aboutsummaryrefslogtreecommitdiff
path: root/absl/container/internal/btree.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/container/internal/btree.h')
-rw-r--r--absl/container/internal/btree.h151
1 files changed, 103 insertions, 48 deletions
diff --git a/absl/container/internal/btree.h b/absl/container/internal/btree.h
index 5000d1c3..d734676a 100644
--- a/absl/container/internal/btree.h
+++ b/absl/container/internal/btree.h
@@ -1017,8 +1017,61 @@ class btree_node {
friend struct btree_access;
};
+template <typename Node>
+bool AreNodesFromSameContainer(const Node *node_a, const Node *node_b) {
+ // If either node is null, then give up on checking whether they're from the
+ // same container. (If exactly one is null, then we'll trigger the
+ // default-constructed assert in Equals.)
+ if (node_a == nullptr || node_b == nullptr) return true;
+ while (!node_a->is_root()) node_a = node_a->parent();
+ while (!node_b->is_root()) node_b = node_b->parent();
+ return node_a == node_b;
+}
+
+class btree_iterator_generation_info_enabled {
+ public:
+ explicit btree_iterator_generation_info_enabled(uint32_t g)
+ : generation_(g) {}
+
+ // Updates the generation. For use internally right before we return an
+ // iterator to the user.
+ template <typename Node>
+ void update_generation(const Node *node) {
+ if (node != nullptr) generation_ = node->generation();
+ }
+ uint32_t generation() const { return generation_; }
+
+ template <typename Node>
+ void assert_valid_generation(const Node *node) const {
+ if (node != nullptr && node->generation() != generation_) {
+ ABSL_INTERNAL_LOG(
+ FATAL,
+ "Attempting to use an invalidated iterator. The corresponding b-tree "
+ "container has been mutated since this iterator was constructed.");
+ }
+ }
+
+ private:
+ // Used to check that the iterator hasn't been invalidated.
+ uint32_t generation_;
+};
+
+class btree_iterator_generation_info_disabled {
+ public:
+ explicit btree_iterator_generation_info_disabled(uint32_t) {}
+ void update_generation(const void *) {}
+ uint32_t generation() const { return 0; }
+ void assert_valid_generation(const void *) const {}
+};
+
+#ifdef ABSL_BTREE_ENABLE_GENERATIONS
+using btree_iterator_generation_info = btree_iterator_generation_info_enabled;
+#else
+using btree_iterator_generation_info = btree_iterator_generation_info_disabled;
+#endif
+
template <typename Node, typename Reference, typename Pointer>
-class btree_iterator {
+class btree_iterator : private btree_iterator_generation_info {
using field_type = typename Node::field_type;
using key_type = typename Node::key_type;
using size_type = typename Node::size_type;
@@ -1049,13 +1102,11 @@ class btree_iterator {
btree_iterator() : btree_iterator(nullptr, -1) {}
explicit btree_iterator(Node *n) : btree_iterator(n, n->start()) {}
- btree_iterator(Node *n, int p) : node_(n), position_(p) {
-#ifdef ABSL_BTREE_ENABLE_GENERATIONS
- // Use `~uint32_t{}` as a sentinel value for iterator generations so it
- // doesn't match the initial value for the actual generation.
- generation_ = n != nullptr ? n->generation() : ~uint32_t{};
-#endif
- }
+ btree_iterator(Node *n, int p)
+ : btree_iterator_generation_info(n != nullptr ? n->generation()
+ : ~uint32_t{}),
+ node_(n),
+ position_(p) {}
// NOTE: this SFINAE allows for implicit conversions from iterator to
// const_iterator, but it specifically avoids hiding the copy constructor so
@@ -1066,23 +1117,21 @@ class btree_iterator {
std::is_same<btree_iterator, const_iterator>::value,
int> = 0>
btree_iterator(const btree_iterator<N, R, P> other) // NOLINT
- : node_(other.node_), position_(other.position_) {
-#ifdef ABSL_BTREE_ENABLE_GENERATIONS
- generation_ = other.generation_;
-#endif
- }
+ : btree_iterator_generation_info(other),
+ node_(other.node_),
+ position_(other.position_) {}
bool operator==(const iterator &other) const {
- return node_ == other.node_ && position_ == other.position_;
+ return Equals(other);
}
bool operator==(const const_iterator &other) const {
- return node_ == other.node_ && position_ == other.position_;
+ return Equals(other);
}
bool operator!=(const iterator &other) const {
- return node_ != other.node_ || position_ != other.position_;
+ return !Equals(other);
}
bool operator!=(const const_iterator &other) const {
- return node_ != other.node_ || position_ != other.position_;
+ return !Equals(other);
}
// Returns n such that n calls to ++other yields *this.
@@ -1098,9 +1147,12 @@ class btree_iterator {
// Accessors for the key/value the iterator is pointing at.
reference operator*() const {
ABSL_HARDENING_ASSERT(node_ != nullptr);
- ABSL_HARDENING_ASSERT(node_->start() <= position_);
- ABSL_HARDENING_ASSERT(node_->finish() > position_);
- assert_valid_generation();
+ assert_valid_generation(node_);
+ ABSL_HARDENING_ASSERT(position_ >= node_->start());
+ if (position_ >= node_->finish()) {
+ ABSL_HARDENING_ASSERT(!IsEndIterator() && "Dereferencing end() iterator");
+ ABSL_HARDENING_ASSERT(position_ < node_->finish());
+ }
return node_->value(static_cast<field_type>(position_));
}
pointer operator->() const { return &operator*(); }
@@ -1151,11 +1203,33 @@ class btree_iterator {
std::is_same<btree_iterator, iterator>::value,
int> = 0>
explicit btree_iterator(const btree_iterator<N, R, P> other)
- : node_(const_cast<node_type *>(other.node_)),
- position_(other.position_) {
-#ifdef ABSL_BTREE_ENABLE_GENERATIONS
- generation_ = other.generation_;
-#endif
+ : btree_iterator_generation_info(other.generation()),
+ node_(const_cast<node_type *>(other.node_)),
+ position_(other.position_) {}
+
+ bool Equals(const const_iterator other) const {
+ ABSL_HARDENING_ASSERT(((node_ == nullptr && other.node_ == nullptr) ||
+ (node_ != nullptr && other.node_ != nullptr)) &&
+ "Comparing default-constructed iterator with "
+ "non-default-constructed iterator.");
+ // Note: we use assert instead of ABSL_HARDENING_ASSERT here because this
+ // changes the complexity of Equals from O(1) to O(log(N) + log(M)) where
+ // N/M are sizes of the containers containing node_/other.node_.
+ assert(AreNodesFromSameContainer(node_, other.node_) &&
+ "Comparing iterators from different containers.");
+ assert_valid_generation(node_);
+ other.assert_valid_generation(other.node_);
+ return node_ == other.node_ && position_ == other.position_;
+ }
+
+ bool IsEndIterator() const {
+ if (position_ != node_->finish()) return false;
+ node_type *node = node_;
+ while (!node->is_root()) {
+ if (node->position() != node->parent()->finish()) return false;
+ node = node->parent();
+ }
+ return true;
}
// Returns n such that n calls to ++other yields *this.
@@ -1165,7 +1239,7 @@ class btree_iterator {
// Increment/decrement the iterator.
void increment() {
- assert_valid_generation();
+ assert_valid_generation(node_);
if (node_->is_leaf() && ++position_ < node_->finish()) {
return;
}
@@ -1174,7 +1248,7 @@ class btree_iterator {
void increment_slow();
void decrement() {
- assert_valid_generation();
+ assert_valid_generation(node_);
if (node_->is_leaf() && --position_ >= node_->start()) {
return;
}
@@ -1182,14 +1256,6 @@ class btree_iterator {
}
void decrement_slow();
- // Updates the generation. For use internally right before we return an
- // iterator to the user.
- void update_generation() {
-#ifdef ABSL_BTREE_ENABLE_GENERATIONS
- if (node_ != nullptr) generation_ = node_->generation();
-#endif
- }
-
const key_type &key() const {
return node_->key(static_cast<size_type>(position_));
}
@@ -1197,15 +1263,8 @@ class btree_iterator {
return node_->slot(static_cast<size_type>(position_));
}
- void assert_valid_generation() const {
-#ifdef ABSL_BTREE_ENABLE_GENERATIONS
- if (node_ != nullptr && node_->generation() != generation_) {
- ABSL_INTERNAL_LOG(
- FATAL,
- "Attempting to use an invalidated iterator. The corresponding b-tree "
- "container has been mutated since this iterator was constructed.");
- }
-#endif
+ void update_generation() {
+ btree_iterator_generation_info::update_generation(node_);
}
// The node in the tree the iterator is pointing at.
@@ -1214,10 +1273,6 @@ class btree_iterator {
// NOTE: this is an int rather than a field_type because iterators can point
// to invalid positions (such as -1) in certain circumstances.
int position_;
-#ifdef ABSL_BTREE_ENABLE_GENERATIONS
- // Used to check that the iterator hasn't been invalidated.
- uint32_t generation_;
-#endif
};
template <typename Params>