@@ -1097,14 +1097,6 @@ 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-
11081100// General notes on capacity/growth methods below:
11091101// - We use 7/8th as maximum load factor. For 16-wide groups, that gives an
11101102// average of two empty slots per group.
@@ -1537,7 +1529,7 @@ ABSL_ATTRIBUTE_NOINLINE void DeallocateBackingArray(
15371529struct PolicyFunctions {
15381530 uint32_t key_size;
15391531 uint32_t value_size;
1540- uint32_t slot_size;
1532+ uint16_t slot_size;
15411533 uint16_t slot_align;
15421534 uint8_t soo_capacity;
15431535 bool is_hashtablez_eligible;
@@ -1584,14 +1576,20 @@ constexpr size_t SooSlotIndex() { return 1; }
15841576// Allowing till 16 would require additional store that can be avoided.
15851577constexpr size_t MaxSmallAfterSooCapacity () { return 7 ; }
15861578
1587- // Resizes empty non-allocated table to the new capacity.
1579+ // Resizes empty non-allocated table to the capacity to fit new_size elements .
15881580// Requires:
15891581// 1. `c.capacity() == policy.soo_capacity`.
15901582// 2. `c.empty()`.
1591- // 3. `new_capacity > policy.soo_capacity`.
1583+ // 3. `new_size > policy.soo_capacity`.
15921584// The table will be attempted to be sampled.
1593- void ResizeEmptyNonAllocatedTable (CommonFields& common, size_t new_capacity,
1594- const PolicyFunctions& policy);
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);
15951593
15961594// Resizes empty non-allocated SOO table to NextCapacity(SooCapacity()) and
15971595// forces the table to be sampled.
@@ -1659,6 +1657,33 @@ InitializeThreeElementsControlBytesAfterSoo(size_t hash, ctrl_t* new_ctrl) {
16591657 // new_ctrl after 2nd store = EHESEHEEEEE
16601658}
16611659
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+
16621687// Returns the optimal size for memcpy when transferring SOO slot.
16631688// Otherwise, returns the optimal size for memcpy SOO slot transfer
16641689// to SooSlotIndex().
@@ -2125,8 +2150,8 @@ class raw_hash_set {
21252150 : settings_(CommonFields::CreateDefault<SooEnabled()>(), hash, eq,
21262151 alloc) {
21272152 if (bucket_count > DefaultCapacity ()) {
2128- ResizeEmptyNonAllocatedTable (common (), NormalizeCapacity ( bucket_count) ,
2129- GetPolicyFunctions ());
2153+ ReserveEmptyNonAllocatedTableToFitBucketCount (common (), bucket_count,
2154+ GetPolicyFunctions ());
21302155 }
21312156 }
21322157
@@ -2402,9 +2427,7 @@ class raw_hash_set {
24022427 ABSL_ASSUME (cap >= kDefaultCapacity );
24032428 return cap;
24042429 }
2405- size_t max_size () const {
2406- return CapacityToGrowth (MaxValidCapacity (sizeof (slot_type)));
2407- }
2430+ size_t max_size () const { return MaxValidSize (sizeof (slot_type)); }
24082431
24092432 ABSL_ATTRIBUTE_REINITIALIZES void clear () {
24102433 if (SwisstableGenerationsEnabled () &&
@@ -2813,16 +2836,10 @@ class raw_hash_set {
28132836 ReserveAllocatedTable (common (), n, GetPolicyFunctions ());
28142837 } else {
28152838 if (ABSL_PREDICT_TRUE (n > DefaultCapacity ())) {
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);
2839+ ReserveEmptyNonAllocatedTableToFitNewSize (common (), n,
2840+ GetPolicyFunctions ());
28222841 }
28232842 }
2824- common ().reset_reserved_growth (n);
2825- common ().set_reservation_size (n);
28262843 }
28272844
28282845 // Extension API: support for heterogeneous keys.
@@ -3558,10 +3575,15 @@ class raw_hash_set {
35583575 }
35593576
35603577 static const PolicyFunctions& GetPolicyFunctions () {
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)());
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)()});
35653587 static constexpr size_t kBackingArrayAlignment =
35663588 BackingArrayAlignment (alignof (slot_type));
35673589 static constexpr PolicyFunctions value = {
0 commit comments