Coverage Report

Created: 2026-10-28 06:49

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