-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatomic_hashset.hpp
95 lines (77 loc) · 2.12 KB
/
atomic_hashset.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#ifndef VI_ATOMIC_HASHSET_HPP
#define VI_ATOMIC_HASHSET_HPP
#include "common_defs.h"
#include "paged_array.hpp"
#include "atomic.hpp"
namespace vi
{
//motivation for such data structure is avoiding memory allocations.
//we just pre-allocate memory and then just fill it.
//i'm not sure but possibly locking memory with mlock() in the memory_block could prevent latencies from swapping.
template<class T>
struct table_entry
{
enum entry_status
{
empty = 0
};
uint32_t status;
T payload;
table_entry() : status(table_entry<T>::empty)
{
}
};
template<class K, class T, class HK, uint32_t MaxEntries, uint32_t PageSize>
class atomic_hashset
{
private:
paged_array<table_entry<T>, MaxEntries, PageSize> mStorage;
uint32_t mSize;
public:
atomic_hashset() : mSize(0)
{
mStorage.zero_fill();
}
uint32_t max_entry_count() const
{
return MaxEntries;
}
uint32_t size() const
{
return mSize;
}
uint32_t try_put(const K& key, const T& value)
{
uint32_t index = HK::to_index(key);
if (index < MaxEntries)
{
uint32_t entryStatus = atomic_xadd(&(mStorage[index].status), 1);
if (table_entry<T>::empty == entryStatus)
{
barrier(); //we want changes to be visible to all
mStorage[index].payload = value;
atomic_add(&mSize, 1);
}
return entryStatus;
}
else
{
return MaxEntries + 1;
}
}
const table_entry<T>& find(const K& key)
{
static table_entry<T> empty;
uint32_t index = HK::to_index(key);
if (index < mStorage.size())
{
return mStorage[index];
}
else
{
return empty;
}
}
};
};
#endif