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