Commit d5eb5032 by Abseil Team Committed by Copybara-Service

Introduce `RawHashSetLayout` helper class.

PiperOrigin-RevId: 602485199
Change-Id: I5cc10eb8dcfe5988cf939080a224522e02ad8607
parent 9a79278a
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
// slot_type slots[capacity]; // slot_type slots[capacity];
// }; // };
// //
// The length of this array is computed by `AllocSize()` below. // The length of this array is computed by `RawHashSetLayout::alloc_size` below.
// //
// Control bytes (`ctrl_t`) are bytes (collected into groups of a // Control bytes (`ctrl_t`) are bytes (collected into groups of a
// platform-specific size) that define the state of the corresponding slot in // platform-specific size) that define the state of the corresponding slot in
...@@ -983,12 +983,6 @@ using HashSetIteratorGenerationInfo = HashSetIteratorGenerationInfoDisabled; ...@@ -983,12 +983,6 @@ using HashSetIteratorGenerationInfo = HashSetIteratorGenerationInfoDisabled;
// A valid capacity is a non-zero integer `2^m - 1`. // A valid capacity is a non-zero integer `2^m - 1`.
inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; }
// Computes the offset from the start of the backing allocation of control.
// infoz and growth_left are stored at the beginning of the backing array.
inline size_t ControlOffset(bool has_infoz) {
return (has_infoz ? sizeof(HashtablezInfoHandle) : 0) + sizeof(size_t);
}
// Returns the number of "cloned control bytes". // Returns the number of "cloned control bytes".
// //
// This is the number of control bytes that are present both at the beginning // This is the number of control bytes that are present both at the beginning
...@@ -996,29 +990,57 @@ inline size_t ControlOffset(bool has_infoz) { ...@@ -996,29 +990,57 @@ inline size_t ControlOffset(bool has_infoz) {
// `Group::kWidth`-width probe window starting from any control byte. // `Group::kWidth`-width probe window starting from any control byte.
constexpr size_t NumClonedBytes() { return Group::kWidth - 1; } constexpr size_t NumClonedBytes() { return Group::kWidth - 1; }
// Given the capacity of a table, computes the offset (from the start of the // Returns the number of control bytes including cloned.
// backing allocation) of the generation counter (if it exists). inline size_t NumControlBytes(size_t capacity) {
inline size_t GenerationOffset(size_t capacity, bool has_infoz) { return capacity + 1 + NumClonedBytes();
assert(IsValidCapacity(capacity));
const size_t num_control_bytes = capacity + 1 + NumClonedBytes();
return ControlOffset(has_infoz) + num_control_bytes;
} }
// Given the capacity of a table, computes the offset (from the start of the // Computes the offset from the start of the backing allocation of control.
// backing allocation) at which the slots begin. // infoz and growth_left are stored at the beginning of the backing array.
inline size_t SlotOffset(size_t capacity, size_t slot_align, bool has_infoz) { inline static size_t ControlOffset(bool has_infoz) {
assert(IsValidCapacity(capacity)); return (has_infoz ? sizeof(HashtablezInfoHandle) : 0) + sizeof(size_t);
return (GenerationOffset(capacity, has_infoz) + NumGenerationBytes() +
slot_align - 1) &
(~slot_align + 1);
} }
// Given the capacity of a table, computes the total size of the backing // Helper class for computing offsets and allocation size of hash set fields.
// array. class RawHashSetLayout {
inline size_t AllocSize(size_t capacity, size_t slot_size, size_t slot_align, public:
bool has_infoz) { explicit RawHashSetLayout(size_t capacity, size_t slot_align, bool has_infoz)
return SlotOffset(capacity, slot_align, has_infoz) + capacity * slot_size; : capacity_(capacity),
} control_offset_(ControlOffset(has_infoz)),
generation_offset_(control_offset_ + NumControlBytes(capacity)),
slot_offset_(
(generation_offset_ + NumGenerationBytes() + slot_align - 1) &
(~slot_align + 1)) {
assert(IsValidCapacity(capacity));
}
// Returns the capacity of a table.
size_t capacity() const { return capacity_; }
// Returns precomputed offset from the start of the backing allocation of
// control.
size_t control_offset() const { return control_offset_; }
// Given the capacity of a table, computes the offset (from the start of the
// backing allocation) of the generation counter (if it exists).
size_t generation_offset() const { return generation_offset_; }
// Given the capacity of a table, computes the offset (from the start of the
// backing allocation) at which the slots begin.
size_t slot_offset() const { return slot_offset_; }
// Given the capacity of a table, computes the total size of the backing
// array.
size_t alloc_size(size_t slot_size) const {
return slot_offset_ + capacity_ * slot_size;
}
private:
size_t capacity_;
size_t control_offset_;
size_t generation_offset_;
size_t slot_offset_;
};
// CommonFields hold the fields in raw_hash_set that do not depend // CommonFields hold the fields in raw_hash_set that do not depend
// on template parameters. This allows us to conveniently pass all // on template parameters. This allows us to conveniently pass all
...@@ -1116,7 +1138,8 @@ class CommonFields : public CommonFieldsGenerationInfo { ...@@ -1116,7 +1138,8 @@ class CommonFields : public CommonFieldsGenerationInfo {
// The size of the backing array allocation. // The size of the backing array allocation.
size_t alloc_size(size_t slot_size, size_t slot_align) const { size_t alloc_size(size_t slot_size, size_t slot_align) const {
return AllocSize(capacity(), slot_size, slot_align, has_infoz()); return RawHashSetLayout(capacity(), slot_align, has_infoz())
.alloc_size(slot_size);
} }
// Returns the number of control bytes set to kDeleted. For testing only. // Returns the number of control bytes set to kDeleted. For testing only.
...@@ -1608,27 +1631,25 @@ class HashSetResizeHelper { ...@@ -1608,27 +1631,25 @@ class HashSetResizeHelper {
sample_size > 0 ? Sample(sample_size) : c.infoz(); sample_size > 0 ? Sample(sample_size) : c.infoz();
const bool has_infoz = infoz.IsSampled(); const bool has_infoz = infoz.IsSampled();
const size_t cap = c.capacity(); RawHashSetLayout layout(c.capacity(), AlignOfSlot, has_infoz);
const size_t alloc_size = char* mem = static_cast<char*>(Allocate<BackingArrayAlignment(AlignOfSlot)>(
AllocSize(cap, SizeOfSlot, AlignOfSlot, has_infoz); &alloc, layout.alloc_size(SizeOfSlot)));
char* mem = static_cast<char*>(
Allocate<BackingArrayAlignment(AlignOfSlot)>(&alloc, alloc_size));
const GenerationType old_generation = c.generation(); const GenerationType old_generation = c.generation();
c.set_generation_ptr(reinterpret_cast<GenerationType*>( c.set_generation_ptr(
mem + GenerationOffset(cap, has_infoz))); reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
c.set_generation(NextGeneration(old_generation)); c.set_generation(NextGeneration(old_generation));
c.set_control(reinterpret_cast<ctrl_t*>(mem + ControlOffset(has_infoz))); c.set_control(reinterpret_cast<ctrl_t*>(mem + layout.control_offset()));
c.set_slots(mem + SlotOffset(cap, AlignOfSlot, has_infoz)); c.set_slots(mem + layout.slot_offset());
ResetGrowthLeft(c); ResetGrowthLeft(c);
const bool grow_single_group = const bool grow_single_group =
IsGrowingIntoSingleGroupApplicable(old_capacity_, c.capacity()); IsGrowingIntoSingleGroupApplicable(old_capacity_, layout.capacity());
if (old_capacity_ != 0 && grow_single_group) { if (old_capacity_ != 0 && grow_single_group) {
if (TransferUsesMemcpy) { if (TransferUsesMemcpy) {
GrowSizeIntoSingleGroupTransferable(c, old_slots, SizeOfSlot); GrowSizeIntoSingleGroupTransferable(c, old_slots, SizeOfSlot);
DeallocateOld<AlignOfSlot>(alloc, SizeOfSlot, old_slots); DeallocateOld<AlignOfSlot>(alloc, SizeOfSlot, old_slots);
} else { } else {
GrowIntoSingleGroupShuffleControlBytes(c.control(), c.capacity()); GrowIntoSingleGroupShuffleControlBytes(c.control(), layout.capacity());
} }
} else { } else {
ResetCtrl(c, SizeOfSlot); ResetCtrl(c, SizeOfSlot);
...@@ -1636,7 +1657,7 @@ class HashSetResizeHelper { ...@@ -1636,7 +1657,7 @@ class HashSetResizeHelper {
c.set_has_infoz(has_infoz); c.set_has_infoz(has_infoz);
if (has_infoz) { if (has_infoz) {
infoz.RecordStorageChanged(c.size(), cap); infoz.RecordStorageChanged(c.size(), layout.capacity());
if (grow_single_group || old_capacity_ == 0) { if (grow_single_group || old_capacity_ == 0) {
infoz.RecordRehash(0); infoz.RecordRehash(0);
} }
...@@ -1675,9 +1696,10 @@ class HashSetResizeHelper { ...@@ -1675,9 +1696,10 @@ class HashSetResizeHelper {
template <size_t AlignOfSlot, class CharAlloc> template <size_t AlignOfSlot, class CharAlloc>
void DeallocateOld(CharAlloc alloc_ref, size_t slot_size, void* old_slots) { void DeallocateOld(CharAlloc alloc_ref, size_t slot_size, void* old_slots) {
SanitizerUnpoisonMemoryRegion(old_slots, slot_size * old_capacity_); SanitizerUnpoisonMemoryRegion(old_slots, slot_size * old_capacity_);
auto layout = RawHashSetLayout(old_capacity_, AlignOfSlot, had_infoz_);
Deallocate<BackingArrayAlignment(AlignOfSlot)>( Deallocate<BackingArrayAlignment(AlignOfSlot)>(
&alloc_ref, old_ctrl_ - ControlOffset(had_infoz_), &alloc_ref, old_ctrl_ - layout.control_offset(),
AllocSize(old_capacity_, slot_size, AlignOfSlot, had_infoz_)); layout.alloc_size(slot_size));
} }
private: private:
......
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