yfast 0.6.1
Loading...
Searching...
No Matches
yfast.h
1#ifndef _YFAST_IMPL_YFAST_H
2#define _YFAST_IMPL_YFAST_H
3
4#include <functional>
5#include <memory>
6
7#include <yfast/impl/avl.h>
8#include <yfast/internal/concepts.h>
9#include <yfast/internal/bit_extractor.h>
10#include <yfast/internal/yfast.h>
11#include <yfast/internal/default_hash.h>
12
13namespace yfast::impl {
14
24template <
25 typename Leaf,
26 unsigned int H,
27 internal::BitExtractorGeneric<typename Leaf::Key> BitExtractor = internal::BitExtractor<typename Leaf::Key>,
28 internal::MapGeneric<typename BitExtractor::ShiftResult, std::uintptr_t> Hash = internal::DefaultHash<typename BitExtractor::ShiftResult, std::uintptr_t>,
29 typename Compare = std::less<typename Leaf::Key>,
30 typename ArbitraryAllocator = std::allocator<typename Leaf::Key>
31>
32class YFastTrie {
33 static_assert(H >= 8, "Key length too short");
34
35public:
36 typedef typename Leaf::Key Key;
37 typedef AVL<Leaf, Compare> Value;
38 typedef internal::XFastLeaf<Key, Value> XFastLeaf;
39
40private:
41 typedef typename std::allocator_traits<ArbitraryAllocator>::template rebind_alloc<XFastLeaf> Alloc;
42
43 static constexpr auto TREE_SPLIT_THRESHOLD = 2 * H;
44 static constexpr auto TREE_MERGE_THRESHOLD = H / 4;
45
46public:
47 struct Where {
48 const YFastTrie* trie;
49 XFastLeaf* xleaf;
50 Leaf* leaf;
51 };
52
53 const Where nowhere = { this, nullptr, nullptr };
54
55private:
56 Alloc _alloc;
57 Compare _cmp;
59 unsigned int _rebuilds;
60 std::size_t _size;
61
62public:
63 explicit YFastTrie(BitExtractor bx = BitExtractor(), Compare cmp = Compare(), ArbitraryAllocator alloc = ArbitraryAllocator()): _alloc(alloc), _cmp(cmp), _trie(bx, cmp), _rebuilds(0), _size(0) {}
64 YFastTrie(YFastTrie&& other) noexcept: _alloc(other._alloc), _cmp(other._cmp), _trie(std::move(other._trie)), _rebuilds(other._rebuilds), _size(other._size) {
65 other._size = 0;
66 other._rebuilds = 0;
67 }
68
69 [[nodiscard]] std::size_t size() const { return _size; }
70 [[nodiscard]] unsigned int rebuilds() const { return _rebuilds; }
71
72 Where leftmost() const {
73 auto xleaf = _trie.leftmost();
74 auto leaf = xleaf != nullptr ? xleaf->value.leftmost() : nullptr;
75 return { this, xleaf, leaf };
76 }
77
78 Where rightmost() const {
79 auto xleaf = _trie.rightmost();
80 auto leaf = xleaf != nullptr ? xleaf->value.rightmost() : nullptr;
81 return { this, xleaf, leaf };
82 }
83
84 Where find(const Key& key) const {
85 auto pred = _trie.pred(key);
86 if (pred != nullptr) {
87 auto leaf = pred->value.find(key);
88 if (leaf != nullptr) {
89 return { this, pred, leaf };
90 }
91 }
92 auto succ = (pred != nullptr) ? pred->nxt : _trie.leftmost();
93 if (succ != nullptr) {
94 auto leaf = succ->value.find(key);
95 if (leaf != nullptr) {
96 return { this, succ, leaf };
97 }
98 }
99 return { this, nullptr, nullptr };
100 }
101
102 Where pred(const Key& key, bool strict = false) const {
103 auto pred = _trie.pred(key, strict);
104 if (pred != nullptr) {
105 auto pred_max = pred->value.rightmost();
106 if (_cmp(pred_max->key, key)) {
107 auto succ = pred->nxt;
108 if (succ != nullptr && !_cmp(key, succ->value.leftmost()->key)) {
109 auto leaf = succ->value.pred(key, strict);
110 if (leaf != nullptr) {
111 return { this, succ, leaf };
112 }
113 else {
114 return { this, pred, pred_max };
115 }
116 }
117 else {
118 return { this, pred, pred_max };
119 }
120 }
121 else {
122 auto leaf = pred->value.pred(key, strict);
123 return { this, pred, leaf };
124 }
125 }
126 else {
127 auto succ = _trie.leftmost();
128 auto leaf = succ != nullptr ? succ->value.pred(key, strict) : nullptr;
129 return { this, succ, leaf };
130 }
131 }
132
133 Where succ(const Key& key, bool strict = false) const {
134 auto succ = _trie.succ(key, strict);
135 if (succ != nullptr) {
136 auto succ_min = succ->value.leftmost();
137 if (_cmp(key, succ_min->key)) {
138 auto pred = succ->prv;
139 if (pred != nullptr && !_cmp(pred->value.rightmost()->key, key)) {
140 auto leaf = pred->value.succ(key, strict);
141 if (leaf != nullptr) {
142 return { this, pred, leaf };
143 }
144 else {
145 return { this, succ, succ_min };
146 }
147 }
148 else {
149 return { this, succ, succ_min };
150 }
151 }
152 else {
153 auto leaf = succ->value.succ(key, strict);
154 return { this, succ, leaf };
155 }
156 }
157 else {
158 auto pred = _trie.rightmost();
159 auto leaf = pred != nullptr ? pred->value.succ(key, strict) : nullptr;
160 return { this, pred, leaf };
161 }
162 }
163
169 Where insert(Leaf* leaf) {
170 auto pred = _trie.pred(leaf->key);
171 auto succ = (pred != nullptr) ? pred->nxt : _trie.leftmost();
172 XFastLeaf* xleaf;
173
174 if (pred != nullptr && succ != nullptr) {
175 if (_cmp(leaf->key, succ->value.leftmost()->key)) {
176 xleaf = pred;
177 }
178 else {
179 xleaf = succ;
180 }
181 }
182 else if (pred != nullptr) {
183 xleaf = pred;
184 }
185 else if (succ != nullptr) {
186 xleaf = succ;
187 }
188 else {
189 xleaf = std::allocator_traits<Alloc>::allocate(_alloc, 1);
190 std::allocator_traits<Alloc>::construct(_alloc, xleaf, leaf->key, Value(_cmp));
191 _trie.insert(xleaf);
192 }
193
194 auto replaced = xleaf->value.insert(leaf);
195
196 if (replaced == nullptr) {
197 if (xleaf->value.size() > TREE_SPLIT_THRESHOLD) {
198 _trie.remove(xleaf);
199 auto split_result = xleaf->value.split();
200 XFastLeaf* left = std::allocator_traits<Alloc>::allocate(_alloc, 1);
201 std::allocator_traits<Alloc>::construct(_alloc, left, split_result.left.root()->key, std::move(split_result.left));
202 XFastLeaf* right = std::allocator_traits<Alloc>::allocate(_alloc, 1);
203 std::allocator_traits<Alloc>::construct(_alloc, right, split_result.right.root()->key, std::move(split_result.right));
204 _trie.insert(left);
205 _trie.insert(right);
206 std::allocator_traits<Alloc>::destroy(_alloc, xleaf);
207 std::allocator_traits<Alloc>::deallocate(_alloc, xleaf, 1);
208 xleaf = _cmp(split_result.left_max->key, leaf->key) ? right : left;
209 ++_rebuilds;
210 }
211 ++_size;
212 }
213
214 return { this, xleaf, replaced };
215 }
216
217 void remove(Leaf* leaf, XFastLeaf* hint = nullptr) {
218 auto xleaf = hint;
219 if (xleaf == nullptr || xleaf->value.find(leaf->key) != leaf) {
220 auto where = find(leaf->key);
221 xleaf = where.xleaf;
222 }
223 if (xleaf == nullptr) {
224 return;
225 }
226 xleaf->value.remove(leaf);
227 if (xleaf->value.size() < TREE_MERGE_THRESHOLD) {
228 auto neighbor = pick_neighbor(xleaf);
229 if (neighbor != nullptr) {
230 _trie.remove(xleaf);
231 _trie.remove(neighbor);
232 auto merged = Value::merge(std::move(xleaf->value), std::move(neighbor->value));
233 if (merged.size() > TREE_SPLIT_THRESHOLD) {
234 auto split_result = merged.split();
235 XFastLeaf* left = std::allocator_traits<Alloc>::allocate(_alloc, 1);
236 std::allocator_traits<Alloc>::construct(_alloc, left, split_result.left.root()->key, std::move(split_result.left));
237 XFastLeaf* right = std::allocator_traits<Alloc>::allocate(_alloc, 1);
238 std::allocator_traits<Alloc>::construct(_alloc, right, split_result.right.root()->key, std::move(split_result.right));
239 _trie.insert(left);
240 _trie.insert(right);
241 }
242 else {
243 XFastLeaf* merged_xleaf = std::allocator_traits<Alloc>::allocate(_alloc, 1);
244 std::allocator_traits<Alloc>::construct(_alloc, merged_xleaf, merged.root()->key, std::move(merged));
245 _trie.insert(merged_xleaf);
246 }
247 std::allocator_traits<Alloc>::destroy(_alloc, xleaf);
248 std::allocator_traits<Alloc>::deallocate(_alloc, xleaf, 1);
249 std::allocator_traits<Alloc>::destroy(_alloc, neighbor);
250 std::allocator_traits<Alloc>::deallocate(_alloc, neighbor, 1);
251 ++_rebuilds;
252 }
253 else if (xleaf->value.size() == 0) {
254 _trie.remove(xleaf);
255 std::allocator_traits<Alloc>::destroy(_alloc, xleaf);
256 std::allocator_traits<Alloc>::deallocate(_alloc, xleaf, 1);
257 ++_rebuilds;
258 }
259 }
260 else {
261 if (_cmp(xleaf->key, xleaf->value.leftmost()->key) || _cmp(xleaf->value.rightmost()->key, xleaf->key)) {
262 _trie.remove(xleaf);
263 XFastLeaf* reinserted_xleaf = std::allocator_traits<Alloc>::allocate(_alloc, 1);
264 std::allocator_traits<Alloc>::construct(_alloc, reinserted_xleaf, xleaf->value.root()->key, std::move(xleaf->value));
265 _trie.insert(reinserted_xleaf);
266 std::allocator_traits<Alloc>::destroy(_alloc, xleaf);
267 std::allocator_traits<Alloc>::deallocate(_alloc, xleaf, 1);
268 }
269 }
270
271 --_size;
272 }
273
274 void clear() {
275 for (auto xleaf = _trie.leftmost(); xleaf != nullptr; xleaf = xleaf->nxt) {
276 std::allocator_traits<Alloc>::destroy(_alloc, xleaf);
277 std::allocator_traits<Alloc>::deallocate(_alloc, xleaf, 1);
278 }
279 _trie.clear();
280 _size = 0;
281 _rebuilds = 0;
282 }
283
284private:
285 static XFastLeaf* pick_neighbor(XFastLeaf* xleaf) {
286 auto pred = xleaf->prv;
287 auto succ = xleaf->nxt;
288 if (pred != nullptr && succ != nullptr) {
289 auto pred_merge_size = pred->value.size() + xleaf->value.size();
290 auto succ_merge_size = succ->value.size() + xleaf->value.size();
291 if (pred_merge_size <= TREE_SPLIT_THRESHOLD && succ_merge_size <= TREE_SPLIT_THRESHOLD) {
292 return pred_merge_size < succ_merge_size ? pred : succ;
293 }
294 if (pred_merge_size <= TREE_SPLIT_THRESHOLD) {
295 return pred;
296 }
297 if (succ_merge_size <= TREE_SPLIT_THRESHOLD) {
298 return succ;
299 }
300 return pred_merge_size > succ_merge_size ? pred : succ;
301 }
302 if (pred != nullptr) {
303 return pred;
304 }
305 if (succ != nullptr) {
306 return succ;
307 }
308 return nullptr;
309 }
310};
311
312}
313
314#endif
Definition avl.h:16
Node * insert(Node *node)
Definition avl.h:42
Definition xfast.h:29
Definition yfast.h:32
Where insert(Leaf *leaf)
Definition yfast.h:169
Definition yfast.h:47
Definition yfast.h:11