@@ -1097,6 +1097,14 @@ constexpr size_t NormalizeCapacity(size_t n) {
10971097 return n ? ~size_t {} >> countl_zero (n) : 1 ;
10981098}
10991099
1100+ constexpr size_t MaxValidCapacity (size_t slot_size) {
1101+ return NormalizeCapacity ((std::numeric_limits<size_t >::max)() / 4 /
1102+ slot_size);
1103+ }
1104+
1105+ // Use a non-inlined function to avoid code bloat.
1106+ [[noreturn]] void HashTableSizeOverflow ();
1107+
11001108// General notes on capacity/growth methods below:
11011109// - We use 7/8th as maximum load factor. For 16-wide groups, that gives an
11021110// average of two empty slots per group.
@@ -1529,7 +1537,7 @@ ABSL_ATTRIBUTE_NOINLINE void DeallocateBackingArray(
15291537struct PolicyFunctions {
15301538 uint32_t key_size;
15311539 uint32_t value_size;
1532- uint16_t slot_size;
1540+ uint32_t slot_size;
15331541 uint16_t slot_align;
15341542 uint8_t soo_capacity;
15351543 bool is_hashtablez_eligible;
@@ -1576,20 +1584,14 @@ constexpr size_t SooSlotIndex() { return 1; }
15761584// Allowing till 16 would require additional store that can be avoided.
15771585constexpr size_t MaxSmallAfterSooCapacity () { return 7 ; }
15781586
1579- // Resizes empty non-allocated table to the capacity to fit new_size elements .
1587+ // Resizes empty non-allocated table to the new capacity .
15801588// Requires:
15811589// 1. `c.capacity() == policy.soo_capacity`.
15821590// 2. `c.empty()`.
1583- // 3. `new_size > policy.soo_capacity`.
1591+ // 3. `new_capacity > policy.soo_capacity`.
15841592// The table will be attempted to be sampled.
1585- void ReserveEmptyNonAllocatedTableToFitNewSize (CommonFields& common,
1586- size_t new_size,
1587- const PolicyFunctions& policy);
1588-
1589- // The same as ReserveEmptyNonAllocatedTableToFitNewSize, but resizes to the
1590- // next valid capacity after `bucket_count`.
1591- void ReserveEmptyNonAllocatedTableToFitBucketCount (
1592- CommonFields& common, size_t bucket_count, const PolicyFunctions& policy);
1593+ void ResizeEmptyNonAllocatedTable (CommonFields& common, size_t new_capacity,
1594+ const PolicyFunctions& policy);
15931595
15941596// Resizes empty non-allocated SOO table to NextCapacity(SooCapacity()) and
15951597// forces the table to be sampled.
@@ -1657,33 +1659,6 @@ InitializeThreeElementsControlBytesAfterSoo(size_t hash, ctrl_t* new_ctrl) {
16571659 // new_ctrl after 2nd store = EHESEHEEEEE
16581660}
16591661
1660- // Template parameter is only used to enable testing.
1661- template <size_t kSizeOfSizeT = sizeof (size_t )>
1662- constexpr size_t MaxValidSize (size_t slot_size) {
1663- if constexpr (kSizeOfSizeT == 4 ) {
1664- return (size_t {1 } << (kSizeOfSizeT * 8 - 2 )) / slot_size - 1 ;
1665- } else {
1666- static_assert (kSizeOfSizeT == 8 );
1667- constexpr size_t kSizeBits = 43 ;
1668- static_assert (
1669- kSizeBits + sizeof (PolicyFunctions::slot_size) * 8 < 64 ,
1670- " we expect that slot size is small enough that allocation size "
1671- " will not overflow" );
1672- return CapacityToGrowth (static_cast <size_t >(uint64_t {1 } << kSizeBits ) - 1 );
1673- }
1674- }
1675-
1676- // Template parameter is only used to enable testing.
1677- template <size_t kSizeOfSizeT = sizeof (size_t )>
1678- constexpr size_t IsAboveMaxValidSize (size_t size, size_t slot_size) {
1679- if constexpr (kSizeOfSizeT == 4 ) {
1680- return uint64_t {size} * slot_size >
1681- MaxValidSize<kSizeOfSizeT >(/* slot_size=*/ 1 );
1682- } else {
1683- return size > MaxValidSize (slot_size);
1684- }
1685- }
1686-
16871662// Returns the optimal size for memcpy when transferring SOO slot.
16881663// Otherwise, returns the optimal size for memcpy SOO slot transfer
16891664// to SooSlotIndex().
@@ -2150,8 +2125,8 @@ class raw_hash_set {
21502125 : settings_(CommonFields::CreateDefault<SooEnabled()>(), hash, eq,
21512126 alloc) {
21522127 if (bucket_count > DefaultCapacity ()) {
2153- ReserveEmptyNonAllocatedTableToFitBucketCount (common (), bucket_count,
2154- GetPolicyFunctions ());
2128+ ResizeEmptyNonAllocatedTable (common (), NormalizeCapacity ( bucket_count) ,
2129+ GetPolicyFunctions ());
21552130 }
21562131 }
21572132
@@ -2427,7 +2402,9 @@ class raw_hash_set {
24272402 ABSL_ASSUME (cap >= kDefaultCapacity );
24282403 return cap;
24292404 }
2430- size_t max_size () const { return MaxValidSize (sizeof (slot_type)); }
2405+ size_t max_size () const {
2406+ return CapacityToGrowth (MaxValidCapacity (sizeof (slot_type)));
2407+ }
24312408
24322409 ABSL_ATTRIBUTE_REINITIALIZES void clear () {
24332410 if (SwisstableGenerationsEnabled () &&
@@ -2836,10 +2813,16 @@ class raw_hash_set {
28362813 ReserveAllocatedTable (common (), n, GetPolicyFunctions ());
28372814 } else {
28382815 if (ABSL_PREDICT_TRUE (n > DefaultCapacity ())) {
2839- ReserveEmptyNonAllocatedTableToFitNewSize (common (), n,
2840- GetPolicyFunctions ());
2816+ ResizeEmptyNonAllocatedTable (
2817+ common (), NormalizeCapacity (GrowthToLowerboundCapacity (n)),
2818+ GetPolicyFunctions ());
2819+ // This is after resize, to ensure that we have completed the allocation
2820+ // and have potentially sampled the hashtable.
2821+ infoz ().RecordReservation (n);
28412822 }
28422823 }
2824+ common ().reset_reserved_growth (n);
2825+ common ().set_reservation_size (n);
28432826 }
28442827
28452828 // Extension API: support for heterogeneous keys.
@@ -3575,15 +3558,10 @@ class raw_hash_set {
35753558 }
35763559
35773560 static const PolicyFunctions& GetPolicyFunctions () {
3578- static_assert (sizeof (slot_type) <= (std::numeric_limits<uint16_t >::max)(),
3579- " Slot size is too large. Use std::unique_ptr for value type "
3580- " or use absl::node_hash_{map,set}." );
3581- static_assert (alignof (slot_type) <=
3582- size_t {(std::numeric_limits<uint16_t >::max)()});
3583- static_assert (sizeof (key_type) <=
3584- size_t {(std::numeric_limits<uint32_t >::max)()});
3585- static_assert (sizeof (value_type) <=
3586- size_t {(std::numeric_limits<uint32_t >::max)()});
3561+ static_assert (sizeof (slot_type) <= (std::numeric_limits<uint32_t >::max)());
3562+ static_assert (alignof (slot_type) <= (std::numeric_limits<uint16_t >::max)());
3563+ static_assert (sizeof (key_type) <= (std::numeric_limits<uint32_t >::max)());
3564+ static_assert (sizeof (value_type) <= (std::numeric_limits<uint32_t >::max)());
35873565 static constexpr size_t kBackingArrayAlignment =
35883566 BackingArrayAlignment (alignof (slot_type));
35893567 static constexpr PolicyFunctions value = {
0 commit comments