33 static_assert(H >= 8,
"Key length too short");
36 typedef typename Leaf::Key Key;
41 typedef typename std::allocator_traits<ArbitraryAllocator>::template rebind_alloc<XFastLeaf> Alloc;
43 static constexpr auto TREE_SPLIT_THRESHOLD = 2 * H;
44 static constexpr auto TREE_MERGE_THRESHOLD = H / 4;
48 const YFastTrie* trie;
53 const Where nowhere = {
this,
nullptr,
nullptr };
59 unsigned int _rebuilds;
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) {
69 [[nodiscard]] std::size_t size()
const {
return _size; }
70 [[nodiscard]]
unsigned int rebuilds()
const {
return _rebuilds; }
72 Where leftmost()
const {
73 auto xleaf = _trie.leftmost();
74 auto leaf = xleaf !=
nullptr ? xleaf->value.leftmost() :
nullptr;
75 return {
this, xleaf, leaf };
78 Where rightmost()
const {
79 auto xleaf = _trie.rightmost();
80 auto leaf = xleaf !=
nullptr ? xleaf->value.rightmost() :
nullptr;
81 return {
this, xleaf, leaf };
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 };
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 };
99 return {
this,
nullptr,
nullptr };
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 };
114 return {
this, pred, pred_max };
118 return {
this, pred, pred_max };
122 auto leaf = pred->value.pred(key, strict);
123 return {
this, pred, leaf };
127 auto succ = _trie.leftmost();
128 auto leaf = succ !=
nullptr ? succ->value.pred(key, strict) :
nullptr;
129 return {
this, succ, leaf };
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 };
145 return {
this, succ, succ_min };
149 return {
this, succ, succ_min };
153 auto leaf = succ->value.succ(key, strict);
154 return {
this, succ, leaf };
158 auto pred = _trie.rightmost();
159 auto leaf = pred !=
nullptr ? pred->value.succ(key, strict) :
nullptr;
160 return {
this, pred, leaf };
170 auto pred = _trie.pred(leaf->key);
171 auto succ = (pred !=
nullptr) ? pred->nxt : _trie.leftmost();
174 if (pred !=
nullptr && succ !=
nullptr) {
175 if (_cmp(leaf->key, succ->value.leftmost()->key)) {
182 else if (pred !=
nullptr) {
185 else if (succ !=
nullptr) {
189 xleaf = std::allocator_traits<Alloc>::allocate(_alloc, 1);
190 std::allocator_traits<Alloc>::construct(_alloc, xleaf, leaf->key, Value(_cmp));
194 auto replaced = xleaf->value.
insert(leaf);
196 if (replaced ==
nullptr) {
197 if (xleaf->value.size() > TREE_SPLIT_THRESHOLD) {
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));
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;
214 return {
this, xleaf, replaced };
217 void remove(Leaf* leaf, XFastLeaf* hint =
nullptr) {
219 if (xleaf ==
nullptr || xleaf->value.find(leaf->key) != leaf) {
220 auto where = find(leaf->key);
223 if (xleaf ==
nullptr) {
226 xleaf->value.remove(leaf);
227 if (xleaf->value.size() < TREE_MERGE_THRESHOLD) {
228 auto neighbor = pick_neighbor(xleaf);
229 if (neighbor !=
nullptr) {
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));
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);
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);
253 else if (xleaf->value.size() == 0) {
255 std::allocator_traits<Alloc>::destroy(_alloc, xleaf);
256 std::allocator_traits<Alloc>::deallocate(_alloc, xleaf, 1);
261 if (_cmp(xleaf->key, xleaf->value.leftmost()->key) || _cmp(xleaf->value.rightmost()->key, xleaf->key)) {
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);
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);
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;
294 if (pred_merge_size <= TREE_SPLIT_THRESHOLD) {
297 if (succ_merge_size <= TREE_SPLIT_THRESHOLD) {
300 return pred_merge_size > succ_merge_size ? pred : succ;
302 if (pred !=
nullptr) {
305 if (succ !=
nullptr) {