tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

raw_hash_set.cc (53658B)


      1 // Copyright 2018 The Abseil Authors.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "absl/container/internal/raw_hash_set.h"
     16 
     17 #include <atomic>
     18 #include <cassert>
     19 #include <cstddef>
     20 #include <cstdint>
     21 #include <cstring>
     22 
     23 #include "absl/base/attributes.h"
     24 #include "absl/base/config.h"
     25 #include "absl/base/dynamic_annotations.h"
     26 #include "absl/base/internal/endian.h"
     27 #include "absl/base/internal/raw_logging.h"
     28 #include "absl/base/optimization.h"
     29 #include "absl/container/internal/container_memory.h"
     30 #include "absl/container/internal/hashtable_control_bytes.h"
     31 #include "absl/container/internal/hashtablez_sampler.h"
     32 #include "absl/functional/function_ref.h"
     33 #include "absl/hash/hash.h"
     34 #include "absl/numeric/bits.h"
     35 
     36 namespace absl {
     37 ABSL_NAMESPACE_BEGIN
     38 namespace container_internal {
     39 
     40 // Represents a control byte corresponding to a full slot with arbitrary hash.
     41 constexpr ctrl_t ZeroCtrlT() { return static_cast<ctrl_t>(0); }
     42 
     43 // We have space for `growth_info` before a single block of control bytes. A
     44 // single block of empty control bytes for tables without any slots allocated.
     45 // This enables removing a branch in the hot path of find(). In order to ensure
     46 // that the control bytes are aligned to 16, we have 16 bytes before the control
     47 // bytes even though growth_info only needs 8.
     48 alignas(16) ABSL_CONST_INIT ABSL_DLL const ctrl_t kEmptyGroup[32] = {
     49    ZeroCtrlT(),       ZeroCtrlT(),    ZeroCtrlT(),    ZeroCtrlT(),
     50    ZeroCtrlT(),       ZeroCtrlT(),    ZeroCtrlT(),    ZeroCtrlT(),
     51    ZeroCtrlT(),       ZeroCtrlT(),    ZeroCtrlT(),    ZeroCtrlT(),
     52    ZeroCtrlT(),       ZeroCtrlT(),    ZeroCtrlT(),    ZeroCtrlT(),
     53    ctrl_t::kSentinel, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
     54    ctrl_t::kEmpty,    ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
     55    ctrl_t::kEmpty,    ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
     56    ctrl_t::kEmpty,    ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty};
     57 
     58 // We need one full byte followed by a sentinel byte for iterator::operator++ to
     59 // work. We have a full group after kSentinel to be safe (in case operator++ is
     60 // changed to read a full group).
     61 ABSL_CONST_INIT ABSL_DLL const ctrl_t kSooControl[17] = {
     62    ZeroCtrlT(),    ctrl_t::kSentinel, ZeroCtrlT(),    ctrl_t::kEmpty,
     63    ctrl_t::kEmpty, ctrl_t::kEmpty,    ctrl_t::kEmpty, ctrl_t::kEmpty,
     64    ctrl_t::kEmpty, ctrl_t::kEmpty,    ctrl_t::kEmpty, ctrl_t::kEmpty,
     65    ctrl_t::kEmpty, ctrl_t::kEmpty,    ctrl_t::kEmpty, ctrl_t::kEmpty,
     66    ctrl_t::kEmpty};
     67 static_assert(NumControlBytes(SooCapacity()) <= 17,
     68              "kSooControl capacity too small");
     69 
     70 namespace {
     71 
     72 [[noreturn]] ABSL_ATTRIBUTE_NOINLINE void HashTableSizeOverflow() {
     73  ABSL_RAW_LOG(FATAL, "Hash table size overflow");
     74 }
     75 
     76 void ValidateMaxSize(size_t size, size_t slot_size) {
     77  if (IsAboveValidSize(size, slot_size)) {
     78    HashTableSizeOverflow();
     79  }
     80 }
     81 
     82 // Returns "random" seed.
     83 inline size_t RandomSeed() {
     84 #ifdef ABSL_HAVE_THREAD_LOCAL
     85  static thread_local size_t counter = 0;
     86  size_t value = ++counter;
     87 #else   // ABSL_HAVE_THREAD_LOCAL
     88  static std::atomic<size_t> counter(0);
     89  size_t value = counter.fetch_add(1, std::memory_order_relaxed);
     90 #endif  // ABSL_HAVE_THREAD_LOCAL
     91  return value ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(&counter));
     92 }
     93 
     94 bool ShouldRehashForBugDetection(PerTableSeed seed, size_t capacity) {
     95  // Note: we can't use the abseil-random library because abseil-random
     96  // depends on swisstable. We want to return true with probability
     97  // `min(1, RehashProbabilityConstant() / capacity())`. In order to do this,
     98  // we probe based on a random hash and see if the offset is less than
     99  // RehashProbabilityConstant().
    100  return probe(seed, capacity, absl::HashOf(RandomSeed())).offset() <
    101         RehashProbabilityConstant();
    102 }
    103 
    104 // Find a non-deterministic hash for single group table.
    105 // Last two bits are used to find a position for a newly inserted element after
    106 // resize.
    107 // This function is mixing all bits of hash and seed to maximize entropy.
    108 size_t SingleGroupTableH1(size_t hash, PerTableSeed seed) {
    109  return static_cast<size_t>(absl::popcount(hash ^ seed.seed()));
    110 }
    111 
    112 // Returns the address of the slot `i` iterations after `slot` assuming each
    113 // slot has the specified size.
    114 inline void* NextSlot(void* slot, size_t slot_size, size_t i = 1) {
    115  return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) +
    116                                 slot_size * i);
    117 }
    118 
    119 // Returns the address of the slot just before `slot` assuming each slot has the
    120 // specified size.
    121 inline void* PrevSlot(void* slot, size_t slot_size) {
    122  return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) - slot_size);
    123 }
    124 
    125 }  // namespace
    126 
    127 GenerationType* EmptyGeneration() {
    128  if (SwisstableGenerationsEnabled()) {
    129    constexpr size_t kNumEmptyGenerations = 1024;
    130    static constexpr GenerationType kEmptyGenerations[kNumEmptyGenerations]{};
    131    return const_cast<GenerationType*>(
    132        &kEmptyGenerations[RandomSeed() % kNumEmptyGenerations]);
    133  }
    134  return nullptr;
    135 }
    136 
    137 bool CommonFieldsGenerationInfoEnabled::
    138    should_rehash_for_bug_detection_on_insert(PerTableSeed seed,
    139                                              size_t capacity) const {
    140  if (reserved_growth_ == kReservedGrowthJustRanOut) return true;
    141  if (reserved_growth_ > 0) return false;
    142  return ShouldRehashForBugDetection(seed, capacity);
    143 }
    144 
    145 bool CommonFieldsGenerationInfoEnabled::should_rehash_for_bug_detection_on_move(
    146    PerTableSeed seed, size_t capacity) const {
    147  return ShouldRehashForBugDetection(seed, capacity);
    148 }
    149 
    150 bool ShouldInsertBackwardsForDebug(size_t capacity, size_t hash,
    151                                   PerTableSeed seed) {
    152  // To avoid problems with weak hashes and single bit tests, we use % 13.
    153  // TODO(kfm,sbenza): revisit after we do unconditional mixing
    154  return !is_small(capacity) && (H1(hash, seed) ^ RandomSeed()) % 13 > 6;
    155 }
    156 
    157 void IterateOverFullSlots(const CommonFields& c, size_t slot_size,
    158                          absl::FunctionRef<void(const ctrl_t*, void*)> cb) {
    159  const size_t cap = c.capacity();
    160  const ctrl_t* ctrl = c.control();
    161  void* slot = c.slot_array();
    162  if (is_small(cap)) {
    163    // Mirrored/cloned control bytes in small table are also located in the
    164    // first group (starting from position 0). We are taking group from position
    165    // `capacity` in order to avoid duplicates.
    166 
    167    // Small tables capacity fits into portable group, where
    168    // GroupPortableImpl::MaskFull is more efficient for the
    169    // capacity <= GroupPortableImpl::kWidth.
    170    assert(cap <= GroupPortableImpl::kWidth &&
    171           "unexpectedly large small capacity");
    172    static_assert(Group::kWidth >= GroupPortableImpl::kWidth,
    173                  "unexpected group width");
    174    // Group starts from kSentinel slot, so indices in the mask will
    175    // be increased by 1.
    176    const auto mask = GroupPortableImpl(ctrl + cap).MaskFull();
    177    --ctrl;
    178    slot = PrevSlot(slot, slot_size);
    179    for (uint32_t i : mask) {
    180      cb(ctrl + i, SlotAddress(slot, i, slot_size));
    181    }
    182    return;
    183  }
    184  size_t remaining = c.size();
    185  ABSL_ATTRIBUTE_UNUSED const size_t original_size_for_assert = remaining;
    186  while (remaining != 0) {
    187    for (uint32_t i : GroupFullEmptyOrDeleted(ctrl).MaskFull()) {
    188      assert(IsFull(ctrl[i]) && "hash table was modified unexpectedly");
    189      cb(ctrl + i, SlotAddress(slot, i, slot_size));
    190      --remaining;
    191    }
    192    ctrl += Group::kWidth;
    193    slot = NextSlot(slot, slot_size, Group::kWidth);
    194    assert((remaining == 0 || *(ctrl - 1) != ctrl_t::kSentinel) &&
    195           "hash table was modified unexpectedly");
    196  }
    197  // NOTE: erasure of the current element is allowed in callback for
    198  // absl::erase_if specialization. So we use `>=`.
    199  assert(original_size_for_assert >= c.size() &&
    200         "hash table was modified unexpectedly");
    201 }
    202 
    203 size_t PrepareInsertAfterSoo(size_t hash, size_t slot_size,
    204                             CommonFields& common) {
    205  assert(common.capacity() == NextCapacity(SooCapacity()));
    206  // After resize from capacity 1 to 3, we always have exactly the slot with
    207  // index 1 occupied, so we need to insert either at index 0 or index 2.
    208  static_assert(SooSlotIndex() == 1, "");
    209  PrepareInsertCommon(common);
    210  const size_t offset = SingleGroupTableH1(hash, common.seed()) & 2;
    211  common.growth_info().OverwriteEmptyAsFull();
    212  SetCtrlInSingleGroupTable(common, offset, H2(hash), slot_size);
    213  common.infoz().RecordInsert(hash, /*distance_from_desired=*/0);
    214  return offset;
    215 }
    216 
    217 void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity) {
    218  assert(ctrl[capacity] == ctrl_t::kSentinel);
    219  assert(IsValidCapacity(capacity));
    220  for (ctrl_t* pos = ctrl; pos < ctrl + capacity; pos += Group::kWidth) {
    221    Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos);
    222  }
    223  // Copy the cloned ctrl bytes.
    224  std::memcpy(ctrl + capacity + 1, ctrl, NumClonedBytes());
    225  ctrl[capacity] = ctrl_t::kSentinel;
    226 }
    227 // Extern template instantiation for inline function.
    228 template FindInfo find_first_non_full(const CommonFields&, size_t);
    229 
    230 FindInfo find_first_non_full_outofline(const CommonFields& common,
    231                                       size_t hash) {
    232  return find_first_non_full(common, hash);
    233 }
    234 
    235 namespace {
    236 
    237 void ResetGrowthLeft(CommonFields& common) {
    238  common.growth_info().InitGrowthLeftNoDeleted(
    239      CapacityToGrowth(common.capacity()) - common.size());
    240 }
    241 
    242 // Finds guaranteed to exists empty slot from the given position.
    243 // NOTE: this function is almost never triggered inside of the
    244 // DropDeletesWithoutResize, so we keep it simple.
    245 // The table is rather sparse, so empty slot will be found very quickly.
    246 size_t FindEmptySlot(size_t start, size_t end, const ctrl_t* ctrl) {
    247  for (size_t i = start; i < end; ++i) {
    248    if (IsEmpty(ctrl[i])) {
    249      return i;
    250    }
    251  }
    252  ABSL_UNREACHABLE();
    253 }
    254 
    255 // Finds guaranteed to exist full slot starting from the given position.
    256 // NOTE: this function is only triggered for rehash(0), when we need to
    257 // go back to SOO state, so we keep it simple.
    258 size_t FindFirstFullSlot(size_t start, size_t end, const ctrl_t* ctrl) {
    259  for (size_t i = start; i < end; ++i) {
    260    if (IsFull(ctrl[i])) {
    261      return i;
    262    }
    263  }
    264  ABSL_UNREACHABLE();
    265 }
    266 
    267 size_t DropDeletesWithoutResizeAndPrepareInsert(CommonFields& common,
    268                                                const PolicyFunctions& policy,
    269                                                size_t new_hash) {
    270  void* set = &common;
    271  void* slot_array = common.slot_array();
    272  const size_t capacity = common.capacity();
    273  assert(IsValidCapacity(capacity));
    274  assert(!is_small(capacity));
    275  // Algorithm:
    276  // - mark all DELETED slots as EMPTY
    277  // - mark all FULL slots as DELETED
    278  // - for each slot marked as DELETED
    279  //     hash = Hash(element)
    280  //     target = find_first_non_full(hash)
    281  //     if target is in the same group
    282  //       mark slot as FULL
    283  //     else if target is EMPTY
    284  //       transfer element to target
    285  //       mark slot as EMPTY
    286  //       mark target as FULL
    287  //     else if target is DELETED
    288  //       swap current element with target element
    289  //       mark target as FULL
    290  //       repeat procedure for current slot with moved from element (target)
    291  ctrl_t* ctrl = common.control();
    292  ConvertDeletedToEmptyAndFullToDeleted(ctrl, capacity);
    293  const void* hash_fn = policy.hash_fn(common);
    294  auto hasher = policy.hash_slot;
    295  auto transfer_n = policy.transfer_n;
    296  const size_t slot_size = policy.slot_size;
    297 
    298  size_t total_probe_length = 0;
    299  void* slot_ptr = SlotAddress(slot_array, 0, slot_size);
    300 
    301  // The index of an empty slot that can be used as temporary memory for
    302  // the swap operation.
    303  constexpr size_t kUnknownId = ~size_t{};
    304  size_t tmp_space_id = kUnknownId;
    305 
    306  for (size_t i = 0; i != capacity;
    307       ++i, slot_ptr = NextSlot(slot_ptr, slot_size)) {
    308    assert(slot_ptr == SlotAddress(slot_array, i, slot_size));
    309    if (IsEmpty(ctrl[i])) {
    310      tmp_space_id = i;
    311      continue;
    312    }
    313    if (!IsDeleted(ctrl[i])) continue;
    314    const size_t hash = (*hasher)(hash_fn, slot_ptr);
    315    const FindInfo target = find_first_non_full(common, hash);
    316    const size_t new_i = target.offset;
    317    total_probe_length += target.probe_length;
    318 
    319    // Verify if the old and new i fall within the same group wrt the hash.
    320    // If they do, we don't need to move the object as it falls already in the
    321    // best probe we can.
    322    const size_t probe_offset = probe(common, hash).offset();
    323    const h2_t h2 = H2(hash);
    324    const auto probe_index = [probe_offset, capacity](size_t pos) {
    325      return ((pos - probe_offset) & capacity) / Group::kWidth;
    326    };
    327 
    328    // Element doesn't move.
    329    if (ABSL_PREDICT_TRUE(probe_index(new_i) == probe_index(i))) {
    330      SetCtrlInLargeTable(common, i, h2, slot_size);
    331      continue;
    332    }
    333 
    334    void* new_slot_ptr = SlotAddress(slot_array, new_i, slot_size);
    335    if (IsEmpty(ctrl[new_i])) {
    336      // Transfer element to the empty spot.
    337      // SetCtrl poisons/unpoisons the slots so we have to call it at the
    338      // right time.
    339      SetCtrlInLargeTable(common, new_i, h2, slot_size);
    340      (*transfer_n)(set, new_slot_ptr, slot_ptr, 1);
    341      SetCtrlInLargeTable(common, i, ctrl_t::kEmpty, slot_size);
    342      // Initialize or change empty space id.
    343      tmp_space_id = i;
    344    } else {
    345      assert(IsDeleted(ctrl[new_i]));
    346      SetCtrlInLargeTable(common, new_i, h2, slot_size);
    347      // Until we are done rehashing, DELETED marks previously FULL slots.
    348 
    349      if (tmp_space_id == kUnknownId) {
    350        tmp_space_id = FindEmptySlot(i + 1, capacity, ctrl);
    351      }
    352      void* tmp_space = SlotAddress(slot_array, tmp_space_id, slot_size);
    353      SanitizerUnpoisonMemoryRegion(tmp_space, slot_size);
    354 
    355      // Swap i and new_i elements.
    356      (*transfer_n)(set, tmp_space, new_slot_ptr, 1);
    357      (*transfer_n)(set, new_slot_ptr, slot_ptr, 1);
    358      (*transfer_n)(set, slot_ptr, tmp_space, 1);
    359 
    360      SanitizerPoisonMemoryRegion(tmp_space, slot_size);
    361 
    362      // repeat the processing of the ith slot
    363      --i;
    364      slot_ptr = PrevSlot(slot_ptr, slot_size);
    365    }
    366  }
    367  // Prepare insert for the new element.
    368  PrepareInsertCommon(common);
    369  ResetGrowthLeft(common);
    370  FindInfo find_info = find_first_non_full(common, new_hash);
    371  SetCtrlInLargeTable(common, find_info.offset, H2(new_hash), policy.slot_size);
    372  common.infoz().RecordInsert(new_hash, find_info.probe_length);
    373  common.infoz().RecordRehash(total_probe_length);
    374  return find_info.offset;
    375 }
    376 
    377 static bool WasNeverFull(CommonFields& c, size_t index) {
    378  if (is_single_group(c.capacity())) {
    379    return true;
    380  }
    381  const size_t index_before = (index - Group::kWidth) & c.capacity();
    382  const auto empty_after = Group(c.control() + index).MaskEmpty();
    383  const auto empty_before = Group(c.control() + index_before).MaskEmpty();
    384 
    385  // We count how many consecutive non empties we have to the right and to the
    386  // left of `it`. If the sum is >= kWidth then there is at least one probe
    387  // window that might have seen a full group.
    388  return empty_before && empty_after &&
    389         static_cast<size_t>(empty_after.TrailingZeros()) +
    390                 empty_before.LeadingZeros() <
    391             Group::kWidth;
    392 }
    393 
    394 // Updates the control bytes to indicate a completely empty table such that all
    395 // control bytes are kEmpty except for the kSentinel byte.
    396 void ResetCtrl(CommonFields& common, size_t slot_size) {
    397  const size_t capacity = common.capacity();
    398  ctrl_t* ctrl = common.control();
    399  static constexpr size_t kTwoGroupCapacity = 2 * Group::kWidth - 1;
    400  if (ABSL_PREDICT_TRUE(capacity <= kTwoGroupCapacity)) {
    401    std::memset(ctrl, static_cast<int8_t>(ctrl_t::kEmpty), Group::kWidth);
    402    std::memset(ctrl + capacity, static_cast<int8_t>(ctrl_t::kEmpty),
    403                Group::kWidth);
    404    if (capacity == kTwoGroupCapacity) {
    405      std::memset(ctrl + Group::kWidth, static_cast<int8_t>(ctrl_t::kEmpty),
    406                  Group::kWidth);
    407    }
    408  } else {
    409    std::memset(ctrl, static_cast<int8_t>(ctrl_t::kEmpty),
    410                capacity + 1 + NumClonedBytes());
    411  }
    412  ctrl[capacity] = ctrl_t::kSentinel;
    413  SanitizerPoisonMemoryRegion(common.slot_array(), slot_size * capacity);
    414 }
    415 
    416 // Initializes control bytes for single element table.
    417 // Capacity of the table must be 1.
    418 ABSL_ATTRIBUTE_ALWAYS_INLINE inline void InitializeSingleElementControlBytes(
    419    uint64_t h2, ctrl_t* new_ctrl) {
    420  static constexpr uint64_t kEmptyXorSentinel =
    421      static_cast<uint8_t>(ctrl_t::kEmpty) ^
    422      static_cast<uint8_t>(ctrl_t::kSentinel);
    423  static constexpr uint64_t kEmpty64 = static_cast<uint8_t>(ctrl_t::kEmpty);
    424  // The first 8 bytes, where present slot positions are replaced with 0.
    425  static constexpr uint64_t kFirstCtrlBytesWithZeroes =
    426      k8EmptyBytes ^ kEmpty64 ^ (kEmptyXorSentinel << 8) ^ (kEmpty64 << 16);
    427 
    428  // Fill the original 0th and mirrored 2nd bytes with the hash.
    429  // Result will look like:
    430  // HSHEEEEE
    431  // Where H = h2, E = kEmpty, S = kSentinel.
    432  const uint64_t first_ctrl_bytes =
    433      (h2 | kFirstCtrlBytesWithZeroes) | (h2 << 16);
    434  // Fill last bytes with kEmpty.
    435  std::memset(new_ctrl + 1, static_cast<int8_t>(ctrl_t::kEmpty), Group::kWidth);
    436  // Overwrite the first 3 bytes with HSH. Other bytes will not be changed.
    437  absl::little_endian::Store64(new_ctrl, first_ctrl_bytes);
    438 }
    439 
    440 // Initializes control bytes after SOO to the next capacity.
    441 // The table must be non-empty SOO.
    442 ABSL_ATTRIBUTE_ALWAYS_INLINE inline void
    443 InitializeThreeElementsControlBytesAfterSoo(size_t hash, ctrl_t* new_ctrl) {
    444  static constexpr size_t kNewCapacity = NextCapacity(SooCapacity());
    445  static_assert(kNewCapacity == 3);
    446  static_assert(is_single_group(kNewCapacity));
    447  static_assert(SooSlotIndex() == 1);
    448 
    449  static constexpr uint64_t kEmptyXorSentinel =
    450      static_cast<uint8_t>(ctrl_t::kEmpty) ^
    451      static_cast<uint8_t>(ctrl_t::kSentinel);
    452  static constexpr uint64_t kEmpty64 = static_cast<uint8_t>(ctrl_t::kEmpty);
    453  static constexpr size_t kMirroredSooSlotIndex =
    454      SooSlotIndex() + kNewCapacity + 1;
    455  // The first 8 bytes, where present slot positions are replaced with 0.
    456  static constexpr uint64_t kFirstCtrlBytesWithZeroes =
    457      k8EmptyBytes ^ (kEmpty64 << (8 * SooSlotIndex())) ^
    458      (kEmptyXorSentinel << (8 * kNewCapacity)) ^
    459      (kEmpty64 << (8 * kMirroredSooSlotIndex));
    460 
    461  const uint64_t h2 = static_cast<uint64_t>(H2(hash));
    462  // Fill the original 0th and mirrored 2nd bytes with the hash.
    463  // Result will look like:
    464  // EHESEHEE
    465  // Where H = h2, E = kEmpty, S = kSentinel.
    466  const uint64_t first_ctrl_bytes =
    467      ((h2 << (8 * SooSlotIndex())) | kFirstCtrlBytesWithZeroes) |
    468      (h2 << (8 * kMirroredSooSlotIndex));
    469 
    470  // Fill last bytes with kEmpty.
    471  std::memset(new_ctrl + kNewCapacity, static_cast<int8_t>(ctrl_t::kEmpty),
    472              Group::kWidth);
    473  // Overwrite the first 8 bytes with first_ctrl_bytes.
    474  absl::little_endian::Store64(new_ctrl, first_ctrl_bytes);
    475 
    476  // Example for group size 16:
    477  // new_ctrl after 1st memset =      ???EEEEEEEEEEEEEEEE
    478  // new_ctrl after 2nd store  =      EHESEHEEEEEEEEEEEEE
    479 
    480  // Example for group size 8:
    481  // new_ctrl after 1st memset =      ???EEEEEEEE
    482  // new_ctrl after 2nd store  =      EHESEHEEEEE
    483 }
    484 
    485 }  // namespace
    486 
    487 void EraseMetaOnly(CommonFields& c, size_t index, size_t slot_size) {
    488  assert(IsFull(c.control()[index]) && "erasing a dangling iterator");
    489  c.decrement_size();
    490  c.infoz().RecordErase();
    491 
    492  if (WasNeverFull(c, index)) {
    493    SetCtrl(c, index, ctrl_t::kEmpty, slot_size);
    494    c.growth_info().OverwriteFullAsEmpty();
    495    return;
    496  }
    497 
    498  c.growth_info().OverwriteFullAsDeleted();
    499  SetCtrlInLargeTable(c, index, ctrl_t::kDeleted, slot_size);
    500 }
    501 
    502 void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
    503                       void* alloc, bool reuse, bool soo_enabled) {
    504  if (reuse) {
    505    c.set_size_to_zero();
    506    assert(!soo_enabled || c.capacity() > SooCapacity());
    507    ResetCtrl(c, policy.slot_size);
    508    ResetGrowthLeft(c);
    509    c.infoz().RecordStorageChanged(0, c.capacity());
    510  } else {
    511    // We need to record infoz before calling dealloc, which will unregister
    512    // infoz.
    513    c.infoz().RecordClearedReservation();
    514    c.infoz().RecordStorageChanged(0, soo_enabled ? SooCapacity() : 0);
    515    c.infoz().Unregister();
    516    (*policy.dealloc)(alloc, c.capacity(), c.control(), policy.slot_size,
    517                      policy.slot_align, c.has_infoz());
    518    c = soo_enabled ? CommonFields{soo_tag_t{}} : CommonFields{non_soo_tag_t{}};
    519  }
    520 }
    521 
    522 namespace {
    523 
    524 // Poisons empty slots. It is useful when slots are transferred via memcpy.
    525 // PRECONDITIONs: common.control() is fully initialized.
    526 void PoisonEmptySlots(CommonFields& c, size_t slot_size) {
    527  for (size_t i = 0; i < c.capacity(); ++i) {
    528    if (!IsFull(c.control()[i])) {
    529      SanitizerPoisonMemoryRegion(SlotAddress(c.slot_array(), i, slot_size),
    530                                  slot_size);
    531    }
    532  }
    533 }
    534 
    535 enum class ResizeNonSooMode {
    536  kGuaranteedEmpty,
    537  kGuaranteedAllocated,
    538 };
    539 
    540 template <ResizeNonSooMode kMode>
    541 void ResizeNonSooImpl(CommonFields& common, const PolicyFunctions& policy,
    542                      size_t new_capacity, HashtablezInfoHandle infoz) {
    543  assert(IsValidCapacity(new_capacity));
    544  assert(new_capacity > policy.soo_capacity);
    545 
    546  const size_t old_capacity = common.capacity();
    547  [[maybe_unused]] ctrl_t* old_ctrl = common.control();
    548  [[maybe_unused]] void* old_slots = common.slot_array();
    549 
    550  const size_t slot_size = policy.slot_size;
    551  const size_t slot_align = policy.slot_align;
    552  const bool has_infoz = infoz.IsSampled();
    553 
    554  common.set_capacity(new_capacity);
    555  RawHashSetLayout layout(new_capacity, slot_size, slot_align, has_infoz);
    556  void* alloc = policy.get_char_alloc(common);
    557  char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
    558  const GenerationType old_generation = common.generation();
    559  common.set_generation_ptr(
    560      reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
    561  common.set_generation(NextGeneration(old_generation));
    562 
    563  common.set_control</*kGenerateSeed=*/true>(
    564      reinterpret_cast<ctrl_t*>(mem + layout.control_offset()));
    565  common.set_slots(mem + layout.slot_offset());
    566 
    567  size_t total_probe_length = 0;
    568  ResetCtrl(common, slot_size);
    569  assert(kMode != ResizeNonSooMode::kGuaranteedEmpty ||
    570         old_capacity == policy.soo_capacity);
    571  assert(kMode != ResizeNonSooMode::kGuaranteedAllocated || old_capacity > 0);
    572  if constexpr (kMode == ResizeNonSooMode::kGuaranteedAllocated) {
    573    total_probe_length = policy.find_new_positions_and_transfer_slots(
    574        common, old_ctrl, old_slots, old_capacity);
    575    (*policy.dealloc)(alloc, old_capacity, old_ctrl, slot_size, slot_align,
    576                      has_infoz);
    577  }
    578 
    579  ResetGrowthLeft(common);
    580  if (has_infoz) {
    581    common.set_has_infoz();
    582    infoz.RecordStorageChanged(common.size(), new_capacity);
    583    infoz.RecordRehash(total_probe_length);
    584    common.set_infoz(infoz);
    585  }
    586 }
    587 
    588 void ResizeEmptyNonAllocatedTableImpl(CommonFields& common,
    589                                      const PolicyFunctions& policy,
    590                                      size_t new_capacity, bool force_infoz) {
    591  assert(IsValidCapacity(new_capacity));
    592  assert(new_capacity > policy.soo_capacity);
    593  assert(!force_infoz || policy.soo_capacity > 0);
    594  assert(common.capacity() <= policy.soo_capacity);
    595  assert(common.empty());
    596  const size_t slot_size = policy.slot_size;
    597  HashtablezInfoHandle infoz;
    598  const bool should_sample =
    599      policy.is_hashtablez_eligible && (force_infoz || ShouldSampleNextTable());
    600  if (ABSL_PREDICT_FALSE(should_sample)) {
    601    infoz = ForcedTrySample(slot_size, policy.key_size, policy.value_size,
    602                            policy.soo_capacity);
    603  }
    604  ResizeNonSooImpl<ResizeNonSooMode::kGuaranteedEmpty>(common, policy,
    605                                                       new_capacity, infoz);
    606 }
    607 
    608 // If the table was SOO, initializes new control bytes and transfers slot.
    609 // After transferring the slot, sets control and slots in CommonFields.
    610 // It is rare to resize an SOO table with one element to a large size.
    611 // Requires: `c` contains SOO data.
    612 void InsertOldSooSlotAndInitializeControlBytes(CommonFields& c,
    613                                               const PolicyFunctions& policy,
    614                                               size_t hash, ctrl_t* new_ctrl,
    615                                               void* new_slots) {
    616  assert(c.size() == policy.soo_capacity);
    617  assert(policy.soo_capacity == SooCapacity());
    618  size_t new_capacity = c.capacity();
    619 
    620  c.generate_new_seed();
    621  size_t offset = probe(c.seed(), new_capacity, hash).offset();
    622  offset = offset == new_capacity ? 0 : offset;
    623  SanitizerPoisonMemoryRegion(new_slots, policy.slot_size * new_capacity);
    624  void* target_slot = SlotAddress(new_slots, offset, policy.slot_size);
    625  SanitizerUnpoisonMemoryRegion(target_slot, policy.slot_size);
    626  policy.transfer_n(&c, target_slot, c.soo_data(), 1);
    627  c.set_control</*kGenerateSeed=*/false>(new_ctrl);
    628  c.set_slots(new_slots);
    629  ResetCtrl(c, policy.slot_size);
    630  SetCtrl(c, offset, H2(hash), policy.slot_size);
    631 }
    632 
    633 enum class ResizeFullSooTableSamplingMode {
    634  kNoSampling,
    635  // Force sampling. If the table was still not sampled, do not resize.
    636  kForceSampleNoResizeIfUnsampled,
    637 };
    638 
    639 void ResizeFullSooTable(CommonFields& common, const PolicyFunctions& policy,
    640                        size_t new_capacity,
    641                        ResizeFullSooTableSamplingMode sampling_mode) {
    642  assert(common.capacity() == policy.soo_capacity);
    643  assert(common.size() == policy.soo_capacity);
    644  assert(policy.soo_capacity == SooCapacity());
    645  const size_t slot_size = policy.slot_size;
    646  const size_t slot_align = policy.slot_align;
    647 
    648  HashtablezInfoHandle infoz;
    649  if (sampling_mode ==
    650      ResizeFullSooTableSamplingMode::kForceSampleNoResizeIfUnsampled) {
    651    if (ABSL_PREDICT_FALSE(policy.is_hashtablez_eligible)) {
    652      infoz = ForcedTrySample(slot_size, policy.key_size, policy.value_size,
    653                              policy.soo_capacity);
    654    }
    655 
    656    if (!infoz.IsSampled()) {
    657      return;
    658    }
    659  }
    660 
    661  const bool has_infoz = infoz.IsSampled();
    662 
    663  common.set_capacity(new_capacity);
    664 
    665  RawHashSetLayout layout(new_capacity, slot_size, slot_align, has_infoz);
    666  void* alloc = policy.get_char_alloc(common);
    667  char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
    668  const GenerationType old_generation = common.generation();
    669  common.set_generation_ptr(
    670      reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
    671  common.set_generation(NextGeneration(old_generation));
    672 
    673  // We do not set control and slots in CommonFields yet to avoid overriding
    674  // SOO data.
    675  ctrl_t* new_ctrl = reinterpret_cast<ctrl_t*>(mem + layout.control_offset());
    676  void* new_slots = mem + layout.slot_offset();
    677 
    678  const size_t soo_slot_hash =
    679      policy.hash_slot(policy.hash_fn(common), common.soo_data());
    680 
    681  InsertOldSooSlotAndInitializeControlBytes(common, policy, soo_slot_hash,
    682                                            new_ctrl, new_slots);
    683  ResetGrowthLeft(common);
    684  if (has_infoz) {
    685    common.set_has_infoz();
    686    common.set_infoz(infoz);
    687  }
    688 }
    689 
    690 void GrowIntoSingleGroupShuffleControlBytes(ctrl_t* __restrict old_ctrl,
    691                                            size_t old_capacity,
    692                                            ctrl_t* __restrict new_ctrl,
    693                                            size_t new_capacity) {
    694  assert(is_single_group(new_capacity));
    695  constexpr size_t kHalfWidth = Group::kWidth / 2;
    696  ABSL_ASSUME(old_capacity < kHalfWidth);
    697  ABSL_ASSUME(old_capacity > 0);
    698  static_assert(Group::kWidth == 8 || Group::kWidth == 16,
    699                "Group size is not supported.");
    700 
    701  // NOTE: operations are done with compile time known size = 8.
    702  // Compiler optimizes that into single ASM operation.
    703 
    704  // Load the bytes from old_capacity. This contains
    705  // - the sentinel byte
    706  // - all the old control bytes
    707  // - the rest is filled with kEmpty bytes
    708  // Example:
    709  // old_ctrl =     012S012EEEEEEEEE...
    710  // copied_bytes = S012EEEE
    711  uint64_t copied_bytes = absl::little_endian::Load64(old_ctrl + old_capacity);
    712 
    713  // We change the sentinel byte to kEmpty before storing to both the start of
    714  // the new_ctrl, and past the end of the new_ctrl later for the new cloned
    715  // bytes. Note that this is faster than setting the sentinel byte to kEmpty
    716  // after the copy directly in new_ctrl because we are limited on store
    717  // bandwidth.
    718  static constexpr uint64_t kEmptyXorSentinel =
    719      static_cast<uint8_t>(ctrl_t::kEmpty) ^
    720      static_cast<uint8_t>(ctrl_t::kSentinel);
    721 
    722  // Replace the first byte kSentinel with kEmpty.
    723  // Resulting bytes will be shifted by one byte old control blocks.
    724  // Example:
    725  // old_ctrl = 012S012EEEEEEEEE...
    726  // before =   S012EEEE
    727  // after  =   E012EEEE
    728  copied_bytes ^= kEmptyXorSentinel;
    729 
    730  if (Group::kWidth == 8) {
    731    // With group size 8, we can grow with two write operations.
    732    assert(old_capacity < 8 && "old_capacity is too large for group size 8");
    733    absl::little_endian::Store64(new_ctrl, copied_bytes);
    734 
    735    static constexpr uint64_t kSentinal64 =
    736        static_cast<uint8_t>(ctrl_t::kSentinel);
    737 
    738    // Prepend kSentinel byte to the beginning of copied_bytes.
    739    // We have maximum 3 non-empty bytes at the beginning of copied_bytes for
    740    // group size 8.
    741    // Example:
    742    // old_ctrl = 012S012EEEE
    743    // before =   E012EEEE
    744    // after  =   SE012EEE
    745    copied_bytes = (copied_bytes << 8) ^ kSentinal64;
    746    absl::little_endian::Store64(new_ctrl + new_capacity, copied_bytes);
    747    // Example for capacity 3:
    748    // old_ctrl = 012S012EEEE
    749    // After the first store:
    750    //           >!
    751    // new_ctrl = E012EEEE???????
    752    // After the second store:
    753    //                  >!
    754    // new_ctrl = E012EEESE012EEE
    755    return;
    756  }
    757 
    758  assert(Group::kWidth == 16);
    759 
    760  // Fill the second half of the main control bytes with kEmpty.
    761  // For small capacity that may write into mirrored control bytes.
    762  // It is fine as we will overwrite all the bytes later.
    763  std::memset(new_ctrl + kHalfWidth, static_cast<int8_t>(ctrl_t::kEmpty),
    764              kHalfWidth);
    765  // Fill the second half of the mirrored control bytes with kEmpty.
    766  std::memset(new_ctrl + new_capacity + kHalfWidth,
    767              static_cast<int8_t>(ctrl_t::kEmpty), kHalfWidth);
    768  // Copy the first half of the non-mirrored control bytes.
    769  absl::little_endian::Store64(new_ctrl, copied_bytes);
    770  new_ctrl[new_capacity] = ctrl_t::kSentinel;
    771  // Copy the first half of the mirrored control bytes.
    772  absl::little_endian::Store64(new_ctrl + new_capacity + 1, copied_bytes);
    773 
    774  // Example for growth capacity 1->3:
    775  // old_ctrl =                  0S0EEEEEEEEEEEEEE
    776  // new_ctrl at the end =       E0ESE0EEEEEEEEEEEEE
    777  //                                    >!
    778  // new_ctrl after 1st memset = ????????EEEEEEEE???
    779  //                                       >!
    780  // new_ctrl after 2nd memset = ????????EEEEEEEEEEE
    781  //                            >!
    782  // new_ctrl after 1st store =  E0EEEEEEEEEEEEEEEEE
    783  // new_ctrl after kSentinel =  E0ESEEEEEEEEEEEEEEE
    784  //                                >!
    785  // new_ctrl after 2nd store =  E0ESE0EEEEEEEEEEEEE
    786 
    787  // Example for growth capacity 3->7:
    788  // old_ctrl =                  012S012EEEEEEEEEEEE
    789  // new_ctrl at the end =       E012EEESE012EEEEEEEEEEE
    790  //                                    >!
    791  // new_ctrl after 1st memset = ????????EEEEEEEE???????
    792  //                                           >!
    793  // new_ctrl after 2nd memset = ????????EEEEEEEEEEEEEEE
    794  //                            >!
    795  // new_ctrl after 1st store =  E012EEEEEEEEEEEEEEEEEEE
    796  // new_ctrl after kSentinel =  E012EEESEEEEEEEEEEEEEEE
    797  //                                >!
    798  // new_ctrl after 2nd store =  E012EEESE012EEEEEEEEEEE
    799 
    800  // Example for growth capacity 7->15:
    801  // old_ctrl =                  0123456S0123456EEEEEEEE
    802  // new_ctrl at the end =       E0123456EEEEEEESE0123456EEEEEEE
    803  //                                    >!
    804  // new_ctrl after 1st memset = ????????EEEEEEEE???????????????
    805  //                                                   >!
    806  // new_ctrl after 2nd memset = ????????EEEEEEEE???????EEEEEEEE
    807  //                            >!
    808  // new_ctrl after 1st store =  E0123456EEEEEEEE???????EEEEEEEE
    809  // new_ctrl after kSentinel =  E0123456EEEEEEES???????EEEEEEEE
    810  //                                            >!
    811  // new_ctrl after 2nd store =  E0123456EEEEEEESE0123456EEEEEEE
    812 }
    813 
    814 size_t GrowToNextCapacityAndPrepareInsert(CommonFields& common,
    815                                          const PolicyFunctions& policy,
    816                                          size_t new_hash) {
    817  assert(common.growth_left() == 0);
    818  const size_t old_capacity = common.capacity();
    819  assert(old_capacity == 0 || old_capacity > policy.soo_capacity);
    820 
    821  const size_t new_capacity = NextCapacity(old_capacity);
    822  assert(IsValidCapacity(new_capacity));
    823  assert(new_capacity > policy.soo_capacity);
    824 
    825  ctrl_t* old_ctrl = common.control();
    826  void* old_slots = common.slot_array();
    827 
    828  common.set_capacity(new_capacity);
    829  const size_t slot_size = policy.slot_size;
    830  const size_t slot_align = policy.slot_align;
    831  HashtablezInfoHandle infoz;
    832  if (old_capacity > 0) {
    833    infoz = common.infoz();
    834  } else {
    835    const bool should_sample =
    836        policy.is_hashtablez_eligible && ShouldSampleNextTable();
    837    if (ABSL_PREDICT_FALSE(should_sample)) {
    838      infoz = ForcedTrySample(slot_size, policy.key_size, policy.value_size,
    839                              policy.soo_capacity);
    840    }
    841  }
    842  const bool has_infoz = infoz.IsSampled();
    843 
    844  RawHashSetLayout layout(new_capacity, slot_size, slot_align, has_infoz);
    845  void* alloc = policy.get_char_alloc(common);
    846  char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
    847  const GenerationType old_generation = common.generation();
    848  common.set_generation_ptr(
    849      reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
    850  common.set_generation(NextGeneration(old_generation));
    851 
    852  ctrl_t* new_ctrl = reinterpret_cast<ctrl_t*>(mem + layout.control_offset());
    853  void* new_slots = mem + layout.slot_offset();
    854  common.set_control</*kGenerateSeed=*/false>(new_ctrl);
    855  common.set_slots(new_slots);
    856 
    857  h2_t new_h2 = H2(new_hash);
    858  size_t total_probe_length = 0;
    859  FindInfo find_info;
    860  if (old_capacity == 0) {
    861    static_assert(NextCapacity(0) == 1);
    862    InitializeSingleElementControlBytes(new_h2, new_ctrl);
    863    common.generate_new_seed();
    864    find_info = FindInfo{0, 0};
    865  } else {
    866    if (ABSL_PREDICT_TRUE(is_single_group(new_capacity))) {
    867      GrowIntoSingleGroupShuffleControlBytes(old_ctrl, old_capacity, new_ctrl,
    868                                             new_capacity);
    869      // Single group tables have all slots full on resize. So we can transfer
    870      // all slots without checking the control bytes.
    871      assert(common.size() == old_capacity);
    872      policy.transfer_n(&common, NextSlot(new_slots, slot_size), old_slots,
    873                        old_capacity);
    874      PoisonEmptySlots(common, slot_size);
    875      // We put the new element either at the beginning or at the end of the
    876      // table with approximately equal probability.
    877      size_t offset = SingleGroupTableH1(new_hash, common.seed()) & 1
    878                          ? 0
    879                          : new_capacity - 1;
    880 
    881      assert(IsEmpty(new_ctrl[offset]));
    882      SetCtrlInSingleGroupTable(common, offset, new_h2, policy.slot_size);
    883      find_info = FindInfo{offset, 0};
    884    } else {
    885      ResetCtrl(common, slot_size);
    886      total_probe_length = policy.find_new_positions_and_transfer_slots(
    887          common, old_ctrl, old_slots, old_capacity);
    888      find_info = find_first_non_full(common, new_hash);
    889      SetCtrlInLargeTable(common, find_info.offset, new_h2, policy.slot_size);
    890    }
    891    assert(old_capacity > policy.soo_capacity);
    892    (*policy.dealloc)(alloc, old_capacity, old_ctrl, slot_size, slot_align,
    893                      has_infoz);
    894  }
    895  PrepareInsertCommon(common);
    896  ResetGrowthLeft(common);
    897 
    898  if (ABSL_PREDICT_FALSE(has_infoz)) {
    899    common.set_has_infoz();
    900    infoz.RecordStorageChanged(common.size() - 1, new_capacity);
    901    infoz.RecordRehash(total_probe_length);
    902    infoz.RecordInsert(new_hash, find_info.probe_length);
    903    common.set_infoz(infoz);
    904  }
    905  return find_info.offset;
    906 }
    907 
    908 // Called whenever the table needs to vacate empty slots either by removing
    909 // tombstones via rehash or growth to next capacity.
    910 ABSL_ATTRIBUTE_NOINLINE
    911 size_t RehashOrGrowToNextCapacityAndPrepareInsert(CommonFields& common,
    912                                                  const PolicyFunctions& policy,
    913                                                  size_t new_hash) {
    914  const size_t cap = common.capacity();
    915  ABSL_ASSUME(cap > 0);
    916  if (cap > Group::kWidth &&
    917      // Do these calculations in 64-bit to avoid overflow.
    918      common.size() * uint64_t{32} <= cap * uint64_t{25}) {
    919    // Squash DELETED without growing if there is enough capacity.
    920    //
    921    // Rehash in place if the current size is <= 25/32 of capacity.
    922    // Rationale for such a high factor: 1) DropDeletesWithoutResize() is
    923    // faster than resize, and 2) it takes quite a bit of work to add
    924    // tombstones.  In the worst case, seems to take approximately 4
    925    // insert/erase pairs to create a single tombstone and so if we are
    926    // rehashing because of tombstones, we can afford to rehash-in-place as
    927    // long as we are reclaiming at least 1/8 the capacity without doing more
    928    // than 2X the work.  (Where "work" is defined to be size() for rehashing
    929    // or rehashing in place, and 1 for an insert or erase.)  But rehashing in
    930    // place is faster per operation than inserting or even doubling the size
    931    // of the table, so we actually afford to reclaim even less space from a
    932    // resize-in-place.  The decision is to rehash in place if we can reclaim
    933    // at about 1/8th of the usable capacity (specifically 3/28 of the
    934    // capacity) which means that the total cost of rehashing will be a small
    935    // fraction of the total work.
    936    //
    937    // Here is output of an experiment using the BM_CacheInSteadyState
    938    // benchmark running the old case (where we rehash-in-place only if we can
    939    // reclaim at least 7/16*capacity) vs. this code (which rehashes in place
    940    // if we can recover 3/32*capacity).
    941    //
    942    // Note that although in the worst-case number of rehashes jumped up from
    943    // 15 to 190, but the number of operations per second is almost the same.
    944    //
    945    // Abridged output of running BM_CacheInSteadyState benchmark from
    946    // raw_hash_set_benchmark.   N is the number of insert/erase operations.
    947    //
    948    //      | OLD (recover >= 7/16        | NEW (recover >= 3/32)
    949    // size |    N/s LoadFactor NRehashes |    N/s LoadFactor NRehashes
    950    //  448 | 145284       0.44        18 | 140118       0.44        19
    951    //  493 | 152546       0.24        11 | 151417       0.48        28
    952    //  538 | 151439       0.26        11 | 151152       0.53        38
    953    //  583 | 151765       0.28        11 | 150572       0.57        50
    954    //  628 | 150241       0.31        11 | 150853       0.61        66
    955    //  672 | 149602       0.33        12 | 150110       0.66        90
    956    //  717 | 149998       0.35        12 | 149531       0.70       129
    957    //  762 | 149836       0.37        13 | 148559       0.74       190
    958    //  807 | 149736       0.39        14 | 151107       0.39        14
    959    //  852 | 150204       0.42        15 | 151019       0.42        15
    960    return DropDeletesWithoutResizeAndPrepareInsert(common, policy, new_hash);
    961  } else {
    962    // Otherwise grow the container.
    963    return GrowToNextCapacityAndPrepareInsert(common, policy, new_hash);
    964  }
    965 }
    966 
    967 // Slow path for PrepareInsertNonSoo that is called when the table has deleted
    968 // slots or need to be resized or rehashed.
    969 size_t PrepareInsertNonSooSlow(CommonFields& common,
    970                               const PolicyFunctions& policy, size_t hash) {
    971  const GrowthInfo growth_info = common.growth_info();
    972  assert(!growth_info.HasNoDeletedAndGrowthLeft());
    973  if (ABSL_PREDICT_TRUE(growth_info.HasNoGrowthLeftAndNoDeleted())) {
    974    // Table without deleted slots (>95% cases) that needs to be resized.
    975    assert(growth_info.HasNoDeleted() && growth_info.GetGrowthLeft() == 0);
    976    return GrowToNextCapacityAndPrepareInsert(common, policy, hash);
    977  }
    978  if (ABSL_PREDICT_FALSE(growth_info.HasNoGrowthLeftAssumingMayHaveDeleted())) {
    979    // Table with deleted slots that needs to be rehashed or resized.
    980    return RehashOrGrowToNextCapacityAndPrepareInsert(common, policy, hash);
    981  }
    982  // Table with deleted slots that has space for the inserting element.
    983  FindInfo target = find_first_non_full(common, hash);
    984  PrepareInsertCommon(common);
    985  common.growth_info().OverwriteControlAsFull(common.control()[target.offset]);
    986  SetCtrlInLargeTable(common, target.offset, H2(hash), policy.slot_size);
    987  common.infoz().RecordInsert(hash, target.probe_length);
    988  return target.offset;
    989 }
    990 
    991 }  // namespace
    992 
    993 void* GetRefForEmptyClass(CommonFields& common) {
    994  // Empty base optimization typically make the empty base class address to be
    995  // the same as the first address of the derived class object.
    996  // But we generally assume that for empty classes we can return any valid
    997  // pointer.
    998  return &common;
    999 }
   1000 
   1001 void ResizeAllocatedTableWithSeedChange(CommonFields& common,
   1002                                        const PolicyFunctions& policy,
   1003                                        size_t new_capacity) {
   1004  ResizeNonSooImpl<ResizeNonSooMode::kGuaranteedAllocated>(
   1005      common, policy, new_capacity, common.infoz());
   1006 }
   1007 
   1008 void ReserveEmptyNonAllocatedTableToFitNewSize(CommonFields& common,
   1009                                               const PolicyFunctions& policy,
   1010                                               size_t new_size) {
   1011  ValidateMaxSize(new_size, policy.slot_size);
   1012  ResizeEmptyNonAllocatedTableImpl(
   1013      common, policy, NormalizeCapacity(GrowthToLowerboundCapacity(new_size)),
   1014      /*force_infoz=*/false);
   1015  // This is after resize, to ensure that we have completed the allocation
   1016  // and have potentially sampled the hashtable.
   1017  common.infoz().RecordReservation(new_size);
   1018  common.reset_reserved_growth(new_size);
   1019  common.set_reservation_size(new_size);
   1020 }
   1021 
   1022 void ReserveEmptyNonAllocatedTableToFitBucketCount(
   1023    CommonFields& common, const PolicyFunctions& policy, size_t bucket_count) {
   1024  size_t new_capacity = NormalizeCapacity(bucket_count);
   1025  ValidateMaxSize(CapacityToGrowth(new_capacity), policy.slot_size);
   1026  ResizeEmptyNonAllocatedTableImpl(common, policy, new_capacity,
   1027                                   /*force_infoz=*/false);
   1028 }
   1029 
   1030 void GrowEmptySooTableToNextCapacityForceSampling(
   1031    CommonFields& common, const PolicyFunctions& policy) {
   1032  ResizeEmptyNonAllocatedTableImpl(common, policy, NextCapacity(SooCapacity()),
   1033                                   /*force_infoz=*/true);
   1034 }
   1035 
   1036 // Resizes a full SOO table to the NextCapacity(SooCapacity()).
   1037 template <size_t SooSlotMemcpySize, bool TransferUsesMemcpy>
   1038 void GrowFullSooTableToNextCapacity(CommonFields& common,
   1039                                    const PolicyFunctions& policy,
   1040                                    size_t soo_slot_hash) {
   1041  assert(common.capacity() == policy.soo_capacity);
   1042  assert(common.size() == policy.soo_capacity);
   1043  static constexpr size_t kNewCapacity = NextCapacity(SooCapacity());
   1044  assert(kNewCapacity > policy.soo_capacity);
   1045  assert(policy.soo_capacity == SooCapacity());
   1046  const size_t slot_size = policy.slot_size;
   1047  const size_t slot_align = policy.slot_align;
   1048  common.set_capacity(kNewCapacity);
   1049 
   1050  // Since the table is not empty, it will not be sampled.
   1051  // The decision to sample was already made during the first insertion.
   1052  RawHashSetLayout layout(kNewCapacity, slot_size, slot_align,
   1053                          /*has_infoz=*/false);
   1054  void* alloc = policy.get_char_alloc(common);
   1055  char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
   1056  const GenerationType old_generation = common.generation();
   1057  common.set_generation_ptr(
   1058      reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
   1059  common.set_generation(NextGeneration(old_generation));
   1060 
   1061  // We do not set control and slots in CommonFields yet to avoid overriding
   1062  // SOO data.
   1063  ctrl_t* new_ctrl = reinterpret_cast<ctrl_t*>(mem + layout.control_offset());
   1064  void* new_slots = mem + layout.slot_offset();
   1065 
   1066  InitializeThreeElementsControlBytesAfterSoo(soo_slot_hash, new_ctrl);
   1067 
   1068  SanitizerPoisonMemoryRegion(new_slots, slot_size * kNewCapacity);
   1069  void* target_slot = SlotAddress(new_slots, SooSlotIndex(), slot_size);
   1070  SanitizerUnpoisonMemoryRegion(target_slot, slot_size);
   1071  if constexpr (TransferUsesMemcpy) {
   1072    // Target slot is placed at index 1, but capacity is at
   1073    // minimum 3. So we are allowed to copy at least twice as much
   1074    // memory.
   1075    static_assert(SooSlotIndex() == 1);
   1076    static_assert(SooSlotMemcpySize > 0);
   1077    static_assert(SooSlotMemcpySize <= MaxSooSlotSize());
   1078    assert(SooSlotMemcpySize <= 2 * slot_size);
   1079    assert(SooSlotMemcpySize >= slot_size);
   1080    void* next_slot = SlotAddress(target_slot, 1, slot_size);
   1081    SanitizerUnpoisonMemoryRegion(next_slot, SooSlotMemcpySize - slot_size);
   1082    std::memcpy(target_slot, common.soo_data(), SooSlotMemcpySize);
   1083    SanitizerPoisonMemoryRegion(next_slot, SooSlotMemcpySize - slot_size);
   1084  } else {
   1085    static_assert(SooSlotMemcpySize == 0);
   1086    policy.transfer_n(&common, target_slot, common.soo_data(), 1);
   1087  }
   1088  common.set_control</*kGenerateSeed=*/true>(new_ctrl);
   1089  common.set_slots(new_slots);
   1090 
   1091  ResetGrowthLeft(common);
   1092 }
   1093 
   1094 void GrowFullSooTableToNextCapacityForceSampling(
   1095    CommonFields& common, const PolicyFunctions& policy) {
   1096  assert(common.capacity() == policy.soo_capacity);
   1097  assert(common.size() == policy.soo_capacity);
   1098  assert(policy.soo_capacity == SooCapacity());
   1099  ResizeFullSooTable(
   1100      common, policy, NextCapacity(SooCapacity()),
   1101      ResizeFullSooTableSamplingMode::kForceSampleNoResizeIfUnsampled);
   1102 }
   1103 
   1104 void Rehash(CommonFields& common, const PolicyFunctions& policy, size_t n) {
   1105  const size_t cap = common.capacity();
   1106 
   1107  auto clear_backing_array = [&]() {
   1108    ClearBackingArray(common, policy, policy.get_char_alloc(common),
   1109                      /*reuse=*/false, policy.soo_capacity > 0);
   1110  };
   1111 
   1112  const size_t slot_size = policy.slot_size;
   1113 
   1114  if (n == 0) {
   1115    if (cap <= policy.soo_capacity) return;
   1116    if (common.empty()) {
   1117      clear_backing_array();
   1118      return;
   1119    }
   1120    if (common.size() <= policy.soo_capacity) {
   1121      // When the table is already sampled, we keep it sampled.
   1122      if (common.infoz().IsSampled()) {
   1123        static constexpr size_t kInitialSampledCapacity =
   1124            NextCapacity(SooCapacity());
   1125        if (cap > kInitialSampledCapacity) {
   1126          ResizeAllocatedTableWithSeedChange(common, policy,
   1127                                             kInitialSampledCapacity);
   1128        }
   1129        // This asserts that we didn't lose sampling coverage in `resize`.
   1130        assert(common.infoz().IsSampled());
   1131        return;
   1132      }
   1133      assert(slot_size <= sizeof(HeapOrSoo));
   1134      assert(policy.slot_align <= alignof(HeapOrSoo));
   1135      HeapOrSoo tmp_slot(uninitialized_tag_t{});
   1136      size_t begin_offset = FindFirstFullSlot(0, cap, common.control());
   1137      policy.transfer_n(
   1138          &common, &tmp_slot,
   1139          SlotAddress(common.slot_array(), begin_offset, slot_size), 1);
   1140      clear_backing_array();
   1141      policy.transfer_n(&common, common.soo_data(), &tmp_slot, 1);
   1142      common.set_full_soo();
   1143      return;
   1144    }
   1145  }
   1146 
   1147  // bitor is a faster way of doing `max` here. We will round up to the next
   1148  // power-of-2-minus-1, so bitor is good enough.
   1149  size_t new_size = n | GrowthToLowerboundCapacity(common.size());
   1150  ValidateMaxSize(n, policy.slot_size);
   1151  const size_t new_capacity = NormalizeCapacity(new_size);
   1152  // n == 0 unconditionally rehashes as per the standard.
   1153  if (n == 0 || new_capacity > cap) {
   1154    if (cap == policy.soo_capacity) {
   1155      if (common.empty()) {
   1156        ResizeEmptyNonAllocatedTableImpl(common, policy, new_capacity,
   1157                                         /*force_infoz=*/false);
   1158      } else {
   1159        ResizeFullSooTable(common, policy, new_capacity,
   1160                           ResizeFullSooTableSamplingMode::kNoSampling);
   1161      }
   1162    } else {
   1163      ResizeAllocatedTableWithSeedChange(common, policy, new_capacity);
   1164    }
   1165    // This is after resize, to ensure that we have completed the allocation
   1166    // and have potentially sampled the hashtable.
   1167    common.infoz().RecordReservation(n);
   1168  }
   1169 }
   1170 
   1171 void ReserveAllocatedTable(CommonFields& common, const PolicyFunctions& policy,
   1172                           size_t n) {
   1173  common.reset_reserved_growth(n);
   1174  common.set_reservation_size(n);
   1175 
   1176  const size_t cap = common.capacity();
   1177  assert(!common.empty() || cap > policy.soo_capacity);
   1178  assert(cap > 0);
   1179  const size_t max_size_before_growth =
   1180      cap <= policy.soo_capacity ? policy.soo_capacity
   1181                                 : common.size() + common.growth_left();
   1182  if (n <= max_size_before_growth) {
   1183    return;
   1184  }
   1185  ValidateMaxSize(n, policy.slot_size);
   1186  const size_t new_capacity = NormalizeCapacity(GrowthToLowerboundCapacity(n));
   1187  if (cap == policy.soo_capacity) {
   1188    assert(!common.empty());
   1189    ResizeFullSooTable(common, policy, new_capacity,
   1190                       ResizeFullSooTableSamplingMode::kNoSampling);
   1191  } else {
   1192    assert(cap > policy.soo_capacity);
   1193    ResizeAllocatedTableWithSeedChange(common, policy, new_capacity);
   1194  }
   1195  common.infoz().RecordReservation(n);
   1196 }
   1197 
   1198 size_t PrepareInsertNonSoo(CommonFields& common, const PolicyFunctions& policy,
   1199                           size_t hash, FindInfo target) {
   1200  const bool rehash_for_bug_detection =
   1201      common.should_rehash_for_bug_detection_on_insert() &&
   1202      // Required to allow use of ResizeAllocatedTable.
   1203      common.capacity() > 0;
   1204  if (rehash_for_bug_detection) {
   1205    // Move to a different heap allocation in order to detect bugs.
   1206    const size_t cap = common.capacity();
   1207    ResizeAllocatedTableWithSeedChange(
   1208        common, policy, common.growth_left() > 0 ? cap : NextCapacity(cap));
   1209    target = find_first_non_full(common, hash);
   1210  }
   1211 
   1212  const GrowthInfo growth_info = common.growth_info();
   1213  // When there are no deleted slots in the table
   1214  // and growth_left is positive, we can insert at the first
   1215  // empty slot in the probe sequence (target).
   1216  if (ABSL_PREDICT_FALSE(!growth_info.HasNoDeletedAndGrowthLeft())) {
   1217    return PrepareInsertNonSooSlow(common, policy, hash);
   1218  }
   1219  PrepareInsertCommon(common);
   1220  common.growth_info().OverwriteEmptyAsFull();
   1221  SetCtrl(common, target.offset, H2(hash), policy.slot_size);
   1222  common.infoz().RecordInsert(hash, target.probe_length);
   1223  return target.offset;
   1224 }
   1225 
   1226 namespace {
   1227 // Returns true if the following is true
   1228 // 1. OptimalMemcpySizeForSooSlotTransfer(left) >
   1229 //    OptimalMemcpySizeForSooSlotTransfer(left - 1)
   1230 // 2. OptimalMemcpySizeForSooSlotTransfer(left) are equal for all i in [left,
   1231 // right].
   1232 // This function is used to verify that we have all the possible template
   1233 // instantiations for GrowFullSooTableToNextCapacity.
   1234 // With this verification the problem may be detected at compile time instead of
   1235 // link time.
   1236 constexpr bool VerifyOptimalMemcpySizeForSooSlotTransferRange(size_t left,
   1237                                                              size_t right) {
   1238  size_t optimal_size_for_range = OptimalMemcpySizeForSooSlotTransfer(left);
   1239  if (optimal_size_for_range <= OptimalMemcpySizeForSooSlotTransfer(left - 1)) {
   1240    return false;
   1241  }
   1242  for (size_t i = left + 1; i <= right; ++i) {
   1243    if (OptimalMemcpySizeForSooSlotTransfer(i) != optimal_size_for_range) {
   1244      return false;
   1245    }
   1246  }
   1247  return true;
   1248 }
   1249 }  // namespace
   1250 
   1251 // We need to instantiate ALL possible template combinations because we define
   1252 // the function in the cc file.
   1253 template void GrowFullSooTableToNextCapacity<0, false>(CommonFields&,
   1254                                                       const PolicyFunctions&,
   1255                                                       size_t);
   1256 template void
   1257 GrowFullSooTableToNextCapacity<OptimalMemcpySizeForSooSlotTransfer(1), true>(
   1258    CommonFields&, const PolicyFunctions&, size_t);
   1259 
   1260 static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(2, 3));
   1261 template void
   1262 GrowFullSooTableToNextCapacity<OptimalMemcpySizeForSooSlotTransfer(3), true>(
   1263    CommonFields&, const PolicyFunctions&, size_t);
   1264 
   1265 static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(4, 8));
   1266 template void
   1267 GrowFullSooTableToNextCapacity<OptimalMemcpySizeForSooSlotTransfer(8), true>(
   1268    CommonFields&, const PolicyFunctions&, size_t);
   1269 
   1270 #if UINTPTR_MAX == UINT32_MAX
   1271 static_assert(MaxSooSlotSize() == 8);
   1272 #else
   1273 static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(9, 16));
   1274 template void
   1275 GrowFullSooTableToNextCapacity<OptimalMemcpySizeForSooSlotTransfer(16), true>(
   1276    CommonFields&, const PolicyFunctions&, size_t);
   1277 static_assert(MaxSooSlotSize() == 16);
   1278 #endif
   1279 
   1280 }  // namespace container_internal
   1281 ABSL_NAMESPACE_END
   1282 }  // namespace absl