NIM 跨平台 C++ SDK
载入中...
搜索中...
未找到
phmap.h
浏览该文件的文档.
1#if !defined(phmap_h_guard_)
2#define phmap_h_guard_
3
4// ---------------------------------------------------------------------------
5// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
6//
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License at
10//
11// https://www.apache.org/licenses/LICENSE-2.0
12//
13// Unless required by applicable law or agreed to in writing, software
14// distributed under the License is distributed on an "AS IS" BASIS,
15// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16// See the License for the specific language governing permissions and
17// limitations under the License.
18//
19// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp)
20// with modifications.
21//
22// Copyright 2018 The Abseil Authors.
23//
24// Licensed under the Apache License, Version 2.0 (the "License");
25// you may not use this file except in compliance with the License.
26// You may obtain a copy of the License at
27//
28// https://www.apache.org/licenses/LICENSE-2.0
29//
30// Unless required by applicable law or agreed to in writing, software
31// distributed under the License is distributed on an "AS IS" BASIS,
32// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33// See the License for the specific language governing permissions and
34// limitations under the License.
35// ---------------------------------------------------------------------------
36
37// ---------------------------------------------------------------------------
38// IMPLEMENTATION DETAILS
39//
40// The table stores elements inline in a slot array. In addition to the slot
41// array the table maintains some control state per slot. The extra state is one
42// byte per slot and stores empty or deleted marks, or alternatively 7 bits from
43// the hash of an occupied slot. The table is split into logical groups of
44// slots, like so:
45//
46// Group 1 Group 2 Group 3
47// +---------------+---------------+---------------+
48// | | | | | | | | | | | | | | | | | | | | | | | | |
49// +---------------+---------------+---------------+
50//
51// On lookup the hash is split into two parts:
52// - H2: 7 bits (those stored in the control bytes)
53// - H1: the rest of the bits
54// The groups are probed using H1. For each group the slots are matched to H2 in
55// parallel. Because H2 is 7 bits (128 states) and the number of slots per group
56// is low (8 or 16) in almost all cases a match in H2 is also a lookup hit.
57//
58// On insert, once the right group is found (as in lookup), its slots are
59// filled in order.
60//
61// On erase a slot is cleared. In case the group did not have any empty slots
62// before the erase, the erased slot is marked as deleted.
63//
64// Groups without empty slots (but maybe with deleted slots) extend the probe
65// sequence. The probing algorithm is quadratic. Given N the number of groups,
66// the probing function for the i'th probe is:
67//
68// P(0) = H1 % N
69//
70// P(i) = (P(i - 1) + i) % N
71//
72// This probing function guarantees that after N probes, all the groups of the
73// table will be probed exactly once.
74//
75// The control state and slot array are stored contiguously in a shared heap
76// allocation. The layout of this allocation is: `capacity()` control bytes,
77// one sentinel control byte, `Group::kWidth - 1` cloned control bytes,
78// <possible padding>, `capacity()` slots. The sentinel control byte is used in
79// iteration so we know when we reach the end of the table. The cloned control
80// bytes at the end of the table are cloned from the beginning of the table so
81// groups that begin near the end of the table can see a full group. In cases in
82// which there are more than `capacity()` cloned control bytes, the extra bytes
83// are `kEmpty`, and these ensure that we always see at least one empty slot and
84// can stop an unsuccessful search.
85// ---------------------------------------------------------------------------
86
87
88
89#ifdef _MSC_VER
90 #pragma warning(push)
91
92 #pragma warning(disable : 4127) // conditional expression is constant
93 #pragma warning(disable : 4324) // structure was padded due to alignment specifier
94 #pragma warning(disable : 4514) // unreferenced inline function has been removed
95 #pragma warning(disable : 4623) // default constructor was implicitly defined as deleted
96 #pragma warning(disable : 4625) // copy constructor was implicitly defined as deleted
97 #pragma warning(disable : 4626) // assignment operator was implicitly defined as deleted
98 #pragma warning(disable : 4710) // function not inlined
99 #pragma warning(disable : 4711) // selected for automatic inline expansion
100 #pragma warning(disable : 4820) // '6' bytes padding added after data member
101 #pragma warning(disable : 4868) // compiler may not enforce left-to-right evaluation order in braced initializer list
102 #pragma warning(disable : 5027) // move assignment operator was implicitly defined as deleted
103 #pragma warning(disable : 5045) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
104#endif
105
106#include <algorithm>
107#include <cmath>
108#include <cstring>
109#include <iterator>
110#include <limits>
111#include <memory>
112#include <tuple>
113#include <type_traits>
114#include <utility>
115#include <array>
116#include <cassert>
117#include <atomic>
118
119#include "phmap_fwd_decl.h"
120#include "phmap_utils.h"
121#include "phmap_base.h"
122
123#if PHMAP_HAVE_STD_STRING_VIEW
124 #include <string_view>
125#endif
126
127namespace phmap {
128
129namespace priv {
130
131// --------------------------------------------------------------------------
132template <typename AllocType>
133void SwapAlloc(AllocType& lhs, AllocType& rhs,
134 std::true_type /* propagate_on_container_swap */) {
135 using std::swap;
136 swap(lhs, rhs);
137}
138template <typename AllocType>
139void SwapAlloc(AllocType& /*lhs*/, AllocType& /*rhs*/,
140 std::false_type /* propagate_on_container_swap */) {}
141
142// --------------------------------------------------------------------------
143template <size_t Width>
145{
146public:
147 probe_seq(size_t hashval, size_t mask) {
148 assert(((mask + 1) & mask) == 0 && "not a mask");
149 mask_ = mask;
150 offset_ = hashval & mask_;
151 }
152 size_t offset() const { return offset_; }
153 size_t offset(size_t i) const { return (offset_ + i) & mask_; }
154
155 void next() {
156 index_ += Width;
157 offset_ += index_;
158 offset_ &= mask_;
159 }
160 // 0-based probe index. The i-th probe in the probe sequence.
161 size_t getindex() const { return index_; }
162
163private:
164 size_t mask_;
165 size_t offset_;
166 size_t index_ = 0;
167};
168
169// --------------------------------------------------------------------------
170template <class ContainerKey, class Hash, class Eq>
172{
173 template <class PassedKey, class... Args>
174 std::pair<
175 decltype(std::declval<const Hash&>()(std::declval<const PassedKey&>())),
176 decltype(std::declval<const Eq&>()(std::declval<const ContainerKey&>(),
177 std::declval<const PassedKey&>()))>*
178 operator()(const PassedKey&, const Args&...) const;
179};
180
181// --------------------------------------------------------------------------
182template <class E, class Policy, class Hash, class Eq, class... Ts>
183struct IsDecomposable : std::false_type {};
184
185template <class Policy, class Hash, class Eq, class... Ts>
187 phmap::void_t<decltype(
188 Policy::apply(RequireUsableKey<typename Policy::key_type, Hash, Eq>(),
189 std::declval<Ts>()...))>,
190 Policy, Hash, Eq, Ts...> : std::true_type {};
191
192// TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it.
193// --------------------------------------------------------------------------
194template <class T>
195constexpr bool IsNoThrowSwappable() {
196 using std::swap;
197 return noexcept(swap(std::declval<T&>(), std::declval<T&>()));
198}
199
200// --------------------------------------------------------------------------
201template <typename T>
203 PHMAP_IF_CONSTEXPR(sizeof(T) == 8)
204 return base_internal::CountTrailingZerosNonZero64(static_cast<uint64_t>(x));
205 else
206 return base_internal::CountTrailingZerosNonZero32(static_cast<uint32_t>(x));
207}
208
209// --------------------------------------------------------------------------
210template <typename T>
211int LeadingZeros(T x) {
212 PHMAP_IF_CONSTEXPR(sizeof(T) == 8)
213 return base_internal::CountLeadingZeros64(static_cast<uint64_t>(x));
214 else
215 return base_internal::CountLeadingZeros32(static_cast<uint32_t>(x));
216}
217
218// --------------------------------------------------------------------------
219// An abstraction over a bitmask. It provides an easy way to iterate through the
220// indexes of the set bits of a bitmask. When Shift=0 (platforms with SSE),
221// this is a true bitmask. On non-SSE, platforms the arithematic used to
222// emulate the SSE behavior works in bytes (Shift=3) and leaves each bytes as
223// either 0x00 or 0x80.
224//
225// For example:
226// for (int i : BitMask<uint32_t, 16>(0x5)) -> yields 0, 2
227// for (int i : BitMask<uint64_t, 8, 3>(0x0000000080800000)) -> yields 2, 3
228// --------------------------------------------------------------------------
229template <class T, int SignificantBits, int Shift = 0>
231{
232 static_assert(std::is_unsigned<T>::value, "");
233 static_assert(Shift == 0 || Shift == 3, "");
234
235public:
236 // These are useful for unit tests (gunit).
237 using value_type = int;
240
241 explicit BitMask(T mask) : mask_(mask) {}
242
243 BitMask& operator++() { // ++iterator
244 mask_ &= (mask_ - 1); // clear the least significant bit set
245 return *this;
246 }
247
248 explicit operator bool() const { return mask_ != 0; }
249 uint32_t operator*() const { return LowestBitSet(); }
250
251 uint32_t LowestBitSet() const {
252 return priv::TrailingZeros(mask_) >> Shift;
253 }
254
255 uint32_t HighestBitSet() const {
256 return (sizeof(T) * CHAR_BIT - priv::LeadingZeros(mask_) - 1) >> Shift;
257 }
258
259 BitMask begin() const { return *this; }
260 BitMask end() const { return BitMask(0); }
261
262 uint32_t TrailingZeros() const {
263 return priv::TrailingZeros(mask_) >> Shift;
264 }
265
266 uint32_t LeadingZeros() const {
267 constexpr uint32_t total_significant_bits = SignificantBits << Shift;
268 constexpr uint32_t extra_bits = sizeof(T) * 8 - total_significant_bits;
269 return priv::LeadingZeros(mask_ << extra_bits) >> Shift;
270 }
271
272private:
273 friend bool operator==(const BitMask& a, const BitMask& b) {
274 return a.mask_ == b.mask_;
275 }
276 friend bool operator!=(const BitMask& a, const BitMask& b) {
277 return a.mask_ != b.mask_;
278 }
279
281};
282
283// --------------------------------------------------------------------------
284using ctrl_t = signed char;
285using h2_t = uint8_t;
286
287// --------------------------------------------------------------------------
288// The values here are selected for maximum performance. See the static asserts
289// below for details.
290// --------------------------------------------------------------------------
292{
293 kEmpty = -128, // 0b10000000 or 0x80
294 kDeleted = -2, // 0b11111110 or 0xfe
295 kSentinel = -1, // 0b11111111 or 0xff
296};
297
298static_assert(
299 kEmpty & kDeleted & kSentinel & 0x80,
300 "Special markers need to have the MSB to make checking for them efficient");
301static_assert(kEmpty < kSentinel && kDeleted < kSentinel,
302 "kEmpty and kDeleted must be smaller than kSentinel to make the "
303 "SIMD test of IsEmptyOrDeleted() efficient");
304static_assert(kSentinel == -1,
305 "kSentinel must be -1 to elide loading it from memory into SIMD "
306 "registers (pcmpeqd xmm, xmm)");
307static_assert(kEmpty == -128,
308 "kEmpty must be -128 to make the SIMD check for its "
309 "existence efficient (psignb xmm, xmm)");
310static_assert(~kEmpty & ~kDeleted & kSentinel & 0x7F,
311 "kEmpty and kDeleted must share an unset bit that is not shared "
312 "by kSentinel to make the scalar test for MatchEmptyOrDeleted() "
313 "efficient");
314static_assert(kDeleted == -2,
315 "kDeleted must be -2 to make the implementation of "
316 "ConvertSpecialToEmptyAndFullToDeleted efficient");
317
318// --------------------------------------------------------------------------
319// A single block of empty control bytes for tables without any slots allocated.
320// This enables removing a branch in the hot path of find().
321// --------------------------------------------------------------------------
323 alignas(16) static constexpr ctrl_t empty_group[] = {
326 return const_cast<ctrl_t*>(empty_group);
327}
328
329// --------------------------------------------------------------------------
330inline size_t HashSeed(const ctrl_t* ctrl) {
331 // The low bits of the pointer have little or no entropy because of
332 // alignment. We shift the pointer to try to use higher entropy bits. A
333 // good number seems to be 12 bits, because that aligns with page size.
334 return reinterpret_cast<uintptr_t>(ctrl) >> 12;
335}
336
337#ifdef PHMAP_NON_DETERMINISTIC
338
339inline size_t H1(size_t hashval, const ctrl_t* ctrl) {
340 // use ctrl_ pointer to add entropy to ensure
341 // non-deterministic iteration order.
342 return (hashval >> 7) ^ HashSeed(ctrl);
343}
344
345#else
346
347inline size_t H1(size_t hashval, const ctrl_t* ) {
348 return (hashval >> 7);
349}
350
351#endif
352
353
354inline h2_t H2(size_t hashval) { return (ctrl_t)(hashval & 0x7F); }
355
356inline bool IsEmpty(ctrl_t c) { return c == kEmpty; }
357inline bool IsFull(ctrl_t c) { return c >= static_cast<ctrl_t>(0); }
358inline bool IsDeleted(ctrl_t c) { return c == kDeleted; }
359inline bool IsEmptyOrDeleted(ctrl_t c) { return c < kSentinel; }
360
361#if PHMAP_HAVE_SSE2
362
363#ifdef _MSC_VER
364 #pragma warning(push)
365 #pragma warning(disable : 4365) // conversion from 'int' to 'T', signed/unsigned mismatch
366#endif
367
368// --------------------------------------------------------------------------
369// https://github.com/abseil/abseil-cpp/issues/209
370// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853
371// _mm_cmpgt_epi8 is broken under GCC with -funsigned-char
372// Work around this by using the portable implementation of Group
373// when using -funsigned-char under GCC.
374// --------------------------------------------------------------------------
375inline __m128i _mm_cmpgt_epi8_fixed(__m128i a, __m128i b) {
376#if defined(__GNUC__) && !defined(__clang__)
377 #pragma GCC diagnostic push
378 #pragma GCC diagnostic ignored "-Woverflow"
379
380 if (std::is_unsigned<char>::value) {
381 const __m128i mask = _mm_set1_epi8(static_cast<char>(0x80));
382 const __m128i diff = _mm_subs_epi8(b, a);
383 return _mm_cmpeq_epi8(_mm_and_si128(diff, mask), mask);
384 }
385
386 #pragma GCC diagnostic pop
387#endif
388 return _mm_cmpgt_epi8(a, b);
389}
390
391// --------------------------------------------------------------------------
392// --------------------------------------------------------------------------
393struct GroupSse2Impl
394{
395 enum { kWidth = 16 }; // the number of slots per group
396
397 explicit GroupSse2Impl(const ctrl_t* pos) {
398 ctrl = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pos));
399 }
400
401 // Returns a bitmask representing the positions of slots that match hash.
402 // ----------------------------------------------------------------------
403 BitMask<uint32_t, kWidth> Match(h2_t hash) const {
404 auto match = _mm_set1_epi8((char)hash);
405 return BitMask<uint32_t, kWidth>(
406 static_cast<uint32_t>(_mm_movemask_epi8(_mm_cmpeq_epi8(match, ctrl))));
407 }
408
409 // Returns a bitmask representing the positions of empty slots.
410 // ------------------------------------------------------------
411 BitMask<uint32_t, kWidth> MatchEmpty() const {
412#if PHMAP_HAVE_SSSE3
413 // This only works because kEmpty is -128.
414 return BitMask<uint32_t, kWidth>(
415 static_cast<uint32_t>(_mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl))));
416#else
417 return Match(static_cast<h2_t>(kEmpty));
418#endif
419 }
420
421#ifdef __INTEL_COMPILER
422#pragma warning push
423#pragma warning disable 68
424#endif
425 // Returns a bitmask representing the positions of empty or deleted slots.
426 // -----------------------------------------------------------------------
427 BitMask<uint32_t, kWidth> MatchEmptyOrDeleted() const {
428 auto special = _mm_set1_epi8(static_cast<uint8_t>(kSentinel));
429 return BitMask<uint32_t, kWidth>(
430 static_cast<uint32_t>(_mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl))));
431 }
432
433 // Returns the number of trailing empty or deleted elements in the group.
434 // ----------------------------------------------------------------------
435 uint32_t CountLeadingEmptyOrDeleted() const {
436 auto special = _mm_set1_epi8(static_cast<uint8_t>(kSentinel));
437 return TrailingZeros(
438 static_cast<uint32_t>(_mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1));
439 }
440#ifdef __INTEL_COMPILER
441#pragma warning pop
442#endif
443
444 // ----------------------------------------------------------------------
445 void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
446 auto msbs = _mm_set1_epi8(static_cast<char>(-128));
447 auto x126 = _mm_set1_epi8(126);
448#if PHMAP_HAVE_SSSE3
449 auto res = _mm_or_si128(_mm_shuffle_epi8(x126, ctrl), msbs);
450#else
451 auto zero = _mm_setzero_si128();
452 auto special_mask = _mm_cmpgt_epi8_fixed(zero, ctrl);
453 auto res = _mm_or_si128(msbs, _mm_andnot_si128(special_mask, x126));
454#endif
455 _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), res);
456 }
457
458 __m128i ctrl;
459};
460
461#ifdef _MSC_VER
462 #pragma warning(pop)
463#endif
464
465#endif // PHMAP_HAVE_SSE2
466
467// --------------------------------------------------------------------------
468// --------------------------------------------------------------------------
470{
471 enum { kWidth = 8 };
472
473 explicit GroupPortableImpl(const ctrl_t* pos)
474 : ctrl(little_endian::Load64(pos)) {}
475
477 // For the technique, see:
478 // http://graphics.stanford.edu/~seander/bithacks.html##ValueInWord
479 // (Determine if a word has a byte equal to n).
480 //
481 // Caveat: there are false positives but:
482 // - they only occur if there is a real match
483 // - they never occur on kEmpty, kDeleted, kSentinel
484 // - they will be handled gracefully by subsequent checks in code
485 //
486 // Example:
487 // v = 0x1716151413121110
488 // hash = 0x12
489 // retval = (v - lsbs) & ~v & msbs = 0x0000000080800000
490 constexpr uint64_t msbs = 0x8080808080808080ULL;
491 constexpr uint64_t lsbs = 0x0101010101010101ULL;
492 auto x = ctrl ^ (lsbs * hash);
493 return BitMask<uint64_t, kWidth, 3>((x - lsbs) & ~x & msbs);
494 }
495
496 BitMask<uint64_t, kWidth, 3> MatchEmpty() const { // bit 1 of each byte is 0 for empty (but not for deleted)
497 constexpr uint64_t msbs = 0x8080808080808080ULL;
498 return BitMask<uint64_t, kWidth, 3>((ctrl & (~ctrl << 6)) & msbs);
499 }
500
501 BitMask<uint64_t, kWidth, 3> MatchEmptyOrDeleted() const { // lsb of each byte is 0 for empty or deleted
502 constexpr uint64_t msbs = 0x8080808080808080ULL;
503 return BitMask<uint64_t, kWidth, 3>((ctrl & (~ctrl << 7)) & msbs);
504 }
505
506 uint32_t CountLeadingEmptyOrDeleted() const {
507 constexpr uint64_t gaps = 0x00FEFEFEFEFEFEFEULL;
508 return (uint32_t)((TrailingZeros(((~ctrl & (ctrl >> 7)) | gaps) + 1) + 7) >> 3);
509 }
510
512 constexpr uint64_t msbs = 0x8080808080808080ULL;
513 constexpr uint64_t lsbs = 0x0101010101010101ULL;
514 auto x = ctrl & msbs;
515 auto res = (~x + (x >> 7)) & ~lsbs;
516 little_endian::Store64(dst, res);
517 }
518
519 uint64_t ctrl;
520};
521
522#if PHMAP_HAVE_SSE2
523 using Group = GroupSse2Impl;
524#else
526#endif
527
528// The number of cloned control bytes that we copy from the beginning to the
529// end of the control bytes array.
530// -------------------------------------------------------------------------
531constexpr size_t NumClonedBytes() { return Group::kWidth - 1; }
532
533template <class Policy, class Hash, class Eq, class Alloc>
534class raw_hash_set;
535
536inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; }
537
538// --------------------------------------------------------------------------
539// PRECONDITION:
540// IsValidCapacity(capacity)
541// ctrl[capacity] == kSentinel
542// ctrl[i] != kSentinel for all i < capacity
543// Applies mapping for every byte in ctrl:
544// DELETED -> EMPTY
545// EMPTY -> EMPTY
546// FULL -> DELETED
547// --------------------------------------------------------------------------
549 ctrl_t* ctrl, size_t capacity)
550{
551 assert(ctrl[capacity] == kSentinel);
552 assert(IsValidCapacity(capacity));
553 for (ctrl_t* pos = ctrl; pos != ctrl + capacity + 1; pos += Group::kWidth) {
555 }
556 // Copy the cloned ctrl bytes.
557 std::memcpy(ctrl + capacity + 1, ctrl, Group::kWidth);
558 ctrl[capacity] = kSentinel;
559}
560
561// --------------------------------------------------------------------------
562// Rounds up the capacity to the next power of 2 minus 1, with a minimum of 1.
563// --------------------------------------------------------------------------
564inline size_t NormalizeCapacity(size_t n)
565{
566 return n ? ~size_t{} >> LeadingZeros(n) : 1;
567}
568
569// --------------------------------------------------------------------------
570// We use 7/8th as maximum load factor.
571// For 16-wide groups, that gives an average of two empty slots per group.
572// --------------------------------------------------------------------------
573inline size_t CapacityToGrowth(size_t capacity)
574{
575 assert(IsValidCapacity(capacity));
576 // `capacity*7/8`
578 if (capacity == 7)
579 {
580 // x-x/8 does not work when x==7.
581 return 6;
582 }
583 }
584 return capacity - capacity / 8;
585}
586
587// --------------------------------------------------------------------------
588// From desired "growth" to a lowerbound of the necessary capacity.
589// Might not be a valid one and required NormalizeCapacity().
590// --------------------------------------------------------------------------
591inline size_t GrowthToLowerboundCapacity(size_t growth)
592{
593 // `growth*8/7`
595 if (growth == 7)
596 {
597 // x+(x-1)/7 does not work when x==7.
598 return 8;
599 }
600 }
601 return growth + static_cast<size_t>((static_cast<int64_t>(growth) - 1) / 7);
602}
603
604namespace hashtable_debug_internal {
605
606// If it is a map, call get<0>().
607using std::get;
608template <typename T, typename = typename T::mapped_type>
609auto GetKey(const typename T::value_type& pair, int) -> decltype(get<0>(pair)) {
610 return get<0>(pair);
611}
612
613// If it is not a map, return the value directly.
614template <typename T>
615const typename T::key_type& GetKey(const typename T::key_type& key, char) {
616 return key;
617}
618
619// --------------------------------------------------------------------------
620// Containers should specialize this to provide debug information for that
621// container.
622// --------------------------------------------------------------------------
623template <class Container, typename Enabler = void>
625{
626 // Returns the number of probes required to find `key` in `c`. The "number of
627 // probes" is a concept that can vary by container. Implementations should
628 // return 0 when `key` was found in the minimum number of operations and
629 // should increment the result for each non-trivial operation required to find
630 // `key`.
631 //
632 // The default implementation uses the bucket api from the standard and thus
633 // works for `std::unordered_*` containers.
634 // --------------------------------------------------------------------------
635 static size_t GetNumProbes(const Container& c,
636 const typename Container::key_type& key) {
637 if (!c.bucket_count()) return {};
638 size_t num_probes = 0;
639 size_t bucket = c.bucket(key);
640 for (auto it = c.begin(bucket), e = c.end(bucket);; ++it, ++num_probes) {
641 if (it == e) return num_probes;
642 if (c.key_eq()(key, GetKey<Container>(*it, 0))) return num_probes;
643 }
644 }
645};
646
647} // namespace hashtable_debug_internal
648
649// ----------------------------------------------------------------------------
650// I N F O Z S T U B S
651// ----------------------------------------------------------------------------
653{
655};
656
657inline void RecordRehashSlow(HashtablezInfo*, size_t ) {}
658
659static inline void RecordInsertSlow(HashtablezInfo* , size_t, size_t ) {}
660
661static inline void RecordEraseSlow(HashtablezInfo*) {}
662
663static inline HashtablezInfo* SampleSlow(int64_t*) { return nullptr; }
664static inline void UnsampleSlow(HashtablezInfo* ) {}
665
667{
668public:
669 inline void RecordStorageChanged(size_t , size_t ) {}
670 inline void RecordRehash(size_t ) {}
671 inline void RecordInsert(size_t , size_t ) {}
672 inline void RecordErase() {}
673 friend inline void swap(HashtablezInfoHandle& ,
674 HashtablezInfoHandle& ) noexcept {}
675};
676
678
680{
681public:
682 // Returns a global Sampler.
683 static HashtablezSampler& Global() { static HashtablezSampler hzs; return hzs; }
684 HashtablezInfo* Register() { static HashtablezInfo info; return &info; }
686
687 using DisposeCallback = void (*)(const HashtablezInfo&);
689 int64_t Iterate(const std::function<void(const HashtablezInfo& stack)>& ) { return 0; }
690};
691
692static inline void SetHashtablezEnabled(bool ) {}
693static inline void SetHashtablezSampleParameter(int32_t ) {}
694static inline void SetHashtablezMaxSamples(int32_t ) {}
695
696
697namespace memory_internal {
698
699// Constructs T into uninitialized storage pointed by `ptr` using the args
700// specified in the tuple.
701// ----------------------------------------------------------------------------
702template <class Alloc, class T, class Tuple, size_t... I>
703void ConstructFromTupleImpl(Alloc* alloc, T* ptr, Tuple&& t,
706 *alloc, ptr, std::get<I>(std::forward<Tuple>(t))...);
707}
708
709template <class T, class F>
711 template <class... Args>
712 decltype(std::declval<F>()(std::declval<T>())) operator()(
713 Args&&... args) const {
714 return std::forward<F>(f)(T(std::forward<Args>(args)...));
715 }
716 F&& f;
717};
718
719template <class T, class Tuple, size_t... Is, class F>
720decltype(std::declval<F>()(std::declval<T>())) WithConstructedImpl(
721 Tuple&& t, phmap::index_sequence<Is...>, F&& f) {
722 return WithConstructedImplF<T, F>{std::forward<F>(f)}(
723 std::get<Is>(std::forward<Tuple>(t))...);
724}
725
726template <class T, size_t... Is>
728 -> decltype(std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...)) {
729 return std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...);
730}
731
732// Returns a tuple of references to the elements of the input tuple. T must be a
733// tuple.
734// ----------------------------------------------------------------------------
735template <class T>
736auto TupleRef(T&& t) -> decltype(
737 TupleRefImpl(std::forward<T>(t),
739 std::tuple_size<typename std::decay<T>::type>::value>())) {
740 return TupleRefImpl(
741 std::forward<T>(t),
743 std::tuple_size<typename std::decay<T>::type>::value>());
744}
745
746template <class F, class K, class V>
747decltype(std::declval<F>()(std::declval<const K&>(), std::piecewise_construct,
748 std::declval<std::tuple<K>>(), std::declval<V>()))
749DecomposePairImpl(F&& f, std::pair<std::tuple<K>, V> p) {
750 const auto& key = std::get<0>(p.first);
751 return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first),
752 std::move(p.second));
753}
754
755} // namespace memory_internal
756
757
758// ----------------------------------------------------------------------------
759// R A W _ H A S H _ S E T
760// ----------------------------------------------------------------------------
761// An open-addressing
762// hashtable with quadratic probing.
763//
764// This is a low level hashtable on top of which different interfaces can be
765// implemented, like flat_hash_set, node_hash_set, string_hash_set, etc.
766//
767// The table interface is similar to that of std::unordered_set. Notable
768// differences are that most member functions support heterogeneous keys when
769// BOTH the hash and eq functions are marked as transparent. They do so by
770// providing a typedef called `is_transparent`.
771//
772// When heterogeneous lookup is enabled, functions that take key_type act as if
773// they have an overload set like:
774//
775// iterator find(const key_type& key);
776// template <class K>
777// iterator find(const K& key);
778//
779// size_type erase(const key_type& key);
780// template <class K>
781// size_type erase(const K& key);
782//
783// std::pair<iterator, iterator> equal_range(const key_type& key);
784// template <class K>
785// std::pair<iterator, iterator> equal_range(const K& key);
786//
787// When heterogeneous lookup is disabled, only the explicit `key_type` overloads
788// exist.
789//
790// find() also supports passing the hash explicitly:
791//
792// iterator find(const key_type& key, size_t hash);
793// template <class U>
794// iterator find(const U& key, size_t hash);
795//
796// In addition the pointer to element and iterator stability guarantees are
797// weaker: all iterators and pointers are invalidated after a new element is
798// inserted.
799//
800// IMPLEMENTATION DETAILS
801//
802// The table stores elements inline in a slot array. In addition to the slot
803// array the table maintains some control state per slot. The extra state is one
804// byte per slot and stores empty or deleted marks, or alternatively 7 bits from
805// the hash of an occupied slot. The table is split into logical groups of
806// slots, like so:
807//
808// Group 1 Group 2 Group 3
809// +---------------+---------------+---------------+
810// | | | | | | | | | | | | | | | | | | | | | | | | |
811// +---------------+---------------+---------------+
812//
813// On lookup the hash is split into two parts:
814// - H2: 7 bits (those stored in the control bytes)
815// - H1: the rest of the bits
816// The groups are probed using H1. For each group the slots are matched to H2 in
817// parallel. Because H2 is 7 bits (128 states) and the number of slots per group
818// is low (8 or 16) in almost all cases a match in H2 is also a lookup hit.
819//
820// On insert, once the right group is found (as in lookup), its slots are
821// filled in order.
822//
823// On erase a slot is cleared. In case the group did not have any empty slots
824// before the erase, the erased slot is marked as deleted.
825//
826// Groups without empty slots (but maybe with deleted slots) extend the probe
827// sequence. The probing algorithm is quadratic. Given N the number of groups,
828// the probing function for the i'th probe is:
829//
830// P(0) = H1 % N
831//
832// P(i) = (P(i - 1) + i) % N
833//
834// This probing function guarantees that after N probes, all the groups of the
835// table will be probed exactly once.
836// ----------------------------------------------------------------------------
837template <class Policy, class Hash, class Eq, class Alloc>
839{
843
844public:
847 // TODO(sbenza): Hide slot_type as it is an implementation detail. Needs user
848 // code fixes!
850 using allocator_type = Alloc;
851 using size_type = size_t;
852 using difference_type = ptrdiff_t;
853 using hasher = Hash;
854 using key_equal = Eq;
855 using policy_type = Policy;
860 allocator_type>::template rebind_traits<value_type>::pointer;
862 allocator_type>::template rebind_traits<value_type>::const_pointer;
863
864 // Alias used for heterogeneous lookup functions.
865 // `key_arg<K>` evaluates to `K` when the functors are transparent and to
866 // `key_type` otherwise. It permits template argument deduction on `K` for the
867 // transparent case.
868 template <class K>
869 using key_arg = typename KeyArgImpl::template type<K, key_type>;
870
871private:
872 // Give an early error when key_type is not hashable/eq.
873 auto KeyTypeCanBeHashed(const Hash& h, const key_type& k) -> decltype(h(k));
874 auto KeyTypeCanBeEq(const Eq& eq, const key_type& k) -> decltype(eq(k, k));
875
877
878 static Layout MakeLayout(size_t capacity) {
879 assert(IsValidCapacity(capacity));
880 return Layout(capacity + Group::kWidth + 1, capacity);
881 }
882
885 allocator_type>::template rebind_alloc<slot_type>;
887 allocator_type>::template rebind_traits<slot_type>;
888
889 static_assert(std::is_lvalue_reference<reference>::value,
890 "Policy::element() must return a reference");
891
892 template <typename T>
894 : std::is_same<typename std::remove_cv<
895 typename std::remove_reference<reference>::type>::type,
896 typename std::remove_cv<
897 typename std::remove_reference<T>::type>::type> {};
898
899 // An enabler for insert(T&&): T must be convertible to init_type or be the
900 // same as [cv] value_type [ref].
901 // Note: we separate SameAsElementReference into its own type to avoid using
902 // reference unless we need to. MSVC doesn't seem to like it in some
903 // cases.
904 template <class T>
905 using RequiresInsertable = typename std::enable_if<
908 int>::type;
909
910 // RequiresNotInit is a workaround for gcc prior to 7.1.
911 // See https://godbolt.org/g/Y4xsUh.
912 template <class T>
914 typename std::enable_if<!std::is_same<T, init_type>::value, int>::type;
915
916 template <class... Ts>
917 using IsDecomposable = IsDecomposable<void, PolicyTraits, Hash, Eq, Ts...>;
918
919public:
920 static_assert(std::is_same<pointer, value_type*>::value,
921 "Allocators with custom pointer types are not supported");
922 static_assert(std::is_same<const_pointer, const value_type*>::value,
923 "Allocators with custom pointer types are not supported");
924
925 class iterator
926 {
927 friend class raw_hash_set;
928
929 public:
930 using iterator_category = std::forward_iterator_tag;
932 using reference =
934 const value_type&, value_type&>;
937
939
940 // PRECONDITION: not an end() iterator.
942
943 // PRECONDITION: not an end() iterator.
944 pointer operator->() const { return &operator*(); }
945
946 // PRECONDITION: not an end() iterator.
948 ++ctrl_;
949 ++slot_;
951 return *this;
952 }
953 // PRECONDITION: not an end() iterator.
955 auto tmp = *this;
956 ++*this;
957 return tmp;
958 }
959
960#if PHMAP_BIDIRECTIONAL
961 // PRECONDITION: not a begin() iterator.
962 iterator& operator--() {
963 assert(ctrl_);
964 do {
965 --ctrl_;
966 --slot_;
967 } while (IsEmptyOrDeleted(*ctrl_));
968 return *this;
969 }
970
971 // PRECONDITION: not a begin() iterator.
972 iterator operator--(int) {
973 auto tmp = *this;
974 --*this;
975 return tmp;
976 }
977#endif
978
979 friend bool operator==(const iterator& a, const iterator& b) {
980 return a.ctrl_ == b.ctrl_;
981 }
982 friend bool operator!=(const iterator& a, const iterator& b) {
983 return !(a == b);
984 }
985
986 private:
987 iterator(ctrl_t* ctrl) : ctrl_(ctrl) {} // for end()
988 iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {}
989
991 while (IsEmptyOrDeleted(*ctrl_)) {
992 // ctrl is not necessarily aligned to Group::kWidth. It is also likely
993 // to read past the space for ctrl bytes and into slots. This is ok
994 // because ctrl has sizeof() == 1 and slot has sizeof() >= 1 so there
995 // is no way to read outside the combined slot array.
996 uint32_t shift = Group{ctrl_}.CountLeadingEmptyOrDeleted();
997 ctrl_ += shift;
998 slot_ += shift;
999 }
1000 }
1001
1002 ctrl_t* ctrl_ = nullptr;
1003 // To avoid uninitialized member warnings, put slot_ in an anonymous union.
1004 // The member is not initialized on singleton and end iterators.
1005 union {
1007 };
1008 };
1009
1011 {
1012 friend class raw_hash_set;
1013
1014 public:
1020
1022 // Implicit construction from iterator.
1024
1025 reference operator*() const { return *inner_; }
1026 pointer operator->() const { return inner_.operator->(); }
1027
1029 ++inner_;
1030 return *this;
1031 }
1033
1034 friend bool operator==(const const_iterator& a, const const_iterator& b) {
1035 return a.inner_ == b.inner_;
1036 }
1037 friend bool operator!=(const const_iterator& a, const const_iterator& b) {
1038 return !(a == b);
1039 }
1040
1041 private:
1042 const_iterator(const ctrl_t* ctrl, const slot_type* slot)
1043 : inner_(const_cast<ctrl_t*>(ctrl), const_cast<slot_type*>(slot)) {}
1044
1046 };
1047
1050
1051 raw_hash_set() noexcept(
1052 std::is_nothrow_default_constructible<hasher>::value&&
1053 std::is_nothrow_default_constructible<key_equal>::value&&
1054 std::is_nothrow_default_constructible<allocator_type>::value) {}
1055
1056 explicit raw_hash_set(size_t bucket_cnt, const hasher& hashfn = hasher(),
1057 const key_equal& eq = key_equal(),
1058 const allocator_type& alloc = allocator_type())
1059 : ctrl_(EmptyGroup()), settings_(0, hashfn, eq, alloc) {
1060 if (bucket_cnt) {
1061 size_t new_capacity = NormalizeCapacity(bucket_cnt);
1062 reset_growth_left(new_capacity);
1063 initialize_slots(new_capacity);
1064 capacity_ = new_capacity;
1065 }
1066 }
1067
1068 raw_hash_set(size_t bucket_cnt, const hasher& hashfn,
1069 const allocator_type& alloc)
1070 : raw_hash_set(bucket_cnt, hashfn, key_equal(), alloc) {}
1071
1072 raw_hash_set(size_t bucket_cnt, const allocator_type& alloc)
1073 : raw_hash_set(bucket_cnt, hasher(), key_equal(), alloc) {}
1074
1075 explicit raw_hash_set(const allocator_type& alloc)
1076 : raw_hash_set(0, hasher(), key_equal(), alloc) {}
1077
1078 template <class InputIter>
1079 raw_hash_set(InputIter first, InputIter last, size_t bucket_cnt = 0,
1080 const hasher& hashfn = hasher(), const key_equal& eq = key_equal(),
1081 const allocator_type& alloc = allocator_type())
1082 : raw_hash_set(bucket_cnt, hashfn, eq, alloc) {
1083 insert(first, last);
1084 }
1085
1086 template <class InputIter>
1087 raw_hash_set(InputIter first, InputIter last, size_t bucket_cnt,
1088 const hasher& hashfn, const allocator_type& alloc)
1089 : raw_hash_set(first, last, bucket_cnt, hashfn, key_equal(), alloc) {}
1090
1091 template <class InputIter>
1092 raw_hash_set(InputIter first, InputIter last, size_t bucket_cnt,
1093 const allocator_type& alloc)
1094 : raw_hash_set(first, last, bucket_cnt, hasher(), key_equal(), alloc) {}
1095
1096 template <class InputIter>
1097 raw_hash_set(InputIter first, InputIter last, const allocator_type& alloc)
1098 : raw_hash_set(first, last, 0, hasher(), key_equal(), alloc) {}
1099
1100 // Instead of accepting std::initializer_list<value_type> as the first
1101 // argument like std::unordered_set<value_type> does, we have two overloads
1102 // that accept std::initializer_list<T> and std::initializer_list<init_type>.
1103 // This is advantageous for performance.
1104 //
1105 // // Turns {"abc", "def"} into std::initializer_list<std::string>, then
1106 // // copies the strings into the set.
1107 // std::unordered_set<std::string> s = {"abc", "def"};
1108 //
1109 // // Turns {"abc", "def"} into std::initializer_list<const char*>, then
1110 // // copies the strings into the set.
1111 // phmap::flat_hash_set<std::string> s = {"abc", "def"};
1112 //
1113 // The same trick is used in insert().
1114 //
1115 // The enabler is necessary to prevent this constructor from triggering where
1116 // the copy constructor is meant to be called.
1117 //
1118 // phmap::flat_hash_set<int> a, b{a};
1119 //
1120 // RequiresNotInit<T> is a workaround for gcc prior to 7.1.
1121 template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
1122 raw_hash_set(std::initializer_list<T> init, size_t bucket_cnt = 0,
1123 const hasher& hashfn = hasher(), const key_equal& eq = key_equal(),
1124 const allocator_type& alloc = allocator_type())
1125 : raw_hash_set(init.begin(), init.end(), bucket_cnt, hashfn, eq, alloc) {}
1126
1127 raw_hash_set(std::initializer_list<init_type> init, size_t bucket_cnt = 0,
1128 const hasher& hashfn = hasher(), const key_equal& eq = key_equal(),
1129 const allocator_type& alloc = allocator_type())
1130 : raw_hash_set(init.begin(), init.end(), bucket_cnt, hashfn, eq, alloc) {}
1131
1132 template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
1133 raw_hash_set(std::initializer_list<T> init, size_t bucket_cnt,
1134 const hasher& hashfn, const allocator_type& alloc)
1135 : raw_hash_set(init, bucket_cnt, hashfn, key_equal(), alloc) {}
1136
1137 raw_hash_set(std::initializer_list<init_type> init, size_t bucket_cnt,
1138 const hasher& hashfn, const allocator_type& alloc)
1139 : raw_hash_set(init, bucket_cnt, hashfn, key_equal(), alloc) {}
1140
1141 template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
1142 raw_hash_set(std::initializer_list<T> init, size_t bucket_cnt,
1143 const allocator_type& alloc)
1144 : raw_hash_set(init, bucket_cnt, hasher(), key_equal(), alloc) {}
1145
1146 raw_hash_set(std::initializer_list<init_type> init, size_t bucket_cnt,
1147 const allocator_type& alloc)
1148 : raw_hash_set(init, bucket_cnt, hasher(), key_equal(), alloc) {}
1149
1150 template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
1151 raw_hash_set(std::initializer_list<T> init, const allocator_type& alloc)
1152 : raw_hash_set(init, 0, hasher(), key_equal(), alloc) {}
1153
1154 raw_hash_set(std::initializer_list<init_type> init,
1155 const allocator_type& alloc)
1156 : raw_hash_set(init, 0, hasher(), key_equal(), alloc) {}
1157
1159 : raw_hash_set(that, AllocTraits::select_on_container_copy_construction(
1160 that.alloc_ref())) {}
1161
1163 : raw_hash_set(0, that.hash_ref(), that.eq_ref(), a) {
1164 rehash(that.capacity()); // operator=() should preserve load_factor
1165 // Because the table is guaranteed to be empty, we can do something faster
1166 // than a full `insert`.
1167 for (const auto& v : that) {
1168 const size_t hashval = PolicyTraits::apply(HashElement{hash_ref()}, v);
1169 auto target = find_first_non_full(hashval);
1170 set_ctrl(target.offset, H2(hashval));
1171 emplace_at(target.offset, v);
1172 infoz_.RecordInsert(hashval, target.probe_length);
1173 }
1174 size_ = that.size();
1175 growth_left() -= that.size();
1176 }
1177
1178 raw_hash_set(raw_hash_set&& that) noexcept(
1179 std::is_nothrow_copy_constructible<hasher>::value&&
1180 std::is_nothrow_copy_constructible<key_equal>::value&&
1181 std::is_nothrow_copy_constructible<allocator_type>::value)
1182 : ctrl_(phmap::exchange(that.ctrl_, EmptyGroup())),
1183 slots_(phmap::exchange(that.slots_, nullptr)),
1184 size_(phmap::exchange(that.size_, 0)),
1185 capacity_(phmap::exchange(that.capacity_, 0)),
1187 // Hash, equality and allocator are copied instead of moved because
1188 // `that` must be left valid. If Hash is std::function<Key>, moving it
1189 // would create a nullptr functor that cannot be called.
1190 settings_(that.settings_) {
1191 // growth_left was copied above, reset the one from `that`.
1192 that.growth_left() = 0;
1193 }
1194
1196 : ctrl_(EmptyGroup()),
1197 slots_(nullptr),
1198 size_(0),
1199 capacity_(0),
1200 settings_(0, that.hash_ref(), that.eq_ref(), a) {
1201 if (a == that.alloc_ref()) {
1202 std::swap(ctrl_, that.ctrl_);
1203 std::swap(slots_, that.slots_);
1204 std::swap(size_, that.size_);
1205 std::swap(capacity_, that.capacity_);
1206 std::swap(growth_left(), that.growth_left());
1207 std::swap(infoz_, that.infoz_);
1208 } else {
1209 reserve(that.size());
1210 // Note: this will copy elements of dense_set and unordered_set instead of
1211 // moving them. This can be fixed if it ever becomes an issue.
1212 for (auto& elem : that) insert(std::move(elem));
1213 }
1214 }
1215
1217 raw_hash_set tmp(that,
1218 AllocTraits::propagate_on_container_copy_assignment::value
1219 ? that.alloc_ref()
1220 : alloc_ref());
1221 swap(tmp);
1222 return *this;
1223 }
1224
1227 std::is_nothrow_move_assignable<hasher>::value&&
1228 std::is_nothrow_move_assignable<key_equal>::value) {
1229 // TODO(sbenza): We should only use the operations from the noexcept clause
1230 // to make sure we actually adhere to that contract.
1231 return move_assign(
1232 std::move(that),
1234 }
1235
1237
1239 auto it = iterator_at(0);
1240 it.skip_empty_or_deleted();
1241 return it;
1242 }
1244 {
1245#if PHMAP_BIDIRECTIONAL
1246 return iterator_at(capacity_);
1247#else
1248 return {ctrl_ + capacity_};
1249#endif
1250 }
1251
1253 return const_cast<raw_hash_set*>(this)->begin();
1254 }
1255 const_iterator end() const { return const_cast<raw_hash_set*>(this)->end(); }
1256 const_iterator cbegin() const { return begin(); }
1257 const_iterator cend() const { return end(); }
1258
1259 bool empty() const { return !size(); }
1260 size_t size() const { return size_; }
1261 size_t capacity() const { return capacity_; }
1262 size_t max_size() const { return (std::numeric_limits<size_t>::max)(); }
1263
1265 // Iterating over this container is O(bucket_count()). When bucket_count()
1266 // is much greater than size(), iteration becomes prohibitively expensive.
1267 // For clear() it is more important to reuse the allocated array when the
1268 // container is small because allocation takes comparatively long time
1269 // compared to destruction of the elements of the container. So we pick the
1270 // largest bucket_count() threshold for which iteration is still fast and
1271 // past that we simply deallocate the array.
1272 if (empty())
1273 return;
1274 if (capacity_ > 127) {
1275 destroy_slots();
1276 } else if (capacity_) {
1277 for (size_t i = 0; i != capacity_; ++i) {
1278 if (IsFull(ctrl_[i])) {
1280 }
1281 }
1282 size_ = 0;
1285 }
1286 assert(empty());
1288 }
1289
1290 // This overload kicks in when the argument is an rvalue of insertable and
1291 // decomposable type other than init_type.
1292 //
1293 // flat_hash_map<std::string, int> m;
1294 // m.insert(std::make_pair("abc", 42));
1295 template <class T, RequiresInsertable<T> = 0,
1296 typename std::enable_if<IsDecomposable<T>::value, int>::type = 0,
1297 T* = nullptr>
1298 std::pair<iterator, bool> insert(T&& value) {
1299 return emplace(std::forward<T>(value));
1300 }
1301
1302 // This overload kicks in when the argument is a bitfield or an lvalue of
1303 // insertable and decomposable type.
1304 //
1305 // union { int n : 1; };
1306 // flat_hash_set<int> s;
1307 // s.insert(n);
1308 //
1309 // flat_hash_set<std::string> s;
1310 // const char* p = "hello";
1311 // s.insert(p);
1312 //
1313 // TODO(romanp): Once we stop supporting gcc 5.1 and below, replace
1314 // RequiresInsertable<T> with RequiresInsertable<const T&>.
1315 // We are hitting this bug: https://godbolt.org/g/1Vht4f.
1316 template <class T, RequiresInsertable<T> = 0,
1317 typename std::enable_if<IsDecomposable<const T&>::value, int>::type = 0>
1318 std::pair<iterator, bool> insert(const T& value) {
1319 return emplace(value);
1320 }
1321
1322 // This overload kicks in when the argument is an rvalue of init_type. Its
1323 // purpose is to handle brace-init-list arguments.
1324 //
1325 // flat_hash_set<std::string, int> s;
1326 // s.insert({"abc", 42});
1327 std::pair<iterator, bool> insert(init_type&& value) {
1328 return emplace(std::move(value));
1329 }
1330
1331 template <class T, RequiresInsertable<T> = 0,
1332 typename std::enable_if<IsDecomposable<T>::value, int>::type = 0,
1333 T* = nullptr>
1335 return insert(std::forward<T>(value)).first;
1336 }
1337
1338 // TODO(romanp): Once we stop supporting gcc 5.1 and below, replace
1339 // RequiresInsertable<T> with RequiresInsertable<const T&>.
1340 // We are hitting this bug: https://godbolt.org/g/1Vht4f.
1341 template <class T, RequiresInsertable<T> = 0,
1342 typename std::enable_if<IsDecomposable<const T&>::value, int>::type = 0>
1343 iterator insert(const_iterator, const T& value) {
1344 return insert(value).first;
1345 }
1346
1348 return insert(std::move(value)).first;
1349 }
1350
1351 template <typename It>
1352 using IsRandomAccess = std::is_same<typename std::iterator_traits<It>::iterator_category,
1353 std::random_access_iterator_tag>;
1354
1355
1356 template<typename T>
1358 {
1359 private:
1360 using yes = std::true_type;
1361 using no = std::false_type;
1362
1363 template<typename U> static auto test(int) -> decltype(std::declval<U>() - std::declval<U>() == 1, yes());
1364 template<typename> static no test(...);
1365
1366 public:
1367 static constexpr bool value = std::is_same<decltype(test<T>(0)), yes>::value;
1368 };
1369
1370 template <class InputIt, typename phmap::enable_if_t<has_difference_operator<InputIt>::value, int> = 0>
1371 void insert(InputIt first, InputIt last) {
1372 this->reserve(this->size() + (last - first));
1373 for (; first != last; ++first)
1374 emplace(*first);
1375 }
1376
1377 template <class InputIt, typename phmap::enable_if_t<!has_difference_operator<InputIt>::value, int> = 0>
1378 void insert(InputIt first, InputIt last) {
1379 for (; first != last; ++first)
1380 emplace(*first);
1381 }
1382
1383 template <class T, RequiresNotInit<T> = 0, RequiresInsertable<const T&> = 0>
1384 void insert(std::initializer_list<T> ilist) {
1385 insert(ilist.begin(), ilist.end());
1386 }
1387
1388 void insert(std::initializer_list<init_type> ilist) {
1389 insert(ilist.begin(), ilist.end());
1390 }
1391
1393 if (!node) return {end(), false, node_type()};
1394 const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node));
1395 auto res = PolicyTraits::apply(
1396 InsertSlot<false>{*this, std::move(*CommonAccess::GetSlot(node))},
1397 elem);
1398 if (res.second) {
1399 CommonAccess::Reset(&node);
1400 return {res.first, true, node_type()};
1401 } else {
1402 return {res.first, false, std::move(node)};
1403 }
1404 }
1405
1406 insert_return_type insert(node_type&& node, size_t hashval) {
1407 if (!node) return {end(), false, node_type()};
1408 const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node));
1409 auto res = PolicyTraits::apply(
1410 InsertSlotWithHash<false>{*this, std::move(*CommonAccess::GetSlot(node)), hashval},
1411 elem);
1412 if (res.second) {
1413 CommonAccess::Reset(&node);
1414 return {res.first, true, node_type()};
1415 } else {
1416 return {res.first, false, std::move(node)};
1417 }
1418 }
1419
1421 auto res = insert(std::move(node));
1422 node = std::move(res.node);
1423 return res.position;
1424 }
1425
1426 // This overload kicks in if we can deduce the key from args. This enables us
1427 // to avoid constructing value_type if an entry with the same key already
1428 // exists.
1429 //
1430 // For example:
1431 //
1432 // flat_hash_map<std::string, std::string> m = {{"abc", "def"}};
1433 // // Creates no std::string copies and makes no heap allocations.
1434 // m.emplace("abc", "xyz");
1435 template <class... Args, typename std::enable_if<
1436 IsDecomposable<Args...>::value, int>::type = 0>
1437 std::pair<iterator, bool> emplace(Args&&... args) {
1439 std::forward<Args>(args)...);
1440 }
1441
1442 template <class... Args, typename std::enable_if<IsDecomposable<Args...>::value, int>::type = 0>
1443 std::pair<iterator, bool> emplace_with_hash(size_t hashval, Args&&... args) {
1444 return PolicyTraits::apply(EmplaceDecomposableHashval{*this, hashval}, std::forward<Args>(args)...);
1445 }
1446
1447 // This overload kicks in if we cannot deduce the key from args. It constructs
1448 // value_type unconditionally and then either moves it into the table or
1449 // destroys.
1450 template <class... Args, typename std::enable_if<
1451 !IsDecomposable<Args...>::value, int>::type = 0>
1452 std::pair<iterator, bool> emplace(Args&&... args) {
1453 typename std::aligned_storage<sizeof(slot_type), alignof(slot_type)>::type
1454 raw;
1455 slot_type* slot = reinterpret_cast<slot_type*>(&raw);
1456
1457 PolicyTraits::construct(&alloc_ref(), slot, std::forward<Args>(args)...);
1458 const auto& elem = PolicyTraits::element(slot);
1459 return PolicyTraits::apply(InsertSlot<true>{*this, std::move(*slot)}, elem);
1460 }
1461
1462 template <class... Args, typename std::enable_if<!IsDecomposable<Args...>::value, int>::type = 0>
1463 std::pair<iterator, bool> emplace_with_hash(size_t hashval, Args&&... args) {
1464 typename std::aligned_storage<sizeof(slot_type), alignof(slot_type)>::type raw;
1465 slot_type* slot = reinterpret_cast<slot_type*>(&raw);
1466
1467 PolicyTraits::construct(&alloc_ref(), slot, std::forward<Args>(args)...);
1468 const auto& elem = PolicyTraits::element(slot);
1469 return PolicyTraits::apply(InsertSlotWithHash<true>{*this, std::move(*slot), hashval}, elem);
1470 }
1471
1472 template <class... Args>
1474 return emplace(std::forward<Args>(args)...).first;
1475 }
1476
1477 template <class... Args>
1478 iterator emplace_hint_with_hash(size_t hashval, const_iterator, Args&&... args) {
1479 return emplace_with_hash(hashval, std::forward<Args>(args)...).first;
1480 }
1481
1482 // Extension API: support for lazy emplace.
1483 //
1484 // Looks up key in the table. If found, returns the iterator to the element.
1485 // Otherwise calls f with one argument of type raw_hash_set::constructor. f
1486 // MUST call raw_hash_set::constructor with arguments as if a
1487 // raw_hash_set::value_type is constructed, otherwise the behavior is
1488 // undefined.
1489 //
1490 // For example:
1491 //
1492 // std::unordered_set<ArenaString> s;
1493 // // Makes ArenaStr even if "abc" is in the map.
1494 // s.insert(ArenaString(&arena, "abc"));
1495 //
1496 // flat_hash_set<ArenaStr> s;
1497 // // Makes ArenaStr only if "abc" is not in the map.
1498 // s.lazy_emplace("abc", [&](const constructor& ctor) {
1499 // ctor(&arena, "abc");
1500 // });
1501 //
1502 // WARNING: This API is currently experimental. If there is a way to implement
1503 // the same thing with the rest of the API, prefer that.
1505 {
1506 friend class raw_hash_set;
1507
1508 public:
1509 template <class... Args>
1510 void operator()(Args&&... args) const {
1511 assert(*slot_);
1512 PolicyTraits::construct(alloc_, *slot_, std::forward<Args>(args)...);
1513 *slot_ = nullptr;
1514 }
1515
1516 private:
1518
1521 };
1522
1523 template <class K = key_type, class F>
1524 iterator lazy_emplace(const key_arg<K>& key, F&& f) {
1525 auto res = find_or_prepare_insert(key);
1526 if (res.second) {
1527 lazy_emplace_at(res.first, std::forward<F>(f));
1528 }
1529 return iterator_at(res.first);
1530 }
1531
1532 template <class K = key_type, class F>
1533 iterator lazy_emplace_with_hash(const key_arg<K>& key, size_t hashval, F&& f) {
1534 auto res = find_or_prepare_insert(key, hashval);
1535 if (res.second) {
1536 lazy_emplace_at(res.first, std::forward<F>(f));
1537 }
1538 return iterator_at(res.first);
1539 }
1540
1541 template <class K = key_type, class F>
1542 void lazy_emplace_at(size_t& idx, F&& f) {
1543 slot_type* slot = slots_ + idx;
1544 std::forward<F>(f)(constructor(&alloc_ref(), &slot));
1545 assert(!slot);
1546 }
1547
1548 template <class K = key_type, class F>
1549 void emplace_single_with_hash(const key_arg<K>& key, size_t hashval, F&& f) {
1550 auto res = find_or_prepare_insert(key, hashval);
1551 if (res.second)
1552 lazy_emplace_at(res.first, std::forward<F>(f));
1553 else
1554 _erase(iterator_at(res.first));
1555 }
1556
1557
1558 // Extension API: support for heterogeneous keys.
1559 //
1560 // std::unordered_set<std::string> s;
1561 // // Turns "abc" into std::string.
1562 // s.erase("abc");
1563 //
1564 // flat_hash_set<std::string> s;
1565 // // Uses "abc" directly without copying it into std::string.
1566 // s.erase("abc");
1567 template <class K = key_type>
1569 auto it = find(key);
1570 if (it == end()) return 0;
1571 _erase(it);
1572 return 1;
1573 }
1574
1575
1577
1578 // Erases the element pointed to by `it`. Unlike `std::unordered_set::erase`,
1579 // this method returns void to reduce algorithmic complexity to O(1). In
1580 // order to erase while iterating across a map, use the following idiom (which
1581 // also works for standard containers):
1582 //
1583 // for (auto it = m.begin(), end = m.end(); it != end;) {
1584 // if (<pred>) {
1585 // m._erase(it++);
1586 // } else {
1587 // ++it;
1588 // }
1589 // }
1590 void _erase(iterator it) {
1591 assert(it != end());
1593 erase_meta_only(it);
1594 }
1596
1597 // This overload is necessary because otherwise erase<K>(const K&) would be
1598 // a better match if non-const iterator is passed as an argument.
1600 auto res = it;
1601 ++res;
1602 _erase(it);
1603 return res;
1604 }
1605
1607 while (first != last) {
1608 _erase(first++);
1609 }
1610 return last.inner_;
1611 }
1612
1613 // Moves elements from `src` into `this`.
1614 // If the element already exists in `this`, it is left unmodified in `src`.
1615 template <typename H, typename E>
1617 assert(this != &src);
1618 for (auto it = src.begin(), e = src.end(); it != e; ++it) {
1619 if (PolicyTraits::apply(InsertSlot<false>{*this, std::move(*it.slot_)},
1620 PolicyTraits::element(it.slot_))
1621 .second) {
1622 src.erase_meta_only(it);
1623 }
1624 }
1625 }
1626
1627 template <typename H, typename E>
1629 merge(src);
1630 }
1631
1633 auto node =
1634 CommonAccess::Make<node_type>(alloc_ref(), position.inner_.slot_);
1635 erase_meta_only(position);
1636 return node;
1637 }
1638
1639 template <
1640 class K = key_type,
1641 typename std::enable_if<!std::is_same<K, iterator>::value, int>::type = 0>
1643 auto it = find(key);
1644 return it == end() ? node_type() : extract(const_iterator{it});
1645 }
1646
1647 void swap(raw_hash_set& that) noexcept(
1648 IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
1649 (!AllocTraits::propagate_on_container_swap::value ||
1650 IsNoThrowSwappable<allocator_type>())) {
1651 using std::swap;
1652 swap(ctrl_, that.ctrl_);
1653 swap(slots_, that.slots_);
1654 swap(size_, that.size_);
1655 swap(capacity_, that.capacity_);
1656 swap(growth_left(), that.growth_left());
1657 swap(hash_ref(), that.hash_ref());
1658 swap(eq_ref(), that.eq_ref());
1659 swap(infoz_, that.infoz_);
1660 if (AllocTraits::propagate_on_container_swap::value) {
1661 swap(alloc_ref(), that.alloc_ref());
1662 } else {
1663 // If the allocators do not compare equal it is officially undefined
1664 // behavior. We choose to do nothing.
1665 }
1666 }
1667
1668#if !defined(PHMAP_NON_DETERMINISTIC)
1669 template<typename OutputArchive>
1670 bool phmap_dump(OutputArchive&) const;
1671
1672 template<typename InputArchive>
1673 bool phmap_load(InputArchive&);
1674#endif
1675
1676 void rehash(size_t n) {
1677 if (n == 0 && capacity_ == 0) return;
1678 if (n == 0 && size_ == 0) {
1679 destroy_slots();
1681 return;
1682 }
1683 // bitor is a faster way of doing `max` here. We will round up to the next
1684 // power-of-2-minus-1, so bitor is good enough.
1685 auto m = NormalizeCapacity((std::max)(n, size()));
1686 // n == 0 unconditionally rehashes as per the standard.
1687 if (n == 0 || m > capacity_) {
1688 resize(m);
1689 }
1690 }
1691
1693
1694 // Extension API: support for heterogeneous keys.
1695 //
1696 // std::unordered_set<std::string> s;
1697 // // Turns "abc" into std::string.
1698 // s.count("abc");
1699 //
1700 // ch_set<std::string> s;
1701 // // Uses "abc" directly without copying it into std::string.
1702 // s.count("abc");
1703 template <class K = key_type>
1704 size_t count(const key_arg<K>& key) const {
1705 return find(key) == end() ? size_t(0) : size_t(1);
1706 }
1707
1708 // Issues CPU prefetch instructions for the memory needed to find or insert
1709 // a key. Like all lookup functions, this support heterogeneous keys.
1710 //
1711 // NOTE: This is a very low level operation and should not be used without
1712 // specific benchmarks indicating its importance.
1713 void prefetch_hash(size_t hashval) const {
1714 (void)hashval;
1715#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
1716 auto seq = probe(hashval);
1717 _mm_prefetch((const char *)(ctrl_ + seq.offset()), _MM_HINT_NTA);
1718 _mm_prefetch((const char *)(slots_ + seq.offset()), _MM_HINT_NTA);
1719#elif defined(__GNUC__)
1720 auto seq = probe(hashval);
1721 __builtin_prefetch(static_cast<const void*>(ctrl_ + seq.offset()));
1722 __builtin_prefetch(static_cast<const void*>(slots_ + seq.offset()));
1723#endif // __GNUC__
1724 }
1725
1726 template <class K = key_type>
1727 void prefetch(const key_arg<K>& key) const {
1728 prefetch_hash(this->hash(key));
1729 }
1730
1731 // The API of find() has two extensions.
1732 //
1733 // 1. The hash can be passed by the user. It must be equal to the hash of the
1734 // key.
1735 //
1736 // 2. The type of the key argument doesn't have to be key_type. This is so
1737 // called heterogeneous key support.
1738 template <class K = key_type>
1739 iterator find(const key_arg<K>& key, size_t hashval) {
1740 size_t offset;
1741 if (find_impl(key, hashval, offset))
1742 return iterator_at(offset);
1743 else
1744 return end();
1745 }
1746
1747 template <class K = key_type>
1748 pointer find_ptr(const key_arg<K>& key, size_t hashval) {
1749 size_t offset;
1750 if (find_impl(key, hashval, offset))
1751 return &PolicyTraits::element(slots_ + offset);
1752 else
1753 return nullptr;
1754 }
1755
1756 template <class K = key_type>
1758 return find(key, this->hash(key));
1759 }
1760
1761 template <class K = key_type>
1762 const_iterator find(const key_arg<K>& key, size_t hashval) const {
1763 return const_cast<raw_hash_set*>(this)->find(key, hashval);
1764 }
1765 template <class K = key_type>
1766 const_iterator find(const key_arg<K>& key) const {
1767 return find(key, this->hash(key));
1768 }
1769
1770 template <class K = key_type>
1771 bool contains(const key_arg<K>& key) const {
1772 return find(key) != end();
1773 }
1774
1775 template <class K = key_type>
1776 bool contains(const key_arg<K>& key, size_t hashval) const {
1777 return find(key, hashval) != end();
1778 }
1779
1780 template <class K = key_type>
1781 std::pair<iterator, iterator> equal_range(const key_arg<K>& key) {
1782 auto it = find(key);
1783 if (it != end()) return {it, std::next(it)};
1784 return {it, it};
1785 }
1786 template <class K = key_type>
1787 std::pair<const_iterator, const_iterator> equal_range(
1788 const key_arg<K>& key) const {
1789 auto it = find(key);
1790 if (it != end()) return {it, std::next(it)};
1791 return {it, it};
1792 }
1793
1794 size_t bucket_count() const { return capacity_; }
1795 float load_factor() const {
1796 return capacity_ ? static_cast<double>(size()) / capacity_ : 0.0;
1797 }
1798 float max_load_factor() const { return 1.0f; }
1799 void max_load_factor(float) {
1800 // Does nothing.
1801 }
1802
1803 hasher hash_function() const { return hash_ref(); } // warning: doesn't match internal hash - use hash() member function
1804 key_equal key_eq() const { return eq_ref(); }
1806
1807 friend bool operator==(const raw_hash_set& a, const raw_hash_set& b) {
1808 if (a.size() != b.size()) return false;
1809 const raw_hash_set* outer = &a;
1810 const raw_hash_set* inner = &b;
1811 if (outer->capacity() > inner->capacity())
1812 std::swap(outer, inner);
1813 for (const value_type& elem : *outer)
1814 if (!inner->has_element(elem)) return false;
1815 return true;
1816 }
1817
1818 friend bool operator!=(const raw_hash_set& a, const raw_hash_set& b) {
1819 return !(a == b);
1820 }
1821
1822 friend void swap(raw_hash_set& a,
1823 raw_hash_set& b) noexcept(noexcept(a.swap(b))) {
1824 a.swap(b);
1825 }
1826
1827 template <class K>
1828 size_t hash(const K& key) const {
1829 return HashElement{hash_ref()}(key);
1830 }
1831
1832private:
1833 template <class Container, typename Enabler>
1835
1836 template <class K = key_type>
1837 bool find_impl(const key_arg<K>& key, size_t hashval, size_t& offset) {
1838 auto seq = probe(hashval);
1839 while (true) {
1840 Group g{ ctrl_ + seq.offset() };
1841 for (uint32_t i : g.Match((h2_t)H2(hashval))) {
1842 offset = seq.offset((size_t)i);
1844 EqualElement<K>{key, eq_ref()},
1845 PolicyTraits::element(slots_ + offset))))
1846 return true;
1847 }
1848 if (PHMAP_PREDICT_TRUE(g.MatchEmpty()))
1849 return false;
1850 seq.next();
1851 }
1852 }
1853
1855 {
1856 template <class K, class... Args>
1857 const_iterator operator()(const K& key, Args&&...) const {
1858 return s.find(key);
1859 }
1861 };
1862
1864 {
1865 template <class K, class... Args>
1866 size_t operator()(const K& key, Args&&...) const {
1867 return phmap_mix<sizeof(size_t)>()(h(key));
1868 }
1869 const hasher& h;
1870 };
1871
1872 template <class K1>
1874 {
1875 template <class K2, class... Args>
1876 bool operator()(const K2& lhs, Args&&...) const {
1877 return eq(lhs, rhs);
1878 }
1879 const K1& rhs;
1881 };
1882
1883 template <class K, class... Args>
1884 std::pair<iterator, bool> emplace_decomposable(const K& key, size_t hashval,
1885 Args&&... args)
1886 {
1887 auto res = find_or_prepare_insert(key, hashval);
1888 if (res.second) {
1889 emplace_at(res.first, std::forward<Args>(args)...);
1890 }
1891 return {iterator_at(res.first), res.second};
1892 }
1893
1895 {
1896 template <class K, class... Args>
1897 std::pair<iterator, bool> operator()(const K& key, Args&&... args) const {
1898 return s.emplace_decomposable(key, s.hash(key), std::forward<Args>(args)...);
1899 }
1901 };
1902
1904 template <class K, class... Args>
1905 std::pair<iterator, bool> operator()(const K& key, Args&&... args) const {
1906 return s.emplace_decomposable(key, hashval, std::forward<Args>(args)...);
1907 }
1909 size_t hashval;
1910 };
1911
1912 template <bool do_destroy>
1914 {
1915 template <class K, class... Args>
1916 std::pair<iterator, bool> operator()(const K& key, Args&&...) && {
1917 auto res = s.find_or_prepare_insert(key);
1918 if (res.second) {
1919 PolicyTraits::transfer(&s.alloc_ref(), s.slots_ + res.first, &slot);
1920 } else if (do_destroy) {
1922 }
1923 return {s.iterator_at(res.first), res.second};
1924 }
1926 // Constructed slot. Either moved into place or destroyed.
1928 };
1929
1930 template <bool do_destroy>
1932 {
1933 template <class K, class... Args>
1934 std::pair<iterator, bool> operator()(const K& key, Args&&...) && {
1935 auto res = s.find_or_prepare_insert(key, hashval);
1936 if (res.second) {
1937 PolicyTraits::transfer(&s.alloc_ref(), s.slots_ + res.first, &slot);
1938 } else if (do_destroy) {
1940 }
1941 return {s.iterator_at(res.first), res.second};
1942 }
1944 // Constructed slot. Either moved into place or destroyed.
1946 size_t &hashval;
1947 };
1948
1949 // "erases" the object from the container, except that it doesn't actually
1950 // destroy the object. It only updates all the metadata of the class.
1951 // This can be used in conjunction with Policy::transfer to move the object to
1952 // another place.
1954 assert(IsFull(*it.inner_.ctrl_) && "erasing a dangling iterator");
1955 --size_;
1956 const size_t index = (size_t)(it.inner_.ctrl_ - ctrl_);
1957 const size_t index_before = (index - Group::kWidth) & capacity_;
1958 const auto empty_after = Group(it.inner_.ctrl_).MatchEmpty();
1959 const auto empty_before = Group(ctrl_ + index_before).MatchEmpty();
1960
1961 // We count how many consecutive non empties we have to the right and to the
1962 // left of `it`. If the sum is >= kWidth then there is at least one probe
1963 // window that might have seen a full group.
1964 bool was_never_full =
1965 empty_before && empty_after &&
1966 static_cast<size_t>(empty_after.TrailingZeros() +
1967 empty_before.LeadingZeros()) < Group::kWidth;
1968
1969 set_ctrl(index, was_never_full ? kEmpty : kDeleted);
1970 growth_left() += was_never_full;
1972 }
1973
1974 void initialize_slots(size_t new_capacity) {
1975 assert(new_capacity);
1976 if (std::is_same<SlotAlloc, std::allocator<slot_type>>::value &&
1977 slots_ == nullptr) {
1978 infoz_ = Sample();
1979 }
1980
1981 auto layout = MakeLayout(new_capacity);
1982 char* mem = static_cast<char*>(
1983 Allocate<Layout::Alignment()>(&alloc_ref(), layout.AllocSize()));
1984 ctrl_ = reinterpret_cast<ctrl_t*>(layout.template Pointer<0>(mem));
1985 slots_ = layout.template Pointer<1>(mem);
1986 reset_ctrl(new_capacity);
1987 reset_growth_left(new_capacity);
1988 infoz_.RecordStorageChanged(size_, new_capacity);
1989 }
1990
1992 if (!capacity_) return;
1993 for (size_t i = 0; i != capacity_; ++i) {
1994 if (IsFull(ctrl_[i])) {
1996 }
1997 }
1998 auto layout = MakeLayout(capacity_);
1999 // Unpoison before returning the memory to the allocator.
2001 Deallocate<Layout::Alignment()>(&alloc_ref(), ctrl_, layout.AllocSize());
2002 ctrl_ = EmptyGroup();
2003 slots_ = nullptr;
2004 size_ = 0;
2005 capacity_ = 0;
2006 growth_left() = 0;
2007 }
2008
2009 void resize(size_t new_capacity) {
2010 assert(IsValidCapacity(new_capacity));
2011 auto* old_ctrl = ctrl_;
2012 auto* old_slots = slots_;
2013 const size_t old_capacity = capacity_;
2014 initialize_slots(new_capacity);
2015 capacity_ = new_capacity;
2016
2017 for (size_t i = 0; i != old_capacity; ++i) {
2018 if (IsFull(old_ctrl[i])) {
2019 size_t hashval = PolicyTraits::apply(HashElement{hash_ref()},
2020 PolicyTraits::element(old_slots + i));
2021 auto target = find_first_non_full(hashval);
2022 size_t new_i = target.offset;
2023 set_ctrl(new_i, H2(hashval));
2024 PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, old_slots + i);
2025 }
2026 }
2027 if (old_capacity) {
2029 sizeof(slot_type) * old_capacity);
2030 auto layout = MakeLayout(old_capacity);
2031 Deallocate<Layout::Alignment()>(&alloc_ref(), old_ctrl,
2032 layout.AllocSize());
2033 }
2034 }
2035
2037 assert(IsValidCapacity(capacity_));
2038 assert(!is_small());
2039 // Algorithm:
2040 // - mark all DELETED slots as EMPTY
2041 // - mark all FULL slots as DELETED
2042 // - for each slot marked as DELETED
2043 // hash = Hash(element)
2044 // target = find_first_non_full(hash)
2045 // if target is in the same group
2046 // mark slot as FULL
2047 // else if target is EMPTY
2048 // transfer element to target
2049 // mark slot as EMPTY
2050 // mark target as FULL
2051 // else if target is DELETED
2052 // swap current element with target element
2053 // mark target as FULL
2054 // repeat procedure for current slot with moved from element (target)
2056 typename std::aligned_storage<sizeof(slot_type), alignof(slot_type)>::type
2057 raw;
2058 slot_type* slot = reinterpret_cast<slot_type*>(&raw);
2059 for (size_t i = 0; i != capacity_; ++i) {
2060 if (!IsDeleted(ctrl_[i])) continue;
2061 size_t hashval = PolicyTraits::apply(HashElement{hash_ref()},
2063 auto target = find_first_non_full(hashval);
2064 size_t new_i = target.offset;
2065
2066 // Verify if the old and new i fall within the same group wrt the hashval.
2067 // If they do, we don't need to move the object as it falls already in the
2068 // best probe we can.
2069 const auto probe_index = [&](size_t pos) {
2070 return ((pos - probe(hashval).offset()) & capacity_) / Group::kWidth;
2071 };
2072
2073 // Element doesn't move.
2074 if (PHMAP_PREDICT_TRUE(probe_index(new_i) == probe_index(i))) {
2075 set_ctrl(i, H2(hashval));
2076 continue;
2077 }
2078 if (IsEmpty(ctrl_[new_i])) {
2079 // Transfer element to the empty spot.
2080 // set_ctrl poisons/unpoisons the slots so we have to call it at the
2081 // right time.
2082 set_ctrl(new_i, H2(hashval));
2084 set_ctrl(i, kEmpty);
2085 } else {
2086 assert(IsDeleted(ctrl_[new_i]));
2087 set_ctrl(new_i, H2(hashval));
2088 // Until we are done rehashing, DELETED marks previously FULL slots.
2089 // Swap i and new_i elements.
2092 PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, slot);
2093 --i; // repeat
2094 }
2095 }
2097 }
2098
2100 if (capacity_ == 0) {
2101 resize(1);
2102 } else if (size() <= CapacityToGrowth(capacity()) / 2) {
2103 // Squash DELETED without growing if there is enough capacity.
2105 } else {
2106 // Otherwise grow the container.
2107 resize(capacity_ * 2 + 1);
2108 }
2109 }
2110
2111 bool has_element(const value_type& elem, size_t hashval) const {
2112 auto seq = probe(hashval);
2113 while (true) {
2114 Group g{ctrl_ + seq.offset()};
2115 for (uint32_t i : g.Match((h2_t)H2(hashval))) {
2116 if (PHMAP_PREDICT_TRUE(PolicyTraits::element(slots_ + seq.offset((size_t)i)) ==
2117 elem))
2118 return true;
2119 }
2120 if (PHMAP_PREDICT_TRUE(g.MatchEmpty())) return false;
2121 seq.next();
2122 assert(seq.getindex() < capacity_ && "full table!");
2123 }
2124 return false;
2125 }
2126
2127 bool has_element(const value_type& elem) const {
2128 size_t hashval = PolicyTraits::apply(HashElement{hash_ref()}, elem);
2129 return has_element(elem, hashval);
2130 }
2131
2132 // Probes the raw_hash_set with the probe sequence for hash and returns the
2133 // pointer to the first empty or deleted slot.
2134 // NOTE: this function must work with tables having both kEmpty and kDelete
2135 // in one group. Such tables appears during drop_deletes_without_resize.
2136 //
2137 // This function is very useful when insertions happen and:
2138 // - the input is already a set
2139 // - there are enough slots
2140 // - the element with the hash is not in the table
2141 struct FindInfo
2142 {
2143 size_t offset;
2145 };
2147 auto seq = probe(hashval);
2148 while (true) {
2149 Group g{ctrl_ + seq.offset()};
2150 auto mask = g.MatchEmptyOrDeleted();
2151 if (mask) {
2152 return {seq.offset((size_t)mask.LowestBitSet()), seq.getindex()};
2153 }
2154 assert(seq.getindex() < capacity_ && "full table!");
2155 seq.next();
2156 }
2157 }
2158
2159 // TODO(alkis): Optimize this assuming *this and that don't overlap.
2160 raw_hash_set& move_assign(raw_hash_set&& that, std::true_type) {
2161 raw_hash_set tmp(std::move(that));
2162 swap(tmp);
2163 return *this;
2164 }
2165 raw_hash_set& move_assign(raw_hash_set&& that, std::false_type) {
2166 raw_hash_set tmp(std::move(that), alloc_ref());
2167 swap(tmp);
2168 return *this;
2169 }
2170
2171protected:
2172 template <class K>
2173 std::pair<size_t, bool> find_or_prepare_insert(const K& key, size_t hashval) {
2174 auto seq = probe(hashval);
2175 while (true) {
2176 Group g{ctrl_ + seq.offset()};
2177 for (uint32_t i : g.Match((h2_t)H2(hashval))) {
2179 EqualElement<K>{key, eq_ref()},
2180 PolicyTraits::element(slots_ + seq.offset((size_t)i)))))
2181 return {seq.offset((size_t)i), false};
2182 }
2183 if (PHMAP_PREDICT_TRUE(g.MatchEmpty())) break;
2184 seq.next();
2185 }
2186 return {prepare_insert(hashval), true};
2187 }
2188
2189 template <class K>
2190 std::pair<size_t, bool> find_or_prepare_insert(const K& key) {
2191 return find_or_prepare_insert(key, this->hash(key));
2192 }
2193
2195 auto target = find_first_non_full(hashval);
2196 if (PHMAP_PREDICT_FALSE(growth_left() == 0 &&
2197 !IsDeleted(ctrl_[target.offset]))) {
2199 target = find_first_non_full(hashval);
2200 }
2201 ++size_;
2202 growth_left() -= IsEmpty(ctrl_[target.offset]);
2203 set_ctrl(target.offset, H2(hashval));
2204 infoz_.RecordInsert(hashval, target.probe_length);
2205 return target.offset;
2206 }
2207
2208 // Constructs the value in the space pointed by the iterator. This only works
2209 // after an unsuccessful find_or_prepare_insert() and before any other
2210 // modifications happen in the raw_hash_set.
2211 //
2212 // PRECONDITION: i is an index returned from find_or_prepare_insert(k), where
2213 // k is the key decomposed from `forward<Args>(args)...`, and the bool
2214 // returned by find_or_prepare_insert(k) was true.
2215 // POSTCONDITION: *m.iterator_at(i) == value_type(forward<Args>(args)...).
2216 template <class... Args>
2217 void emplace_at(size_t i, Args&&... args) {
2219 std::forward<Args>(args)...);
2220
2221 assert(PolicyTraits::apply(FindElement{*this}, *iterator_at(i)) ==
2222 iterator_at(i) &&
2223 "constructed value does not match the lookup key");
2224 }
2225
2226 iterator iterator_at(size_t i) { return {ctrl_ + i, slots_ + i}; }
2227 const_iterator iterator_at(size_t i) const { return {ctrl_ + i, slots_ + i}; }
2228
2229private:
2231
2232 probe_seq<Group::kWidth> probe(size_t hashval) const {
2233 return probe_seq<Group::kWidth>(H1(hashval, ctrl_), capacity_);
2234 }
2235
2236 // Reset all ctrl bytes back to kEmpty, except the sentinel.
2237 void reset_ctrl(size_t capacity) {
2238 std::memset(ctrl_, kEmpty, capacity + Group::kWidth);
2241 }
2242
2245 }
2246
2247 // Sets the control byte, and if `i < Group::kWidth`, set the cloned byte at
2248 // the end too.
2249 void set_ctrl(size_t i, ctrl_t h) {
2250 assert(i < capacity_);
2251
2252 if (IsFull(h)) {
2254 } else {
2256 }
2257
2258 ctrl_[i] = h;
2259 ctrl_[((i - Group::kWidth) & capacity_) + 1 +
2260 ((Group::kWidth - 1) & capacity_)] = h;
2261 }
2262
2263 size_t& growth_left() { return settings_.template get<0>(); }
2264
2265 template <size_t N,
2266 template <class, class, class, class> class RefSet,
2267 class M, class P, class H, class E, class A>
2268 friend class parallel_hash_set;
2269
2270 template <size_t N,
2271 template <class, class, class, class> class RefSet,
2272 class M, class P, class H, class E, class A>
2273 friend class parallel_hash_map;
2274
2275 // The representation of the object has two modes:
2276 // - small: For capacities < kWidth-1
2277 // - large: For the rest.
2278 //
2279 // Differences:
2280 // - In small mode we are able to use the whole capacity. The extra control
2281 // bytes give us at least one "empty" control byte to stop the iteration.
2282 // This is important to make 1 a valid capacity.
2283 //
2284 // - In small mode only the first `capacity()` control bytes after the
2285 // sentinel are valid. The rest contain dummy kEmpty values that do not
2286 // represent a real slot. This is important to take into account on
2287 // find_first_non_full(), where we never try ShouldInsertBackwards() for
2288 // small tables.
2289 bool is_small() const { return capacity_ < Group::kWidth - 1; }
2290
2291 hasher& hash_ref() { return settings_.template get<1>(); }
2292 const hasher& hash_ref() const { return settings_.template get<1>(); }
2293 key_equal& eq_ref() { return settings_.template get<2>(); }
2294 const key_equal& eq_ref() const { return settings_.template get<2>(); }
2295 allocator_type& alloc_ref() { return settings_.template get<3>(); }
2296 const allocator_type& alloc_ref() const {
2297 return settings_.template get<3>();
2298 }
2299
2300 // TODO(alkis): Investigate removing some of these fields:
2301 // - ctrl/slots can be derived from each other
2302 // - size can be moved into the slot array
2303 ctrl_t* ctrl_ = EmptyGroup(); // [(capacity + 1) * ctrl_t]
2304 slot_type* slots_ = nullptr; // [capacity * slot_type]
2305 size_t size_ = 0; // number of full slots
2306 size_t capacity_ = 0; // total number of slots
2308 phmap::priv::CompressedTuple<size_t /* growth_left */, hasher,
2311};
2312
2313
2314// --------------------------------------------------------------------------
2315// --------------------------------------------------------------------------
2316template <class Policy, class Hash, class Eq, class Alloc>
2317class raw_hash_map : public raw_hash_set<Policy, Hash, Eq, Alloc>
2318{
2319 // P is Policy. It's passed as a template argument to support maps that have
2320 // incomplete types as values, as in unordered_map<K, IncompleteType>.
2321 // MappedReference<> may be a non-reference type.
2322 template <class P>
2323 using MappedReference = decltype(P::value(
2324 std::addressof(std::declval<typename raw_hash_map::reference>())));
2325
2326 // MappedConstReference<> may be a non-reference type.
2327 template <class P>
2328 using MappedConstReference = decltype(P::value(
2329 std::addressof(std::declval<typename raw_hash_map::const_reference>())));
2330
2333
2335
2336public:
2337 using key_type = typename Policy::key_type;
2338 using mapped_type = typename Policy::mapped_type;
2339 template <class K>
2340 using key_arg = typename KeyArgImpl::template type<K, key_type>;
2341
2342 static_assert(!std::is_reference<key_type>::value, "");
2343
2344 // TODO(b/187807849): Evaluate whether to support reference mapped_type and
2345 // remove this assertion if/when it is supported.
2346 static_assert(!std::is_reference<mapped_type>::value, "");
2347
2348 using iterator = typename raw_hash_map::raw_hash_set::iterator;
2349 using const_iterator = typename raw_hash_map::raw_hash_set::const_iterator;
2350
2352 using Base::raw_hash_set; // use raw_hash_set constructor
2353
2354 // The last two template parameters ensure that both arguments are rvalues
2355 // (lvalue arguments are handled by the overloads below). This is necessary
2356 // for supporting bitfield arguments.
2357 //
2358 // union { int n : 1; };
2359 // flat_hash_map<int, int> m;
2360 // m.insert_or_assign(n, n);
2361 template <class K = key_type, class V = mapped_type, K* = nullptr,
2362 V* = nullptr>
2363 std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v) {
2364 return insert_or_assign_impl(std::forward<K>(k), std::forward<V>(v));
2365 }
2366
2367 template <class K = key_type, class V = mapped_type, K* = nullptr>
2368 std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v) {
2369 return insert_or_assign_impl(std::forward<K>(k), v);
2370 }
2371
2372 template <class K = key_type, class V = mapped_type, V* = nullptr>
2373 std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v) {
2374 return insert_or_assign_impl(k, std::forward<V>(v));
2375 }
2376
2377 template <class K = key_type, class V = mapped_type>
2378 std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const V& v) {
2379 return insert_or_assign_impl(k, v);
2380 }
2381
2382 template <class K = key_type, class V = mapped_type, K* = nullptr,
2383 V* = nullptr>
2385 return insert_or_assign(std::forward<K>(k), std::forward<V>(v)).first;
2386 }
2387
2388 template <class K = key_type, class V = mapped_type, K* = nullptr>
2390 return insert_or_assign(std::forward<K>(k), v).first;
2391 }
2392
2393 template <class K = key_type, class V = mapped_type, V* = nullptr>
2395 return insert_or_assign(k, std::forward<V>(v)).first;
2396 }
2397
2398 template <class K = key_type, class V = mapped_type>
2400 return insert_or_assign(k, v).first;
2401 }
2402
2403 template <class K = key_type, class... Args,
2404 typename std::enable_if<
2405 !std::is_convertible<K, const_iterator>::value, int>::type = 0,
2406 K* = nullptr>
2407 std::pair<iterator, bool> try_emplace(key_arg<K>&& k, Args&&... args) {
2408 return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
2409 }
2410
2411 template <class K = key_type, class... Args,
2412 typename std::enable_if<
2413 !std::is_convertible<K, const_iterator>::value, int>::type = 0>
2414 std::pair<iterator, bool> try_emplace(const key_arg<K>& k, Args&&... args) {
2415 return try_emplace_impl(k, std::forward<Args>(args)...);
2416 }
2417
2418 template <class K = key_type, class... Args, K* = nullptr>
2420 return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
2421 }
2422
2423 template <class K = key_type, class... Args>
2424 iterator try_emplace(const_iterator, const key_arg<K>& k, Args&&... args) {
2425 return try_emplace(k, std::forward<Args>(args)...).first;
2426 }
2427
2428 template <class K = key_type, class P = Policy>
2430 auto it = this->find(key);
2431 if (it == this->end())
2432 phmap::base_internal::ThrowStdOutOfRange("phmap at(): lookup non-existent key");
2433 return Policy::value(&*it);
2434 }
2435
2436 template <class K = key_type, class P = Policy>
2438 auto it = this->find(key);
2439 if (it == this->end())
2440 phmap::base_internal::ThrowStdOutOfRange("phmap at(): lookup non-existent key");
2441 return Policy::value(&*it);
2442 }
2443
2444 template <class K = key_type, class P = Policy, K* = nullptr>
2446 return Policy::value(&*try_emplace(std::forward<K>(key)).first);
2447 }
2448
2449 template <class K = key_type, class P = Policy>
2451 return Policy::value(&*try_emplace(key).first);
2452 }
2453
2454private:
2455 template <class K, class V>
2456 std::pair<iterator, bool> insert_or_assign_impl(K&& k, V&& v) {
2457 auto res = this->find_or_prepare_insert(k);
2458 if (res.second)
2459 this->emplace_at(res.first, std::forward<K>(k), std::forward<V>(v));
2460 else
2461 Policy::value(&*this->iterator_at(res.first)) = std::forward<V>(v);
2462 return {this->iterator_at(res.first), res.second};
2463 }
2464
2465 template <class K = key_type, class... Args>
2466 std::pair<iterator, bool> try_emplace_impl(K&& k, Args&&... args) {
2467 auto res = this->find_or_prepare_insert(k);
2468 if (res.second)
2469 this->emplace_at(res.first, std::piecewise_construct,
2470 std::forward_as_tuple(std::forward<K>(k)),
2471 std::forward_as_tuple(std::forward<Args>(args)...));
2472 return {this->iterator_at(res.first), res.second};
2473 }
2474};
2475
2476// ----------------------------------------------------------------------------
2477// ----------------------------------------------------------------------------
2478// Returns "random" seed.
2479inline size_t RandomSeed()
2480{
2481#if PHMAP_HAVE_THREAD_LOCAL
2482 static thread_local size_t counter = 0;
2483 size_t value = ++counter;
2484#else // PHMAP_HAVE_THREAD_LOCAL
2485 static std::atomic<size_t> counter(0);
2486 size_t value = counter.fetch_add(1, std::memory_order_relaxed);
2487#endif // PHMAP_HAVE_THREAD_LOCAL
2488 return value ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(&counter));
2489}
2490
2491// ----------------------------------------------------------------------------
2492// ----------------------------------------------------------------------------
2493template <size_t N,
2494 template <class, class, class, class> class RefSet,
2495 class Mtx_,
2496 class Policy, class Hash, class Eq, class Alloc>
2498{
2502
2503 static_assert(N <= 12, "N = 12 means 4096 hash tables!");
2504 constexpr static size_t num_tables = 1 << N;
2505 constexpr static size_t mask = num_tables - 1;
2506
2507public:
2508 using EmbeddedSet = RefSet<Policy, Hash, Eq, Alloc>;
2509 using EmbeddedIterator= typename EmbeddedSet::iterator;
2510 using EmbeddedConstIterator= typename EmbeddedSet::const_iterator;
2511 using constructor = typename EmbeddedSet::constructor;
2515 using allocator_type = Alloc;
2516 using size_type = size_t;
2517 using difference_type = ptrdiff_t;
2518 using hasher = Hash;
2519 using key_equal = Eq;
2520 using policy_type = Policy;
2525 allocator_type>::template rebind_traits<value_type>::pointer;
2527 allocator_type>::template rebind_traits<value_type>::const_pointer;
2528
2529 // Alias used for heterogeneous lookup functions.
2530 // `key_arg<K>` evaluates to `K` when the functors are transparent and to
2531 // `key_type` otherwise. It permits template argument deduction on `K` for the
2532 // transparent case.
2533 // --------------------------------------------------------------------
2534 template <class K>
2535 using key_arg = typename KeyArgImpl::template type<K, key_type>;
2536
2537protected:
2539
2540 // --------------------------------------------------------------------
2541 struct Inner : public Lockable
2542 {
2543 struct Params
2544 {
2549 };
2550
2552
2553 Inner(Params const &p) : set_(p.bucket_cnt, p.hashfn, p.eq, p.alloc)
2554 {}
2555
2556 bool operator==(const Inner& o) const
2557 {
2558 typename Lockable::SharedLocks l(const_cast<Inner &>(*this), const_cast<Inner &>(o));
2559 return set_ == o.set_;
2560 }
2561
2563 };
2564
2565private:
2566 // Give an early error when key_type is not hashable/eq.
2567 // --------------------------------------------------------------------
2568 auto KeyTypeCanBeHashed(const Hash& h, const key_type& k) -> decltype(h(k));
2569 auto KeyTypeCanBeEq(const Eq& eq, const key_type& k) -> decltype(eq(k, k));
2570
2572
2573 static_assert(std::is_lvalue_reference<reference>::value,
2574 "Policy::element() must return a reference");
2575
2576 template <typename T>
2577 struct SameAsElementReference : std::is_same<
2578 typename std::remove_cv<typename std::remove_reference<reference>::type>::type,
2579 typename std::remove_cv<typename std::remove_reference<T>::type>::type> {};
2580
2581 // An enabler for insert(T&&): T must be convertible to init_type or be the
2582 // same as [cv] value_type [ref].
2583 // Note: we separate SameAsElementReference into its own type to avoid using
2584 // reference unless we need to. MSVC doesn't seem to like it in some
2585 // cases.
2586 // --------------------------------------------------------------------
2587 template <class T>
2588 using RequiresInsertable = typename std::enable_if<
2591 int>::type;
2592
2593 // RequiresNotInit is a workaround for gcc prior to 7.1.
2594 // See https://godbolt.org/g/Y4xsUh.
2595 template <class T>
2597 typename std::enable_if<!std::is_same<T, init_type>::value, int>::type;
2598
2599 template <class... Ts>
2601
2602public:
2603 static_assert(std::is_same<pointer, value_type*>::value,
2604 "Allocators with custom pointer types are not supported");
2605 static_assert(std::is_same<const_pointer, const value_type*>::value,
2606 "Allocators with custom pointer types are not supported");
2607
2608 // --------------------- i t e r a t o r ------------------------------
2610 {
2611 friend class parallel_hash_set;
2612
2613 public:
2614 using iterator_category = std::forward_iterator_tag;
2618 const value_type&, value_type&>;
2623 using EmbeddedIterator = typename EmbeddedSet::iterator;
2624
2626
2627 reference operator*() const { return *it_; }
2628 pointer operator->() const { return &operator*(); }
2629
2631 assert(inner_); // null inner means we are already at the end
2632 ++it_;
2633 skip_empty();
2634 return *this;
2635 }
2636
2638 assert(inner_); // null inner means we are already at the end
2639 auto tmp = *this;
2640 ++*this;
2641 return tmp;
2642 }
2643
2644 friend bool operator==(const iterator& a, const iterator& b) {
2645 return a.inner_ == b.inner_ && (!a.inner_ || a.it_ == b.it_);
2646 }
2647
2648 friend bool operator!=(const iterator& a, const iterator& b) {
2649 return !(a == b);
2650 }
2651
2652 private:
2653 iterator(Inner *inner, Inner *inner_end, const EmbeddedIterator& it) :
2654 inner_(inner), inner_end_(inner_end), it_(it) { // for begin() and end()
2655 if (inner)
2656 it_end_ = inner->set_.end();
2657 }
2658
2659 void skip_empty() {
2660 while (it_ == it_end_) {
2661 ++inner_;
2662 if (inner_ == inner_end_) {
2663 inner_ = nullptr; // marks end()
2664 break;
2665 }
2666 else {
2667 it_ = inner_->set_.begin();
2668 it_end_ = inner_->set_.end();
2669 }
2670 }
2671 }
2672
2673 Inner *inner_ = nullptr;
2674 Inner *inner_end_ = nullptr;
2676 };
2677
2678 // --------------------- c o n s t i t e r a t o r -----------------
2680 {
2681 friend class parallel_hash_set;
2682
2683 public:
2690
2692 // Implicit construction from iterator.
2694
2695 reference operator*() const { return *(iter_); }
2696 pointer operator->() const { return iter_.operator->(); }
2697
2699 ++iter_;
2700 return *this;
2701 }
2703
2704 friend bool operator==(const const_iterator& a, const const_iterator& b) {
2705 return a.iter_ == b.iter_;
2706 }
2707 friend bool operator!=(const const_iterator& a, const const_iterator& b) {
2708 return !(a == b);
2709 }
2710
2711 private:
2712 const_iterator(const Inner *inner, const Inner *inner_end, const EmbeddedIterator& it)
2713 : iter_(const_cast<Inner**>(inner),
2714 const_cast<Inner**>(inner_end),
2715 const_cast<EmbeddedIterator*>(it)) {}
2716
2718 };
2719
2722
2723 // ------------------------- c o n s t r u c t o r s ------------------
2724
2726 std::is_nothrow_default_constructible<hasher>::value&&
2727 std::is_nothrow_default_constructible<key_equal>::value&&
2728 std::is_nothrow_default_constructible<allocator_type>::value) {}
2729
2730#if (__cplusplus >= 201703L || _MSVC_LANG >= 201402) && (defined(_MSC_VER) || defined(__clang__) || (defined(__GNUC__) && __GNUC__ > 6))
2731 explicit parallel_hash_set(size_t bucket_cnt,
2732 const hasher& hash_param = hasher(),
2733 const key_equal& eq = key_equal(),
2734 const allocator_type& alloc = allocator_type()) :
2735 parallel_hash_set(typename Inner::Params{bucket_cnt, hash_param, eq, alloc},
2737 {}
2738
2739 template <std::size_t... i>
2740 parallel_hash_set(typename Inner::Params const &p,
2741 phmap::index_sequence<i...>) : sets_{((void)i, p)...}
2742 {}
2743#else
2744 explicit parallel_hash_set(size_t bucket_cnt,
2745 const hasher& hash_param = hasher(),
2746 const key_equal& eq = key_equal(),
2747 const allocator_type& alloc = allocator_type()) {
2748 for (auto& inner : sets_)
2749 inner.set_ = EmbeddedSet(bucket_cnt / N, hash_param, eq, alloc);
2750 }
2751#endif
2752
2753 parallel_hash_set(size_t bucket_cnt,
2754 const hasher& hash_param,
2755 const allocator_type& alloc)
2756 : parallel_hash_set(bucket_cnt, hash_param, key_equal(), alloc) {}
2757
2758 parallel_hash_set(size_t bucket_cnt, const allocator_type& alloc)
2759 : parallel_hash_set(bucket_cnt, hasher(), key_equal(), alloc) {}
2760
2761 explicit parallel_hash_set(const allocator_type& alloc)
2762 : parallel_hash_set(0, hasher(), key_equal(), alloc) {}
2763
2764 template <class InputIter>
2765 parallel_hash_set(InputIter first, InputIter last, size_t bucket_cnt = 0,
2766 const hasher& hash_param = hasher(), const key_equal& eq = key_equal(),
2767 const allocator_type& alloc = allocator_type())
2768 : parallel_hash_set(bucket_cnt, hash_param, eq, alloc) {
2769 insert(first, last);
2770 }
2771
2772 template <class InputIter>
2773 parallel_hash_set(InputIter first, InputIter last, size_t bucket_cnt,
2774 const hasher& hash_param, const allocator_type& alloc)
2775 : parallel_hash_set(first, last, bucket_cnt, hash_param, key_equal(), alloc) {}
2776
2777 template <class InputIter>
2778 parallel_hash_set(InputIter first, InputIter last, size_t bucket_cnt,
2779 const allocator_type& alloc)
2780 : parallel_hash_set(first, last, bucket_cnt, hasher(), key_equal(), alloc) {}
2781
2782 template <class InputIter>
2783 parallel_hash_set(InputIter first, InputIter last, const allocator_type& alloc)
2784 : parallel_hash_set(first, last, 0, hasher(), key_equal(), alloc) {}
2785
2786 // Instead of accepting std::initializer_list<value_type> as the first
2787 // argument like std::unordered_set<value_type> does, we have two overloads
2788 // that accept std::initializer_list<T> and std::initializer_list<init_type>.
2789 // This is advantageous for performance.
2790 //
2791 // // Turns {"abc", "def"} into std::initializer_list<std::string>, then copies
2792 // // the strings into the set.
2793 // std::unordered_set<std::string> s = {"abc", "def"};
2794 //
2795 // // Turns {"abc", "def"} into std::initializer_list<const char*>, then
2796 // // copies the strings into the set.
2797 // phmap::flat_hash_set<std::string> s = {"abc", "def"};
2798 //
2799 // The same trick is used in insert().
2800 //
2801 // The enabler is necessary to prevent this constructor from triggering where
2802 // the copy constructor is meant to be called.
2803 //
2804 // phmap::flat_hash_set<int> a, b{a};
2805 //
2806 // RequiresNotInit<T> is a workaround for gcc prior to 7.1.
2807 // --------------------------------------------------------------------
2808 template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
2809 parallel_hash_set(std::initializer_list<T> init, size_t bucket_cnt = 0,
2810 const hasher& hash_param = hasher(), const key_equal& eq = key_equal(),
2811 const allocator_type& alloc = allocator_type())
2812 : parallel_hash_set(init.begin(), init.end(), bucket_cnt, hash_param, eq, alloc) {}
2813
2814 parallel_hash_set(std::initializer_list<init_type> init, size_t bucket_cnt = 0,
2815 const hasher& hash_param = hasher(), const key_equal& eq = key_equal(),
2816 const allocator_type& alloc = allocator_type())
2817 : parallel_hash_set(init.begin(), init.end(), bucket_cnt, hash_param, eq, alloc) {}
2818
2819 template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
2820 parallel_hash_set(std::initializer_list<T> init, size_t bucket_cnt,
2821 const hasher& hash_param, const allocator_type& alloc)
2822 : parallel_hash_set(init, bucket_cnt, hash_param, key_equal(), alloc) {}
2823
2824 parallel_hash_set(std::initializer_list<init_type> init, size_t bucket_cnt,
2825 const hasher& hash_param, const allocator_type& alloc)
2826 : parallel_hash_set(init, bucket_cnt, hash_param, key_equal(), alloc) {}
2827
2828 template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
2829 parallel_hash_set(std::initializer_list<T> init, size_t bucket_cnt,
2830 const allocator_type& alloc)
2831 : parallel_hash_set(init, bucket_cnt, hasher(), key_equal(), alloc) {}
2832
2833 parallel_hash_set(std::initializer_list<init_type> init, size_t bucket_cnt,
2834 const allocator_type& alloc)
2835 : parallel_hash_set(init, bucket_cnt, hasher(), key_equal(), alloc) {}
2836
2837 template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
2838 parallel_hash_set(std::initializer_list<T> init, const allocator_type& alloc)
2839 : parallel_hash_set(init, 0, hasher(), key_equal(), alloc) {}
2840
2841 parallel_hash_set(std::initializer_list<init_type> init,
2842 const allocator_type& alloc)
2843 : parallel_hash_set(init, 0, hasher(), key_equal(), alloc) {}
2844
2846 : parallel_hash_set(that, AllocTraits::select_on_container_copy_construction(
2847 that.alloc_ref())) {}
2848
2850 : parallel_hash_set(0, that.hash_ref(), that.eq_ref(), a) {
2851 for (size_t i=0; i<num_tables; ++i)
2852 sets_[i].set_ = { that.sets_[i].set_, a };
2853 }
2854
2856 std::is_nothrow_copy_constructible<hasher>::value&&
2857 std::is_nothrow_copy_constructible<key_equal>::value&&
2858 std::is_nothrow_copy_constructible<allocator_type>::value)
2859 : parallel_hash_set(std::move(that), that.alloc_ref()) {
2860 }
2861
2863 {
2864 for (size_t i=0; i<num_tables; ++i)
2865 sets_[i].set_ = { std::move(that.sets_[i]).set_, a };
2866 }
2867
2869 for (size_t i=0; i<num_tables; ++i)
2870 sets_[i].set_ = that.sets_[i].set_;
2871 return *this;
2872 }
2873
2876 std::is_nothrow_move_assignable<hasher>::value &&
2877 std::is_nothrow_move_assignable<key_equal>::value) {
2878 for (size_t i=0; i<num_tables; ++i)
2879 sets_[i].set_ = std::move(that.sets_[i].set_);
2880 return *this;
2881 }
2882
2884
2886 auto it = iterator(&sets_[0], &sets_[0] + num_tables, sets_[0].set_.begin());
2887 it.skip_empty();
2888 return it;
2889 }
2890
2891 iterator end() { return iterator(); }
2892 const_iterator begin() const { return const_cast<parallel_hash_set *>(this)->begin(); }
2893 const_iterator end() const { return const_cast<parallel_hash_set *>(this)->end(); }
2894 const_iterator cbegin() const { return begin(); }
2895 const_iterator cend() const { return end(); }
2896
2897 bool empty() const { return !size(); }
2898
2899 size_t size() const {
2900 size_t sz = 0;
2901 for (const auto& inner : sets_)
2902 sz += inner.set_.size();
2903 return sz;
2904 }
2905
2906 size_t capacity() const {
2907 size_t c = 0;
2908 for (const auto& inner : sets_)
2909 c += inner.set_.capacity();
2910 return c;
2911 }
2912
2913 size_t max_size() const { return (std::numeric_limits<size_t>::max)(); }
2914
2916 for (auto& inner : sets_)
2917 {
2918 typename Lockable::UniqueLock m(inner);
2919 inner.set_.clear();
2920 }
2921 }
2922
2923 // extension - clears only soecified submap
2924 // ----------------------------------------
2925 void clear(std::size_t submap_index) {
2926 Inner& inner = sets_[submap_index];
2927 typename Lockable::UniqueLock m(inner);
2928 inner.set_.clear();
2929 }
2930
2931 // This overload kicks in when the argument is an rvalue of insertable and
2932 // decomposable type other than init_type.
2933 //
2934 // flat_hash_map<std::string, int> m;
2935 // m.insert(std::make_pair("abc", 42));
2936 // --------------------------------------------------------------------
2937 template <class T, RequiresInsertable<T> = 0,
2938 typename std::enable_if<IsDecomposable<T>::value, int>::type = 0,
2939 T* = nullptr>
2940 std::pair<iterator, bool> insert(T&& value) {
2941 return emplace(std::forward<T>(value));
2942 }
2943
2944 // This overload kicks in when the argument is a bitfield or an lvalue of
2945 // insertable and decomposable type.
2946 //
2947 // union { int n : 1; };
2948 // flat_hash_set<int> s;
2949 // s.insert(n);
2950 //
2951 // flat_hash_set<std::string> s;
2952 // const char* p = "hello";
2953 // s.insert(p);
2954 //
2955 // TODO(romanp): Once we stop supporting gcc 5.1 and below, replace
2956 // RequiresInsertable<T> with RequiresInsertable<const T&>.
2957 // We are hitting this bug: https://godbolt.org/g/1Vht4f.
2958 // --------------------------------------------------------------------
2959 template <
2960 class T, RequiresInsertable<T> = 0,
2961 typename std::enable_if<IsDecomposable<const T&>::value, int>::type = 0>
2962 std::pair<iterator, bool> insert(const T& value) {
2963 return emplace(value);
2964 }
2965
2966 // This overload kicks in when the argument is an rvalue of init_type. Its
2967 // purpose is to handle brace-init-list arguments.
2968 //
2969 // flat_hash_set<std::pair<std::string, int>> s;
2970 // s.insert({"abc", 42});
2971 // --------------------------------------------------------------------
2972 std::pair<iterator, bool> insert(init_type&& value) {
2973 return emplace(std::move(value));
2974 }
2975
2976 template <class T, RequiresInsertable<T> = 0,
2977 typename std::enable_if<IsDecomposable<T>::value, int>::type = 0,
2978 T* = nullptr>
2980 return insert(std::forward<T>(value)).first;
2981 }
2982
2983 // TODO(romanp): Once we stop supporting gcc 5.1 and below, replace
2984 // RequiresInsertable<T> with RequiresInsertable<const T&>.
2985 // We are hitting this bug: https://godbolt.org/g/1Vht4f.
2986 // --------------------------------------------------------------------
2987 template <
2988 class T, RequiresInsertable<T> = 0,
2989 typename std::enable_if<IsDecomposable<const T&>::value, int>::type = 0>
2990 iterator insert(const_iterator, const T& value) {
2991 return insert(value).first;
2992 }
2993
2995 return insert(std::move(value)).first;
2996 }
2997
2998 template <class InputIt>
2999 void insert(InputIt first, InputIt last) {
3000 for (; first != last; ++first) insert(*first);
3001 }
3002
3003 template <class T, RequiresNotInit<T> = 0, RequiresInsertable<const T&> = 0>
3004 void insert(std::initializer_list<T> ilist) {
3005 insert(ilist.begin(), ilist.end());
3006 }
3007
3008 void insert(std::initializer_list<init_type> ilist) {
3009 insert(ilist.begin(), ilist.end());
3010 }
3011
3013 if (!node)
3014 return {end(), false, node_type()};
3015 auto& key = node.key();
3016 size_t hashval = this->hash(key);
3017 Inner& inner = sets_[subidx(hashval)];
3018 auto& set = inner.set_;
3019
3020 typename Lockable::UniqueLock m(inner);
3021 auto res = set.insert(std::move(node), hashval);
3022 return { make_iterator(&inner, res.position),
3023 res.inserted,
3024 res.inserted ? node_type() : std::move(res.node) };
3025 }
3026
3028 return insert(std::move(node)).first;
3029 }
3030
3032 {
3033 template <class Key, class... Args>
3034 Key operator()(Key&& k, const Args&...) const {
3035 return std::forward<Key>(k);
3036 }
3037 };
3038
3039 // --------------------------------------------------------------------
3040 // phmap extension: emplace_with_hash
3041 // ----------------------------------
3042 // same as emplace, but hashval is provided
3043 // --------------------------------------------------------------------
3044 template <class K, class... Args>
3045 std::pair<iterator, bool> emplace_decomposable_with_hash(const K& key, size_t hashval, Args&&... args)
3046 {
3047 Inner& inner = sets_[subidx(hashval)];
3048 auto& set = inner.set_;
3049 typename Lockable::UniqueLock m(inner);
3050 return make_rv(&inner, set.emplace_decomposable(key, hashval, std::forward<Args>(args)...));
3051 }
3052
3054 {
3055 template <class K, class... Args>
3056 std::pair<iterator, bool> operator()(const K& key, Args&&... args) const {
3057 return s.emplace_decomposable_with_hash(key, hashval, std::forward<Args>(args)...);
3058 }
3060 size_t hashval;
3061 };
3062
3063 // This overload kicks in if we can deduce the key from args. This enables us
3064 // to avoid constructing value_type if an entry with the same key already
3065 // exists.
3066 //
3067 // For example:
3068 //
3069 // flat_hash_map<std::string, std::string> m = {{"abc", "def"}};
3070 // // Creates no std::string copies and makes no heap allocations.
3071 // m.emplace("abc", "xyz");
3072 // --------------------------------------------------------------------
3073 template <class... Args, typename std::enable_if<
3074 IsDecomposable<Args...>::value, int>::type = 0>
3075 std::pair<iterator, bool> emplace_with_hash(size_t hashval, Args&&... args) {
3076 return PolicyTraits::apply(EmplaceDecomposableHashval{*this, hashval},
3077 std::forward<Args>(args)...);
3078 }
3079
3080 // This overload kicks in if we cannot deduce the key from args. It constructs
3081 // value_type unconditionally and then either moves it into the table or
3082 // destroys.
3083 // --------------------------------------------------------------------
3084 template <class... Args, typename std::enable_if<
3085 !IsDecomposable<Args...>::value, int>::type = 0>
3086 std::pair<iterator, bool> emplace_with_hash(size_t hashval, Args&&... args) {
3087 typename std::aligned_storage<sizeof(slot_type), alignof(slot_type)>::type raw;
3088 slot_type* slot = reinterpret_cast<slot_type*>(&raw);
3089
3090 PolicyTraits::construct(&alloc_ref(), slot, std::forward<Args>(args)...);
3091 const auto& elem = PolicyTraits::element(slot);
3092 Inner& inner = sets_[subidx(hashval)];
3093 auto& set = inner.set_;
3094 typename Lockable::UniqueLock m(inner);
3095 typename EmbeddedSet::template InsertSlotWithHash<true> f {
3096 inner, std::move(*slot), hashval};
3097 return make_rv(PolicyTraits::apply(f, elem));
3098 }
3099
3100 template <class... Args>
3101 iterator emplace_hint_with_hash(size_t hashval, const_iterator, Args&&... args) {
3102 return emplace_with_hash(hashval, std::forward<Args>(args)...).first;
3103 }
3104
3105 template <class K = key_type, class F>
3106 iterator lazy_emplace_with_hash(const key_arg<K>& key, size_t hashval, F&& f) {
3107 Inner& inner = sets_[subidx(hashval)];
3108 auto& set = inner.set_;
3109 typename Lockable::UniqueLock m(inner);
3110 return make_iterator(&inner, set.lazy_emplace_with_hash(key, hashval, std::forward<F>(f)));
3111 }
3112
3113 // --------------------------------------------------------------------
3114 // end of phmap expension
3115 // --------------------------------------------------------------------
3116
3117 template <class K, class... Args>
3118 std::pair<iterator, bool> emplace_decomposable(const K& key, Args&&... args)
3119 {
3120 size_t hashval = this->hash(key);
3121 Inner& inner = sets_[subidx(hashval)];
3122 auto& set = inner.set_;
3123 typename Lockable::UniqueLock m(inner);
3124 return make_rv(&inner, set.emplace_decomposable(key, hashval, std::forward<Args>(args)...));
3125 }
3126
3128 {
3129 template <class K, class... Args>
3130 std::pair<iterator, bool> operator()(const K& key, Args&&... args) const {
3131 return s.emplace_decomposable(key, std::forward<Args>(args)...);
3132 }
3134 };
3135
3136 // This overload kicks in if we can deduce the key from args. This enables us
3137 // to avoid constructing value_type if an entry with the same key already
3138 // exists.
3139 //
3140 // For example:
3141 //
3142 // flat_hash_map<std::string, std::string> m = {{"abc", "def"}};
3143 // // Creates no std::string copies and makes no heap allocations.
3144 // m.emplace("abc", "xyz");
3145 // --------------------------------------------------------------------
3146 template <class... Args, typename std::enable_if<
3147 IsDecomposable<Args...>::value, int>::type = 0>
3148 std::pair<iterator, bool> emplace(Args&&... args) {
3150 std::forward<Args>(args)...);
3151 }
3152
3153 // This overload kicks in if we cannot deduce the key from args. It constructs
3154 // value_type unconditionally and then either moves it into the table or
3155 // destroys.
3156 // --------------------------------------------------------------------
3157 template <class... Args, typename std::enable_if<
3158 !IsDecomposable<Args...>::value, int>::type = 0>
3159 std::pair<iterator, bool> emplace(Args&&... args) {
3160 typename std::aligned_storage<sizeof(slot_type), alignof(slot_type)>::type raw;
3161 slot_type* slot = reinterpret_cast<slot_type*>(&raw);
3162 size_t hashval = this->hash(PolicyTraits::key(slot));
3163
3164 PolicyTraits::construct(&alloc_ref(), slot, std::forward<Args>(args)...);
3165 const auto& elem = PolicyTraits::element(slot);
3166 Inner& inner = sets_[subidx(hashval)];
3167 auto& set = inner.set_;
3168 typename Lockable::UniqueLock m(inner);
3169 typename EmbeddedSet::template InsertSlotWithHash<true> f {
3170 inner, std::move(*slot), hashval};
3171 return make_rv(PolicyTraits::apply(f, elem));
3172 }
3173
3174 template <class... Args>
3176 return emplace(std::forward<Args>(args)...).first;
3177 }
3178
3180 {
3181 if (it == inner->set_.end())
3182 return iterator();
3183 return iterator(inner, &sets_[0] + num_tables, it);
3184 }
3185
3186 std::pair<iterator, bool> make_rv(Inner* inner,
3187 const std::pair<EmbeddedIterator, bool>& res)
3188 {
3189 return {iterator(inner, &sets_[0] + num_tables, res.first), res.second};
3190 }
3191
3192 // lazy_emplace
3193 // ------------
3194 template <class K = key_type, class F>
3195 iterator lazy_emplace(const key_arg<K>& key, F&& f) {
3196 auto hashval = this->hash(key);
3197 Inner& inner = sets_[subidx(hashval)];
3198 auto& set = inner.set_;
3199 typename Lockable::UniqueLock m(inner);
3200 return make_iterator(&inner, set.lazy_emplace_with_hash(key, hashval, std::forward<F>(f)));
3201 }
3202
3203 // emplace_single
3204 // --------------
3205 template <class K = key_type, class F>
3206 void emplace_single_with_hash(const key_arg<K>& key, size_t hashval, F&& f) {
3207 Inner& inner = sets_[subidx(hashval)];
3208 auto& set = inner.set_;
3209 typename Lockable::UniqueLock m(inner);
3210 set.emplace_single_with_hash(key, hashval, std::forward<F>(f));
3211 }
3212
3213 template <class K = key_type, class F>
3214 void emplace_single(const key_arg<K>& key, F&& f) {
3215 auto hashval = this->hash(key);
3216 emplace_single_with_hash<K, F>(key, hashval, std::forward<F>(f));
3217 }
3218
3219 // if set contains key, lambda is called with the value_type (under read lock protection),
3220 // and if_contains returns true. This is a const API and lambda should not modify the value
3221 // -----------------------------------------------------------------------------------------
3222 template <class K = key_type, class F>
3223 bool if_contains(const key_arg<K>& key, F&& f) const {
3224 return const_cast<parallel_hash_set*>(this)->template
3225 modify_if_impl<K, F, typename Lockable::SharedLock>(key, std::forward<F>(f));
3226 }
3227
3228 // if set contains key, lambda is called with the value_type without read lock protection,
3229 // and if_contains_unsafe returns true. This is a const API and lambda should not modify the value
3230 // This should be used only if we know that no other thread may be mutating the set at the time.
3231 // -----------------------------------------------------------------------------------------
3232 template <class K = key_type, class F>
3233 bool if_contains_unsafe(const key_arg<K>& key, F&& f) const {
3234 return const_cast<parallel_hash_set*>(this)->template
3235 modify_if_impl<K, F, LockableBaseImpl<phmap::NullMutex>::DoNothing>(key, std::forward<F>(f));
3236 }
3237
3238 // if map contains key, lambda is called with the value_type (under write lock protection),
3239 // and modify_if returns true. This is a non-const API and lambda is allowed to modify the mapped value
3240 // ----------------------------------------------------------------------------------------------------
3241 template <class K = key_type, class F>
3242 bool modify_if(const key_arg<K>& key, F&& f) {
3243 return modify_if_impl<K, F, typename Lockable::UniqueLock>(key, std::forward<F>(f));
3244 }
3245
3246 // -----------------------------------------------------------------------------------------
3247 template <class K = key_type, class F, class L>
3248 bool modify_if_impl(const key_arg<K>& key, F&& f) {
3249#if __cplusplus >= 201703L
3250 static_assert(std::is_invocable<F, value_type&>::value);
3251#endif
3252 L m;
3253 auto ptr = this->template find_ptr<K, L>(key, this->hash(key), m);
3254 if (ptr == nullptr)
3255 return false;
3256 std::forward<F>(f)(*ptr);
3257 return true;
3258 }
3259
3260 // if map contains key, lambda is called with the mapped value (under write lock protection).
3261 // If the lambda returns true, the key is subsequently erased from the map (the write lock
3262 // is only released after erase).
3263 // returns true if key was erased, false otherwise.
3264 // ----------------------------------------------------------------------------------------------------
3265 template <class K = key_type, class F>
3266 bool erase_if(const key_arg<K>& key, F&& f) {
3267 return erase_if_impl<K, F, typename Lockable::UniqueLock>(key, std::forward<F>(f));
3268 }
3269
3270 template <class K = key_type, class F, class L>
3271 bool erase_if_impl(const key_arg<K>& key, F&& f) {
3272#if __cplusplus >= 201703L
3273 static_assert(std::is_invocable<F, value_type&>::value);
3274#endif
3275 L m;
3276 auto it = this->template find<K, L>(key, this->hash(key), m);
3277 if (it == this->end()) return false;
3278 if (std::forward<F>(f)(const_cast<value_type &>(*it)))
3279 {
3280 this->erase(it);
3281 return true;
3282 }
3283 return false;
3284 }
3285
3286 // if map already contains key, the first lambda is called with the mapped value (under
3287 // write lock protection) and can update the mapped value.
3288 // if map does not contains key, the second lambda is called and it should invoke the
3289 // passed constructor to construct the value
3290 // returns true if key was not already present, false otherwise.
3291 // ---------------------------------------------------------------------------------------
3292 template <class K = key_type, class FExists, class FEmplace>
3293 bool lazy_emplace_l(const key_arg<K>& key, FExists&& fExists, FEmplace&& fEmplace) {
3294 typename Lockable::UniqueLock m;
3295 auto res = this->find_or_prepare_insert(key, m);
3296 Inner* inner = std::get<0>(res);
3297 if (std::get<2>(res))
3298 inner->set_.lazy_emplace_at(std::get<1>(res), std::forward<FEmplace>(fEmplace));
3299 else {
3300 auto it = this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res)));
3301 std::forward<FExists>(fExists)(const_cast<value_type &>(*it)); // in case of the set, non "key" part of value_type can be changed
3302 }
3303 return std::get<2>(res);
3304 }
3305
3306 // Extension API: support iterating over all values
3307 //
3308 // flat_hash_set<std::string> s;
3309 // s.insert(...);
3310 // s.for_each([](auto const & key) {
3311 // // Safely iterates over all the keys
3312 // });
3313 template <class F>
3314 void for_each(F&& fCallback) const {
3315 for (auto const& inner : sets_) {
3316 typename Lockable::SharedLock m(const_cast<Inner&>(inner));
3317 std::for_each(inner.set_.begin(), inner.set_.end(), fCallback);
3318 }
3319 }
3320
3321 // this version allows to modify the values
3322 template <class F>
3323 void for_each_m(F&& fCallback) {
3324 for (auto& inner : sets_) {
3325 typename Lockable::UniqueLock m(inner);
3326 std::for_each(inner.set_.begin(), inner.set_.end(), fCallback);
3327 }
3328 }
3329
3330#if __cplusplus >= 201703L
3331 template <class ExecutionPolicy, class F>
3332 void for_each(ExecutionPolicy&& policy, F&& fCallback) const {
3333 std::for_each(
3334 std::forward<ExecutionPolicy>(policy), sets_.begin(), sets_.end(),
3335 [&](auto const& inner) {
3336 typename Lockable::SharedLock m(const_cast<Inner&>(inner));
3337 std::for_each(inner.set_.begin(), inner.set_.end(), fCallback);
3338 }
3339 );
3340 }
3341
3342 template <class ExecutionPolicy, class F>
3343 void for_each_m(ExecutionPolicy&& policy, F&& fCallback) {
3344 std::for_each(
3345 std::forward<ExecutionPolicy>(policy), sets_.begin(), sets_.end(),
3346 [&](auto& inner) {
3347 typename Lockable::UniqueLock m(inner);
3348 std::for_each(inner.set_.begin(), inner.set_.end(), fCallback);
3349 }
3350 );
3351 }
3352#endif
3353
3354 // Extension API: access internal submaps by index
3355 // under lock protection
3356 // ex: m.with_submap(i, [&](const Map::EmbeddedSet& set) {
3357 // for (auto& p : set) { ...; }});
3358 // -------------------------------------------------
3359 template <class F>
3360 void with_submap(size_t idx, F&& fCallback) const {
3361 const Inner& inner = sets_[idx];
3362 const auto& set = inner.set_;
3363 typename Lockable::SharedLock m(const_cast<Inner&>(inner));
3364 fCallback(set);
3365 }
3366
3367 template <class F>
3368 void with_submap_m(size_t idx, F&& fCallback) {
3369 Inner& inner = sets_[idx];
3370 auto& set = inner.set_;
3371 typename Lockable::UniqueLock m(inner);
3372 fCallback(set);
3373 }
3374
3375 // unsafe, for internal use only
3376 Inner& get_inner(size_t idx) {
3377 return sets_[idx];
3378 }
3379
3380 // Extension API: support for heterogeneous keys.
3381 //
3382 // std::unordered_set<std::string> s;
3383 // // Turns "abc" into std::string.
3384 // s.erase("abc");
3385 //
3386 // flat_hash_set<std::string> s;
3387 // // Uses "abc" directly without copying it into std::string.
3388 // s.erase("abc");
3389 //
3390 // --------------------------------------------------------------------
3391 template <class K = key_type>
3393 auto hashval = this->hash(key);
3394 Inner& inner = sets_[subidx(hashval)];
3395 auto& set = inner.set_;
3396 typename Lockable::UpgradeLock m(inner);
3397 auto it = set.find(key, hashval);
3398 if (it == set.end())
3399 return 0;
3400
3401 typename Lockable::UpgradeToUnique unique(m);
3402 set._erase(it);
3403 return 1;
3404 }
3405
3406 // --------------------------------------------------------------------
3408
3409 // Erases the element pointed to by `it`. Unlike `std::unordered_set::erase`,
3410 // this method returns void to reduce algorithmic complexity to O(1). In
3411 // order to erase while iterating across a map, use the following idiom (which
3412 // also works for standard containers):
3413 //
3414 // for (auto it = m.begin(), end = m.end(); it != end;) {
3415 // if (<pred>) {
3416 // m._erase(it++);
3417 // } else {
3418 // ++it;
3419 // }
3420 // }
3421 //
3422 // Do not use erase APIs taking iterators when accessing the map concurrently
3423 // --------------------------------------------------------------------
3424 void _erase(iterator it) {
3425 Inner* inner = it.inner_;
3426 assert(inner != nullptr);
3427 auto& set = inner->set_;
3428 // typename Lockable::UniqueLock m(*inner); // don't lock here
3429
3430 set._erase(it.it_);
3431 }
3432 void _erase(const_iterator cit) { _erase(cit.iter_); }
3433
3434 // This overload is necessary because otherwise erase<K>(const K&) would be
3435 // a better match if non-const iterator is passed as an argument.
3436 // Do not use erase APIs taking iterators when accessing the map concurrently
3437 // --------------------------------------------------------------------
3438 iterator erase(iterator it) { _erase(it++); return it; }
3439
3441 while (first != last) {
3442 _erase(first++);
3443 }
3444 return last.iter_;
3445 }
3446
3447 // Moves elements from `src` into `this`.
3448 // If the element already exists in `this`, it is left unmodified in `src`.
3449 // Do not use erase APIs taking iterators when accessing the map concurrently
3450 // --------------------------------------------------------------------
3451 template <typename E = Eq>
3453 assert(this != &src);
3454 if (this != &src)
3455 {
3456 for (size_t i=0; i<num_tables; ++i)
3457 {
3458 typename Lockable::UniqueLocks l(sets_[i], src.sets_[i]);
3459 sets_[i].set_.merge(src.sets_[i].set_);
3460 }
3461 }
3462 }
3463
3464 template <typename E = Eq>
3466 merge(src);
3467 }
3468
3470 return position.iter_.inner_->set_.extract(EmbeddedConstIterator(position.iter_.it_));
3471 }
3472
3473 template <
3474 class K = key_type,
3475 typename std::enable_if<!std::is_same<K, iterator>::value, int>::type = 0>
3477 auto it = find(key);
3478 return it == end() ? node_type() : extract(const_iterator{it});
3479 }
3480
3481 template<class Mtx2_>
3483 noexcept(IsNoThrowSwappable<EmbeddedSet>() &&
3484 (!AllocTraits::propagate_on_container_swap::value ||
3485 IsNoThrowSwappable<allocator_type>()))
3486 {
3487 using std::swap;
3488 using Lockable2 = phmap::LockableImpl<Mtx2_>;
3489
3490 for (size_t i=0; i<num_tables; ++i)
3491 {
3492 typename Lockable::UniqueLock l(sets_[i]);
3493 typename Lockable2::UniqueLock l2(that.get_inner(i));
3494 swap(sets_[i].set_, that.get_inner(i).set_);
3495 }
3496 }
3497
3498 void rehash(size_t n) {
3499 size_t nn = n / num_tables;
3500 for (auto& inner : sets_)
3501 {
3502 typename Lockable::UniqueLock m(inner);
3503 inner.set_.rehash(nn);
3504 }
3505 }
3506
3507 void reserve(size_t n)
3508 {
3509 size_t target = GrowthToLowerboundCapacity(n);
3510 size_t normalized = 16 * NormalizeCapacity(n / num_tables);
3511 rehash(normalized > target ? normalized : target);
3512 }
3513
3514 // Extension API: support for heterogeneous keys.
3515 //
3516 // std::unordered_set<std::string> s;
3517 // // Turns "abc" into std::string.
3518 // s.count("abc");
3519 //
3520 // ch_set<std::string> s;
3521 // // Uses "abc" directly without copying it into std::string.
3522 // s.count("abc");
3523 // --------------------------------------------------------------------
3524 template <class K = key_type>
3525 size_t count(const key_arg<K>& key) const {
3526 return find(key) == end() ? 0 : 1;
3527 }
3528
3529 // Issues CPU prefetch instructions for the memory needed to find or insert
3530 // a key. Like all lookup functions, this support heterogeneous keys.
3531 //
3532 // NOTE: This is a very low level operation and should not be used without
3533 // specific benchmarks indicating its importance.
3534 // --------------------------------------------------------------------
3535 void prefetch_hash(size_t hashval) const {
3536 const Inner& inner = sets_[subidx(hashval)];
3537 const auto& set = inner.set_;
3538 typename Lockable::SharedLock m(const_cast<Inner&>(inner));
3539 set.prefetch_hash(hashval);
3540 }
3541
3542 template <class K = key_type>
3543 void prefetch(const key_arg<K>& key) const {
3544 prefetch_hash(this->hash(key));
3545 }
3546
3547 // The API of find() has two extensions.
3548 //
3549 // 1. The hash can be passed by the user. It must be equal to the hash of the
3550 // key.
3551 //
3552 // 2. The type of the key argument doesn't have to be key_type. This is so
3553 // called heterogeneous key support.
3554 // --------------------------------------------------------------------
3555 template <class K = key_type>
3556 iterator find(const key_arg<K>& key, size_t hashval) {
3557 typename Lockable::SharedLock m;
3558 return find(key, hashval, m);
3559 }
3560
3561 template <class K = key_type>
3563 return find(key, this->hash(key));
3564 }
3565
3566 template <class K = key_type>
3567 const_iterator find(const key_arg<K>& key, size_t hashval) const {
3568 return const_cast<parallel_hash_set*>(this)->find(key, hashval);
3569 }
3570
3571 template <class K = key_type>
3572 const_iterator find(const key_arg<K>& key) const {
3573 return find(key, this->hash(key));
3574 }
3575
3576 template <class K = key_type>
3577 bool contains(const key_arg<K>& key) const {
3578 return find(key) != end();
3579 }
3580
3581 template <class K = key_type>
3582 bool contains(const key_arg<K>& key, size_t hashval) const {
3583 return find(key, hashval) != end();
3584 }
3585
3586 template <class K = key_type>
3587 std::pair<iterator, iterator> equal_range(const key_arg<K>& key) {
3588 auto it = find(key);
3589 if (it != end()) return {it, std::next(it)};
3590 return {it, it};
3591 }
3592
3593 template <class K = key_type>
3594 std::pair<const_iterator, const_iterator> equal_range(
3595 const key_arg<K>& key) const {
3596 auto it = find(key);
3597 if (it != end()) return {it, std::next(it)};
3598 return {it, it};
3599 }
3600
3601 size_t bucket_count() const {
3602 size_t sz = 0;
3603 for (const auto& inner : sets_)
3604 {
3605 typename Lockable::SharedLock m(const_cast<Inner&>(inner));
3606 sz += inner.set_.bucket_count();
3607 }
3608 return sz;
3609 }
3610
3611 float load_factor() const {
3612 size_t _capacity = bucket_count();
3613 return _capacity ? static_cast<float>(static_cast<double>(size()) / _capacity) : 0;
3614 }
3615
3616 float max_load_factor() const { return 1.0f; }
3617 void max_load_factor(float) {
3618 // Does nothing.
3619 }
3620
3621 hasher hash_function() const { return hash_ref(); } // warning: doesn't match internal hash - use hash() member function
3622 key_equal key_eq() const { return eq_ref(); }
3624
3625 friend bool operator==(const parallel_hash_set& a, const parallel_hash_set& b) {
3626 return std::equal(a.sets_.begin(), a.sets_.end(), b.sets_.begin());
3627 }
3628
3629 friend bool operator!=(const parallel_hash_set& a, const parallel_hash_set& b) {
3630 return !(a == b);
3631 }
3632
3633 template<class Mtx2_>
3634 friend void swap(parallel_hash_set& a,
3636 noexcept(noexcept(a.swap(b)))
3637 {
3638 a.swap(b);
3639 }
3640
3641 template <class K>
3642 size_t hash(const K& key) const {
3643 return HashElement{hash_ref()}(key);
3644 }
3645
3646#if !defined(PHMAP_NON_DETERMINISTIC)
3647 template<typename OutputArchive>
3648 bool phmap_dump(OutputArchive& ar) const;
3649
3650 template<typename InputArchive>
3651 bool phmap_load(InputArchive& ar);
3652#endif
3653
3654private:
3655 template <class Container, typename Enabler>
3657
3659 {
3660 template <class K, class... Args>
3661 const_iterator operator()(const K& key, Args&&...) const {
3662 return s.find(key);
3663 }
3665 };
3666
3668 {
3669 template <class K, class... Args>
3670 size_t operator()(const K& key, Args&&...) const {
3671 return phmap_mix<sizeof(size_t)>()(h(key));
3672 }
3673 const hasher& h;
3674 };
3675
3676 template <class K1>
3678 {
3679 template <class K2, class... Args>
3680 bool operator()(const K2& lhs, Args&&...) const {
3681 return eq(lhs, rhs);
3682 }
3683 const K1& rhs;
3685 };
3686
3687 // "erases" the object from the container, except that it doesn't actually
3688 // destroy the object. It only updates all the metadata of the class.
3689 // This can be used in conjunction with Policy::transfer to move the object to
3690 // another place.
3691 // --------------------------------------------------------------------
3693 auto &it = cit.iter_;
3694 assert(it.set_ != nullptr);
3695 it.set_.erase_meta_only(const_iterator(it.it_));
3696 }
3697
3699 for (auto& inner : sets_)
3700 {
3701 typename Lockable::UniqueLock m(inner);
3702 inner.set_.drop_deletes_without_resize();
3703 }
3704 }
3705
3706 bool has_element(const value_type& elem) const {
3707 size_t hashval = PolicyTraits::apply(HashElement{hash_ref()}, elem);
3708 Inner& inner = sets_[subidx(hashval)];
3709 auto& set = inner.set_;
3710 typename Lockable::SharedLock m(const_cast<Inner&>(inner));
3711 return set.has_element(elem, hashval);
3712 }
3713
3714 // TODO(alkis): Optimize this assuming *this and that don't overlap.
3715 // --------------------------------------------------------------------
3716 template<class Mtx2_>
3719 swap(tmp);
3720 return *this;
3721 }
3722
3723 template<class Mtx2_>
3726 swap(tmp);
3727 return *this;
3728 }
3729
3730protected:
3731 template <class K = key_type, class L = typename Lockable::SharedLock>
3732 pointer find_ptr(const key_arg<K>& key, size_t hashval, L& mutexlock)
3733 {
3734 Inner& inner = sets_[subidx(hashval)];
3735 auto& set = inner.set_;
3736 mutexlock = std::move(L(inner));
3737 return set.find_ptr(key, hashval);
3738 }
3739
3740 template <class K = key_type, class L = typename Lockable::SharedLock>
3741 iterator find(const key_arg<K>& key, size_t hashval, L& mutexlock) {
3742 Inner& inner = sets_[subidx(hashval)];
3743 auto& set = inner.set_;
3744 mutexlock = std::move(L(inner));
3745 return make_iterator(&inner, set.find(key, hashval));
3746 }
3747
3748 template <class K>
3749 std::tuple<Inner*, size_t, bool>
3750 find_or_prepare_insert_with_hash(size_t hashval, const K& key, typename Lockable::UniqueLock &mutexlock) {
3751 Inner& inner = sets_[subidx(hashval)];
3752 auto& set = inner.set_;
3753 mutexlock = std::move(typename Lockable::UniqueLock(inner));
3754 auto p = set.find_or_prepare_insert(key, hashval); // std::pair<size_t, bool>
3755 return std::make_tuple(&inner, p.first, p.second);
3756 }
3757
3758 template <class K>
3759 std::tuple<Inner*, size_t, bool>
3760 find_or_prepare_insert(const K& key, typename Lockable::UniqueLock &mutexlock) {
3761 return find_or_prepare_insert_with_hash<K>(this->hash(key), key, mutexlock);
3762 }
3763
3765 const EmbeddedIterator& it) {
3766 return {inner, &sets_[0] + num_tables, it};
3767 }
3769 const EmbeddedIterator& it) const {
3770 return {inner, &sets_[0] + num_tables, it};
3771 }
3772
3773 static size_t subidx(size_t hashval) {
3774 return ((hashval >> 8) ^ (hashval >> 16) ^ (hashval >> 24)) & mask;
3775 }
3776
3777 static size_t subcnt() {
3778 return num_tables;
3779 }
3780
3781private:
3783
3784 size_t growth_left() {
3785 size_t sz = 0;
3786 for (const auto& set : sets_)
3787 sz += set.growth_left();
3788 return sz;
3789 }
3790
3791 hasher& hash_ref() { return sets_[0].set_.hash_ref(); }
3792 const hasher& hash_ref() const { return sets_[0].set_.hash_ref(); }
3793 key_equal& eq_ref() { return sets_[0].set_.eq_ref(); }
3794 const key_equal& eq_ref() const { return sets_[0].set_.eq_ref(); }
3795 allocator_type& alloc_ref() { return sets_[0].set_.alloc_ref(); }
3796 const allocator_type& alloc_ref() const {
3797 return sets_[0].set_.alloc_ref();
3798 }
3799
3800protected: // protected in case users want to derive fromm this
3801 std::array<Inner, num_tables> sets_;
3802};
3803
3804// --------------------------------------------------------------------------
3805// --------------------------------------------------------------------------
3806template <size_t N,
3807 template <class, class, class, class> class RefSet,
3808 class Mtx_,
3809 class Policy, class Hash, class Eq, class Alloc>
3810class parallel_hash_map : public parallel_hash_set<N, RefSet, Mtx_, Policy, Hash, Eq, Alloc>
3811{
3812 // P is Policy. It's passed as a template argument to support maps that have
3813 // incomplete types as values, as in unordered_map<K, IncompleteType>.
3814 // MappedReference<> may be a non-reference type.
3815 template <class P>
3816 using MappedReference = decltype(P::value(
3817 std::addressof(std::declval<typename parallel_hash_map::reference>())));
3818
3819 // MappedConstReference<> may be a non-reference type.
3820 template <class P>
3821 using MappedConstReference = decltype(P::value(
3822 std::addressof(std::declval<typename parallel_hash_map::const_reference>())));
3823
3826
3829
3830public:
3831 using key_type = typename Policy::key_type;
3832 using mapped_type = typename Policy::mapped_type;
3833 using value_type = typename Base::value_type;
3834 template <class K>
3835 using key_arg = typename KeyArgImpl::template type<K, key_type>;
3836
3837 static_assert(!std::is_reference<key_type>::value, "");
3838 // TODO(alkis): remove this assertion and verify that reference mapped_type is
3839 // supported.
3840 static_assert(!std::is_reference<mapped_type>::value, "");
3841
3842 using iterator = typename parallel_hash_map::parallel_hash_set::iterator;
3843 using const_iterator = typename parallel_hash_map::parallel_hash_set::const_iterator;
3844
3846
3847#ifdef __INTEL_COMPILER
3848 using Base::parallel_hash_set;
3849#else
3850 using parallel_hash_map::parallel_hash_set::parallel_hash_set;
3851#endif
3852
3853 // The last two template parameters ensure that both arguments are rvalues
3854 // (lvalue arguments are handled by the overloads below). This is necessary
3855 // for supporting bitfield arguments.
3856 //
3857 // union { int n : 1; };
3858 // flat_hash_map<int, int> m;
3859 // m.insert_or_assign(n, n);
3860 template <class K = key_type, class V = mapped_type, K* = nullptr,
3861 V* = nullptr>
3862 std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v) {
3863 return insert_or_assign_impl(std::forward<K>(k), std::forward<V>(v));
3864 }
3865
3866 template <class K = key_type, class V = mapped_type, K* = nullptr>
3867 std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v) {
3868 return insert_or_assign_impl(std::forward<K>(k), v);
3869 }
3870
3871 template <class K = key_type, class V = mapped_type, V* = nullptr>
3872 std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v) {
3873 return insert_or_assign_impl(k, std::forward<V>(v));
3874 }
3875
3876 template <class K = key_type, class V = mapped_type>
3877 std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const V& v) {
3878 return insert_or_assign_impl(k, v);
3879 }
3880
3881 template <class K = key_type, class V = mapped_type, K* = nullptr,
3882 V* = nullptr>
3884 return insert_or_assign(std::forward<K>(k), std::forward<V>(v)).first;
3885 }
3886
3887 template <class K = key_type, class V = mapped_type, K* = nullptr>
3889 return insert_or_assign(std::forward<K>(k), v).first;
3890 }
3891
3892 template <class K = key_type, class V = mapped_type, V* = nullptr>
3894 return insert_or_assign(k, std::forward<V>(v)).first;
3895 }
3896
3897 template <class K = key_type, class V = mapped_type>
3899 return insert_or_assign(k, v).first;
3900 }
3901
3902 template <class K = key_type, class... Args,
3903 typename std::enable_if<
3904 !std::is_convertible<K, const_iterator>::value, int>::type = 0,
3905 K* = nullptr>
3906 std::pair<iterator, bool> try_emplace(key_arg<K>&& k, Args&&... args) {
3907 return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
3908 }
3909
3910 template <class K = key_type, class... Args,
3911 typename std::enable_if<
3912 !std::is_convertible<K, const_iterator>::value, int>::type = 0>
3913 std::pair<iterator, bool> try_emplace(const key_arg<K>& k, Args&&... args) {
3914 return try_emplace_impl(k, std::forward<Args>(args)...);
3915 }
3916
3917 template <class K = key_type, class... Args, K* = nullptr>
3919 return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
3920 }
3921
3922 template <class K = key_type, class... Args>
3923 iterator try_emplace(const_iterator, const key_arg<K>& k, Args&&... args) {
3924 return try_emplace(k, std::forward<Args>(args)...).first;
3925 }
3926
3927 template <class K = key_type, class P = Policy>
3929 auto it = this->find(key);
3930 if (it == this->end())
3931 phmap::base_internal::ThrowStdOutOfRange("phmap at(): lookup non-existent key");
3932 return Policy::value(&*it);
3933 }
3934
3935 template <class K = key_type, class P = Policy>
3937 auto it = this->find(key);
3938 if (it == this->end())
3939 phmap::base_internal::ThrowStdOutOfRange("phmap at(): lookup non-existent key");
3940 return Policy::value(&*it);
3941 }
3942
3943 // ----------- phmap extensions --------------------------
3944
3945 template <class K = key_type, class... Args,
3946 typename std::enable_if<
3947 !std::is_convertible<K, const_iterator>::value, int>::type = 0,
3948 K* = nullptr>
3949 std::pair<iterator, bool> try_emplace_with_hash(size_t hashval, key_arg<K>&& k, Args&&... args) {
3950 return try_emplace_impl_with_hash(hashval, std::forward<K>(k), std::forward<Args>(args)...);
3951 }
3952
3953 template <class K = key_type, class... Args,
3954 typename std::enable_if<
3955 !std::is_convertible<K, const_iterator>::value, int>::type = 0>
3956 std::pair<iterator, bool> try_emplace_with_hash(size_t hashval, const key_arg<K>& k, Args&&... args) {
3957 return try_emplace_impl_with_hash(hashval, k, std::forward<Args>(args)...);
3958 }
3959
3960 template <class K = key_type, class... Args, K* = nullptr>
3961 iterator try_emplace_with_hash(size_t hashval, const_iterator, key_arg<K>&& k, Args&&... args) {
3962 return try_emplace_with_hash(hashval, std::forward<K>(k), std::forward<Args>(args)...).first;
3963 }
3964
3965 template <class K = key_type, class... Args>
3966 iterator try_emplace_with_hash(size_t hashval, const_iterator, const key_arg<K>& k, Args&&... args) {
3967 return try_emplace_with_hash(hashval, k, std::forward<Args>(args)...).first;
3968 }
3969
3970 // if map does not contains key, it is inserted and the mapped value is value-constructed
3971 // with the provided arguments (if any), as with try_emplace.
3972 // if map already contains key, then the lambda is called with the mapped value (under
3973 // write lock protection) and can update the mapped value.
3974 // returns true if key was not already present, false otherwise.
3975 // ---------------------------------------------------------------------------------------
3976 template <class K = key_type, class F, class... Args>
3977 bool try_emplace_l(K&& k, F&& f, Args&&... args) {
3978 typename Lockable::UniqueLock m;
3979 auto res = this->find_or_prepare_insert(k, m);
3980 typename Base::Inner *inner = std::get<0>(res);
3981 if (std::get<2>(res))
3982 inner->set_.emplace_at(std::get<1>(res), std::piecewise_construct,
3983 std::forward_as_tuple(std::forward<K>(k)),
3984 std::forward_as_tuple(std::forward<Args>(args)...));
3985 else {
3986 auto it = this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res)));
3987 std::forward<F>(f)(const_cast<value_type &>(*it)); // in case of the set, non "key" part of value_type can be changed
3988 }
3989 return std::get<2>(res);
3990 }
3991
3992 // ----------- end of phmap extensions --------------------------
3993
3994 template <class K = key_type, class P = Policy, K* = nullptr>
3996 return Policy::value(&*try_emplace(std::forward<K>(key)).first);
3997 }
3998
3999 template <class K = key_type, class P = Policy>
4001 return Policy::value(&*try_emplace(key).first);
4002 }
4003
4004private:
4005
4006 template <class K, class V>
4007 std::pair<iterator, bool> insert_or_assign_impl(K&& k, V&& v) {
4008 typename Lockable::UniqueLock m;
4009 auto res = this->find_or_prepare_insert(k, m);
4010 typename Base::Inner *inner = std::get<0>(res);
4011 if (std::get<2>(res))
4012 inner->set_.emplace_at(std::get<1>(res), std::forward<K>(k), std::forward<V>(v));
4013 else
4014 Policy::value(&*inner->set_.iterator_at(std::get<1>(res))) = std::forward<V>(v);
4015 return {this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))),
4016 std::get<2>(res)};
4017 }
4018
4019 template <class K = key_type, class... Args>
4020 std::pair<iterator, bool> try_emplace_impl(K&& k, Args&&... args) {
4021 typename Lockable::UniqueLock m;
4022 auto res = this->find_or_prepare_insert(k, m);
4023 typename Base::Inner *inner = std::get<0>(res);
4024 if (std::get<2>(res))
4025 inner->set_.emplace_at(std::get<1>(res), std::piecewise_construct,
4026 std::forward_as_tuple(std::forward<K>(k)),
4027 std::forward_as_tuple(std::forward<Args>(args)...));
4028 return {this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))),
4029 std::get<2>(res)};
4030 }
4031
4032 template <class K = key_type, class... Args>
4033 std::pair<iterator, bool> try_emplace_impl_with_hash(size_t hashval, K&& k, Args&&... args) {
4034 typename Lockable::UniqueLock m;
4035 auto res = this->find_or_prepare_insert_with_hash(hashval, k, m);
4036 typename Base::Inner *inner = std::get<0>(res);
4037 if (std::get<2>(res))
4038 inner->set_.emplace_at(std::get<1>(res), std::piecewise_construct,
4039 std::forward_as_tuple(std::forward<K>(k)),
4040 std::forward_as_tuple(std::forward<Args>(args)...));
4041 return {this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))),
4042 std::get<2>(res)};
4043 }
4044
4045
4046};
4047
4048
4049// Constructs T into uninitialized storage pointed by `ptr` using the args
4050// specified in the tuple.
4051// ----------------------------------------------------------------------------
4052template <class Alloc, class T, class Tuple>
4053void ConstructFromTuple(Alloc* alloc, T* ptr, Tuple&& t) {
4055 alloc, ptr, std::forward<Tuple>(t),
4057 std::tuple_size<typename std::decay<Tuple>::type>::value>());
4058}
4059
4060// Constructs T using the args specified in the tuple and calls F with the
4061// constructed value.
4062// ----------------------------------------------------------------------------
4063template <class T, class Tuple, class F>
4064decltype(std::declval<F>()(std::declval<T>())) WithConstructed(
4065 Tuple&& t, F&& f) {
4066 return memory_internal::WithConstructedImpl<T>(
4067 std::forward<Tuple>(t),
4069 std::tuple_size<typename std::decay<Tuple>::type>::value>(),
4070 std::forward<F>(f));
4071}
4072
4073// ----------------------------------------------------------------------------
4074// Given arguments of an std::pair's consructor, PairArgs() returns a pair of
4075// tuples with references to the passed arguments. The tuples contain
4076// constructor arguments for the first and the second elements of the pair.
4077//
4078// The following two snippets are equivalent.
4079//
4080// 1. std::pair<F, S> p(args...);
4081//
4082// 2. auto a = PairArgs(args...);
4083// std::pair<F, S> p(std::piecewise_construct,
4084// std::move(p.first), std::move(p.second));
4085// ----------------------------------------------------------------------------
4086inline std::pair<std::tuple<>, std::tuple<>> PairArgs() { return {}; }
4087
4088template <class F, class S>
4089std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(F&& f, S&& s) {
4090 return {std::piecewise_construct, std::forward_as_tuple(std::forward<F>(f)),
4091 std::forward_as_tuple(std::forward<S>(s))};
4092}
4093
4094template <class F, class S>
4095std::pair<std::tuple<const F&>, std::tuple<const S&>> PairArgs(
4096 const std::pair<F, S>& p) {
4097 return PairArgs(p.first, p.second);
4098}
4099
4100template <class F, class S>
4101std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(std::pair<F, S>&& p) {
4102 return PairArgs(std::forward<F>(p.first), std::forward<S>(p.second));
4103}
4104
4105template <class F, class S>
4106auto PairArgs(std::piecewise_construct_t, F&& f, S&& s)
4107 -> decltype(std::make_pair(memory_internal::TupleRef(std::forward<F>(f)),
4108 memory_internal::TupleRef(std::forward<S>(s)))) {
4109 return std::make_pair(memory_internal::TupleRef(std::forward<F>(f)),
4110 memory_internal::TupleRef(std::forward<S>(s)));
4111}
4112
4113// A helper function for implementing apply() in map policies.
4114// ----------------------------------------------------------------------------
4115template <class F, class... Args>
4116auto DecomposePair(F&& f, Args&&... args)
4118 std::forward<F>(f), PairArgs(std::forward<Args>(args)...))) {
4120 std::forward<F>(f), PairArgs(std::forward<Args>(args)...));
4121}
4122
4123// A helper function for implementing apply() in set policies.
4124// ----------------------------------------------------------------------------
4125template <class F, class Arg>
4126decltype(std::declval<F>()(std::declval<const Arg&>(), std::declval<Arg>()))
4127DecomposeValue(F&& f, Arg&& arg) {
4128 const auto& key = arg;
4129 return std::forward<F>(f)(key, std::forward<Arg>(arg));
4130}
4131
4132
4133// --------------------------------------------------------------------------
4134// Policy: a policy defines how to perform different operations on
4135// the slots of the hashtable (see hash_policy_traits.h for the full interface
4136// of policy).
4137//
4138// Hash: a (possibly polymorphic) functor that hashes keys of the hashtable. The
4139// functor should accept a key and return size_t as hash. For best performance
4140// it is important that the hash function provides high entropy across all bits
4141// of the hash.
4142//
4143// Eq: a (possibly polymorphic) functor that compares two keys for equality. It
4144// should accept two (of possibly different type) keys and return a bool: true
4145// if they are equal, false if they are not. If two keys compare equal, then
4146// their hash values as defined by Hash MUST be equal.
4147//
4148// Allocator: an Allocator [https://devdocs.io/cpp/concept/allocator] with which
4149// the storage of the hashtable will be allocated and the elements will be
4150// constructed and destroyed.
4151// --------------------------------------------------------------------------
4152template <class T>
4154{
4155 using slot_type = T;
4156 using key_type = T;
4157 using init_type = T;
4158 using constant_iterators = std::true_type;
4159
4160 template <class Allocator, class... Args>
4161 static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
4163 std::forward<Args>(args)...);
4164 }
4165
4166 template <class Allocator>
4167 static void destroy(Allocator* alloc, slot_type* slot) {
4169 }
4170
4171 template <class Allocator>
4172 static void transfer(Allocator* alloc, slot_type* new_slot,
4173 slot_type* old_slot) {
4174 construct(alloc, new_slot, std::move(*old_slot));
4175 destroy(alloc, old_slot);
4176 }
4177
4178 static T& element(slot_type* slot) { return *slot; }
4179
4180 template <class F, class... Args>
4181 static decltype(phmap::priv::DecomposeValue(
4182 std::declval<F>(), std::declval<Args>()...))
4183 apply(F&& f, Args&&... args) {
4185 std::forward<F>(f), std::forward<Args>(args)...);
4186 }
4187
4188 static size_t space_used(const T*) { return 0; }
4189};
4190
4191// --------------------------------------------------------------------------
4192// --------------------------------------------------------------------------
4193template <class K, class V>
4195{
4198 using key_type = K;
4199 using mapped_type = V;
4200 using init_type = std::pair</*non const*/ key_type, mapped_type>;
4201
4202 template <class Allocator, class... Args>
4203 static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
4204 slot_policy::construct(alloc, slot, std::forward<Args>(args)...);
4205 }
4206
4207 template <class Allocator>
4208 static void destroy(Allocator* alloc, slot_type* slot) {
4209 slot_policy::destroy(alloc, slot);
4210 }
4211
4212 template <class Allocator>
4213 static void transfer(Allocator* alloc, slot_type* new_slot,
4214 slot_type* old_slot) {
4215 slot_policy::transfer(alloc, new_slot, old_slot);
4216 }
4217
4218 template <class F, class... Args>
4219 static decltype(phmap::priv::DecomposePair(
4220 std::declval<F>(), std::declval<Args>()...))
4221 apply(F&& f, Args&&... args) {
4222 return phmap::priv::DecomposePair(std::forward<F>(f),
4223 std::forward<Args>(args)...);
4224 }
4225
4226 static size_t space_used(const slot_type*) { return 0; }
4227
4228 static std::pair<const K, V>& element(slot_type* slot) { return slot->value; }
4229
4230 static V& value(std::pair<const K, V>* kv) { return kv->second; }
4231 static const V& value(const std::pair<const K, V>* kv) { return kv->second; }
4232};
4233
4234template <class Reference, class Policy>
4236 static_assert(std::is_lvalue_reference<Reference>::value, "");
4237
4238 using slot_type = typename std::remove_cv<
4239 typename std::remove_reference<Reference>::type>::type*;
4240
4241 template <class Alloc, class... Args>
4242 static void construct(Alloc* alloc, slot_type* slot, Args&&... args) {
4243 *slot = Policy::new_element(alloc, std::forward<Args>(args)...);
4244 }
4245
4246 template <class Alloc>
4247 static void destroy(Alloc* alloc, slot_type* slot) {
4248 Policy::delete_element(alloc, *slot);
4249 }
4250
4251 template <class Alloc>
4252 static void transfer(Alloc*, slot_type* new_slot, slot_type* old_slot) {
4253 *new_slot = *old_slot;
4254 }
4255
4256 static size_t space_used(const slot_type* slot) {
4257 if (slot == nullptr) return Policy::element_space_used(nullptr);
4258 return Policy::element_space_used(*slot);
4259 }
4260
4261 static Reference element(slot_type* slot) { return **slot; }
4262
4263 template <class T, class P = Policy>
4264 static auto value(T* elem) -> decltype(P::value(elem)) {
4265 return P::value(elem);
4266 }
4267
4268 template <class... Ts, class P = Policy>
4269 static auto apply(Ts&&... ts) -> decltype(P::apply(std::forward<Ts>(ts)...)) {
4270 return P::apply(std::forward<Ts>(ts)...);
4271 }
4272};
4273
4274// --------------------------------------------------------------------------
4275// --------------------------------------------------------------------------
4276template <class T>
4278 : phmap::priv::node_hash_policy<T&, NodeHashSetPolicy<T>>
4279{
4280 using key_type = T;
4281 using init_type = T;
4282 using constant_iterators = std::true_type;
4283
4284 template <class Allocator, class... Args>
4285 static T* new_element(Allocator* alloc, Args&&... args) {
4286 using ValueAlloc =
4287 typename phmap::allocator_traits<Allocator>::template rebind_alloc<T>;
4288 ValueAlloc value_alloc(*alloc);
4289 T* res = phmap::allocator_traits<ValueAlloc>::allocate(value_alloc, 1);
4291 std::forward<Args>(args)...);
4292 return res;
4293 }
4294
4295 template <class Allocator>
4296 static void delete_element(Allocator* alloc, T* elem) {
4297 using ValueAlloc =
4298 typename phmap::allocator_traits<Allocator>::template rebind_alloc<T>;
4299 ValueAlloc value_alloc(*alloc);
4302 }
4303
4304 template <class F, class... Args>
4305 static decltype(phmap::priv::DecomposeValue(
4306 std::declval<F>(), std::declval<Args>()...))
4307 apply(F&& f, Args&&... args) {
4309 std::forward<F>(f), std::forward<Args>(args)...);
4310 }
4311
4312 static size_t element_space_used(const T*) { return sizeof(T); }
4313};
4314
4315// --------------------------------------------------------------------------
4316// --------------------------------------------------------------------------
4317template <class Key, class Value>
4320 std::pair<const Key, Value>&, NodeHashMapPolicy<Key, Value>>
4321{
4322 using value_type = std::pair<const Key, Value>;
4323
4324public:
4325 using key_type = Key;
4326 using mapped_type = Value;
4327 using init_type = std::pair</*non const*/ key_type, mapped_type>;
4328
4329 template <class Allocator, class... Args>
4330 static value_type* new_element(Allocator* alloc, Args&&... args) {
4331 using PairAlloc = typename phmap::allocator_traits<
4332 Allocator>::template rebind_alloc<value_type>;
4333 PairAlloc pair_alloc(*alloc);
4334 value_type* res =
4337 std::forward<Args>(args)...);
4338 return res;
4339 }
4340
4341 template <class Allocator>
4342 static void delete_element(Allocator* alloc, value_type* pair) {
4343 using PairAlloc = typename phmap::allocator_traits<
4344 Allocator>::template rebind_alloc<value_type>;
4345 PairAlloc pair_alloc(*alloc);
4348 }
4349
4350 template <class F, class... Args>
4351 static decltype(phmap::priv::DecomposePair(
4352 std::declval<F>(), std::declval<Args>()...))
4353 apply(F&& f, Args&&... args) {
4354 return phmap::priv::DecomposePair(std::forward<F>(f),
4355 std::forward<Args>(args)...);
4356 }
4357
4358 static size_t element_space_used(const value_type*) {
4359 return sizeof(value_type);
4360 }
4361
4362 static Value& value(value_type* elem) { return elem->second; }
4363 static const Value& value(const value_type* elem) { return elem->second; }
4364};
4365
4366
4367// --------------------------------------------------------------------------
4368// hash_default
4369// --------------------------------------------------------------------------
4370
4371#if PHMAP_HAVE_STD_STRING_VIEW
4372
4373// Supports heterogeneous lookup for basic_string<T>-like elements.
4374template<class CharT>
4375struct StringHashEqT
4376{
4377 struct Hash
4378 {
4379 using is_transparent = void;
4380
4381 size_t operator()(std::basic_string_view<CharT> v) const {
4382 std::string_view bv{
4383 reinterpret_cast<const char*>(v.data()), v.size() * sizeof(CharT)};
4384 return std::hash<std::string_view>()(bv);
4385 }
4386 };
4387
4388 struct Eq {
4389 using is_transparent = void;
4390
4391 bool operator()(std::basic_string_view<CharT> lhs,
4392 std::basic_string_view<CharT> rhs) const {
4393 return lhs == rhs;
4394 }
4395 };
4396};
4397
4398template <>
4399struct HashEq<std::string> : StringHashEqT<char> {};
4400
4401template <>
4402struct HashEq<std::string_view> : StringHashEqT<char> {};
4403
4404// char16_t
4405template <>
4406struct HashEq<std::u16string> : StringHashEqT<char16_t> {};
4407
4408template <>
4409struct HashEq<std::u16string_view> : StringHashEqT<char16_t> {};
4410
4411// wchar_t
4412template <>
4413struct HashEq<std::wstring> : StringHashEqT<wchar_t> {};
4414
4415template <>
4416struct HashEq<std::wstring_view> : StringHashEqT<wchar_t> {};
4417
4418#endif
4419
4420// Supports heterogeneous lookup for pointers and smart pointers.
4421// -------------------------------------------------------------
4422template <class T>
4423struct HashEq<T*>
4424{
4425 struct Hash {
4426 using is_transparent = void;
4427 template <class U>
4428 size_t operator()(const U& ptr) const {
4429 return phmap::Hash<const T*>{}(HashEq::ToPtr(ptr));
4430 }
4431 };
4432
4433 struct Eq {
4434 using is_transparent = void;
4435 template <class A, class B>
4436 bool operator()(const A& a, const B& b) const {
4437 return HashEq::ToPtr(a) == HashEq::ToPtr(b);
4438 }
4439 };
4440
4441private:
4442 static const T* ToPtr(const T* ptr) { return ptr; }
4443
4444 template <class U, class D>
4445 static const T* ToPtr(const std::unique_ptr<U, D>& ptr) {
4446 return ptr.get();
4447 }
4448
4449 template <class U>
4450 static const T* ToPtr(const std::shared_ptr<U>& ptr) {
4451 return ptr.get();
4452 }
4453};
4454
4455template <class T, class D>
4456struct HashEq<std::unique_ptr<T, D>> : HashEq<T*> {};
4457
4458template <class T>
4459struct HashEq<std::shared_ptr<T>> : HashEq<T*> {};
4460
4461namespace hashtable_debug_internal {
4462
4463// --------------------------------------------------------------------------
4464// --------------------------------------------------------------------------
4465
4466template<typename, typename = void >
4467struct has_member_type_raw_hash_set : std::false_type
4468{};
4469template<typename T>
4470struct has_member_type_raw_hash_set<T, phmap::void_t<typename T::raw_hash_set>> : std::true_type
4471{};
4472
4473template <typename Set>
4474struct HashtableDebugAccess<Set, typename std::enable_if<has_member_type_raw_hash_set<Set>::value>::type>
4475{
4476 using Traits = typename Set::PolicyTraits;
4477 using Slot = typename Traits::slot_type;
4478
4479 static size_t GetNumProbes(const Set& set,
4480 const typename Set::key_type& key) {
4481 size_t num_probes = 0;
4482 size_t hashval = set.hash(key);
4483 auto seq = set.probe(hashval);
4484 while (true) {
4485 priv::Group g{set.ctrl_ + seq.offset()};
4486 for (uint32_t i : g.Match(priv::H2(hashval))) {
4487 if (Traits::apply(
4488 typename Set::template EqualElement<typename Set::key_type>{
4489 key, set.eq_ref()},
4490 Traits::element(set.slots_ + seq.offset((size_t)i))))
4491 return num_probes;
4492 ++num_probes;
4493 }
4494 if (g.MatchEmpty()) return num_probes;
4495 seq.next();
4496 ++num_probes;
4497 }
4498 }
4499
4500 static size_t AllocatedByteSize(const Set& c) {
4501 size_t capacity = c.capacity_;
4502 if (capacity == 0) return 0;
4503 auto layout = Set::MakeLayout(capacity);
4504 size_t m = layout.AllocSize();
4505
4506 size_t per_slot = Traits::space_used(static_cast<const Slot*>(nullptr));
4507 if (per_slot != ~size_t{}) {
4508 m += per_slot * c.size();
4509 } else {
4510 for (size_t i = 0; i != capacity; ++i) {
4511 if (priv::IsFull(c.ctrl_[i])) {
4512 m += Traits::space_used(c.slots_ + i);
4513 }
4514 }
4515 }
4516 return m;
4517 }
4518
4519 static size_t LowerBoundAllocatedByteSize(size_t size) {
4520 size_t capacity = GrowthToLowerboundCapacity(size);
4521 if (capacity == 0) return 0;
4522 auto layout = Set::MakeLayout(NormalizeCapacity(capacity));
4523 size_t m = layout.AllocSize();
4524 size_t per_slot = Traits::space_used(static_cast<const Slot*>(nullptr));
4525 if (per_slot != ~size_t{}) {
4526 m += per_slot * size;
4527 }
4528 return m;
4529 }
4530};
4531
4532
4533template<typename, typename = void >
4534struct has_member_type_EmbeddedSet : std::false_type
4535{};
4536template<typename T>
4537struct has_member_type_EmbeddedSet<T, phmap::void_t<typename T::EmbeddedSet>> : std::true_type
4538{};
4539
4540template <typename Set>
4541struct HashtableDebugAccess<Set, typename std::enable_if<has_member_type_EmbeddedSet<Set>::value>::type> {
4542 using Traits = typename Set::PolicyTraits;
4543 using Slot = typename Traits::slot_type;
4544 using EmbeddedSet = typename Set::EmbeddedSet;
4545
4546 static size_t GetNumProbes(const Set& set, const typename Set::key_type& key) {
4547 size_t hashval = set.hash(key);
4548 auto& inner = set.sets_[set.subidx(hashval)];
4549 auto& inner_set = inner.set_;
4551 }
4552};
4553
4554} // namespace hashtable_debug_internal
4555} // namespace priv
4556
4557// -----------------------------------------------------------------------------
4558// phmap::flat_hash_set
4559// -----------------------------------------------------------------------------
4560// An `phmap::flat_hash_set<T>` is an unordered associative container which has
4561// been optimized for both speed and memory footprint in most common use cases.
4562// Its interface is similar to that of `std::unordered_set<T>` with the
4563// following notable differences:
4564//
4565// * Supports heterogeneous lookup, through `find()`, `operator[]()` and
4566// `insert()`, provided that the set is provided a compatible heterogeneous
4567// hashing function and equality operator.
4568// * Invalidates any references and pointers to elements within the table after
4569// `rehash()`.
4570// * Contains a `capacity()` member function indicating the number of element
4571// slots (open, deleted, and empty) within the hash set.
4572// * Returns `void` from the `_erase(iterator)` overload.
4573// -----------------------------------------------------------------------------
4574template <class T, class Hash, class Eq, class Alloc> // default values in phmap_fwd_decl.h
4577 phmap::priv::FlatHashSetPolicy<T>, Hash, Eq, Alloc>
4578{
4580
4581public:
4583#ifdef __INTEL_COMPILER
4584 using Base::raw_hash_set;
4585#else
4586 using Base::Base;
4587#endif
4588 using Base::begin;
4589 using Base::cbegin;
4590 using Base::cend;
4591 using Base::end;
4592 using Base::capacity;
4593 using Base::empty;
4594 using Base::max_size;
4595 using Base::size;
4596 using Base::clear; // may shrink - To avoid shrinking `erase(begin(), end())`
4597 using Base::erase;
4598 using Base::insert;
4599 using Base::emplace;
4600 using Base::emplace_hint;
4601 using Base::extract;
4602 using Base::merge;
4603 using Base::swap;
4604 using Base::rehash;
4605 using Base::reserve;
4606 using Base::contains;
4607 using Base::count;
4608 using Base::equal_range;
4609 using Base::find;
4610 using Base::bucket_count;
4611 using Base::load_factor;
4612 using Base::max_load_factor;
4613 using Base::get_allocator;
4614 using Base::hash_function;
4615 using Base::hash;
4616 using Base::key_eq;
4617};
4618
4619// -----------------------------------------------------------------------------
4620// phmap::flat_hash_map
4621// -----------------------------------------------------------------------------
4622//
4623// An `phmap::flat_hash_map<K, V>` is an unordered associative container which
4624// has been optimized for both speed and memory footprint in most common use
4625// cases. Its interface is similar to that of `std::unordered_map<K, V>` with
4626// the following notable differences:
4627//
4628// * Supports heterogeneous lookup, through `find()`, `operator[]()` and
4629// `insert()`, provided that the map is provided a compatible heterogeneous
4630// hashing function and equality operator.
4631// * Invalidates any references and pointers to elements within the table after
4632// `rehash()`.
4633// * Contains a `capacity()` member function indicating the number of element
4634// slots (open, deleted, and empty) within the hash map.
4635// * Returns `void` from the `_erase(iterator)` overload.
4636// -----------------------------------------------------------------------------
4637template <class K, class V, class Hash, class Eq, class Alloc> // default values in phmap_fwd_decl.h
4639 phmap::priv::FlatHashMapPolicy<K, V>,
4640 Hash, Eq, Alloc> {
4642
4643public:
4645#ifdef __INTEL_COMPILER
4646 using Base::raw_hash_map;
4647#else
4648 using Base::Base;
4649#endif
4650 using Base::begin;
4651 using Base::cbegin;
4652 using Base::cend;
4653 using Base::end;
4654 using Base::capacity;
4655 using Base::empty;
4656 using Base::max_size;
4657 using Base::size;
4658 using Base::clear;
4659 using Base::erase;
4660 using Base::insert;
4661 using Base::insert_or_assign;
4662 using Base::emplace;
4663 using Base::emplace_hint;
4664 using Base::try_emplace;
4665 using Base::extract;
4666 using Base::merge;
4667 using Base::swap;
4668 using Base::rehash;
4669 using Base::reserve;
4670 using Base::at;
4671 using Base::contains;
4672 using Base::count;
4673 using Base::equal_range;
4674 using Base::find;
4675 using Base::operator[];
4676 using Base::bucket_count;
4677 using Base::load_factor;
4678 using Base::max_load_factor;
4679 using Base::get_allocator;
4680 using Base::hash_function;
4681 using Base::hash;
4682 using Base::key_eq;
4683};
4684
4685// -----------------------------------------------------------------------------
4686// phmap::node_hash_set
4687// -----------------------------------------------------------------------------
4688// An `phmap::node_hash_set<T>` is an unordered associative container which
4689// has been optimized for both speed and memory footprint in most common use
4690// cases. Its interface is similar to that of `std::unordered_set<T>` with the
4691// following notable differences:
4692//
4693// * Supports heterogeneous lookup, through `find()`, `operator[]()` and
4694// `insert()`, provided that the map is provided a compatible heterogeneous
4695// hashing function and equality operator.
4696// * Contains a `capacity()` member function indicating the number of element
4697// slots (open, deleted, and empty) within the hash set.
4698// * Returns `void` from the `erase(iterator)` overload.
4699// -----------------------------------------------------------------------------
4700template <class T, class Hash, class Eq, class Alloc> // default values in phmap_fwd_decl.h
4703 phmap::priv::NodeHashSetPolicy<T>, Hash, Eq, Alloc>
4704{
4706
4707public:
4709#ifdef __INTEL_COMPILER
4710 using Base::raw_hash_set;
4711#else
4712 using Base::Base;
4713#endif
4714 using Base::begin;
4715 using Base::cbegin;
4716 using Base::cend;
4717 using Base::end;
4718 using Base::capacity;
4719 using Base::empty;
4720 using Base::max_size;
4721 using Base::size;
4722 using Base::clear;
4723 using Base::erase;
4724 using Base::insert;
4725 using Base::emplace;
4726 using Base::emplace_hint;
4727 using Base::emplace_with_hash;
4728 using Base::emplace_hint_with_hash;
4729 using Base::extract;
4730 using Base::merge;
4731 using Base::swap;
4732 using Base::rehash;
4733 using Base::reserve;
4734 using Base::contains;
4735 using Base::count;
4736 using Base::equal_range;
4737 using Base::find;
4738 using Base::bucket_count;
4739 using Base::load_factor;
4740 using Base::max_load_factor;
4741 using Base::get_allocator;
4742 using Base::hash_function;
4743 using Base::hash;
4744 using Base::key_eq;
4745 typename Base::hasher hash_funct() { return this->hash_function(); }
4746 void resize(typename Base::size_type hint) { this->rehash(hint); }
4747};
4748
4749// -----------------------------------------------------------------------------
4750// phmap::node_hash_map
4751// -----------------------------------------------------------------------------
4752//
4753// An `phmap::node_hash_map<K, V>` is an unordered associative container which
4754// has been optimized for both speed and memory footprint in most common use
4755// cases. Its interface is similar to that of `std::unordered_map<K, V>` with
4756// the following notable differences:
4757//
4758// * Supports heterogeneous lookup, through `find()`, `operator[]()` and
4759// `insert()`, provided that the map is provided a compatible heterogeneous
4760// hashing function and equality operator.
4761// * Contains a `capacity()` member function indicating the number of element
4762// slots (open, deleted, and empty) within the hash map.
4763// * Returns `void` from the `erase(iterator)` overload.
4764// -----------------------------------------------------------------------------
4765template <class Key, class Value, class Hash, class Eq, class Alloc> // default values in phmap_fwd_decl.h
4768 phmap::priv::NodeHashMapPolicy<Key, Value>, Hash, Eq,
4769 Alloc>
4770{
4772
4773public:
4775#ifdef __INTEL_COMPILER
4776 using Base::raw_hash_map;
4777#else
4778 using Base::Base;
4779#endif
4780 using Base::begin;
4781 using Base::cbegin;
4782 using Base::cend;
4783 using Base::end;
4784 using Base::capacity;
4785 using Base::empty;
4786 using Base::max_size;
4787 using Base::size;
4788 using Base::clear;
4789 using Base::erase;
4790 using Base::insert;
4791 using Base::insert_or_assign;
4792 using Base::emplace;
4793 using Base::emplace_hint;
4794 using Base::try_emplace;
4795 using Base::extract;
4796 using Base::merge;
4797 using Base::swap;
4798 using Base::rehash;
4799 using Base::reserve;
4800 using Base::at;
4801 using Base::contains;
4802 using Base::count;
4803 using Base::equal_range;
4804 using Base::find;
4805 using Base::operator[];
4806 using Base::bucket_count;
4807 using Base::load_factor;
4808 using Base::max_load_factor;
4809 using Base::get_allocator;
4810 using Base::hash_function;
4811 using Base::hash;
4812 using Base::key_eq;
4813 typename Base::hasher hash_funct() { return this->hash_function(); }
4814 void resize(typename Base::size_type hint) { this->rehash(hint); }
4815};
4816
4817// -----------------------------------------------------------------------------
4818// phmap::parallel_flat_hash_set
4819// -----------------------------------------------------------------------------
4820template <class T, class Hash, class Eq, class Alloc, size_t N, class Mtx_> // default values in phmap_fwd_decl.h
4823 N, phmap::priv::raw_hash_set, Mtx_,
4824 phmap::priv::FlatHashSetPolicy<T>,
4825 Hash, Eq, Alloc>
4826{
4828
4829public:
4831#ifdef __INTEL_COMPILER
4832 using Base::parallel_hash_set;
4833#else
4834 using Base::Base;
4835#endif
4836 using Base::hash;
4837 using Base::subidx;
4838 using Base::subcnt;
4839 using Base::begin;
4840 using Base::cbegin;
4841 using Base::cend;
4842 using Base::end;
4843 using Base::capacity;
4844 using Base::empty;
4845 using Base::max_size;
4846 using Base::size;
4847 using Base::clear;
4848 using Base::erase;
4849 using Base::insert;
4850 using Base::emplace;
4851 using Base::emplace_hint;
4852 using Base::emplace_with_hash;
4853 using Base::emplace_hint_with_hash;
4854 using Base::extract;
4855 using Base::merge;
4856 using Base::swap;
4857 using Base::rehash;
4858 using Base::reserve;
4859 using Base::contains;
4860 using Base::count;
4861 using Base::equal_range;
4862 using Base::find;
4863 using Base::bucket_count;
4864 using Base::load_factor;
4865 using Base::max_load_factor;
4866 using Base::get_allocator;
4867 using Base::hash_function;
4868 using Base::key_eq;
4869};
4870
4871// -----------------------------------------------------------------------------
4872// phmap::parallel_flat_hash_map - default values in phmap_fwd_decl.h
4873// -----------------------------------------------------------------------------
4874template <class K, class V, class Hash, class Eq, class Alloc, size_t N, class Mtx_>
4876 N, phmap::priv::raw_hash_set, Mtx_,
4877 phmap::priv::FlatHashMapPolicy<K, V>,
4878 Hash, Eq, Alloc>
4879{
4881
4882public:
4884#ifdef __INTEL_COMPILER
4885 using Base::parallel_hash_map;
4886#else
4887 using Base::Base;
4888#endif
4889 using Base::hash;
4890 using Base::subidx;
4891 using Base::subcnt;
4892 using Base::begin;
4893 using Base::cbegin;
4894 using Base::cend;
4895 using Base::end;
4896 using Base::capacity;
4897 using Base::empty;
4898 using Base::max_size;
4899 using Base::size;
4900 using Base::clear;
4901 using Base::erase;
4902 using Base::insert;
4903 using Base::insert_or_assign;
4904 using Base::emplace;
4905 using Base::emplace_hint;
4906 using Base::try_emplace;
4907 using Base::emplace_with_hash;
4908 using Base::emplace_hint_with_hash;
4909 using Base::try_emplace_with_hash;
4910 using Base::extract;
4911 using Base::merge;
4912 using Base::swap;
4913 using Base::rehash;
4914 using Base::reserve;
4915 using Base::at;
4916 using Base::contains;
4917 using Base::count;
4918 using Base::equal_range;
4919 using Base::find;
4920 using Base::operator[];
4921 using Base::bucket_count;
4922 using Base::load_factor;
4923 using Base::max_load_factor;
4924 using Base::get_allocator;
4925 using Base::hash_function;
4926 using Base::key_eq;
4927};
4928
4929// -----------------------------------------------------------------------------
4930// phmap::parallel_node_hash_set
4931// -----------------------------------------------------------------------------
4932template <class T, class Hash, class Eq, class Alloc, size_t N, class Mtx_>
4935 N, phmap::priv::raw_hash_set, Mtx_,
4936 phmap::priv::NodeHashSetPolicy<T>, Hash, Eq, Alloc>
4937{
4939
4940public:
4942#ifdef __INTEL_COMPILER
4943 using Base::parallel_hash_set;
4944#else
4945 using Base::Base;
4946#endif
4947 using Base::hash;
4948 using Base::subidx;
4949 using Base::subcnt;
4950 using Base::begin;
4951 using Base::cbegin;
4952 using Base::cend;
4953 using Base::end;
4954 using Base::capacity;
4955 using Base::empty;
4956 using Base::max_size;
4957 using Base::size;
4958 using Base::clear;
4959 using Base::erase;
4960 using Base::insert;
4961 using Base::emplace;
4962 using Base::emplace_hint;
4963 using Base::emplace_with_hash;
4964 using Base::emplace_hint_with_hash;
4965 using Base::extract;
4966 using Base::merge;
4967 using Base::swap;
4968 using Base::rehash;
4969 using Base::reserve;
4970 using Base::contains;
4971 using Base::count;
4972 using Base::equal_range;
4973 using Base::find;
4974 using Base::bucket_count;
4975 using Base::load_factor;
4976 using Base::max_load_factor;
4977 using Base::get_allocator;
4978 using Base::hash_function;
4979 using Base::key_eq;
4980 typename Base::hasher hash_funct() { return this->hash_function(); }
4981 void resize(typename Base::size_type hint) { this->rehash(hint); }
4982};
4983
4984// -----------------------------------------------------------------------------
4985// phmap::parallel_node_hash_map
4986// -----------------------------------------------------------------------------
4987template <class Key, class Value, class Hash, class Eq, class Alloc, size_t N, class Mtx_>
4990 N, phmap::priv::raw_hash_set, Mtx_,
4991 phmap::priv::NodeHashMapPolicy<Key, Value>, Hash, Eq,
4992 Alloc>
4993{
4995
4996public:
4998#ifdef __INTEL_COMPILER
4999 using Base::parallel_hash_map;
5000#else
5001 using Base::Base;
5002#endif
5003 using Base::hash;
5004 using Base::subidx;
5005 using Base::subcnt;
5006 using Base::begin;
5007 using Base::cbegin;
5008 using Base::cend;
5009 using Base::end;
5010 using Base::capacity;
5011 using Base::empty;
5012 using Base::max_size;
5013 using Base::size;
5014 using Base::clear;
5015 using Base::erase;
5016 using Base::insert;
5017 using Base::insert_or_assign;
5018 using Base::emplace;
5019 using Base::emplace_hint;
5020 using Base::try_emplace;
5021 using Base::emplace_with_hash;
5022 using Base::emplace_hint_with_hash;
5023 using Base::try_emplace_with_hash;
5024 using Base::extract;
5025 using Base::merge;
5026 using Base::swap;
5027 using Base::rehash;
5028 using Base::reserve;
5029 using Base::at;
5030 using Base::contains;
5031 using Base::count;
5032 using Base::equal_range;
5033 using Base::find;
5034 using Base::operator[];
5035 using Base::bucket_count;
5036 using Base::load_factor;
5037 using Base::max_load_factor;
5038 using Base::get_allocator;
5039 using Base::hash_function;
5040 using Base::key_eq;
5041 typename Base::hasher hash_funct() { return this->hash_function(); }
5042 void resize(typename Base::size_type hint) { this->rehash(hint); }
5043};
5044
5045} // namespace phmap
5046
5047
5048namespace phmap {
5049 namespace priv {
5050 template <class C, class Pred>
5051 std::size_t erase_if(C &c, Pred pred) {
5052 auto old_size = c.size();
5053 for (auto i = c.begin(), last = c.end(); i != last; ) {
5054 if (pred(*i)) {
5055 i = c.erase(i);
5056 } else {
5057 ++i;
5058 }
5059 }
5060 return old_size - c.size();
5061 }
5062 } // priv
5063
5064 // ======== erase_if for phmap set containers ==================================
5065 template <class T, class Hash, class Eq, class Alloc, class Pred>
5067 return phmap::priv::erase_if(c, std::move(pred));
5068 }
5069
5070 template <class T, class Hash, class Eq, class Alloc, class Pred>
5072 return phmap::priv::erase_if(c, std::move(pred));
5073 }
5074
5075 template <class T, class Hash, class Eq, class Alloc, size_t N, class Mtx_, class Pred>
5077 return phmap::priv::erase_if(c, std::move(pred));
5078 }
5079
5080 template <class T, class Hash, class Eq, class Alloc, size_t N, class Mtx_, class Pred>
5082 return phmap::priv::erase_if(c, std::move(pred));
5083 }
5084
5085 // ======== erase_if for phmap map containers ==================================
5086 template <class K, class V, class Hash, class Eq, class Alloc, class Pred>
5088 return phmap::priv::erase_if(c, std::move(pred));
5089 }
5090
5091 template <class K, class V, class Hash, class Eq, class Alloc, class Pred>
5093 return phmap::priv::erase_if(c, std::move(pred));
5094 }
5095
5096 template <class K, class V, class Hash, class Eq, class Alloc, size_t N, class Mtx_, class Pred>
5098 return phmap::priv::erase_if(c, std::move(pred));
5099 }
5100
5101 template <class K, class V, class Hash, class Eq, class Alloc, size_t N, class Mtx_, class Pred>
5103 return phmap::priv::erase_if(c, std::move(pred));
5104 }
5105
5106} // phmap
5107
5108#ifdef _MSC_VER
5109 #pragma warning(pop)
5110#endif
5111
5112
5113#endif // phmap_h_guard_
Definition: phmap_base.h:5037
typename Base::WriteLock UpgradeLock
Definition: phmap_base.h:5042
typename Base::WriteLock SharedLock
Definition: phmap_base.h:5041
typename Base::DoNothing UpgradeToUnique
Definition: phmap_base.h:5046
typename Base::WriteLocks UniqueLocks
Definition: phmap_base.h:5045
typename Base::WriteLocks SharedLocks
Definition: phmap_base.h:5044
typename Base::WriteLock UniqueLock
Definition: phmap_base.h:5043
Definition: phmap.h:4640
typename flat_hash_map::raw_hash_map Base
Definition: phmap.h:4641
flat_hash_map()
Definition: phmap.h:4644
Definition: phmap.h:4578
flat_hash_set()
Definition: phmap.h:4582
typename flat_hash_set::raw_hash_set Base
Definition: phmap.h:4579
Definition: phmap.h:4770
node_hash_map()
Definition: phmap.h:4774
typename node_hash_map::raw_hash_map Base
Definition: phmap.h:4771
void resize(typename Base::size_type hint)
Definition: phmap.h:4814
Base::hasher hash_funct()
Definition: phmap.h:4813
Definition: phmap.h:4704
typename node_hash_set::raw_hash_set Base
Definition: phmap.h:4705
void resize(typename Base::size_type hint)
Definition: phmap.h:4746
node_hash_set()
Definition: phmap.h:4708
Base::hasher hash_funct()
Definition: phmap.h:4745
Definition: phmap.h:4879
parallel_flat_hash_map()
Definition: phmap.h:4883
typename parallel_flat_hash_map::parallel_hash_map Base
Definition: phmap.h:4880
Definition: phmap.h:4826
typename parallel_flat_hash_set::parallel_hash_set Base
Definition: phmap.h:4827
parallel_flat_hash_set()
Definition: phmap.h:4830
Definition: phmap.h:4993
parallel_node_hash_map()
Definition: phmap.h:4997
Base::hasher hash_funct()
Definition: phmap.h:5041
typename parallel_node_hash_map::parallel_hash_map Base
Definition: phmap.h:4994
void resize(typename Base::size_type hint)
Definition: phmap.h:5042
Definition: phmap.h:4937
parallel_node_hash_set()
Definition: phmap.h:4941
void resize(typename Base::size_type hint)
Definition: phmap.h:4981
Base::hasher hash_funct()
Definition: phmap.h:4980
typename parallel_node_hash_set::parallel_hash_set Base
Definition: phmap.h:4938
Definition: phmap.h:231
BitMask & operator++()
Definition: phmap.h:243
friend bool operator!=(const BitMask &a, const BitMask &b)
Definition: phmap.h:276
BitMask begin() const
Definition: phmap.h:259
T mask_
Definition: phmap.h:280
BitMask end() const
Definition: phmap.h:260
uint32_t HighestBitSet() const
Definition: phmap.h:255
friend bool operator==(const BitMask &a, const BitMask &b)
Definition: phmap.h:273
uint32_t LeadingZeros() const
Definition: phmap.h:266
uint32_t operator*() const
Definition: phmap.h:249
uint32_t LowestBitSet() const
Definition: phmap.h:251
uint32_t TrailingZeros() const
Definition: phmap.h:262
BitMask(T mask)
Definition: phmap.h:241
int value_type
Definition: phmap.h:237
Definition: phmap_base.h:4286
Definition: phmap.h:667
friend void swap(HashtablezInfoHandle &, HashtablezInfoHandle &) noexcept
Definition: phmap.h:673
void RecordInsert(size_t, size_t)
Definition: phmap.h:671
void RecordStorageChanged(size_t, size_t)
Definition: phmap.h:669
void RecordErase()
Definition: phmap.h:672
void RecordRehash(size_t)
Definition: phmap.h:670
Definition: phmap.h:680
void Unregister(HashtablezInfo *)
Definition: phmap.h:685
void(*)(const HashtablezInfo &) DisposeCallback
Definition: phmap.h:687
int64_t Iterate(const std::function< void(const HashtablezInfo &stack)> &)
Definition: phmap.h:689
DisposeCallback SetDisposeCallback(DisposeCallback)
Definition: phmap.h:688
HashtablezInfo * Register()
Definition: phmap.h:684
static HashtablezSampler & Global()
Definition: phmap.h:683
Definition: phmap_base.h:4129
Definition: phmap.h:4321
Value mapped_type
Definition: phmap.h:4326
static size_t element_space_used(const value_type *)
Definition: phmap.h:4358
static void delete_element(Allocator *alloc, value_type *pair)
Definition: phmap.h:4342
std::pair< const Key, Value > value_type
Definition: phmap.h:4322
Key key_type
Definition: phmap.h:4325
static const Value & value(const value_type *elem)
Definition: phmap.h:4363
static Value & value(value_type *elem)
Definition: phmap.h:4362
static value_type * new_element(Allocator *alloc, Args &&... args)
Definition: phmap.h:4330
static decltype(phmap::priv::DecomposePair(std::declval< F >(), std::declval< Args >()...)) apply(F &&f, Args &&... args)
Definition: phmap.h:4353
std::pair< key_type, mapped_type > init_type
Definition: phmap.h:4327
Definition: phmap_base.h:2833
Definition: phmap.h:3811
MappedReference< P > operator[](const key_arg< K > &key)
Definition: phmap.h:4000
std::pair< iterator, bool > try_emplace_impl(K &&k, Args &&... args)
Definition: phmap.h:4020
std::pair< iterator, bool > try_emplace(const key_arg< K > &k, Args &&... args)
Definition: phmap.h:3913
std::pair< iterator, bool > insert_or_assign(key_arg< K > &&k, const V &v)
Definition: phmap.h:3867
iterator try_emplace(const_iterator, const key_arg< K > &k, Args &&... args)
Definition: phmap.h:3923
parallel_hash_map()
Definition: phmap.h:3845
iterator insert_or_assign(const_iterator, key_arg< K > &&k, const V &v)
Definition: phmap.h:3888
std::pair< iterator, bool > insert_or_assign(key_arg< K > &&k, V &&v)
Definition: phmap.h:3862
typename Base::value_type value_type
Definition: phmap.h:3833
std::pair< iterator, bool > try_emplace_with_hash(size_t hashval, const key_arg< K > &k, Args &&... args)
Definition: phmap.h:3956
typename Policy::key_type key_type
Definition: phmap.h:3831
iterator try_emplace(const_iterator, key_arg< K > &&k, Args &&... args)
Definition: phmap.h:3918
MappedReference< P > at(const key_arg< K > &key)
Definition: phmap.h:3928
std::pair< iterator, bool > try_emplace_with_hash(size_t hashval, key_arg< K > &&k, Args &&... args)
Definition: phmap.h:3949
iterator insert_or_assign(const_iterator, key_arg< K > &&k, V &&v)
Definition: phmap.h:3883
iterator try_emplace_with_hash(size_t hashval, const_iterator, key_arg< K > &&k, Args &&... args)
Definition: phmap.h:3961
std::pair< iterator, bool > try_emplace(key_arg< K > &&k, Args &&... args)
Definition: phmap.h:3906
typename Policy::mapped_type mapped_type
Definition: phmap.h:3832
typename parallel_hash_map::parallel_hash_set Base
Definition: phmap.h:3827
std::pair< iterator, bool > try_emplace_impl_with_hash(size_t hashval, K &&k, Args &&... args)
Definition: phmap.h:4033
bool try_emplace_l(K &&k, F &&f, Args &&... args)
Definition: phmap.h:3977
iterator insert_or_assign(const_iterator, const key_arg< K > &k, V &&v)
Definition: phmap.h:3893
typename parallel_hash_map::parallel_hash_set::iterator iterator
Definition: phmap.h:3842
typename KeyArgImpl::template type< K, key_type > key_arg
Definition: phmap.h:3835
std::pair< iterator, bool > insert_or_assign_impl(K &&k, V &&v)
Definition: phmap.h:4007
std::pair< iterator, bool > insert_or_assign(const key_arg< K > &k, const V &v)
Definition: phmap.h:3877
MappedConstReference< P > at(const key_arg< K > &key) const
Definition: phmap.h:3936
iterator insert_or_assign(const_iterator, const key_arg< K > &k, const V &v)
Definition: phmap.h:3898
iterator try_emplace_with_hash(size_t hashval, const_iterator, const key_arg< K > &k, Args &&... args)
Definition: phmap.h:3966
MappedReference< P > operator[](key_arg< K > &&key)
Definition: phmap.h:3995
typename parallel_hash_map::parallel_hash_set::const_iterator const_iterator
Definition: phmap.h:3843
std::pair< iterator, bool > insert_or_assign(const key_arg< K > &k, V &&v)
Definition: phmap.h:3872
decltype(P::value(std::addressof(std::declval< typename parallel_hash_map::reference >()))) MappedReference
Definition: phmap.h:3817
decltype(P::value(std::addressof(std::declval< typename parallel_hash_map::const_reference >()))) MappedConstReference
Definition: phmap.h:3822
reference operator*() const
Definition: phmap.h:2695
const_iterator operator++(int)
Definition: phmap.h:2702
typename iterator::iterator_category iterator_category
Definition: phmap.h:2684
typename parallel_hash_set::difference_type difference_type
Definition: phmap.h:2688
const_iterator(iterator i)
Definition: phmap.h:2693
typename parallel_hash_set::value_type value_type
Definition: phmap.h:2685
typename parallel_hash_set::const_pointer pointer
Definition: phmap.h:2687
friend bool operator!=(const const_iterator &a, const const_iterator &b)
Definition: phmap.h:2707
iterator iter_
Definition: phmap.h:2717
const_iterator & operator++()
Definition: phmap.h:2698
friend bool operator==(const const_iterator &a, const const_iterator &b)
Definition: phmap.h:2704
const_iterator(const Inner *inner, const Inner *inner_end, const EmbeddedIterator &it)
Definition: phmap.h:2712
typename parallel_hash_set::Inner Inner
Definition: phmap.h:2689
pointer operator->() const
Definition: phmap.h:2696
typename parallel_hash_set::const_reference reference
Definition: phmap.h:2686
typename parallel_hash_set::Inner Inner
Definition: phmap.h:2621
phmap::remove_reference_t< reference > * pointer
Definition: phmap.h:2619
iterator()
Definition: phmap.h:2625
std::forward_iterator_tag iterator_category
Definition: phmap.h:2614
phmap::conditional_t< PolicyTraits::constant_iterators::value, const value_type &, value_type & > reference
Definition: phmap.h:2618
Inner * inner_
Definition: phmap.h:2673
iterator & operator++()
Definition: phmap.h:2630
typename parallel_hash_set::EmbeddedSet EmbeddedSet
Definition: phmap.h:2622
friend bool operator!=(const iterator &a, const iterator &b)
Definition: phmap.h:2648
void skip_empty()
Definition: phmap.h:2659
EmbeddedIterator it_
Definition: phmap.h:2675
reference operator*() const
Definition: phmap.h:2627
typename parallel_hash_set::difference_type difference_type
Definition: phmap.h:2620
iterator operator++(int)
Definition: phmap.h:2637
friend bool operator==(const iterator &a, const iterator &b)
Definition: phmap.h:2644
pointer operator->() const
Definition: phmap.h:2628
iterator(Inner *inner, Inner *inner_end, const EmbeddedIterator &it)
Definition: phmap.h:2653
typename EmbeddedSet::iterator EmbeddedIterator
Definition: phmap.h:2623
typename parallel_hash_set::value_type value_type
Definition: phmap.h:2615
Inner * inner_end_
Definition: phmap.h:2674
EmbeddedIterator it_end_
Definition: phmap.h:2675
Definition: phmap.h:2498
friend void swap(parallel_hash_set &a, parallel_hash_set< N, RefSet, Mtx2_, Policy, Hash, Eq, Alloc > &b) noexcept(noexcept(a.swap(b)))
Definition: phmap.h:3634
friend bool operator==(const parallel_hash_set &a, const parallel_hash_set &b)
Definition: phmap.h:3625
bool erase_if_impl(const key_arg< K > &key, F &&f)
Definition: phmap.h:3271
~parallel_hash_set()
Definition: phmap.h:2883
void _erase(iterator it)
Definition: phmap.h:3424
parallel_hash_set(InputIter first, InputIter last, size_t bucket_cnt, const allocator_type &alloc)
Definition: phmap.h:2778
bool has_element(const value_type &elem) const
Definition: phmap.h:3706
std::pair< iterator, bool > insert(init_type &&value)
Definition: phmap.h:2972
allocator_type & alloc_ref()
Definition: phmap.h:3795
bool contains(const key_arg< K > &key) const
Definition: phmap.h:3577
parallel_hash_set(std::initializer_list< init_type > init, size_t bucket_cnt, const allocator_type &alloc)
Definition: phmap.h:2833
iterator emplace_hint_with_hash(size_t hashval, const_iterator, Args &&... args)
Definition: phmap.h:3101
size_t count(const key_arg< K > &key) const
Definition: phmap.h:3525
void insert(std::initializer_list< init_type > ilist)
Definition: phmap.h:3008
size_t size() const
Definition: phmap.h:2899
auto KeyTypeCanBeHashed(const Hash &h, const key_type &k) -> decltype(h(k))
const hasher & hash_ref() const
Definition: phmap.h:3792
void emplace_single_with_hash(const key_arg< K > &key, size_t hashval, F &&f)
Definition: phmap.h:3206
const_iterator end() const
Definition: phmap.h:2893
parallel_hash_set(const allocator_type &alloc)
Definition: phmap.h:2761
const value_type & const_reference
Definition: phmap.h:2523
parallel_hash_set(std::initializer_list< T > init, size_t bucket_cnt, const allocator_type &alloc)
Definition: phmap.h:2829
const key_equal & eq_ref() const
Definition: phmap.h:3794
auto KeyTypeCanBeEq(const Eq &eq, const key_type &k) -> decltype(eq(k, k))
iterator find(const key_arg< K > &key)
Definition: phmap.h:3562
void rehash(size_t n)
Definition: phmap.h:3498
allocator_type get_allocator() const
Definition: phmap.h:3623
typename PolicyTraits::slot_type slot_type
Definition: phmap.h:2514
void for_each_m(F &&fCallback)
Definition: phmap.h:3323
std::pair< iterator, bool > make_rv(Inner *inner, const std::pair< EmbeddedIterator, bool > &res)
Definition: phmap.h:3186
void erase_meta_only(const_iterator cit)
Definition: phmap.h:3692
iterator erase(iterator it)
Definition: phmap.h:3438
parallel_hash_set & move_assign(parallel_hash_set< N, RefSet, Mtx2_, Policy, Hash, Eq, Alloc > &&that, std::true_type)
Definition: phmap.h:3717
typename EmbeddedSet::iterator EmbeddedIterator
Definition: phmap.h:2509
parallel_hash_set(InputIter first, InputIter last, size_t bucket_cnt, const hasher &hash_param, const allocator_type &alloc)
Definition: phmap.h:2773
parallel_hash_set(parallel_hash_set &&that) noexcept(std::is_nothrow_copy_constructible< hasher >::value &&std::is_nothrow_copy_constructible< key_equal >::value &&std::is_nothrow_copy_constructible< allocator_type >::value)
Definition: phmap.h:2855
size_type erase(const key_arg< K > &key)
Definition: phmap.h:3392
iterator make_iterator(Inner *inner, const EmbeddedIterator it)
Definition: phmap.h:3179
const_iterator iterator_at(Inner *inner, const EmbeddedIterator &it) const
Definition: phmap.h:3768
size_t size_type
Definition: phmap.h:2516
IsDecomposable< void, PolicyTraits, Hash, Eq, Ts... > IsDecomposable
Definition: phmap.h:2600
iterator insert(const_iterator, const T &value)
Definition: phmap.h:2990
iterator emplace_hint(const_iterator, Args &&... args)
Definition: phmap.h:3175
node_type extract(const key_arg< K > &key)
Definition: phmap.h:3476
key_equal key_eq() const
Definition: phmap.h:3622
void insert(InputIt first, InputIt last)
Definition: phmap.h:2999
std::pair< iterator, bool > emplace_decomposable(const K &key, Args &&... args)
Definition: phmap.h:3118
insert_return_type insert(node_type &&node)
Definition: phmap.h:3012
Policy policy_type
Definition: phmap.h:2520
parallel_hash_set(std::initializer_list< T > init, const allocator_type &alloc)
Definition: phmap.h:2838
const allocator_type & alloc_ref() const
Definition: phmap.h:3796
void prefetch_hash(size_t hashval) const
Definition: phmap.h:3535
parallel_hash_set & operator=(parallel_hash_set &&that) noexcept(phmap::allocator_traits< allocator_type >::is_always_equal::value &&std::is_nothrow_move_assignable< hasher >::value &&std::is_nothrow_move_assignable< key_equal >::value)
Definition: phmap.h:2874
const_iterator cend() const
Definition: phmap.h:2895
parallel_hash_set(std::initializer_list< init_type > init, size_t bucket_cnt=0, const hasher &hash_param=hasher(), const key_equal &eq=key_equal(), const allocator_type &alloc=allocator_type())
Definition: phmap.h:2814
Eq key_equal
Definition: phmap.h:2519
parallel_hash_set & operator=(const parallel_hash_set &that)
Definition: phmap.h:2868
value_type & reference
Definition: phmap.h:2522
size_t hash(const K &key) const
Definition: phmap.h:3642
hasher hash_function() const
Definition: phmap.h:3621
bool modify_if_impl(const key_arg< K > &key, F &&f)
Definition: phmap.h:3248
static size_t subcnt()
Definition: phmap.h:3777
parallel_hash_set(const parallel_hash_set &that, const allocator_type &a)
Definition: phmap.h:2849
typename phmap::allocator_traits< allocator_type >::template rebind_traits< value_type >::pointer pointer
Definition: phmap.h:2525
typename std::enable_if< phmap::disjunction< std::is_convertible< T, init_type >, SameAsElementReference< T > >::value, int >::type RequiresInsertable
Definition: phmap.h:2591
parallel_hash_set(parallel_hash_set &&that, const allocator_type &a)
Definition: phmap.h:2862
typename PolicyTraits::value_type value_type
Definition: phmap.h:2521
Alloc allocator_type
Definition: phmap.h:2515
iterator insert(const_iterator, init_type &&value)
Definition: phmap.h:2994
parallel_hash_set(std::initializer_list< T > init, size_t bucket_cnt, const hasher &hash_param, const allocator_type &alloc)
Definition: phmap.h:2820
node_handle< Policy, hash_policy_traits< Policy >, Alloc > node_type
Definition: phmap.h:2720
pointer find_ptr(const key_arg< K > &key, size_t hashval, L &mutexlock)
Definition: phmap.h:3732
std::tuple< Inner *, size_t, bool > find_or_prepare_insert_with_hash(size_t hashval, const K &key, typename Lockable::UniqueLock &mutexlock)
Definition: phmap.h:3750
std::pair< iterator, iterator > equal_range(const key_arg< K > &key)
Definition: phmap.h:3587
std::pair< iterator, bool > emplace_decomposable_with_hash(const K &key, size_t hashval, Args &&... args)
Definition: phmap.h:3045
void emplace_single(const key_arg< K > &key, F &&f)
Definition: phmap.h:3214
key_equal & eq_ref()
Definition: phmap.h:3793
const_iterator find(const key_arg< K > &key) const
Definition: phmap.h:3572
iterator lazy_emplace_with_hash(const key_arg< K > &key, size_t hashval, F &&f)
Definition: phmap.h:3106
bool contains(const key_arg< K > &key, size_t hashval) const
Definition: phmap.h:3582
const_iterator cbegin() const
Definition: phmap.h:2894
bool lazy_emplace_l(const key_arg< K > &key, FExists &&fExists, FEmplace &&fEmplace)
Definition: phmap.h:3293
friend bool operator!=(const parallel_hash_set &a, const parallel_hash_set &b)
Definition: phmap.h:3629
Inner & get_inner(size_t idx)
Definition: phmap.h:3376
const_iterator begin() const
Definition: phmap.h:2892
size_t capacity() const
Definition: phmap.h:2906
hasher & hash_ref()
Definition: phmap.h:3791
std::pair< iterator, bool > emplace(Args &&... args)
Definition: phmap.h:3148
void drop_deletes_without_resize() PHMAP_ATTRIBUTE_NOINLINE
Definition: phmap.h:3698
hash_policy_traits< Policy > PolicyTraits
Definition: phmap.h:2499
parallel_hash_set(std::initializer_list< init_type > init, size_t bucket_cnt, const hasher &hash_param, const allocator_type &alloc)
Definition: phmap.h:2824
iterator find(const key_arg< K > &key, size_t hashval, L &mutexlock)
Definition: phmap.h:3741
size_t max_size() const
Definition: phmap.h:2913
std::array< Inner, num_tables > sets_
Definition: phmap.h:3801
parallel_hash_set() noexcept(std::is_nothrow_default_constructible< hasher >::value &&std::is_nothrow_default_constructible< key_equal >::value &&std::is_nothrow_default_constructible< allocator_type >::value)
Definition: phmap.h:2725
void _erase(const_iterator cit)
Definition: phmap.h:3432
PHMAP_ATTRIBUTE_REINITIALIZES void clear()
Definition: phmap.h:2915
void merge(parallel_hash_set< N, RefSet, Mtx_, Policy, Hash, E, Alloc > &&src)
Definition: phmap.h:3465
void swap(parallel_hash_set< N, RefSet, Mtx2_, Policy, Hash, Eq, Alloc > &that) noexcept(IsNoThrowSwappable< EmbeddedSet >() &&(!AllocTraits::propagate_on_container_swap::value||IsNoThrowSwappable< allocator_type >()))
Definition: phmap.h:3482
iterator erase(const_iterator first, const_iterator last)
Definition: phmap.h:3440
void with_submap_m(size_t idx, F &&fCallback)
Definition: phmap.h:3368
friend struct RawHashSetTestOnlyAccess
Definition: phmap.h:3782
size_t growth_left()
Definition: phmap.h:3784
bool if_contains_unsafe(const key_arg< K > &key, F &&f) const
Definition: phmap.h:3233
bool if_contains(const key_arg< K > &key, F &&f) const
Definition: phmap.h:3223
std::tuple< Inner *, size_t, bool > find_or_prepare_insert(const K &key, typename Lockable::UniqueLock &mutexlock)
Definition: phmap.h:3760
typename EmbeddedSet::constructor constructor
Definition: phmap.h:2511
iterator iterator_at(Inner *inner, const EmbeddedIterator &it)
Definition: phmap.h:3764
iterator lazy_emplace(const key_arg< K > &key, F &&f)
Definition: phmap.h:3195
typename EmbeddedSet::const_iterator EmbeddedConstIterator
Definition: phmap.h:2510
bool phmap_load(InputArchive &ar)
Definition: phmap_dump.h:115
void prefetch(const key_arg< K > &key) const
Definition: phmap.h:3543
void max_load_factor(float)
Definition: phmap.h:3617
static size_t subidx(size_t hashval)
Definition: phmap.h:3773
parallel_hash_set(std::initializer_list< init_type > init, const allocator_type &alloc)
Definition: phmap.h:2841
parallel_hash_set(size_t bucket_cnt, const hasher &hash_param, const allocator_type &alloc)
Definition: phmap.h:2753
iterator erase(const_iterator cit)
Definition: phmap.h:3407
static constexpr size_t mask
Definition: phmap.h:2505
parallel_hash_set(InputIter first, InputIter last, size_t bucket_cnt=0, const hasher &hash_param=hasher(), const key_equal &eq=key_equal(), const allocator_type &alloc=allocator_type())
Definition: phmap.h:2765
bool modify_if(const key_arg< K > &key, F &&f)
Definition: phmap.h:3242
node_type extract(const_iterator position)
Definition: phmap.h:3469
iterator insert(const_iterator, node_type &&node)
Definition: phmap.h:3027
std::pair< const_iterator, const_iterator > equal_range(const key_arg< K > &key) const
Definition: phmap.h:3594
typename std::enable_if<!std::is_same< T, init_type >::value, int >::type RequiresNotInit
Definition: phmap.h:2597
const_iterator find(const key_arg< K > &key, size_t hashval) const
Definition: phmap.h:3567
parallel_hash_set(size_t bucket_cnt, const allocator_type &alloc)
Definition: phmap.h:2758
iterator begin()
Definition: phmap.h:2885
static constexpr size_t num_tables
Definition: phmap.h:2504
parallel_hash_set & move_assign(parallel_hash_set< N, RefSet, Mtx2_, Policy, Hash, Eq, Alloc > &&that, std::false_type)
Definition: phmap.h:3724
void with_submap(size_t idx, F &&fCallback) const
Definition: phmap.h:3360
typename PolicyTraits::key_type key_type
Definition: phmap.h:2513
parallel_hash_set(size_t bucket_cnt, const hasher &hash_param=hasher(), const key_equal &eq=key_equal(), const allocator_type &alloc=allocator_type())
Definition: phmap.h:2744
void for_each(F &&fCallback) const
Definition: phmap.h:3314
std::pair< iterator, bool > emplace_with_hash(size_t hashval, Args &&... args)
Definition: phmap.h:3075
RefSet< Policy, Hash, Eq, Alloc > EmbeddedSet
Definition: phmap.h:2508
float load_factor() const
Definition: phmap.h:3611
float max_load_factor() const
Definition: phmap.h:3616
typename phmap::allocator_traits< allocator_type >::template rebind_traits< value_type >::const_pointer const_pointer
Definition: phmap.h:2527
bool phmap_dump(OutputArchive &ar) const
Definition: phmap_dump.h:93
typename KeyArgImpl::template type< K, key_type > key_arg
Definition: phmap.h:2535
void insert(std::initializer_list< T > ilist)
Definition: phmap.h:3004
iterator find(const key_arg< K > &key, size_t hashval)
Definition: phmap.h:3556
bool erase_if(const key_arg< K > &key, F &&f)
Definition: phmap.h:3266
iterator insert(const_iterator, T &&value)
Definition: phmap.h:2979
parallel_hash_set(std::initializer_list< T > init, size_t bucket_cnt=0, const hasher &hash_param=hasher(), const key_equal &eq=key_equal(), const allocator_type &alloc=allocator_type())
Definition: phmap.h:2809
parallel_hash_set(InputIter first, InputIter last, const allocator_type &alloc)
Definition: phmap.h:2783
Hash hasher
Definition: phmap.h:2518
size_t bucket_count() const
Definition: phmap.h:3601
std::pair< iterator, bool > insert(T &&value)
Definition: phmap.h:2940
std::pair< iterator, bool > insert(const T &value)
Definition: phmap.h:2962
iterator end()
Definition: phmap.h:2891
ptrdiff_t difference_type
Definition: phmap.h:2517
void clear(std::size_t submap_index)
Definition: phmap.h:2925
parallel_hash_set(const parallel_hash_set &that)
Definition: phmap.h:2845
typename PolicyTraits::init_type init_type
Definition: phmap.h:2512
void reserve(size_t n)
Definition: phmap.h:3507
void merge(parallel_hash_set< N, RefSet, Mtx_, Policy, Hash, E, Alloc > &src)
Definition: phmap.h:3452
bool empty() const
Definition: phmap.h:2897
Definition: phmap.h:145
void next()
Definition: phmap.h:155
size_t getindex() const
Definition: phmap.h:161
size_t offset_
Definition: phmap.h:165
size_t offset(size_t i) const
Definition: phmap.h:153
size_t mask_
Definition: phmap.h:164
size_t index_
Definition: phmap.h:166
size_t offset() const
Definition: phmap.h:152
probe_seq(size_t hashval, size_t mask)
Definition: phmap.h:147
Definition: phmap.h:2318
iterator insert_or_assign(const_iterator, key_arg< K > &&k, V &&v)
Definition: phmap.h:2384
std::pair< iterator, bool > insert_or_assign(key_arg< K > &&k, V &&v)
Definition: phmap.h:2363
typename raw_hash_map::raw_hash_set::const_iterator const_iterator
Definition: phmap.h:2349
decltype(P::value(std::addressof(std::declval< typename raw_hash_map::reference >()))) MappedReference
Definition: phmap.h:2324
std::pair< iterator, bool > insert_or_assign(key_arg< K > &&k, const V &v)
Definition: phmap.h:2368
std::pair< iterator, bool > try_emplace_impl(K &&k, Args &&... args)
Definition: phmap.h:2466
iterator insert_or_assign(const_iterator, key_arg< K > &&k, const V &v)
Definition: phmap.h:2389
MappedReference< P > operator[](key_arg< K > &&key)
Definition: phmap.h:2445
MappedReference< P > at(const key_arg< K > &key)
Definition: phmap.h:2429
MappedConstReference< P > at(const key_arg< K > &key) const
Definition: phmap.h:2437
iterator try_emplace(const_iterator, const key_arg< K > &k, Args &&... args)
Definition: phmap.h:2424
iterator insert_or_assign(const_iterator, const key_arg< K > &k, V &&v)
Definition: phmap.h:2394
MappedReference< P > operator[](const key_arg< K > &key)
Definition: phmap.h:2450
iterator insert_or_assign(const_iterator, const key_arg< K > &k, const V &v)
Definition: phmap.h:2399
std::pair< iterator, bool > insert_or_assign(const key_arg< K > &k, const V &v)
Definition: phmap.h:2378
std::pair< iterator, bool > try_emplace(const key_arg< K > &k, Args &&... args)
Definition: phmap.h:2414
std::pair< iterator, bool > insert_or_assign(const key_arg< K > &k, V &&v)
Definition: phmap.h:2373
typename Policy::mapped_type mapped_type
Definition: phmap.h:2338
decltype(P::value(std::addressof(std::declval< typename raw_hash_map::const_reference >()))) MappedConstReference
Definition: phmap.h:2329
std::pair< iterator, bool > try_emplace(key_arg< K > &&k, Args &&... args)
Definition: phmap.h:2407
typename KeyArgImpl::template type< K, key_type > key_arg
Definition: phmap.h:2340
std::pair< iterator, bool > insert_or_assign_impl(K &&k, V &&v)
Definition: phmap.h:2456
typename raw_hash_map::raw_hash_set::iterator iterator
Definition: phmap.h:2348
raw_hash_map()
Definition: phmap.h:2351
typename Policy::key_type key_type
Definition: phmap.h:2337
iterator try_emplace(const_iterator, key_arg< K > &&k, Args &&... args)
Definition: phmap.h:2419
const_iterator()
Definition: phmap.h:1021
friend bool operator!=(const const_iterator &a, const const_iterator &b)
Definition: phmap.h:1037
typename raw_hash_set::value_type value_type
Definition: phmap.h:1016
typename raw_hash_set::difference_type difference_type
Definition: phmap.h:1019
const_iterator & operator++()
Definition: phmap.h:1028
reference operator*() const
Definition: phmap.h:1025
typename iterator::iterator_category iterator_category
Definition: phmap.h:1015
friend bool operator==(const const_iterator &a, const const_iterator &b)
Definition: phmap.h:1034
pointer operator->() const
Definition: phmap.h:1026
typename raw_hash_set::const_reference reference
Definition: phmap.h:1017
typename raw_hash_set::const_pointer pointer
Definition: phmap.h:1018
const_iterator operator++(int)
Definition: phmap.h:1032
iterator inner_
Definition: phmap.h:1045
const_iterator(const ctrl_t *ctrl, const slot_type *slot)
Definition: phmap.h:1042
const_iterator(iterator i)
Definition: phmap.h:1023
constructor(allocator_type *a, slot_type **slot)
Definition: phmap.h:1517
allocator_type * alloc_
Definition: phmap.h:1519
void operator()(Args &&... args) const
Definition: phmap.h:1510
slot_type ** slot_
Definition: phmap.h:1520
reference operator*() const
Definition: phmap.h:941
typename raw_hash_set::value_type value_type
Definition: phmap.h:931
ctrl_t * ctrl_
Definition: phmap.h:1002
iterator(ctrl_t *ctrl, slot_type *slot)
Definition: phmap.h:988
iterator operator++(int)
Definition: phmap.h:954
phmap::conditional_t< PolicyTraits::constant_iterators::value, const value_type &, value_type & > reference
Definition: phmap.h:934
friend bool operator!=(const iterator &a, const iterator &b)
Definition: phmap.h:982
iterator & operator++()
Definition: phmap.h:947
iterator(ctrl_t *ctrl)
Definition: phmap.h:987
void skip_empty_or_deleted()
Definition: phmap.h:990
std::forward_iterator_tag iterator_category
Definition: phmap.h:930
typename raw_hash_set::difference_type difference_type
Definition: phmap.h:936
phmap::remove_reference_t< reference > * pointer
Definition: phmap.h:935
friend bool operator==(const iterator &a, const iterator &b)
Definition: phmap.h:979
slot_type * slot_
Definition: phmap.h:1006
pointer operator->() const
Definition: phmap.h:944
iterator()
Definition: phmap.h:938
Definition: phmap.h:839
void lazy_emplace_at(size_t &idx, F &&f)
Definition: phmap.h:1542
iterator iterator_at(size_t i)
Definition: phmap.h:2226
PHMAP_ATTRIBUTE_REINITIALIZES void clear()
Definition: phmap.h:1264
hash_policy_traits< Policy > PolicyTraits
Definition: phmap.h:840
raw_hash_set(std::initializer_list< T > init, const allocator_type &alloc)
Definition: phmap.h:1151
raw_hash_set(std::initializer_list< init_type > init, size_t bucket_cnt=0, const hasher &hashfn=hasher(), const key_equal &eq=key_equal(), const allocator_type &alloc=allocator_type())
Definition: phmap.h:1127
bool has_element(const value_type &elem, size_t hashval) const
Definition: phmap.h:2111
iterator find(const key_arg< K > &key)
Definition: phmap.h:1757
Hash hasher
Definition: phmap.h:853
size_t prepare_insert(size_t hashval) PHMAP_ATTRIBUTE_NOINLINE
Definition: phmap.h:2194
friend bool operator!=(const raw_hash_set &a, const raw_hash_set &b)
Definition: phmap.h:1818
std::pair< size_t, bool > find_or_prepare_insert(const K &key, size_t hashval)
Definition: phmap.h:2173
raw_hash_set & move_assign(raw_hash_set &&that, std::true_type)
Definition: phmap.h:2160
raw_hash_set(raw_hash_set &&that, const allocator_type &a)
Definition: phmap.h:1195
float max_load_factor() const
Definition: phmap.h:1798
raw_hash_set & move_assign(raw_hash_set &&that, std::false_type)
Definition: phmap.h:2165
FindInfo find_first_non_full(size_t hashval)
Definition: phmap.h:2146
bool phmap_load(InputArchive &)
Definition: phmap_dump.h:67
insert_return_type insert(node_type &&node)
Definition: phmap.h:1392
Alloc allocator_type
Definition: phmap.h:850
bool is_small() const
Definition: phmap.h:2289
void insert(InputIt first, InputIt last)
Definition: phmap.h:1371
size_t & growth_left()
Definition: phmap.h:2263
const_iterator cend() const
Definition: phmap.h:1257
typename phmap::allocator_traits< allocator_type >::template rebind_traits< value_type >::const_pointer const_pointer
Definition: phmap.h:862
void destroy_slots()
Definition: phmap.h:1991
raw_hash_set(std::initializer_list< T > init, size_t bucket_cnt, const allocator_type &alloc)
Definition: phmap.h:1142
const_iterator find(const key_arg< K > &key, size_t hashval) const
Definition: phmap.h:1762
key_equal key_eq() const
Definition: phmap.h:1804
raw_hash_set(std::initializer_list< init_type > init, const allocator_type &alloc)
Definition: phmap.h:1154
void reserve(size_t n)
Definition: phmap.h:1692
raw_hash_set(raw_hash_set &&that) noexcept(std::is_nothrow_copy_constructible< hasher >::value &&std::is_nothrow_copy_constructible< key_equal >::value &&std::is_nothrow_copy_constructible< allocator_type >::value)
Definition: phmap.h:1178
iterator end()
Definition: phmap.h:1243
iterator erase(iterator it)
Definition: phmap.h:1599
void emplace_single_with_hash(const key_arg< K > &key, size_t hashval, F &&f)
Definition: phmap.h:1549
phmap::priv::CompressedTuple< size_t, hasher, key_equal, allocator_type > settings_
Definition: phmap.h:2310
iterator lazy_emplace_with_hash(const key_arg< K > &key, size_t hashval, F &&f)
Definition: phmap.h:1533
typename PolicyTraits::value_type value_type
Definition: phmap.h:856
typename std::enable_if< phmap::disjunction< std::is_convertible< T, init_type >, SameAsElementReference< T > >::value, int >::type RequiresInsertable
Definition: phmap.h:908
const hasher & hash_ref() const
Definition: phmap.h:2292
raw_hash_set & operator=(raw_hash_set &&that) noexcept(phmap::allocator_traits< allocator_type >::is_always_equal::value &&std::is_nothrow_move_assignable< hasher >::value &&std::is_nothrow_move_assignable< key_equal >::value)
Definition: phmap.h:1225
void _erase(const_iterator cit)
Definition: phmap.h:1595
std::pair< iterator, bool > emplace_decomposable(const K &key, size_t hashval, Args &&... args)
Definition: phmap.h:1884
void reset_ctrl(size_t capacity)
Definition: phmap.h:2237
bool contains(const key_arg< K > &key, size_t hashval) const
Definition: phmap.h:1776
size_t max_size() const
Definition: phmap.h:1262
size_t count(const key_arg< K > &key) const
Definition: phmap.h:1704
size_t size_
Definition: phmap.h:2305
bool phmap_dump(OutputArchive &) const
Definition: phmap_dump.h:52
iterator find(const key_arg< K > &key, size_t hashval)
Definition: phmap.h:1739
raw_hash_set(const raw_hash_set &that, const allocator_type &a)
Definition: phmap.h:1162
value_type & reference
Definition: phmap.h:857
iterator insert(const_iterator, init_type &&value)
Definition: phmap.h:1347
void swap(raw_hash_set &that) noexcept(IsNoThrowSwappable< hasher >() &&IsNoThrowSwappable< key_equal >() &&(!AllocTraits::propagate_on_container_swap::value||IsNoThrowSwappable< allocator_type >()))
Definition: phmap.h:1647
typename PolicyTraits::key_type key_type
Definition: phmap.h:846
std::pair< iterator, bool > insert(const T &value)
Definition: phmap.h:1318
iterator insert(const_iterator, node_type &&node)
Definition: phmap.h:1420
typename PolicyTraits::slot_type slot_type
Definition: phmap.h:849
void drop_deletes_without_resize() PHMAP_ATTRIBUTE_NOINLINE
Definition: phmap.h:2036
raw_hash_set(std::initializer_list< init_type > init, size_t bucket_cnt, const hasher &hashfn, const allocator_type &alloc)
Definition: phmap.h:1137
node_type extract(const_iterator position)
Definition: phmap.h:1632
hasher & hash_ref()
Definition: phmap.h:2291
const value_type & const_reference
Definition: phmap.h:858
friend void swap(raw_hash_set &a, raw_hash_set &b) noexcept(noexcept(a.swap(b)))
Definition: phmap.h:1822
std::pair< const_iterator, const_iterator > equal_range(const key_arg< K > &key) const
Definition: phmap.h:1787
void reset_growth_left(size_t capacity)
Definition: phmap.h:2243
size_t size() const
Definition: phmap.h:1260
insert_return_type insert(node_type &&node, size_t hashval)
Definition: phmap.h:1406
size_t hash(const K &key) const
Definition: phmap.h:1828
void insert(std::initializer_list< init_type > ilist)
Definition: phmap.h:1388
void _erase(iterator it)
Definition: phmap.h:1590
pointer find_ptr(const key_arg< K > &key, size_t hashval)
Definition: phmap.h:1748
node_type extract(const key_arg< K > &key)
Definition: phmap.h:1642
bool has_element(const value_type &elem) const
Definition: phmap.h:2127
iterator lazy_emplace(const key_arg< K > &key, F &&f)
Definition: phmap.h:1524
void prefetch_hash(size_t hashval) const
Definition: phmap.h:1713
raw_hash_set(InputIter first, InputIter last, size_t bucket_cnt=0, const hasher &hashfn=hasher(), const key_equal &eq=key_equal(), const allocator_type &alloc=allocator_type())
Definition: phmap.h:1079
raw_hash_set() noexcept(std::is_nothrow_default_constructible< hasher >::value &&std::is_nothrow_default_constructible< key_equal >::value &&std::is_nothrow_default_constructible< allocator_type >::value)
Definition: phmap.h:1051
Eq key_equal
Definition: phmap.h:854
void max_load_factor(float)
Definition: phmap.h:1799
node_handle< Policy, hash_policy_traits< Policy >, Alloc > node_type
Definition: phmap.h:1048
void prefetch(const key_arg< K > &key) const
Definition: phmap.h:1727
void merge(raw_hash_set< Policy, H, E, Alloc > &&src)
Definition: phmap.h:1628
static Layout MakeLayout(size_t capacity)
Definition: phmap.h:878
iterator insert(const_iterator, const T &value)
Definition: phmap.h:1343
iterator begin()
Definition: phmap.h:1238
raw_hash_set(InputIter first, InputIter last, size_t bucket_cnt, const hasher &hashfn, const allocator_type &alloc)
Definition: phmap.h:1087
typename KeyArgImpl::template type< K, key_type > key_arg
Definition: phmap.h:869
void rehash_and_grow_if_necessary()
Definition: phmap.h:2099
allocator_type & alloc_ref()
Definition: phmap.h:2295
raw_hash_set(const allocator_type &alloc)
Definition: phmap.h:1075
slot_type * slots_
Definition: phmap.h:2304
IsDecomposable< void, PolicyTraits, Hash, Eq, Ts... > IsDecomposable
Definition: phmap.h:917
raw_hash_set(size_t bucket_cnt, const hasher &hashfn=hasher(), const key_equal &eq=key_equal(), const allocator_type &alloc=allocator_type())
Definition: phmap.h:1056
std::pair< size_t, bool > find_or_prepare_insert(const K &key)
Definition: phmap.h:2190
raw_hash_set(std::initializer_list< init_type > init, size_t bucket_cnt, const allocator_type &alloc)
Definition: phmap.h:1146
iterator emplace_hint(const_iterator, Args &&... args)
Definition: phmap.h:1473
float load_factor() const
Definition: phmap.h:1795
auto KeyTypeCanBeEq(const Eq &eq, const key_type &k) -> decltype(eq(k, k))
iterator insert(const_iterator, T &&value)
Definition: phmap.h:1334
ptrdiff_t difference_type
Definition: phmap.h:852
typename phmap::allocator_traits< allocator_type >::template rebind_traits< slot_type > SlotAllocTraits
Definition: phmap.h:887
~raw_hash_set()
Definition: phmap.h:1236
hasher hash_function() const
Definition: phmap.h:1803
raw_hash_set & operator=(const raw_hash_set &that)
Definition: phmap.h:1216
bool find_impl(const key_arg< K > &key, size_t hashval, size_t &offset)
Definition: phmap.h:1837
iterator emplace_hint_with_hash(size_t hashval, const_iterator, Args &&... args)
Definition: phmap.h:1478
std::pair< iterator, bool > insert(init_type &&value)
Definition: phmap.h:1327
friend struct RawHashSetTestOnlyAccess
Definition: phmap.h:2230
HashtablezInfoHandle infoz_
Definition: phmap.h:2307
probe_seq< Group::kWidth > probe(size_t hashval) const
Definition: phmap.h:2232
phmap::priv::Layout< ctrl_t, slot_type > Layout
Definition: phmap.h:876
std::is_same< typename std::iterator_traits< It >::iterator_category, std::random_access_iterator_tag > IsRandomAccess
Definition: phmap.h:1353
bool contains(const key_arg< K > &key) const
Definition: phmap.h:1771
void insert(std::initializer_list< T > ilist)
Definition: phmap.h:1384
friend bool operator==(const raw_hash_set &a, const raw_hash_set &b)
Definition: phmap.h:1807
size_t bucket_count() const
Definition: phmap.h:1794
std::pair< iterator, iterator > equal_range(const key_arg< K > &key)
Definition: phmap.h:1781
raw_hash_set(size_t bucket_cnt, const hasher &hashfn, const allocator_type &alloc)
Definition: phmap.h:1068
raw_hash_set(const raw_hash_set &that)
Definition: phmap.h:1158
raw_hash_set(InputIter first, InputIter last, const allocator_type &alloc)
Definition: phmap.h:1097
std::pair< iterator, bool > insert(T &&value)
Definition: phmap.h:1298
ctrl_t * ctrl_
Definition: phmap.h:2303
const_iterator end() const
Definition: phmap.h:1255
typename phmap::allocator_traits< allocator_type >::template rebind_traits< value_type >::pointer pointer
Definition: phmap.h:860
void erase_meta_only(const_iterator it)
Definition: phmap.h:1953
raw_hash_set(size_t bucket_cnt, const allocator_type &alloc)
Definition: phmap.h:1072
const_iterator cbegin() const
Definition: phmap.h:1256
size_t capacity_
Definition: phmap.h:2306
std::pair< iterator, bool > emplace(Args &&... args)
Definition: phmap.h:1437
const key_equal & eq_ref() const
Definition: phmap.h:2294
Policy policy_type
Definition: phmap.h:855
iterator erase(const_iterator cit)
Definition: phmap.h:1576
typename std::enable_if<!std::is_same< T, init_type >::value, int >::type RequiresNotInit
Definition: phmap.h:914
auto KeyTypeCanBeHashed(const Hash &h, const key_type &k) -> decltype(h(k))
void set_ctrl(size_t i, ctrl_t h)
Definition: phmap.h:2249
size_type erase(const key_arg< K > &key)
Definition: phmap.h:1568
const_iterator find(const key_arg< K > &key) const
Definition: phmap.h:1766
raw_hash_set(std::initializer_list< T > init, size_t bucket_cnt, const hasher &hashfn, const allocator_type &alloc)
Definition: phmap.h:1133
void rehash(size_t n)
Definition: phmap.h:1676
const_iterator iterator_at(size_t i) const
Definition: phmap.h:2227
void merge(raw_hash_set< Policy, H, E, Alloc > &src)
Definition: phmap.h:1616
raw_hash_set(std::initializer_list< T > init, size_t bucket_cnt=0, const hasher &hashfn=hasher(), const key_equal &eq=key_equal(), const allocator_type &alloc=allocator_type())
Definition: phmap.h:1122
const allocator_type & alloc_ref() const
Definition: phmap.h:2296
void emplace_at(size_t i, Args &&... args)
Definition: phmap.h:2217
const_iterator begin() const
Definition: phmap.h:1252
void initialize_slots(size_t new_capacity)
Definition: phmap.h:1974
bool empty() const
Definition: phmap.h:1259
allocator_type get_allocator() const
Definition: phmap.h:1805
size_t size_type
Definition: phmap.h:851
typename phmap::allocator_traits< allocator_type >::template rebind_alloc< slot_type > SlotAlloc
Definition: phmap.h:885
iterator erase(const_iterator first, const_iterator last)
Definition: phmap.h:1606
typename PolicyTraits::init_type init_type
Definition: phmap.h:845
void resize(size_t new_capacity)
Definition: phmap.h:2009
key_equal & eq_ref()
Definition: phmap.h:2293
size_t capacity() const
Definition: phmap.h:1261
std::pair< iterator, bool > emplace_with_hash(size_t hashval, Args &&... args)
Definition: phmap.h:1443
raw_hash_set(InputIter first, InputIter last, size_t bucket_cnt, const allocator_type &alloc)
Definition: phmap.h:1092
_string<> string
Definition: ne_stl_string.h:762
PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n)
Definition: phmap_bits.h:282
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountTrailingZerosNonZero64(uint64_t n)
Definition: phmap_bits.h:363
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountTrailingZerosNonZero32(uint32_t n)
Definition: phmap_bits.h:396
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros32(uint32_t n)
Definition: phmap_bits.h:326
static void ThrowStdOutOfRange(const std::string &what_arg)
Definition: phmap_base.h:694
void Store64(void *p, uint64_t v)
Definition: phmap_bits.h:592
auto GetKey(const typename T::value_type &pair, int) -> decltype(get< 0 >(pair))
Definition: phmap.h:609
auto TupleRef(T &&t) -> decltype(TupleRefImpl(std::forward< T >(t), phmap::make_index_sequence< std::tuple_size< typename std::decay< T >::type >::value >()))
Definition: phmap.h:736
decltype(std::declval< F >()(std::declval< T >())) WithConstructedImpl(Tuple &&t, phmap::index_sequence< Is... >, F &&f)
Definition: phmap.h:720
decltype(std::declval< F >()(std::declval< const K & >(), std::piecewise_construct, std::declval< std::tuple< K > >(), std::declval< V >())) DecomposePairImpl(F &&f, std::pair< std::tuple< K >, V > p)
Definition: phmap.h:749
void ConstructFromTupleImpl(Alloc *alloc, T *ptr, Tuple &&t, phmap::index_sequence< I... >)
Definition: phmap.h:703
auto TupleRefImpl(T &&t, phmap::index_sequence< Is... >) -> decltype(std::forward_as_tuple(std::get< Is >(std::forward< T >(t))...))
Definition: phmap.h:727
size_t HashSeed(const ctrl_t *ctrl)
Definition: phmap.h:330
decltype(std::declval< F >()(std::declval< T >())) WithConstructed(Tuple &&t, F &&f)
Definition: phmap.h:4064
static void SetHashtablezSampleParameter(int32_t)
Definition: phmap.h:693
size_t CapacityToGrowth(size_t capacity)
Definition: phmap.h:573
ctrl_t * EmptyGroup()
Definition: phmap.h:322
bool IsValidCapacity(size_t n)
Definition: phmap.h:536
constexpr bool IsNoThrowSwappable()
Definition: phmap.h:195
void SwapAlloc(AllocType &lhs, AllocType &rhs, std::true_type)
Definition: phmap.h:133
std::pair< std::tuple<>, std::tuple<> > PairArgs()
Definition: phmap.h:4086
static HashtablezInfo * SampleSlow(int64_t *)
Definition: phmap.h:663
decltype(std::declval< F >()(std::declval< const Arg & >(), std::declval< Arg >())) DecomposeValue(F &&f, Arg &&arg)
Definition: phmap.h:4127
static void RecordInsertSlow(HashtablezInfo *, size_t, size_t)
Definition: phmap.h:659
constexpr size_t NumClonedBytes()
Definition: phmap.h:531
static void RecordEraseSlow(HashtablezInfo *)
Definition: phmap.h:661
std::size_t erase_if(C &c, Pred pred)
Definition: phmap.h:5051
int LeadingZeros(T x)
Definition: phmap.h:211
void SanitizerPoisonObject(const T *object)
Definition: phmap_base.h:4407
static void UnsampleSlow(HashtablezInfo *)
Definition: phmap.h:664
uint8_t h2_t
Definition: phmap.h:285
typename phmap::Allocator< T > Allocator
Definition: phmap_fwd_decl.h:61
Ctrl
Definition: phmap.h:292
@ kDeleted
Definition: phmap.h:294
@ kSentinel
Definition: phmap.h:295
@ kEmpty
Definition: phmap.h:293
bool IsDeleted(ctrl_t c)
Definition: phmap.h:358
size_t NormalizeCapacity(size_t n)
Definition: phmap.h:564
auto DecomposePair(F &&f, Args &&... args) -> decltype(memory_internal::DecomposePairImpl(std::forward< F >(f), PairArgs(std::forward< Args >(args)...)))
Definition: phmap.h:4116
void RecordRehashSlow(HashtablezInfo *, size_t)
Definition: phmap.h:657
h2_t H2(size_t hashval)
Definition: phmap.h:354
void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t *ctrl, size_t capacity)
Definition: phmap.h:548
int TrailingZeros(T x)
Definition: phmap.h:202
void SanitizerUnpoisonObject(const T *object)
Definition: phmap_base.h:4412
GroupPortableImpl Group
Definition: phmap.h:525
void ConstructFromTuple(Alloc *alloc, T *ptr, Tuple &&t)
Definition: phmap.h:4053
static void SetHashtablezMaxSamples(int32_t)
Definition: phmap.h:694
void SanitizerPoisonMemoryRegion(const void *m, size_t s)
Definition: phmap_base.h:4384
void SanitizerUnpoisonMemoryRegion(const void *m, size_t s)
Definition: phmap_base.h:4395
bool IsEmpty(ctrl_t c)
Definition: phmap.h:356
size_t GrowthToLowerboundCapacity(size_t growth)
Definition: phmap.h:591
static HashtablezInfoHandle Sample()
Definition: phmap.h:677
static void SetHashtablezEnabled(bool)
Definition: phmap.h:692
signed char ctrl_t
Definition: phmap.h:284
bool IsEmptyOrDeleted(ctrl_t c)
Definition: phmap.h:359
size_t H1(size_t hashval, const ctrl_t *)
Definition: phmap.h:347
bool IsFull(ctrl_t c)
Definition: phmap.h:357
size_t RandomSeed()
Definition: phmap.h:2479
Definition: btree.h:77
typename std::conditional< B, T, F >::type conditional_t
Definition: phmap_base.h:322
T exchange(T &obj, U &&new_value)
Definition: phmap_base.h:1127
void erase_if(btree_set< K, C, A > &set, Pred pred)
Definition: btree.h:3889
typename std::remove_reference< T >::type remove_reference_t
Definition: phmap_base.h:285
constexpr phmap::remove_reference_t< T > && move(T &&t) noexcept
Definition: phmap_base.h:1029
make_integer_sequence< size_t, N > make_index_sequence
Definition: phmap_base.h:966
typename type_traits_internal::VoidTImpl< Ts... >::type void_t
Definition: btree.h:134
STL namespace
#define PHMAP_PREDICT_TRUE(x)
Definition: phmap_bits.h:252
#define PHMAP_PREDICT_FALSE(x)
Definition: phmap_bits.h:251
#define PHMAP_ATTRIBUTE_NOINLINE
Definition: phmap_config.h:434
#define PHMAP_ATTRIBUTE_REINITIALIZES
Definition: phmap_config.h:604
#define PHMAP_IF_CONSTEXPR(expr)
Definition: phmap_config.h:672
unsigned char bool
Definition: stdbool.h:25
Definition: phmap_utils.h:139
Definition: phmap_base.h:4785
Definition: phmap_base.h:1379
static void construct(Alloc &a, T *p, Args &&... args)
Definition: phmap_base.h:1491
memory_internal::ExtractOrT< memory_internal::GetPropagateOnContainerMoveAssignment, Alloc, std::false_type > propagate_on_container_move_assignment
Definition: phmap_base.h:1439
static void destroy(Alloc &a, T *p)
Definition: phmap_base.h:1499
static void deallocate(Alloc &a, pointer p, size_type n)
Definition: phmap_base.h:1481
static pointer allocate(Alloc &a, size_type n)
Definition: phmap_base.h:1466
Definition: phmap_base.h:224
Definition: phmap_base.h:906
Definition: phmap_utils.h:54
static void Reset(Node *node)
Definition: phmap_base.h:2895
static auto GetSlot(const Node &node) -> decltype(node.slot())
Definition: phmap_base.h:2885
Definition: phmap.h:4195
static size_t space_used(const slot_type *)
Definition: phmap.h:4226
K key_type
Definition: phmap.h:4198
typename slot_policy::slot_type slot_type
Definition: phmap.h:4197
static void destroy(Allocator *alloc, slot_type *slot)
Definition: phmap.h:4208
static decltype(phmap::priv::DecomposePair(std::declval< F >(), std::declval< Args >()...)) apply(F &&f, Args &&... args)
Definition: phmap.h:4221
static const V & value(const std::pair< const K, V > *kv)
Definition: phmap.h:4231
std::pair< key_type, mapped_type > init_type
Definition: phmap.h:4200
static std::pair< const K, V > & element(slot_type *slot)
Definition: phmap.h:4228
static void transfer(Allocator *alloc, slot_type *new_slot, slot_type *old_slot)
Definition: phmap.h:4213
static void construct(Allocator *alloc, slot_type *slot, Args &&... args)
Definition: phmap.h:4203
static V & value(std::pair< const K, V > *kv)
Definition: phmap.h:4230
V mapped_type
Definition: phmap.h:4199
Definition: phmap.h:4154
T key_type
Definition: phmap.h:4156
static void transfer(Allocator *alloc, slot_type *new_slot, slot_type *old_slot)
Definition: phmap.h:4172
static T & element(slot_type *slot)
Definition: phmap.h:4178
static size_t space_used(const T *)
Definition: phmap.h:4188
T init_type
Definition: phmap.h:4157
static void destroy(Allocator *alloc, slot_type *slot)
Definition: phmap.h:4167
static decltype(phmap::priv::DecomposeValue(std::declval< F >(), std::declval< Args >()...)) apply(F &&f, Args &&... args)
Definition: phmap.h:4183
static void construct(Allocator *alloc, slot_type *slot, Args &&... args)
Definition: phmap.h:4161
std::true_type constant_iterators
Definition: phmap.h:4158
T slot_type
Definition: phmap.h:4155
Definition: phmap.h:470
BitMask< uint64_t, kWidth, 3 > Match(h2_t hash) const
Definition: phmap.h:476
BitMask< uint64_t, kWidth, 3 > MatchEmpty() const
Definition: phmap.h:496
void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t *dst) const
Definition: phmap.h:511
BitMask< uint64_t, kWidth, 3 > MatchEmptyOrDeleted() const
Definition: phmap.h:501
GroupPortableImpl(const ctrl_t *pos)
Definition: phmap.h:473
@ kWidth
Definition: phmap.h:471
uint64_t ctrl
Definition: phmap.h:519
uint32_t CountLeadingEmptyOrDeleted() const
Definition: phmap.h:506
bool operator()(const A &a, const B &b) const
Definition: phmap.h:4436
void is_transparent
Definition: phmap.h:4434
void is_transparent
Definition: phmap.h:4426
size_t operator()(const U &ptr) const
Definition: phmap.h:4428
static const T * ToPtr(const T *ptr)
Definition: phmap.h:4442
static const T * ToPtr(const std::unique_ptr< U, D > &ptr)
Definition: phmap.h:4445
static const T * ToPtr(const std::shared_ptr< U > &ptr)
Definition: phmap.h:4450
Definition: phmap_fwd_decl.h:48
Definition: phmap.h:653
void PrepareForSampling()
Definition: phmap.h:654
Definition: phmap_base.h:2918
Definition: phmap.h:183
Definition: phmap_base.h:2716
Definition: phmap_base.h:2723
Definition: phmap.h:4279
static T * new_element(Allocator *alloc, Args &&... args)
Definition: phmap.h:4285
static size_t element_space_used(const T *)
Definition: phmap.h:4312
T init_type
Definition: phmap.h:4281
T key_type
Definition: phmap.h:4280
std::true_type constant_iterators
Definition: phmap.h:4282
static decltype(phmap::priv::DecomposeValue(std::declval< F >(), std::declval< Args >()...)) apply(F &&f, Args &&... args)
Definition: phmap.h:4307
static void delete_element(Allocator *alloc, T *elem)
Definition: phmap.h:4296
Definition: phmap.h:172
std::pair< decltype(std::declval< const Hash & >()(std::declval< const PassedKey & >())), decltype(std::declval< const Eq & >()(std::declval< const ContainerKey & >(), std::declval< const PassedKey & >()))> * operator()(const PassedKey &, const Args &...) const
Definition: phmap_base.h:425
typename std::remove_reference< reference >::type value_type
Definition: phmap_base.h:460
static auto key(slot_type *slot) -> decltype(P::apply(ReturnKey(), element(slot)))
Definition: phmap_base.h:554
static void transfer(Alloc *alloc, slot_type *new_slot, slot_type *old_slot)
Definition: phmap_base.h:494
static auto element(slot_type *slot) -> decltype(P::element(slot))
Definition: phmap_base.h:501
typename Policy::init_type init_type
Definition: phmap_base.h:456
static void construct(Alloc *alloc, slot_type *slot, Args &&... args)
Definition: phmap_base.h:471
static auto apply(F &&f, Ts &&... ts) -> decltype(P::apply(std::forward< F >(f), std::forward< Ts >(ts)...))
Definition: phmap_base.h:546
static void destroy(Alloc *alloc, slot_type *slot)
Definition: phmap_base.h:478
typename Policy::slot_type slot_type
Definition: phmap_base.h:448
typename Policy::key_type key_type
Definition: phmap_base.h:451
static auto value(T *elem) -> decltype(P::value(elem))
Definition: phmap_base.h:562
static size_t GetNumProbes(const Container &c, const typename Container::key_type &key)
Definition: phmap.h:635
Definition: phmap_base.h:4634
static void destroy(Allocator *alloc, slot_type *slot)
Definition: phmap_base.h:4686
static void transfer(Allocator *alloc, slot_type *new_slot, slot_type *old_slot)
Definition: phmap_base.h:4695
static void construct(Allocator *alloc, slot_type *slot, Args &&... args)
Definition: phmap_base.h:4661
map_slot_type< K, V > slot_type
Definition: phmap_base.h:4635
decltype(std::declval< F >()(std::declval< T >())) operator()(Args &&... args) const
Definition: phmap.h:712
Definition: phmap.h:4235
static auto value(T *elem) -> decltype(P::value(elem))
Definition: phmap.h:4264
static void transfer(Alloc *, slot_type *new_slot, slot_type *old_slot)
Definition: phmap.h:4252
static size_t space_used(const slot_type *slot)
Definition: phmap.h:4256
static Reference element(slot_type *slot)
Definition: phmap.h:4261
static auto apply(Ts &&... ts) -> decltype(P::apply(std::forward< Ts >(ts)...))
Definition: phmap.h:4269
static void destroy(Alloc *alloc, slot_type *slot)
Definition: phmap.h:4247
typename std::remove_cv< typename std::remove_reference< Reference >::type >::type * slot_type
Definition: phmap.h:4239
static void construct(Alloc *alloc, slot_type *slot, Args &&... args)
Definition: phmap.h:4242
std::pair< iterator, bool > operator()(const K &key, Args &&... args) const
Definition: phmap.h:3056
parallel_hash_set & s
Definition: phmap.h:3059
parallel_hash_set & s
Definition: phmap.h:3133
std::pair< iterator, bool > operator()(const K &key, Args &&... args) const
Definition: phmap.h:3130
bool operator()(const K2 &lhs, Args &&...) const
Definition: phmap.h:3680
const K1 & rhs
Definition: phmap.h:3683
const key_equal & eq
Definition: phmap.h:3684
const_iterator operator()(const K &key, Args &&...) const
Definition: phmap.h:3661
const parallel_hash_set & s
Definition: phmap.h:3664
const hasher & h
Definition: phmap.h:3673
size_t operator()(const K &key, Args &&...) const
Definition: phmap.h:3670
const key_equal & eq
Definition: phmap.h:2547
const hasher & hashfn
Definition: phmap.h:2546
const allocator_type & alloc
Definition: phmap.h:2548
size_t bucket_cnt
Definition: phmap.h:2545
EmbeddedSet set_
Definition: phmap.h:2562
bool operator==(const Inner &o) const
Definition: phmap.h:2556
Inner()
Definition: phmap.h:2551
Inner(Params const &p)
Definition: phmap.h:2553
Key operator()(Key &&k, const Args &...) const
Definition: phmap.h:3034
raw_hash_set & s
Definition: phmap.h:1908
std::pair< iterator, bool > operator()(const K &key, Args &&... args) const
Definition: phmap.h:1905
std::pair< iterator, bool > operator()(const K &key, Args &&... args) const
Definition: phmap.h:1897
raw_hash_set & s
Definition: phmap.h:1900
const K1 & rhs
Definition: phmap.h:1879
bool operator()(const K2 &lhs, Args &&...) const
Definition: phmap.h:1876
const key_equal & eq
Definition: phmap.h:1880
const raw_hash_set & s
Definition: phmap.h:1860
const_iterator operator()(const K &key, Args &&...) const
Definition: phmap.h:1857
Definition: phmap.h:2142
size_t offset
Definition: phmap.h:2143
size_t probe_length
Definition: phmap.h:2144
size_t operator()(const K &key, Args &&...) const
Definition: phmap.h:1866
const hasher & h
Definition: phmap.h:1869
std::pair< iterator, bool > operator()(const K &key, Args &&...) &&
Definition: phmap.h:1916
raw_hash_set & s
Definition: phmap.h:1925
slot_type && slot
Definition: phmap.h:1927
size_t & hashval
Definition: phmap.h:1946
std::pair< iterator, bool > operator()(const K &key, Args &&...) &&
Definition: phmap.h:1934
slot_type && slot
Definition: phmap.h:1945
raw_hash_set & s
Definition: phmap.h:1943
std::true_type yes
Definition: phmap.h:1360
std::false_type no
Definition: phmap.h:1361
static auto test(int) -> decltype(std::declval< U >() - std::declval< U >()==1, yes())
static constexpr bool value
Definition: phmap.h:1367