Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_b_tree.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
49#ifndef TPL_B_TREE_H
50#define TPL_B_TREE_H
51
52#include <algorithm>
53#include <concepts>
54#include <initializer_list>
55#include <iterator>
56#include <memory>
57#include <optional>
58#include <utility>
59
60#include <ah-concepts.H>
61#include <ah-errors.H>
62#include <ahFunction.H>
63#include <tpl_array.H>
64#include <tpl_sort_utils.H>
65
66namespace Aleph {
67namespace detail {
68template <typename Compare, typename Key> [[nodiscard]] bool equiv(const Compare &cmp, const Key &lhs, const Key &rhs)
69{
70 return not cmp(lhs, rhs) and not cmp(rhs, lhs);
71}
72
73template <typename Key> struct BTreeNode
74{
75 bool leaf = true;
78
79 explicit BTreeNode(const bool is_leaf) : leaf(is_leaf) {}
80};
81} // namespace detail
82
129template <typename Key,
130 class Compare = Aleph::less<Key>,
131 size_t MinDegree = 16>
134{
135 static_assert(MinDegree >= 2, "B_Tree requires MinDegree >= 2");
136 static_assert(std::copy_constructible<Key>, "B_Tree requires copy-constructible keys");
137
139
140 static constexpr size_t MaxKeys = 2 * MinDegree - 1;
141 static constexpr size_t MinKeys = MinDegree - 1;
142
143 std::unique_ptr<Node> root_;
144 size_t size_ = 0;
145 Compare cmp_;
146
147 [[nodiscard]] size_t lower_bound_index(const Array<Key> &keys, const Key &key) const
148 {
149 size_t lo = 0, hi = keys.size();
150 while (lo < hi)
151 {
152 const size_t mid = lo + (hi - lo) / 2;
153 if (cmp_(keys[mid], key))
154 lo = mid + 1;
155 else
156 hi = mid;
157 }
158 return lo;
159 }
160
161 [[nodiscard]] size_t upper_bound_index(const Array<Key> &keys, const Key &key) const
162 {
163 size_t lo = 0, hi = keys.size();
164 while (lo < hi)
165 {
166 const size_t mid = lo + (hi - lo) / 2;
167 if (cmp_(key, keys[mid]))
168 hi = mid;
169 else
170 lo = mid + 1;
171 }
172 return lo;
173 }
174
175 [[nodiscard]] bool equals(const Key &lhs, const Key &rhs) const
176 {
177 return detail::equiv(cmp_, lhs, rhs);
178 }
179
180 template <std::input_iterator It> void insert_range(It first, It last)
181 {
182 for (; first != last; ++first)
183 insert(*first);
184 }
185
186 template <typename T, typename U> static void insert_at(Array<T> &array, const size_t idx, U &&value)
187 {
188 if (idx == array.size())
189 {
190 array.append(std::forward<U>(value));
191 return;
192 }
193
194 array.putn(1);
195 T *base = &array[0];
196 Aleph::open_gap(base, array.size(), idx, 1);
197 array(idx) = std::forward<U>(value);
198 }
199
200 template <typename T> static T erase_at(Array<T> &array, const size_t idx)
201 {
202 T ret = std::move(array(idx));
203 if (idx + 1 < array.size())
204 {
205 T *base = &array[0];
206 Aleph::close_gap(base, array.size(), idx, 1);
207 }
208 (void) array.remove_last();
209 return ret;
210 }
211
212 template <typename T> static void truncate(Array<T> &array, const size_t new_size)
213 {
214 while (array.size() > new_size)
215 (void) array.remove_last();
216 }
217
218 template <typename T> static void append_copy_range(Array<T> &dst, const Array<T> &src, const size_t from)
219 {
220 dst.reserve(dst.size() + src.size() - from);
221 for (size_t i = from; i < src.size(); ++i)
222 dst.append(src[i]);
223 }
224
225 template <typename T> static void append_move_range(Array<T> &dst, Array<T> &src, const size_t from)
226 {
227 dst.reserve(dst.size() + src.size() - from);
228 for (size_t i = from; i < src.size(); ++i)
229 dst.append(std::move(src(i)));
230 }
231
232 [[nodiscard]] std::unique_ptr<Node> clone_node(const Node *node) const
233 {
234 if (node == nullptr)
235 return nullptr;
236
237 auto copy = std::make_unique<Node>(node->leaf);
238 copy->keys = node->keys;
239 if (not node->leaf)
240 {
241 copy->children.reserve(node->children.size());
242 for (const auto &child : node->children)
243 copy->children.append(clone_node(child.get()));
244 }
245 return copy;
246 }
247
248 [[nodiscard]] size_t height_of(const Node *node) const noexcept
249 {
250 size_t height = 0;
251 for (const Node *curr = node; curr != nullptr;)
252 {
253 ++height;
254 if (curr->leaf or curr->children.is_empty())
255 break;
256 curr = curr->children.get_first().get();
257 }
258 return height;
259 }
260
261 [[nodiscard]] bool contains_in(const Node *node, const Key &key) const
262 {
263 const Node *curr = node;
264 while (curr != nullptr)
265 {
266 const size_t idx = lower_bound_index(curr->keys, key);
267 if (idx < curr->keys.size() and equals(curr->keys[idx], key))
268 return true;
269 if (curr->leaf)
270 return false;
271 curr = curr->children[idx].get();
272 }
273 return false;
274 }
275
276 void split_child(Node *parent, const size_t idx)
277 {
278 Node *child = parent->children[idx].get();
279 auto right = std::make_unique<Node>(child->leaf);
280
281 const Key median = child->keys[MinKeys];
282
283 append_copy_range(right->keys, child->keys, MinDegree);
284 truncate(child->keys, MinKeys);
285
286 if (not child->leaf)
287 {
288 append_move_range(right->children, child->children, MinDegree);
289 truncate(child->children, MinDegree);
290 }
291
292 insert_at(parent->keys, idx, median);
293 insert_at(parent->children, idx + 1, std::move(right));
294 }
295
296 void insert_nonfull(Node *node, const Key &key)
297 {
298 if (node->leaf)
299 {
300 const size_t idx = lower_bound_index(node->keys, key);
301 insert_at(node->keys, idx, key);
302 return;
303 }
304
305 size_t idx = lower_bound_index(node->keys, key);
306 if (node->children[idx]->keys.size() == MaxKeys)
307 {
308 split_child(node, idx);
309 if (cmp_(node->keys[idx], key))
310 ++idx;
311 }
312 insert_nonfull(node->children[idx].get(), key);
313 }
314
315 [[nodiscard]] std::optional<Key> min_in(const Node *node) const
316 {
317 if (node == nullptr)
318 return std::nullopt;
319
320 const Node *curr = node;
321 while (curr != nullptr and not curr->leaf)
322 {
323 if (curr->children.is_empty())
324 return std::nullopt;
325 curr = curr->children.get_first().get();
326 }
327
328 if (curr == nullptr or curr->keys.is_empty())
329 return std::nullopt;
330
331 return curr->keys.get_first();
332 }
333
334 [[nodiscard]] std::optional<Key> max_in(const Node *node) const
335 {
336 if (node == nullptr)
337 return std::nullopt;
338
339 const Node *curr = node;
340 while (curr != nullptr and not curr->leaf)
341 {
342 if (curr->children.is_empty())
343 return std::nullopt;
344 curr = curr->children.get_last().get();
345 }
346
347 if (curr == nullptr or curr->keys.is_empty())
348 return std::nullopt;
349
350 return curr->keys.get_last();
351 }
352
353 void borrow_from_prev(Node *parent, const size_t idx)
354 {
355 Node *child = parent->children[idx].get();
356 Node *left = parent->children[idx - 1].get();
357
358 insert_at(child->keys, 0, parent->keys[idx - 1]);
359 parent->keys[idx - 1] = left->keys.get_last();
360 (void) left->keys.remove_last();
361
362 if (not left->leaf)
363 {
364 insert_at(child->children, 0, std::move(left->children.get_last()));
365 (void) left->children.remove_last();
366 }
367 }
368
369 void borrow_from_next(Node *parent, const size_t idx)
370 {
371 Node *child = parent->children[idx].get();
372 Node *right = parent->children[idx + 1].get();
373
374 child->keys.append(parent->keys[idx]);
375 parent->keys[idx] = right->keys.get_first();
376 erase_at(right->keys, 0);
377
378 if (not right->leaf)
379 {
380 child->children.append(std::move(right->children.get_first()));
381 erase_at(right->children, 0);
382 }
383 }
384
385 void merge_children(Node *parent, const size_t idx)
386 {
387 Node *left = parent->children[idx].get();
388 auto right = std::move(parent->children[idx + 1]);
389
390 left->keys.append(parent->keys[idx]);
391 append_copy_range(left->keys, right->keys, 0);
392
393 if (not left->leaf)
394 append_move_range(left->children, right->children, 0);
395
396 erase_at(parent->keys, idx);
397 erase_at(parent->children, idx + 1);
398 }
399
400 [[nodiscard]] size_t ensure_child_has_extra(Node *parent, const size_t idx)
401 {
402 if (parent->children[idx]->keys.size() >= MinDegree)
403 return idx;
404
405 if (idx > 0 and parent->children[idx - 1]->keys.size() >= MinDegree)
406 {
407 borrow_from_prev(parent, idx);
408 return idx;
409 }
410
411 if (idx + 1 < parent->children.size() and parent->children[idx + 1]->keys.size() >= MinDegree)
412 {
413 borrow_from_next(parent, idx);
414 return idx;
415 }
416
417 if (idx + 1 < parent->children.size())
418 {
419 merge_children(parent, idx);
420 return idx;
421 }
422
423 merge_children(parent, idx - 1);
424 return idx - 1;
425 }
426
427 [[nodiscard]] bool remove_from(Node *node, const Key &key)
428 {
429 const size_t idx = lower_bound_index(node->keys, key);
430 const bool found = idx < node->keys.size() and equals(node->keys[idx], key);
431
432 if (found)
433 {
434 if (node->leaf)
435 {
436 erase_at(node->keys, idx);
437 return true;
438 }
439
440 if (node->children[idx]->keys.size() >= MinDegree)
441 {
442 auto pred_opt = max_in(node->children[idx].get());
444 << "max_in returned nullopt on non-empty child in remove_from";
445 const Key pred = *pred_opt;
446 node->keys[idx] = pred;
447 return remove_from(node->children[idx].get(), pred);
448 }
449
450 if (node->children[idx + 1]->keys.size() >= MinDegree)
451 {
452 auto succ_opt = min_in(node->children[idx + 1].get());
454 << "min_in returned nullopt on non-empty child in remove_from";
455 const Key succ = *succ_opt;
456 node->keys[idx] = succ;
457 return remove_from(node->children[idx + 1].get(), succ);
458 }
459
460 merge_children(node, idx);
461 return remove_from(node->children[idx].get(), key);
462 }
463
464 if (node->leaf)
465 return false;
466
467 const size_t child_idx = ensure_child_has_extra(node, idx);
468 return remove_from(node->children[child_idx].get(), key);
469 }
470
471 void collect_keys(const Node *node, Array<Key> &out) const
472 {
473 if (node == nullptr)
474 return;
475
476 if (node->leaf)
477 {
478 for (const auto &key : node->keys)
479 out.append(key);
480 return;
481 }
482
483 for (size_t i = 0; i < node->keys.size(); ++i)
484 {
485 collect_keys(node->children[i].get(), out);
486 out.append(node->keys[i]);
487 }
488 collect_keys(node->children.get_last().get(), out);
489 }
490
491 [[nodiscard]] bool verify_node(const Node *node, const std::optional<Key> &min_key, const std::optional<Key> &max_key,
492 const size_t depth, size_t &leaf_depth, size_t &counted) const
493 {
494 if (node == nullptr)
495 return false;
496
497 if (node != root_.get())
498 {
499 if (node->keys.size() < MinKeys or node->keys.size() > MaxKeys)
500 return false;
501 }
502 else
503 {
504 if (node->keys.size() > MaxKeys)
505 return false;
506 if (not node->leaf and node->keys.size() < 1)
507 return false;
508 }
509
510 // Keys must be strictly increasing — no equal adjacent entries are allowed.
511 {
512 const auto & ks = node->keys;
513 for (size_t ki = 0; ki + 1 < ks.size(); ++ki)
514 if (not cmp_(ks[ki], ks[ki + 1]))
515 return false;
516 }
517
518 if (min_key.has_value() and not node->keys.is_empty() and not cmp_(*min_key, node->keys.get_first()))
519 return false;
520
521 if (max_key.has_value() and not node->keys.is_empty() and not cmp_(node->keys.get_last(), *max_key))
522 return false;
523
524 counted += node->keys.size();
525
526 if (node->leaf)
527 {
528 if (not node->children.is_empty())
529 return false;
530 if (leaf_depth == static_cast<size_t>(-1))
531 leaf_depth = depth;
532 return leaf_depth == depth;
533 }
534
535 if (node->children.size() != node->keys.size() + 1)
536 return false;
537
538 for (size_t i = 0; i < node->children.size(); ++i)
539 {
540 std::optional<Key> child_min = min_key;
541 std::optional<Key> child_max = max_key;
542 if (i > 0)
543 child_min = node->keys[i - 1];
544 if (i < node->keys.size())
545 child_max = node->keys[i];
546 if (not verify_node(node->children[i].get(), child_min, child_max, depth + 1, leaf_depth, counted))
547 return false;
548 }
549
550 return true;
551 }
552
553public:
554 using key_type = Key;
555
561 explicit Gen_B_Tree(const Compare &cmp = Compare()) : cmp_(cmp) {}
562
570 template <std::input_iterator It> Gen_B_Tree(It first, It last, const Compare &cmp = Compare()) : cmp_(cmp)
571 {
572 insert_range(first, last);
573 }
574
581 Gen_B_Tree(std::initializer_list<Key> init, const Compare &cmp = Compare())
582 : Gen_B_Tree(init.begin(), init.end(), cmp)
583 {}
584
591
597
604 {
605 if (this == &other)
606 return *this;
607
608 // Copy-and-swap: build a full copy first so that if cmp_'s copy-assignment
609 // (or clone_node) throws, *this is left unchanged.
611 std::swap(root_, tmp.root_);
612 std::swap(size_, tmp.size_);
613 std::swap(cmp_, tmp.cmp_);
614 return *this;
615 }
616
623
629 [[nodiscard]] const Compare &key_comp() const noexcept
630 {
631 return cmp_;
632 }
633
639 [[nodiscard]] const Compare &get_compare() const noexcept
640 {
641 return key_comp();
642 }
643
650 {
651 return size_ == 0;
652 }
653
660 {
661 return empty();
662 }
663
670 {
671 return size_;
672 }
673
680 {
681 return height_of(root_.get());
682 }
683
689 {
690 root_.reset();
691 size_ = 0;
692 }
693
700 [[nodiscard]] bool contains(const Key &key) const
701 {
702 return contains_in(root_.get(), key);
703 }
704
711 [[nodiscard]] bool search(const Key &key) const
712 {
713 return contains(key);
714 }
715
723 bool insert(const Key &key)
724 {
725 if (contains(key))
726 return false;
727
728 if (root_ == nullptr)
729 {
730 root_ = std::make_unique<Node>(true);
731 root_->keys.append(key);
732 size_ = 1;
733 return true;
734 }
735
736 if (root_->keys.size() == MaxKeys)
737 {
738 auto new_root = std::make_unique<Node>(false);
739 new_root->children.append(std::move(root_));
740 split_child(new_root.get(), 0);
741 root_ = std::move(new_root);
742 }
743
744 insert_nonfull(root_.get(), key);
745 ++size_;
746 return true;
747 }
748
756 bool insert(Key &&key)
757 {
758 Key copy = std::move(key);
759 return insert(copy);
760 }
761
768 bool remove(const Key &key)
769 {
770 if (root_ == nullptr)
771 return false;
772
773 const bool removed = remove_from(root_.get(), key);
774
775 // The search path in remove_from may trigger merges (via
776 // ensure_child_has_extra) that leave the root with zero keys even
777 // when the key is not found. Promote the sole child regardless
778 // so the invariant "non-leaf root has >= 1 key" is preserved.
779 while (root_ != nullptr and root_->keys.is_empty())
780 {
781 if (root_->leaf)
782 {
783 root_.reset();
784 break;
785 }
786
787 if (root_->children.is_empty())
788 {
789 root_.reset();
790 break;
791 }
792
793 root_ = std::move(root_->children.get_first());
794 }
795
796 if (not removed)
797 return false;
798
799 --size_;
800 return true;
801 }
802
808 [[nodiscard]] std::optional<Key> min_key() const
809 {
810 return min_in(root_.get());
811 }
812
818 [[nodiscard]] std::optional<Key> max_key() const
819 {
820 return max_in(root_.get());
821 }
822
829 [[nodiscard]] std::optional<Key> lower_bound(const Key &key) const
830 {
831 const Node *curr = root_.get();
832 std::optional<Key> candidate;
833
834 while (curr != nullptr)
835 {
836 const size_t idx = lower_bound_index(curr->keys, key);
838 candidate = curr->keys[idx];
839 if (curr->leaf)
840 return candidate;
841 curr = curr->children[idx].get();
842 }
843
844 return candidate;
845 }
846
853 [[nodiscard]] std::optional<Key> upper_bound(const Key &key) const
854 {
855 const Node *curr = root_.get();
856 std::optional<Key> candidate;
857
858 while (curr != nullptr)
859 {
860 const size_t idx = upper_bound_index(curr->keys, key);
862 candidate = curr->keys[idx];
863 if (curr->leaf)
864 return candidate;
865 curr = curr->children[idx].get();
866 }
867
868 return candidate;
869 }
870
878 {
880 out.reserve(size_ == 0 ? 1 : size_);
881 collect_keys(root_.get(), out);
882 return out;
883 }
884
890 [[nodiscard]] bool verify() const
891 {
892 if (root_ == nullptr)
893 return size_ == 0;
894
895 auto leaf_depth = static_cast<size_t>(-1);
896 size_t counted = 0;
897 return verify_node(root_.get(), std::nullopt, std::nullopt, 1, leaf_depth, counted) and counted == size_;
898 }
899};
900
906template <typename Key, class Compare = Aleph::less<Key>, size_t MinDegree = 16>
908} // namespace Aleph
909
910#endif // TPL_B_TREE_H
C++20 concepts for constraining comparison functors.
Exception handling system with formatted messages for Aleph-w.
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
Definition ah-errors.H:250
Standard functor implementations and comparison objects.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:351
constexpr bool is_empty() const noexcept
Checks if the container is empty.
Definition tpl_array.H:348
T & get_first() noexcept
return a modifiable reference to the first element.
Definition tpl_array.H:358
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:245
T & get_last() noexcept
return a modifiable reference to the last element.
Definition tpl_array.H:366
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:315
void putn(const size_t n)
Reserve n additional logical slots in the array without value-initializing them.
Definition tpl_array.H:305
Generic filter iterator wrapper.
Generic B-Tree with configurable minimum degree.
Definition tpl_b_tree.H:134
void borrow_from_next(Node *parent, const size_t idx)
Definition tpl_b_tree.H:369
bool remove(const Key &key)
Remove a key if present.
Definition tpl_b_tree.H:768
Gen_B_Tree(It first, It last, const Compare &cmp=Compare())
Construct a B-Tree from an iterator range.
Definition tpl_b_tree.H:570
size_t height() const noexcept
Return the current tree height.
Definition tpl_b_tree.H:679
bool insert(Key &&key)
Insert a key by move if it is not already present.
Definition tpl_b_tree.H:756
size_t upper_bound_index(const Array< Key > &keys, const Key &key) const
Definition tpl_b_tree.H:161
void insert_range(It first, It last)
Definition tpl_b_tree.H:180
static void append_move_range(Array< T > &dst, Array< T > &src, const size_t from)
Definition tpl_b_tree.H:225
Gen_B_Tree & operator=(const Gen_B_Tree &other)
Copy assignment.
Definition tpl_b_tree.H:603
bool contains_in(const Node *node, const Key &key) const
Definition tpl_b_tree.H:261
void split_child(Node *parent, const size_t idx)
Definition tpl_b_tree.H:276
const Compare & key_comp() const noexcept
Return the comparison object (read-only).
Definition tpl_b_tree.H:629
std::unique_ptr< Node > clone_node(const Node *node) const
Definition tpl_b_tree.H:232
std::optional< Key > max_key() const
Return the maximum key, if any.
Definition tpl_b_tree.H:818
bool verify_node(const Node *node, const std::optional< Key > &min_key, const std::optional< Key > &max_key, const size_t depth, size_t &leaf_depth, size_t &counted) const
Definition tpl_b_tree.H:491
size_t height_of(const Node *node) const noexcept
Definition tpl_b_tree.H:248
Gen_B_Tree(Gen_B_Tree &&other)=default
Move constructor.
std::optional< Key > lower_bound(const Key &key) const
Return the first key not less than key.
Definition tpl_b_tree.H:829
const Compare & get_compare() const noexcept
Return the comparison object (read-only).
Definition tpl_b_tree.H:639
bool search(const Key &key) const
Synonym for contains().
Definition tpl_b_tree.H:711
bool insert(const Key &key)
Insert a key if it is not already present.
Definition tpl_b_tree.H:723
void borrow_from_prev(Node *parent, const size_t idx)
Definition tpl_b_tree.H:353
bool empty() const noexcept
Return whether the tree has no keys.
Definition tpl_b_tree.H:649
static constexpr size_t MinKeys
Definition tpl_b_tree.H:141
bool is_empty() const noexcept
Synonym for empty() in traditional Aleph style.
Definition tpl_b_tree.H:659
void insert_nonfull(Node *node, const Key &key)
Definition tpl_b_tree.H:296
std::optional< Key > min_key() const
Return the minimum key, if any.
Definition tpl_b_tree.H:808
bool equals(const Key &lhs, const Key &rhs) const
Definition tpl_b_tree.H:175
std::optional< Key > max_in(const Node *node) const
Definition tpl_b_tree.H:334
size_t lower_bound_index(const Array< Key > &keys, const Key &key) const
Definition tpl_b_tree.H:147
bool verify() const
Verify structural B-Tree invariants.
Definition tpl_b_tree.H:890
bool contains(const Key &key) const
Return whether a key is present.
Definition tpl_b_tree.H:700
Gen_B_Tree(std::initializer_list< Key > init, const Compare &cmp=Compare())
Construct a B-Tree from an initializer list.
Definition tpl_b_tree.H:581
Gen_B_Tree(const Gen_B_Tree &other)
Copy constructor performing a deep copy.
Definition tpl_b_tree.H:590
void clear() noexcept
Remove every key from the tree.
Definition tpl_b_tree.H:688
bool remove_from(Node *node, const Key &key)
Definition tpl_b_tree.H:427
Key key_type
Stored key type.
Definition tpl_b_tree.H:554
std::unique_ptr< Node > root_
Definition tpl_b_tree.H:143
static void append_copy_range(Array< T > &dst, const Array< T > &src, const size_t from)
Definition tpl_b_tree.H:218
static T erase_at(Array< T > &array, const size_t idx)
Definition tpl_b_tree.H:200
void collect_keys(const Node *node, Array< Key > &out) const
Definition tpl_b_tree.H:471
Gen_B_Tree(const Compare &cmp=Compare())
Construct an empty B-Tree.
Definition tpl_b_tree.H:561
Array< Key > keys() const
Materialize the tree contents in sorted order.
Definition tpl_b_tree.H:877
void merge_children(Node *parent, const size_t idx)
Definition tpl_b_tree.H:385
size_t ensure_child_has_extra(Node *parent, const size_t idx)
Definition tpl_b_tree.H:400
static void truncate(Array< T > &array, const size_t new_size)
Definition tpl_b_tree.H:212
static constexpr size_t MaxKeys
Definition tpl_b_tree.H:140
std::optional< Key > min_in(const Node *node) const
Definition tpl_b_tree.H:315
static void insert_at(Array< T > &array, const size_t idx, U &&value)
Definition tpl_b_tree.H:186
Gen_B_Tree & operator=(Gen_B_Tree &&other)=default
Move assignment.
std::optional< Key > upper_bound(const Key &key) const
Return the first key strictly greater than key.
Definition tpl_b_tree.H:853
size_t size() const noexcept
Return the number of stored keys.
Definition tpl_b_tree.H:669
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4118
Freq_Node * pred
Predecessor node in level-order traversal.
bool equiv(const Compare &cmp, const Key &lhs, const Key &rhs)
Definition tpl_b_tree.H:68
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
Definition ahAlgo.H:584
const T * median(const T &a, const T &b, const T &c, const Compare &cmp=Compare())
Return a pointer to the median value among three elements.
Definition ahUtils.H:84
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
void open_gap(Tarray &ptr, size_t n, size_t pos=0, size_t num_entries=1)
Open a gap in an array by shifting elements right.
Definition array_utils.H:96
static bool is_leaf(BinNode< std::string > *p) noexcept
Definition Huffman.H:111
static std::atomic< bool > init
Definition hash-fct.C:53
void close_gap(T *ptr, size_t n, size_t pos, size_t num_entries=1)
Close a gap in an array by shifting elements left.
BTreeNode(const bool is_leaf)
Definition tpl_b_tree.H:79
Array< std::unique_ptr< BTreeNode > > children
Definition tpl_b_tree.H:77
Aleph::DynList< T > keys() const
Definition ah-dry.H:1729
Dynamic array container with automatic resizing.
Comprehensive sorting algorithms and search utilities for Aleph-w.