summaryrefslogtreecommitdiff
path: root/absl/container/internal/raw_hash_set.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/container/internal/raw_hash_set.h')
-rw-r--r--absl/container/internal/raw_hash_set.h124
1 files changed, 80 insertions, 44 deletions
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index 33e05736..bc33389b 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -179,6 +179,7 @@
#include <iterator>
#include <limits>
#include <memory>
+#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
@@ -1038,35 +1039,75 @@ size_t SelectBucketCountForIterRange(InputIter first, InputIter last,
return 0;
}
-#define ABSL_INTERNAL_ASSERT_IS_FULL(ctrl, generation, generation_ptr, \
- operation) \
- do { \
- ABSL_HARDENING_ASSERT((ctrl != nullptr) && operation \
- " called on end() iterator."); \
- ABSL_HARDENING_ASSERT((ctrl != EmptyGroup()) && operation \
- " called on default-constructed iterator."); \
- if (SwisstableGenerationsEnabled() && generation != *generation_ptr) \
- ABSL_INTERNAL_LOG(FATAL, operation \
- " called on invalidated iterator. The table could " \
- "have rehashed since this iterator was initialized."); \
- ABSL_HARDENING_ASSERT( \
- (IsFull(*ctrl)) && operation \
- " called on invalid iterator. The element might have been erased or " \
- "the table might have rehashed."); \
- } while (0)
+constexpr bool SwisstableDebugEnabled() {
+#if defined(ABSL_SWISSTABLE_ENABLE_GENERATIONS) || \
+ ABSL_OPTION_HARDENED == 1 || !defined(NDEBUG)
+ return true;
+#else
+ return false;
+#endif
+}
+
+inline void AssertIsFull(const ctrl_t* ctrl, GenerationType generation,
+ const GenerationType* generation_ptr,
+ const char* operation) {
+ if (!SwisstableDebugEnabled()) return;
+ if (ctrl == nullptr) {
+ ABSL_INTERNAL_LOG(FATAL,
+ std::string(operation) + " called on end() iterator.");
+ }
+ if (ctrl == EmptyGroup()) {
+ ABSL_INTERNAL_LOG(FATAL, std::string(operation) +
+ " called on default-constructed iterator.");
+ }
+ if (SwisstableGenerationsEnabled()) {
+ if (generation != *generation_ptr) {
+ ABSL_INTERNAL_LOG(FATAL,
+ std::string(operation) +
+ " called on invalid iterator. The table could have "
+ "rehashed since this iterator was initialized.");
+ }
+ if (!IsFull(*ctrl)) {
+ ABSL_INTERNAL_LOG(
+ FATAL,
+ std::string(operation) +
+ " called on invalid iterator. The element was likely erased.");
+ }
+ } else {
+ if (!IsFull(*ctrl)) {
+ ABSL_INTERNAL_LOG(
+ FATAL,
+ std::string(operation) +
+ " called on invalid iterator. The element might have been erased "
+ "or the table might have rehashed. Consider running with "
+ "--config=asan to diagnose rehashing issues.");
+ }
+ }
+}
// Note that for comparisons, null/end iterators are valid.
inline void AssertIsValidForComparison(const ctrl_t* ctrl,
GenerationType generation,
const GenerationType* generation_ptr) {
- ABSL_HARDENING_ASSERT(
- (ctrl == nullptr || ctrl == EmptyGroup() || IsFull(*ctrl)) &&
- "Invalid iterator comparison. The element might have "
- "been erased or the table might have rehashed.");
- if (SwisstableGenerationsEnabled() && generation != *generation_ptr) {
- ABSL_INTERNAL_LOG(FATAL,
- "Invalid iterator comparison. The table could have "
- "rehashed since this iterator was initialized.");
+ if (!SwisstableDebugEnabled()) return;
+ const bool ctrl_is_valid_for_comparison =
+ ctrl == nullptr || ctrl == EmptyGroup() || IsFull(*ctrl);
+ if (SwisstableGenerationsEnabled()) {
+ if (generation != *generation_ptr) {
+ ABSL_INTERNAL_LOG(FATAL,
+ "Invalid iterator comparison. The table could have "
+ "rehashed since this iterator was initialized.");
+ }
+ if (!ctrl_is_valid_for_comparison) {
+ ABSL_INTERNAL_LOG(
+ FATAL, "Invalid iterator comparison. The element was likely erased.");
+ }
+ } else {
+ ABSL_HARDENING_ASSERT(
+ ctrl_is_valid_for_comparison &&
+ "Invalid iterator comparison. The element might have been erased or "
+ "the table might have rehashed. Consider running with --config=asan to "
+ "diagnose rehashing issues.");
}
}
@@ -1097,8 +1138,7 @@ inline void AssertSameContainer(const ctrl_t* ctrl_a, const ctrl_t* ctrl_b,
const void* const& slot_b,
const GenerationType* generation_ptr_a,
const GenerationType* generation_ptr_b) {
-#if defined(ABSL_SWISSTABLE_ENABLE_GENERATIONS) || \
- ABSL_OPTION_HARDENED == 1 || !defined(NDEBUG)
+ if (!SwisstableDebugEnabled()) return;
const bool a_is_default = ctrl_a == EmptyGroup();
const bool b_is_default = ctrl_b == EmptyGroup();
if (a_is_default != b_is_default) {
@@ -1108,9 +1148,9 @@ inline void AssertSameContainer(const ctrl_t* ctrl_a, const ctrl_t* ctrl_b,
"with non-default-constructed iterator.");
}
if (a_is_default && b_is_default) return;
-#endif
- if (SwisstableGenerationsEnabled() && generation_ptr_a != generation_ptr_b) {
+ if (SwisstableGenerationsEnabled()) {
+ if (generation_ptr_a == generation_ptr_b) return;
const bool a_is_empty = generation_ptr_a == EmptyGeneration();
const bool b_is_empty = generation_ptr_b == EmptyGeneration();
if (a_is_empty != b_is_empty) {
@@ -1129,11 +1169,13 @@ inline void AssertSameContainer(const ctrl_t* ctrl_a, const ctrl_t* ctrl_b,
ABSL_INTERNAL_LOG(FATAL,
"Invalid iterator comparison. Comparing non-end() "
"iterators from different hashtables.");
+ } else {
+ ABSL_HARDENING_ASSERT(
+ AreItersFromSameContainer(ctrl_a, ctrl_b, slot_a, slot_b) &&
+ "Invalid iterator comparison. The iterators may be from different "
+ "containers or the container might have rehashed. Consider running "
+ "with --config=asan to diagnose rehashing issues.");
}
- ABSL_HARDENING_ASSERT(
- AreItersFromSameContainer(ctrl_a, ctrl_b, slot_a, slot_b) &&
- "Invalid iterator comparison. The iterators may be from different "
- "containers or the container might have rehashed.");
}
struct FindInfo {
@@ -1471,22 +1513,19 @@ class raw_hash_set {
// PRECONDITION: not an end() iterator.
reference operator*() const {
- ABSL_INTERNAL_ASSERT_IS_FULL(ctrl_, generation(), generation_ptr(),
- "operator*()");
+ AssertIsFull(ctrl_, generation(), generation_ptr(), "operator*()");
return PolicyTraits::element(slot_);
}
// PRECONDITION: not an end() iterator.
pointer operator->() const {
- ABSL_INTERNAL_ASSERT_IS_FULL(ctrl_, generation(), generation_ptr(),
- "operator->");
+ AssertIsFull(ctrl_, generation(), generation_ptr(), "operator->");
return &operator*();
}
// PRECONDITION: not an end() iterator.
iterator& operator++() {
- ABSL_INTERNAL_ASSERT_IS_FULL(ctrl_, generation(), generation_ptr(),
- "operator++");
+ AssertIsFull(ctrl_, generation(), generation_ptr(), "operator++");
++ctrl_;
++slot_;
skip_empty_or_deleted();
@@ -2052,8 +2091,7 @@ class raw_hash_set {
// This overload is necessary because otherwise erase<K>(const K&) would be
// a better match if non-const iterator is passed as an argument.
void erase(iterator it) {
- ABSL_INTERNAL_ASSERT_IS_FULL(it.ctrl_, it.generation(), it.generation_ptr(),
- "erase()");
+ AssertIsFull(it.ctrl_, it.generation(), it.generation_ptr(), "erase()");
PolicyTraits::destroy(&alloc_ref(), it.slot_);
erase_meta_only(it);
}
@@ -2087,9 +2125,8 @@ class raw_hash_set {
}
node_type extract(const_iterator position) {
- ABSL_INTERNAL_ASSERT_IS_FULL(position.inner_.ctrl_,
- position.inner_.generation(),
- position.inner_.generation_ptr(), "extract()");
+ AssertIsFull(position.inner_.ctrl_, position.inner_.generation(),
+ position.inner_.generation_ptr(), "extract()");
auto node =
CommonAccess::Transfer<node_type>(alloc_ref(), position.inner_.slot_);
erase_meta_only(position);
@@ -2739,6 +2776,5 @@ ABSL_NAMESPACE_END
} // namespace absl
#undef ABSL_SWISSTABLE_ENABLE_GENERATIONS
-#undef ABSL_INTERNAL_ASSERT_IS_FULL
#endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_