49#ifndef TPL_BPLUS_TREE_H
50#define TPL_BPLUS_TREE_H
54#include <initializer_list>
68template <
typename Compare,
typename Key>
132template <
typename Key,
class Compare = Aleph::less<Key>,
size_t MinDegree = 16>
136 static_assert(
MinDegree >= 2,
"BPlus_Tree requires MinDegree >= 2");
137 static_assert(std::copy_constructible<Key>,
"BPlus_Tree requires copy-constructible keys");
176 for (
size_t i = 1; i <
keys.
size(); ++i)
184 for (; first != last; ++first)
188 template <
typename T,
typename U>
static void insert_at(
Array<T> &array,
const size_t idx,
U &&value)
190 if (idx == array.
size())
192 array.
append(std::forward<U>(value));
199 array(idx) = std::forward<U>(value);
204 T ret = std::move(array(idx));
205 if (idx + 1 < array.
size())
223 for (
size_t i = from; i < src.
size(); ++i)
230 for (
size_t i = from; i < src.
size(); ++i)
231 dst.append(std::move(src(i)));
236 const Node *curr = node;
238 curr = curr->
children.get_first().get();
244 const Node *curr = node;
246 curr = curr->
children.get_last().get();
276 for (
const Node *curr = node; curr !=
nullptr;)
279 if (curr->leaf
or curr->children.is_empty())
281 curr = curr->children.get_first().get();
288 if (node ==
nullptr or node->
leaf)
293 for (
size_t i = 1; i < node->
children.size(); ++i)
302 auto copy = std::make_unique<Node>(node->
leaf);
314 for (
const auto &child : node->
children)
344 auto right = std::make_unique<Node>(child->
leaf);
351 right->next = child->
next;
352 child->
next = right.get();
468 if (idx + 1 < parent->
children.size())
499 std::optional<Key> prev;
501 while (leaf !=
nullptr)
506 for (
const auto &key : leaf->
keys)
508 if (prev.has_value()
and not cmp_(*prev, key))
514 if (leaf->
next !=
nullptr)
529 const size_t depth,
size_t &leaf_depth,
size_t &
counted)
const
534 if (node !=
root_.get())
555 if (leaf_depth ==
static_cast<size_t>(-1))
557 return leaf_depth == depth;
563 for (
size_t i = 1; i < node->
children.size(); ++i)
570 for (
size_t i = 0; i < node->
children.size(); ++i)
585 if (first ==
nullptr or last ==
nullptr)
660 <<
"BPlus_Tree::Iterator(): invalid range (last < first)";
663 if (
leaf_ !=
nullptr)
888 if (
root_ ==
nullptr)
890 root_ = std::make_unique<Node>(
true);
891 root_->keys.append(key);
898 auto new_root = std::make_unique<Node>(
false);
918 Key
copy = std::move(key);
929 if (
root_ ==
nullptr)
941 root_ = std::move(
root_->children.get_first());
982 while (leaf !=
nullptr)
985 return leaf->
keys[idx];
1001 if (leaf ==
nullptr)
1002 return std::nullopt;
1005 while (leaf !=
nullptr)
1008 return leaf->
keys[idx];
1013 return std::nullopt;
1034 return Iterator(*
this, first, last);
1050 out.append(it.get_curr());
1065 out.append(it.get_curr());
1076 if (
root_ ==
nullptr)
1079 if (
root_->keys.is_empty())
1082 auto leaf_depth =
static_cast<size_t>(-1);
1094template <
typename Key,
class Compare = Aleph::less<Key>,
size_t MinDegree = 16>
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.
#define ah_underflow_error_if(C)
Throws std::underflow_error if condition holds.
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
Standard functor implementations and comparison objects.
Simple dynamic array with automatic resizing and functional operations.
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
void empty() noexcept
Empties the container.
constexpr bool is_empty() const noexcept
Checks if the container is empty.
T & get_first() noexcept
return a modifiable reference to the first element.
T & append(const T &data)
Append a copy of data
T & get_last() noexcept
return a modifiable reference to the last element.
void reserve(size_t cap)
Reserves cap cells into the array.
void putn(const size_t n)
Reserve n additional logical slots in the array without value-initializing them.
Generic filter iterator wrapper.
Lazy iterator over ordered leaf keys.
void next()
Synonym for next_ne().
const Key * operator->() const
Member-access shorthand for the current key.
const Gen_BPlus_Tree * tree_
void next_ne()
Advance to the next key.
bool has_curr() const noexcept
Return whether the iterator still points to a key.
Iterator(const Gen_BPlus_Tree &tree, const Key &first, const Key &last)
Construct an iterator over the inclusive range [first, last].
Iterator() noexcept=default
Construct an exhausted iterator.
const Key & operator*() const
Dereference the iterator.
std::optional< Key > last_
const Key & get_curr() const
Return the current key.
Generic B+ Tree with configurable minimum degree.
Gen_BPlus_Tree & operator=(const Gen_BPlus_Tree &other)
Copy assignment.
const Key * subtree_max_ptr(const Node *node) const noexcept
const Node * rightmost_leaf(const Node *node) const noexcept
size_t upper_bound_index(const Array< Key > &keys, const Key &key) const
void merge_children(Node *parent, const size_t left_idx)
void fix_underflow(Node *parent, const size_t idx)
static T erase_at(Array< T > &array, const size_t idx)
std::optional< Key > lower_bound(const Key &key) const
Return the first key not less than key.
bool verify_leaf_chain() const
Gen_BPlus_Tree(const Compare &cmp=Compare())
Construct an empty B+ Tree.
size_t height() const noexcept
Return the current tree height.
bool remove(const Key &key)
Remove a key if present.
bool search(const Key &key) const
Synonym for contains().
Array< Key > keys() const
Materialize the tree contents in sorted order.
size_t lower_bound_index(const Array< Key > &keys, const Key &key) const
bool empty() const noexcept
Return whether the tree has no keys.
void rebuild_separators(Node *node) const
static constexpr size_t MaxKeys
Gen_BPlus_Tree(It first, It last, const Compare &cmp=Compare())
Construct a B+ Tree from an iterator range.
std::unique_ptr< Node > root_
std::optional< Key > max_key() const
Return the maximum key, if any.
bool verify() const
Verify structural B+ Tree invariants.
static void append_move_range(Array< T > &dst, Array< T > &src, const size_t from)
bool insert(const Key &key)
Insert a key if it is not already present.
Gen_BPlus_Tree(const Gen_BPlus_Tree &other)
Copy constructor performing a deep copy.
void insert_nonfull(Node *node, const Key &key)
void split_child(Node *parent, const size_t idx)
const Compare & get_compare() const noexcept
Return the comparison object (read-only).
bool remove_from(Node *node, const Key &key)
Gen_BPlus_Tree(std::initializer_list< Key > init, const Compare &cmp=Compare())
Construct a B+ Tree from an initializer list.
const Key * subtree_min_ptr(const Node *node) const noexcept
static void append_copy_range(Array< T > &dst, const Array< T > &src, const size_t from)
Gen_BPlus_Tree(Gen_BPlus_Tree &&other)=default
Move constructor.
std::optional< Key > min_key() const
Return the minimum key, if any.
void clear() noexcept
Remove every key from the tree.
Key key_type
Stored key type.
const Key & subtree_min(const Node *node) const
bool contains_in(const Node *node, const Key &key) const
const Compare & key_comp() const noexcept
Return the comparison object (read-only).
const Node * find_leaf(const Key &key) const
bool is_empty() const noexcept
Synonym for empty() in traditional Aleph style.
size_t height_of(const Node *node) const noexcept
Gen_BPlus_Tree & operator=(Gen_BPlus_Tree &&other)=default
Move assignment.
void borrow_from_next(Node *parent, const size_t idx)
static void truncate(Array< T > &array, const size_t new_size)
std::optional< Key > upper_bound(const Key &key) const
Return the first key strictly greater than key.
size_t size() const noexcept
Return the number of stored keys.
Iterator get_it() const noexcept
Return a lazy iterator over the full key order.
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
bool strictly_sorted(const Array< Key > &keys) const
static constexpr size_t MinKeys
bool insert(Key &&key)
Insert a key by move if it is not already present.
bool contains(const Key &key) const
Return whether a key is present.
Iterator get_range_it(const Key &first, const Key &last) const
Return a lazy iterator over an inclusive key range.
static void insert_at(Array< T > &array, const size_t idx, U &&value)
const Node * leftmost_leaf(const Node *node) const noexcept
std::unique_ptr< Node > clone_node(const Node *node, Node *&prev_leaf) const
void insert_range(It first, It last)
size_t child_index(const Node *node, const Key &key) const
Array< Key > range(const Key &first, const Key &last) const
Collect all keys in the inclusive range [first, last].
bool equals(const Key &lhs, const Key &rhs) const
void borrow_from_prev(Node *parent, const size_t idx)
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
bool bplus_equiv(const Compare &cmp, const Key &lhs, const Key &rhs)
Main namespace for Aleph-w library functions.
and
Check uniqueness with explicit hash + equality functors.
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
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
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.
static bool is_leaf(BinNode< std::string > *p) noexcept
static std::atomic< bool > init
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.
BPlusTreeNode(const bool is_leaf)
Array< std::unique_ptr< BPlusTreeNode > > children
Aleph::DynList< T > keys() const
Dynamic array container with automatic resizing.
Comprehensive sorting algorithms and search utilities for Aleph-w.