Coverage Report

Created: 2026-05-30 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/abseil-cpp/absl/container/internal/raw_hash_set.h
Line
Count
Source
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
// An open-addressing
16
// hashtable with quadratic probing.
17
//
18
// This is a low level hashtable on top of which different interfaces can be
19
// implemented, like flat_hash_set, node_hash_set, string_hash_set, etc.
20
//
21
// The table interface is similar to that of std::unordered_set. Notable
22
// differences are that most member functions support heterogeneous keys when
23
// BOTH the hash and eq functions are marked as transparent. They do so by
24
// providing a typedef called `is_transparent`.
25
//
26
// When heterogeneous lookup is enabled, functions that take key_type act as if
27
// they have an overload set like:
28
//
29
//   iterator find(const key_type& key);
30
//   template <class K>
31
//   iterator find(const K& key);
32
//
33
//   size_type erase(const key_type& key);
34
//   template <class K>
35
//   size_type erase(const K& key);
36
//
37
//   std::pair<iterator, iterator> equal_range(const key_type& key);
38
//   template <class K>
39
//   std::pair<iterator, iterator> equal_range(const K& key);
40
//
41
// When heterogeneous lookup is disabled, only the explicit `key_type` overloads
42
// exist.
43
//
44
// In addition the pointer to element and iterator stability guarantees are
45
// weaker: all iterators and pointers are invalidated after a new element is
46
// inserted.
47
//
48
// IMPLEMENTATION DETAILS
49
//
50
// # Table Layout
51
//
52
// A raw_hash_set's backing array consists of control bytes followed by slots
53
// that may or may not contain objects.
54
//
55
// The layout of the backing array, for `capacity` slots, is thus, as a
56
// pseudo-struct:
57
//
58
//   struct BackingArray {
59
//     // Sampling handler. This field isn't present when the sampling is
60
//     // disabled or this allocation hasn't been selected for sampling.
61
//     HashtablezInfoHandle infoz_;
62
//     // The number of elements we can insert before growing the capacity.
63
//     size_t growth_left;
64
//     // Control bytes for the "real" slots.
65
//     ctrl_t ctrl[capacity];
66
//     // Always `ctrl_t::kSentinel`. This is used by iterators to find when to
67
//     // stop and serves no other purpose.
68
//     ctrl_t sentinel;
69
//     // A copy of the first `kWidth - 1` elements of `ctrl`. This is used so
70
//     // that if a probe sequence picks a value near the end of `ctrl`,
71
//     // `Group` will have valid control bytes to look at.
72
//     ctrl_t clones[kWidth - 1];
73
//     // The actual slot data.
74
//     slot_type slots[capacity];
75
//   };
76
//
77
// The length of this array is computed by `RawHashSetLayout::alloc_size` below.
78
//
79
// Control bytes (`ctrl_t`) are bytes (collected into groups of a
80
// platform-specific size) that define the state of the corresponding slot in
81
// the slot array. Group manipulation is tightly optimized to be as efficient
82
// as possible: SSE and friends on x86, clever bit operations on other arches.
83
//
84
//      Group 1         Group 2        Group 3
85
// +---------------+---------------+---------------+
86
// | | | | | | | | | | | | | | | | | | | | | | | | |
87
// +---------------+---------------+---------------+
88
//
89
// Each control byte is either a special value for empty slots, deleted slots
90
// (sometimes called *tombstones*), and a special end-of-table marker used by
91
// iterators, or, if occupied, seven bits (H2) from the hash of the value in the
92
// corresponding slot.
93
//
94
// Storing control bytes in a separate array also has beneficial cache effects,
95
// since more logical slots will fit into a cache line.
96
//
97
// # Small Object Optimization (SOO)
98
//
99
// When the size/alignment of the value_type and the capacity of the table are
100
// small, we enable small object optimization and store the values inline in
101
// the raw_hash_set object. This optimization allows us to avoid
102
// allocation/deallocation as well as cache/dTLB misses.
103
//
104
// # Hashing
105
//
106
// We compute two separate hashes, `H1` and `H2`, from the hash of an object.
107
// `H1(hash(x))` is an index into `slots`, and essentially the starting point
108
// for the probe sequence. `H2(hash(x))` is a 7-bit value used to filter out
109
// objects that cannot possibly be the one we are looking for.
110
//
111
// # Table operations.
112
//
113
// The key operations are `insert`, `find`, and `erase`.
114
//
115
// Since `insert` and `erase` are implemented in terms of `find`, we describe
116
// `find` first. To `find` a value `x`, we compute `hash(x)`. From
117
// `H1(hash(x))` and the capacity, we construct a `probe_seq` that visits every
118
// group of slots in some interesting order.
119
//
120
// We now walk through these indices. At each index, we select the entire group
121
// starting with that index and extract potential candidates: occupied slots
122
// with a control byte equal to `H2(hash(x))`. If we find an empty slot in the
123
// group, we stop and return an error. Each candidate slot `y` is compared with
124
// `x`; if `x == y`, we are done and return `&y`; otherwise we continue to the
125
// next probe index. Tombstones effectively behave like full slots that never
126
// match the value we're looking for.
127
//
128
// The `H2` bits ensure when we compare a slot to an object with `==`, we are
129
// likely to have actually found the object.  That is, the chance is low that
130
// `==` is called and returns `false`.  Thus, when we search for an object, we
131
// are unlikely to call `==` many times.  This likelyhood can be analyzed as
132
// follows (assuming that H2 is a random enough hash function).
133
//
134
// Let's assume that there are `k` "wrong" objects that must be examined in a
135
// probe sequence.  For example, when doing a `find` on an object that is in the
136
// table, `k` is the number of objects between the start of the probe sequence
137
// and the final found object (not including the final found object).  The
138
// expected number of objects with an H2 match is then `k/128`.  Measurements
139
// and analysis indicate that even at high load factors, `k` is less than 32,
140
// meaning that the number of "false positive" comparisons we must perform is
141
// less than 1/8 per `find`.
142
143
// `insert` is implemented in terms of `unchecked_insert`, which inserts a
144
// value presumed to not be in the table (violating this requirement will cause
145
// the table to behave erratically). Given `x` and its hash `hash(x)`, to insert
146
// it, we construct a `probe_seq` once again, and use it to find the first
147
// group with an unoccupied (empty *or* deleted) slot. We place `x` into the
148
// first such slot in the group and mark it as full with `x`'s H2.
149
//
150
// To `insert`, we compose `unchecked_insert` with `find`. We compute `h(x)` and
151
// perform a `find` to see if it's already present; if it is, we're done. If
152
// it's not, we may decide the table is getting overcrowded (i.e. the load
153
// factor is greater than 7/8 for big tables; tables smaller than one probing
154
// group use a max load factor of 1); in this case, we allocate a bigger array,
155
// `unchecked_insert` each element of the table into the new array (we know that
156
// no insertion here will insert an already-present value), and discard the old
157
// backing array. At this point, we may `unchecked_insert` the value `x`.
158
//
159
// Below, `unchecked_insert` is partly implemented by `prepare_insert`, which
160
// presents a viable, initialized slot pointee to the caller.
161
//
162
// `erase` is implemented in terms of `erase_at`, which takes an index to a
163
// slot. Given an offset, we simply create a tombstone and destroy its contents.
164
// If we can prove that the slot would not appear in a probe sequence, we can
165
// make the slot as empty, instead. We can prove this by observing that if a
166
// group has any empty slots, it has never been full (assuming we never create
167
// an empty slot in a group with no empties, which this heuristic guarantees we
168
// never do) and find would stop at this group anyways (since it does not probe
169
// beyond groups with empties).
170
//
171
// `erase` is `erase_at` composed with `find`: if we
172
// have a value `x`, we can perform a `find`, and then `erase_at` the resulting
173
// slot.
174
//
175
// To iterate, we simply traverse the array, skipping empty and deleted slots
176
// and stopping when we hit a `kSentinel`.
177
178
#ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_
179
#define ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_
180
181
#include <algorithm>
182
#include <cassert>
183
#include <cmath>
184
#include <cstddef>
185
#include <cstdint>
186
#include <cstring>
187
#include <functional>
188
#include <initializer_list>
189
#include <iterator>
190
#include <limits>
191
#include <memory>
192
#include <tuple>
193
#include <type_traits>
194
#include <utility>
195
196
#include "absl/base/attributes.h"
197
#include "absl/base/casts.h"
198
#include "absl/base/config.h"
199
#include "absl/base/internal/endian.h"
200
#include "absl/base/internal/iterator_traits.h"
201
#include "absl/base/internal/raw_logging.h"
202
#include "absl/base/macros.h"
203
#include "absl/base/optimization.h"
204
#include "absl/base/options.h"
205
#include "absl/base/port.h"
206
#include "absl/base/prefetch.h"
207
#include "absl/container/internal/common.h"  // IWYU pragma: export // for node_handle
208
#include "absl/container/internal/common_policy_traits.h"
209
#include "absl/container/internal/compressed_tuple.h"
210
#include "absl/container/internal/container_memory.h"
211
#include "absl/container/internal/hash_function_defaults.h"
212
#include "absl/container/internal/hash_policy_traits.h"
213
#include "absl/container/internal/hashtable_control_bytes.h"
214
#include "absl/container/internal/hashtable_debug_hooks.h"
215
#include "absl/container/internal/hashtablez_sampler.h"
216
#include "absl/functional/function_ref.h"
217
#include "absl/hash/hash.h"
218
#include "absl/hash/internal/weakly_mixed_integer.h"
219
#include "absl/memory/memory.h"
220
#include "absl/meta/type_traits.h"
221
#include "absl/numeric/bits.h"
222
#include "absl/utility/utility.h"
223
224
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
225
#include <ranges>  // NOLINT(build/c++20)
226
#endif
227
228
#ifdef __BMI2__
229
#include <bmi2intrin.h>
230
#endif  // __BMI2__
231
232
namespace absl {
233
ABSL_NAMESPACE_BEGIN
234
namespace container_internal {
235
236
#ifdef ABSL_SWISSTABLE_ENABLE_GENERATIONS
237
#error ABSL_SWISSTABLE_ENABLE_GENERATIONS cannot be directly set
238
#elif (defined(ABSL_HAVE_ADDRESS_SANITIZER) ||   \
239
       defined(ABSL_HAVE_HWADDRESS_SANITIZER) || \
240
       defined(ABSL_HAVE_MEMORY_SANITIZER)) &&   \
241
    !defined(NDEBUG_SANITIZER)  // If defined, performance is important.
242
// When compiled in sanitizer mode, we add generation integers to the backing
243
// array and iterators. In the backing array, we store the generation between
244
// the control bytes and the slots. When iterators are dereferenced, we assert
245
// that the container has not been mutated in a way that could cause iterator
246
// invalidation since the iterator was initialized.
247
#define ABSL_SWISSTABLE_ENABLE_GENERATIONS
248
#endif
249
250
#ifdef ABSL_SWISSTABLE_ASSERT
251
#error ABSL_SWISSTABLE_ASSERT cannot be directly set
252
#else
253
// We use this macro for assertions that users may see when the table is in an
254
// invalid state that sanitizers may help diagnose.
255
#define ABSL_SWISSTABLE_ASSERT(CONDITION) \
256
302M
  assert((CONDITION) && "Try enabling sanitizers.")
257
#endif
258
259
// We use uint8_t so we don't need to worry about padding.
260
using GenerationType = uint8_t;
261
262
// A sentinel value for empty generations. Using 0 makes it easy to constexpr
263
// initialize an array of this value.
264
201k
constexpr GenerationType SentinelEmptyGeneration() { return 0; }
265
266
201k
constexpr GenerationType NextGeneration(GenerationType generation) {
267
201k
  return ++generation == SentinelEmptyGeneration() ? ++generation : generation;
268
201k
}
269
270
#ifdef ABSL_SWISSTABLE_ENABLE_GENERATIONS
271
constexpr bool SwisstableGenerationsEnabled() { return true; }
272
constexpr size_t NumGenerationBytes() { return sizeof(GenerationType); }
273
#else
274
0
constexpr bool SwisstableGenerationsEnabled() { return false; }
275
402k
constexpr size_t NumGenerationBytes() { return 0; }
276
#endif
277
278
// Returns true if we should assert that the table is not accessed after it has
279
// been destroyed or during the destruction of the table.
280
0
constexpr bool SwisstableAssertAccessToDestroyedTable() {
281
0
#ifndef NDEBUG
282
0
  return true;
283
0
#endif
284
0
  return SwisstableGenerationsEnabled();
285
0
}
286
287
template <typename AllocType>
288
void SwapAlloc(AllocType& lhs, AllocType& rhs,
289
               std::true_type /* propagate_on_container_swap */) {
290
  using std::swap;
291
  swap(lhs, rhs);
292
}
293
template <typename AllocType>
294
void SwapAlloc([[maybe_unused]] AllocType& lhs, [[maybe_unused]] AllocType& rhs,
295
               std::false_type /* propagate_on_container_swap */) {
296
  assert(lhs == rhs &&
297
         "It's UB to call swap with unequal non-propagating allocators.");
298
}
299
300
template <typename AllocType>
301
void CopyAlloc(AllocType& lhs, AllocType& rhs,
302
               std::true_type /* propagate_alloc */) {
303
  lhs = rhs;
304
}
305
template <typename AllocType>
306
void CopyAlloc(AllocType&, AllocType&, std::false_type /* propagate_alloc */) {}
307
308
template <class ContainerKey, class Hash, class Eq>
309
struct RequireUsableKey {
310
  template <class PassedKey, class... Args>
311
  std::pair<
312
      decltype(std::declval<const Hash&>()(std::declval<const PassedKey&>())),
313
      decltype(std::declval<const Eq&>()(std::declval<const ContainerKey&>(),
314
                                         std::declval<const PassedKey&>()))>*
315
  operator()(const PassedKey&, const Args&...) const;
316
};
317
318
template <class E, class Policy, class Hash, class Eq, class... Ts>
319
struct IsDecomposable : std::false_type {};
320
321
template <class Policy, class Hash, class Eq, class... Ts>
322
struct IsDecomposable<
323
    std::void_t<decltype(Policy::apply(
324
        RequireUsableKey<typename Policy::key_type, Hash, Eq>(),
325
        std::declval<Ts>()...))>,
326
    Policy, Hash, Eq, Ts...> : std::true_type {};
327
328
ABSL_DLL extern ctrl_t kDefaultIterControl;
329
330
// Returns a pointer to a control byte that can be used by default-constructed
331
// iterators. We don't expect this pointer to be dereferenced.
332
0
inline ctrl_t* DefaultIterControl() { return &kDefaultIterControl; }
333
334
// For use in SOO iterators.
335
// TODO(b/289225379): we could potentially get rid of this by adding an is_soo
336
// bit in iterators. This would add branches but reduce cache misses.
337
ABSL_DLL extern const ctrl_t kSooControl[2];
338
339
// Returns a pointer to a full byte followed by a sentinel byte.
340
0
inline ctrl_t* SooControl() {
341
  // Const must be cast away here; no uses of this function will actually write
342
  // to it because it is only used for SOO iterators.
343
0
  return const_cast<ctrl_t*>(kSooControl);
344
0
}
345
// Whether ctrl is from the SooControl array.
346
0
inline bool IsSooControl(const ctrl_t* ctrl) { return ctrl == SooControl(); }
347
348
// Returns a pointer to a generation to use for an empty hashtable.
349
GenerationType* EmptyGeneration();
350
351
// Returns whether `generation` is a generation for an empty hashtable that
352
// could be returned by EmptyGeneration().
353
0
inline bool IsEmptyGeneration(const GenerationType* generation) {
354
0
  return *generation == SentinelEmptyGeneration();
355
0
}
356
357
// We only allow a maximum of 1 SOO element, which makes the implementation
358
// much simpler. Complications with multiple SOO elements include:
359
// - Satisfying the guarantee that erasing one element doesn't invalidate
360
//   iterators to other elements means we would probably need actual SOO
361
//   control bytes.
362
// - In order to prevent user code from depending on iteration order for small
363
//   tables, we would need to randomize the iteration order somehow.
364
447k
constexpr size_t SooCapacity() { return 1; }
365
// Maximum capacity of a table where we don't need to hash any keys.
366
44.2M
constexpr size_t MaxSmallCapacity() { return 1; }
367
// Sentinel type to indicate SOO CommonFields construction.
368
struct soo_tag_t {};
369
// Sentinel type to indicate SOO CommonFields construction with full size.
370
struct full_soo_tag_t {};
371
// Sentinel type to indicate non-SOO CommonFields construction.
372
struct non_soo_tag_t {};
373
// Sentinel value to indicate an uninitialized value explicitly.
374
struct uninitialized_tag_t {};
375
// Sentinel value to indicate creation of an empty table without a seed.
376
struct no_seed_empty_tag_t {};
377
378
// Returns whether `n` is a valid capacity (i.e., number of slots).
379
//
380
// A valid capacity is a non-zero integer `2^m - 1`.
381
1.14M
constexpr bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; }
382
383
// Whether a table is small enough that we don't need to hash any keys.
384
43.9M
constexpr bool IsSmallCapacity(size_t capacity) {
385
43.9M
  return capacity <= MaxSmallCapacity();
386
43.9M
}
387
388
// Converts `n` into the next valid capacity, per `IsValidCapacity`.
389
0
constexpr size_t NormalizeCapacity(size_t n) {
390
0
  return n ? ~size_t{} >> countl_zero(n) : 1;
391
0
}
392
393
// Returns the next valid capacity after `n`.
394
152k
constexpr size_t NextCapacity(size_t n) {
395
152k
  ABSL_SWISSTABLE_ASSERT(IsValidCapacity(n) || n == 0);
396
152k
  return n * 2 + 1;
397
152k
}
398
399
// Returns the previous valid capacity before `n`.
400
0
constexpr size_t PreviousCapacity(size_t n) {
401
0
  ABSL_SWISSTABLE_ASSERT(IsValidCapacity(n));
402
0
  return n / 2;
403
0
}
404
405
// General notes on capacity/growth methods below:
406
// - We use 7/8th as maximum load factor. For 16-wide groups, that gives an
407
//   average of two empty slots per group.
408
// - For (capacity+1) >= Group::kWidth, growth is 7/8*capacity.
409
// - For (capacity+1) < Group::kWidth, growth == capacity. In this case, we
410
//   never need to probe (the whole table fits in one group) so we don't need a
411
//   load factor less than 1.
412
413
// Given `capacity`, applies the load factor; i.e., it returns the maximum
414
// number of values we should put into the table before a resizing rehash.
415
372k
constexpr size_t CapacityToGrowth(size_t capacity) {
416
372k
  ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity));
417
  // `capacity*7/8`
418
372k
  if (Group::kWidth == 8 && capacity == 7) {
419
    // x-x/8 does not work when x==7.
420
0
    return 6;
421
0
  }
422
372k
  return capacity - capacity / 8;
423
372k
}
424
425
// Given `size`, "unapplies" the load factor to find how large the capacity
426
// should be to stay within the load factor.
427
//
428
// For size == 0, returns 0.
429
// For other values, returns the same as `NormalizeCapacity(size*8/7)`.
430
0
constexpr size_t SizeToCapacity(size_t size) {
431
0
  if (size == 0) {
432
0
    return 0;
433
0
  }
434
  // The minimum possible capacity is NormalizeCapacity(size).
435
  // Shifting right `~size_t{}` by `leading_zeros` yields
436
  // NormalizeCapacity(size).
437
0
  int leading_zeros = absl::countl_zero(size);
438
0
  constexpr size_t kLast3Bits = size_t{7} << (sizeof(size_t) * 8 - 3);
439
  // max_size_for_next_capacity = max_load_factor * next_capacity
440
  //                            = (7/8) * (~size_t{} >> leading_zeros)
441
  //                            = (7/8*~size_t{}) >> leading_zeros
442
  //                            = kLast3Bits >> leading_zeros
443
0
  size_t max_size_for_next_capacity = kLast3Bits >> leading_zeros;
444
  // Decrease shift if size is too big for the minimum capacity.
445
0
  leading_zeros -= static_cast<int>(size > max_size_for_next_capacity);
446
  if constexpr (Group::kWidth == 8) {
447
    // Formula doesn't work when size==7 for 8-wide groups.
448
    leading_zeros -= (size == 7);
449
  }
450
0
  return (~size_t{}) >> leading_zeros;
451
0
}
452
453
// The mode we store capacity in the table.
454
enum HashtableCapacityStorageMode {
455
  // Capacity stored as size_t as a full number.
456
  kCapacityByValue,
457
  // Capacity stored as uint8_t as log2, i.e. capacity = 2^capacity_ - 1.
458
  kCapacityByLog,
459
};
460
461
// The number of slots in the backing array. This is always 2^N-1 for an
462
// integer N.
463
// NOTE: this class exists to simplify experiments with different ways to store
464
// capacity within size.
465
// NOTE: we tried experimenting with compressing the capacity and storing it
466
// together with size_: (a) using 6 bits to store the corresponding power (N in
467
// 2^N-1), and (b) storing 2^N as the most significant bit of size_ and storing
468
// size in the low bits. Both of these experiments were regressions, presumably
469
// because we need capacity to do find operations.
470
template <HashtableCapacityStorageMode StorageMode>
471
class HashtableCapacityImpl {
472
  using IntType =
473
      std::conditional_t<StorageMode == kCapacityByValue, size_t, uint8_t>;
474
475
 public:
476
0
  static constexpr HashtableCapacityImpl CreateDestroyed() {
477
0
    return HashtableCapacityImpl(kDestroyed);
478
0
  }
479
0
  static constexpr HashtableCapacityImpl CreateReentrance() {
480
0
    return HashtableCapacityImpl(kReentrance);
481
0
  }
482
0
  static constexpr HashtableCapacityImpl CreateMovedFrom() {
483
0
    return HashtableCapacityImpl(kMovedFrom);
484
0
  }
485
0
  static constexpr HashtableCapacityImpl CreateSelfMovedFrom() {
486
0
    return HashtableCapacityImpl(kSelfMovedFrom);
487
0
  }
488
489
128M
  explicit HashtableCapacityImpl(uninitialized_tag_t) {}
490
  explicit constexpr HashtableCapacityImpl(size_t capacity)
491
216k
      : capacity_data_(static_cast<IntType>(
492
216k
            StorageMode == kCapacityByValue ? capacity
493
216k
                                            : TrailingZeros(capacity + 1))) {
494
216k
    ABSL_SWISSTABLE_ASSERT(capacity == 0 || IsValidCapacity(capacity));
495
216k
  }
496
497
  // Creates capacity from the value that was returned by `ToRawData()`.
498
  // This is needed to use bitfield for capacity.
499
  // At least on Windows combination uint8_t and uint64_t bitfield in one struct
500
  // is not optimized by compiler.
501
128M
  static HashtableCapacityImpl FromRawData(uint64_t capacity) {
502
128M
    auto cap = HashtableCapacityImpl(uninitialized_tag_t{});
503
128M
    cap.capacity_data_ = static_cast<IntType>(capacity);
504
128M
    return cap;
505
128M
  }
506
216k
  IntType ToRawData() const { return capacity_data_; }
507
508
224M
  constexpr bool IsValid() const {
509
224M
    return capacity_data_ <= kAboveMaxValidCapacity;
510
224M
  }
511
512
0
  constexpr bool IsDestroyed() const { return capacity_data_ == kDestroyed; }
513
0
  constexpr bool IsReentrance() const { return capacity_data_ == kReentrance; }
514
  // Returns true if the table is moved-from including self moved-from.
515
0
  constexpr bool IsMovedFrom() const { return capacity_data_ >= kMovedFrom; }
516
0
  constexpr bool IsSelfMovedFrom() const {
517
0
    return capacity_data_ == kSelfMovedFrom;
518
0
  }
519
520
112M
  constexpr size_t capacity() const {
521
112M
    ABSL_SWISSTABLE_ASSERT(IsValid());
522
112M
    return StorageMode == kCapacityByValue ? capacity_data_
523
112M
                                           : (size_t{1} << capacity_data_) - 1;
524
112M
  }
525
526
16.4M
  constexpr bool is_small() const {
527
    // Small tables have capacity 0 or 1. This expression is valid for both
528
    // capacity storage modes.
529
    // Comparing capacity_data_ directly leads to a better generated code.
530
    // One byte comparison is used before computing the capacity in order to
531
    // detect small tables faster for critical path.
532
16.4M
    static_assert(MaxSmallCapacity() == 1);
533
16.4M
    return capacity_data_ <= 1;
534
16.4M
  }
535
536
250k
  constexpr size_t mask(size_t value) const {
537
#ifdef __BMI2__
538
    if constexpr (StorageMode == kCapacityByLog) {
539
      if constexpr (sizeof(size_t) == 8) {
540
        return _bzhi_u64(value, capacity_data_);
541
      } else {
542
        return _bzhi_u32(value, capacity_data_);
543
      }
544
    }
545
#endif  // __BMI2__
546
250k
    return value & capacity();
547
250k
  }
548
549
 private:
550
  // We use these sentinel capacity values in debug mode to indicate different
551
  // classes of bugs.
552
  enum InvalidCapacity : IntType {
553
    kAboveMaxValidCapacity = (std::numeric_limits<IntType>::max)() - 100,
554
    kReentrance,
555
    kDestroyed,
556
557
    // These two must be last because we use `>= kMovedFrom` to mean moved-from.
558
    kMovedFrom,
559
    kSelfMovedFrom,
560
  };
561
562
  explicit constexpr HashtableCapacityImpl(InvalidCapacity capacity)
563
      : capacity_data_(capacity) {
564
    ABSL_SWISSTABLE_ASSERT(capacity_data_ > kAboveMaxValidCapacity);
565
  }
566
567
  // Capacity is stored as a value or as a log2 depending on `StorageMode`.
568
  IntType capacity_data_;
569
};
570
571
template <HashtableCapacityStorageMode StorageMode>
572
class HashtableInlineDataImpl;
573
574
// Returns next per-table seed.
575
uint16_t NextHashTableSeed();
576
577
// Per table hash salt. This gets mixed into H1 to randomize iteration order
578
// per-table.
579
// The seed is needed to ensure non-determinism of iteration order.
580
template <typename StorageType>
581
class PerTableSeedImpl {
582
 public:
583
  using IntType = StorageType;
584
585
  // The number of bits in the seed.
586
  // It is big enough to ensure non-determinism of iteration order.
587
  // We store the seed inside a uint64_t together with size and other metadata.
588
  // Using 8 or 16 bits allows us to save one `and` instruction in H1 (we use
589
  // zero-extended move instead of mov+and). When absl::Hash is inlined, it can
590
  // also have lower latency knowing that the high bits of the seed are zero.
591
  static constexpr size_t kBitCount = sizeof(IntType) * 8;
592
593
  // We need to use a constant seed when the table is sampled so that sampled
594
  // hashes use the same seed and can e.g. identify stuck bits accurately.
595
  static constexpr IntType kSampledSeed = static_cast<IntType>(~IntType{0});
596
597
  // Returns the seed for the table.
598
206k
  size_t seed() const { return seed_; }
599
600
 private:
601
  template <HashtableCapacityStorageMode StorageMode>
602
  friend class HashtableInlineDataImpl;
603
604
  explicit PerTableSeedImpl(uint64_t seed)
605
206k
      : seed_(static_cast<IntType>(seed)) {}
606
607
  const IntType seed_;
608
};
609
610
// Capacity, size and also has additionally
611
// 1) one bit that stores whether we have infoz.
612
// 2) PerTableSeed::kBitCount bits for the seed. (For SOO tables, the lowest
613
//    bit of the seed is repurposed to track if sampling has been tried).
614
template <HashtableCapacityStorageMode StorageMode>
615
class HashtableInlineDataImpl {
616
 public:
617
  static constexpr HashtableCapacityStorageMode kStorageMode = StorageMode;
618
  using PerTableSeed = PerTableSeedImpl<
619
      std::conditional_t<StorageMode == kCapacityByValue, uint16_t, uint8_t>>;
620
  using HashtableCapacity = HashtableCapacityImpl<StorageMode>;
621
  static constexpr size_t kSizeBitCount =
622
      StorageMode == kCapacityByValue
623
          ? 64 - PerTableSeed::kBitCount - 1
624
          : 64 - PerTableSeed::kBitCount - sizeof(HashtableCapacity) * 8 - 1;
625
626
  explicit HashtableInlineDataImpl(uninitialized_tag_t) {}
627
  explicit HashtableInlineDataImpl(HashtableCapacity capacity,
628
                                   no_seed_empty_tag_t)
629
14.9k
      : capacity_internal_(capacity.ToRawData()), data_(0) {}
630
  HashtableInlineDataImpl(HashtableCapacity capacity, full_soo_tag_t,
631
                          bool has_tried_sampling)
632
      : capacity_internal_(capacity.ToRawData()),
633
        data_(kSizeOneNoMetadata |
634
              (has_tried_sampling ? kSooHasTriedSamplingMask : 0)) {}
635
636
128M
  HashtableCapacity capacity() const {
637
128M
    return HashtableCapacity::FromRawData(capacity_internal_);
638
128M
  }
639
16.4M
  bool is_small() const { return capacity().is_small(); }
640
641
201k
  void set_capacity(HashtableCapacity c) { capacity_internal_ = c.ToRawData(); }
642
  void set_capacity(size_t c) { set_capacity(HashtableCapacity(c)); }
643
644
  // Returns actual size of the table.
645
8.86M
  size_t size() const { return static_cast<size_t>(data_ >> kSizeShift); }
646
8.33M
  void increment_size() { data_ += kSizeOneNoMetadata; }
647
0
  void increment_size(size_t size) {
648
0
    data_ += static_cast<uint64_t>(size) << kSizeShift;
649
0
  }
650
0
  void decrement_size() { data_ -= kSizeOneNoMetadata; }
651
  // Returns true if the table is empty.
652
0
  bool empty() const { return data_ < kSizeOneNoMetadata; }
653
654
  // Returns true if an empty SOO table has already queried should_sample_soo().
655
0
  bool soo_has_tried_sampling() const {
656
0
    return (data_ & kSooHasTriedSamplingMask) != 0;
657
0
  }
658
659
  // Records that an empty SOO table has tried sampling.
660
0
  void set_soo_has_tried_sampling() { data_ |= kSooHasTriedSamplingMask; }
661
662
  // Sets the size, but keeps all the metadata bits.
663
220k
  void set_size(size_t size) {
664
220k
    data_ =
665
220k
        (data_ & kMetadataMask) | (static_cast<uint64_t>(size) << kSizeShift);
666
220k
  }
667
668
206k
  PerTableSeed seed() const { return PerTableSeed(data_ & kSeedMask); }
669
670
49.0k
  void generate_new_seed() {
671
49.0k
    set_seed(static_cast<typename PerTableSeed::IntType>(NextHashTableSeed()));
672
49.0k
  }
673
674
  // We need to use a constant seed when the table is sampled so that sampled
675
  // hashes use the same seed and can e.g. identify stuck bits accurately.
676
0
  void set_sampled_seed() { set_seed(PerTableSeed::kSampledSeed); }
677
678
0
  bool is_sampled_seed() const {
679
0
    return seed().seed() == PerTableSeed::kSampledSeed;
680
0
  }
681
682
  // Returns true if the table has infoz.
683
8.61M
  bool has_infoz() const {
684
8.61M
    return ABSL_PREDICT_FALSE((data_ & kHasInfozMask) != 0);
685
8.61M
  }
686
687
  // Sets the has_infoz bit.
688
0
  void set_has_infoz() { data_ |= kHasInfozMask; }
689
690
0
  void set_no_seed_for_testing() { data_ &= ~kSeedMask; }
691
692
 private:
693
  // Bit layout of `data_` from MSB to LSB:
694
  // (47 bits)      : size
695
  // (1 bit)        : has_infoz
696
  // (16 or 8 bits) : seed
697
  // We don't split these components of `data_` into separate bit field elements
698
  // because we get worse generated code that way.
699
  static constexpr size_t kDataBitCount =
700
      PerTableSeed::kBitCount + 1 + kSizeBitCount;
701
  static constexpr size_t kSizeShift = kDataBitCount - kSizeBitCount;
702
  static constexpr uint64_t kSizeOneNoMetadata = uint64_t{1} << kSizeShift;
703
  static constexpr uint64_t kMetadataMask = kSizeOneNoMetadata - 1;
704
  static constexpr uint64_t kSeedMask =
705
      (uint64_t{1} << PerTableSeed::kBitCount) - 1;
706
  // The next bit after the seed.
707
  static constexpr uint64_t kHasInfozMask = kSeedMask + 1;
708
  // For SOO tables, the seed is unused, and bit 0 is repurposed to track
709
  // whether the table has already queried should_sample_soo().
710
  static constexpr uint64_t kSooHasTriedSamplingMask = 1;
711
712
49.0k
  void set_seed(typename PerTableSeed::IntType seed) {
713
49.0k
    data_ = (data_ & ~kSeedMask) | seed;
714
49.0k
  }
715
716
  uint64_t capacity_internal_ : sizeof(HashtableCapacity) * 8;
717
  uint64_t data_ : kDataBitCount;
718
};
719
720
static_assert(
721
    sizeof(HashtableInlineDataImpl<kCapacityByValue>::HashtableCapacity) ==
722
    sizeof(size_t));
723
// NOTE: some platforms have this size to be equal to 12 for two reasons:
724
// 1) alignof(uint64_t) == 4.
725
// 2) sizeof(size_t) == sizeof(HashtableCapacityImpl<kCapacityByValue>) == 4.
726
static_assert(sizeof(HashtableInlineDataImpl<kCapacityByValue>) <= 16);
727
static_assert(
728
    sizeof(HashtableInlineDataImpl<kCapacityByLog>::HashtableCapacity) == 1);
729
static_assert(sizeof(HashtableInlineDataImpl<kCapacityByLog>) == 8);
730
731
#ifndef ABSL_SWISSTABLE_INTERNAL_ENABLE_CAPACITY_BY_VALUE
732
using HashtableInlineData = HashtableInlineDataImpl<kCapacityByLog>;
733
#else
734
using HashtableInlineData = HashtableInlineDataImpl<kCapacityByValue>;
735
#endif  // ABSL_SWISSTABLE_INTERNAL_ENABLE_CAPACITY_BY_VALUE
736
using PerTableSeed = HashtableInlineData::PerTableSeed;
737
using HashtableCapacity = HashtableInlineData::HashtableCapacity;
738
739
// H1 is just the low bits of the hash.
740
92.4k
inline size_t H1(size_t hash) { return hash; }
741
742
// Extracts the H2 portion of a hash: the 7 most significant bits.
743
//
744
// These are used as an occupied control byte.
745
8.38M
inline h2_t H2(size_t hash) { return hash >> (sizeof(size_t) * 8 - 7); }
746
747
// When there is an insertion with no reserved growth, we rehash with
748
// probability `min(1, RehashProbabilityConstant() / capacity())`. Using a
749
// constant divided by capacity ensures that inserting N elements is still O(N)
750
// in the average case. Using the constant 16 means that we expect to rehash ~8
751
// times more often than when generations are disabled. We are adding expected
752
// rehash_probability * #insertions/capacity_growth = 16/capacity * ((7/8 -
753
// 7/16) * capacity)/capacity_growth = ~7 extra rehashes per capacity growth.
754
0
inline size_t RehashProbabilityConstant() { return 16; }
755
756
class CommonFieldsGenerationInfoEnabled {
757
  // A sentinel value for reserved_growth_ indicating that we just ran out of
758
  // reserved growth on the last insertion. When reserve is called and then
759
  // insertions take place, reserved_growth_'s state machine is N, ..., 1,
760
  // kReservedGrowthJustRanOut, 0.
761
  static constexpr size_t kReservedGrowthJustRanOut =
762
      (std::numeric_limits<size_t>::max)();
763
764
 public:
765
  CommonFieldsGenerationInfoEnabled() = default;
766
  CommonFieldsGenerationInfoEnabled(CommonFieldsGenerationInfoEnabled&& that)
767
      : reserved_growth_(that.reserved_growth_),
768
        reservation_size_(that.reservation_size_),
769
0
        generation_(that.generation_) {
770
0
    that.reserved_growth_ = 0;
771
0
    that.reservation_size_ = 0;
772
0
    that.generation_ = EmptyGeneration();
773
0
  }
774
  CommonFieldsGenerationInfoEnabled& operator=(
775
      CommonFieldsGenerationInfoEnabled&&) = default;
776
777
  // Whether we should rehash on insert in order to detect bugs of using invalid
778
  // references. We rehash on the first insertion after reserved_growth_ reaches
779
  // 0 after a call to reserve. We also do a rehash with low probability
780
  // whenever reserved_growth_ is zero.
781
  bool should_rehash_for_bug_detection_on_insert(size_t capacity) const;
782
  // Similar to above, except that we don't depend on reserved_growth_.
783
  bool should_rehash_for_bug_detection_on_move(size_t capacity) const;
784
0
  void maybe_increment_generation_on_insert() {
785
0
    if (reserved_growth_ == kReservedGrowthJustRanOut) reserved_growth_ = 0;
786
0
787
0
    if (reserved_growth_ > 0) {
788
0
      if (--reserved_growth_ == 0) reserved_growth_ = kReservedGrowthJustRanOut;
789
0
    } else {
790
0
      increment_generation();
791
0
    }
792
0
  }
793
0
  void increment_generation() { *generation_ = NextGeneration(*generation_); }
794
0
  void reset_reserved_growth(size_t reservation, size_t size) {
795
0
    reserved_growth_ = reservation - size;
796
0
  }
797
0
  size_t reserved_growth() const { return reserved_growth_; }
798
0
  void set_reserved_growth(size_t r) { reserved_growth_ = r; }
799
0
  size_t reservation_size() const { return reservation_size_; }
800
0
  void set_reservation_size(size_t r) { reservation_size_ = r; }
801
0
  GenerationType generation() const { return *generation_; }
802
0
  void set_generation(GenerationType g) { *generation_ = g; }
803
0
  GenerationType* generation_ptr() const { return generation_; }
804
0
  void set_generation_ptr(GenerationType* g) { generation_ = g; }
805
806
 private:
807
  // The number of insertions remaining that are guaranteed to not rehash due to
808
  // a prior call to reserve. Note: we store reserved growth in addition to
809
  // reservation size because calls to erase() decrease size_ but don't decrease
810
  // reserved growth.
811
  size_t reserved_growth_ = 0;
812
  // The maximum argument to reserve() since the container was cleared. We need
813
  // to keep track of this, in addition to reserved growth, because we reset
814
  // reserved growth to this when erase(begin(), end()) is called.
815
  size_t reservation_size_ = 0;
816
  // Pointer to the generation counter, which is used to validate iterators and
817
  // is stored in the backing array between the control bytes and the slots.
818
  // Note that we can't store the generation inside the container itself and
819
  // keep a pointer to the container in the iterators because iterators must
820
  // remain valid when the container is moved.
821
  // Note: we could derive this pointer from the control pointer, but it makes
822
  // the code more complicated, and there's a benefit in having the sizes of
823
  // raw_hash_set in sanitizer mode and non-sanitizer mode a bit more different,
824
  // which is that tests are less likely to rely on the size remaining the same.
825
  GenerationType* generation_ = EmptyGeneration();
826
};
827
828
class CommonFieldsGenerationInfoDisabled {
829
 public:
830
  CommonFieldsGenerationInfoDisabled() = default;
831
  CommonFieldsGenerationInfoDisabled(CommonFieldsGenerationInfoDisabled&&) =
832
      default;
833
  CommonFieldsGenerationInfoDisabled& operator=(
834
      CommonFieldsGenerationInfoDisabled&&) = default;
835
836
0
  bool should_rehash_for_bug_detection_on_insert(size_t) const { return false; }
837
0
  bool should_rehash_for_bug_detection_on_move(size_t) const { return false; }
838
8.33M
  void maybe_increment_generation_on_insert() {}
839
0
  void increment_generation() {}
840
0
  void reset_reserved_growth(size_t, size_t) {}
841
0
  size_t reserved_growth() const { return 0; }
842
0
  void set_reserved_growth(size_t) {}
843
0
  size_t reservation_size() const { return 0; }
844
0
  void set_reservation_size(size_t) {}
845
201k
  GenerationType generation() const { return 0; }
846
201k
  void set_generation(GenerationType) {}
847
0
  GenerationType* generation_ptr() const { return nullptr; }
848
201k
  void set_generation_ptr(GenerationType*) {}
849
};
850
851
class HashSetIteratorGenerationInfoEnabled {
852
 public:
853
  HashSetIteratorGenerationInfoEnabled() = default;
854
  explicit HashSetIteratorGenerationInfoEnabled(
855
      const GenerationType* generation_ptr)
856
0
      : generation_ptr_(generation_ptr), generation_(*generation_ptr) {}
857
858
0
  GenerationType generation() const { return generation_; }
859
0
  void reset_generation() { generation_ = *generation_ptr_; }
860
0
  const GenerationType* generation_ptr() const { return generation_ptr_; }
861
0
  void set_generation_ptr(const GenerationType* ptr) { generation_ptr_ = ptr; }
862
863
 private:
864
  const GenerationType* generation_ptr_ = EmptyGeneration();
865
  GenerationType generation_ = *generation_ptr_;
866
};
867
868
class HashSetIteratorGenerationInfoDisabled {
869
 public:
870
  HashSetIteratorGenerationInfoDisabled() = default;
871
0
  explicit HashSetIteratorGenerationInfoDisabled(const GenerationType*) {}
872
873
0
  GenerationType generation() const { return 0; }
874
0
  void reset_generation() {}
875
0
  const GenerationType* generation_ptr() const { return nullptr; }
876
0
  void set_generation_ptr(const GenerationType*) {}
877
};
878
879
#ifdef ABSL_SWISSTABLE_ENABLE_GENERATIONS
880
using CommonFieldsGenerationInfo = CommonFieldsGenerationInfoEnabled;
881
using HashSetIteratorGenerationInfo = HashSetIteratorGenerationInfoEnabled;
882
#else
883
using CommonFieldsGenerationInfo = CommonFieldsGenerationInfoDisabled;
884
using HashSetIteratorGenerationInfo = HashSetIteratorGenerationInfoDisabled;
885
#endif
886
887
// Stored the information regarding number of slots we can still fill
888
// without needing to rehash.
889
//
890
// We want to ensure sufficient number of empty slots in the table in order
891
// to keep probe sequences relatively short. Empty slot in the probe group
892
// is required to stop probing.
893
//
894
// Tombstones (kDeleted slots) are not included in the growth capacity,
895
// because we'd like to rehash when the table is filled with tombstones and/or
896
// full slots.
897
//
898
// GrowthInfo also stores a bit that encodes whether table may have any
899
// deleted slots.
900
// Most of the tables (>95%) have no deleted slots, so some functions can
901
// be more efficient with this information.
902
//
903
// Callers can also force a rehash via the standard `rehash(0)`,
904
// which will recompute this value as a side-effect.
905
//
906
// See also `CapacityToGrowth()`.
907
class GrowthInfo {
908
 public:
909
  // Leaves data member uninitialized.
910
  GrowthInfo() = default;
911
912
  // Initializes the GrowthInfo assuming we can grow `growth_left` elements
913
  // and there are no kDeleted slots in the table.
914
421k
  void InitGrowthLeftNoDeleted(size_t growth_left) {
915
421k
    growth_left_info_ = growth_left;
916
421k
  }
917
918
  // Overwrites single full slot with an empty slot.
919
0
  void OverwriteFullAsEmpty() { ++growth_left_info_; }
920
921
  // Overwrites single empty slot with a full slot.
922
8.13M
  void OverwriteEmptyAsFull() {
923
8.13M
    ABSL_SWISSTABLE_ASSERT(GetGrowthLeft() > 0);
924
8.13M
    --growth_left_info_;
925
8.13M
  }
926
927
  // Overwrites several empty slots with full slots.
928
0
  void OverwriteManyEmptyAsFull(size_t count) {
929
0
    ABSL_SWISSTABLE_ASSERT(GetGrowthLeft() >= count);
930
0
    growth_left_info_ -= count;
931
0
  }
932
933
  // Overwrites specified control element with full slot.
934
0
  void OverwriteControlAsFull(ctrl_t ctrl) {
935
0
    ABSL_SWISSTABLE_ASSERT(GetGrowthLeft() >=
936
0
                           static_cast<size_t>(IsEmpty(ctrl)));
937
0
    growth_left_info_ -= static_cast<size_t>(IsEmpty(ctrl));
938
0
  }
939
940
  // Overwrites single full slot with a deleted slot.
941
0
  void OverwriteFullAsDeleted() { growth_left_info_ |= kDeletedBit; }
942
943
  // Returns true if table satisfies two properties:
944
  // 1. Guaranteed to have no kDeleted slots.
945
  // 2. There is a place for at least one element to grow.
946
8.43M
  bool HasNoDeletedAndGrowthLeft() const {
947
8.43M
    return static_cast<std::make_signed_t<size_t>>(growth_left_info_) > 0;
948
8.43M
  }
949
950
  // Returns true if the table satisfies two properties:
951
  // 1. Guaranteed to have no kDeleted slots.
952
  // 2. There is no growth left.
953
152k
  bool HasNoGrowthLeftAndNoDeleted() const { return growth_left_info_ == 0; }
954
955
  // Returns true if GetGrowthLeft() == 0, but must be called only if
956
  // HasNoDeleted() is false. It is slightly more efficient.
957
0
  bool HasNoGrowthLeftAssumingMayHaveDeleted() const {
958
0
    ABSL_SWISSTABLE_ASSERT(!HasNoDeleted());
959
0
    return growth_left_info_ == kDeletedBit;
960
0
  }
961
962
  // Returns true if table guaranteed to have no kDeleted slots.
963
152k
  bool HasNoDeleted() const {
964
152k
    return static_cast<std::make_signed_t<size_t>>(growth_left_info_) >= 0;
965
152k
  }
966
967
  // Returns the number of elements left to grow.
968
8.43M
  size_t GetGrowthLeft() const { return growth_left_info_ & kGrowthLeftMask; }
969
970
 private:
971
  static constexpr size_t kGrowthLeftMask = ((~size_t{}) >> 1);
972
  static constexpr size_t kDeletedBit = ~kGrowthLeftMask;
973
  // Topmost bit signal whenever there are deleted slots.
974
  size_t growth_left_info_;
975
};
976
977
static_assert(sizeof(GrowthInfo) == sizeof(size_t), "");
978
static_assert(alignof(GrowthInfo) == alignof(size_t), "");
979
980
// Returns the number of "cloned control bytes".
981
//
982
// This is the number of control bytes that are present both at the beginning
983
// of the control byte array and at the end, such that we can create a
984
// `Group::kWidth`-width probe window starting from any control byte.
985
42.9M
constexpr size_t NumClonedBytes() { return Group::kWidth - 1; }
986
987
// Returns the number of control bytes including cloned.
988
26.3M
constexpr size_t NumControlBytes(size_t capacity) {
989
26.3M
  return IsSmallCapacity(capacity) ? 0 : capacity + 1 + NumClonedBytes();
990
26.3M
}
991
992
// Returns whether table with the given capacity has a GrowthInfo.
993
17.3M
constexpr bool HasGrowthInfoForCapacity(size_t capacity) {
994
17.3M
  return !IsSmallCapacity(capacity);
995
17.3M
}
996
997
// Computes the offset from the start of the backing allocation of control.
998
// infoz and growth_info are stored at the beginning of the backing array.
999
402k
constexpr size_t ControlOffset(bool has_infoz, bool has_growth_info) {
1000
402k
  if (ABSL_PREDICT_FALSE(has_infoz)) {
1001
    // We always allocate GrowthInfo for sampled tables to allow branchless
1002
    // access to infoz pointer.
1003
0
    return sizeof(HashtablezInfoHandle) + sizeof(GrowthInfo);
1004
0
  }
1005
402k
  return has_growth_info ? sizeof(GrowthInfo) : 0;
1006
402k
}
1007
1008
// Returns the offset of the next item after `offset` that is aligned to `align`
1009
// bytes. `align` must be a power of two.
1010
402k
constexpr size_t AlignUpTo(size_t offset, size_t align) {
1011
402k
  return (offset + align - 1) & (~align + 1);
1012
402k
}
1013
1014
// Helper class for computing offsets and allocation size of hash set fields.
1015
class RawHashSetLayout {
1016
 public:
1017
  explicit RawHashSetLayout(size_t capacity, size_t slot_size,
1018
                            size_t slot_align, bool has_infoz)
1019
      : control_offset_(
1020
402k
            ControlOffset(has_infoz, HasGrowthInfoForCapacity(capacity))),
1021
402k
        generation_offset_(control_offset_ + NumControlBytes(capacity)),
1022
        slot_offset_(
1023
402k
            AlignUpTo(generation_offset_ + NumGenerationBytes(), slot_align)),
1024
402k
        alloc_size_(slot_offset_ + capacity * slot_size) {
1025
402k
    ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity));
1026
402k
    ABSL_SWISSTABLE_ASSERT(
1027
402k
        slot_size <=
1028
402k
        ((std::numeric_limits<size_t>::max)() - slot_offset_) / capacity);
1029
402k
  }
1030
1031
  // Returns precomputed offset from the start of the backing allocation of
1032
  // control.
1033
402k
  size_t control_offset() const { return control_offset_; }
1034
1035
  // Given the capacity of a table, computes the offset (from the start of the
1036
  // backing allocation) of the generation counter (if it exists).
1037
201k
  size_t generation_offset() const { return generation_offset_; }
1038
1039
  // Given the capacity of a table, computes the offset (from the start of the
1040
  // backing allocation) at which the slots begin.
1041
201k
  size_t slot_offset() const { return slot_offset_; }
1042
1043
  // Given the capacity of a table, computes the total size of the backing
1044
  // array.
1045
603k
  size_t alloc_size() const { return alloc_size_; }
1046
1047
 private:
1048
  size_t control_offset_;
1049
  size_t generation_offset_;
1050
  size_t slot_offset_;
1051
  size_t alloc_size_;
1052
};
1053
1054
struct HashtableFreeFunctionsAccess;
1055
1056
// This allows us to work around an uninitialized memory warning when
1057
// constructing begin() iterators in empty hashtables.
1058
template <typename T>
1059
union MaybeInitializedPtr {
1060
34.6M
  T* get() const { ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(p); }
absl::container_internal::MaybeInitializedPtr<void>::get() const
Line
Count
Source
1060
8.75M
  T* get() const { ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(p); }
absl::container_internal::MaybeInitializedPtr<absl::container_internal::ctrl_t>::get() const
Line
Count
Source
1060
25.8M
  T* get() const { ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(p); }
1061
402k
  void set(T* ptr) { p = ptr; }
absl::container_internal::MaybeInitializedPtr<absl::container_internal::ctrl_t>::set(absl::container_internal::ctrl_t*)
Line
Count
Source
1061
201k
  void set(T* ptr) { p = ptr; }
absl::container_internal::MaybeInitializedPtr<void>::set(void*)
Line
Count
Source
1061
201k
  void set(T* ptr) { p = ptr; }
1062
1063
  T* p;
1064
};
1065
1066
struct HeapPtrs {
1067
  // The control bytes (and, also, a pointer near to the base of the backing
1068
  // array).
1069
  //
1070
  // This contains `capacity + 1 + NumClonedBytes()` entries.
1071
  //
1072
  // Note that growth_info is stored immediately before this pointer.
1073
  // May be uninitialized for small tables.
1074
  MaybeInitializedPtr<ctrl_t> control;
1075
1076
  // The beginning of the slots, located at `SlotOffset()` bytes after
1077
  // `control`. May be uninitialized for empty tables.
1078
  // Note: we can't use `slots` because Qt defines "slots" as a macro.
1079
  MaybeInitializedPtr<void> slot_array;
1080
};
1081
1082
// Returns the maximum size of the SOO slot.
1083
0
constexpr size_t MaxSooSlotSize() { return sizeof(HeapPtrs); }
1084
1085
// Manages the backing array pointers or the SOO slot. When raw_hash_set::is_soo
1086
// is true, the SOO slot is stored in `soo_data`. Otherwise, we use `heap`.
1087
union HeapOrSoo {
1088
201k
  MaybeInitializedPtr<ctrl_t>& control() {
1089
201k
    ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(heap.control);
1090
201k
  }
1091
25.8M
  MaybeInitializedPtr<ctrl_t> control() const {
1092
25.8M
    ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(heap.control);
1093
25.8M
  }
1094
201k
  MaybeInitializedPtr<void>& slot_array() {
1095
201k
    ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(heap.slot_array);
1096
201k
  }
1097
8.75M
  MaybeInitializedPtr<void> slot_array() const {
1098
8.75M
    ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(heap.slot_array);
1099
8.75M
  }
1100
98.1k
  void* get_soo_data() {
1101
98.1k
    ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(soo_data);
1102
98.1k
  }
1103
0
  const void* get_soo_data() const {
1104
0
    ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(soo_data);
1105
0
  }
1106
1107
  HeapPtrs heap;
1108
  unsigned char soo_data[MaxSooSlotSize()];
1109
};
1110
1111
// Returns a reference to the GrowthInfo object stored immediately before
1112
// `control`.
1113
17.1M
inline GrowthInfo& GetGrowthInfoFromControl(ctrl_t* control) {
1114
17.1M
  auto* gl_ptr = reinterpret_cast<GrowthInfo*>(control) - 1;
1115
17.1M
  ABSL_SWISSTABLE_ASSERT(
1116
17.1M
      reinterpret_cast<uintptr_t>(gl_ptr) % alignof(GrowthInfo) == 0);
1117
17.1M
  return *gl_ptr;
1118
17.1M
}
1119
1120
// CommonFields hold the fields in raw_hash_set that do not depend
1121
// on template parameters. This allows us to conveniently pass all
1122
// of this state to helper functions as a single argument.
1123
class CommonFields : public CommonFieldsGenerationInfo {
1124
 public:
1125
  explicit CommonFields(soo_tag_t)
1126
14.9k
      : inline_data_(HashtableCapacity(SooCapacity()), no_seed_empty_tag_t{}) {}
1127
  explicit CommonFields(full_soo_tag_t, bool has_tried_sampling)
1128
      : inline_data_(HashtableCapacity(SooCapacity()), full_soo_tag_t{},
1129
0
                     has_tried_sampling) {}
1130
  explicit CommonFields(non_soo_tag_t)
1131
0
      : inline_data_(HashtableCapacity(0), no_seed_empty_tag_t{}) {}
1132
  // For use in swapping.
1133
  explicit CommonFields(uninitialized_tag_t)
1134
0
      : inline_data_(uninitialized_tag_t{}) {}
1135
1136
  // Not copyable
1137
  CommonFields(const CommonFields&) = delete;
1138
  CommonFields& operator=(const CommonFields&) = delete;
1139
1140
  // Copy with guarantee that it is not SOO.
1141
  CommonFields(non_soo_tag_t, const CommonFields& that)
1142
0
      : inline_data_(that.inline_data_), heap_or_soo_(that.heap_or_soo_) {}
1143
1144
  // Movable
1145
  CommonFields(CommonFields&& that) = default;
1146
  CommonFields& operator=(CommonFields&&) = default;
1147
1148
  template <bool kSooEnabled>
1149
  static CommonFields CreateDefault() {
1150
    return kSooEnabled ? CommonFields{soo_tag_t{}}
1151
                       : CommonFields{non_soo_tag_t{}};
1152
  }
1153
1154
  // The inline data for SOO is written on top of control_/slots_.
1155
0
  const void* soo_data() const { return heap_or_soo_.get_soo_data(); }
1156
98.1k
  void* soo_data() { return heap_or_soo_.get_soo_data(); }
1157
1158
25.8M
  ctrl_t* control() const {
1159
25.8M
    ABSL_SWISSTABLE_ASSERT(capacity() > 0);
1160
    // Assume that the control bytes don't alias `this`.
1161
25.8M
    ctrl_t* ctrl = heap_or_soo_.control().get();
1162
25.8M
    [[maybe_unused]] size_t num_control_bytes = NumControlBytes(capacity());
1163
25.8M
    ABSL_ASSUME(reinterpret_cast<uintptr_t>(ctrl + num_control_bytes) <=
1164
25.8M
                    reinterpret_cast<uintptr_t>(this) ||
1165
25.8M
                reinterpret_cast<uintptr_t>(this + 1) <=
1166
25.8M
                    reinterpret_cast<uintptr_t>(ctrl));
1167
25.8M
    ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(ctrl);
1168
25.8M
  }
1169
1170
201k
  void set_control(ctrl_t* c) { heap_or_soo_.control().set(c); }
1171
1172
  // Note: we can't use slots() because Qt defines "slots" as a macro.
1173
8.75M
  void* slot_array() const { return heap_or_soo_.slot_array().get(); }
1174
0
  MaybeInitializedPtr<void> slots_union() const {
1175
0
    return heap_or_soo_.slot_array();
1176
0
  }
1177
201k
  void set_slots(void* s) { heap_or_soo_.slot_array().set(s); }
1178
1179
  // The number of filled slots.
1180
8.86M
  size_t size() const { return inline_data_.size(); }
1181
  // Sets the size to zero, but keeps hashinfoz bit and seed.
1182
220k
  void set_size_to_zero() { inline_data_.set_size(0); }
1183
0
  void set_empty_soo() {
1184
0
    AssertInSooMode();
1185
0
    inline_data_.set_size(0);
1186
0
  }
1187
0
  void set_full_soo() {
1188
0
    AssertInSooMode();
1189
0
    inline_data_.set_size(1);
1190
0
  }
1191
8.33M
  void increment_size() {
1192
8.33M
    ABSL_SWISSTABLE_ASSERT(size() < capacity());
1193
8.33M
    inline_data_.increment_size();
1194
8.33M
  }
1195
0
  void increment_size(size_t n) {
1196
0
    ABSL_SWISSTABLE_ASSERT(size() + n <= capacity());
1197
0
    inline_data_.increment_size(n);
1198
0
  }
1199
0
  void decrement_size() {
1200
0
    ABSL_SWISSTABLE_ASSERT(!empty());
1201
0
    inline_data_.decrement_size();
1202
0
  }
1203
0
  bool empty() const { return inline_data_.empty(); }
1204
0
  void set_soo_has_tried_sampling() {
1205
0
    inline_data_.set_soo_has_tried_sampling();
1206
0
  }
1207
0
  bool soo_has_tried_sampling() const {
1208
0
    return inline_data_.soo_has_tried_sampling();
1209
0
  }
1210
1211
  // The seed used for the hash function.
1212
206k
  PerTableSeed seed() const { return inline_data_.seed(); }
1213
  // Generates a new seed the hash function.
1214
  // The table will be invalidated if `!empty()` because hash is being changed.
1215
  // In such cases, we will need to rehash the table.
1216
49.0k
  void generate_new_seed(bool has_infoz) {
1217
    // Note: we can't use has_infoz() here because we set has_infoz later than
1218
    // we generate the seed.
1219
49.0k
    if (ABSL_PREDICT_FALSE(has_infoz)) {
1220
0
      inline_data_.set_sampled_seed();
1221
0
      return;
1222
0
    }
1223
49.0k
    inline_data_.generate_new_seed();
1224
49.0k
  }
1225
0
  void set_no_seed_for_testing() { inline_data_.set_no_seed_for_testing(); }
1226
1227
111M
  HashtableCapacity capacity_impl() const {
1228
111M
    HashtableCapacity cap = inline_data_.capacity();
1229
111M
    ABSL_SWISSTABLE_ASSERT(cap.IsValid());
1230
111M
    return cap;
1231
111M
  }
1232
111M
  size_t capacity() const { return capacity_impl().capacity(); }
1233
  // We have a separate alias for callsites in which the capacity may be
1234
  // invalid.
1235
0
  HashtableCapacity maybe_invalid_capacity() const {
1236
0
    return inline_data_.capacity();
1237
0
  }
1238
201k
  void set_capacity(HashtableCapacity c) { inline_data_.set_capacity(c); }
1239
201k
  void set_capacity(size_t c) {
1240
201k
    set_capacity(HashtableCapacity(c));
1241
201k
  }
1242
16.4M
  bool is_small() const { return inline_data_.is_small(); }
1243
1244
  // The number of slots we can still fill without needing to rehash.
1245
  // This is stored in the heap allocation before the control bytes.
1246
  // TODO(b/289225379): experiment with moving growth_info back inline to
1247
  // increase room for SOO.
1248
152k
  size_t growth_left() const { return growth_info().GetGrowthLeft(); }
1249
1250
16.9M
  GrowthInfo& growth_info() {
1251
16.9M
    ABSL_SWISSTABLE_ASSERT(HasGrowthInfoForCapacity(capacity()));
1252
16.9M
    return GetGrowthInfoFromControl(control());
1253
16.9M
  }
1254
152k
  GrowthInfo growth_info() const {
1255
152k
    return const_cast<CommonFields*>(this)->growth_info();
1256
152k
  }
1257
1258
8.61M
  bool has_infoz() const { return inline_data_.has_infoz(); }
1259
0
  void set_has_infoz() {
1260
0
    ABSL_SWISSTABLE_ASSERT(inline_data_.is_sampled_seed());
1261
0
    inline_data_.set_has_infoz();
1262
0
  }
1263
1264
0
  HashtablezInfoHandle* infoz_ptr() const {
1265
    // growth_info is stored before control bytes.
1266
0
    ABSL_SWISSTABLE_ASSERT(
1267
0
        reinterpret_cast<uintptr_t>(control()) % alignof(size_t) == 0);
1268
0
    ABSL_SWISSTABLE_ASSERT(has_infoz());
1269
0
    return reinterpret_cast<HashtablezInfoHandle*>(
1270
0
        control() - ControlOffset(/*has_infoz=*/true,
1271
0
                                  HasGrowthInfoForCapacity(capacity())));
1272
0
  }
1273
1274
8.59M
  HashtablezInfoHandle infoz() {
1275
8.59M
    return has_infoz() ? *infoz_ptr() : HashtablezInfoHandle();
1276
8.59M
  }
1277
0
  void set_infoz(HashtablezInfoHandle infoz) {
1278
0
    ABSL_SWISSTABLE_ASSERT(has_infoz());
1279
0
    *infoz_ptr() = infoz;
1280
0
  }
1281
1282
0
  bool should_rehash_for_bug_detection_on_insert() const {
1283
0
    if constexpr (!SwisstableGenerationsEnabled()) {
1284
0
      return false;
1285
0
    }
1286
0
    // As an optimization, we avoid calling ShouldRehashForBugDetection if we
1287
0
    // will end up rehashing anyways.
1288
0
    if (growth_left() == 0) return false;
1289
0
    return CommonFieldsGenerationInfo::
1290
0
        should_rehash_for_bug_detection_on_insert(capacity());
1291
0
  }
1292
0
  bool should_rehash_for_bug_detection_on_move() const {
1293
0
    return CommonFieldsGenerationInfo::should_rehash_for_bug_detection_on_move(
1294
0
        capacity());
1295
0
  }
1296
0
  void reset_reserved_growth(size_t reservation) {
1297
0
    CommonFieldsGenerationInfo::reset_reserved_growth(reservation, size());
1298
0
  }
1299
1300
  // The size of the backing array allocation.
1301
0
  size_t alloc_size(size_t slot_size, size_t slot_align) const {
1302
0
    return RawHashSetLayout(capacity(), slot_size, slot_align, has_infoz())
1303
0
        .alloc_size();
1304
0
  }
1305
1306
  // Move fields other than heap_or_soo_.
1307
0
  void move_non_heap_or_soo_fields(CommonFields& that) {
1308
0
    static_cast<CommonFieldsGenerationInfo&>(*this) =
1309
0
        std::move(static_cast<CommonFieldsGenerationInfo&>(that));
1310
0
    inline_data_ = that.inline_data_;
1311
0
  }
1312
1313
  // Returns the number of control bytes set to kDeleted. For testing only.
1314
0
  size_t TombstonesCount() const {
1315
0
    return static_cast<size_t>(
1316
0
        std::count(control(), control() + capacity(), ctrl_t::kDeleted));
1317
0
  }
1318
1319
  // Helper to enable sanitizer mode validation to protect against reentrant
1320
  // calls during element constructor/destructor.
1321
  template <typename F>
1322
  void RunWithReentrancyGuard(F f) {
1323
#ifdef NDEBUG
1324
    f();
1325
    return;
1326
#endif
1327
    const HashtableCapacity cap = maybe_invalid_capacity();
1328
    set_capacity(HashtableCapacity::CreateReentrance());
1329
    f();
1330
    set_capacity(cap);
1331
  }
1332
1333
 private:
1334
  // We store the has_infoz bit in the lowest bit of size_.
1335
0
  static constexpr size_t HasInfozShift() { return 1; }
1336
0
  static constexpr size_t HasInfozMask() {
1337
0
    return (size_t{1} << HasInfozShift()) - 1;
1338
0
  }
1339
1340
  // We can't assert that SOO is enabled because we don't have SooEnabled(), but
1341
  // we assert what we can.
1342
0
  void AssertInSooMode() const {
1343
0
    ABSL_SWISSTABLE_ASSERT(capacity() == SooCapacity());
1344
0
    ABSL_SWISSTABLE_ASSERT(!has_infoz());
1345
0
  }
1346
1347
  // TODO(b/289225379): we could put size_ into HeapOrSoo and make capacity_
1348
  // encode the size in SOO case. We would be making size()/capacity() more
1349
  // expensive in order to have more SOO space.
1350
  HashtableInlineData inline_data_;
1351
1352
  // Either the control/slots pointers or the SOO slot.
1353
  HeapOrSoo heap_or_soo_;
1354
};
1355
1356
template <class Policy, class... Params>
1357
class raw_hash_set;
1358
1359
// Applies the following mapping to every byte in the control array:
1360
//   * kDeleted -> kEmpty
1361
//   * kEmpty -> kEmpty
1362
//   * _ -> kDeleted
1363
// PRECONDITION:
1364
//   IsValidCapacity(capacity)
1365
//   ctrl[capacity] == ctrl_t::kSentinel
1366
//   ctrl[i] != ctrl_t::kSentinel for all i < capacity
1367
void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity);
1368
1369
template <class InputIter>
1370
size_t SelectBucketCountForIterRange(InputIter first, InputIter last,
1371
                                     size_t bucket_count) {
1372
  if (bucket_count != 0) {
1373
    return bucket_count;
1374
  }
1375
  if (base_internal::IsAtLeastIterator<std::random_access_iterator_tag,
1376
                                       InputIter>()) {
1377
    return SizeToCapacity(static_cast<size_t>(std::distance(first, last)));
1378
  }
1379
  return 0;
1380
}
1381
1382
0
constexpr bool SwisstableDebugEnabled() {
1383
0
#if defined(ABSL_SWISSTABLE_ENABLE_GENERATIONS) || \
1384
0
    ABSL_OPTION_HARDENED == 1 || !defined(NDEBUG)
1385
0
  return true;
1386
0
#else
1387
0
  return false;
1388
0
#endif
1389
0
}
1390
1391
// Dereferences `ptr`. The function is named in order to provide a helpful error
1392
// message when users see crashing stack traces. Note that this function is not
1393
// guaranteed to crash when `ptr` is invalid if sanitizer mode is not enabled.
1394
template <typename T>
1395
0
T CrashIfIteratorIsInvalid(const T* ptr) {
1396
0
  // If the following line(s) crash, then it's likely that `ptr` is from a
1397
0
  // backing array that has been deallocated. If you see a crash here, it likely
1398
0
  // means that you are comparing an invalid iterator from a table that has
1399
0
  // rehashed, moved, or been destroyed. In such cases, it is often helpful to
1400
0
  // reproduce the issue with --config=asan and (assuming there's a crash here)
1401
0
  // examine the corresponding deallocation stack trace.
1402
0
  T ret = *ptr;
1403
0
  // Force a read with inline asm to make sure that a crash happens here, rather
1404
0
  // than later when the value is used.
1405
0
#ifdef __clang__
1406
0
  asm("" : "+r"(ret));
1407
0
#endif
1408
0
  return ret;
1409
0
}
Unexecuted instantiation: unsigned char absl::container_internal::CrashIfIteratorIsInvalid<unsigned char>(unsigned char const*)
Unexecuted instantiation: absl::container_internal::ctrl_t absl::container_internal::CrashIfIteratorIsInvalid<absl::container_internal::ctrl_t>(absl::container_internal::ctrl_t const*)
1410
1411
inline void AssertIsFull(const ctrl_t* ctrl, GenerationType generation,
1412
                         const GenerationType* generation_ptr,
1413
0
                         const char* operation) {
1414
0
  if (!SwisstableDebugEnabled()) return;
1415
0
  // `SwisstableDebugEnabled()` is also true for release builds with hardening
1416
0
  // enabled. To minimize their impact in those builds:
1417
0
  // - use `ABSL_PREDICT_FALSE()` to provide a compiler hint for code layout
1418
0
  // - use `ABSL_RAW_LOG()` with a format string to reduce code size and improve
1419
0
  //   the chances that the hot paths will be inlined.
1420
0
  if (ABSL_PREDICT_FALSE(ctrl == nullptr)) {
1421
0
    ABSL_RAW_LOG(FATAL, "%s called on end() iterator.", operation);
1422
0
  }
1423
0
  if (ABSL_PREDICT_FALSE(ctrl == DefaultIterControl())) {
1424
0
    ABSL_RAW_LOG(FATAL, "%s called on default-constructed iterator.",
1425
0
                 operation);
1426
0
  }
1427
0
  if (SwisstableGenerationsEnabled()) {
1428
0
    if (ABSL_PREDICT_FALSE(generation !=
1429
0
                           CrashIfIteratorIsInvalid(generation_ptr))) {
1430
0
      ABSL_RAW_LOG(FATAL,
1431
0
                   "%s called on invalid iterator. The table could have "
1432
0
                   "rehashed or moved since this iterator was initialized.",
1433
0
                   operation);
1434
0
    }
1435
0
    if (ABSL_PREDICT_FALSE(!IsFull(CrashIfIteratorIsInvalid(ctrl)))) {
1436
0
      ABSL_RAW_LOG(
1437
0
          FATAL,
1438
0
          "%s called on invalid iterator. The element was likely erased.",
1439
0
          operation);
1440
0
    }
1441
0
  } else {
1442
0
    if (ABSL_PREDICT_FALSE(!IsFull(CrashIfIteratorIsInvalid(ctrl)))) {
1443
0
      ABSL_RAW_LOG(
1444
0
          FATAL,
1445
0
          "%s called on invalid iterator. The element might have been erased "
1446
0
          "or the table might have rehashed. Consider running with "
1447
0
          "--config=asan to diagnose rehashing issues.",
1448
0
          operation);
1449
0
    }
1450
0
  }
1451
0
}
1452
1453
// Note that for comparisons, null/end iterators are valid.
1454
inline void AssertIsValidForComparison(const ctrl_t* ctrl,
1455
                                       GenerationType generation,
1456
0
                                       const GenerationType* generation_ptr) {
1457
0
  if (!SwisstableDebugEnabled()) return;
1458
0
  const bool ctrl_is_valid_for_comparison =
1459
0
      ctrl == nullptr || ctrl == DefaultIterControl() ||
1460
0
      IsFull(CrashIfIteratorIsInvalid(ctrl));
1461
0
  if (SwisstableGenerationsEnabled()) {
1462
0
    if (ABSL_PREDICT_FALSE(generation !=
1463
0
                           CrashIfIteratorIsInvalid(generation_ptr))) {
1464
0
      // Note: in the case of a rehash, we would expect to see a sanitizer crash
1465
0
      // in CrashIfIteratorIsInvalid so this assertion will only catch moved
1466
0
      // table cases, unless we're using a custom allocator that does not
1467
0
      // deallocate the old backing array (e.g. an arena allocator).
1468
0
      ABSL_RAW_LOG(
1469
0
          FATAL,
1470
0
          "Invalid iterator comparison. The table was likely moved (or "
1471
0
          "possibly rehashed) since this iterator was initialized.");
1472
0
    }
1473
0
    if (ABSL_PREDICT_FALSE(!ctrl_is_valid_for_comparison)) {
1474
0
      ABSL_RAW_LOG(
1475
0
          FATAL, "Invalid iterator comparison. The element was likely erased.");
1476
0
    }
1477
0
  } else {
1478
0
    ABSL_HARDENING_ASSERT_SLOW(
1479
0
        ctrl_is_valid_for_comparison &&
1480
0
        "Invalid iterator comparison. The element might have been erased or "
1481
0
        "the table might have rehashed. Consider running with --config=asan to "
1482
0
        "diagnose rehashing issues.");
1483
0
  }
1484
0
}
1485
1486
// If the two iterators come from the same container, then their pointers will
1487
// interleave such that ctrl_a <= ctrl_b < slot_a <= slot_b or vice/versa.
1488
// Note: we take slots by reference so that it's not UB if they're uninitialized
1489
// as long as we don't read them (when ctrl is null).
1490
inline bool AreItersFromSameContainer(const ctrl_t* ctrl_a,
1491
                                      const ctrl_t* ctrl_b,
1492
                                      const void* const& slot_a,
1493
0
                                      const void* const& slot_b) {
1494
0
  // If either control byte is null, then we can't tell.
1495
0
  if (ctrl_a == nullptr || ctrl_b == nullptr) return true;
1496
0
  const bool a_is_soo = IsSooControl(ctrl_a);
1497
0
  if (a_is_soo != IsSooControl(ctrl_b)) return false;
1498
0
  if (a_is_soo) return slot_a == slot_b;
1499
0
1500
0
  const void* low_slot = slot_a;
1501
0
  const void* hi_slot = slot_b;
1502
0
  if (ctrl_a > ctrl_b) {
1503
0
    std::swap(ctrl_a, ctrl_b);
1504
0
    std::swap(low_slot, hi_slot);
1505
0
  }
1506
0
  return ctrl_b < low_slot && low_slot <= hi_slot;
1507
0
}
1508
1509
// Asserts that two iterators come from the same container.
1510
// Note: we take slots by reference so that it's not UB if they're uninitialized
1511
// as long as we don't read them (when ctrl is null).
1512
inline void AssertSameContainer(const ctrl_t* ctrl_a, const ctrl_t* ctrl_b,
1513
                                const void* const& slot_a,
1514
                                const void* const& slot_b,
1515
                                const GenerationType* generation_ptr_a,
1516
0
                                const GenerationType* generation_ptr_b) {
1517
0
  if (!SwisstableDebugEnabled()) return;
1518
0
  // `SwisstableDebugEnabled()` is also true for release builds with hardening
1519
0
  // enabled. To minimize their impact in those builds:
1520
0
  // - use `ABSL_PREDICT_FALSE()` to provide a compiler hint for code layout
1521
0
  // - use `ABSL_RAW_LOG()` with a format string to reduce code size and improve
1522
0
  //   the chances that the hot paths will be inlined.
1523
0
1524
0
  // fail_if(is_invalid, message) crashes when is_invalid is true and provides
1525
0
  // an error message based on `message`.
1526
0
  const auto fail_if = [](bool is_invalid, const char* message) {
1527
0
    if (ABSL_PREDICT_FALSE(is_invalid)) {
1528
0
      ABSL_RAW_LOG(FATAL, "Invalid iterator comparison. %s", message);
1529
0
    }
1530
0
  };
1531
0
1532
0
  const bool a_is_default = ctrl_a == DefaultIterControl();
1533
0
  const bool b_is_default = ctrl_b == DefaultIterControl();
1534
0
  if (a_is_default && b_is_default) return;
1535
0
  fail_if(a_is_default != b_is_default,
1536
0
          "Comparing default-constructed hashtable iterator with a "
1537
0
          "non-default-constructed hashtable iterator.");
1538
0
1539
0
  if (SwisstableGenerationsEnabled()) {
1540
0
    if (ABSL_PREDICT_TRUE(generation_ptr_a == generation_ptr_b)) return;
1541
0
    const bool a_is_empty = IsEmptyGeneration(generation_ptr_a);
1542
0
    const bool b_is_empty = IsEmptyGeneration(generation_ptr_b);
1543
0
    fail_if(a_is_empty != b_is_empty,
1544
0
            "Comparing an iterator from an empty hashtable with an iterator "
1545
0
            "from a non-empty hashtable.");
1546
0
    fail_if(a_is_empty && b_is_empty,
1547
0
            "Comparing iterators from different empty hashtables.");
1548
0
1549
0
    const bool a_is_end = ctrl_a == nullptr;
1550
0
    const bool b_is_end = ctrl_b == nullptr;
1551
0
    fail_if(a_is_end || b_is_end,
1552
0
            "Comparing iterator with an end() iterator from a different "
1553
0
            "hashtable.");
1554
0
    fail_if(true, "Comparing non-end() iterators from different hashtables.");
1555
0
  } else {
1556
0
    ABSL_HARDENING_ASSERT_SLOW(
1557
0
        AreItersFromSameContainer(ctrl_a, ctrl_b, slot_a, slot_b) &&
1558
0
        "Invalid iterator comparison. The iterators may be from different "
1559
0
        "containers or the container might have rehashed or moved. Consider "
1560
0
        "running with --config=asan to diagnose issues.");
1561
0
  }
1562
0
}
1563
1564
struct FindInfo {
1565
  size_t offset;
1566
  size_t probe_length;
1567
};
1568
1569
// Whether a table fits entirely into a probing group.
1570
// Arbitrary order of elements in such tables is correct.
1571
271k
constexpr bool is_single_group(size_t capacity) {
1572
271k
  return capacity <= Group::kWidth;
1573
271k
}
1574
1575
// The state for a probe sequence.
1576
//
1577
// Currently, the sequence is a triangular progression of the form
1578
//
1579
//   p(i) := Width * (i^2 + i)/2 + hash (mod mask + 1)
1580
//
1581
// The use of `Width` ensures that each probe step does not overlap groups;
1582
// the sequence effectively outputs the addresses of *groups* (although not
1583
// necessarily aligned to any boundary). The `Group` machinery allows us
1584
// to check an entire group with minimal branching.
1585
//
1586
// Wrapping around at `mask + 1` is important, but not for the obvious reason.
1587
// As described above, the first few entries of the control byte array
1588
// are mirrored at the end of the array, which `Group` will find and use
1589
// for selecting candidates. However, when those candidates' slots are
1590
// actually inspected, there are no corresponding slots for the cloned bytes,
1591
// so we need to make sure we've treated those offsets as "wrapping around".
1592
//
1593
// It turns out that this probe sequence visits every group exactly once if the
1594
// number of groups is a power of two, since (i^2+i)/2 is a bijection in
1595
// Z/(2^m). See https://en.wikipedia.org/wiki/Quadratic_probing
1596
template <size_t Width>
1597
class probe_seq {
1598
 public:
1599
  // Creates a new probe sequence using `hash` as the initial value of the
1600
  // sequence and `capacity` as the mask to apply to each value in the
1601
  // progression.
1602
  probe_seq(HashtableCapacity capacity, size_t hash)
1603
166k
      : capacity_(capacity), offset_(capacity.mask(hash)) {}
1604
1605
  // The offset within the table, i.e., the value `p(i)` above.
1606
335k
  size_t offset() const { return offset_; }
1607
81.7k
  size_t offset(size_t i) const { return capacity_.mask(offset_ + i); }
1608
1609
2.57k
  void next() {
1610
2.57k
    index_ += Width;
1611
2.57k
    offset_ += index_;
1612
2.57k
    offset_ = capacity_.mask(offset_);
1613
2.57k
  }
1614
  // 0-based probe index, a multiple of `Width`.
1615
84.3k
  size_t index() const { return index_; }
1616
1617
 private:
1618
  HashtableCapacity capacity_;
1619
  size_t offset_;
1620
  size_t index_ = 0;
1621
};
1622
1623
// Begins a probing operation on `common.control`, using `hash`.
1624
inline probe_seq<Group::kWidth> probe_h1(HashtableCapacity capacity,
1625
166k
                                         size_t h1) {
1626
166k
  return probe_seq<Group::kWidth>(capacity, h1);
1627
166k
}
1628
0
inline probe_seq<Group::kWidth> probe(HashtableCapacity capacity, size_t hash) {
1629
0
  return probe_h1(capacity, H1(hash));
1630
0
}
1631
0
inline probe_seq<Group::kWidth> probe(const CommonFields& common, size_t hash) {
1632
0
  return probe(common.capacity_impl(), hash);
1633
0
}
1634
1635
constexpr size_t kProbedElementIndexSentinel = ~size_t{};
1636
1637
// Implementation detail of transfer_unprobed_elements_to_next_capacity_fn.
1638
// Tries to find the new index for an element whose hash corresponds to
1639
// `h1` for growth to the next capacity.
1640
// Returns kProbedElementIndexSentinel if full probing is required.
1641
//
1642
// If element is located in the first probing group in the table before growth,
1643
// returns one of two positions: `old_index` or `old_index + old_capacity + 1`.
1644
//
1645
// Otherwise, we will try to insert it into the first probe group of the new
1646
// table. We only attempt to do so if the first probe group is already
1647
// initialized.
1648
template <typename = void>
1649
inline size_t TryFindNewIndexWithoutProbing(size_t h1, size_t old_index,
1650
                                            size_t old_capacity,
1651
                                            ctrl_t* new_ctrl,
1652
0
                                            size_t new_capacity) {
1653
0
  size_t index_diff = old_index - h1;
1654
  // The first probe group starts with h1 & capacity.
1655
  // All following groups start at (h1 + Group::kWidth * K) & capacity.
1656
  // We can find an index within the floating group as index_diff modulo
1657
  // Group::kWidth.
1658
  // Both old and new capacity are larger than Group::kWidth so we can avoid
1659
  // computing `& capacity`.
1660
0
  size_t in_floating_group_index = index_diff & (Group::kWidth - 1);
1661
  // By subtracting we will get the difference between the first probe group
1662
  // and the probe group corresponding to old_index.
1663
0
  index_diff -= in_floating_group_index;
1664
0
  if (ABSL_PREDICT_TRUE((index_diff & old_capacity) == 0)) {
1665
0
    size_t new_index = (h1 + in_floating_group_index) & new_capacity;
1666
0
    ABSL_ASSUME(new_index != kProbedElementIndexSentinel);
1667
0
    return new_index;
1668
0
  }
1669
0
  ABSL_SWISSTABLE_ASSERT(((old_index - h1) & old_capacity) >= Group::kWidth);
1670
  // Try to insert element into the first probe group.
1671
  // new_ctrl is not yet fully initialized so we can't use regular search via
1672
  // find_first_non_full.
1673
1674
  // We can search in the first probe group only if it is located in already
1675
  // initialized part of the table.
1676
0
  if (ABSL_PREDICT_FALSE((h1 & old_capacity) >= old_index)) {
1677
0
    return kProbedElementIndexSentinel;
1678
0
  }
1679
0
  size_t offset = h1 & new_capacity;
1680
0
  Group new_g(new_ctrl + offset);
1681
0
  if (auto mask = new_g.MaskNonFull(); ABSL_PREDICT_TRUE(mask)) {
1682
0
    size_t result = offset + mask.LowestBitSet();
1683
0
    ABSL_ASSUME(result != kProbedElementIndexSentinel);
1684
0
    return result;
1685
0
  }
1686
0
  return kProbedElementIndexSentinel;
1687
0
}
1688
1689
// Extern template for inline function keeps possibility of inlining.
1690
// When compiler decided to not inline, no symbols will be added to the
1691
// corresponding translation unit.
1692
extern template size_t TryFindNewIndexWithoutProbing(size_t h1,
1693
                                                     size_t old_index,
1694
                                                     size_t old_capacity,
1695
                                                     ctrl_t* new_ctrl,
1696
                                                     size_t new_capacity);
1697
1698
// growth_info (which is a size_t) is stored with the backing array.
1699
0
constexpr size_t BackingArrayAlignment(size_t align_of_slot) {
1700
0
  return (std::max)(align_of_slot, alignof(GrowthInfo));
1701
0
}
1702
1703
// Iterates over all full slots and calls `cb(const ctrl_t*, void*)`.
1704
// No insertion to the table is allowed during `cb` call.
1705
// Erasure is allowed only for the element passed to the callback.
1706
// The table must not be in SOO mode.
1707
void IterateOverFullSlots(const CommonFields& c, size_t slot_size,
1708
                          absl::FunctionRef<void(const ctrl_t*, void*)> cb);
1709
1710
template <typename CharAlloc>
1711
constexpr bool ShouldSampleHashtablezInfoForAlloc() {
1712
  // Folks with custom allocators often make unwarranted assumptions about the
1713
  // behavior of their classes vis-a-vis trivial destructability and what
1714
  // calls they will or won't make.  Avoid sampling for people with custom
1715
  // allocators to get us out of this mess.  This is not a hard guarantee but
1716
  // a workaround while we plan the exact guarantee we want to provide.
1717
  return std::is_same_v<CharAlloc, std::allocator<char>>;
1718
}
1719
1720
// Allocates `n` bytes for a backing array.
1721
template <size_t AlignOfBackingArray, typename Alloc>
1722
201k
void* AllocateBackingArray(void* alloc, size_t n) {
1723
201k
  return Allocate<AlignOfBackingArray>(static_cast<Alloc*>(alloc), n);
1724
201k
}
1725
1726
// Note: we mark this function as ABSL_ATTRIBUTE_NOINLINE because we don't want
1727
// it to be inlined into e.g. the destructor to save code size.
1728
template <size_t AlignOfBackingArray, typename Alloc>
1729
ABSL_ATTRIBUTE_NOINLINE void DeallocateBackingArray(
1730
    void* alloc, size_t capacity, ctrl_t* ctrl, size_t slot_size,
1731
201k
    size_t slot_align, bool had_infoz) {
1732
201k
  RawHashSetLayout layout(capacity, slot_size, slot_align, had_infoz);
1733
201k
  void* backing_array = ctrl - layout.control_offset();
1734
  // Unpoison before returning the memory to the allocator.
1735
201k
  SanitizerUnpoisonMemoryRegion(backing_array, layout.alloc_size());
1736
201k
  Deallocate<AlignOfBackingArray>(static_cast<Alloc*>(alloc), backing_array,
1737
201k
                                  layout.alloc_size());
1738
201k
}
1739
1740
// PolicyFunctions bundles together some information for a particular
1741
// raw_hash_set<T, ...> instantiation. This information is passed to
1742
// type-erased functions that want to do small amounts of type-specific
1743
// work.
1744
struct PolicyFunctions {
1745
  uint32_t key_size;
1746
  uint32_t value_size;
1747
  uint32_t slot_size;
1748
  uint16_t slot_align;
1749
  bool soo_enabled;
1750
  bool is_hashtablez_eligible;
1751
1752
  // Returns the pointer to the hash function stored in the set.
1753
  void* (*hash_fn)(CommonFields& common);
1754
1755
  // Returns the hash of the pointed-to slot.
1756
  HashSlotFn hash_slot;
1757
1758
  // Transfers the contents of `count` slots from src_slot to dst_slot.
1759
  // We use ability to transfer several slots in single group table growth.
1760
  void (*transfer_n)(void* set, void* dst_slot, void* src_slot, size_t count);
1761
1762
  // Returns the pointer to the CharAlloc stored in the set.
1763
  void* (*get_char_alloc)(CommonFields& common);
1764
1765
  // Allocates n bytes for the backing store for common.
1766
  void* (*alloc)(void* alloc, size_t n);
1767
1768
  // Deallocates the backing store from common.
1769
  void (*dealloc)(void* alloc, size_t capacity, ctrl_t* ctrl, size_t slot_size,
1770
                  size_t slot_align, bool had_infoz);
1771
1772
  // Implementation detail of GrowToNextCapacity.
1773
  // Iterates over all full slots and transfers unprobed elements.
1774
  // Initializes the new control bytes except mirrored bytes and kSentinel.
1775
  // Caller must finish the initialization.
1776
  // All slots corresponding to the full control bytes are transferred.
1777
  // Probed elements are reported by `encode_probed_element` callback.
1778
  // encode_probed_element may overwrite old_ctrl buffer till source_offset.
1779
  // Different encoding is used depending on the capacity of the table.
1780
  // See ProbedItem*Bytes classes for details.
1781
  void (*transfer_unprobed_elements_to_next_capacity)(
1782
      CommonFields& common, const ctrl_t* old_ctrl, void* old_slots,
1783
      // TODO(b/382423690): Try to use absl::FunctionRef here.
1784
      void* probed_storage,
1785
      void (*encode_probed_element)(void* probed_storage, h2_t h2,
1786
                                    size_t source_offset, size_t h1));
1787
1788
432k
  uint8_t soo_capacity() const {
1789
432k
    return static_cast<uint8_t>(soo_enabled ? SooCapacity() : 0);
1790
432k
  }
1791
};
1792
1793
// The following functions are used for calculating the max valid size of the
1794
// table. This is important for security to avoid overflowing size_t when
1795
// calculating the allocation size of the backing array
1796
// (https://nvd.nist.gov/vuln/detail/CVE-2025-0838). We also limit the max valid
1797
// size based on the size of the key_type, and this is an optimization because
1798
// we ABSL_ASSUME that the size is less than MaxValidSize, which can enable
1799
// other optimizations for tables with small keys.
1800
1801
template <size_t kSizeOfSizeT = sizeof(size_t)>
1802
0
constexpr size_t MaxSizeAtMaxValidCapacity(size_t slot_size) {
1803
0
  using SizeT = std::conditional_t<kSizeOfSizeT == 4, uint32_t, uint64_t>;
1804
  // We shift right by 2 for a safe margin against overflow.
1805
0
  constexpr SizeT kMaxValidCapacity = ~SizeT{} >> 2;
1806
0
  return CapacityToGrowth(kMaxValidCapacity) / slot_size;
1807
0
}
1808
1809
0
constexpr size_t MaxStorableSize() {
1810
0
  return static_cast<size_t>(uint64_t{1}
1811
0
                             << HashtableInlineData::kSizeBitCount) -
1812
0
         1;
1813
0
}
1814
1815
// There are no more than 2^sizeof(key_type) unique key_types (and hashtable
1816
// keys must be unique) so we can't have a hashtable with more than
1817
// 2^sizeof(key_type) elements.
1818
template <size_t kSizeOfSizeT = sizeof(size_t)>
1819
0
constexpr size_t MaxValidSizeForKeySize(size_t key_size) {
1820
0
  if (key_size < kSizeOfSizeT) return size_t{1} << 8 * key_size;
1821
0
  return (std::numeric_limits<size_t>::max)();
1822
0
}
1823
1824
template <size_t kSizeOfSizeT = sizeof(size_t)>
1825
0
constexpr size_t MaxValidSizeForSlotSize(size_t slot_size) {
1826
0
  if constexpr (kSizeOfSizeT == 8) {
1827
    // For small slot sizes we are limited by HashtableStackData::kSizeBitCount.
1828
0
    if (slot_size < size_t{1} << (64 - HashtableInlineData::kSizeBitCount)) {
1829
0
      return MaxStorableSize();
1830
0
    }
1831
0
  }
1832
0
  return MaxSizeAtMaxValidCapacity<kSizeOfSizeT>(slot_size);
1833
0
}
1834
1835
// Returns the maximum valid size for a table, given the key size and slot size.
1836
// Template parameter is only used to enable testing.
1837
template <size_t kSizeOfSizeT = sizeof(size_t)>
1838
0
constexpr size_t MaxValidSize(size_t key_size, size_t slot_size) {
1839
0
  return (std::min)(MaxValidSizeForKeySize<kSizeOfSizeT>(key_size),
1840
0
                    MaxValidSizeForSlotSize<kSizeOfSizeT>(slot_size));
1841
0
}
1842
1843
// Returns the index of the SOO slot when growing from SOO to non-SOO in a
1844
// single group. See also InitializeSmallControlBytesAfterSoo(). It's important
1845
// to use index 1 so that when resizing from capacity 1 to 3, we can still have
1846
// random iteration order between the first two inserted elements.
1847
// I.e. it allows inserting the second element at either index 0 or 2.
1848
98.1k
constexpr size_t SooSlotIndex() { return 1; }
1849
1850
// Maximum capacity for the algorithm for small table after SOO.
1851
// Note that typical size after SOO is 3, but we allow up to 7.
1852
// Allowing till 16 would require additional store that can be avoided.
1853
0
constexpr size_t MaxSmallAfterSooCapacity() { return 7; }
1854
1855
// Type erased version of raw_hash_set::reserve. Requires:
1856
//   1. `new_size > policy.soo_capacity`.
1857
//   2. `new_size <= kMaxValidSize`.
1858
void ReserveTableToFitNewSize(CommonFields& common,
1859
                              const PolicyFunctions& policy, size_t new_size);
1860
1861
// Resizes empty non-allocated table to the next valid capacity after
1862
// `bucket_count`. Requires:
1863
//   1. `c.capacity() == policy.soo_capacity`.
1864
//   2. `c.empty()`.
1865
//   3. `new_size > policy.soo_capacity`.
1866
//   4. `bucket_count <= MaxValidCapacity()`.
1867
// The table will be attempted to be sampled.
1868
void ReserveEmptyNonAllocatedTableToFitBucketCount(
1869
    CommonFields& common, const PolicyFunctions& policy, size_t bucket_count);
1870
1871
// Type erased version of raw_hash_set::rehash.
1872
// Requires: `n <= MaxValidCapacity()`.
1873
void Rehash(CommonFields& common, const PolicyFunctions& policy, size_t n);
1874
1875
// Type erased version of copy constructor.
1876
void Copy(CommonFields& common, const PolicyFunctions& policy,
1877
          const CommonFields& other,
1878
          absl::FunctionRef<void(void*, const void*)> copy_fn);
1879
1880
// Returns the optimal size for memcpy when transferring SOO slot.
1881
// Otherwise, returns the optimal size for memcpy SOO slot transfer
1882
// to SooSlotIndex().
1883
// At the destination we are allowed to copy upto twice more bytes,
1884
// because there is at least one more slot after SooSlotIndex().
1885
// The result must not exceed MaxSooSlotSize().
1886
// Some of the cases are merged to minimize the number of function
1887
// instantiations.
1888
constexpr size_t OptimalMemcpySizeForSooSlotTransfer(
1889
0
    size_t slot_size, size_t max_soo_slot_size = MaxSooSlotSize()) {
1890
0
  static_assert(MaxSooSlotSize() >= 8, "unexpectedly small SOO slot size");
1891
0
  if (slot_size == 1) {
1892
0
    return 1;
1893
0
  }
1894
0
  if (slot_size <= 3) {
1895
0
    return 4;
1896
0
  }
1897
0
  // We are merging 4 and 8 into one case because we expect them to be the
1898
0
  // hottest cases. Copying 8 bytes is as fast on common architectures.
1899
0
  if (slot_size <= 8) {
1900
0
    return 8;
1901
0
  }
1902
0
  if (max_soo_slot_size <= 16) {
1903
0
    return max_soo_slot_size;
1904
0
  }
1905
0
  if (slot_size <= 16) {
1906
0
    return 16;
1907
0
  }
1908
0
  if (max_soo_slot_size <= 24) {
1909
0
    return max_soo_slot_size;
1910
0
  }
1911
0
  static_assert(MaxSooSlotSize() <= 24, "unexpectedly large SOO slot size");
1912
0
  return 24;
1913
0
}
1914
1915
// Resizes SOO table to the NextCapacity(SooCapacity()) and prepares insert for
1916
// the given new_hash. Returns the offset of the new element.
1917
// All possible template combinations are defined in cc file to improve
1918
// compilation time.
1919
template <size_t SooSlotMemcpySize, bool TransferUsesMemcpy>
1920
size_t GrowSooTableToNextCapacityAndPrepareInsert(
1921
    CommonFields& common, const PolicyFunctions& policy,
1922
    absl::FunctionRef<size_t(size_t)> get_hash, bool force_sampling);
1923
1924
// PrepareInsert for small tables (is_small()==true).
1925
// Returns the new control and the new slot.
1926
// Hash is only computed if the table is sampled or grew to large size
1927
// (is_small()==false).
1928
std::pair<ctrl_t*, void*> PrepareInsertSmallNonSoo(
1929
    CommonFields& common, const PolicyFunctions& policy,
1930
    absl::FunctionRef<size_t(size_t)> get_hash);
1931
1932
// Resizes table with allocated slots and change the table seed.
1933
// Tables with SOO enabled must have capacity > policy.soo_capacity.
1934
// No sampling will be performed since table is already allocated.
1935
void ResizeAllocatedTableWithSeedChange(CommonFields& common,
1936
                                        const PolicyFunctions& policy,
1937
                                        size_t new_capacity);
1938
1939
// ClearBackingArray clears the backing array, either modifying it in place,
1940
// or creating a new one based on the value of "reuse".
1941
// REQUIRES: c.capacity > MaxSmallCapacity().
1942
void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
1943
                       void* alloc, bool reuse);
1944
1945
// Type-erased versions of raw_hash_set::erase_meta_only_{small,large}.
1946
void EraseMetaOnlySmall(CommonFields& c, bool soo_enabled, size_t slot_size);
1947
void EraseMetaOnlyLarge(CommonFields& c, const ctrl_t* ctrl, size_t slot_size);
1948
1949
// For trivially relocatable types we use memcpy directly. This allows us to
1950
// share the same function body for raw_hash_set instantiations that have the
1951
// same slot size as long as they are relocatable.
1952
// Separate function for relocating single slot cause significant binary bloat.
1953
template <size_t SizeOfSlot>
1954
ABSL_ATTRIBUTE_NOINLINE void TransferNRelocatable(void*, void* dst, void* src,
1955
                                                  size_t count) {
1956
  // TODO(b/382423690): Experiment with making specialization for power of 2 and
1957
  // non power of 2. This would require passing the size of the slot.
1958
  memcpy(dst, src, SizeOfSlot * count);
1959
}
1960
1961
// Returns a pointer to `common`. This is used to implement type erased
1962
// raw_hash_set::get_hash_ref_fn and raw_hash_set::get_alloc_ref_fn for the
1963
// empty class cases.
1964
void* GetRefForEmptyClass(CommonFields& common);
1965
1966
// Given the hash of a value not currently in the table and the first group with
1967
// an empty slot in the probe sequence, finds a viable slot index to insert it
1968
// at.
1969
//
1970
// In case there's no space left, the table can be resized or rehashed
1971
// (for tables with deleted slots, see FindInsertPositionWithGrowthOrRehash).
1972
//
1973
// In the case of absence of deleted slots and positive growth_left, the element
1974
// can be inserted in one of the empty slots in the provided `target_group`.
1975
//
1976
// When the table has deleted slots (according to GrowthInfo), the target
1977
// position will be searched one more time using `find_first_non_full`.
1978
//
1979
// REQUIRES: `!common.is_small()`.
1980
// REQUIRES: At least one non-full slot available.
1981
// REQUIRES: `mask_empty` is a mask containing empty slots for the
1982
//           `target_group`.
1983
// REQUIRES: `target_group` is a starting position for the group that has
1984
//            at least one empty slot.
1985
size_t PrepareInsertLarge(CommonFields& common, const PolicyFunctions& policy,
1986
                          size_t hash, Group::NonIterableBitMaskType mask_empty,
1987
                          FindInfo target_group);
1988
1989
// Same as above, but with generations enabled, we may end up changing the seed,
1990
// which means we need to be able to recompute the hash.
1991
size_t PrepareInsertLargeGenerationsEnabled(
1992
    CommonFields& common, const PolicyFunctions& policy, size_t hash,
1993
    Group::NonIterableBitMaskType mask_empty, FindInfo target_group,
1994
    absl::FunctionRef<size_t(size_t)> recompute_hash);
1995
1996
template <typename Policy, typename Hash, typename Eq, typename Alloc>
1997
struct InstantiateRawHashSet {
1998
  using type = typename ApplyWithoutDefaultSuffix<
1999
      raw_hash_set,
2000
      TypeList<void, typename Policy::DefaultHash, typename Policy::DefaultEq,
2001
               typename Policy::DefaultAlloc>,
2002
      TypeList<Policy, Hash, Eq, Alloc>>::type;
2003
};
2004
2005
// A SwissTable.
2006
//
2007
// Policy: a policy defines how to perform different operations on
2008
// the slots of the hashtable (see hash_policy_traits.h for the full interface
2009
// of policy).
2010
//
2011
// Params...: a variadic list of parameters that allows us to omit default
2012
//            types. This reduces the mangled name of the class and the size of
2013
//            debug strings like __PRETTY_FUNCTION__. Default types do not give
2014
//            any new information.
2015
//
2016
// Hash: a (possibly polymorphic) functor that hashes keys of the hashtable. The
2017
// functor should accept a key and return size_t as hash. For best performance
2018
// it is important that the hash function provides high entropy across all bits
2019
// of the hash.
2020
// This is the first element in `Params...` if it exists, or Policy::DefaultHash
2021
// otherwise.
2022
//
2023
// Eq: a (possibly polymorphic) functor that compares two keys for equality. It
2024
// should accept two (of possibly different type) keys and return a bool: true
2025
// if they are equal, false if they are not. If two keys compare equal, then
2026
// their hash values as defined by Hash MUST be equal.
2027
// This is the second element in `Params...` if it exists, or Policy::DefaultEq
2028
// otherwise.
2029
//
2030
// Allocator: an Allocator
2031
// [https://en.cppreference.com/w/cpp/named_req/Allocator] with which
2032
// the storage of the hashtable will be allocated and the elements will be
2033
// constructed and destroyed.
2034
// This is the third element in `Params...` if it exists, or
2035
// Policy::DefaultAlloc otherwise.
2036
template <class Policy, class... Params>
2037
class raw_hash_set {
2038
  using PolicyTraits = hash_policy_traits<Policy>;
2039
  using Hash = GetFromListOr<typename Policy::DefaultHash, 0, Params...>;
2040
  using Eq = GetFromListOr<typename Policy::DefaultEq, 1, Params...>;
2041
  using Alloc = GetFromListOr<typename Policy::DefaultAlloc, 2, Params...>;
2042
  using KeyArgImpl =
2043
      KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
2044
2045
  static_assert(
2046
      std::is_same_v<
2047
          typename InstantiateRawHashSet<Policy, Hash, Eq, Alloc>::type,
2048
          raw_hash_set>,
2049
      "Redundant template parameters were passed. Use InstantiateRawHashSet<> "
2050
      "instead");
2051
2052
 public:
2053
  using init_type = typename PolicyTraits::init_type;
2054
  using key_type = typename PolicyTraits::key_type;
2055
  using allocator_type = Alloc;
2056
  using size_type = size_t;
2057
  using difference_type = ptrdiff_t;
2058
  using hasher = Hash;
2059
  using key_equal = Eq;
2060
  using policy_type = Policy;
2061
  using value_type = typename PolicyTraits::value_type;
2062
  using reference = value_type&;
2063
  using const_reference = const value_type&;
2064
  using pointer = typename std::allocator_traits<
2065
      allocator_type>::template rebind_traits<value_type>::pointer;
2066
  using const_pointer = typename std::allocator_traits<
2067
      allocator_type>::template rebind_traits<value_type>::const_pointer;
2068
2069
 private:
2070
  // Alias used for heterogeneous lookup functions.
2071
  // `key_arg<K>` evaluates to `K` when the functors are transparent and to
2072
  // `key_type` otherwise. It permits template argument deduction on `K` for the
2073
  // transparent case.
2074
  template <class K>
2075
  using key_arg = typename KeyArgImpl::template type<K, key_type>;
2076
2077
  using slot_type = typename PolicyTraits::slot_type;
2078
2079
  constexpr static bool kIsDefaultHash =
2080
      std::is_same_v<hasher, absl::Hash<key_type>> ||
2081
      std::is_same_v<hasher, absl::container_internal::StringHash>;
2082
2083
  // TODO(b/289225379): we could add extra SOO space inside raw_hash_set
2084
  // after CommonFields to allow inlining larger slot_types (e.g. std::string),
2085
  // but it's a bit complicated if we want to support incomplete mapped_type in
2086
  // flat_hash_map. We could potentially do this for flat_hash_set and for an
2087
  // allowlist of `mapped_type`s of flat_hash_map that includes e.g. arithmetic
2088
  // types, strings, cords, and pairs/tuples of allowlisted types.
2089
  constexpr static bool SooEnabled() {
2090
    return PolicyTraits::soo_enabled() &&
2091
           sizeof(slot_type) <= sizeof(HeapOrSoo) &&
2092
           alignof(slot_type) <= alignof(HeapOrSoo);
2093
  }
2094
2095
  constexpr static size_t DefaultCapacity() {
2096
    return SooEnabled() ? SooCapacity() : 0;
2097
  }
2098
  constexpr static size_t MaxValidSize() {
2099
    return container_internal::MaxValidSize(sizeof(key_type),
2100
                                            sizeof(slot_type));
2101
  }
2102
  constexpr static size_t MaxValidCapacity() {
2103
    return SizeToCapacity(MaxValidSize());
2104
  }
2105
2106
  // Whether `size` fits in the SOO capacity of this table.
2107
  bool fits_in_soo(size_t size) const {
2108
    return SooEnabled() && size <= SooCapacity();
2109
  }
2110
  // Whether this table is in SOO mode or non-SOO mode.
2111
  bool is_soo() const {
2112
    HashtableCapacity cap = maybe_invalid_capacity();
2113
    return cap.IsValid() && fits_in_soo(cap.capacity());
2114
  }
2115
  bool is_full_soo() const { return is_soo() && !empty(); }
2116
2117
  bool is_small() const { return common().is_small(); }
2118
2119
  // Give an early error when key_type is not hashable/eq.
2120
  auto KeyTypeCanBeHashed(const Hash& h, const key_type& k) -> decltype(h(k));
2121
  auto KeyTypeCanBeEq(const Eq& eq, const key_type& k) -> decltype(eq(k, k));
2122
2123
  // Try to be helpful when the hasher returns an unreasonable type.
2124
  using key_hash_result =
2125
      absl::remove_cvref_t<decltype(std::declval<const Hash&>()(
2126
          std::declval<const key_type&>()))>;
2127
  static_assert(sizeof(key_hash_result) >= sizeof(size_t),
2128
                "`Hash::operator()` should return a `size_t`");
2129
2130
  using AllocTraits = std::allocator_traits<allocator_type>;
2131
  using SlotAlloc = typename std::allocator_traits<
2132
      allocator_type>::template rebind_alloc<slot_type>;
2133
  // People are often sloppy with the exact type of their allocator (sometimes
2134
  // it has an extra const or is missing the pair, but rebinds made it work
2135
  // anyway).
2136
  using CharAlloc =
2137
      typename std::allocator_traits<Alloc>::template rebind_alloc<char>;
2138
  using SlotAllocTraits = typename std::allocator_traits<
2139
      allocator_type>::template rebind_traits<slot_type>;
2140
2141
  static_assert(std::is_lvalue_reference<reference>::value,
2142
                "Policy::element() must return a reference");
2143
2144
  // An enabler for insert(T&&): T must be convertible to init_type or be the
2145
  // same as [cv] value_type [ref].
2146
  template <class T>
2147
  using Insertable = std::disjunction<
2148
      std::is_same<absl::remove_cvref_t<reference>, absl::remove_cvref_t<T>>,
2149
      std::is_convertible<T, init_type>>;
2150
  template <class T>
2151
  using IsNotBitField = std::is_pointer<T*>;
2152
2153
  // RequiresNotInit is a workaround for gcc prior to 7.1.
2154
  // See https://godbolt.org/g/Y4xsUh.
2155
  template <class T>
2156
  using RequiresNotInit =
2157
      typename std::enable_if<!std::is_same<T, init_type>::value, int>::type;
2158
2159
  template <class... Ts>
2160
  using IsDecomposable = IsDecomposable<void, PolicyTraits, Hash, Eq, Ts...>;
2161
2162
  template <class T>
2163
  using IsDecomposableAndInsertable =
2164
      IsDecomposable<std::enable_if_t<Insertable<T>::value, T>>;
2165
2166
  // Evaluates to true if an assignment from the given type would require the
2167
  // source object to remain alive for the life of the element.
2168
  template <class U>
2169
  using IsLifetimeBoundAssignmentFrom = std::conditional_t<
2170
      policy_trait_element_is_owner<Policy>::value, std::false_type,
2171
      type_traits_internal::IsLifetimeBoundAssignment<init_type, U>>;
2172
2173
 public:
2174
  static_assert(std::is_same<pointer, value_type*>::value,
2175
                "Allocators with custom pointer types are not supported");
2176
  static_assert(std::is_same<const_pointer, const value_type*>::value,
2177
                "Allocators with custom pointer types are not supported");
2178
2179
  class iterator : private HashSetIteratorGenerationInfo {
2180
    friend class raw_hash_set;
2181
    friend struct HashtableFreeFunctionsAccess;
2182
2183
   public:
2184
    using iterator_category = std::forward_iterator_tag;
2185
    using value_type = typename raw_hash_set::value_type;
2186
    using reference =
2187
        std::conditional_t<PolicyTraits::constant_iterators::value,
2188
                            const value_type&, value_type&>;
2189
    using pointer = std::remove_reference_t<reference>*;
2190
    using difference_type = typename raw_hash_set::difference_type;
2191
2192
    iterator() {}
2193
2194
    // PRECONDITION: not an end() iterator.
2195
    reference operator*() const {
2196
      assert_is_full("operator*()");
2197
      return unchecked_deref();
2198
    }
2199
2200
    // PRECONDITION: not an end() iterator.
2201
    pointer operator->() const {
2202
      assert_is_full("operator->");
2203
      return &operator*();
2204
    }
2205
2206
    // PRECONDITION: not an end() iterator.
2207
    iterator& operator++() {
2208
      assert_is_full("operator++");
2209
      ++ctrl_;
2210
      ++slot_;
2211
      skip_empty_or_deleted();
2212
      if (ABSL_PREDICT_FALSE(*ctrl_ == ctrl_t::kSentinel)) ctrl_ = nullptr;
2213
      return *this;
2214
    }
2215
    // PRECONDITION: not an end() iterator.
2216
    iterator operator++(int) {
2217
      auto tmp = *this;
2218
      ++*this;
2219
      return tmp;
2220
    }
2221
2222
    friend bool operator==(const iterator& a, const iterator& b) {
2223
      AssertIsValidForComparison(a.ctrl_, a.generation(), a.generation_ptr());
2224
      AssertIsValidForComparison(b.ctrl_, b.generation(), b.generation_ptr());
2225
      AssertSameContainer(a.ctrl_, b.ctrl_, a.slot_, b.slot_,
2226
                          a.generation_ptr(), b.generation_ptr());
2227
      return a.ctrl_ == b.ctrl_;
2228
    }
2229
    friend bool operator!=(const iterator& a, const iterator& b) {
2230
      return !(a == b);
2231
    }
2232
2233
   private:
2234
    iterator(ctrl_t* ctrl, slot_type* slot,
2235
             const GenerationType* generation_ptr)
2236
        : HashSetIteratorGenerationInfo(generation_ptr),
2237
          ctrl_(ctrl),
2238
          slot_(slot) {
2239
      // This assumption helps the compiler know that any non-end iterator is
2240
      // not equal to any end iterator.
2241
      ABSL_ASSUME(ctrl != nullptr);
2242
    }
2243
    // This constructor is used in begin() to avoid an MSan
2244
    // use-of-uninitialized-value error. Delegating from this constructor to
2245
    // the previous one doesn't avoid the error.
2246
    iterator(ctrl_t* ctrl, MaybeInitializedPtr<void> slot,
2247
             const GenerationType* generation_ptr)
2248
        : HashSetIteratorGenerationInfo(generation_ptr),
2249
          ctrl_(ctrl),
2250
          slot_(to_slot(slot.get())) {
2251
      // This assumption helps the compiler know that any non-end iterator is
2252
      // not equal to any end iterator.
2253
      ABSL_ASSUME(ctrl != nullptr);
2254
    }
2255
    // For end() iterators.
2256
    explicit iterator(const GenerationType* generation_ptr)
2257
        : HashSetIteratorGenerationInfo(generation_ptr), ctrl_(nullptr) {}
2258
2259
    void assert_is_full(const char* operation) const {
2260
      AssertIsFull(ctrl_, generation(), generation_ptr(), operation);
2261
    }
2262
2263
    // Fixes up `ctrl_` to point to a full or sentinel by advancing `ctrl_` and
2264
    // `slot_` until they reach one.
2265
    void skip_empty_or_deleted() {
2266
      while (IsEmptyOrDeleted(*ctrl_)) {
2267
        ++ctrl_;
2268
        ++slot_;
2269
      }
2270
    }
2271
2272
    // An equality check which skips ABSL Hardening iterator invalidation
2273
    // checks.
2274
    // Should be used when the lifetimes of the iterators are well-enough
2275
    // understood to prove that they cannot be invalid.
2276
    bool unchecked_equals(const iterator& b) const {
2277
      return ctrl_ == b.control();
2278
    }
2279
2280
    // Dereferences the iterator without ABSL Hardening iterator invalidation
2281
    // checks.
2282
    reference unchecked_deref() const { return PolicyTraits::element(slot_); }
2283
2284
    ctrl_t* control() const { return ctrl_; }
2285
    slot_type* slot() const { return slot_; }
2286
2287
    // We use DefaultIterControl() for default-constructed iterators so that
2288
    // they can be distinguished from end iterators, which have nullptr ctrl_.
2289
    ctrl_t* ctrl_ = DefaultIterControl();
2290
    // To avoid uninitialized member warnings, put slot_ in an anonymous union.
2291
    // The member is not initialized on singleton and end iterators.
2292
    union {
2293
      slot_type* slot_;
2294
    };
2295
  };
2296
2297
  class const_iterator {
2298
    friend class raw_hash_set;
2299
    template <class Container, typename Enabler>
2300
    friend struct absl::container_internal::hashtable_debug_internal::
2301
        HashtableDebugAccess;
2302
2303
   public:
2304
    using iterator_category = typename iterator::iterator_category;
2305
    using value_type = typename raw_hash_set::value_type;
2306
    using reference = typename raw_hash_set::const_reference;
2307
    using pointer = typename raw_hash_set::const_pointer;
2308
    using difference_type = typename raw_hash_set::difference_type;
2309
2310
    const_iterator() = default;
2311
    // Implicit construction from iterator.
2312
    const_iterator(iterator i) : inner_(std::move(i)) {}  // NOLINT
2313
2314
    reference operator*() const { return *inner_; }
2315
    pointer operator->() const { return inner_.operator->(); }
2316
2317
    const_iterator& operator++() {
2318
      ++inner_;
2319
      return *this;
2320
    }
2321
    const_iterator operator++(int) { return inner_++; }
2322
2323
    friend bool operator==(const const_iterator& a, const const_iterator& b) {
2324
      return a.inner_ == b.inner_;
2325
    }
2326
    friend bool operator!=(const const_iterator& a, const const_iterator& b) {
2327
      return !(a == b);
2328
    }
2329
2330
   private:
2331
    const_iterator(const ctrl_t* ctrl, const slot_type* slot,
2332
                   const GenerationType* gen)
2333
        : inner_(const_cast<ctrl_t*>(ctrl), const_cast<slot_type*>(slot), gen) {
2334
    }
2335
    bool unchecked_equals(const const_iterator& b) const {
2336
      return inner_.unchecked_equals(b.inner_);
2337
    }
2338
    ctrl_t* control() const { return inner_.control(); }
2339
    slot_type* slot() const { return inner_.slot(); }
2340
2341
    iterator inner_;
2342
  };
2343
2344
  using node_type = node_handle<Policy, hash_policy_traits<Policy>, Alloc>;
2345
  using insert_return_type = InsertReturnType<iterator, node_type>;
2346
2347
  // Note: can't use `= default` due to non-default noexcept (causes
2348
  // problems for some compilers). NOLINTNEXTLINE
2349
  raw_hash_set() noexcept(
2350
      std::is_nothrow_default_constructible<hasher>::value &&
2351
      std::is_nothrow_default_constructible<key_equal>::value &&
2352
      std::is_nothrow_default_constructible<allocator_type>::value) {}
2353
2354
  explicit raw_hash_set(
2355
      size_t bucket_count, const hasher& hash = hasher(),
2356
      const key_equal& eq = key_equal(),
2357
      const allocator_type& alloc = allocator_type())
2358
      : settings_(CommonFields::CreateDefault<SooEnabled()>(), hash, eq,
2359
                  alloc) {
2360
    if (bucket_count > DefaultCapacity()) {
2361
      ReserveEmptyNonAllocatedTableToFitBucketCount(
2362
          common(), GetPolicyFunctions(),
2363
          (std::min)(bucket_count, MaxValidCapacity()));
2364
    }
2365
  }
2366
2367
  raw_hash_set(size_t bucket_count, const hasher& hash,
2368
               const allocator_type& alloc)
2369
      : raw_hash_set(bucket_count, hash, key_equal(), alloc) {}
2370
2371
  raw_hash_set(size_t bucket_count, const allocator_type& alloc)
2372
      : raw_hash_set(bucket_count, hasher(), key_equal(), alloc) {}
2373
2374
  explicit raw_hash_set(const allocator_type& alloc)
2375
      : raw_hash_set(0, hasher(), key_equal(), alloc) {}
2376
2377
  template <class InputIter>
2378
  raw_hash_set(InputIter first, InputIter last, size_t bucket_count = 0,
2379
               const hasher& hash = hasher(), const key_equal& eq = key_equal(),
2380
               const allocator_type& alloc = allocator_type())
2381
      : raw_hash_set(SelectBucketCountForIterRange(first, last, bucket_count),
2382
                     hash, eq, alloc) {
2383
    insert(first, last);
2384
  }
2385
2386
  template <class InputIter>
2387
  raw_hash_set(InputIter first, InputIter last, size_t bucket_count,
2388
               const hasher& hash, const allocator_type& alloc)
2389
      : raw_hash_set(first, last, bucket_count, hash, key_equal(), alloc) {}
2390
2391
  template <class InputIter>
2392
  raw_hash_set(InputIter first, InputIter last, size_t bucket_count,
2393
               const allocator_type& alloc)
2394
      : raw_hash_set(first, last, bucket_count, hasher(), key_equal(), alloc) {}
2395
2396
#if defined(__cpp_lib_containers_ranges) && \
2397
    __cpp_lib_containers_ranges >= 202202L
2398
  template <typename R>
2399
  raw_hash_set(std::from_range_t, R&& rg, size_type bucket_count = 0,
2400
               const hasher& hash = hasher(), const key_equal& eq = key_equal(),
2401
               const allocator_type& alloc = allocator_type())
2402
      : raw_hash_set(std::begin(rg), std::end(rg), bucket_count, hash, eq,
2403
                     alloc) {}
2404
2405
  template <typename R>
2406
  raw_hash_set(std::from_range_t, R&& rg, size_type bucket_count,
2407
               const allocator_type& alloc)
2408
      : raw_hash_set(std::from_range, std::forward<R>(rg), bucket_count,
2409
                     hasher(), key_equal(), alloc) {}
2410
2411
  template <typename R>
2412
  raw_hash_set(std::from_range_t, R&& rg, size_type bucket_count,
2413
               const hasher& hash, const allocator_type& alloc)
2414
      : raw_hash_set(std::from_range, std::forward<R>(rg), bucket_count, hash,
2415
                     key_equal(), alloc) {}
2416
#endif
2417
2418
  template <class InputIter>
2419
  raw_hash_set(InputIter first, InputIter last, const allocator_type& alloc)
2420
      : raw_hash_set(first, last, 0, hasher(), key_equal(), alloc) {}
2421
2422
  // Instead of accepting std::initializer_list<value_type> as the first
2423
  // argument like std::unordered_set<value_type> does, we have two overloads
2424
  // that accept std::initializer_list<T> and std::initializer_list<init_type>.
2425
  // This is advantageous for performance.
2426
  //
2427
  //   // Turns {"abc", "def"} into std::initializer_list<std::string>, then
2428
  //   // copies the strings into the set.
2429
  //   std::unordered_set<std::string> s = {"abc", "def"};
2430
  //
2431
  //   // Turns {"abc", "def"} into std::initializer_list<const char*>, then
2432
  //   // copies the strings into the set.
2433
  //   absl::flat_hash_set<std::string> s = {"abc", "def"};
2434
  //
2435
  // The same trick is used in insert().
2436
  //
2437
  // The enabler is necessary to prevent this constructor from triggering where
2438
  // the copy constructor is meant to be called.
2439
  //
2440
  //   absl::flat_hash_set<int> a, b{a};
2441
  //
2442
  // RequiresNotInit<T> is a workaround for gcc prior to 7.1.
2443
  template <class T, RequiresNotInit<T> = 0,
2444
            std::enable_if_t<Insertable<T>::value, int> = 0>
2445
  raw_hash_set(std::initializer_list<T> init, size_t bucket_count = 0,
2446
               const hasher& hash = hasher(), const key_equal& eq = key_equal(),
2447
               const allocator_type& alloc = allocator_type())
2448
      : raw_hash_set(init.begin(), init.end(), bucket_count, hash, eq, alloc) {}
2449
2450
  raw_hash_set(std::initializer_list<init_type> init, size_t bucket_count = 0,
2451
               const hasher& hash = hasher(), const key_equal& eq = key_equal(),
2452
               const allocator_type& alloc = allocator_type())
2453
      : raw_hash_set(init.begin(), init.end(), bucket_count, hash, eq, alloc) {}
2454
2455
  template <class T, RequiresNotInit<T> = 0,
2456
            std::enable_if_t<Insertable<T>::value, int> = 0>
2457
  raw_hash_set(std::initializer_list<T> init, size_t bucket_count,
2458
               const hasher& hash, const allocator_type& alloc)
2459
      : raw_hash_set(init, bucket_count, hash, key_equal(), alloc) {}
2460
2461
  raw_hash_set(std::initializer_list<init_type> init, size_t bucket_count,
2462
               const hasher& hash, const allocator_type& alloc)
2463
      : raw_hash_set(init, bucket_count, hash, key_equal(), alloc) {}
2464
2465
  template <class T, RequiresNotInit<T> = 0,
2466
            std::enable_if_t<Insertable<T>::value, int> = 0>
2467
  raw_hash_set(std::initializer_list<T> init, size_t bucket_count,
2468
               const allocator_type& alloc)
2469
      : raw_hash_set(init, bucket_count, hasher(), key_equal(), alloc) {}
2470
2471
  raw_hash_set(std::initializer_list<init_type> init, size_t bucket_count,
2472
               const allocator_type& alloc)
2473
      : raw_hash_set(init, bucket_count, hasher(), key_equal(), alloc) {}
2474
2475
  template <class T, RequiresNotInit<T> = 0,
2476
            std::enable_if_t<Insertable<T>::value, int> = 0>
2477
  raw_hash_set(std::initializer_list<T> init, const allocator_type& alloc)
2478
      : raw_hash_set(init, 0, hasher(), key_equal(), alloc) {}
2479
2480
  raw_hash_set(std::initializer_list<init_type> init,
2481
               const allocator_type& alloc)
2482
      : raw_hash_set(init, 0, hasher(), key_equal(), alloc) {}
2483
2484
  raw_hash_set(const raw_hash_set& that)
2485
      : raw_hash_set(that, AllocTraits::select_on_container_copy_construction(
2486
                               allocator_type(that.char_alloc_ref()))) {}
2487
2488
  raw_hash_set(const raw_hash_set& that, const allocator_type& a)
2489
      : raw_hash_set(0, that.hash_ref(), that.eq_ref(), a) {
2490
    that.AssertNotDebugCapacity();
2491
    if (that.empty()) return;
2492
    Copy(common(), GetPolicyFunctions(), that.common(),
2493
         [this](void* dst, const void* src) {
2494
           // TODO(b/413598253): type erase for trivially copyable types via
2495
           // PolicyTraits.
2496
           construct(to_slot(dst),
2497
                     PolicyTraits::element(
2498
                         static_cast<slot_type*>(const_cast<void*>(src))));
2499
         });
2500
  }
2501
2502
  ABSL_ATTRIBUTE_NOINLINE raw_hash_set(raw_hash_set&& that) noexcept(
2503
      std::is_nothrow_copy_constructible<hasher>::value &&
2504
      std::is_nothrow_copy_constructible<key_equal>::value &&
2505
      std::is_nothrow_copy_constructible<allocator_type>::value)
2506
      :  // Hash, equality and allocator are copied instead of moved because
2507
         // `that` must be left valid. If Hash is std::function<Key>, moving it
2508
         // would create a nullptr functor that cannot be called.
2509
         // Note: we avoid using exchange for better generated code.
2510
        settings_(PolicyTraits::transfer_uses_memcpy() || !that.is_full_soo()
2511
                      ? std::move(that.common())
2512
                      : CommonFields{full_soo_tag_t{},
2513
                                     that.common().soo_has_tried_sampling()},
2514
                  that.hash_ref(), that.eq_ref(), that.char_alloc_ref()) {
2515
    if (!PolicyTraits::transfer_uses_memcpy() && that.is_full_soo()) {
2516
      transfer(soo_slot(), that.soo_slot());
2517
    }
2518
    that.common() = CommonFields::CreateDefault<SooEnabled()>();
2519
    annotate_for_bug_detection_on_move(that);
2520
  }
2521
2522
  raw_hash_set(raw_hash_set&& that, const allocator_type& a)
2523
      : settings_(CommonFields::CreateDefault<SooEnabled()>(), that.hash_ref(),
2524
                  that.eq_ref(), a) {
2525
    if (CharAlloc(a) == that.char_alloc_ref()) {
2526
      swap_common(that);
2527
      annotate_for_bug_detection_on_move(that);
2528
    } else {
2529
      move_elements_allocs_unequal(std::move(that));
2530
    }
2531
  }
2532
2533
  raw_hash_set& operator=(const raw_hash_set& that) {
2534
    that.AssertNotDebugCapacity();
2535
    if (ABSL_PREDICT_FALSE(this == &that)) return *this;
2536
    constexpr bool propagate_alloc =
2537
        AllocTraits::propagate_on_container_copy_assignment::value;
2538
    // TODO(ezb): maybe avoid allocating a new backing array if this->capacity()
2539
    // is an exact match for that.size(). If this->capacity() is too big, then
2540
    // it would make iteration very slow to reuse the allocation. Maybe we can
2541
    // do the same heuristic as clear() and reuse if it's small enough.
2542
    allocator_type alloc(propagate_alloc ? that.char_alloc_ref()
2543
                                         : char_alloc_ref());
2544
    raw_hash_set tmp(that, alloc);
2545
    // NOLINTNEXTLINE: not returning *this for performance.
2546
    return assign_impl<propagate_alloc>(std::move(tmp));
2547
  }
2548
2549
  raw_hash_set& operator=(raw_hash_set&& that) noexcept(
2550
      AllocTraits::is_always_equal::value &&
2551
      std::is_nothrow_move_assignable<hasher>::value &&
2552
      std::is_nothrow_move_assignable<key_equal>::value) {
2553
    // TODO(sbenza): We should only use the operations from the noexcept clause
2554
    // to make sure we actually adhere to that contract.
2555
    // NOLINTNEXTLINE: not returning *this for performance.
2556
    return move_assign(
2557
        std::move(that),
2558
        typename AllocTraits::propagate_on_container_move_assignment());
2559
  }
2560
2561
  ~raw_hash_set() {
2562
    destructor_impl();
2563
    if constexpr (SwisstableAssertAccessToDestroyedTable()) {
2564
      common().set_capacity(HashtableCapacity::CreateDestroyed());
2565
    }
2566
  }
2567
2568
  iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND {
2569
    if (ABSL_PREDICT_FALSE(empty())) return end();
2570
    if (is_small()) return single_iterator();
2571
    iterator it = {control(), common().slots_union(),
2572
                   common().generation_ptr()};
2573
    it.skip_empty_or_deleted();
2574
    ABSL_SWISSTABLE_ASSERT(IsFull(*it.control()));
2575
    return it;
2576
  }
2577
  iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND {
2578
    AssertNotDebugCapacity();
2579
    return iterator(common().generation_ptr());
2580
  }
2581
2582
  const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
2583
    return const_cast<raw_hash_set*>(this)->begin();
2584
  }
2585
  const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
2586
    return const_cast<raw_hash_set*>(this)->end();
2587
  }
2588
  const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
2589
    return begin();
2590
  }
2591
  const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return end(); }
2592
2593
  bool empty() const { return !size(); }
2594
  size_t size() const {
2595
    AssertNotDebugCapacity();
2596
    const size_t size = common().size();
2597
    [[maybe_unused]] const size_t kMaxValidSize = MaxValidSize();
2598
    ABSL_ASSUME(size <= kMaxValidSize);
2599
    return size;
2600
  }
2601
  size_t capacity() const {
2602
    const size_t cap = common().capacity();
2603
    // Compiler complains when using functions in ASSUME so use local variables.
2604
    [[maybe_unused]] const bool kIsValid = IsValidCapacity(cap);
2605
    [[maybe_unused]] const size_t kDefaultCapacity = DefaultCapacity();
2606
    [[maybe_unused]] const size_t kMaxValidCapacity = MaxValidCapacity();
2607
    ABSL_ASSUME(kIsValid || cap == 0);
2608
    ABSL_ASSUME(cap >= kDefaultCapacity);
2609
    ABSL_ASSUME(cap <= kMaxValidCapacity);
2610
    return cap;
2611
  }
2612
  size_t max_size() const { return MaxValidSize(); }
2613
2614
  ABSL_ATTRIBUTE_REINITIALIZES void clear() {
2615
    if (SwisstableGenerationsEnabled() &&
2616
        maybe_invalid_capacity().IsMovedFrom()) {
2617
      common().set_capacity(DefaultCapacity());
2618
    }
2619
    AssertNotDebugCapacity();
2620
    // Iterating over this container is O(bucket_count()). When bucket_count()
2621
    // is much greater than size(), iteration becomes prohibitively expensive.
2622
    // For clear() it is more important to reuse the allocated array when the
2623
    // container is small because allocation takes comparatively long time
2624
    // compared to destruction of the elements of the container. So we pick the
2625
    // largest bucket_count() threshold for which iteration is still fast and
2626
    // past that we simply deallocate the array.
2627
    const size_t cap = capacity();
2628
    if (cap == 0) {
2629
      // Already guaranteed to be empty; so nothing to do.
2630
    } else if (is_small()) {
2631
      if (!empty()) {
2632
        destroy(single_slot());
2633
        decrement_small_size();
2634
      }
2635
    } else {
2636
      destroy_slots();
2637
      clear_backing_array(/*reuse=*/cap < 128);
2638
    }
2639
    common().set_reserved_growth(0);
2640
    common().set_reservation_size(0);
2641
  }
2642
2643
  // This overload kicks in when the argument is an rvalue of insertable and
2644
  // decomposable type other than init_type.
2645
  //
2646
  //   flat_hash_map<std::string, int> m;
2647
  //   m.insert(std::make_pair("abc", 42));
2648
  template <class T,
2649
            int = std::enable_if_t<IsDecomposableAndInsertable<T>::value &&
2650
                                       IsNotBitField<T>::value &&
2651
                                       !IsLifetimeBoundAssignmentFrom<T>::value,
2652
                                   int>()>
2653
  std::pair<iterator, bool> insert(T&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
2654
    return emplace(std::forward<T>(value));
2655
  }
2656
2657
  template <class T, int&...,
2658
            std::enable_if_t<IsDecomposableAndInsertable<T>::value &&
2659
                                 IsNotBitField<T>::value &&
2660
                                 IsLifetimeBoundAssignmentFrom<T>::value,
2661
                             int> = 0>
2662
  std::pair<iterator, bool> insert(
2663
      T&& value ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
2664
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
2665
    return this->template insert<T, 0>(std::forward<T>(value));
2666
  }
2667
2668
  // This overload kicks in when the argument is a bitfield or an lvalue of
2669
  // insertable and decomposable type.
2670
  //
2671
  //   union { int n : 1; };
2672
  //   flat_hash_set<int> s;
2673
  //   s.insert(n);
2674
  //
2675
  //   flat_hash_set<std::string> s;
2676
  //   const char* p = "hello";
2677
  //   s.insert(p);
2678
  //
2679
  template <class T, int = std::enable_if_t<
2680
                         IsDecomposableAndInsertable<const T&>::value &&
2681
                             !IsLifetimeBoundAssignmentFrom<const T&>::value,
2682
                         int>()>
2683
  std::pair<iterator, bool> insert(const T& value)
2684
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
2685
    return emplace(value);
2686
  }
2687
  template <class T, int&...,
2688
            std::enable_if_t<IsDecomposableAndInsertable<const T&>::value &&
2689
                                 IsLifetimeBoundAssignmentFrom<const T&>::value,
2690
                             int> = 0>
2691
  std::pair<iterator, bool> insert(
2692
      const T& value ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
2693
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
2694
    return this->template insert<T, 0>(value);
2695
  }
2696
2697
  // This overload kicks in when the argument is an rvalue of init_type. Its
2698
  // purpose is to handle brace-init-list arguments.
2699
  //
2700
  //   flat_hash_map<std::string, int> s;
2701
  //   s.insert({"abc", 42});
2702
  std::pair<iterator, bool> insert(init_type&& value)
2703
      ABSL_ATTRIBUTE_LIFETIME_BOUND
2704
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
2705
    requires(!IsLifetimeBoundAssignmentFrom<init_type>::value)
2706
#endif
2707
  {
2708
    return emplace(std::move(value));
2709
  }
2710
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
2711
  std::pair<iterator, bool> insert(
2712
      init_type&& value ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
2713
      ABSL_ATTRIBUTE_LIFETIME_BOUND
2714
    requires(IsLifetimeBoundAssignmentFrom<init_type>::value)
2715
  {
2716
    return emplace(std::move(value));
2717
  }
2718
#endif
2719
2720
  template <class T,
2721
            int = std::enable_if_t<IsDecomposableAndInsertable<T>::value &&
2722
                                       IsNotBitField<T>::value &&
2723
                                       !IsLifetimeBoundAssignmentFrom<T>::value,
2724
                                   int>()>
2725
  iterator insert(const_iterator, T&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
2726
    return insert(std::forward<T>(value)).first;
2727
  }
2728
  template <class T, int&...,
2729
            std::enable_if_t<IsDecomposableAndInsertable<T>::value &&
2730
                                 IsNotBitField<T>::value &&
2731
                                 IsLifetimeBoundAssignmentFrom<T>::value,
2732
                             int> = 0>
2733
  iterator insert(const_iterator hint,
2734
                  T&& value ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
2735
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
2736
    return this->template insert<T, 0>(hint, std::forward<T>(value));
2737
  }
2738
2739
  template <class T, std::enable_if_t<
2740
                         IsDecomposableAndInsertable<const T&>::value, int> = 0>
2741
  iterator insert(const_iterator,
2742
                  const T& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
2743
    return insert(value).first;
2744
  }
2745
2746
  iterator insert(const_iterator,
2747
                  init_type&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
2748
    return insert(std::move(value)).first;
2749
  }
2750
2751
  template <class InputIt>
2752
  void insert(InputIt first, InputIt last) {
2753
    insert_range(first, last);
2754
  }
2755
2756
  template <class T, RequiresNotInit<T> = 0,
2757
            std::enable_if_t<Insertable<const T&>::value, int> = 0>
2758
  void insert(std::initializer_list<T> ilist) {
2759
    insert_range(ilist.begin(), ilist.end());
2760
  }
2761
2762
  void insert(std::initializer_list<init_type> ilist) {
2763
    insert_range(ilist.begin(), ilist.end());
2764
  }
2765
2766
  insert_return_type insert(node_type&& node) ABSL_ATTRIBUTE_LIFETIME_BOUND {
2767
    if (!node) return {end(), false, node_type()};
2768
    const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node));
2769
    auto res = PolicyTraits::apply(
2770
        InsertSlot<false>{*this, std::move(*CommonAccess::GetSlot(node))},
2771
        elem);
2772
    if (res.second) {
2773
      CommonAccess::Reset(&node);
2774
      return {res.first, true, node_type()};
2775
    } else {
2776
      return {res.first, false, std::move(node)};
2777
    }
2778
  }
2779
2780
  iterator insert(const_iterator,
2781
                  node_type&& node) ABSL_ATTRIBUTE_LIFETIME_BOUND {
2782
    auto res = insert(std::move(node));
2783
    node = std::move(res.node);
2784
    return res.position;
2785
  }
2786
2787
  // This overload kicks in if we can deduce the key from args. This enables us
2788
  // to avoid constructing value_type if an entry with the same key already
2789
  // exists.
2790
  //
2791
  // For example:
2792
  //
2793
  //   flat_hash_map<std::string, std::string> m = {{"abc", "def"}};
2794
  //   // Creates no std::string copies and makes no heap allocations.
2795
  //   m.emplace("abc", "xyz");
2796
  template <class... Args,
2797
            std::enable_if_t<IsDecomposable<Args...>::value, int> = 0>
2798
  std::pair<iterator, bool> emplace(Args&&... args)
2799
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
2800
    return PolicyTraits::apply(EmplaceDecomposable{*this},
2801
                               std::forward<Args>(args)...);
2802
  }
2803
2804
  // This overload kicks in if we cannot deduce the key from args. It constructs
2805
  // value_type unconditionally and then either moves it into the table or
2806
  // destroys.
2807
  template <class... Args,
2808
            std::enable_if_t<!IsDecomposable<Args...>::value, int> = 0>
2809
  std::pair<iterator, bool> emplace(Args&&... args)
2810
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
2811
    alignas(slot_type) unsigned char raw[sizeof(slot_type)];
2812
    slot_type* slot = to_slot(&raw);
2813
2814
    construct(slot, std::forward<Args>(args)...);
2815
    const auto& elem = PolicyTraits::element(slot);
2816
    return PolicyTraits::apply(InsertSlot<true>{*this, std::move(*slot)}, elem);
2817
  }
2818
2819
  template <class... Args>
2820
  iterator emplace_hint(const_iterator,
2821
                        Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
2822
    return emplace(std::forward<Args>(args)...).first;
2823
  }
2824
2825
  // Extension API: support for lazy emplace.
2826
  //
2827
  // Looks up key in the table. If found, returns the iterator to the element.
2828
  // Otherwise calls `f` with one argument of type `raw_hash_set::constructor`,
2829
  // and returns an iterator to the new element.
2830
  //
2831
  // `f` must abide by several restrictions:
2832
  //  - it MUST call `raw_hash_set::constructor` with arguments as if a
2833
  //    `raw_hash_set::value_type` is constructed,
2834
  //  - it MUST NOT access the container before the call to
2835
  //    `raw_hash_set::constructor`, and
2836
  //  - it MUST NOT erase the lazily emplaced element.
2837
  // Doing any of these is undefined behavior.
2838
  //
2839
  // For example:
2840
  //
2841
  //   std::unordered_set<ArenaString> s;
2842
  //   // Makes ArenaStr even if "abc" is in the map.
2843
  //   s.insert(ArenaString(&arena, "abc"));
2844
  //
2845
  //   flat_hash_set<ArenaStr> s;
2846
  //   // Makes ArenaStr only if "abc" is not in the map.
2847
  //   s.lazy_emplace("abc", [&](const constructor& ctor) {
2848
  //     ctor(&arena, "abc");
2849
  //   });
2850
  //
2851
  // WARNING: This API is currently experimental. If there is a way to implement
2852
  // the same thing with the rest of the API, prefer that.
2853
  class constructor {
2854
    friend class raw_hash_set;
2855
2856
   public:
2857
    template <class... Args>
2858
    void operator()(Args&&... args) const {
2859
      ABSL_SWISSTABLE_ASSERT(*slot_);
2860
      PolicyTraits::construct(alloc_, *slot_, std::forward<Args>(args)...);
2861
      *slot_ = nullptr;
2862
    }
2863
2864
   private:
2865
    constructor(allocator_type* a, slot_type** slot) : alloc_(a), slot_(slot) {}
2866
2867
    allocator_type* alloc_;
2868
    slot_type** slot_;
2869
  };
2870
2871
  template <class K = key_type, class F>
2872
  iterator lazy_emplace(const key_arg<K>& key,
2873
                        F&& f) ABSL_ATTRIBUTE_LIFETIME_BOUND {
2874
    auto res = find_or_prepare_insert(key);
2875
    if (res.second) {
2876
      slot_type* slot = res.first.slot();
2877
      allocator_type alloc(char_alloc_ref());
2878
      std::forward<F>(f)(constructor(&alloc, &slot));
2879
      ABSL_SWISSTABLE_ASSERT(!slot);
2880
    }
2881
    return res.first;
2882
  }
2883
2884
  // Extension API: support for heterogeneous keys.
2885
  //
2886
  //   std::unordered_set<std::string> s;
2887
  //   // Turns "abc" into std::string.
2888
  //   s.erase("abc");
2889
  //
2890
  //   flat_hash_set<std::string> s;
2891
  //   // Uses "abc" directly without copying it into std::string.
2892
  //   s.erase("abc");
2893
  template <class K = key_type>
2894
  size_type erase(const key_arg<K>& key) {
2895
    auto it = find(key);
2896
    if (it == end()) return 0;
2897
    erase(it);
2898
    return 1;
2899
  }
2900
2901
  // Erases the element pointed to by `it`. Unlike `std::unordered_set::erase`,
2902
  // this method returns void to reduce algorithmic complexity to O(1). The
2903
  // iterator is invalidated so any increment should be done before calling
2904
  // erase (e.g. `erase(it++)`).
2905
  void erase(const_iterator cit) { erase(cit.inner_); }
2906
2907
  // This overload is necessary because otherwise erase<K>(const K&) would be
2908
  // a better match if non-const iterator is passed as an argument.
2909
  void erase(iterator it) {
2910
    ABSL_SWISSTABLE_ASSERT(capacity() > 0);
2911
    AssertNotDebugCapacity();
2912
    it.assert_is_full("erase()");
2913
    destroy(it.slot());
2914
    erase_meta_only(it);
2915
  }
2916
2917
  iterator erase(const_iterator first,
2918
                 const_iterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND {
2919
    AssertNotDebugCapacity();
2920
    // We check for empty and for is_small because clear_backing_array requires
2921
    // that capacity() > MaxSmallCapacity() as a precondition.
2922
    if (empty()) return end();
2923
    if (first == last) return last.inner_;
2924
    if (is_small()) {
2925
      destroy(single_slot());
2926
      erase_meta_only_small();
2927
      return end();
2928
    }
2929
    if (first == begin() && last == end()) {
2930
      // TODO(ezb): we access control bytes in destroy_slots so it could make
2931
      // sense to combine destroy_slots and clear_backing_array to avoid cache
2932
      // misses when the table is large. Note that we also do this in clear().
2933
      destroy_slots();
2934
      clear_backing_array(/*reuse=*/true);
2935
      common().set_reserved_growth(common().reservation_size());
2936
      return end();
2937
    }
2938
    while (first != last) {
2939
      erase(first++);
2940
    }
2941
    return last.inner_;
2942
  }
2943
2944
  // Moves elements from `src` into `this`.
2945
  // If the element already exists in `this`, it is left unmodified in `src`.
2946
  template <
2947
      typename... Params2,
2948
      typename = std::enable_if_t<std::is_same_v<
2949
          Alloc, typename raw_hash_set<Policy, Params2...>::allocator_type>>>
2950
  void merge(raw_hash_set<Policy, Params2...>& src) {  // NOLINT
2951
    AssertNotDebugCapacity();
2952
    src.AssertNotDebugCapacity();
2953
    assert(this != &src);
2954
    // Returns whether insertion took place.
2955
    const auto insert_slot = [this](slot_type* src_slot) {
2956
      return PolicyTraits::apply(InsertSlot<false>{*this, std::move(*src_slot)},
2957
                                 PolicyTraits::element(src_slot))
2958
          .second;
2959
    };
2960
2961
    if (src.is_small()) {
2962
      if (src.empty()) return;
2963
      if (insert_slot(src.single_slot()))
2964
        src.erase_meta_only_small();
2965
      return;
2966
    }
2967
    for (auto it = src.begin(), e = src.end(); it != e;) {
2968
      auto next = std::next(it);
2969
      if (insert_slot(it.slot())) src.erase_meta_only_large(it);
2970
      it = next;
2971
    }
2972
  }
2973
2974
  template <
2975
      typename... Params2,
2976
      typename = std::enable_if_t<std::is_same_v<
2977
          Alloc, typename raw_hash_set<Policy, Params2...>::allocator_type>>>
2978
  void merge(raw_hash_set<Policy, Params2...>&& src) {  // NOLINT
2979
    merge(src);
2980
  }
2981
2982
  node_type extract(const_iterator position) {
2983
    AssertNotDebugCapacity();
2984
    position.inner_.assert_is_full("extract()");
2985
    allocator_type alloc(char_alloc_ref());
2986
    auto node = CommonAccess::Transfer<node_type>(alloc, position.slot());
2987
    erase_meta_only(position);
2988
    return node;
2989
  }
2990
2991
  template <class K = key_type,
2992
            std::enable_if_t<!std::is_same<K, iterator>::value, int> = 0>
2993
  node_type extract(const key_arg<K>& key) {
2994
    auto it = find(key);
2995
    return it == end() ? node_type() : extract(const_iterator{it});
2996
  }
2997
2998
  void swap(raw_hash_set& that) noexcept(
2999
      AllocTraits::is_always_equal::value &&
3000
      std::is_nothrow_swappable<hasher>::value &&
3001
      std::is_nothrow_swappable<key_equal>::value) {
3002
    AssertNotDebugCapacity();
3003
    that.AssertNotDebugCapacity();
3004
    using std::swap;
3005
    swap_common(that);
3006
    swap(hash_ref(), that.hash_ref());
3007
    swap(eq_ref(), that.eq_ref());
3008
    SwapAlloc(char_alloc_ref(), that.char_alloc_ref(),
3009
              typename AllocTraits::propagate_on_container_swap{});
3010
  }
3011
3012
  void rehash(size_t n) {
3013
    Rehash(common(), GetPolicyFunctions(), (std::min)(n, MaxValidCapacity()));
3014
  }
3015
3016
  void reserve(size_t n) {
3017
    if (ABSL_PREDICT_TRUE(n > DefaultCapacity())) {
3018
      ReserveTableToFitNewSize(common(), GetPolicyFunctions(),
3019
                               (std::min)(n, MaxValidSize()));
3020
    }
3021
  }
3022
3023
  // Extension API: support for heterogeneous keys.
3024
  //
3025
  //   std::unordered_set<std::string> s;
3026
  //   // Turns "abc" into std::string.
3027
  //   s.count("abc");
3028
  //
3029
  //   ch_set<std::string> s;
3030
  //   // Uses "abc" directly without copying it into std::string.
3031
  //   s.count("abc");
3032
  template <class K = key_type>
3033
  size_t count(const key_arg<K>& key) const {
3034
    return find(key) == end() ? 0 : 1;
3035
  }
3036
3037
  // Issues CPU prefetch instructions for the memory needed to find or insert
3038
  // a key.  Like all lookup functions, this support heterogeneous keys.
3039
  //
3040
  // NOTE: This is a very low level operation and should not be used without
3041
  // specific benchmarks indicating its importance.
3042
  template <class K = key_type>
3043
  void prefetch([[maybe_unused]] const key_arg<K>& key) const {
3044
    if (capacity() == DefaultCapacity()) return;
3045
    // Avoid probing if we won't be able to prefetch the addresses received.
3046
#ifdef ABSL_HAVE_PREFETCH
3047
    prefetch_heap_block();
3048
    if (is_small()) return;
3049
    auto seq = probe(common(), hash_of(key));
3050
    PrefetchToLocalCache(control() + seq.offset());
3051
    PrefetchToLocalCache(slot_array() + seq.offset());
3052
#endif  // ABSL_HAVE_PREFETCH
3053
  }
3054
3055
  template <class K = key_type>
3056
  ABSL_DEPRECATE_AND_INLINE()
3057
  iterator find(const key_arg<K>& key,
3058
                size_t) ABSL_ATTRIBUTE_LIFETIME_BOUND {
3059
    return find(key);
3060
  }
3061
  // The API of find() has one extension: the type of the key argument doesn't
3062
  // have to be key_type. This is so called heterogeneous key support.
3063
  template <class K = key_type>
3064
  iterator find(const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
3065
    AssertOnFind(key);
3066
    if (is_small()) return find_small(key);
3067
    prefetch_heap_block();
3068
    return find_large(key, hash_of(key));
3069
  }
3070
3071
  template <class K = key_type>
3072
  ABSL_DEPRECATE_AND_INLINE()
3073
  const_iterator find(const key_arg<K>& key,
3074
                      size_t) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
3075
    return find(key);
3076
  }
3077
  template <class K = key_type>
3078
  const_iterator find(const key_arg<K>& key) const
3079
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
3080
    return const_cast<raw_hash_set*>(this)->find(key);
3081
  }
3082
3083
  template <class K = key_type>
3084
  bool contains(const key_arg<K>& key) const {
3085
    // Here neither the iterator returned by `find()` nor `end()` can be invalid
3086
    // outside of potential thread-safety issues.
3087
    // `find()`'s return value is constructed, used, and then destructed
3088
    // all in this context.
3089
    return !find(key).unchecked_equals(end());
3090
  }
3091
3092
  template <class K = key_type>
3093
  std::pair<iterator, iterator> equal_range(const key_arg<K>& key)
3094
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
3095
    auto it = find(key);
3096
    if (it != end()) return {it, std::next(it)};
3097
    return {it, it};
3098
  }
3099
  template <class K = key_type>
3100
  std::pair<const_iterator, const_iterator> equal_range(
3101
      const key_arg<K>& key) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
3102
    auto it = find(key);
3103
    if (it != end()) return {it, std::next(it)};
3104
    return {it, it};
3105
  }
3106
3107
  size_t bucket_count() const { return capacity(); }
3108
  float load_factor() const {
3109
    return capacity() ? static_cast<double>(size()) / capacity() : 0.0;
3110
  }
3111
  float max_load_factor() const { return 1.0f; }
3112
  void max_load_factor(float) {
3113
    // Does nothing.
3114
  }
3115
3116
  hasher hash_function() const { return hash_ref(); }
3117
  key_equal key_eq() const { return eq_ref(); }
3118
  allocator_type get_allocator() const {
3119
    return allocator_type(char_alloc_ref());
3120
  }
3121
3122
  friend bool operator==(const raw_hash_set& a, const raw_hash_set& b) {
3123
    if (a.size() != b.size()) return false;
3124
    const raw_hash_set* outer = &a;
3125
    const raw_hash_set* inner = &b;
3126
    if (outer->capacity() > inner->capacity()) std::swap(outer, inner);
3127
    for (const value_type& elem : *outer) {
3128
      auto it = PolicyTraits::apply(FindElement{*inner}, elem);
3129
      if (it == inner->end()) return false;
3130
      // Note: we used key_equal to check for key equality in FindElement, but
3131
      // we may need to do an additional comparison using
3132
      // value_type::operator==. E.g. the keys could be equal and the
3133
      // mapped_types could be unequal in a map or even in a set, key_equal
3134
      // could ignore some fields that aren't ignored by operator==.
3135
      static constexpr bool kKeyEqIsValueEq =
3136
          std::is_same<key_type, value_type>::value &&
3137
          std::is_same<key_equal, hash_default_eq<key_type>>::value;
3138
      if (!kKeyEqIsValueEq && !(*it == elem)) return false;
3139
    }
3140
    return true;
3141
  }
3142
3143
  friend bool operator!=(const raw_hash_set& a, const raw_hash_set& b) {
3144
    return !(a == b);
3145
  }
3146
3147
  template <typename H>
3148
  friend typename std::enable_if<H::template is_hashable<value_type>::value,
3149
                                 H>::type
3150
  AbslHashValue(H h, const raw_hash_set& s) {
3151
    return H::combine(H::combine_unordered(std::move(h), s.begin(), s.end()),
3152
                      hash_internal::WeaklyMixedInteger{s.size()});
3153
  }
3154
3155
  friend void swap(raw_hash_set& a,
3156
                   raw_hash_set& b) noexcept(noexcept(a.swap(b))) {
3157
    a.swap(b);
3158
  }
3159
3160
 private:
3161
  template <class Container, typename Enabler>
3162
  friend struct absl::container_internal::hashtable_debug_internal::
3163
      HashtableDebugAccess;
3164
3165
  friend struct absl::container_internal::HashtableFreeFunctionsAccess;
3166
3167
  struct FindElement {
3168
    template <class K, class... Args>
3169
    const_iterator operator()(const K& key, Args&&...) const {
3170
      return s.find(key);
3171
    }
3172
    const raw_hash_set& s;
3173
  };
3174
3175
  struct EmplaceDecomposable {
3176
    template <class K, class... Args>
3177
    std::pair<iterator, bool> operator()(const K& key, Args&&... args) const {
3178
      auto res = s.find_or_prepare_insert(key);
3179
      if (res.second) {
3180
        s.emplace_at(res.first, std::forward<Args>(args)...);
3181
      }
3182
      return res;
3183
    }
3184
    raw_hash_set& s;
3185
  };
3186
3187
  template <bool do_destroy>
3188
  struct InsertSlot {
3189
    template <class K, class... Args>
3190
    std::pair<iterator, bool> operator()(const K& key, Args&&...) && {
3191
      auto res = s.find_or_prepare_insert(key);
3192
      if (res.second) {
3193
        s.transfer(res.first.slot(), &slot);
3194
      } else if (do_destroy) {
3195
        s.destroy(&slot);
3196
      }
3197
      return res;
3198
    }
3199
    raw_hash_set& s;
3200
    // Constructed slot. Either moved into place or destroyed.
3201
    slot_type&& slot;
3202
  };
3203
3204
  template <typename... Args>
3205
  inline void construct(slot_type* slot, Args&&... args) {
3206
    common().RunWithReentrancyGuard([&] {
3207
      allocator_type alloc(char_alloc_ref());
3208
      PolicyTraits::construct(&alloc, slot, std::forward<Args>(args)...);
3209
    });
3210
  }
3211
  inline void destroy(slot_type* slot) {
3212
    common().RunWithReentrancyGuard([&] {
3213
      allocator_type alloc(char_alloc_ref());
3214
      PolicyTraits::destroy(&alloc, slot);
3215
    });
3216
  }
3217
  inline void transfer(slot_type* to, slot_type* from) {
3218
    common().RunWithReentrancyGuard([&] {
3219
      allocator_type alloc(char_alloc_ref());
3220
      PolicyTraits::transfer(&alloc, to, from);
3221
    });
3222
  }
3223
3224
  // TODO(b/289225379): consider having a helper class that has the impls for
3225
  // SOO functionality.
3226
  template <class K = key_type>
3227
  iterator find_small(const key_arg<K>& key) {
3228
    ABSL_SWISSTABLE_ASSERT(is_small());
3229
    return empty() || !equal_to(key, single_slot()) ? end() : single_iterator();
3230
  }
3231
3232
  template <class K = key_type>
3233
  iterator find_large(const key_arg<K>& key, size_t hash) {
3234
    ABSL_SWISSTABLE_ASSERT(!is_small());
3235
    auto seq = probe(common(), hash);
3236
    const h2_t h2 = H2(hash);
3237
    const ctrl_t* ctrl = control();
3238
    while (true) {
3239
#ifndef ABSL_HAVE_MEMORY_SANITIZER
3240
      absl::PrefetchToLocalCache(slot_array() + seq.offset());
3241
#endif
3242
      Group g{ctrl + seq.offset()};
3243
      for (uint32_t i : g.Match(h2)) {
3244
        if (ABSL_PREDICT_TRUE(equal_to(key, slot_array() + seq.offset(i))))
3245
          return iterator_at(seq.offset(i));
3246
      }
3247
      if (ABSL_PREDICT_TRUE(g.MaskEmpty())) return end();
3248
      seq.next();
3249
      ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity() && "full table!");
3250
    }
3251
  }
3252
3253
  // Returns true if the table needs to be sampled. This keeps track of whether
3254
  // sampling has already been evaluated and ensures that it can only return
3255
  // true on its first evaluation. All subsequent calls will return false.
3256
  //
3257
  // This should be called on insertion into an empty SOO table and in copy
3258
  // construction when the size can fit in SOO capacity.
3259
  bool should_sample_soo() {
3260
    ABSL_SWISSTABLE_ASSERT(is_soo());
3261
    if constexpr (!ShouldSampleHashtablezInfoForAlloc<CharAlloc>()) {
3262
      return false;
3263
    }
3264
    if (common().soo_has_tried_sampling()) {
3265
      // Already evaluated sampling on this SOO table; do not re-evaluate
3266
      // sampling each time it transitions from empty to full SOO state.
3267
      return false;
3268
    }
3269
    // TODO: b/396049910 -- consider managing this flag on the 1->0 size
3270
    // transition of SOO tables rather than the 0->1 transition.
3271
    common().set_soo_has_tried_sampling();
3272
    return ABSL_PREDICT_FALSE(ShouldSampleNextTable());
3273
  }
3274
3275
  void clear_backing_array(bool reuse) {
3276
    ABSL_SWISSTABLE_ASSERT(capacity() > MaxSmallCapacity());
3277
    ClearBackingArray(common(), GetPolicyFunctions(), &char_alloc_ref(), reuse);
3278
  }
3279
3280
  void destroy_slots() {
3281
    ABSL_SWISSTABLE_ASSERT(!is_small());
3282
    if (PolicyTraits::template destroy_is_trivial<Alloc>()) return;
3283
    auto destroy_slot = [&](const ctrl_t*, void* slot) {
3284
      this->destroy(static_cast<slot_type*>(slot));
3285
    };
3286
    if constexpr (SwisstableAssertAccessToDestroyedTable()) {
3287
      CommonFields common_copy(non_soo_tag_t{}, this->common());
3288
      common().set_capacity(HashtableCapacity::CreateDestroyed());
3289
      IterateOverFullSlots(common_copy, sizeof(slot_type), destroy_slot);
3290
      common().set_capacity(common_copy.capacity());
3291
    } else {
3292
      IterateOverFullSlots(common(), sizeof(slot_type), destroy_slot);
3293
    }
3294
  }
3295
3296
  void dealloc() {
3297
    ABSL_SWISSTABLE_ASSERT(capacity() > DefaultCapacity());
3298
    // Unpoison before returning the memory to the allocator.
3299
    SanitizerUnpoisonMemoryRegion(slot_array(), sizeof(slot_type) * capacity());
3300
    infoz().Unregister();
3301
    DeallocateBackingArray<BackingArrayAlignment(alignof(slot_type)),
3302
                           CharAlloc>(&char_alloc_ref(), capacity(), control(),
3303
                                      sizeof(slot_type), alignof(slot_type),
3304
                                      common().has_infoz());
3305
  }
3306
3307
  void destructor_impl() {
3308
    if (SwisstableGenerationsEnabled() &&
3309
        maybe_invalid_capacity().IsMovedFrom()) {
3310
      return;
3311
    }
3312
    if (capacity() == 0) return;
3313
    if (is_small()) {
3314
      if (!empty()) {
3315
        ABSL_SWISSTABLE_IGNORE_UNINITIALIZED(destroy(single_slot()));
3316
      }
3317
      if constexpr (SooEnabled()) return;
3318
    } else {
3319
      destroy_slots();
3320
    }
3321
    dealloc();
3322
  }
3323
3324
  // Erases, but does not destroy, the value pointed to by `it`.
3325
  //
3326
  // This merely updates the pertinent control byte. This can be used in
3327
  // conjunction with Policy::transfer to move the object to another place.
3328
  void erase_meta_only(const_iterator it) {
3329
    if (is_small()) {
3330
      erase_meta_only_small();
3331
      return;
3332
    }
3333
    erase_meta_only_large(it);
3334
  }
3335
  void erase_meta_only_small() {
3336
    EraseMetaOnlySmall(common(), SooEnabled(), sizeof(slot_type));
3337
  }
3338
  void erase_meta_only_large(const_iterator it) {
3339
    EraseMetaOnlyLarge(common(), it.control(), sizeof(slot_type));
3340
  }
3341
3342
  template <class K>
3343
  ABSL_ATTRIBUTE_ALWAYS_INLINE bool equal_to(const K& key,
3344
                                             slot_type* slot) const {
3345
    return PolicyTraits::apply(EqualElement<K, key_equal>{key, eq_ref()},
3346
                               PolicyTraits::element(slot));
3347
  }
3348
  template <class K>
3349
  ABSL_ATTRIBUTE_ALWAYS_INLINE size_t hash_of(const K& key) const {
3350
    return HashElement<hasher, kIsDefaultHash>{hash_ref(),
3351
                                               common().seed().seed()}(key);
3352
  }
3353
  ABSL_ATTRIBUTE_ALWAYS_INLINE size_t hash_of(slot_type* slot) const {
3354
    return PolicyTraits::apply(
3355
        HashElement<hasher, kIsDefaultHash>{hash_ref(), common().seed().seed()},
3356
        PolicyTraits::element(slot));
3357
  }
3358
3359
  // Casting directly from e.g. char* to slot_type* can cause compilation errors
3360
  // on objective-C. This function converts to void* first, avoiding the issue.
3361
  static ABSL_ATTRIBUTE_ALWAYS_INLINE slot_type* to_slot(void* buf) {
3362
    return static_cast<slot_type*>(buf);
3363
  }
3364
3365
  // Requires that lhs does not have a full SOO slot.
3366
  static void move_common(bool rhs_is_full_soo, CharAlloc& rhs_alloc,
3367
                          CommonFields& lhs, CommonFields&& rhs) {
3368
    if (PolicyTraits::transfer_uses_memcpy() || !rhs_is_full_soo) {
3369
      lhs = std::move(rhs);
3370
    } else {
3371
      lhs.move_non_heap_or_soo_fields(rhs);
3372
      rhs.RunWithReentrancyGuard([&] {
3373
        lhs.RunWithReentrancyGuard([&] {
3374
          PolicyTraits::transfer(&rhs_alloc, to_slot(lhs.soo_data()),
3375
                                 to_slot(rhs.soo_data()));
3376
        });
3377
      });
3378
    }
3379
  }
3380
3381
  // Swaps common fields making sure to avoid memcpy'ing a full SOO slot if we
3382
  // aren't allowed to do so.
3383
  void swap_common(raw_hash_set& that) {
3384
    using std::swap;
3385
    if (PolicyTraits::transfer_uses_memcpy()) {
3386
      swap(common(), that.common());
3387
      return;
3388
    }
3389
    CommonFields tmp = CommonFields(uninitialized_tag_t{});
3390
    const bool that_is_full_soo = that.is_full_soo();
3391
    move_common(that_is_full_soo, that.char_alloc_ref(), tmp,
3392
                std::move(that.common()));
3393
    move_common(is_full_soo(), char_alloc_ref(), that.common(),
3394
                std::move(common()));
3395
    move_common(that_is_full_soo, that.char_alloc_ref(), common(),
3396
                std::move(tmp));
3397
  }
3398
3399
  void annotate_for_bug_detection_on_move([[maybe_unused]] raw_hash_set& that) {
3400
    // We only enable moved-from validation when generations are enabled (rather
3401
    // than using NDEBUG) to avoid issues in which NDEBUG is enabled in some
3402
    // translation units but not in others.
3403
    if (SwisstableGenerationsEnabled()) {
3404
      that.common().set_capacity(this == &that
3405
                                     ? HashtableCapacity::CreateSelfMovedFrom()
3406
                                     : HashtableCapacity::CreateMovedFrom());
3407
    }
3408
    if (!SwisstableGenerationsEnabled() ||
3409
        !maybe_invalid_capacity().IsValid() ||
3410
        capacity() == DefaultCapacity()) {
3411
      return;
3412
    }
3413
    common().increment_generation();
3414
    if (!empty() && common().should_rehash_for_bug_detection_on_move()) {
3415
      ResizeAllocatedTableWithSeedChange(common(), GetPolicyFunctions(),
3416
                                         capacity());
3417
    }
3418
  }
3419
3420
  template <bool propagate_alloc>
3421
  raw_hash_set& assign_impl(raw_hash_set&& that) {
3422
    // We don't bother checking for this/that aliasing. We just need to avoid
3423
    // breaking the invariants in that case.
3424
    destructor_impl();
3425
    move_common(that.is_full_soo(), that.char_alloc_ref(), common(),
3426
                std::move(that.common()));
3427
    hash_ref() = that.hash_ref();
3428
    eq_ref() = that.eq_ref();
3429
    CopyAlloc(char_alloc_ref(), that.char_alloc_ref(),
3430
              std::integral_constant<bool, propagate_alloc>());
3431
    that.common() = CommonFields::CreateDefault<SooEnabled()>();
3432
    annotate_for_bug_detection_on_move(that);
3433
    return *this;
3434
  }
3435
3436
  raw_hash_set& move_elements_allocs_unequal(raw_hash_set&& that) {
3437
    const size_t size = that.size();
3438
    if (size == 0) return *this;
3439
    reserve(size);
3440
    for (iterator it = that.begin(); it != that.end(); ++it) {
3441
      insert(std::move(PolicyTraits::element(it.slot())));
3442
      that.destroy(it.slot());
3443
    }
3444
    if (!that.is_soo()) that.dealloc();
3445
    that.common() = CommonFields::CreateDefault<SooEnabled()>();
3446
    annotate_for_bug_detection_on_move(that);
3447
    return *this;
3448
  }
3449
3450
  raw_hash_set& move_assign(raw_hash_set&& that,
3451
                            std::true_type /*propagate_alloc*/) {
3452
    return assign_impl<true>(std::move(that));
3453
  }
3454
  raw_hash_set& move_assign(raw_hash_set&& that,
3455
                            std::false_type /*propagate_alloc*/) {
3456
    if (char_alloc_ref() == that.char_alloc_ref()) {
3457
      return assign_impl<false>(std::move(that));
3458
    }
3459
    // Aliasing can't happen here because allocs would compare equal above.
3460
    assert(this != &that);
3461
    destructor_impl();
3462
    // We can't take over that's memory so we need to move each element.
3463
    // While moving elements, this should have that's hash/eq so copy hash/eq
3464
    // before moving elements.
3465
    hash_ref() = that.hash_ref();
3466
    eq_ref() = that.eq_ref();
3467
    return move_elements_allocs_unequal(std::move(that));
3468
  }
3469
3470
  template <class K>
3471
  std::pair<iterator, bool> find_or_prepare_insert_soo(const K& key) {
3472
    ABSL_SWISSTABLE_ASSERT(is_soo());
3473
    bool force_sampling;
3474
    if (empty()) {
3475
      if (!should_sample_soo()) {
3476
        common().set_full_soo();
3477
        return {single_iterator(), true};
3478
      }
3479
      force_sampling = true;
3480
    } else if (equal_to(key, single_slot())) {
3481
      return {single_iterator(), false};
3482
    } else {
3483
      force_sampling = false;
3484
    }
3485
    ABSL_SWISSTABLE_ASSERT(capacity() == 1);
3486
    constexpr bool kUseMemcpy =
3487
        PolicyTraits::transfer_uses_memcpy() && SooEnabled();
3488
    size_t index = GrowSooTableToNextCapacityAndPrepareInsert<
3489
        kUseMemcpy ? OptimalMemcpySizeForSooSlotTransfer(sizeof(slot_type)) : 0,
3490
        kUseMemcpy>(common(), GetPolicyFunctions(),
3491
                    HashKey<hasher, K, kIsDefaultHash>{hash_ref(), key},
3492
                    force_sampling);
3493
    return {iterator_at(index), true};
3494
  }
3495
3496
  template <class K>
3497
  std::pair<iterator, bool> find_or_prepare_insert_small(const K& key) {
3498
    ABSL_SWISSTABLE_ASSERT(is_small());
3499
    if constexpr (SooEnabled()) {
3500
      return find_or_prepare_insert_soo(key);
3501
    }
3502
    if (!empty()) {
3503
      if (equal_to(key, single_slot())) {
3504
        return {single_iterator(), false};
3505
      }
3506
    }
3507
    return {iterator_at_ptr(PrepareInsertSmallNonSoo(
3508
                common(), GetPolicyFunctions(),
3509
                HashKey<hasher, K, kIsDefaultHash>{hash_ref(), key})),
3510
            true};
3511
  }
3512
3513
  template <class K>
3514
  std::pair<iterator, bool> find_or_prepare_insert_large(const K& key) {
3515
    ABSL_SWISSTABLE_ASSERT(!is_soo());
3516
    prefetch_heap_block();
3517
    const size_t hash = hash_of(key);
3518
    auto seq = probe(common(), hash);
3519
    const h2_t h2 = H2(hash);
3520
    const ctrl_t* ctrl = control();
3521
    size_t index;
3522
    bool inserted;
3523
    // We use a lambda function to be able to exit from the nested loop without
3524
    // duplicating generated code for the return statement (e.g. iterator_at).
3525
    [&]() ABSL_ATTRIBUTE_ALWAYS_INLINE {
3526
      while (true) {
3527
#ifndef ABSL_HAVE_MEMORY_SANITIZER
3528
        absl::PrefetchToLocalCache(slot_array() + seq.offset());
3529
#endif
3530
        Group g{ctrl + seq.offset()};
3531
        for (uint32_t i : g.Match(h2)) {
3532
          if (ABSL_PREDICT_TRUE(equal_to(key, slot_array() + seq.offset(i)))) {
3533
            index = seq.offset(i);
3534
            inserted = false;
3535
            return;
3536
          }
3537
        }
3538
        auto mask_empty = g.MaskEmpty();
3539
        if (ABSL_PREDICT_TRUE(mask_empty)) {
3540
          size_t target_group_offset = seq.offset();
3541
          index = SwisstableGenerationsEnabled()
3542
                      ? PrepareInsertLargeGenerationsEnabled(
3543
                            common(), GetPolicyFunctions(), hash, mask_empty,
3544
                            FindInfo{target_group_offset, seq.index()},
3545
                            HashKey<hasher, K, kIsDefaultHash>{hash_ref(), key})
3546
                      : PrepareInsertLarge(
3547
                            common(), GetPolicyFunctions(), hash, mask_empty,
3548
                            FindInfo{target_group_offset, seq.index()});
3549
          inserted = true;
3550
          return;
3551
        }
3552
        seq.next();
3553
        ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity() && "full table!");
3554
      }
3555
    }();
3556
    return {iterator_at(index), inserted};
3557
  }
3558
3559
  template <class InputIt>
3560
  void insert_range(InputIt first, InputIt last) {
3561
    for (; first != last; ++first) emplace(*first);
3562
  }
3563
3564
 protected:
3565
  // Asserts for correctness that we run on find/find_or_prepare_insert.
3566
  template <class K>
3567
  void AssertOnFind([[maybe_unused]] const K& key) {
3568
    AssertHashEqConsistent(key);
3569
    AssertNotDebugCapacity();
3570
  }
3571
3572
  // Asserts that the capacity is not a sentinel invalid value.
3573
  void AssertNotDebugCapacity() const {
3574
#ifdef NDEBUG
3575
    if (!SwisstableGenerationsEnabled()) {
3576
      return;
3577
    }
3578
#endif
3579
    const HashtableCapacity cap = maybe_invalid_capacity();
3580
    if (ABSL_PREDICT_TRUE(cap.IsValid())) {
3581
      return;
3582
    }
3583
    assert(!cap.IsReentrance() &&
3584
           "Reentrant container access during element construction/destruction "
3585
           "is not allowed.");
3586
    if constexpr (SwisstableAssertAccessToDestroyedTable()) {
3587
      if (cap.IsDestroyed()) {
3588
        ABSL_RAW_LOG(FATAL, "Use of destroyed hash table.");
3589
      }
3590
    }
3591
    if (SwisstableGenerationsEnabled() &&
3592
        ABSL_PREDICT_FALSE(cap.IsMovedFrom())) {
3593
      if (cap.IsSelfMovedFrom()) {
3594
        // If this log triggers, then a hash table was move-assigned to itself
3595
        // and then used again later without being reinitialized.
3596
        ABSL_RAW_LOG(FATAL, "Use of self-move-assigned hash table.");
3597
      }
3598
      ABSL_RAW_LOG(FATAL, "Use of moved-from hash table.");
3599
    }
3600
  }
3601
3602
  // Asserts that hash and equal functors provided by the user are consistent,
3603
  // meaning that `eq(k1, k2)` implies `hash(k1)==hash(k2)`.
3604
  template <class K>
3605
  void AssertHashEqConsistent(const K& key) {
3606
#ifdef NDEBUG
3607
    return;
3608
#endif
3609
    // If the hash/eq functors are known to be consistent, then skip validation.
3610
    if (std::is_same<hasher, absl::container_internal::StringHash>::value &&
3611
        std::is_same<key_equal, absl::container_internal::StringEq>::value) {
3612
      return;
3613
    }
3614
    if (std::is_scalar<key_type>::value &&
3615
        std::is_same<hasher, absl::Hash<key_type>>::value &&
3616
        std::is_same<key_equal, std::equal_to<key_type>>::value) {
3617
      return;
3618
    }
3619
    if (empty()) return;
3620
3621
    const size_t hash_of_arg = hash_of(key);
3622
    const auto assert_consistent = [&](const ctrl_t*, void* slot) {
3623
      const bool is_key_equal = equal_to(key, to_slot(slot));
3624
      if (!is_key_equal) return;
3625
3626
      [[maybe_unused]] const bool is_hash_equal =
3627
          hash_of_arg == hash_of(to_slot(slot));
3628
      assert((!is_key_equal || is_hash_equal) &&
3629
             "eq(k1, k2) must imply that hash(k1) == hash(k2). "
3630
             "hash/eq functors are inconsistent.");
3631
    };
3632
3633
    if (is_small()) {
3634
      assert_consistent(/*unused*/ nullptr, single_slot());
3635
      return;
3636
    }
3637
    // We only do validation for small tables so that it's constant time.
3638
    if (capacity() > 16) return;
3639
    IterateOverFullSlots(common(), sizeof(slot_type), assert_consistent);
3640
  }
3641
3642
  // Attempts to find `key` in the table; if it isn't found, returns an iterator
3643
  // where the value can be inserted into, with the control byte already set to
3644
  // `key`'s H2. Returns a bool indicating whether an insertion can take place.
3645
  template <class K>
3646
  std::pair<iterator, bool> find_or_prepare_insert(const K& key) {
3647
    AssertOnFind(key);
3648
    if (is_small()) return find_or_prepare_insert_small(key);
3649
    return find_or_prepare_insert_large(key);
3650
  }
3651
3652
  // Constructs the value in the space pointed by the iterator. This only works
3653
  // after an unsuccessful find_or_prepare_insert() and before any other
3654
  // modifications happen in the raw_hash_set.
3655
  //
3656
  // PRECONDITION: iter was returned from find_or_prepare_insert(k), where k is
3657
  // the key decomposed from `forward<Args>(args)...`, and the bool returned by
3658
  // find_or_prepare_insert(k) was true.
3659
  // POSTCONDITION: *m.iterator_at(i) == value_type(forward<Args>(args)...).
3660
  template <class... Args>
3661
  void emplace_at(iterator iter, Args&&... args) {
3662
    construct(iter.slot(), std::forward<Args>(args)...);
3663
3664
    // When is_small, find calls find_small and if size is 0, then it will
3665
    // return an end iterator. This can happen in the raw_hash_set copy ctor.
3666
    assert((is_small() ||
3667
            PolicyTraits::apply(FindElement{*this}, *iter) == iter) &&
3668
           "constructed value does not match the lookup key");
3669
  }
3670
3671
  iterator iterator_at(size_t i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
3672
    return {control() + i, slot_array() + i, common().generation_ptr()};
3673
  }
3674
  const_iterator iterator_at(size_t i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
3675
    return const_cast<raw_hash_set*>(this)->iterator_at(i);
3676
  }
3677
  iterator iterator_at_ptr(std::pair<ctrl_t*, void*> ptrs)
3678
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
3679
    return {ptrs.first, to_slot(ptrs.second), common().generation_ptr()};
3680
  }
3681
3682
  reference unchecked_deref(iterator it) { return it.unchecked_deref(); }
3683
3684
 private:
3685
  friend struct RawHashSetTestOnlyAccess;
3686
3687
  // The number of slots we can still fill without needing to rehash.
3688
  //
3689
  // This is stored separately due to tombstones: we do not include tombstones
3690
  // in the growth capacity, because we'd like to rehash when the table is
3691
  // otherwise filled with tombstones: otherwise, probe sequences might get
3692
  // unacceptably long without triggering a rehash. Callers can also force a
3693
  // rehash via the standard `rehash(0)`, which will recompute this value as a
3694
  // side-effect.
3695
  //
3696
  // See `CapacityToGrowth()`.
3697
  size_t growth_left() const {
3698
    return common().growth_left();
3699
  }
3700
3701
  GrowthInfo& growth_info() {
3702
    return common().growth_info();
3703
  }
3704
  GrowthInfo growth_info() const {
3705
    return common().growth_info();
3706
  }
3707
3708
  // Prefetch the heap-allocated memory region to resolve potential TLB and
3709
  // cache misses. This is intended to overlap with execution of calculating the
3710
  // hash for a key.
3711
  void prefetch_heap_block() const {
3712
    ABSL_SWISSTABLE_ASSERT(!is_soo());
3713
#if ABSL_HAVE_BUILTIN(__builtin_prefetch) || defined(__GNUC__)
3714
    __builtin_prefetch(control(), 0, 1);
3715
#endif
3716
  }
3717
3718
  CommonFields& common() { return settings_.template get<0>(); }
3719
  const CommonFields& common() const { return settings_.template get<0>(); }
3720
3721
  // For use when the capacity is potentially invalid we return
3722
  // HashtableCapacity directly.
3723
  HashtableCapacity maybe_invalid_capacity() const {
3724
    return common().maybe_invalid_capacity();
3725
  }
3726
  ctrl_t* control() const {
3727
    ABSL_SWISSTABLE_ASSERT(!is_soo());
3728
    return common().control();
3729
  }
3730
  slot_type* slot_array() const {
3731
    ABSL_SWISSTABLE_ASSERT(!is_soo());
3732
    return static_cast<slot_type*>(common().slot_array());
3733
  }
3734
  slot_type* soo_slot() {
3735
    ABSL_SWISSTABLE_ASSERT(is_soo());
3736
    ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(
3737
        static_cast<slot_type*>(common().soo_data()));
3738
  }
3739
  const slot_type* soo_slot() const {
3740
    ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(
3741
        const_cast<raw_hash_set*>(this)->soo_slot());
3742
  }
3743
  slot_type* single_slot() {
3744
    ABSL_SWISSTABLE_ASSERT(is_small());
3745
    return SooEnabled() ? soo_slot() : slot_array();
3746
  }
3747
  const slot_type* single_slot() const {
3748
    return const_cast<raw_hash_set*>(this)->single_slot();
3749
  }
3750
  void decrement_small_size() {
3751
    ABSL_SWISSTABLE_ASSERT(is_small());
3752
    SooEnabled() ? common().set_empty_soo() : common().decrement_size();
3753
    if (!SooEnabled()) {
3754
      SanitizerPoisonObject(single_slot());
3755
    }
3756
  }
3757
  iterator single_iterator() {
3758
    return {SooControl(), single_slot(), common().generation_ptr()};
3759
  }
3760
  const_iterator single_iterator() const {
3761
    return const_cast<raw_hash_set*>(this)->single_iterator();
3762
  }
3763
  HashtablezInfoHandle infoz() {
3764
    ABSL_SWISSTABLE_ASSERT(!is_soo());
3765
    return common().infoz();
3766
  }
3767
3768
  hasher& hash_ref() { return settings_.template get<1>(); }
3769
  const hasher& hash_ref() const { return settings_.template get<1>(); }
3770
  key_equal& eq_ref() { return settings_.template get<2>(); }
3771
  const key_equal& eq_ref() const { return settings_.template get<2>(); }
3772
  CharAlloc& char_alloc_ref() { return settings_.template get<3>(); }
3773
  const CharAlloc& char_alloc_ref() const {
3774
    return settings_.template get<3>();
3775
  }
3776
3777
  static void* get_char_alloc_ref_fn(CommonFields& common) {
3778
    auto* h = reinterpret_cast<raw_hash_set*>(&common);
3779
    return &h->char_alloc_ref();
3780
  }
3781
  static void* get_hash_ref_fn(CommonFields& common) {
3782
    auto* h = reinterpret_cast<raw_hash_set*>(&common);
3783
    // TODO(b/397453582): Remove support for const hasher.
3784
    return const_cast<std::remove_const_t<hasher>*>(&h->hash_ref());
3785
  }
3786
  static void transfer_n_slots_fn(void* set, void* dst, void* src,
3787
                                  size_t count) {
3788
    auto* src_slot = to_slot(src);
3789
    auto* dst_slot = to_slot(dst);
3790
3791
    auto* h = static_cast<raw_hash_set*>(set);
3792
    for (; count > 0; --count, ++src_slot, ++dst_slot) {
3793
      h->transfer(dst_slot, src_slot);
3794
    }
3795
  }
3796
3797
  // TODO(b/382423690): Try to type erase entire function or at least type erase
3798
  // by GetKey + Hash for memcpyable types.
3799
  // TODO(b/382423690): Try to type erase for big slots: sizeof(slot_type) > 16.
3800
  static void transfer_unprobed_elements_to_next_capacity_fn(
3801
      CommonFields& common, const ctrl_t* old_ctrl, void* old_slots,
3802
      void* probed_storage,
3803
      void (*encode_probed_element)(void* probed_storage, h2_t h2,
3804
                                    size_t source_offset, size_t h1)) {
3805
    const size_t new_capacity = common.capacity();
3806
    const size_t old_capacity = PreviousCapacity(new_capacity);
3807
    ABSL_ASSUME(old_capacity + 1 >= Group::kWidth);
3808
    ABSL_ASSUME((old_capacity + 1) % Group::kWidth == 0);
3809
3810
    auto* set = reinterpret_cast<raw_hash_set*>(&common);
3811
    slot_type* old_slots_ptr = to_slot(old_slots);
3812
    ctrl_t* new_ctrl = common.control();
3813
    slot_type* new_slots = set->slot_array();
3814
3815
    for (size_t group_index = 0; group_index < old_capacity;
3816
         group_index += Group::kWidth) {
3817
      GroupFullEmptyOrDeleted old_g(old_ctrl + group_index);
3818
      std::memset(new_ctrl + group_index, static_cast<int8_t>(ctrl_t::kEmpty),
3819
                  Group::kWidth);
3820
      std::memset(new_ctrl + group_index + old_capacity + 1,
3821
                  static_cast<int8_t>(ctrl_t::kEmpty), Group::kWidth);
3822
      // TODO(b/382423690): try to type erase everything outside of the loop.
3823
      // We will share a lot of code in expense of one function call per group.
3824
      for (auto in_fixed_group_index : old_g.MaskFull()) {
3825
        size_t old_index = group_index + in_fixed_group_index;
3826
        slot_type* old_slot = old_slots_ptr + old_index;
3827
        // TODO(b/382423690): try to avoid entire hash calculation since we need
3828
        // only one new bit of h1.
3829
        size_t hash = set->hash_of(old_slot);
3830
        size_t h1 = H1(hash);
3831
        h2_t h2 = H2(hash);
3832
        size_t new_index = TryFindNewIndexWithoutProbing(
3833
            h1, old_index, old_capacity, new_ctrl, new_capacity);
3834
        // Note that encode_probed_element is allowed to use old_ctrl buffer
3835
        // till and included the old_index.
3836
        if (ABSL_PREDICT_FALSE(new_index == kProbedElementIndexSentinel)) {
3837
          encode_probed_element(probed_storage, h2, old_index, h1);
3838
          continue;
3839
        }
3840
        ABSL_SWISSTABLE_ASSERT((new_index & old_capacity) <= old_index);
3841
        ABSL_SWISSTABLE_ASSERT(IsEmpty(new_ctrl[new_index]));
3842
        new_ctrl[new_index] = static_cast<ctrl_t>(h2);
3843
        auto* new_slot = new_slots + new_index;
3844
        SanitizerUnpoisonMemoryRegion(new_slot, sizeof(slot_type));
3845
        set->transfer(new_slot, old_slot);
3846
        SanitizerPoisonMemoryRegion(old_slot, sizeof(slot_type));
3847
      }
3848
    }
3849
  }
3850
3851
  static const PolicyFunctions& GetPolicyFunctions() {
3852
    static_assert(sizeof(slot_type) <= (std::numeric_limits<uint32_t>::max)(),
3853
                  "Slot size is too large. Use std::unique_ptr for value type "
3854
                  "or use absl::node_hash_{map,set}.");
3855
    static_assert(alignof(slot_type) <=
3856
                  size_t{(std::numeric_limits<uint16_t>::max)()});
3857
    static_assert(sizeof(key_type) <=
3858
                  size_t{(std::numeric_limits<uint32_t>::max)()});
3859
    static_assert(sizeof(value_type) <=
3860
                  size_t{(std::numeric_limits<uint32_t>::max)()});
3861
    static constexpr size_t kBackingArrayAlignment =
3862
        BackingArrayAlignment(alignof(slot_type));
3863
    static constexpr PolicyFunctions value = {
3864
        static_cast<uint32_t>(sizeof(key_type)),
3865
        static_cast<uint32_t>(sizeof(value_type)),
3866
        static_cast<uint32_t>(sizeof(slot_type)),
3867
        static_cast<uint16_t>(alignof(slot_type)), SooEnabled(),
3868
        ShouldSampleHashtablezInfoForAlloc<CharAlloc>(),
3869
        // TODO(b/328722020): try to type erase
3870
        // for standard layout and alignof(Hash) <= alignof(CommonFields).
3871
        std::is_empty_v<hasher> ? &GetRefForEmptyClass
3872
                                : &raw_hash_set::get_hash_ref_fn,
3873
        PolicyTraits::template get_hash_slot_fn<hasher, kIsDefaultHash>(),
3874
        PolicyTraits::transfer_uses_memcpy()
3875
            ? TransferNRelocatable<sizeof(slot_type)>
3876
            : &raw_hash_set::transfer_n_slots_fn,
3877
        std::is_empty_v<Alloc> ? &GetRefForEmptyClass
3878
                               : &raw_hash_set::get_char_alloc_ref_fn,
3879
        &AllocateBackingArray<kBackingArrayAlignment, CharAlloc>,
3880
        &DeallocateBackingArray<kBackingArrayAlignment, CharAlloc>,
3881
        &raw_hash_set::transfer_unprobed_elements_to_next_capacity_fn};
3882
    return value;
3883
  }
3884
3885
  // Bundle together CommonFields plus other objects which might be empty.
3886
  // CompressedTuple will ensure that sizeof is not affected by any of the empty
3887
  // fields that occur after CommonFields.
3888
  absl::container_internal::CompressedTuple<CommonFields, hasher, key_equal,
3889
                                            CharAlloc>
3890
      settings_{CommonFields::CreateDefault<SooEnabled()>(), hasher{},
3891
                key_equal{}, CharAlloc{}};
3892
};
3893
3894
// Friend access for free functions in raw_hash_set.h.
3895
struct HashtableFreeFunctionsAccess {
3896
  template <class Predicate, typename Set>
3897
  static typename Set::size_type EraseIf(Predicate& pred, Set* c) {
3898
    if (c->empty()) {
3899
      return 0;
3900
    }
3901
    if (c->is_small()) {
3902
      auto it = c->single_iterator();
3903
      if (!pred(*it)) {
3904
        ABSL_SWISSTABLE_ASSERT(c->size() == 1 &&
3905
                               "hash table was modified unexpectedly");
3906
        return 0;
3907
      }
3908
      c->destroy(it.slot());
3909
      c->erase_meta_only_small();
3910
      return 1;
3911
    }
3912
    [[maybe_unused]] const size_t original_size_for_assert = c->size();
3913
    size_t num_deleted = 0;
3914
    using SlotType = typename Set::slot_type;
3915
    IterateOverFullSlots(
3916
        c->common(), sizeof(SlotType),
3917
        [&](const ctrl_t* ctrl, void* slot_void) {
3918
          auto* slot = static_cast<SlotType*>(slot_void);
3919
          if (pred(Set::PolicyTraits::element(slot))) {
3920
            c->destroy(slot);
3921
            EraseMetaOnlyLarge(c->common(), ctrl, sizeof(*slot));
3922
            ++num_deleted;
3923
          }
3924
        });
3925
    // NOTE: IterateOverFullSlots allow removal of the current element, so we
3926
    // verify the size additionally here.
3927
    ABSL_SWISSTABLE_ASSERT(original_size_for_assert - num_deleted ==
3928
                               c->size() &&
3929
                           "hash table was modified unexpectedly");
3930
    return num_deleted;
3931
  }
3932
3933
  template <class Callback, typename Set>
3934
  static void ForEach(Callback& cb, Set* c) {
3935
    if (c->empty()) {
3936
      return;
3937
    }
3938
    if (c->is_small()) {
3939
      cb(*c->single_iterator());
3940
      return;
3941
    }
3942
    using SlotType = typename Set::slot_type;
3943
    using ElementTypeWithConstness = decltype(*c->begin());
3944
    IterateOverFullSlots(
3945
        c->common(), sizeof(SlotType), [&cb](const ctrl_t*, void* slot) {
3946
          ElementTypeWithConstness& element =
3947
              Set::PolicyTraits::element(static_cast<SlotType*>(slot));
3948
          cb(element);
3949
        });
3950
  }
3951
};
3952
3953
// Erases all elements that satisfy the predicate `pred` from the container `c`.
3954
template <typename P, typename... Params, typename Predicate>
3955
typename raw_hash_set<P, Params...>::size_type EraseIf(
3956
    Predicate& pred, raw_hash_set<P, Params...>* c) {
3957
  return HashtableFreeFunctionsAccess::EraseIf(pred, c);
3958
}
3959
3960
// Calls `cb` for all elements in the container `c`.
3961
template <typename P, typename... Params, typename Callback>
3962
void ForEach(Callback& cb, raw_hash_set<P, Params...>* c) {
3963
  return HashtableFreeFunctionsAccess::ForEach(cb, c);
3964
}
3965
template <typename P, typename... Params, typename Callback>
3966
void ForEach(Callback& cb, const raw_hash_set<P, Params...>* c) {
3967
  return HashtableFreeFunctionsAccess::ForEach(cb, c);
3968
}
3969
3970
namespace hashtable_debug_internal {
3971
template <typename Set>
3972
struct HashtableDebugAccess<Set, std::void_t<typename Set::raw_hash_set>> {
3973
  using Traits = typename Set::PolicyTraits;
3974
  using Slot = typename Traits::slot_type;
3975
3976
  constexpr static bool kIsDefaultHash = Set::kIsDefaultHash;
3977
3978
  static size_t GetNumProbes(const Set& set,
3979
                             const typename Set::key_type& key) {
3980
    if (set.is_small()) return 0;
3981
    size_t num_probes = 0;
3982
    const size_t hash = set.hash_of(key);
3983
    auto seq = probe(set.common(), hash);
3984
    const h2_t h2 = H2(hash);
3985
    const ctrl_t* ctrl = set.control();
3986
    while (true) {
3987
      container_internal::Group g{ctrl + seq.offset()};
3988
      for (uint32_t i : g.Match(h2)) {
3989
        if (set.equal_to(key, set.slot_array() + seq.offset(i)))
3990
          return num_probes;
3991
        ++num_probes;
3992
      }
3993
      if (g.MaskEmpty()) return num_probes;
3994
      seq.next();
3995
      ++num_probes;
3996
    }
3997
  }
3998
3999
  static size_t AllocatedByteSize(const Set& c) {
4000
    size_t capacity = c.capacity();
4001
    if (capacity == 0) return 0;
4002
    size_t m =
4003
        c.is_soo() ? 0 : c.common().alloc_size(sizeof(Slot), alignof(Slot));
4004
4005
    size_t per_slot = Traits::space_used(static_cast<const Slot*>(nullptr));
4006
    if (per_slot != ~size_t{}) {
4007
      m += per_slot * c.size();
4008
    } else {
4009
      for (auto it = c.begin(); it != c.end(); ++it) {
4010
        m += Traits::space_used(it.slot());
4011
      }
4012
    }
4013
    return m;
4014
  }
4015
};
4016
4017
}  // namespace hashtable_debug_internal
4018
4019
// Extern template instantiations reduce binary size and linker input size.
4020
// Function definition is in raw_hash_set.cc.
4021
extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<0, false>(
4022
    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
4023
    bool);
4024
extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<1, true>(
4025
    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
4026
    bool);
4027
extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<4, true>(
4028
    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
4029
    bool);
4030
extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<8, true>(
4031
    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
4032
    bool);
4033
#if UINTPTR_MAX == UINT64_MAX
4034
extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<16, true>(
4035
    CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
4036
    bool);
4037
#endif
4038
4039
extern template void* AllocateBackingArray<
4040
    BackingArrayAlignment(alignof(size_t)), std::allocator<char>>(void* alloc,
4041
                                                                  size_t n);
4042
extern template void DeallocateBackingArray<
4043
    BackingArrayAlignment(alignof(size_t)), std::allocator<char>>(
4044
    void* alloc, size_t capacity, ctrl_t* ctrl, size_t slot_size,
4045
    size_t slot_align, bool had_infoz);
4046
4047
}  // namespace container_internal
4048
ABSL_NAMESPACE_END
4049
}  // namespace absl
4050
4051
#undef ABSL_SWISSTABLE_ENABLE_GENERATIONS
4052
#undef ABSL_SWISSTABLE_IGNORE_UNINITIALIZED
4053
#undef ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN
4054
#undef ABSL_SWISSTABLE_ASSERT
4055
4056
#endif  // ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_