Coverage Report

Created: 2026-08-13 07:15

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