yfast 0.6.1
Loading...
Searching...
No Matches
xfast.h
1#ifndef _YFAST_IMPL_XFAST_H
2#define _YFAST_IMPL_XFAST_H
3
4#include <cstdint>
5#include <functional>
6
7#include <yfast/internal/bit_extractor.h>
8#include <yfast/internal/concepts.h>
9#include <yfast/internal/default_hash.h>
10#include <yfast/internal/xfast.h>
11
12namespace yfast::impl {
13
22template <
23 typename Leaf,
24 unsigned int H,
25 internal::BitExtractorGeneric<typename Leaf::Key> BitExtractor = internal::BitExtractor<typename Leaf::Key>,
26 internal::MapGeneric<typename BitExtractor::ShiftResult, std::uintptr_t> Hash = internal::DefaultHash<typename BitExtractor::ShiftResult, std::uintptr_t>,
27 typename Compare = std::less<typename Leaf::Key>
28>
29class XFastTrie {
30public:
31 typedef typename Leaf::Key Key;
32
33protected:
34 typedef enum {EMPTY, MISSED_LEFT, ON_TARGET, MISSED_RIGHT} Missed;
35
36 typedef struct {
37 Leaf* leaf;
38 Missed missed;
39 unsigned int level;
41
42 typedef internal::XFastNode<Leaf> Node;
43
44private:
45 BitExtractor _bx;
46 Compare _cmp;
47 Node _root;
48 Leaf* _leftmost;
49 Leaf* _rightmost;
50 Hash _hash[H];
51
52public:
53 explicit XFastTrie(BitExtractor bx = BitExtractor(), Compare cmp = Compare()): _bx(bx), _cmp(cmp), _root(nullptr, false, false), _leftmost(nullptr), _rightmost(nullptr) {}
54 XFastTrie(const XFastTrie& other) = delete;
55 XFastTrie(XFastTrie&& other) noexcept: _bx(other._bx), _cmp(other._cmp), _root(other._root), _leftmost(other._leftmost), _rightmost(other._rightmost), _hash(std::move(other._hash)) {
56 other._root = Node(nullptr, false, false);
57 other._leftmost = nullptr;
58 other._rightmost = nullptr;
59 }
60
61 Leaf* leftmost() const { return _leftmost; }
62 Leaf* rightmost() const { return _rightmost; }
63
64 Leaf* find(const Key& key) const {
65 auto key_ = _bx.shift(key, 0);
66 if (_hash[0].contains(key_)) {
67 return reinterpret_cast<Leaf*>(_hash[0].at(key_));
68 }
69 return nullptr;
70 }
71
72 Leaf* pred(const Key& key, bool strict = false) const {
73 auto [guess, missed, level] = approx(key);
74 switch (missed) {
75 case EMPTY:
76 return nullptr;
77 case MISSED_LEFT:
78 return guess;
79 case ON_TARGET:
80 return strict ? guess->prv : guess;
81 case MISSED_RIGHT:
82 return guess->prv;
83 }
84 }
85
86 Leaf* succ(const Key& key, bool strict = false) const {
87 auto [guess, missed, level] = approx(key);
88 switch (missed) {
89 case EMPTY:
90 return nullptr;
91 case MISSED_LEFT:
92 return guess->nxt;
93 case ON_TARGET:
94 return strict ? guess->nxt : guess;
95 case MISSED_RIGHT:
96 return guess;
97 }
98 }
99
100 void insert(Leaf* leaf) {
101 Leaf* prv;
102 Leaf* nxt;
103 auto [guess, missed, level] = approx(leaf->key);
104 switch (missed) {
105 case EMPTY:
106 _root = Node(leaf, false, false);
107 prv = nullptr;
108 nxt = nullptr;
109 break;
110 case MISSED_LEFT:
111 prv = guess;
112 nxt = guess->nxt;
113 break;
114 case ON_TARGET:
115 return;
116 case MISSED_RIGHT:
117 prv = guess->prv;
118 nxt = guess;
119 break;
120 }
121
122 leaf->prv = prv;
123 leaf->nxt = nxt;
124 if (prv != nullptr) {
125 prv->nxt = leaf;
126 }
127 if (nxt != nullptr) {
128 nxt->prv = leaf;
129 }
130
131 bool next_bit;
132
133 if (level == H) {
134 next_bit = _bx.extract_bit(leaf->key, H - 1);
135 if (next_bit) {
136 _root.set_right_present();
137 }
138 else {
139 _root.set_left_present();
140 }
141 }
142
143 next_bit = _bx.extract_bit(leaf->key, level - 1);
144
145 if ((!_root.left_present() && !next_bit) || (!_root.right_present() && next_bit)) {
146 _root.set_descendant(leaf);
147 }
148
149 for (unsigned int h = H - 1; h >= level; --h) {
150 auto key_prefix = _bx.shift(leaf->key, h);
151 std::uintptr_t value = _hash[h].at(key_prefix);
152 Node node = value;
153 if (!node.left_present()) {
154 if (_cmp(leaf->key, node.descendant()->key)) {
155 node.set_descendant(leaf);
156 _hash[h][key_prefix] = node.value;
157 }
158 }
159 if (!node.right_present()) {
160 if (_cmp(node.descendant()->key, leaf->key)) {
161 node.set_descendant(leaf);
162 _hash[h][key_prefix] = node.value;
163 }
164 }
165 }
166
167 for (unsigned int h = std::min(level, H - 1); h > 0; --h) {
168 next_bit = _bx.extract_bit(leaf->key, h - 1);
169 auto key_prefix = _bx.shift(leaf->key, h);
170 if (_hash[h].contains(key_prefix)) {
171 std::uintptr_t value = _hash[h].at(key_prefix);
172 Node node = value;
173 if (next_bit) {
174 node.set_right_present();
175 if (!node.left_present()) {
176 if (_cmp(leaf->key, node.descendant()->key)) {
177 node.set_descendant(leaf);
178 }
179 }
180 }
181 else {
182 node.set_left_present();
183 if (!node.right_present()) {
184 if (_cmp(node.descendant()->key, leaf->key)) {
185 node.set_descendant(leaf);
186 }
187 }
188 }
189 _hash[h][key_prefix] = node.value;
190 }
191 else {
192 Node node(leaf, !next_bit, next_bit);
193 _hash[h][key_prefix] = node.value;
194 }
195 }
196
197 _hash[0][_bx.shift(leaf->key, 0)] = reinterpret_cast<std::uintptr_t>(leaf);
198
199 if (_leftmost == nullptr || _cmp(leaf->key, _leftmost->key)) {
200 _leftmost = leaf;
201 }
202 if (_rightmost == nullptr || _cmp(_rightmost->key, leaf->key)) {
203 _rightmost = leaf;
204 }
205 }
206
207 void remove(Leaf* leaf) {
208 auto prv = leaf->prv;
209 auto nxt = leaf->nxt;
210 if (prv != nullptr) {
211 prv->nxt = nxt;
212 }
213 if (nxt != nullptr) {
214 nxt->prv = prv;
215 }
216
217 _hash[0].erase(_bx.shift(leaf->key, 0));
218
219 bool subtree_removed = true;
220 for (unsigned int h = 1; h < H; ++h) {
221 auto key_prefix = _bx.shift(leaf->key, h);
222 std::uintptr_t value = _hash[h].at(key_prefix);
223 Node node = value;
224 if (subtree_removed) {
225 if (_bx.extract_bit(leaf->key, h - 1)) {
226 node.clear_right_present();
227 if (node.left_present()) {
228 node.set_descendant(prv);
229 _hash[h][key_prefix] = node.value;
230 subtree_removed = false;
231 }
232 else {
233 _hash[h].erase(key_prefix);
234 }
235 }
236 else {
237 node.clear_left_present();
238 if (node.right_present()) {
239 node.set_descendant(nxt);
240 _hash[h][key_prefix] = node.value;
241 subtree_removed = false;
242 }
243 else {
244 _hash[h].erase(key_prefix);
245 }
246 }
247 }
248 else {
249 if (node.descendant() == leaf) {
250 if (!node.left_present()) {
251 node.set_descendant(nxt);
252 }
253 if (!node.right_present()) {
254 node.set_descendant(prv);
255 }
256 _hash[h][key_prefix] = node.value;
257 }
258 }
259 }
260
261 if (subtree_removed) {
262 if (_bx.extract_bit(leaf->key, H - 1)) {
263 _root.clear_right_present();
264 if (_root.left_present()) {
265 _root.set_descendant(prv);
266 }
267 else {
268 _root.set_descendant(nullptr);
269 }
270 }
271 else {
272 _root.clear_left_present();
273 if (_root.right_present()) {
274 _root.set_descendant(nxt);
275 }
276 else {
277 _root.set_descendant(nullptr);
278 }
279 }
280 }
281 else {
282 if (_root.descendant() == leaf) {
283 if (!_root.left_present()) {
284 _root.set_descendant(nxt);
285 }
286 if (!_root.right_present()) {
287 _root.set_descendant(prv);
288 }
289 }
290 }
291
292 if (_leftmost == leaf) {
293 _leftmost = nxt;
294 }
295 if (_rightmost == leaf) {
296 _rightmost = prv;
297 }
298 }
299
300 void clear() {
301 for (unsigned int h = 0; h < H; ++h) {
302 _hash[h].clear();
303 }
304 _root = Node(nullptr, false, false);
305 _leftmost = nullptr;
306 _rightmost = nullptr;
307 }
308
309private:
310 ApproxReport approx(const Key& key) const {
311 if (!_root.left_present() && !_root.right_present()) {
312 return {nullptr, EMPTY, H };
313 }
314
315 unsigned int l = 0;
316 unsigned int r = H;
317 unsigned int m;
318 while (r - l > 1) { // ln H
319 m = (r + l) / 2;
320 if (_hash[m].contains(_bx.shift(key, m))) {
321 r = m;
322 }
323 else {
324 l = m;
325 }
326 }
327 if (_hash[l].contains(_bx.shift(key, l))) {
328 m = l;
329 }
330 else {
331 m = r;
332 }
333
334 if (m == 0) {
335 std::uintptr_t value = _hash[0].at(_bx.shift(key, 0));
336 return {reinterpret_cast<Leaf*>(value), ON_TARGET, 0 };
337 }
338
339 Node node;
340 if (m < H) {
341 std::uintptr_t value = _hash[m].at(_bx.shift(key, m));
342 node.value = value;
343 }
344 else {
345 node = _root;
346 }
347 if (node.left_present()) {
348 return { node.descendant(), MISSED_LEFT, m };
349 }
350 else {
351 return { node.descendant(), MISSED_RIGHT, m };
352 }
353 }
354};
355
356}
357
358#endif
Definition xfast.h:29
Definition xfast.h:18