Commit 116ee0fe by Evan Brown Committed by Copybara-Service

Add control()/slot() functions to iterator/const_iterator.

This allows for avoiding e.g. it.inner_.slot_ on const iterators.

Also, refactor HashtableDebugAccess::AllocatedByteSize to use regular iteration instead of looking directly at control/slot_array of the table in order to support small object optimization.

PiperOrigin-RevId: 580194253
Change-Id: I64cd69287834ee5c7a8daf867c532258806bfb7b
parent 3be31775
...@@ -1746,6 +1746,9 @@ class raw_hash_set { ...@@ -1746,6 +1746,9 @@ class raw_hash_set {
if (ABSL_PREDICT_FALSE(*ctrl_ == ctrl_t::kSentinel)) ctrl_ = nullptr; if (ABSL_PREDICT_FALSE(*ctrl_ == ctrl_t::kSentinel)) ctrl_ = nullptr;
} }
ctrl_t* control() const { return ctrl_; }
slot_type* slot() const { return slot_; }
// We use EmptyGroup() for default-constructed iterators so that they can // We use EmptyGroup() for default-constructed iterators so that they can
// be distinguished from end iterators, which have nullptr ctrl_. // be distinguished from end iterators, which have nullptr ctrl_.
ctrl_t* ctrl_ = EmptyGroup(); ctrl_t* ctrl_ = EmptyGroup();
...@@ -1758,6 +1761,9 @@ class raw_hash_set { ...@@ -1758,6 +1761,9 @@ class raw_hash_set {
class const_iterator { class const_iterator {
friend class raw_hash_set; friend class raw_hash_set;
template <class Container, typename Enabler>
friend struct absl::container_internal::hashtable_debug_internal::
HashtableDebugAccess;
public: public:
using iterator_category = typename iterator::iterator_category; using iterator_category = typename iterator::iterator_category;
...@@ -1791,6 +1797,8 @@ class raw_hash_set { ...@@ -1791,6 +1797,8 @@ class raw_hash_set {
const GenerationType* gen) const GenerationType* gen)
: inner_(const_cast<ctrl_t*>(ctrl), const_cast<slot_type*>(slot), gen) { : inner_(const_cast<ctrl_t*>(ctrl), const_cast<slot_type*>(slot), gen) {
} }
ctrl_t* control() const { return inner_.control(); }
slot_type* slot() const { return inner_.slot(); }
iterator inner_; iterator inner_;
}; };
...@@ -2257,8 +2265,8 @@ class raw_hash_set { ...@@ -2257,8 +2265,8 @@ class raw_hash_set {
// This overload is necessary because otherwise erase<K>(const K&) would be // This overload is necessary because otherwise erase<K>(const K&) would be
// a better match if non-const iterator is passed as an argument. // a better match if non-const iterator is passed as an argument.
void erase(iterator it) { void erase(iterator it) {
AssertIsFull(it.ctrl_, it.generation(), it.generation_ptr(), "erase()"); AssertIsFull(it.control(), it.generation(), it.generation_ptr(), "erase()");
destroy(it.slot_); destroy(it.slot());
erase_meta_only(it); erase_meta_only(it);
} }
...@@ -2289,8 +2297,8 @@ class raw_hash_set { ...@@ -2289,8 +2297,8 @@ class raw_hash_set {
assert(this != &src); assert(this != &src);
for (auto it = src.begin(), e = src.end(); it != e;) { for (auto it = src.begin(), e = src.end(); it != e;) {
auto next = std::next(it); auto next = std::next(it);
if (PolicyTraits::apply(InsertSlot<false>{*this, std::move(*it.slot_)}, if (PolicyTraits::apply(InsertSlot<false>{*this, std::move(*it.slot())},
PolicyTraits::element(it.slot_)) PolicyTraits::element(it.slot()))
.second) { .second) {
src.erase_meta_only(it); src.erase_meta_only(it);
} }
...@@ -2304,10 +2312,9 @@ class raw_hash_set { ...@@ -2304,10 +2312,9 @@ class raw_hash_set {
} }
node_type extract(const_iterator position) { node_type extract(const_iterator position) {
AssertIsFull(position.inner_.ctrl_, position.inner_.generation(), AssertIsFull(position.control(), position.inner_.generation(),
position.inner_.generation_ptr(), "extract()"); position.inner_.generation_ptr(), "extract()");
auto node = auto node = CommonAccess::Transfer<node_type>(alloc_ref(), position.slot());
CommonAccess::Transfer<node_type>(alloc_ref(), position.inner_.slot_);
erase_meta_only(position); erase_meta_only(position);
return node; return node;
} }
...@@ -2612,7 +2619,7 @@ class raw_hash_set { ...@@ -2612,7 +2619,7 @@ class raw_hash_set {
// This merely updates the pertinent control byte. This can be used in // This merely updates the pertinent control byte. This can be used in
// conjunction with Policy::transfer to move the object to another place. // conjunction with Policy::transfer to move the object to another place.
void erase_meta_only(const_iterator it) { void erase_meta_only(const_iterator it) {
EraseMetaOnly(common(), it.inner_.ctrl_, sizeof(slot_type)); EraseMetaOnly(common(), it.control(), sizeof(slot_type));
} }
// Allocates a backing array for `self` and initializes its control bytes. // Allocates a backing array for `self` and initializes its control bytes.
...@@ -2758,8 +2765,8 @@ class raw_hash_set { ...@@ -2758,8 +2765,8 @@ class raw_hash_set {
if (size == 0) return *this; if (size == 0) return *this;
reserve(size); reserve(size);
for (iterator it = that.begin(); it != that.end(); ++it) { for (iterator it = that.begin(); it != that.end(); ++it) {
insert(std::move(PolicyTraits::element(it.slot_))); insert(std::move(PolicyTraits::element(it.slot())));
that.destroy(it.slot_); that.destroy(it.slot());
} }
that.dealloc(); that.dealloc();
that.common() = CommonFields{}; that.common() = CommonFields{};
...@@ -3006,11 +3013,8 @@ struct HashtableDebugAccess<Set, absl::void_t<typename Set::raw_hash_set>> { ...@@ -3006,11 +3013,8 @@ struct HashtableDebugAccess<Set, absl::void_t<typename Set::raw_hash_set>> {
if (per_slot != ~size_t{}) { if (per_slot != ~size_t{}) {
m += per_slot * c.size(); m += per_slot * c.size();
} else { } else {
const ctrl_t* ctrl = c.control(); for (auto it = c.begin(); it != c.end(); ++it) {
for (size_t i = 0; i != capacity; ++i) { m += Traits::space_used(it.slot());
if (container_internal::IsFull(ctrl[i])) {
m += Traits::space_used(c.slot_array() + i);
}
} }
} }
return m; return m;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment