Coverage Report

Created: 2026-09-14 06:45

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