Skip to content

Commit 523b869

Browse files
ezbrcopybara-github
authored andcommitted
Change CommonFields from a private base class of raw_hash_set to be the first member of the settings_ CompressedTuple so that we can move growth_left into CommonFields.
This allows for removing growth_left as a separate argument for a few functions. Also, move the infoz() accessor functions to be before the data members of CommonFields to comply with the style guide. PiperOrigin-RevId: 493918310 Change-Id: I58474e37d3b16a1513d2931af6b153dea1d809c2
1 parent 2e17768 commit 523b869

File tree

2 files changed

+44
-48
lines changed

2 files changed

+44
-48
lines changed

absl/container/internal/raw_hash_set.cc

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ static inline void* PrevSlot(void* slot, size_t slot_size) {
9090
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) - slot_size);
9191
}
9292

93-
void DropDeletesWithoutResize(CommonFields& common, size_t& growth_left,
93+
void DropDeletesWithoutResize(CommonFields& common,
9494
const PolicyFunctions& policy, void* tmp_space) {
9595
void* set = &common;
9696
void* slot_array = common.slots_;
@@ -167,12 +167,11 @@ void DropDeletesWithoutResize(CommonFields& common, size_t& growth_left,
167167
slot_ptr = PrevSlot(slot_ptr, slot_size);
168168
}
169169
}
170-
ResetGrowthLeft(common, growth_left);
170+
ResetGrowthLeft(common);
171171
common.infoz().RecordRehash(total_probe_length);
172172
}
173173

174-
void EraseMetaOnly(CommonFields& c, size_t& growth_left, ctrl_t* it,
175-
size_t slot_size) {
174+
void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size) {
176175
assert(IsFull(*it) && "erasing a dangling iterator");
177176
--c.size_;
178177
const auto index = static_cast<size_t>(it - c.control_);
@@ -190,15 +189,15 @@ void EraseMetaOnly(CommonFields& c, size_t& growth_left, ctrl_t* it,
190189

191190
SetCtrl(c, index, was_never_full ? ctrl_t::kEmpty : ctrl_t::kDeleted,
192191
slot_size);
193-
growth_left += (was_never_full ? 1 : 0);
192+
c.growth_left_ += (was_never_full ? 1 : 0);
194193
c.infoz().RecordErase();
195194
}
196195

197-
void ClearBackingArray(CommonFields& c, size_t& growth_left,
198-
const PolicyFunctions& policy, bool reuse) {
196+
void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
197+
bool reuse) {
199198
if (reuse) {
200199
c.size_ = 0;
201-
ResetCtrl(c, growth_left, policy.slot_size);
200+
ResetCtrl(c, policy.slot_size);
202201
c.infoz().RecordStorageChanged(0, c.capacity_);
203202
} else {
204203
void* set = &c;
@@ -207,7 +206,7 @@ void ClearBackingArray(CommonFields& c, size_t& growth_left,
207206
c.slots_ = nullptr;
208207
c.size_ = 0;
209208
c.capacity_ = 0;
210-
growth_left = 0;
209+
c.growth_left_ = 0;
211210
c.infoz().RecordClearedReservation();
212211
assert(c.size_ == 0);
213212
c.infoz().RecordStorageChanged(0, 0);

absl/container/internal/raw_hash_set.h

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -740,14 +740,19 @@ class CommonFields : public HashtablezInfoHandle {
740740
control_(that.control_),
741741
slots_(that.slots_),
742742
size_(that.size_),
743-
capacity_(that.capacity_) {
743+
capacity_(that.capacity_),
744+
growth_left_(that.growth_left_) {
744745
that.control_ = EmptyGroup();
745746
that.slots_ = nullptr;
746747
that.size_ = 0;
747748
that.capacity_ = 0;
749+
that.growth_left_ = 0;
748750
}
749751
CommonFields& operator=(CommonFields&&) = default;
750752

753+
HashtablezInfoHandle& infoz() { return *this; }
754+
const HashtablezInfoHandle& infoz() const { return *this; }
755+
751756
// TODO(b/259599413): Investigate removing some of these fields:
752757
// - control/slots can be derived from each other
753758
// - size can be moved into the slot array
@@ -768,8 +773,8 @@ class CommonFields : public HashtablezInfoHandle {
768773
// The total number of available slots.
769774
size_t capacity_ = 0;
770775

771-
HashtablezInfoHandle& infoz() { return *this; }
772-
const HashtablezInfoHandle& infoz() const { return *this; }
776+
// The number of slots we can still fill without needing to rehash.
777+
size_t growth_left_ = 0;
773778
};
774779

775780
// Returns he number of "cloned control bytes".
@@ -968,21 +973,20 @@ extern template FindInfo find_first_non_full(const CommonFields&, size_t);
968973
// performance critical routines.
969974
FindInfo find_first_non_full_outofline(const CommonFields&, size_t);
970975

971-
inline void ResetGrowthLeft(CommonFields& common, size_t& growth_left) {
972-
growth_left = CapacityToGrowth(common.capacity_) - common.size_;
976+
inline void ResetGrowthLeft(CommonFields& common) {
977+
common.growth_left_ = CapacityToGrowth(common.capacity_) - common.size_;
973978
}
974979

975980
// Sets `ctrl` to `{kEmpty, kSentinel, ..., kEmpty}`, marking the entire
976981
// array as marked as empty.
977-
inline void ResetCtrl(CommonFields& common, size_t& growth_left,
978-
size_t slot_size) {
982+
inline void ResetCtrl(CommonFields& common, size_t slot_size) {
979983
const size_t capacity = common.capacity_;
980984
ctrl_t* ctrl = common.control_;
981985
std::memset(ctrl, static_cast<int8_t>(ctrl_t::kEmpty),
982986
capacity + 1 + NumClonedBytes());
983987
ctrl[capacity] = ctrl_t::kSentinel;
984988
SanitizerPoisonMemoryRegion(common.slots_, slot_size * capacity);
985-
ResetGrowthLeft(common, growth_left);
989+
ResetGrowthLeft(common);
986990
}
987991

988992
// Sets `ctrl[i]` to `h`.
@@ -1027,8 +1031,7 @@ inline size_t AllocSize(size_t capacity, size_t slot_size, size_t slot_align) {
10271031
}
10281032

10291033
template <typename Alloc, size_t SizeOfSlot, size_t AlignOfSlot>
1030-
ABSL_ATTRIBUTE_NOINLINE void InitializeSlots(CommonFields& c,
1031-
size_t& growth_left, Alloc alloc) {
1034+
ABSL_ATTRIBUTE_NOINLINE void InitializeSlots(CommonFields& c, Alloc alloc) {
10321035
assert(c.capacity_);
10331036
// Folks with custom allocators often make unwarranted assumptions about the
10341037
// behavior of their classes vis-a-vis trivial destructability and what
@@ -1045,7 +1048,7 @@ ABSL_ATTRIBUTE_NOINLINE void InitializeSlots(CommonFields& c,
10451048
Allocate<AlignOfSlot>(&alloc, AllocSize(cap, SizeOfSlot, AlignOfSlot)));
10461049
c.control_ = reinterpret_cast<ctrl_t*>(mem);
10471050
c.slots_ = mem + SlotOffset(cap, AlignOfSlot);
1048-
ResetCtrl(c, growth_left, SizeOfSlot);
1051+
ResetCtrl(c, SizeOfSlot);
10491052
if (sample_size) {
10501053
c.infoz() = Sample(sample_size);
10511054
}
@@ -1073,12 +1076,11 @@ struct PolicyFunctions {
10731076
// ClearBackingArray clears the backing array, either modifying it in place,
10741077
// or creating a new one based on the value of "reuse".
10751078
// REQUIRES: c.capacity > 0
1076-
void ClearBackingArray(CommonFields& c, size_t& growth_left,
1077-
const PolicyFunctions& policy, bool reuse);
1079+
void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
1080+
bool reuse);
10781081

10791082
// Type-erased version of raw_hash_set::erase_meta_only.
1080-
void EraseMetaOnly(CommonFields& c, size_t& growth_left, ctrl_t* it,
1081-
size_t slot_size);
1083+
void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size);
10821084

10831085
// Function to place in PolicyFunctions::dealloc for raw_hash_sets
10841086
// that are using std::allocator. This allows us to share the same
@@ -1106,7 +1108,7 @@ ABSL_ATTRIBUTE_NOINLINE void TransferRelocatable(void*, void* dst, void* src) {
11061108
}
11071109

11081110
// Type-erased version of raw_hash_set::drop_deletes_without_resize.
1109-
void DropDeletesWithoutResize(CommonFields& common, size_t& growth_left,
1111+
void DropDeletesWithoutResize(CommonFields& common,
11101112
const PolicyFunctions& policy, void* tmp_space);
11111113

11121114
// A SwissTable.
@@ -1130,7 +1132,7 @@ void DropDeletesWithoutResize(CommonFields& common, size_t& growth_left,
11301132
// the storage of the hashtable will be allocated and the elements will be
11311133
// constructed and destroyed.
11321134
template <class Policy, class Hash, class Eq, class Alloc>
1133-
class raw_hash_set : private CommonFields {
1135+
class raw_hash_set {
11341136
using PolicyTraits = hash_policy_traits<Policy>;
11351137
using KeyArgImpl =
11361138
KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
@@ -1337,7 +1339,7 @@ class raw_hash_set : private CommonFields {
13371339
size_t bucket_count, const hasher& hash = hasher(),
13381340
const key_equal& eq = key_equal(),
13391341
const allocator_type& alloc = allocator_type())
1340-
: settings_(0u, hash, eq, alloc) {
1342+
: settings_(CommonFields{}, hash, eq, alloc) {
13411343
if (bucket_count) {
13421344
common().capacity_ = NormalizeCapacity(bucket_count);
13431345
initialize_slots();
@@ -1462,15 +1464,13 @@ class raw_hash_set : private CommonFields {
14621464
: // Hash, equality and allocator are copied instead of moved because
14631465
// `that` must be left valid. If Hash is std::function<Key>, moving it
14641466
// would create a nullptr functor that cannot be called.
1465-
CommonFields(std::move(that)),
1466-
settings_(absl::exchange(that.growth_left(), size_t{0}),
1467+
settings_(absl::exchange(that.common(), CommonFields{}),
14671468
that.hash_ref(), that.eq_ref(), that.alloc_ref()) {}
14681469

14691470
raw_hash_set(raw_hash_set&& that, const allocator_type& a)
1470-
: settings_(0, that.hash_ref(), that.eq_ref(), a) {
1471+
: settings_(CommonFields{}, that.hash_ref(), that.eq_ref(), a) {
14711472
if (a == that.alloc_ref()) {
14721473
std::swap(common(), that.common());
1473-
std::swap(growth_left(), that.growth_left());
14741474
} else {
14751475
reserve(that.size());
14761476
// Note: this will copy elements of dense_set and unordered_set instead of
@@ -1545,7 +1545,7 @@ class raw_hash_set : private CommonFields {
15451545
// Already guaranteed to be empty; so nothing to do.
15461546
} else {
15471547
destroy_slots();
1548-
ClearBackingArray(common(), growth_left(), GetPolicyFunctions(),
1548+
ClearBackingArray(common(), GetPolicyFunctions(),
15491549
/*reuse=*/cap < 128);
15501550
}
15511551
}
@@ -1843,7 +1843,6 @@ class raw_hash_set : private CommonFields {
18431843
typename AllocTraits::propagate_on_container_swap{})) {
18441844
using std::swap;
18451845
swap(common(), that.common());
1846-
swap(growth_left(), that.growth_left());
18471846
swap(hash_ref(), that.hash_ref());
18481847
swap(eq_ref(), that.eq_ref());
18491848
SwapAlloc(alloc_ref(), that.alloc_ref(),
@@ -1853,7 +1852,7 @@ class raw_hash_set : private CommonFields {
18531852
void rehash(size_t n) {
18541853
if (n == 0 && capacity() == 0) return;
18551854
if (n == 0 && size() == 0) {
1856-
ClearBackingArray(common(), growth_left(), GetPolicyFunctions(),
1855+
ClearBackingArray(common(), GetPolicyFunctions(),
18571856
/*reuse=*/false);
18581857
return;
18591858
}
@@ -2079,7 +2078,7 @@ class raw_hash_set : private CommonFields {
20792078
// This merely updates the pertinent control byte. This can be used in
20802079
// conjunction with Policy::transfer to move the object to another place.
20812080
void erase_meta_only(const_iterator it) {
2082-
EraseMetaOnly(common(), growth_left(), it.inner_.ctrl_, sizeof(slot_type));
2081+
EraseMetaOnly(common(), it.inner_.ctrl_, sizeof(slot_type));
20832082
}
20842083

20852084
// Allocates a backing array for `self` and initializes its control bytes.
@@ -2094,7 +2093,7 @@ class raw_hash_set : private CommonFields {
20942093
using CharAlloc =
20952094
typename absl::allocator_traits<Alloc>::template rebind_alloc<char>;
20962095
InitializeSlots<CharAlloc, sizeof(slot_type), alignof(slot_type)>(
2097-
common(), growth_left(), CharAlloc(alloc_ref()));
2096+
common(), CharAlloc(alloc_ref()));
20982097
}
20992098

21002099
ABSL_ATTRIBUTE_NOINLINE void resize(size_t new_capacity) {
@@ -2134,8 +2133,7 @@ class raw_hash_set : private CommonFields {
21342133
inline void drop_deletes_without_resize() {
21352134
// Stack-allocate space for swapping elements.
21362135
alignas(slot_type) unsigned char tmp[sizeof(slot_type)];
2137-
DropDeletesWithoutResize(common(), growth_left(), GetPolicyFunctions(),
2138-
tmp);
2136+
DropDeletesWithoutResize(common(), GetPolicyFunctions(), tmp);
21392137
}
21402138

21412139
// Called whenever the table *might* need to conditionally grow.
@@ -2305,15 +2303,15 @@ class raw_hash_set : private CommonFields {
23052303
// side-effect.
23062304
//
23072305
// See `CapacityToGrowth()`.
2308-
size_t& growth_left() { return settings_.template get<0>(); }
2306+
size_t& growth_left() { return common().growth_left_; }
23092307

23102308
// Prefetch the heap-allocated memory region to resolve potential TLB misses.
23112309
// This is intended to overlap with execution of calculating the hash for a
23122310
// key.
23132311
void prefetch_heap_block() const { base_internal::PrefetchT2(control()); }
23142312

2315-
CommonFields& common() { return *this; }
2316-
const CommonFields& common() const { return *this; }
2313+
CommonFields& common() { return settings_.template get<0>(); }
2314+
const CommonFields& common() const { return settings_.template get<0>(); }
23172315

23182316
ctrl_t* control() const { return common().control_; }
23192317
slot_type* slot_array() const {
@@ -2369,13 +2367,12 @@ class raw_hash_set : private CommonFields {
23692367
return value;
23702368
}
23712369

2372-
// Bundle together growth_left (number of slots that can be filled without
2373-
// rehashing) plus other objects which might be empty. CompressedTuple will
2374-
// ensure that sizeof is not affected by any of the empty fields that occur
2375-
// after growth_left.
2376-
absl::container_internal::CompressedTuple<size_t /* growth_left */, hasher,
2377-
key_equal, allocator_type>
2378-
settings_{0u, hasher{}, key_equal{}, allocator_type{}};
2370+
// Bundle together CommonFields plus other objects which might be empty.
2371+
// CompressedTuple will ensure that sizeof is not affected by any of the empty
2372+
// fields that occur after CommonFields.
2373+
absl::container_internal::CompressedTuple<CommonFields, hasher, key_equal,
2374+
allocator_type>
2375+
settings_{CommonFields{}, hasher{}, key_equal{}, allocator_type{}};
23792376
};
23802377

23812378
// Erases all elements that satisfy the predicate `pred` from the container `c`.

0 commit comments

Comments
 (0)