In btree, move rightmost_ into the CompressedTuple instead of root_.

We also add accessors for rightmost()/mutable_rightmost().

PiperOrigin-RevId: 446515231
Change-Id: I4b8cb46f4bd209a0f51dcdcb96c9479e480828a3
pull/1163/merge
Evan Brown 3 years ago committed by Copybara-Service
parent 981e2c8880
commit 02934b4921
  1. 85
      absl/container/internal/btree.h

@ -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);
}

Loading…
Cancel
Save