Coverage Report

Created: 2026-07-16 06:43

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