|
|
|
@ -191,8 +191,8 @@ struct key_compare_adapter { |
|
|
|
|
// Inherit from checked_compare_base to support function pointers and also
|
|
|
|
|
// keep empty-base-optimization (EBO) support for classes.
|
|
|
|
|
// Note: we can't use CompressedTuple here because that would interfere
|
|
|
|
|
// with the EBO for `btree::root_`. `btree::root_` is itself a CompressedTuple
|
|
|
|
|
// and nested `CompressedTuple`s don't support EBO.
|
|
|
|
|
// with the EBO for `btree::rightmost_`. `btree::rightmost_` is itself a
|
|
|
|
|
// CompressedTuple and nested `CompressedTuple`s don't support EBO.
|
|
|
|
|
// TODO(b/214288561): use CompressedTuple instead once it supports EBO for
|
|
|
|
|
// nested `CompressedTuple`s.
|
|
|
|
|
struct checked_compare : checked_compare_base<Compare> { |
|
|
|
@ -1329,7 +1329,7 @@ class btree { |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
btree(const key_compare &comp, const allocator_type &alloc) |
|
|
|
|
: root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {} |
|
|
|
|
: root_(EmptyNode()), rightmost_(comp, alloc, EmptyNode()), size_(0) {} |
|
|
|
|
|
|
|
|
|
btree(const btree &other) : btree(other, other.allocator()) {} |
|
|
|
|
btree(const btree &other, const allocator_type &alloc) |
|
|
|
@ -1337,10 +1337,10 @@ class btree { |
|
|
|
|
copy_or_move_values_in_order(other); |
|
|
|
|
} |
|
|
|
|
btree(btree &&other) noexcept |
|
|
|
|
: root_(std::move(other.root_)), |
|
|
|
|
rightmost_(absl::exchange(other.rightmost_, EmptyNode())), |
|
|
|
|
: root_(absl::exchange(other.root_, EmptyNode())), |
|
|
|
|
rightmost_(std::move(other.rightmost_)), |
|
|
|
|
size_(absl::exchange(other.size_, 0)) { |
|
|
|
|
other.mutable_root() = EmptyNode(); |
|
|
|
|
other.mutable_rightmost() = EmptyNode(); |
|
|
|
|
} |
|
|
|
|
btree(btree &&other, const allocator_type &alloc) |
|
|
|
|
: btree(other.key_comp(), alloc) { |
|
|
|
@ -1365,9 +1365,9 @@ class btree { |
|
|
|
|
|
|
|
|
|
iterator begin() { return iterator(leftmost()); } |
|
|
|
|
const_iterator begin() const { return const_iterator(leftmost()); } |
|
|
|
|
iterator end() { return iterator(rightmost_, rightmost_->finish()); } |
|
|
|
|
iterator end() { return iterator(rightmost(), rightmost()->finish()); } |
|
|
|
|
const_iterator end() const { |
|
|
|
|
return const_iterator(rightmost_, rightmost_->finish()); |
|
|
|
|
return const_iterator(rightmost(), rightmost()->finish()); |
|
|
|
|
} |
|
|
|
|
reverse_iterator rbegin() { return reverse_iterator(end()); } |
|
|
|
|
const_reverse_iterator rbegin() const { |
|
|
|
@ -1493,7 +1493,7 @@ class btree { |
|
|
|
|
void swap(btree &other); |
|
|
|
|
|
|
|
|
|
const key_compare &key_comp() const noexcept { |
|
|
|
|
return root_.template get<0>(); |
|
|
|
|
return rightmost_.template get<0>(); |
|
|
|
|
} |
|
|
|
|
template <typename K1, typename K2> |
|
|
|
|
bool compare_keys(const K1 &a, const K2 &b) const { |
|
|
|
@ -1587,10 +1587,17 @@ class btree { |
|
|
|
|
friend struct btree_access; |
|
|
|
|
|
|
|
|
|
// Internal accessor routines.
|
|
|
|
|
node_type *root() { return root_.template get<2>(); } |
|
|
|
|
const node_type *root() const { return root_.template get<2>(); } |
|
|
|
|
node_type *&mutable_root() noexcept { return root_.template get<2>(); } |
|
|
|
|
key_compare *mutable_key_comp() noexcept { return &root_.template get<0>(); } |
|
|
|
|
node_type *root() { return root_; } |
|
|
|
|
const node_type *root() const { return root_; } |
|
|
|
|
node_type *&mutable_root() noexcept { return root_; } |
|
|
|
|
node_type *rightmost() { return rightmost_.template get<2>(); } |
|
|
|
|
const node_type *rightmost() const { return rightmost_.template get<2>(); } |
|
|
|
|
node_type *&mutable_rightmost() noexcept { |
|
|
|
|
return rightmost_.template get<2>(); |
|
|
|
|
} |
|
|
|
|
key_compare *mutable_key_comp() noexcept { |
|
|
|
|
return &rightmost_.template get<0>(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// The leftmost node is stored as the parent of the root node.
|
|
|
|
|
node_type *leftmost() { return root()->parent(); } |
|
|
|
@ -1598,10 +1605,10 @@ class btree { |
|
|
|
|
|
|
|
|
|
// Allocator routines.
|
|
|
|
|
allocator_type *mutable_allocator() noexcept { |
|
|
|
|
return &root_.template get<1>(); |
|
|
|
|
return &rightmost_.template get<1>(); |
|
|
|
|
} |
|
|
|
|
const allocator_type &allocator() const noexcept { |
|
|
|
|
return root_.template get<1>(); |
|
|
|
|
return rightmost_.template get<1>(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Allocates a correctly aligned node of at least size bytes using the
|
|
|
|
@ -1709,15 +1716,14 @@ class btree { |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// We use compressed tuple in order to save space because key_compare and
|
|
|
|
|
// allocator_type are usually empty.
|
|
|
|
|
absl::container_internal::CompressedTuple<key_compare, allocator_type, |
|
|
|
|
node_type *> |
|
|
|
|
root_; |
|
|
|
|
node_type *root_; |
|
|
|
|
|
|
|
|
|
// A pointer to the rightmost node. Note that the leftmost node is stored as
|
|
|
|
|
// the root's parent.
|
|
|
|
|
node_type *rightmost_; |
|
|
|
|
// the root's parent. We use compressed tuple in order to save space because
|
|
|
|
|
// key_compare and allocator_type are usually empty.
|
|
|
|
|
absl::container_internal::CompressedTuple<key_compare, allocator_type, |
|
|
|
|
node_type *> |
|
|
|
|
rightmost_; |
|
|
|
|
|
|
|
|
|
// Number of values.
|
|
|
|
|
size_type size_; |
|
|
|
@ -2141,7 +2147,7 @@ template <typename K, typename... Args> |
|
|
|
|
auto btree<P>::insert_unique(const K &key, Args &&... args) |
|
|
|
|
-> std::pair<iterator, bool> { |
|
|
|
|
if (empty()) { |
|
|
|
|
mutable_root() = rightmost_ = new_leaf_root_node(1); |
|
|
|
|
mutable_root() = mutable_rightmost() = new_leaf_root_node(1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key); |
|
|
|
@ -2208,7 +2214,7 @@ template <typename P> |
|
|
|
|
template <typename ValueType> |
|
|
|
|
auto btree<P>::insert_multi(const key_type &key, ValueType &&v) -> iterator { |
|
|
|
|
if (empty()) { |
|
|
|
|
mutable_root() = rightmost_ = new_leaf_root_node(1); |
|
|
|
|
mutable_root() = mutable_rightmost() = new_leaf_root_node(1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
iterator iter = internal_upper_bound(key); |
|
|
|
@ -2272,15 +2278,15 @@ auto btree<P>::operator=(btree &&other) noexcept -> btree & { |
|
|
|
|
using std::swap; |
|
|
|
|
if (absl::allocator_traits< |
|
|
|
|
allocator_type>::propagate_on_container_copy_assignment::value) { |
|
|
|
|
// Note: `root_` also contains the allocator and the key comparator.
|
|
|
|
|
swap(root_, other.root_); |
|
|
|
|
// Note: `rightmost_` also contains the allocator and the key comparator.
|
|
|
|
|
swap(rightmost_, other.rightmost_); |
|
|
|
|
swap(size_, other.size_); |
|
|
|
|
} else { |
|
|
|
|
if (allocator() == other.allocator()) { |
|
|
|
|
swap(mutable_root(), other.mutable_root()); |
|
|
|
|
swap(*mutable_key_comp(), *other.mutable_key_comp()); |
|
|
|
|
swap(rightmost_, other.rightmost_); |
|
|
|
|
swap(mutable_rightmost(), other.mutable_rightmost()); |
|
|
|
|
swap(size_, other.size_); |
|
|
|
|
} else { |
|
|
|
|
// We aren't allowed to propagate the allocator and the allocator is
|
|
|
|
@ -2422,8 +2428,7 @@ void btree<P>::clear() { |
|
|
|
|
if (!empty()) { |
|
|
|
|
node_type::clear_and_delete(root(), mutable_allocator()); |
|
|
|
|
} |
|
|
|
|
mutable_root() = EmptyNode(); |
|
|
|
|
rightmost_ = EmptyNode(); |
|
|
|
|
mutable_root() = mutable_rightmost() = EmptyNode(); |
|
|
|
|
size_ = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -2432,15 +2437,15 @@ void btree<P>::swap(btree &other) { |
|
|
|
|
using std::swap; |
|
|
|
|
if (absl::allocator_traits< |
|
|
|
|
allocator_type>::propagate_on_container_swap::value) { |
|
|
|
|
// Note: `root_` also contains the allocator and the key comparator.
|
|
|
|
|
swap(root_, other.root_); |
|
|
|
|
// Note: `rightmost_` also contains the allocator and the key comparator.
|
|
|
|
|
swap(rightmost_, other.rightmost_); |
|
|
|
|
} else { |
|
|
|
|
// It's undefined behavior if the allocators are unequal here.
|
|
|
|
|
assert(allocator() == other.allocator()); |
|
|
|
|
swap(mutable_root(), other.mutable_root()); |
|
|
|
|
swap(mutable_rightmost(), other.mutable_rightmost()); |
|
|
|
|
swap(*mutable_key_comp(), *other.mutable_key_comp()); |
|
|
|
|
} |
|
|
|
|
swap(rightmost_, other.rightmost_); |
|
|
|
|
swap(mutable_root(), other.mutable_root()); |
|
|
|
|
swap(size_, other.size_); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -2448,12 +2453,12 @@ template <typename P> |
|
|
|
|
void btree<P>::verify() const { |
|
|
|
|
assert(root() != nullptr); |
|
|
|
|
assert(leftmost() != nullptr); |
|
|
|
|
assert(rightmost_ != nullptr); |
|
|
|
|
assert(rightmost() != nullptr); |
|
|
|
|
assert(empty() || size() == internal_verify(root(), nullptr, nullptr)); |
|
|
|
|
assert(leftmost() == (++const_iterator(root(), -1)).node_); |
|
|
|
|
assert(rightmost_ == (--const_iterator(root(), root()->finish())).node_); |
|
|
|
|
assert(rightmost() == (--const_iterator(root(), root()->finish())).node_); |
|
|
|
|
assert(leftmost()->is_leaf()); |
|
|
|
|
assert(rightmost_->is_leaf()); |
|
|
|
|
assert(rightmost()->is_leaf()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename P> |
|
|
|
@ -2539,7 +2544,7 @@ void btree<P>::rebalance_or_split(iterator *iter) { |
|
|
|
|
mutable_root() = parent; |
|
|
|
|
// If the former root was a leaf node, then it's now the rightmost node.
|
|
|
|
|
assert(parent->start_child()->is_internal() || |
|
|
|
|
parent->start_child() == rightmost_); |
|
|
|
|
parent->start_child() == rightmost()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Split the node.
|
|
|
|
@ -2547,7 +2552,7 @@ void btree<P>::rebalance_or_split(iterator *iter) { |
|
|
|
|
if (node->is_leaf()) { |
|
|
|
|
split_node = new_leaf_node(parent); |
|
|
|
|
node->split(insert_position, split_node, mutable_allocator()); |
|
|
|
|
if (rightmost_ == node) rightmost_ = split_node; |
|
|
|
|
if (rightmost() == node) mutable_rightmost() = split_node; |
|
|
|
|
} else { |
|
|
|
|
split_node = new_internal_node(parent); |
|
|
|
|
node->split(insert_position, split_node, mutable_allocator()); |
|
|
|
@ -2562,7 +2567,7 @@ void btree<P>::rebalance_or_split(iterator *iter) { |
|
|
|
|
template <typename P> |
|
|
|
|
void btree<P>::merge_nodes(node_type *left, node_type *right) { |
|
|
|
|
left->merge(right, mutable_allocator()); |
|
|
|
|
if (rightmost_ == right) rightmost_ = left; |
|
|
|
|
if (rightmost() == right) mutable_rightmost() = left; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename P> |
|
|
|
@ -2627,7 +2632,7 @@ void btree<P>::try_shrink() { |
|
|
|
|
// Deleted the last item on the root node, shrink the height of the tree.
|
|
|
|
|
if (orig_root->is_leaf()) { |
|
|
|
|
assert(size() == 0); |
|
|
|
|
mutable_root() = rightmost_ = EmptyNode(); |
|
|
|
|
mutable_root() = mutable_rightmost() = EmptyNode(); |
|
|
|
|
} else { |
|
|
|
|
node_type *child = orig_root->start_child(); |
|
|
|
|
child->make_root(); |
|
|
|
@ -2681,7 +2686,7 @@ inline auto btree<P>::internal_emplace(iterator iter, Args &&... args) |
|
|
|
|
old_root->set_finish(old_root->start()); |
|
|
|
|
new_root->set_generation(old_root->generation()); |
|
|
|
|
node_type::clear_and_delete(old_root, alloc); |
|
|
|
|
mutable_root() = rightmost_ = new_root; |
|
|
|
|
mutable_root() = mutable_rightmost() = new_root; |
|
|
|
|
} else { |
|
|
|
|
rebalance_or_split(&iter); |
|
|
|
|
} |
|
|
|
|