forked from utsaslab/RECIPE
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathN16.cpp
133 lines (120 loc) · 4.48 KB
/
N16.cpp
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <assert.h>
#include <algorithm>
#include "N.h"
#include <emmintrin.h> // x86 SSE intrinsics
namespace ART_ROWEX {
inline bool N16::insert(uint8_t key, N *n, bool flush) {
if (compactCount == 16) {
return false;
}
keys[compactCount].store(flipSign(key), flush ? std::memory_order_release : std::memory_order_relaxed);
children[compactCount].store(n, flush ? std::memory_order_release : std::memory_order_relaxed);
if (flush) clflush((char *)&children[compactCount], sizeof(N *), false, true);
compactCount++;
count++;
// this clflush will atomically flush the cache line including counters and entire key entries
if (flush) clflush((char *)this, sizeof(uintptr_t), true, true);
return true;
}
template<class NODE>
void N16::copyTo(NODE *n) const {
for (unsigned i = 0; i < compactCount; i++) {
N *child = children[i].load();
if (child != nullptr) {
n->insert(flipSign(keys[i]), child, false);
}
}
}
void N16::change(uint8_t key, N *val) {
auto childPos = getChildPos(key);
assert(childPos != nullptr);
childPos->store(val, std::memory_order_release);
clflush((char *)childPos, sizeof(N *), false, true);
}
std::atomic<N *> *N16::getChildPos(const uint8_t k) {
__m128i cmp = _mm_cmpeq_epi8(_mm_set1_epi8(flipSign(k)),
_mm_loadu_si128(reinterpret_cast<const __m128i *>(keys)));
unsigned bitfield = _mm_movemask_epi8(cmp) & ((1 << compactCount) - 1);
while (bitfield) {
uint8_t pos = ctz(bitfield);
if (children[pos].load() != nullptr) {
return &children[pos];
}
bitfield = bitfield ^ (1 << pos);
}
return nullptr;
}
N *N16::getChild(const uint8_t k) const {
__m128i cmp = _mm_cmpeq_epi8(_mm_set1_epi8(flipSign(k)),
_mm_loadu_si128(reinterpret_cast<const __m128i *>(keys)));
unsigned bitfield = _mm_movemask_epi8(cmp) & ((1 << 16) - 1);
while (bitfield) {
uint8_t pos = ctz(bitfield);
N *child = children[pos].load();
if (child != nullptr && keys[pos].load() == flipSign(k)) {
return child;
}
bitfield = bitfield ^ (1 << pos);
}
return nullptr;
}
bool N16::remove(uint8_t k, bool force, bool flush) {
if (count <= 3 && !force) {
return false;
}
auto leafPlace = getChildPos(k);
assert(leafPlace != nullptr);
leafPlace->store(nullptr, flush ? std::memory_order_release : std::memory_order_relaxed);
if (flush) clflush((char *)leafPlace, sizeof(N *), false, true);
count--;
assert(getChild(k) == nullptr);
return true;
}
N *N16::getAnyChild() const {
N *anyChild = nullptr;
for (int i = 0; i < 16; ++i) {
N *child = children[i].load();
if (child != nullptr) {
if (N::isLeaf(child)) {
return child;
}
anyChild = child;
}
}
return anyChild;
}
void N16::deleteChildren() {
for (std::size_t i = 0; i < compactCount; ++i) {
if (children[i].load() != nullptr) {
N::deleteChildren(children[i]);
N::deleteNode(children[i]);
}
}
}
void N16::getChildren(uint8_t start, uint8_t end, std::tuple<uint8_t, N *> *&children,
uint32_t &childrenCount) const {
childrenCount = 0;
for (int i = 0; i < compactCount; ++i) {
uint8_t key = flipSign(this->keys[i]);
if (key >= start && key <= end) {
N *child = this->children[i].load();
if (child != nullptr) {
children[childrenCount] = std::make_tuple(key, child);
childrenCount++;
}
}
}
std::sort(children, children + childrenCount, [](auto &first, auto &second) {
return std::get<0>(first) < std::get<0>(second);
});
}
uint32_t N16::getCount() const {
uint32_t cnt = 0;
for (uint32_t i = 0; i < compactCount && cnt < 3; i++) {
N *child = children[i].load();
if (child != nullptr)
++cnt;
}
return cnt;
}
}