LRez  v2.1
robin_hood.h
Go to the documentation of this file.
1 // ______ _____ ______ _________
2 // ______________ ___ /_ ___(_)_______ ___ /_ ______ ______ ______ /
3 // __ ___/_ __ \__ __ \__ / __ __ \ __ __ \_ __ \_ __ \_ __ /
4 // _ / / /_/ /_ /_/ /_ / _ / / / _ / / // /_/ // /_/ // /_/ /
5 // /_/ \____/ /_.___/ /_/ /_/ /_/ ________/_/ /_/ \____/ \____/ \__,_/
6 // _/_____/
7 //
8 // Fast & memory efficient hashtable based on robin hood hashing for C++11/14/17/20
9 // https://github.com/martinus/robin-hood-hashing
10 //
11 // Licensed under the MIT License <http://opensource.org/licenses/MIT>.
12 // SPDX-License-Identifier: MIT
13 // Copyright (c) 2018-2021 Martin Ankerl <http://martin.ankerl.com>
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining a copy
16 // of this software and associated documentation files (the "Software"), to deal
17 // in the Software without restriction, including without limitation the rights
18 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19 // copies of the Software, and to permit persons to whom the Software is
20 // furnished to do so, subject to the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be included in all
23 // copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 // SOFTWARE.
32 
33 #ifndef ROBIN_HOOD_H_INCLUDED
34 #define ROBIN_HOOD_H_INCLUDED
35 
36 // see https://semver.org/
37 #define ROBIN_HOOD_VERSION_MAJOR 3 // for incompatible API changes
38 #define ROBIN_HOOD_VERSION_MINOR 11 // for adding functionality in a backwards-compatible manner
39 #define ROBIN_HOOD_VERSION_PATCH 1 // for backwards-compatible bug fixes
40 
41 #include <algorithm>
42 #include <cstdlib>
43 #include <cstring>
44 #include <functional>
45 #include <memory> // only to support hash of smart pointers
46 #include <stdexcept>
47 #include <string>
48 #include <type_traits>
49 #include <utility>
50 #if __cplusplus >= 201703L
51 # include <string_view>
52 #endif
53 
54 // #define ROBIN_HOOD_LOG_ENABLED
55 #ifdef ROBIN_HOOD_LOG_ENABLED
56 # include <iostream>
57 # define ROBIN_HOOD_LOG(...) \
58  std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << __VA_ARGS__ << std::endl;
59 #else
60 # define ROBIN_HOOD_LOG(x)
61 #endif
62 
63 // #define ROBIN_HOOD_TRACE_ENABLED
64 #ifdef ROBIN_HOOD_TRACE_ENABLED
65 # include <iostream>
66 # define ROBIN_HOOD_TRACE(...) \
67  std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << __VA_ARGS__ << std::endl;
68 #else
69 # define ROBIN_HOOD_TRACE(x)
70 #endif
71 
72 // #define ROBIN_HOOD_COUNT_ENABLED
73 #ifdef ROBIN_HOOD_COUNT_ENABLED
74 # include <iostream>
75 # define ROBIN_HOOD_COUNT(x) ++counts().x;
76 namespace robin_hood {
77 struct Counts {
78  uint64_t shiftUp{};
79  uint64_t shiftDown{};
80 };
81 inline std::ostream& operator<<(std::ostream& os, Counts const& c) {
82  return os << c.shiftUp << " shiftUp" << std::endl << c.shiftDown << " shiftDown" << std::endl;
83 }
84 
85 static Counts& counts() {
86  static Counts counts{};
87  return counts;
88 }
89 } // namespace robin_hood
90 #else
91 # define ROBIN_HOOD_COUNT(x)
92 #endif
93 
94 // all non-argument macros should use this facility. See
95 // https://www.fluentcpp.com/2019/05/28/better-macros-better-flags/
96 #define ROBIN_HOOD(x) ROBIN_HOOD_PRIVATE_DEFINITION_##x()
97 
98 // mark unused members with this macro
99 #define ROBIN_HOOD_UNUSED(identifier)
100 
101 // bitness
102 #if SIZE_MAX == UINT32_MAX
103 # define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 32
104 #elif SIZE_MAX == UINT64_MAX
105 # define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 64
106 #else
107 # error Unsupported bitness
108 #endif
109 
110 // endianess
111 #ifdef _MSC_VER
112 # define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() 1
113 # define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() 0
114 #else
115 # define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() \
116  (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
117 # define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
118 #endif
119 
120 // inline
121 #ifdef _MSC_VER
122 # define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __declspec(noinline)
123 #else
124 # define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __attribute__((noinline))
125 #endif
126 
127 // exceptions
128 #if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND)
129 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 0
130 #else
131 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 1
132 #endif
133 
134 // count leading/trailing bits
135 #if !defined(ROBIN_HOOD_DISABLE_INTRINSICS)
136 # ifdef _MSC_VER
137 # if ROBIN_HOOD(BITNESS) == 32
138 # define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward
139 # else
140 # define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward64
141 # endif
142 # include <intrin.h>
143 # pragma intrinsic(ROBIN_HOOD(BITSCANFORWARD))
144 # define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) \
145  [](size_t mask) noexcept -> int { \
146  unsigned long index; \
147  return ROBIN_HOOD(BITSCANFORWARD)(&index, mask) ? static_cast<int>(index) \
148  : ROBIN_HOOD(BITNESS); \
149  }(x)
150 # else
151 # if ROBIN_HOOD(BITNESS) == 32
152 # define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzl
153 # define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzl
154 # else
155 # define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzll
156 # define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzll
157 # endif
158 # define ROBIN_HOOD_COUNT_LEADING_ZEROES(x) ((x) ? ROBIN_HOOD(CLZ)(x) : ROBIN_HOOD(BITNESS))
159 # define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ((x) ? ROBIN_HOOD(CTZ)(x) : ROBIN_HOOD(BITNESS))
160 # endif
161 #endif
162 
163 // fallthrough
164 #ifndef __has_cpp_attribute // For backwards compatibility
165 # define __has_cpp_attribute(x) 0
166 #endif
167 #if __has_cpp_attribute(clang::fallthrough)
168 # define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[clang::fallthrough]]
169 #elif __has_cpp_attribute(gnu::fallthrough)
170 # define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[gnu::fallthrough]]
171 #else
172 # define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH()
173 #endif
174 
175 // likely/unlikely
176 #ifdef _MSC_VER
177 # define ROBIN_HOOD_LIKELY(condition) condition
178 # define ROBIN_HOOD_UNLIKELY(condition) condition
179 #else
180 # define ROBIN_HOOD_LIKELY(condition) __builtin_expect(condition, 1)
181 # define ROBIN_HOOD_UNLIKELY(condition) __builtin_expect(condition, 0)
182 #endif
183 
184 // detect if native wchar_t type is availiable in MSVC
185 #ifdef _MSC_VER
186 # ifdef _NATIVE_WCHAR_T_DEFINED
187 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1
188 # else
189 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 0
190 # endif
191 #else
192 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1
193 #endif
194 
195 // detect if MSVC supports the pair(std::piecewise_construct_t,...) consructor being constexpr
196 #ifdef _MSC_VER
197 # if _MSC_VER <= 1900
198 # define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 1
199 # else
200 # define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0
201 # endif
202 #else
203 # define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0
204 #endif
205 
206 // workaround missing "is_trivially_copyable" in g++ < 5.0
207 // See https://stackoverflow.com/a/31798726/48181
208 #if defined(__GNUC__) && __GNUC__ < 5
209 # define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)
210 #else
211 # define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value
212 #endif
213 
214 // helpers for C++ versions, see https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
215 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX() __cplusplus
216 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX98() 199711L
217 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX11() 201103L
218 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX14() 201402L
219 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX17() 201703L
220 
221 #if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)
222 # define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD() [[nodiscard]]
223 #else
224 # define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD()
225 #endif
226 
227 namespace robin_hood {
228 
229 #if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)
230 # define ROBIN_HOOD_STD std
231 #else
232 
233 // c++11 compatibility layer
234 namespace ROBIN_HOOD_STD {
235 template <class T>
237  : std::integral_constant<std::size_t, alignof(typename std::remove_all_extents<T>::type)> {};
238 
239 template <class T, T... Ints>
241 public:
242  using value_type = T;
243  static_assert(std::is_integral<value_type>::value, "not integral type");
244  static constexpr std::size_t size() noexcept {
245  return sizeof...(Ints);
246  }
247 };
248 template <std::size_t... Inds>
249 using index_sequence = integer_sequence<std::size_t, Inds...>;
250 
251 namespace detail_ {
252 template <class T, T Begin, T End, bool>
253 struct IntSeqImpl {
254  using TValue = T;
255  static_assert(std::is_integral<TValue>::value, "not integral type");
256  static_assert(Begin >= 0 && Begin < End, "unexpected argument (Begin<0 || Begin<=End)");
257 
258  template <class, class>
260 
261  template <TValue... Inds0, TValue... Inds1>
263  using TResult = integer_sequence<TValue, Inds0..., Inds1...>;
264  };
265 
266  using TResult =
267  typename IntSeqCombiner<typename IntSeqImpl<TValue, Begin, Begin + (End - Begin) / 2,
268  (End - Begin) / 2 == 1>::TResult,
269  typename IntSeqImpl<TValue, Begin + (End - Begin) / 2, End,
270  (End - Begin + 1) / 2 == 1>::TResult>::TResult;
271 };
272 
273 template <class T, T Begin>
274 struct IntSeqImpl<T, Begin, Begin, false> {
275  using TValue = T;
276  static_assert(std::is_integral<TValue>::value, "not integral type");
277  static_assert(Begin >= 0, "unexpected argument (Begin<0)");
279 };
280 
281 template <class T, T Begin, T End>
282 struct IntSeqImpl<T, Begin, End, true> {
283  using TValue = T;
284  static_assert(std::is_integral<TValue>::value, "not integral type");
285  static_assert(Begin >= 0, "unexpected argument (Begin<0)");
287 };
288 } // namespace detail_
289 
290 template <class T, T N>
291 using make_integer_sequence = typename detail_::IntSeqImpl<T, 0, N, (N - 0) == 1>::TResult;
292 
293 template <std::size_t N>
295 
296 template <class... T>
298 
299 } // namespace ROBIN_HOOD_STD
300 
301 #endif
302 
303 namespace detail {
304 
305 // make sure we static_cast to the correct type for hash_int
306 #if ROBIN_HOOD(BITNESS) == 64
307 using SizeT = uint64_t;
308 #else
309 using SizeT = uint32_t;
310 #endif
311 
312 template <typename T>
313 T rotr(T x, unsigned k) {
314  return (x >> k) | (x << (8U * sizeof(T) - k));
315 }
316 
317 // This cast gets rid of warnings like "cast from 'uint8_t*' {aka 'unsigned char*'} to
318 // 'uint64_t*' {aka 'long unsigned int*'} increases required alignment of target type". Use with
319 // care!
320 template <typename T>
321 inline T reinterpret_cast_no_cast_align_warning(void* ptr) noexcept {
322  return reinterpret_cast<T>(ptr);
323 }
324 
325 template <typename T>
326 inline T reinterpret_cast_no_cast_align_warning(void const* ptr) noexcept {
327  return reinterpret_cast<T>(ptr);
328 }
329 
330 // make sure this is not inlined as it is slow and dramatically enlarges code, thus making other
331 // inlinings more difficult. Throws are also generally the slow path.
332 template <typename E, typename... Args>
333 [[noreturn]] ROBIN_HOOD(NOINLINE)
334 #if ROBIN_HOOD(HAS_EXCEPTIONS)
335  void doThrow(Args&&... args) {
336  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
337  throw E(std::forward<Args>(args)...);
338 }
339 #else
340  void doThrow(Args&&... ROBIN_HOOD_UNUSED(args) /*unused*/) {
341  abort();
342 }
343 #endif
344 
345 template <typename E, typename T, typename... Args>
346 T* assertNotNull(T* t, Args&&... args) {
347  if (ROBIN_HOOD_UNLIKELY(nullptr == t)) {
348  doThrow<E>(std::forward<Args>(args)...);
349  }
350  return t;
351 }
352 
353 template <typename T>
354 inline T unaligned_load(void const* ptr) noexcept {
355  // using memcpy so we don't get into unaligned load problems.
356  // compiler should optimize this very well anyways.
357  T t;
358  std::memcpy(&t, ptr, sizeof(T));
359  return t;
360 }
361 
362 // Allocates bulks of memory for objects of type T. This deallocates the memory in the destructor,
363 // and keeps a linked list of the allocated memory around. Overhead per allocation is the size of a
364 // pointer.
365 template <typename T, size_t MinNumAllocs = 4, size_t MaxNumAllocs = 256>
367 public:
368  BulkPoolAllocator() noexcept = default;
369 
370  // does not copy anything, just creates a new allocator.
372  : mHead(nullptr)
373  , mListForFree(nullptr) {}
374 
376  : mHead(o.mHead)
377  , mListForFree(o.mListForFree) {
378  o.mListForFree = nullptr;
379  o.mHead = nullptr;
380  }
381 
383  reset();
384  mHead = o.mHead;
385  mListForFree = o.mListForFree;
386  o.mListForFree = nullptr;
387  o.mHead = nullptr;
388  return *this;
389  }
390 
392  // NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp)
393  operator=(const BulkPoolAllocator& ROBIN_HOOD_UNUSED(o) /*unused*/) noexcept {
394  // does not do anything
395  return *this;
396  }
397 
398  ~BulkPoolAllocator() noexcept {
399  reset();
400  }
401 
402  // Deallocates all allocated memory.
403  void reset() noexcept {
404  while (mListForFree) {
405  T* tmp = *mListForFree;
406  ROBIN_HOOD_LOG("std::free")
407  std::free(mListForFree);
408  mListForFree = reinterpret_cast_no_cast_align_warning<T**>(tmp);
409  }
410  mHead = nullptr;
411  }
412 
413  // allocates, but does NOT initialize. Use in-place new constructor, e.g.
414  // T* obj = pool.allocate();
415  // ::new (static_cast<void*>(obj)) T();
416  T* allocate() {
417  T* tmp = mHead;
418  if (!tmp) {
419  tmp = performAllocation();
420  }
421 
422  mHead = *reinterpret_cast_no_cast_align_warning<T**>(tmp);
423  return tmp;
424  }
425 
426  // does not actually deallocate but puts it in store.
427  // make sure you have already called the destructor! e.g. with
428  // obj->~T();
429  // pool.deallocate(obj);
430  void deallocate(T* obj) noexcept {
431  *reinterpret_cast_no_cast_align_warning<T**>(obj) = mHead;
432  mHead = obj;
433  }
434 
435  // Adds an already allocated block of memory to the allocator. This allocator is from now on
436  // responsible for freeing the data (with free()). If the provided data is not large enough to
437  // make use of, it is immediately freed. Otherwise it is reused and freed in the destructor.
438  void addOrFree(void* ptr, const size_t numBytes) noexcept {
439  // calculate number of available elements in ptr
440  if (numBytes < ALIGNMENT + ALIGNED_SIZE) {
441  // not enough data for at least one element. Free and return.
442  ROBIN_HOOD_LOG("std::free")
443  std::free(ptr);
444  } else {
445  ROBIN_HOOD_LOG("add to buffer")
446  add(ptr, numBytes);
447  }
448  }
449 
451  using std::swap;
452  swap(mHead, other.mHead);
453  swap(mListForFree, other.mListForFree);
454  }
455 
456 private:
457  // iterates the list of allocated memory to calculate how many to alloc next.
458  // Recalculating this each time saves us a size_t member.
459  // This ignores the fact that memory blocks might have been added manually with addOrFree. In
460  // practice, this should not matter much.
461  ROBIN_HOOD(NODISCARD) size_t calcNumElementsToAlloc() const noexcept {
462  auto tmp = mListForFree;
463  size_t numAllocs = MinNumAllocs;
464 
465  while (numAllocs * 2 <= MaxNumAllocs && tmp) {
466  auto x = reinterpret_cast<T***>(tmp);
467  tmp = *x;
468  numAllocs *= 2;
469  }
470 
471  return numAllocs;
472  }
473 
474  // WARNING: Underflow if numBytes < ALIGNMENT! This is guarded in addOrFree().
475  void add(void* ptr, const size_t numBytes) noexcept {
476  const size_t numElements = (numBytes - ALIGNMENT) / ALIGNED_SIZE;
477 
478  auto data = reinterpret_cast<T**>(ptr);
479 
480  // link free list
481  auto x = reinterpret_cast<T***>(data);
482  *x = mListForFree;
483  mListForFree = data;
484 
485  // create linked list for newly allocated data
486  auto* const headT =
487  reinterpret_cast_no_cast_align_warning<T*>(reinterpret_cast<char*>(ptr) + ALIGNMENT);
488 
489  auto* const head = reinterpret_cast<char*>(headT);
490 
491  // Visual Studio compiler automatically unrolls this loop, which is pretty cool
492  for (size_t i = 0; i < numElements; ++i) {
493  *reinterpret_cast_no_cast_align_warning<char**>(head + i * ALIGNED_SIZE) =
494  head + (i + 1) * ALIGNED_SIZE;
495  }
496 
497  // last one points to 0
498  *reinterpret_cast_no_cast_align_warning<T**>(head + (numElements - 1) * ALIGNED_SIZE) =
499  mHead;
500  mHead = headT;
501  }
502 
503  // Called when no memory is available (mHead == 0).
504  // Don't inline this slow path.
505  ROBIN_HOOD(NOINLINE) T* performAllocation() {
506  size_t const numElementsToAlloc = calcNumElementsToAlloc();
507 
508  // alloc new memory: [prev |T, T, ... T]
509  size_t const bytes = ALIGNMENT + ALIGNED_SIZE * numElementsToAlloc;
510  ROBIN_HOOD_LOG("std::malloc " << bytes << " = " << ALIGNMENT << " + " << ALIGNED_SIZE
511  << " * " << numElementsToAlloc)
512  add(assertNotNull<std::bad_alloc>(std::malloc(bytes)), bytes);
513  return mHead;
514  }
515 
516  // enforce byte alignment of the T's
517 #if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)
518  static constexpr size_t ALIGNMENT =
519  (std::max)(std::alignment_of<T>::value, std::alignment_of<T*>::value);
520 #else
521  static const size_t ALIGNMENT =
522  (ROBIN_HOOD_STD::alignment_of<T>::value > ROBIN_HOOD_STD::alignment_of<T*>::value)
523  ? ROBIN_HOOD_STD::alignment_of<T>::value
524  : +ROBIN_HOOD_STD::alignment_of<T*>::value; // the + is for walkarround
525 #endif
526 
527  static constexpr size_t ALIGNED_SIZE = ((sizeof(T) - 1) / ALIGNMENT + 1) * ALIGNMENT;
528 
529  static_assert(MinNumAllocs >= 1, "MinNumAllocs");
530  static_assert(MaxNumAllocs >= MinNumAllocs, "MaxNumAllocs");
531  static_assert(ALIGNED_SIZE >= sizeof(T*), "ALIGNED_SIZE");
532  static_assert(0 == (ALIGNED_SIZE % sizeof(T*)), "ALIGNED_SIZE mod");
533  static_assert(ALIGNMENT >= sizeof(T*), "ALIGNMENT");
534 
535  T* mHead{nullptr};
536  T** mListForFree{nullptr};
537 };
538 
539 template <typename T, size_t MinSize, size_t MaxSize, bool IsFlat>
541 
542 // dummy allocator that does nothing
543 template <typename T, size_t MinSize, size_t MaxSize>
544 struct NodeAllocator<T, MinSize, MaxSize, true> {
545 
546  // we are not using the data, so just free it.
547  void addOrFree(void* ptr, size_t ROBIN_HOOD_UNUSED(numBytes) /*unused*/) noexcept {
548  ROBIN_HOOD_LOG("std::free")
549  std::free(ptr);
550  }
551 };
552 
553 template <typename T, size_t MinSize, size_t MaxSize>
554 struct NodeAllocator<T, MinSize, MaxSize, false> : public BulkPoolAllocator<T, MinSize, MaxSize> {};
555 
556 // c++14 doesn't have is_nothrow_swappable, and clang++ 6.0.1 doesn't like it either, so I'm making
557 // my own here.
558 namespace swappable {
559 #if ROBIN_HOOD(CXX) < ROBIN_HOOD(CXX17)
560 using std::swap;
561 template <typename T>
562 struct nothrow {
563  static const bool value = noexcept(swap(std::declval<T&>(), std::declval<T&>()));
564 };
565 #else
566 template <typename T>
567 struct nothrow {
568  static const bool value = std::is_nothrow_swappable<T>::value;
569 };
570 #endif
571 } // namespace swappable
572 
573 } // namespace detail
574 
576 
577 // A custom pair implementation is used in the map because std::pair is not is_trivially_copyable,
578 // which means it would not be allowed to be used in std::memcpy. This struct is copyable, which is
579 // also tested.
580 template <typename T1, typename T2>
581 struct pair {
582  using first_type = T1;
583  using second_type = T2;
584 
585  template <typename U1 = T1, typename U2 = T2,
586  typename = typename std::enable_if<std::is_default_constructible<U1>::value &&
587  std::is_default_constructible<U2>::value>::type>
588  constexpr pair() noexcept(noexcept(U1()) && noexcept(U2()))
589  : first()
590  , second() {}
591 
592  // pair constructors are explicit so we don't accidentally call this ctor when we don't have to.
593  explicit constexpr pair(std::pair<T1, T2> const& o) noexcept(
594  noexcept(T1(std::declval<T1 const&>())) && noexcept(T2(std::declval<T2 const&>())))
595  : first(o.first)
596  , second(o.second) {}
597 
598  // pair constructors are explicit so we don't accidentally call this ctor when we don't have to.
599  explicit constexpr pair(std::pair<T1, T2>&& o) noexcept(noexcept(
600  T1(std::move(std::declval<T1&&>()))) && noexcept(T2(std::move(std::declval<T2&&>()))))
601  : first(std::move(o.first))
602  , second(std::move(o.second)) {}
603 
604  constexpr pair(T1&& a, T2&& b) noexcept(noexcept(
605  T1(std::move(std::declval<T1&&>()))) && noexcept(T2(std::move(std::declval<T2&&>()))))
606  : first(std::move(a))
607  , second(std::move(b)) {}
608 
609  template <typename U1, typename U2>
610  constexpr pair(U1&& a, U2&& b) noexcept(noexcept(T1(std::forward<U1>(
611  std::declval<U1&&>()))) && noexcept(T2(std::forward<U2>(std::declval<U2&&>()))))
612  : first(std::forward<U1>(a))
613  , second(std::forward<U2>(b)) {}
614 
615  template <typename... U1, typename... U2>
616  // MSVC 2015 produces error "C2476: ‘constexpr’ constructor does not initialize all members"
617  // if this constructor is constexpr
618 #if !ROBIN_HOOD(BROKEN_CONSTEXPR)
619  constexpr
620 #endif
621  pair(std::piecewise_construct_t /*unused*/, std::tuple<U1...> a,
622  std::tuple<U2...>
623  b) noexcept(noexcept(pair(std::declval<std::tuple<U1...>&>(),
624  std::declval<std::tuple<U2...>&>(),
627  : pair(a, b, ROBIN_HOOD_STD::index_sequence_for<U1...>(),
628  ROBIN_HOOD_STD::index_sequence_for<U2...>()) {
629  }
630 
631  // constructor called from the std::piecewise_construct_t ctor
632  template <typename... U1, size_t... I1, typename... U2, size_t... I2>
633  pair(std::tuple<U1...>& a, std::tuple<U2...>& b, ROBIN_HOOD_STD::index_sequence<I1...> /*unused*/, ROBIN_HOOD_STD::index_sequence<I2...> /*unused*/) noexcept(
634  noexcept(T1(std::forward<U1>(std::get<I1>(
635  std::declval<std::tuple<
636  U1...>&>()))...)) && noexcept(T2(std::
637  forward<U2>(std::get<I2>(
638  std::declval<std::tuple<U2...>&>()))...)))
639  : first(std::forward<U1>(std::get<I1>(a))...)
640  , second(std::forward<U2>(std::get<I2>(b))...) {
641  // make visual studio compiler happy about warning about unused a & b.
642  // Visual studio's pair implementation disables warning 4100.
643  (void)a;
644  (void)b;
645  }
646 
649  using std::swap;
650  swap(first, o.first);
651  swap(second, o.second);
652  }
653 
654  T1 first; // NOLINT(misc-non-private-member-variables-in-classes)
655  T2 second; // NOLINT(misc-non-private-member-variables-in-classes)
656 };
657 
658 template <typename A, typename B>
659 inline void swap(pair<A, B>& a, pair<A, B>& b) noexcept(
660  noexcept(std::declval<pair<A, B>&>().swap(std::declval<pair<A, B>&>()))) {
661  a.swap(b);
662 }
663 
664 template <typename A, typename B>
665 inline constexpr bool operator==(pair<A, B> const& x, pair<A, B> const& y) {
666  return (x.first == y.first) && (x.second == y.second);
667 }
668 template <typename A, typename B>
669 inline constexpr bool operator!=(pair<A, B> const& x, pair<A, B> const& y) {
670  return !(x == y);
671 }
672 template <typename A, typename B>
673 inline constexpr bool operator<(pair<A, B> const& x, pair<A, B> const& y) noexcept(noexcept(
674  std::declval<A const&>() < std::declval<A const&>()) && noexcept(std::declval<B const&>() <
675  std::declval<B const&>())) {
676  return x.first < y.first || (!(y.first < x.first) && x.second < y.second);
677 }
678 template <typename A, typename B>
679 inline constexpr bool operator>(pair<A, B> const& x, pair<A, B> const& y) {
680  return y < x;
681 }
682 template <typename A, typename B>
683 inline constexpr bool operator<=(pair<A, B> const& x, pair<A, B> const& y) {
684  return !(x > y);
685 }
686 template <typename A, typename B>
687 inline constexpr bool operator>=(pair<A, B> const& x, pair<A, B> const& y) {
688  return !(x < y);
689 }
690 
691 inline size_t hash_bytes(void const* ptr, size_t len) noexcept {
692  static constexpr uint64_t m = UINT64_C(0xc6a4a7935bd1e995);
693  static constexpr uint64_t seed = UINT64_C(0xe17a1465);
694  static constexpr unsigned int r = 47;
695 
696  auto const* const data64 = static_cast<uint64_t const*>(ptr);
697  uint64_t h = seed ^ (len * m);
698 
699  size_t const n_blocks = len / 8;
700  for (size_t i = 0; i < n_blocks; ++i) {
701  auto k = detail::unaligned_load<uint64_t>(data64 + i);
702 
703  k *= m;
704  k ^= k >> r;
705  k *= m;
706 
707  h ^= k;
708  h *= m;
709  }
710 
711  auto const* const data8 = reinterpret_cast<uint8_t const*>(data64 + n_blocks);
712  switch (len & 7U) {
713  case 7:
714  h ^= static_cast<uint64_t>(data8[6]) << 48U;
715  ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
716  case 6:
717  h ^= static_cast<uint64_t>(data8[5]) << 40U;
718  ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
719  case 5:
720  h ^= static_cast<uint64_t>(data8[4]) << 32U;
721  ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
722  case 4:
723  h ^= static_cast<uint64_t>(data8[3]) << 24U;
724  ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
725  case 3:
726  h ^= static_cast<uint64_t>(data8[2]) << 16U;
727  ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
728  case 2:
729  h ^= static_cast<uint64_t>(data8[1]) << 8U;
730  ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
731  case 1:
732  h ^= static_cast<uint64_t>(data8[0]);
733  h *= m;
734  ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
735  default:
736  break;
737  }
738 
739  h ^= h >> r;
740 
741  // not doing the final step here, because this will be done by keyToIdx anyways
742  // h *= m;
743  // h ^= h >> r;
744  return static_cast<size_t>(h);
745 }
746 
747 inline size_t hash_int(uint64_t x) noexcept {
748  // tried lots of different hashes, let's stick with murmurhash3. It's simple, fast, well tested,
749  // and doesn't need any special 128bit operations.
750  x ^= x >> 33U;
751  x *= UINT64_C(0xff51afd7ed558ccd);
752  x ^= x >> 33U;
753 
754  // not doing the final step here, because this will be done by keyToIdx anyways
755  // x *= UINT64_C(0xc4ceb9fe1a85ec53);
756  // x ^= x >> 33U;
757  return static_cast<size_t>(x);
758 }
759 
760 // A thin wrapper around std::hash, performing an additional simple mixing step of the result.
761 template <typename T, typename Enable = void>
762 struct hash : public std::hash<T> {
763  size_t operator()(T const& obj) const
764  noexcept(noexcept(std::declval<std::hash<T>>().operator()(std::declval<T const&>()))) {
765  // call base hash
766  auto result = std::hash<T>::operator()(obj);
767  // return mixed of that, to be save against identity has
768  return hash_int(static_cast<detail::SizeT>(result));
769  }
770 };
771 
772 template <typename CharT>
773 struct hash<std::basic_string<CharT>> {
774  size_t operator()(std::basic_string<CharT> const& str) const noexcept {
775  return hash_bytes(str.data(), sizeof(CharT) * str.size());
776  }
777 };
778 
779 #if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)
780 template <typename CharT>
781 struct hash<std::basic_string_view<CharT>> {
782  size_t operator()(std::basic_string_view<CharT> const& sv) const noexcept {
783  return hash_bytes(sv.data(), sizeof(CharT) * sv.size());
784  }
785 };
786 #endif
787 
788 template <class T>
789 struct hash<T*> {
790  size_t operator()(T* ptr) const noexcept {
791  return hash_int(reinterpret_cast<detail::SizeT>(ptr));
792  }
793 };
794 
795 template <class T>
796 struct hash<std::unique_ptr<T>> {
797  size_t operator()(std::unique_ptr<T> const& ptr) const noexcept {
798  return hash_int(reinterpret_cast<detail::SizeT>(ptr.get()));
799  }
800 };
801 
802 template <class T>
803 struct hash<std::shared_ptr<T>> {
804  size_t operator()(std::shared_ptr<T> const& ptr) const noexcept {
805  return hash_int(reinterpret_cast<detail::SizeT>(ptr.get()));
806  }
807 };
808 
809 template <typename Enum>
810 struct hash<Enum, typename std::enable_if<std::is_enum<Enum>::value>::type> {
811  size_t operator()(Enum e) const noexcept {
812  using Underlying = typename std::underlying_type<Enum>::type;
813  return hash<Underlying>{}(static_cast<Underlying>(e));
814  }
815 };
816 
817 #define ROBIN_HOOD_HASH_INT(T) \
818  template <> \
819  struct hash<T> { \
820  size_t operator()(T const& obj) const noexcept { \
821  return hash_int(static_cast<uint64_t>(obj)); \
822  } \
823  }
824 
825 #if defined(__GNUC__) && !defined(__clang__)
826 # pragma GCC diagnostic push
827 # pragma GCC diagnostic ignored "-Wuseless-cast"
828 #endif
829 // see https://en.cppreference.com/w/cpp/utility/hash
830 ROBIN_HOOD_HASH_INT(bool);
831 ROBIN_HOOD_HASH_INT(char);
832 ROBIN_HOOD_HASH_INT(signed char);
833 ROBIN_HOOD_HASH_INT(unsigned char);
834 ROBIN_HOOD_HASH_INT(char16_t);
835 ROBIN_HOOD_HASH_INT(char32_t);
836 #if ROBIN_HOOD(HAS_NATIVE_WCHART)
837 ROBIN_HOOD_HASH_INT(wchar_t);
838 #endif
839 ROBIN_HOOD_HASH_INT(short);
840 ROBIN_HOOD_HASH_INT(unsigned short);
842 ROBIN_HOOD_HASH_INT(unsigned int);
843 ROBIN_HOOD_HASH_INT(long);
844 ROBIN_HOOD_HASH_INT(long long);
845 ROBIN_HOOD_HASH_INT(unsigned long);
846 ROBIN_HOOD_HASH_INT(unsigned long long);
847 #if defined(__GNUC__) && !defined(__clang__)
848 # pragma GCC diagnostic pop
849 #endif
850 namespace detail {
851 
852 template <typename T>
853 struct void_type {
854  using type = void;
855 };
856 
857 template <typename T, typename = void>
858 struct has_is_transparent : public std::false_type {};
859 
860 template <typename T>
861 struct has_is_transparent<T, typename void_type<typename T::is_transparent>::type>
862  : public std::true_type {};
863 
864 // using wrapper classes for hash and key_equal prevents the diamond problem when the same type
865 // is used. see https://stackoverflow.com/a/28771920/48181
866 template <typename T>
867 struct WrapHash : public T {
868  WrapHash() = default;
869  explicit WrapHash(T const& o) noexcept(noexcept(T(std::declval<T const&>())))
870  : T(o) {}
871 };
872 
873 template <typename T>
874 struct WrapKeyEqual : public T {
875  WrapKeyEqual() = default;
876  explicit WrapKeyEqual(T const& o) noexcept(noexcept(T(std::declval<T const&>())))
877  : T(o) {}
878 };
879 
880 // A highly optimized hashmap implementation, using the Robin Hood algorithm.
881 //
882 // In most cases, this map should be usable as a drop-in replacement for std::unordered_map, but
883 // be about 2x faster in most cases and require much less allocations.
884 //
885 // This implementation uses the following memory layout:
886 //
887 // [Node, Node, ... Node | info, info, ... infoSentinel ]
888 //
889 // * Node: either a DataNode that directly has the std::pair<key, val> as member,
890 // or a DataNode with a pointer to std::pair<key,val>. Which DataNode representation to use
891 // depends on how fast the swap() operation is. Heuristically, this is automatically choosen
892 // based on sizeof(). there are always 2^n Nodes.
893 //
894 // * info: Each Node in the map has a corresponding info byte, so there are 2^n info bytes.
895 // Each byte is initialized to 0, meaning the corresponding Node is empty. Set to 1 means the
896 // corresponding node contains data. Set to 2 means the corresponding Node is filled, but it
897 // actually belongs to the previous position and was pushed out because that place is already
898 // taken.
899 //
900 // * infoSentinel: Sentinel byte set to 1, so that iterator's ++ can stop at end() without the
901 // need for a idx variable.
902 //
903 // According to STL, order of templates has effect on throughput. That's why I've moved the
904 // boolean to the front.
905 // https://www.reddit.com/r/cpp/comments/ahp6iu/compile_time_binary_size_reductions_and_cs_future/eeguck4/
906 template <bool IsFlat, size_t MaxLoadFactor100, typename Key, typename T, typename Hash,
907  typename KeyEqual>
908 class Table
909  : public WrapHash<Hash>,
910  public WrapKeyEqual<KeyEqual>,
912  typename std::conditional<
913  std::is_void<T>::value, Key,
914  robin_hood::pair<typename std::conditional<IsFlat, Key, Key const>::type, T>>::type,
915  4, 16384, IsFlat> {
916 public:
917  static constexpr bool is_flat = IsFlat;
918  static constexpr bool is_map = !std::is_void<T>::value;
919  static constexpr bool is_set = !is_map;
920  static constexpr bool is_transparent =
922 
923  using key_type = Key;
924  using mapped_type = T;
925  using value_type = typename std::conditional<
926  is_set, Key,
928  using size_type = size_t;
929  using hasher = Hash;
930  using key_equal = KeyEqual;
932 
933 private:
934  static_assert(MaxLoadFactor100 > 10 && MaxLoadFactor100 < 100,
935  "MaxLoadFactor100 needs to be >10 && < 100");
936 
937  using WHash = WrapHash<Hash>;
939 
940  // configuration defaults
941 
942  // make sure we have 8 elements, needed to quickly rehash mInfo
943  static constexpr size_t InitialNumElements = sizeof(uint64_t);
944  static constexpr uint32_t InitialInfoNumBits = 5;
945  static constexpr uint8_t InitialInfoInc = 1U << InitialInfoNumBits;
946  static constexpr size_t InfoMask = InitialInfoInc - 1U;
947  static constexpr uint8_t InitialInfoHashShift = 0;
949 
950  // type needs to be wider than uint8_t.
951  using InfoType = uint32_t;
952 
953  // DataNode ////////////////////////////////////////////////////////
954 
955  // Primary template for the data node. We have special implementations for small and big
956  // objects. For large objects it is assumed that swap() is fairly slow, so we allocate these
957  // on the heap so swap merely swaps a pointer.
958  template <typename M, bool>
959  class DataNode {};
960 
961  // Small: just allocate on the stack.
962  template <typename M>
963  class DataNode<M, true> final {
964  public:
965  template <typename... Args>
966  explicit DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, Args&&... args) noexcept(
967  noexcept(value_type(std::forward<Args>(args)...)))
968  : mData(std::forward<Args>(args)...) {}
969 
970  DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, DataNode<M, true>&& n) noexcept(
971  std::is_nothrow_move_constructible<value_type>::value)
972  : mData(std::move(n.mData)) {}
973 
974  // doesn't do anything
975  void destroy(M& ROBIN_HOOD_UNUSED(map) /*unused*/) noexcept {}
976  void destroyDoNotDeallocate() noexcept {}
977 
978  value_type const* operator->() const noexcept {
979  return &mData;
980  }
981  value_type* operator->() noexcept {
982  return &mData;
983  }
984 
985  const value_type& operator*() const noexcept {
986  return mData;
987  }
988 
989  value_type& operator*() noexcept {
990  return mData;
991  }
992 
993  template <typename VT = value_type>
994  ROBIN_HOOD(NODISCARD)
995  typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {
996  return mData.first;
997  }
998  template <typename VT = value_type>
999  ROBIN_HOOD(NODISCARD)
1000  typename std::enable_if<is_set, VT&>::type getFirst() noexcept {
1001  return mData;
1002  }
1003 
1004  template <typename VT = value_type>
1005  ROBIN_HOOD(NODISCARD)
1006  typename std::enable_if<is_map, typename VT::first_type const&>::type
1007  getFirst() const noexcept {
1008  return mData.first;
1009  }
1010  template <typename VT = value_type>
1011  ROBIN_HOOD(NODISCARD)
1012  typename std::enable_if<is_set, VT const&>::type getFirst() const noexcept {
1013  return mData;
1014  }
1015 
1016  template <typename MT = mapped_type>
1017  ROBIN_HOOD(NODISCARD)
1018  typename std::enable_if<is_map, MT&>::type getSecond() noexcept {
1019  return mData.second;
1020  }
1021 
1022  template <typename MT = mapped_type>
1023  ROBIN_HOOD(NODISCARD)
1024  typename std::enable_if<is_set, MT const&>::type getSecond() const noexcept {
1025  return mData.second;
1026  }
1027 
1028  void swap(DataNode<M, true>& o) noexcept(
1029  noexcept(std::declval<value_type>().swap(std::declval<value_type>()))) {
1030  mData.swap(o.mData);
1031  }
1032 
1033  private:
1034  value_type mData;
1035  };
1036 
1037  // big object: allocate on heap.
1038  template <typename M>
1039  class DataNode<M, false> {
1040  public:
1041  template <typename... Args>
1042  explicit DataNode(M& map, Args&&... args)
1043  : mData(map.allocate()) {
1044  ::new (static_cast<void*>(mData)) value_type(std::forward<Args>(args)...);
1045  }
1046 
1047  DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, DataNode<M, false>&& n) noexcept
1048  : mData(std::move(n.mData)) {}
1049 
1050  void destroy(M& map) noexcept {
1051  // don't deallocate, just put it into list of datapool.
1052  mData->~value_type();
1053  map.deallocate(mData);
1054  }
1055 
1056  void destroyDoNotDeallocate() noexcept {
1057  mData->~value_type();
1058  }
1059 
1060  value_type const* operator->() const noexcept {
1061  return mData;
1062  }
1063 
1064  value_type* operator->() noexcept {
1065  return mData;
1066  }
1067 
1068  const value_type& operator*() const {
1069  return *mData;
1070  }
1071 
1072  value_type& operator*() {
1073  return *mData;
1074  }
1075 
1076  template <typename VT = value_type>
1077  ROBIN_HOOD(NODISCARD)
1078  typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {
1079  return mData->first;
1080  }
1081  template <typename VT = value_type>
1082  ROBIN_HOOD(NODISCARD)
1083  typename std::enable_if<is_set, VT&>::type getFirst() noexcept {
1084  return *mData;
1085  }
1086 
1087  template <typename VT = value_type>
1088  ROBIN_HOOD(NODISCARD)
1089  typename std::enable_if<is_map, typename VT::first_type const&>::type
1090  getFirst() const noexcept {
1091  return mData->first;
1092  }
1093  template <typename VT = value_type>
1094  ROBIN_HOOD(NODISCARD)
1095  typename std::enable_if<is_set, VT const&>::type getFirst() const noexcept {
1096  return *mData;
1097  }
1098 
1099  template <typename MT = mapped_type>
1100  ROBIN_HOOD(NODISCARD)
1101  typename std::enable_if<is_map, MT&>::type getSecond() noexcept {
1102  return mData->second;
1103  }
1104 
1105  template <typename MT = mapped_type>
1106  ROBIN_HOOD(NODISCARD)
1107  typename std::enable_if<is_map, MT const&>::type getSecond() const noexcept {
1108  return mData->second;
1109  }
1110 
1111  void swap(DataNode<M, false>& o) noexcept {
1112  using std::swap;
1113  swap(mData, o.mData);
1114  }
1115 
1116  private:
1117  value_type* mData;
1118  };
1119 
1120  using Node = DataNode<Self, IsFlat>;
1121 
1122  // helpers for insertKeyPrepareEmptySpot: extract first entry (only const required)
1123  ROBIN_HOOD(NODISCARD) key_type const& getFirstConst(Node const& n) const noexcept {
1124  return n.getFirst();
1125  }
1126 
1127  // in case we have void mapped_type, we are not using a pair, thus we just route k through.
1128  // No need to disable this because it's just not used if not applicable.
1129  ROBIN_HOOD(NODISCARD) key_type const& getFirstConst(key_type const& k) const noexcept {
1130  return k;
1131  }
1132 
1133  // in case we have non-void mapped_type, we have a standard robin_hood::pair
1134  template <typename Q = mapped_type>
1135  ROBIN_HOOD(NODISCARD)
1136  typename std::enable_if<!std::is_void<Q>::value, key_type const&>::type
1137  getFirstConst(value_type const& vt) const noexcept {
1138  return vt.first;
1139  }
1140 
1141  // Cloner //////////////////////////////////////////////////////////
1142 
1143  template <typename M, bool UseMemcpy>
1144  struct Cloner;
1145 
1146  // fast path: Just copy data, without allocating anything.
1147  template <typename M>
1148  struct Cloner<M, true> {
1149  void operator()(M const& source, M& target) const {
1150  auto const* const src = reinterpret_cast<char const*>(source.mKeyVals);
1151  auto* tgt = reinterpret_cast<char*>(target.mKeyVals);
1152  auto const numElementsWithBuffer = target.calcNumElementsWithBuffer(target.mMask + 1);
1153  std::copy(src, src + target.calcNumBytesTotal(numElementsWithBuffer), tgt);
1154  }
1155  };
1156 
1157  template <typename M>
1158  struct Cloner<M, false> {
1159  void operator()(M const& s, M& t) const {
1160  auto const numElementsWithBuffer = t.calcNumElementsWithBuffer(t.mMask + 1);
1161  std::copy(s.mInfo, s.mInfo + t.calcNumBytesInfo(numElementsWithBuffer), t.mInfo);
1162 
1163  for (size_t i = 0; i < numElementsWithBuffer; ++i) {
1164  if (t.mInfo[i]) {
1165  ::new (static_cast<void*>(t.mKeyVals + i)) Node(t, *s.mKeyVals[i]);
1166  }
1167  }
1168  }
1169  };
1170 
1171  // Destroyer ///////////////////////////////////////////////////////
1172 
1173  template <typename M, bool IsFlatAndTrivial>
1174  struct Destroyer {};
1175 
1176  template <typename M>
1177  struct Destroyer<M, true> {
1178  void nodes(M& m) const noexcept {
1179  m.mNumElements = 0;
1180  }
1181 
1182  void nodesDoNotDeallocate(M& m) const noexcept {
1183  m.mNumElements = 0;
1184  }
1185  };
1186 
1187  template <typename M>
1188  struct Destroyer<M, false> {
1189  void nodes(M& m) const noexcept {
1190  m.mNumElements = 0;
1191  // clear also resets mInfo to 0, that's sometimes not necessary.
1192  auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
1193 
1194  for (size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
1195  if (0 != m.mInfo[idx]) {
1196  Node& n = m.mKeyVals[idx];
1197  n.destroy(m);
1198  n.~Node();
1199  }
1200  }
1201  }
1202 
1203  void nodesDoNotDeallocate(M& m) const noexcept {
1204  m.mNumElements = 0;
1205  // clear also resets mInfo to 0, that's sometimes not necessary.
1206  auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
1207  for (size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
1208  if (0 != m.mInfo[idx]) {
1209  Node& n = m.mKeyVals[idx];
1210  n.destroyDoNotDeallocate();
1211  n.~Node();
1212  }
1213  }
1214  }
1215  };
1216 
1217  // Iter ////////////////////////////////////////////////////////////
1218 
1219  struct fast_forward_tag {};
1220 
1221  // generic iterator for both const_iterator and iterator.
1222  template <bool IsConst>
1223  // NOLINTNEXTLINE(hicpp-special-member-functions,cppcoreguidelines-special-member-functions)
1224  class Iter {
1225  private:
1226  using NodePtr = typename std::conditional<IsConst, Node const*, Node*>::type;
1227 
1228  public:
1229  using difference_type = std::ptrdiff_t;
1230  using value_type = typename Self::value_type;
1231  using reference = typename std::conditional<IsConst, value_type const&, value_type&>::type;
1232  using pointer = typename std::conditional<IsConst, value_type const*, value_type*>::type;
1233  using iterator_category = std::forward_iterator_tag;
1234 
1235  // default constructed iterator can be compared to itself, but WON'T return true when
1236  // compared to end().
1237  Iter() = default;
1238 
1239  // Rule of zero: nothing specified. The conversion constructor is only enabled for
1240  // iterator to const_iterator, so it doesn't accidentally work as a copy ctor.
1241 
1242  // Conversion constructor from iterator to const_iterator.
1243  template <bool OtherIsConst,
1244  typename = typename std::enable_if<IsConst && !OtherIsConst>::type>
1245  // NOLINTNEXTLINE(hicpp-explicit-conversions)
1246  Iter(Iter<OtherIsConst> const& other) noexcept
1247  : mKeyVals(other.mKeyVals)
1248  , mInfo(other.mInfo) {}
1249 
1250  Iter(NodePtr valPtr, uint8_t const* infoPtr) noexcept
1251  : mKeyVals(valPtr)
1252  , mInfo(infoPtr) {}
1253 
1254  Iter(NodePtr valPtr, uint8_t const* infoPtr,
1255  fast_forward_tag ROBIN_HOOD_UNUSED(tag) /*unused*/) noexcept
1256  : mKeyVals(valPtr)
1257  , mInfo(infoPtr) {
1258  fastForward();
1259  }
1260 
1261  template <bool OtherIsConst,
1262  typename = typename std::enable_if<IsConst && !OtherIsConst>::type>
1263  Iter& operator=(Iter<OtherIsConst> const& other) noexcept {
1264  mKeyVals = other.mKeyVals;
1265  mInfo = other.mInfo;
1266  return *this;
1267  }
1268 
1269  // prefix increment. Undefined behavior if we are at end()!
1270  Iter& operator++() noexcept {
1271  mInfo++;
1272  mKeyVals++;
1273  fastForward();
1274  return *this;
1275  }
1276 
1277  Iter operator++(int) noexcept {
1278  Iter tmp = *this;
1279  ++(*this);
1280  return tmp;
1281  }
1282 
1283  reference operator*() const {
1284  return **mKeyVals;
1285  }
1286 
1287  pointer operator->() const {
1288  return &**mKeyVals;
1289  }
1290 
1291  template <bool O>
1292  bool operator==(Iter<O> const& o) const noexcept {
1293  return mKeyVals == o.mKeyVals;
1294  }
1295 
1296  template <bool O>
1297  bool operator!=(Iter<O> const& o) const noexcept {
1298  return mKeyVals != o.mKeyVals;
1299  }
1300 
1301  private:
1302  // fast forward to the next non-free info byte
1303  // I've tried a few variants that don't depend on intrinsics, but unfortunately they are
1304  // quite a bit slower than this one. So I've reverted that change again. See map_benchmark.
1305  void fastForward() noexcept {
1306  size_t n = 0;
1307  while (0U == (n = detail::unaligned_load<size_t>(mInfo))) {
1308  mInfo += sizeof(size_t);
1309  mKeyVals += sizeof(size_t);
1310  }
1311 #if defined(ROBIN_HOOD_DISABLE_INTRINSICS)
1312  // we know for certain that within the next 8 bytes we'll find a non-zero one.
1313  if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint32_t>(mInfo))) {
1314  mInfo += 4;
1315  mKeyVals += 4;
1316  }
1317  if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint16_t>(mInfo))) {
1318  mInfo += 2;
1319  mKeyVals += 2;
1320  }
1321  if (ROBIN_HOOD_UNLIKELY(0U == *mInfo)) {
1322  mInfo += 1;
1323  mKeyVals += 1;
1324  }
1325 #else
1326 # if ROBIN_HOOD(LITTLE_ENDIAN)
1327  auto inc = ROBIN_HOOD_COUNT_TRAILING_ZEROES(n) / 8;
1328 # else
1329  auto inc = ROBIN_HOOD_COUNT_LEADING_ZEROES(n) / 8;
1330 # endif
1331  mInfo += inc;
1332  mKeyVals += inc;
1333 #endif
1334  }
1335 
1336  friend class Table<IsFlat, MaxLoadFactor100, key_type, mapped_type, hasher, key_equal>;
1337  NodePtr mKeyVals{nullptr};
1338  uint8_t const* mInfo{nullptr};
1339  };
1340 
1342 
1343  // highly performance relevant code.
1344  // Lower bits are used for indexing into the array (2^n size)
1345  // The upper 1-5 bits need to be a reasonable good hash, to save comparisons.
1346  template <typename HashKey>
1347  void keyToIdx(HashKey&& key, size_t* idx, InfoType* info) const {
1348  // In addition to whatever hash is used, add another mul & shift so we get better hashing.
1349  // This serves as a bad hash prevention, if the given data is
1350  // badly mixed.
1351  auto h = static_cast<uint64_t>(WHash::operator()(key));
1352 
1353  h *= mHashMultiplier;
1354  h ^= h >> 33U;
1355 
1356  // the lower InitialInfoNumBits are reserved for info.
1357  *info = mInfoInc + static_cast<InfoType>((h & InfoMask) >> mInfoHashShift);
1358  *idx = (static_cast<size_t>(h) >> InitialInfoNumBits) & mMask;
1359  }
1360 
1361  // forwards the index by one, wrapping around at the end
1362  void next(InfoType* info, size_t* idx) const noexcept {
1363  *idx = *idx + 1;
1364  *info += mInfoInc;
1365  }
1366 
1367  void nextWhileLess(InfoType* info, size_t* idx) const noexcept {
1368  // unrolling this by hand did not bring any speedups.
1369  while (*info < mInfo[*idx]) {
1370  next(info, idx);
1371  }
1372  }
1373 
1374  // Shift everything up by one element. Tries to move stuff around.
1375  void
1376  shiftUp(size_t startIdx,
1377  size_t const insertion_idx) noexcept(std::is_nothrow_move_assignable<Node>::value) {
1378  auto idx = startIdx;
1379  ::new (static_cast<void*>(mKeyVals + idx)) Node(std::move(mKeyVals[idx - 1]));
1380  while (--idx != insertion_idx) {
1381  mKeyVals[idx] = std::move(mKeyVals[idx - 1]);
1382  }
1383 
1384  idx = startIdx;
1385  while (idx != insertion_idx) {
1386  ROBIN_HOOD_COUNT(shiftUp)
1387  mInfo[idx] = static_cast<uint8_t>(mInfo[idx - 1] + mInfoInc);
1388  if (ROBIN_HOOD_UNLIKELY(mInfo[idx] + mInfoInc > 0xFF)) {
1389  mMaxNumElementsAllowed = 0;
1390  }
1391  --idx;
1392  }
1393  }
1394 
1395  void shiftDown(size_t idx) noexcept(std::is_nothrow_move_assignable<Node>::value) {
1396  // until we find one that is either empty or has zero offset.
1397  // TODO(martinus) we don't need to move everything, just the last one for the same
1398  // bucket.
1399  mKeyVals[idx].destroy(*this);
1400 
1401  // until we find one that is either empty or has zero offset.
1402  while (mInfo[idx + 1] >= 2 * mInfoInc) {
1403  ROBIN_HOOD_COUNT(shiftDown)
1404  mInfo[idx] = static_cast<uint8_t>(mInfo[idx + 1] - mInfoInc);
1405  mKeyVals[idx] = std::move(mKeyVals[idx + 1]);
1406  ++idx;
1407  }
1408 
1409  mInfo[idx] = 0;
1410  // don't destroy, we've moved it
1411  // mKeyVals[idx].destroy(*this);
1412  mKeyVals[idx].~Node();
1413  }
1414 
1415  // copy of find(), except that it returns iterator instead of const_iterator.
1416  template <typename Other>
1417  ROBIN_HOOD(NODISCARD)
1418  size_t findIdx(Other const& key) const {
1419  size_t idx{};
1420  InfoType info{};
1421  keyToIdx(key, &idx, &info);
1422 
1423  do {
1424  // unrolling this twice gives a bit of a speedup. More unrolling did not help.
1425  if (info == mInfo[idx] &&
1426  ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) {
1427  return idx;
1428  }
1429  next(&info, &idx);
1430  if (info == mInfo[idx] &&
1431  ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) {
1432  return idx;
1433  }
1434  next(&info, &idx);
1435  } while (info <= mInfo[idx]);
1436 
1437  // nothing found!
1438  return mMask == 0 ? 0
1439  : static_cast<size_t>(std::distance(
1440  mKeyVals, reinterpret_cast_no_cast_align_warning<Node*>(mInfo)));
1441  }
1442 
1443  void cloneData(const Table& o) {
1444  Cloner<Table, IsFlat && ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(Node)>()(o, *this);
1445  }
1446 
1447  // inserts a keyval that is guaranteed to be new, e.g. when the hashmap is resized.
1448  // @return True on success, false if something went wrong
1449  void insert_move(Node&& keyval) {
1450  // we don't retry, fail if overflowing
1451  // don't need to check max num elements
1452  if (0 == mMaxNumElementsAllowed && !try_increase_info()) {
1453  throwOverflowError();
1454  }
1455 
1456  size_t idx{};
1457  InfoType info{};
1458  keyToIdx(keyval.getFirst(), &idx, &info);
1459 
1460  // skip forward. Use <= because we are certain that the element is not there.
1461  while (info <= mInfo[idx]) {
1462  idx = idx + 1;
1463  info += mInfoInc;
1464  }
1465 
1466  // key not found, so we are now exactly where we want to insert it.
1467  auto const insertion_idx = idx;
1468  auto const insertion_info = static_cast<uint8_t>(info);
1469  if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {
1470  mMaxNumElementsAllowed = 0;
1471  }
1472 
1473  // find an empty spot
1474  while (0 != mInfo[idx]) {
1475  next(&info, &idx);
1476  }
1477 
1478  auto& l = mKeyVals[insertion_idx];
1479  if (idx == insertion_idx) {
1480  ::new (static_cast<void*>(&l)) Node(std::move(keyval));
1481  } else {
1482  shiftUp(idx, insertion_idx);
1483  l = std::move(keyval);
1484  }
1485 
1486  // put at empty spot
1487  mInfo[insertion_idx] = insertion_info;
1488 
1489  ++mNumElements;
1490  }
1491 
1492 public:
1493  using iterator = Iter<false>;
1494  using const_iterator = Iter<true>;
1495 
1496  Table() noexcept(noexcept(Hash()) && noexcept(KeyEqual()))
1497  : WHash()
1498  , WKeyEqual() {
1499  ROBIN_HOOD_TRACE(this)
1500  }
1501 
1502  // Creates an empty hash map. Nothing is allocated yet, this happens at the first insert.
1503  // This tremendously speeds up ctor & dtor of a map that never receives an element. The
1504  // penalty is payed at the first insert, and not before. Lookup of this empty map works
1505  // because everybody points to DummyInfoByte::b. parameter bucket_count is dictated by the
1506  // standard, but we can ignore it.
1507  explicit Table(
1508  size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/, const Hash& h = Hash{},
1509  const KeyEqual& equal = KeyEqual{}) noexcept(noexcept(Hash(h)) && noexcept(KeyEqual(equal)))
1510  : WHash(h)
1511  , WKeyEqual(equal) {
1512  ROBIN_HOOD_TRACE(this)
1513  }
1514 
1515  template <typename Iter>
1516  Table(Iter first, Iter last, size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0,
1517  const Hash& h = Hash{}, const KeyEqual& equal = KeyEqual{})
1518  : WHash(h)
1519  , WKeyEqual(equal) {
1520  ROBIN_HOOD_TRACE(this)
1521  insert(first, last);
1522  }
1523 
1524  Table(std::initializer_list<value_type> initlist,
1525  size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0, const Hash& h = Hash{},
1526  const KeyEqual& equal = KeyEqual{})
1527  : WHash(h)
1528  , WKeyEqual(equal) {
1529  ROBIN_HOOD_TRACE(this)
1530  insert(initlist.begin(), initlist.end());
1531  }
1532 
1533  Table(Table&& o) noexcept
1534  : WHash(std::move(static_cast<WHash&>(o)))
1535  , WKeyEqual(std::move(static_cast<WKeyEqual&>(o)))
1536  , DataPool(std::move(static_cast<DataPool&>(o))) {
1537  ROBIN_HOOD_TRACE(this)
1538  if (o.mMask) {
1539  mHashMultiplier = std::move(o.mHashMultiplier);
1540  mKeyVals = std::move(o.mKeyVals);
1541  mInfo = std::move(o.mInfo);
1542  mNumElements = std::move(o.mNumElements);
1543  mMask = std::move(o.mMask);
1544  mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);
1545  mInfoInc = std::move(o.mInfoInc);
1546  mInfoHashShift = std::move(o.mInfoHashShift);
1547  // set other's mask to 0 so its destructor won't do anything
1548  o.init();
1549  }
1550  }
1551 
1552  Table& operator=(Table&& o) noexcept {
1553  ROBIN_HOOD_TRACE(this)
1554  if (&o != this) {
1555  if (o.mMask) {
1556  // only move stuff if the other map actually has some data
1557  destroy();
1558  mHashMultiplier = std::move(o.mHashMultiplier);
1559  mKeyVals = std::move(o.mKeyVals);
1560  mInfo = std::move(o.mInfo);
1561  mNumElements = std::move(o.mNumElements);
1562  mMask = std::move(o.mMask);
1563  mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);
1564  mInfoInc = std::move(o.mInfoInc);
1565  mInfoHashShift = std::move(o.mInfoHashShift);
1566  WHash::operator=(std::move(static_cast<WHash&>(o)));
1567  WKeyEqual::operator=(std::move(static_cast<WKeyEqual&>(o)));
1568  DataPool::operator=(std::move(static_cast<DataPool&>(o)));
1569 
1570  o.init();
1571 
1572  } else {
1573  // nothing in the other map => just clear us.
1574  clear();
1575  }
1576  }
1577  return *this;
1578  }
1579 
1580  Table(const Table& o)
1581  : WHash(static_cast<const WHash&>(o))
1582  , WKeyEqual(static_cast<const WKeyEqual&>(o))
1583  , DataPool(static_cast<const DataPool&>(o)) {
1584  ROBIN_HOOD_TRACE(this)
1585  if (!o.empty()) {
1586  // not empty: create an exact copy. it is also possible to just iterate through all
1587  // elements and insert them, but copying is probably faster.
1588 
1589  auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);
1590  auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
1591 
1592  ROBIN_HOOD_LOG("std::malloc " << numBytesTotal << " = calcNumBytesTotal("
1593  << numElementsWithBuffer << ")")
1594  mHashMultiplier = o.mHashMultiplier;
1595  mKeyVals = static_cast<Node*>(
1596  detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
1597  // no need for calloc because clonData does memcpy
1598  mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);
1599  mNumElements = o.mNumElements;
1600  mMask = o.mMask;
1601  mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;
1602  mInfoInc = o.mInfoInc;
1603  mInfoHashShift = o.mInfoHashShift;
1604  cloneData(o);
1605  }
1606  }
1607 
1608  // Creates a copy of the given map. Copy constructor of each entry is used.
1609  // Not sure why clang-tidy thinks this doesn't handle self assignment, it does
1610  // NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp)
1611  Table& operator=(Table const& o) {
1612  ROBIN_HOOD_TRACE(this)
1613  if (&o == this) {
1614  // prevent assigning of itself
1615  return *this;
1616  }
1617 
1618  // we keep using the old allocator and not assign the new one, because we want to keep
1619  // the memory available. when it is the same size.
1620  if (o.empty()) {
1621  if (0 == mMask) {
1622  // nothing to do, we are empty too
1623  return *this;
1624  }
1625 
1626  // not empty: destroy what we have there
1627  // clear also resets mInfo to 0, that's sometimes not necessary.
1628  destroy();
1629  init();
1630  WHash::operator=(static_cast<const WHash&>(o));
1631  WKeyEqual::operator=(static_cast<const WKeyEqual&>(o));
1632  DataPool::operator=(static_cast<DataPool const&>(o));
1633 
1634  return *this;
1635  }
1636 
1637  // clean up old stuff
1638  Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*this);
1639 
1640  if (mMask != o.mMask) {
1641  // no luck: we don't have the same array size allocated, so we need to realloc.
1642  if (0 != mMask) {
1643  // only deallocate if we actually have data!
1644  ROBIN_HOOD_LOG("std::free")
1645  std::free(mKeyVals);
1646  }
1647 
1648  auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);
1649  auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
1650  ROBIN_HOOD_LOG("std::malloc " << numBytesTotal << " = calcNumBytesTotal("
1651  << numElementsWithBuffer << ")")
1652  mKeyVals = static_cast<Node*>(
1653  detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
1654 
1655  // no need for calloc here because cloneData performs a memcpy.
1656  mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);
1657  // sentinel is set in cloneData
1658  }
1659  WHash::operator=(static_cast<const WHash&>(o));
1660  WKeyEqual::operator=(static_cast<const WKeyEqual&>(o));
1661  DataPool::operator=(static_cast<DataPool const&>(o));
1662  mHashMultiplier = o.mHashMultiplier;
1663  mNumElements = o.mNumElements;
1664  mMask = o.mMask;
1665  mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;
1666  mInfoInc = o.mInfoInc;
1667  mInfoHashShift = o.mInfoHashShift;
1668  cloneData(o);
1669 
1670  return *this;
1671  }
1672 
1673  // Swaps everything between the two maps.
1674  void swap(Table& o) {
1675  ROBIN_HOOD_TRACE(this)
1676  using std::swap;
1677  swap(o, *this);
1678  }
1679 
1680  // Clears all data, without resizing.
1681  void clear() {
1682  ROBIN_HOOD_TRACE(this)
1683  if (empty()) {
1684  // don't do anything! also important because we don't want to write to
1685  // DummyInfoByte::b, even though we would just write 0 to it.
1686  return;
1687  }
1688 
1689  Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*this);
1690 
1691  auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
1692  // clear everything, then set the sentinel again
1693  uint8_t const z = 0;
1694  std::fill(mInfo, mInfo + calcNumBytesInfo(numElementsWithBuffer), z);
1695  mInfo[numElementsWithBuffer] = 1;
1696 
1697  mInfoInc = InitialInfoInc;
1698  mInfoHashShift = InitialInfoHashShift;
1699  }
1700 
1701  // Destroys the map and all it's contents.
1703  ROBIN_HOOD_TRACE(this)
1704  destroy();
1705  }
1706 
1707  // Checks if both tables contain the same entries. Order is irrelevant.
1708  bool operator==(const Table& other) const {
1709  ROBIN_HOOD_TRACE(this)
1710  if (other.size() != size()) {
1711  return false;
1712  }
1713  for (auto const& otherEntry : other) {
1714  if (!has(otherEntry)) {
1715  return false;
1716  }
1717  }
1718 
1719  return true;
1720  }
1721 
1722  bool operator!=(const Table& other) const {
1723  ROBIN_HOOD_TRACE(this)
1724  return !operator==(other);
1725  }
1726 
1727  template <typename Q = mapped_type>
1728  typename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](const key_type& key) {
1729  ROBIN_HOOD_TRACE(this)
1730  auto idxAndState = insertKeyPrepareEmptySpot(key);
1731  switch (idxAndState.second) {
1732  case InsertionState::key_found:
1733  break;
1734 
1735  case InsertionState::new_node:
1736  ::new (static_cast<void*>(&mKeyVals[idxAndState.first]))
1737  Node(*this, std::piecewise_construct, std::forward_as_tuple(key),
1738  std::forward_as_tuple());
1739  break;
1740 
1741  case InsertionState::overwrite_node:
1742  mKeyVals[idxAndState.first] = Node(*this, std::piecewise_construct,
1743  std::forward_as_tuple(key), std::forward_as_tuple());
1744  break;
1745 
1746  case InsertionState::overflow_error:
1747  throwOverflowError();
1748  }
1749 
1750  return mKeyVals[idxAndState.first].getSecond();
1751  }
1752 
1753  template <typename Q = mapped_type>
1754  typename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](key_type&& key) {
1755  ROBIN_HOOD_TRACE(this)
1756  auto idxAndState = insertKeyPrepareEmptySpot(key);
1757  switch (idxAndState.second) {
1758  case InsertionState::key_found:
1759  break;
1760 
1761  case InsertionState::new_node:
1762  ::new (static_cast<void*>(&mKeyVals[idxAndState.first]))
1763  Node(*this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),
1764  std::forward_as_tuple());
1765  break;
1766 
1767  case InsertionState::overwrite_node:
1768  mKeyVals[idxAndState.first] =
1769  Node(*this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),
1770  std::forward_as_tuple());
1771  break;
1772 
1773  case InsertionState::overflow_error:
1774  throwOverflowError();
1775  }
1776 
1777  return mKeyVals[idxAndState.first].getSecond();
1778  }
1779 
1780  template <typename Iter>
1781  void insert(Iter first, Iter last) {
1782  for (; first != last; ++first) {
1783  // value_type ctor needed because this might be called with std::pair's
1784  insert(value_type(*first));
1785  }
1786  }
1787 
1788  void insert(std::initializer_list<value_type> ilist) {
1789  for (auto&& vt : ilist) {
1790  insert(std::move(vt));
1791  }
1792  }
1793 
1794  template <typename... Args>
1795  std::pair<iterator, bool> emplace(Args&&... args) {
1796  ROBIN_HOOD_TRACE(this)
1797  Node n{*this, std::forward<Args>(args)...};
1798  auto idxAndState = insertKeyPrepareEmptySpot(getFirstConst(n));
1799  switch (idxAndState.second) {
1800  case InsertionState::key_found:
1801  n.destroy(*this);
1802  break;
1803 
1804  case InsertionState::new_node:
1805  ::new (static_cast<void*>(&mKeyVals[idxAndState.first])) Node(*this, std::move(n));
1806  break;
1807 
1808  case InsertionState::overwrite_node:
1809  mKeyVals[idxAndState.first] = std::move(n);
1810  break;
1811 
1812  case InsertionState::overflow_error:
1813  n.destroy(*this);
1814  throwOverflowError();
1815  break;
1816  }
1817 
1818  return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
1819  InsertionState::key_found != idxAndState.second);
1820  }
1821 
1822  template <typename... Args>
1823  std::pair<iterator, bool> try_emplace(const key_type& key, Args&&... args) {
1824  return try_emplace_impl(key, std::forward<Args>(args)...);
1825  }
1826 
1827  template <typename... Args>
1828  std::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args) {
1829  return try_emplace_impl(std::move(key), std::forward<Args>(args)...);
1830  }
1831 
1832  template <typename... Args>
1833  std::pair<iterator, bool> try_emplace(const_iterator hint, const key_type& key,
1834  Args&&... args) {
1835  (void)hint;
1836  return try_emplace_impl(key, std::forward<Args>(args)...);
1837  }
1838 
1839  template <typename... Args>
1840  std::pair<iterator, bool> try_emplace(const_iterator hint, key_type&& key, Args&&... args) {
1841  (void)hint;
1842  return try_emplace_impl(std::move(key), std::forward<Args>(args)...);
1843  }
1844 
1845  template <typename Mapped>
1846  std::pair<iterator, bool> insert_or_assign(const key_type& key, Mapped&& obj) {
1847  return insertOrAssignImpl(key, std::forward<Mapped>(obj));
1848  }
1849 
1850  template <typename Mapped>
1851  std::pair<iterator, bool> insert_or_assign(key_type&& key, Mapped&& obj) {
1852  return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj));
1853  }
1854 
1855  template <typename Mapped>
1856  std::pair<iterator, bool> insert_or_assign(const_iterator hint, const key_type& key,
1857  Mapped&& obj) {
1858  (void)hint;
1859  return insertOrAssignImpl(key, std::forward<Mapped>(obj));
1860  }
1861 
1862  template <typename Mapped>
1863  std::pair<iterator, bool> insert_or_assign(const_iterator hint, key_type&& key, Mapped&& obj) {
1864  (void)hint;
1865  return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj));
1866  }
1867 
1868  std::pair<iterator, bool> insert(const value_type& keyval) {
1869  ROBIN_HOOD_TRACE(this)
1870  return emplace(keyval);
1871  }
1872 
1873  std::pair<iterator, bool> insert(value_type&& keyval) {
1874  return emplace(std::move(keyval));
1875  }
1876 
1877  // Returns 1 if key is found, 0 otherwise.
1878  size_t count(const key_type& key) const { // NOLINT(modernize-use-nodiscard)
1879  ROBIN_HOOD_TRACE(this)
1880  auto kv = mKeyVals + findIdx(key);
1881  if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1882  return 1;
1883  }
1884  return 0;
1885  }
1886 
1887  template <typename OtherKey, typename Self_ = Self>
1888  // NOLINTNEXTLINE(modernize-use-nodiscard)
1889  typename std::enable_if<Self_::is_transparent, size_t>::type count(const OtherKey& key) const {
1890  ROBIN_HOOD_TRACE(this)
1891  auto kv = mKeyVals + findIdx(key);
1892  if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1893  return 1;
1894  }
1895  return 0;
1896  }
1897 
1898  bool contains(const key_type& key) const { // NOLINT(modernize-use-nodiscard)
1899  return 1U == count(key);
1900  }
1901 
1902  template <typename OtherKey, typename Self_ = Self>
1903  // NOLINTNEXTLINE(modernize-use-nodiscard)
1904  typename std::enable_if<Self_::is_transparent, bool>::type contains(const OtherKey& key) const {
1905  return 1U == count(key);
1906  }
1907 
1908  // Returns a reference to the value found for key.
1909  // Throws std::out_of_range if element cannot be found
1910  template <typename Q = mapped_type>
1911  // NOLINTNEXTLINE(modernize-use-nodiscard)
1912  typename std::enable_if<!std::is_void<Q>::value, Q&>::type at(key_type const& key) {
1913  ROBIN_HOOD_TRACE(this)
1914  auto kv = mKeyVals + findIdx(key);
1915  if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1916  doThrow<std::out_of_range>("key not found");
1917  }
1918  return kv->getSecond();
1919  }
1920 
1921  // Returns a reference to the value found for key.
1922  // Throws std::out_of_range if element cannot be found
1923  template <typename Q = mapped_type>
1924  // NOLINTNEXTLINE(modernize-use-nodiscard)
1925  typename std::enable_if<!std::is_void<Q>::value, Q const&>::type at(key_type const& key) const {
1926  ROBIN_HOOD_TRACE(this)
1927  auto kv = mKeyVals + findIdx(key);
1928  if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1929  doThrow<std::out_of_range>("key not found");
1930  }
1931  return kv->getSecond();
1932  }
1933 
1934  const_iterator find(const key_type& key) const { // NOLINT(modernize-use-nodiscard)
1935  ROBIN_HOOD_TRACE(this)
1936  const size_t idx = findIdx(key);
1937  return const_iterator{mKeyVals + idx, mInfo + idx};
1938  }
1939 
1940  template <typename OtherKey>
1941  const_iterator find(const OtherKey& key, is_transparent_tag /*unused*/) const {
1942  ROBIN_HOOD_TRACE(this)
1943  const size_t idx = findIdx(key);
1944  return const_iterator{mKeyVals + idx, mInfo + idx};
1945  }
1946 
1947  template <typename OtherKey, typename Self_ = Self>
1948  typename std::enable_if<Self_::is_transparent, // NOLINT(modernize-use-nodiscard)
1949  const_iterator>::type // NOLINT(modernize-use-nodiscard)
1950  find(const OtherKey& key) const { // NOLINT(modernize-use-nodiscard)
1951  ROBIN_HOOD_TRACE(this)
1952  const size_t idx = findIdx(key);
1953  return const_iterator{mKeyVals + idx, mInfo + idx};
1954  }
1955 
1956  iterator find(const key_type& key) {
1957  ROBIN_HOOD_TRACE(this)
1958  const size_t idx = findIdx(key);
1959  return iterator{mKeyVals + idx, mInfo + idx};
1960  }
1961 
1962  template <typename OtherKey>
1963  iterator find(const OtherKey& key, is_transparent_tag /*unused*/) {
1964  ROBIN_HOOD_TRACE(this)
1965  const size_t idx = findIdx(key);
1966  return iterator{mKeyVals + idx, mInfo + idx};
1967  }
1968 
1969  template <typename OtherKey, typename Self_ = Self>
1970  typename std::enable_if<Self_::is_transparent, iterator>::type find(const OtherKey& key) {
1971  ROBIN_HOOD_TRACE(this)
1972  const size_t idx = findIdx(key);
1973  return iterator{mKeyVals + idx, mInfo + idx};
1974  }
1975 
1977  ROBIN_HOOD_TRACE(this)
1978  if (empty()) {
1979  return end();
1980  }
1981  return iterator(mKeyVals, mInfo, fast_forward_tag{});
1982  }
1983  const_iterator begin() const { // NOLINT(modernize-use-nodiscard)
1984  ROBIN_HOOD_TRACE(this)
1985  return cbegin();
1986  }
1987  const_iterator cbegin() const { // NOLINT(modernize-use-nodiscard)
1988  ROBIN_HOOD_TRACE(this)
1989  if (empty()) {
1990  return cend();
1991  }
1992  return const_iterator(mKeyVals, mInfo, fast_forward_tag{});
1993  }
1994 
1996  ROBIN_HOOD_TRACE(this)
1997  // no need to supply valid info pointer: end() must not be dereferenced, and only node
1998  // pointer is compared.
1999  return iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo), nullptr};
2000  }
2001  const_iterator end() const { // NOLINT(modernize-use-nodiscard)
2002  ROBIN_HOOD_TRACE(this)
2003  return cend();
2004  }
2005  const_iterator cend() const { // NOLINT(modernize-use-nodiscard)
2006  ROBIN_HOOD_TRACE(this)
2007  return const_iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo), nullptr};
2008  }
2009 
2011  ROBIN_HOOD_TRACE(this)
2012  // its safe to perform const cast here
2013  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
2014  return erase(iterator{const_cast<Node*>(pos.mKeyVals), const_cast<uint8_t*>(pos.mInfo)});
2015  }
2016 
2017  // Erases element at pos, returns iterator to the next element.
2019  ROBIN_HOOD_TRACE(this)
2020  // we assume that pos always points to a valid entry, and not end().
2021  auto const idx = static_cast<size_t>(pos.mKeyVals - mKeyVals);
2022 
2023  shiftDown(idx);
2024  --mNumElements;
2025 
2026  if (*pos.mInfo) {
2027  // we've backward shifted, return this again
2028  return pos;
2029  }
2030 
2031  // no backward shift, return next element
2032  return ++pos;
2033  }
2034 
2035  size_t erase(const key_type& key) {
2036  ROBIN_HOOD_TRACE(this)
2037  size_t idx{};
2038  InfoType info{};
2039  keyToIdx(key, &idx, &info);
2040 
2041  // check while info matches with the source idx
2042  do {
2043  if (info == mInfo[idx] && WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
2044  shiftDown(idx);
2045  --mNumElements;
2046  return 1;
2047  }
2048  next(&info, &idx);
2049  } while (info <= mInfo[idx]);
2050 
2051  // nothing found to delete
2052  return 0;
2053  }
2054 
2055  // reserves space for the specified number of elements. Makes sure the old data fits.
2056  // exactly the same as reserve(c).
2057  void rehash(size_t c) {
2058  // forces a reserve
2059  reserve(c, true);
2060  }
2061 
2062  // reserves space for the specified number of elements. Makes sure the old data fits.
2063  // Exactly the same as rehash(c). Use rehash(0) to shrink to fit.
2064  void reserve(size_t c) {
2065  // reserve, but don't force rehash
2066  reserve(c, false);
2067  }
2068 
2069  // If possible reallocates the map to a smaller one. This frees the underlying table.
2070  // Does not do anything if load_factor is too large for decreasing the table's size.
2071  void compact() {
2072  ROBIN_HOOD_TRACE(this)
2073  auto newSize = InitialNumElements;
2074  while (calcMaxNumElementsAllowed(newSize) < mNumElements && newSize != 0) {
2075  newSize *= 2;
2076  }
2077  if (ROBIN_HOOD_UNLIKELY(newSize == 0)) {
2078  throwOverflowError();
2079  }
2080 
2081  ROBIN_HOOD_LOG("newSize > mMask + 1: " << newSize << " > " << mMask << " + 1")
2082 
2083  // only actually do anything when the new size is bigger than the old one. This prevents to
2084  // continuously allocate for each reserve() call.
2085  if (newSize < mMask + 1) {
2086  rehashPowerOfTwo(newSize, true);
2087  }
2088  }
2089 
2090  size_type size() const noexcept { // NOLINT(modernize-use-nodiscard)
2091  ROBIN_HOOD_TRACE(this)
2092  return mNumElements;
2093  }
2094 
2095  size_type max_size() const noexcept { // NOLINT(modernize-use-nodiscard)
2096  ROBIN_HOOD_TRACE(this)
2097  return static_cast<size_type>(-1);
2098  }
2099 
2100  ROBIN_HOOD(NODISCARD) bool empty() const noexcept {
2101  ROBIN_HOOD_TRACE(this)
2102  return 0 == mNumElements;
2103  }
2104 
2105  float max_load_factor() const noexcept { // NOLINT(modernize-use-nodiscard)
2106  ROBIN_HOOD_TRACE(this)
2107  return MaxLoadFactor100 / 100.0F;
2108  }
2109 
2110  // Average number of elements per bucket. Since we allow only 1 per bucket
2111  float load_factor() const noexcept { // NOLINT(modernize-use-nodiscard)
2112  ROBIN_HOOD_TRACE(this)
2113  return static_cast<float>(size()) / static_cast<float>(mMask + 1);
2114  }
2115 
2116  ROBIN_HOOD(NODISCARD) size_t mask() const noexcept {
2117  ROBIN_HOOD_TRACE(this)
2118  return mMask;
2119  }
2120 
2121  ROBIN_HOOD(NODISCARD) size_t calcMaxNumElementsAllowed(size_t maxElements) const noexcept {
2122  if (ROBIN_HOOD_LIKELY(maxElements <= (std::numeric_limits<size_t>::max)() / 100)) {
2123  return maxElements * MaxLoadFactor100 / 100;
2124  }
2125 
2126  // we might be a bit inprecise, but since maxElements is quite large that doesn't matter
2127  return (maxElements / 100) * MaxLoadFactor100;
2128  }
2129 
2130  ROBIN_HOOD(NODISCARD) size_t calcNumBytesInfo(size_t numElements) const noexcept {
2131  // we add a uint64_t, which houses the sentinel (first byte) and padding so we can load
2132  // 64bit types.
2133  return numElements + sizeof(uint64_t);
2134  }
2135 
2136  ROBIN_HOOD(NODISCARD)
2137  size_t calcNumElementsWithBuffer(size_t numElements) const noexcept {
2138  auto maxNumElementsAllowed = calcMaxNumElementsAllowed(numElements);
2139  return numElements + (std::min)(maxNumElementsAllowed, (static_cast<size_t>(0xFF)));
2140  }
2141 
2142  // calculation only allowed for 2^n values
2143  ROBIN_HOOD(NODISCARD) size_t calcNumBytesTotal(size_t numElements) const {
2144 #if ROBIN_HOOD(BITNESS) == 64
2145  return numElements * sizeof(Node) + calcNumBytesInfo(numElements);
2146 #else
2147  // make sure we're doing 64bit operations, so we are at least safe against 32bit overflows.
2148  auto const ne = static_cast<uint64_t>(numElements);
2149  auto const s = static_cast<uint64_t>(sizeof(Node));
2150  auto const infos = static_cast<uint64_t>(calcNumBytesInfo(numElements));
2151 
2152  auto const total64 = ne * s + infos;
2153  auto const total = static_cast<size_t>(total64);
2154 
2155  if (ROBIN_HOOD_UNLIKELY(static_cast<uint64_t>(total) != total64)) {
2156  throwOverflowError();
2157  }
2158  return total;
2159 #endif
2160  }
2161 
2162 private:
2163  template <typename Q = mapped_type>
2164  ROBIN_HOOD(NODISCARD)
2165  typename std::enable_if<!std::is_void<Q>::value, bool>::type has(const value_type& e) const {
2166  ROBIN_HOOD_TRACE(this)
2167  auto it = find(e.first);
2168  return it != end() && it->second == e.second;
2169  }
2170 
2171  template <typename Q = mapped_type>
2172  ROBIN_HOOD(NODISCARD)
2173  typename std::enable_if<std::is_void<Q>::value, bool>::type has(const value_type& e) const {
2174  ROBIN_HOOD_TRACE(this)
2175  return find(e) != end();
2176  }
2177 
2178  void reserve(size_t c, bool forceRehash) {
2179  ROBIN_HOOD_TRACE(this)
2180  auto const minElementsAllowed = (std::max)(c, mNumElements);
2181  auto newSize = InitialNumElements;
2182  while (calcMaxNumElementsAllowed(newSize) < minElementsAllowed && newSize != 0) {
2183  newSize *= 2;
2184  }
2185  if (ROBIN_HOOD_UNLIKELY(newSize == 0)) {
2186  throwOverflowError();
2187  }
2188 
2189  ROBIN_HOOD_LOG("newSize > mMask + 1: " << newSize << " > " << mMask << " + 1")
2190 
2191  // only actually do anything when the new size is bigger than the old one. This prevents to
2192  // continuously allocate for each reserve() call.
2193  if (forceRehash || newSize > mMask + 1) {
2194  rehashPowerOfTwo(newSize, false);
2195  }
2196  }
2197 
2198  // reserves space for at least the specified number of elements.
2199  // only works if numBuckets if power of two
2200  // True on success, false otherwise
2201  void rehashPowerOfTwo(size_t numBuckets, bool forceFree) {
2202  ROBIN_HOOD_TRACE(this)
2203 
2204  Node* const oldKeyVals = mKeyVals;
2205  uint8_t const* const oldInfo = mInfo;
2206 
2207  const size_t oldMaxElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
2208 
2209  // resize operation: move stuff
2210  initData(numBuckets);
2211  if (oldMaxElementsWithBuffer > 1) {
2212  for (size_t i = 0; i < oldMaxElementsWithBuffer; ++i) {
2213  if (oldInfo[i] != 0) {
2214  // might throw an exception, which is really bad since we are in the middle of
2215  // moving stuff.
2216  insert_move(std::move(oldKeyVals[i]));
2217  // destroy the node but DON'T destroy the data.
2218  oldKeyVals[i].~Node();
2219  }
2220  }
2221 
2222  // this check is not necessary as it's guarded by the previous if, but it helps
2223  // silence g++'s overeager "attempt to free a non-heap object 'map'
2224  // [-Werror=free-nonheap-object]" warning.
2225  if (oldKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
2226  // don't destroy old data: put it into the pool instead
2227  if (forceFree) {
2228  std::free(oldKeyVals);
2229  } else {
2230  DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer));
2231  }
2232  }
2233  }
2234  }
2235 
2236  ROBIN_HOOD(NOINLINE) void throwOverflowError() const {
2237 #if ROBIN_HOOD(HAS_EXCEPTIONS)
2238  throw std::overflow_error("robin_hood::map overflow");
2239 #else
2240  abort();
2241 #endif
2242  }
2243 
2244  template <typename OtherKey, typename... Args>
2245  std::pair<iterator, bool> try_emplace_impl(OtherKey&& key, Args&&... args) {
2246  ROBIN_HOOD_TRACE(this)
2247  auto idxAndState = insertKeyPrepareEmptySpot(key);
2248  switch (idxAndState.second) {
2249  case InsertionState::key_found:
2250  break;
2251 
2252  case InsertionState::new_node:
2253  ::new (static_cast<void*>(&mKeyVals[idxAndState.first])) Node(
2254  *this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
2255  std::forward_as_tuple(std::forward<Args>(args)...));
2256  break;
2257 
2258  case InsertionState::overwrite_node:
2259  mKeyVals[idxAndState.first] = Node(*this, std::piecewise_construct,
2260  std::forward_as_tuple(std::forward<OtherKey>(key)),
2261  std::forward_as_tuple(std::forward<Args>(args)...));
2262  break;
2263 
2264  case InsertionState::overflow_error:
2265  throwOverflowError();
2266  break;
2267  }
2268 
2269  return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
2270  InsertionState::key_found != idxAndState.second);
2271  }
2272 
2273  template <typename OtherKey, typename Mapped>
2274  std::pair<iterator, bool> insertOrAssignImpl(OtherKey&& key, Mapped&& obj) {
2275  ROBIN_HOOD_TRACE(this)
2276  auto idxAndState = insertKeyPrepareEmptySpot(key);
2277  switch (idxAndState.second) {
2278  case InsertionState::key_found:
2279  mKeyVals[idxAndState.first].getSecond() = std::forward<Mapped>(obj);
2280  break;
2281 
2282  case InsertionState::new_node:
2283  ::new (static_cast<void*>(&mKeyVals[idxAndState.first])) Node(
2284  *this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
2285  std::forward_as_tuple(std::forward<Mapped>(obj)));
2286  break;
2287 
2288  case InsertionState::overwrite_node:
2289  mKeyVals[idxAndState.first] = Node(*this, std::piecewise_construct,
2290  std::forward_as_tuple(std::forward<OtherKey>(key)),
2291  std::forward_as_tuple(std::forward<Mapped>(obj)));
2292  break;
2293 
2294  case InsertionState::overflow_error:
2295  throwOverflowError();
2296  break;
2297  }
2298 
2299  return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
2300  InsertionState::key_found != idxAndState.second);
2301  }
2302 
2303  void initData(size_t max_elements) {
2304  mNumElements = 0;
2305  mMask = max_elements - 1;
2306  mMaxNumElementsAllowed = calcMaxNumElementsAllowed(max_elements);
2307 
2308  auto const numElementsWithBuffer = calcNumElementsWithBuffer(max_elements);
2309 
2310  // calloc also zeroes everything
2311  auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
2312  ROBIN_HOOD_LOG("std::calloc " << numBytesTotal << " = calcNumBytesTotal("
2313  << numElementsWithBuffer << ")")
2314  mKeyVals = reinterpret_cast<Node*>(
2315  detail::assertNotNull<std::bad_alloc>(std::calloc(1, numBytesTotal)));
2316  mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);
2317 
2318  // set sentinel
2319  mInfo[numElementsWithBuffer] = 1;
2320 
2321  mInfoInc = InitialInfoInc;
2322  mInfoHashShift = InitialInfoHashShift;
2323  }
2324 
2325  enum class InsertionState { overflow_error, key_found, new_node, overwrite_node };
2326 
2327  // Finds key, and if not already present prepares a spot where to pot the key & value.
2328  // This potentially shifts nodes out of the way, updates mInfo and number of inserted
2329  // elements, so the only operation left to do is create/assign a new node at that spot.
2330  template <typename OtherKey>
2331  std::pair<size_t, InsertionState> insertKeyPrepareEmptySpot(OtherKey&& key) {
2332  for (int i = 0; i < 256; ++i) {
2333  size_t idx{};
2334  InfoType info{};
2335  keyToIdx(key, &idx, &info);
2336  nextWhileLess(&info, &idx);
2337 
2338  // while we potentially have a match
2339  while (info == mInfo[idx]) {
2340  if (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
2341  // key already exists, do NOT insert.
2342  // see http://en.cppreference.com/w/cpp/container/unordered_map/insert
2343  return std::make_pair(idx, InsertionState::key_found);
2344  }
2345  next(&info, &idx);
2346  }
2347 
2348  // unlikely that this evaluates to true
2349  if (ROBIN_HOOD_UNLIKELY(mNumElements >= mMaxNumElementsAllowed)) {
2350  if (!increase_size()) {
2351  return std::make_pair(size_t(0), InsertionState::overflow_error);
2352  }
2353  continue;
2354  }
2355 
2356  // key not found, so we are now exactly where we want to insert it.
2357  auto const insertion_idx = idx;
2358  auto const insertion_info = info;
2359  if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {
2360  mMaxNumElementsAllowed = 0;
2361  }
2362 
2363  // find an empty spot
2364  while (0 != mInfo[idx]) {
2365  next(&info, &idx);
2366  }
2367 
2368  if (idx != insertion_idx) {
2369  shiftUp(idx, insertion_idx);
2370  }
2371  // put at empty spot
2372  mInfo[insertion_idx] = static_cast<uint8_t>(insertion_info);
2373  ++mNumElements;
2374  return std::make_pair(insertion_idx, idx == insertion_idx
2375  ? InsertionState::new_node
2376  : InsertionState::overwrite_node);
2377  }
2378 
2379  // enough attempts failed, so finally give up.
2380  return std::make_pair(size_t(0), InsertionState::overflow_error);
2381  }
2382 
2383  bool try_increase_info() {
2384  ROBIN_HOOD_LOG("mInfoInc=" << mInfoInc << ", numElements=" << mNumElements
2385  << ", maxNumElementsAllowed="
2386  << calcMaxNumElementsAllowed(mMask + 1))
2387  if (mInfoInc <= 2) {
2388  // need to be > 2 so that shift works (otherwise undefined behavior!)
2389  return false;
2390  }
2391  // we got space left, try to make info smaller
2392  mInfoInc = static_cast<uint8_t>(mInfoInc >> 1U);
2393 
2394  // remove one bit of the hash, leaving more space for the distance info.
2395  // This is extremely fast because we can operate on 8 bytes at once.
2396  ++mInfoHashShift;
2397  auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
2398 
2399  for (size_t i = 0; i < numElementsWithBuffer; i += 8) {
2400  auto val = unaligned_load<uint64_t>(mInfo + i);
2401  val = (val >> 1U) & UINT64_C(0x7f7f7f7f7f7f7f7f);
2402  std::memcpy(mInfo + i, &val, sizeof(val));
2403  }
2404  // update sentinel, which might have been cleared out!
2405  mInfo[numElementsWithBuffer] = 1;
2406 
2407  mMaxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
2408  return true;
2409  }
2410 
2411  // True if resize was possible, false otherwise
2412  bool increase_size() {
2413  // nothing allocated yet? just allocate InitialNumElements
2414  if (0 == mMask) {
2415  initData(InitialNumElements);
2416  return true;
2417  }
2418 
2419  auto const maxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
2420  if (mNumElements < maxNumElementsAllowed && try_increase_info()) {
2421  return true;
2422  }
2423 
2424  ROBIN_HOOD_LOG("mNumElements=" << mNumElements << ", maxNumElementsAllowed="
2425  << maxNumElementsAllowed << ", load="
2426  << (static_cast<double>(mNumElements) * 100.0 /
2427  (static_cast<double>(mMask) + 1)))
2428 
2429  nextHashMultiplier();
2430  if (mNumElements * 2 < calcMaxNumElementsAllowed(mMask + 1)) {
2431  // we have to resize, even though there would still be plenty of space left!
2432  // Try to rehash instead. Delete freed memory so we don't steadyily increase mem in case
2433  // we have to rehash a few times
2434  rehashPowerOfTwo(mMask + 1, true);
2435  } else {
2436  // Each resize use a different hash so we don't so easily overflow.
2437  // Make sure we only have odd numbers, so that the multiplication is reversible!
2438  rehashPowerOfTwo((mMask + 1) * 2, false);
2439  }
2440  return true;
2441  }
2442 
2443  void nextHashMultiplier() {
2444  // adding an *even* number, so that the multiplier will always stay odd. This is necessary
2445  // so that the hash stays a mixing function (and thus doesn't have any information loss).
2446  mHashMultiplier += UINT64_C(0xc4ceb9fe1a85ec54);
2447  }
2448 
2449  void destroy() {
2450  if (0 == mMask) {
2451  // don't deallocate!
2452  return;
2453  }
2454 
2455  Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}
2456  .nodesDoNotDeallocate(*this);
2457 
2458  // This protection against not deleting mMask shouldn't be needed as it's sufficiently
2459  // protected with the 0==mMask check, but I have this anyways because g++ 7 otherwise
2460  // reports a compile error: attempt to free a non-heap object 'fm'
2461  // [-Werror=free-nonheap-object]
2462  if (mKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
2463  ROBIN_HOOD_LOG("std::free")
2464  std::free(mKeyVals);
2465  }
2466  }
2467 
2468  void init() noexcept {
2469  mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);
2470  mInfo = reinterpret_cast<uint8_t*>(&mMask);
2471  mNumElements = 0;
2472  mMask = 0;
2473  mMaxNumElementsAllowed = 0;
2474  mInfoInc = InitialInfoInc;
2475  mInfoHashShift = InitialInfoHashShift;
2476  }
2477 
2478  // members are sorted so no padding occurs
2479  uint64_t mHashMultiplier = UINT64_C(0xc4ceb9fe1a85ec53); // 8 byte 8
2480  Node* mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask); // 8 byte 16
2481  uint8_t* mInfo = reinterpret_cast<uint8_t*>(&mMask); // 8 byte 24
2482  size_t mNumElements = 0; // 8 byte 32
2483  size_t mMask = 0; // 8 byte 40
2484  size_t mMaxNumElementsAllowed = 0; // 8 byte 48
2485  InfoType mInfoInc = InitialInfoInc; // 4 byte 52
2486  InfoType mInfoHashShift = InitialInfoHashShift; // 4 byte 56
2487  // 16 byte 56 if NodeAllocator
2488 };
2489 
2490 } // namespace detail
2491 
2492 // map
2493 
2494 template <typename Key, typename T, typename Hash = hash<Key>,
2495  typename KeyEqual = std::equal_to<Key>, size_t MaxLoadFactor100 = 80>
2497 
2498 template <typename Key, typename T, typename Hash = hash<Key>,
2499  typename KeyEqual = std::equal_to<Key>, size_t MaxLoadFactor100 = 80>
2501 
2502 template <typename Key, typename T, typename Hash = hash<Key>,
2503  typename KeyEqual = std::equal_to<Key>, size_t MaxLoadFactor100 = 80>
2504 using unordered_map =
2505  detail::Table<sizeof(robin_hood::pair<Key, T>) <= sizeof(size_t) * 6 &&
2506  std::is_nothrow_move_constructible<robin_hood::pair<Key, T>>::value &&
2507  std::is_nothrow_move_assignable<robin_hood::pair<Key, T>>::value,
2508  MaxLoadFactor100, Key, T, Hash, KeyEqual>;
2509 
2510 // set
2511 
2512 template <typename Key, typename Hash = hash<Key>, typename KeyEqual = std::equal_to<Key>,
2513  size_t MaxLoadFactor100 = 80>
2515 
2516 template <typename Key, typename Hash = hash<Key>, typename KeyEqual = std::equal_to<Key>,
2517  size_t MaxLoadFactor100 = 80>
2519 
2520 template <typename Key, typename Hash = hash<Key>, typename KeyEqual = std::equal_to<Key>,
2521  size_t MaxLoadFactor100 = 80>
2522 using unordered_set = detail::Table<sizeof(Key) <= sizeof(size_t) * 6 &&
2523  std::is_nothrow_move_constructible<Key>::value &&
2524  std::is_nothrow_move_assignable<Key>::value,
2525  MaxLoadFactor100, Key, void, Hash, KeyEqual>;
2526 
2527 } // namespace robin_hood
2528 
2529 #endif
robin_hood::detail::swappable::nothrow::value
static const bool value
Definition: robin_hood.h:563
robin_hood::detail::Table::cend
const_iterator cend() const
Definition: robin_hood.h:2005
robin_hood::detail::Table::ROBIN_HOOD
ROBIN_HOOD(NODISCARD) size_t calcNumBytesTotal(size_t numElements) const
Definition: robin_hood.h:2143
robin_hood::detail::Table::operator!=
bool operator!=(const Table &other) const
Definition: robin_hood.h:1722
ROBIN_HOOD_LIKELY
#define ROBIN_HOOD_LIKELY(condition)
Definition: robin_hood.h:180
ROBIN_HOOD_COUNT_TRAILING_ZEROES
#define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x)
Definition: robin_hood.h:159
robin_hood::detail::Table::ROBIN_HOOD
ROBIN_HOOD(NODISCARD) size_t calcNumBytesInfo(size_t numElements) const noexcept
Definition: robin_hood.h:2130
robin_hood::detail::BulkPoolAllocator::reset
void reset() noexcept
Definition: robin_hood.h:403
robin_hood::detail::Table::erase
size_t erase(const key_type &key)
Definition: robin_hood.h:2035
robin_hood::detail::Table::size_type
size_t size_type
Definition: robin_hood.h:928
robin_hood::detail::Table::try_emplace
std::pair< iterator, bool > try_emplace(const key_type &key, Args &&... args)
Definition: robin_hood.h:1823
robin_hood::detail::Table::Table
Table(Iter first, Iter last, size_t ROBIN_HOOD_UNUSED(bucket_count)=0, const Hash &h=Hash{}, const KeyEqual &equal=KeyEqual{})
Definition: robin_hood.h:1516
robin_hood::pair::second
T2 second
Definition: robin_hood.h:655
robin_hood::detail::Table::begin
iterator begin()
Definition: robin_hood.h:1976
robin_hood::ROBIN_HOOD_STD::index_sequence_for
make_index_sequence< sizeof...(T)> index_sequence_for
Definition: robin_hood.h:297
robin_hood::detail::Table::contains
bool contains(const key_type &key) const
Definition: robin_hood.h:1898
robin_hood::detail::Table::try_emplace
std::pair< iterator, bool > try_emplace(const_iterator hint, const key_type &key, Args &&... args)
Definition: robin_hood.h:1833
robin_hood::pair::first_type
T1 first_type
Definition: robin_hood.h:582
robin_hood::detail::NodeAllocator
Definition: robin_hood.h:540
robin_hood::detail::BulkPoolAllocator::operator=
BulkPoolAllocator & operator=(BulkPoolAllocator &&o) noexcept
Definition: robin_hood.h:382
robin_hood::detail::Table::is_set
static constexpr bool is_set
Definition: robin_hood.h:919
robin_hood::detail::Table::insert
void insert(Iter first, Iter last)
Definition: robin_hood.h:1781
robin_hood::detail::Table::hasher
Hash hasher
Definition: robin_hood.h:929
robin_hood::hash_int
size_t hash_int(uint64_t x) noexcept
Definition: robin_hood.h:747
robin_hood::operator>
constexpr bool operator>(pair< A, B > const &x, pair< A, B > const &y)
Definition: robin_hood.h:679
robin_hood::detail::WrapHash::WrapHash
WrapHash(T const &o) noexcept(noexcept(T(std::declval< T const & >())))
Definition: robin_hood.h:869
robin_hood::detail::Table::find
iterator find(const OtherKey &key, is_transparent_tag)
Definition: robin_hood.h:1963
robin_hood::ROBIN_HOOD_STD::detail_::IntSeqImpl::IntSeqCombiner
Definition: robin_hood.h:259
robin_hood::detail::Table::insert_or_assign
std::pair< iterator, bool > insert_or_assign(const key_type &key, Mapped &&obj)
Definition: robin_hood.h:1846
robin_hood
Definition: robin_hood.h:227
robin_hood::operator<
constexpr bool operator<(pair< A, B > const &x, pair< A, B > const &y) noexcept(noexcept(std::declval< A const & >()< std::declval< A const & >()) &&noexcept(std::declval< B const & >()< std::declval< B const & >()))
Definition: robin_hood.h:673
robin_hood::pair::pair
constexpr pair(std::pair< T1, T2 > const &o) noexcept(noexcept(T1(std::declval< T1 const & >())) &&noexcept(T2(std::declval< T2 const & >())))
Definition: robin_hood.h:593
robin_hood::detail::Table::find
iterator find(const key_type &key)
Definition: robin_hood.h:1956
robin_hood::detail::Table::max_load_factor
float max_load_factor() const noexcept
Definition: robin_hood.h:2105
robin_hood::detail::void_type
Definition: robin_hood.h:853
robin_hood::pair::first
T1 first
Definition: robin_hood.h:654
robin_hood::detail::reinterpret_cast_no_cast_align_warning
T reinterpret_cast_no_cast_align_warning(void *ptr) noexcept
Definition: robin_hood.h:321
robin_hood::detail::assertNotNull
T * assertNotNull(T *t, Args &&... args)
Definition: robin_hood.h:346
robin_hood::detail::BulkPoolAllocator::allocate
T * allocate()
Definition: robin_hood.h:416
robin_hood::operator>=
constexpr bool operator>=(pair< A, B > const &x, pair< A, B > const &y)
Definition: robin_hood.h:687
robin_hood::detail::WrapKeyEqual
Definition: robin_hood.h:874
robin_hood::detail::Table::value_type
typename std::conditional< is_set, Key, robin_hood::pair< typename std::conditional< is_flat, Key, Key const >::type, T > >::type value_type
Definition: robin_hood.h:927
robin_hood::detail::Table::cbegin
const_iterator cbegin() const
Definition: robin_hood.h:1987
ROBIN_HOOD_UNLIKELY
#define ROBIN_HOOD_UNLIKELY(condition)
Definition: robin_hood.h:181
robin_hood::detail::Table::operator==
bool operator==(const Table &other) const
Definition: robin_hood.h:1708
robin_hood::detail::Table::begin
const_iterator begin() const
Definition: robin_hood.h:1983
ROBIN_HOOD_COUNT_LEADING_ZEROES
#define ROBIN_HOOD_COUNT_LEADING_ZEROES(x)
Definition: robin_hood.h:158
robin_hood::detail::Table::compact
void compact()
Definition: robin_hood.h:2071
robin_hood::detail::Table::erase
iterator erase(iterator pos)
Definition: robin_hood.h:2018
robin_hood::detail::Table::emplace
std::pair< iterator, bool > emplace(Args &&... args)
Definition: robin_hood.h:1795
robin_hood::pair::pair
constexpr pair() noexcept(noexcept(U1()) &&noexcept(U2()))
Definition: robin_hood.h:588
robin_hood::detail::Table::is_map
static constexpr bool is_map
Definition: robin_hood.h:918
robin_hood::detail::BulkPoolAllocator::BulkPoolAllocator
BulkPoolAllocator(const BulkPoolAllocator &ROBIN_HOOD_UNUSED(o)) noexcept
Definition: robin_hood.h:371
robin_hood::detail::Table::insert
std::pair< iterator, bool > insert(value_type &&keyval)
Definition: robin_hood.h:1873
robin_hood::detail::Table::ROBIN_HOOD
ROBIN_HOOD(NODISCARD) bool empty() const noexcept
Definition: robin_hood.h:2100
robin_hood::detail::WrapKeyEqual::WrapKeyEqual
WrapKeyEqual(T const &o) noexcept(noexcept(T(std::declval< T const & >())))
Definition: robin_hood.h:876
robin_hood::is_transparent_tag
Definition: robin_hood.h:575
robin_hood::pair::pair
constexpr pair(std::pair< T1, T2 > &&o) noexcept(noexcept(T1(std::move(std::declval< T1 && >()))) &&noexcept(T2(std::move(std::declval< T2 && >()))))
Definition: robin_hood.h:599
robin_hood::detail::Table::insert_or_assign
std::pair< iterator, bool > insert_or_assign(key_type &&key, Mapped &&obj)
Definition: robin_hood.h:1851
robin_hood::detail::Table::clear
void clear()
Definition: robin_hood.h:1681
robin_hood::detail::Table::insert
void insert(std::initializer_list< value_type > ilist)
Definition: robin_hood.h:1788
robin_hood::operator<=
constexpr bool operator<=(pair< A, B > const &x, pair< A, B > const &y)
Definition: robin_hood.h:683
robin_hood::ROBIN_HOOD_STD::make_index_sequence
make_integer_sequence< std::size_t, N > make_index_sequence
Definition: robin_hood.h:294
robin_hood::ROBIN_HOOD_STD::detail_::IntSeqImpl< T, Begin, Begin, false >::TValue
T TValue
Definition: robin_hood.h:275
robin_hood::detail::Table::contains
std::enable_if< Self_::is_transparent, bool >::type contains(const OtherKey &key) const
Definition: robin_hood.h:1904
robin_hood::hash< std::basic_string< CharT > >::operator()
size_t operator()(std::basic_string< CharT > const &str) const noexcept
Definition: robin_hood.h:774
robin_hood::detail::ROBIN_HOOD
ROBIN_HOOD(NOINLINE) void doThrow(Args &&... ROBIN_HOOD_UNUSED(args))
Definition: robin_hood.h:333
robin_hood::detail::BulkPoolAllocator::BulkPoolAllocator
BulkPoolAllocator() noexcept=default
robin_hood::detail::Table::ROBIN_HOOD
ROBIN_HOOD(NODISCARD) size_t calcMaxNumElementsAllowed(size_t maxElements) const noexcept
Definition: robin_hood.h:2121
robin_hood::detail::Table::operator[]
std::enable_if<!std::is_void< Q >::value, Q & >::type operator[](key_type &&key)
Definition: robin_hood.h:1754
robin_hood::detail::Table::mapped_type
T mapped_type
Definition: robin_hood.h:924
robin_hood::detail::Table::Table
Table() noexcept(noexcept(Hash()) &&noexcept(KeyEqual()))
Definition: robin_hood.h:1496
robin_hood::hash< std::shared_ptr< T > >::operator()
size_t operator()(std::shared_ptr< T > const &ptr) const noexcept
Definition: robin_hood.h:804
robin_hood::detail::WrapHash
Definition: robin_hood.h:867
robin_hood::detail::Table::at
std::enable_if<!std::is_void< Q >::value, Q const & >::type at(key_type const &key) const
Definition: robin_hood.h:1925
robin_hood::detail::Table::load_factor
float load_factor() const noexcept
Definition: robin_hood.h:2111
robin_hood::detail::NodeAllocator< T, MinSize, MaxSize, true >::addOrFree
void addOrFree(void *ptr, size_t ROBIN_HOOD_UNUSED(numBytes)) noexcept
Definition: robin_hood.h:547
robin_hood::hash< Enum, typename std::enable_if< std::is_enum< Enum >::value >::type >::operator()
size_t operator()(Enum e) const noexcept
Definition: robin_hood.h:811
robin_hood::ROBIN_HOOD_STD::detail_::IntSeqImpl::TValue
T TValue
Definition: robin_hood.h:254
robin_hood::detail::BulkPoolAllocator::deallocate
void deallocate(T *obj) noexcept
Definition: robin_hood.h:430
robin_hood::ROBIN_HOOD_STD::alignment_of
Definition: robin_hood.h:236
ROBIN_HOOD_TRACE
#define ROBIN_HOOD_TRACE(x)
Definition: robin_hood.h:69
robin_hood::detail::Table::calcNumElementsWithBuffer
size_t calcNumElementsWithBuffer(size_t numElements) const noexcept
Definition: robin_hood.h:2137
robin_hood::detail::Table::iterator
Iter< false > iterator
Definition: robin_hood.h:1493
robin_hood::pair
Definition: robin_hood.h:581
robin_hood::detail::Table::size
size_type size() const noexcept
Definition: robin_hood.h:2090
robin_hood::hash::operator()
size_t operator()(T const &obj) const noexcept(noexcept(std::declval< std::hash< T >>().operator()(std::declval< T const & >())))
Definition: robin_hood.h:763
robin_hood::detail::Table::max_size
size_type max_size() const noexcept
Definition: robin_hood.h:2095
robin_hood::detail::Table::try_emplace
std::pair< iterator, bool > try_emplace(const_iterator hint, key_type &&key, Args &&... args)
Definition: robin_hood.h:1840
robin_hood::detail::BulkPoolAllocator::operator=
BulkPoolAllocator & operator=(const BulkPoolAllocator &ROBIN_HOOD_UNUSED(o)) noexcept
Definition: robin_hood.h:393
robin_hood::detail::BulkPoolAllocator::~BulkPoolAllocator
~BulkPoolAllocator() noexcept
Definition: robin_hood.h:398
robin_hood::detail::Table::try_emplace
std::pair< iterator, bool > try_emplace(key_type &&key, Args &&... args)
Definition: robin_hood.h:1828
robin_hood::detail::BulkPoolAllocator
Definition: robin_hood.h:366
robin_hood::pair::pair
constexpr pair(std::piecewise_construct_t, std::tuple< U1... > a, std::tuple< U2... > b) noexcept(noexcept(pair(std::declval< std::tuple< U1... > & >(), std::declval< std::tuple< U2... > & >(), ROBIN_HOOD_STD::index_sequence_for< U1... >(), ROBIN_HOOD_STD::index_sequence_for< U2... >())))
Definition: robin_hood.h:621
robin_hood::operator!=
constexpr bool operator!=(pair< A, B > const &x, pair< A, B > const &y)
Definition: robin_hood.h:669
robin_hood::detail::Table::swap
void swap(Table &o)
Definition: robin_hood.h:1674
robin_hood::detail::Table::rehash
void rehash(size_t c)
Definition: robin_hood.h:2057
robin_hood::detail::Table::operator[]
std::enable_if<!std::is_void< Q >::value, Q & >::type operator[](const key_type &key)
Definition: robin_hood.h:1728
robin_hood::detail::void_type::type
void type
Definition: robin_hood.h:854
robin_hood::hash_bytes
size_t hash_bytes(void const *ptr, size_t len) noexcept
Definition: robin_hood.h:691
robin_hood::pair::swap
void swap(pair< T1, T2 > &o) noexcept((detail::swappable::nothrow< T1 >::value) &&(detail::swappable::nothrow< T2 >::value))
Definition: robin_hood.h:647
robin_hood::detail::Table::end
iterator end()
Definition: robin_hood.h:1995
robin_hood::detail::Table::ROBIN_HOOD
ROBIN_HOOD(NODISCARD) size_t mask() const noexcept
Definition: robin_hood.h:2116
robin_hood::detail::SizeT
uint32_t SizeT
Definition: robin_hood.h:309
robin_hood::detail::Table::find
const_iterator find(const OtherKey &key, is_transparent_tag) const
Definition: robin_hood.h:1941
robin_hood::hash
Definition: robin_hood.h:762
robin_hood::detail::BulkPoolAllocator::addOrFree
void addOrFree(void *ptr, const size_t numBytes) noexcept
Definition: robin_hood.h:438
robin_hood::detail::Table::operator=
Table & operator=(Table &&o) noexcept
Definition: robin_hood.h:1552
robin_hood::detail::Table::is_flat
static constexpr bool is_flat
Definition: robin_hood.h:917
robin_hood::hash< T * >::operator()
size_t operator()(T *ptr) const noexcept
Definition: robin_hood.h:790
robin_hood::hash< std::unique_ptr< T > >::operator()
size_t operator()(std::unique_ptr< T > const &ptr) const noexcept
Definition: robin_hood.h:797
ROBIN_HOOD
#define ROBIN_HOOD(x)
Definition: robin_hood.h:96
robin_hood::detail::Table::end
const_iterator end() const
Definition: robin_hood.h:2001
robin_hood::pair::pair
constexpr pair(T1 &&a, T2 &&b) noexcept(noexcept(T1(std::move(std::declval< T1 && >()))) &&noexcept(T2(std::move(std::declval< T2 && >()))))
Definition: robin_hood.h:604
robin_hood::detail::WrapHash::WrapHash
WrapHash()=default
robin_hood::ROBIN_HOOD_STD::make_integer_sequence
typename detail_::IntSeqImpl< T, 0, N,(N - 0)==1 >::TResult make_integer_sequence
Definition: robin_hood.h:291
robin_hood::ROBIN_HOOD_STD::detail_::IntSeqImpl::TResult
typename IntSeqCombiner< typename IntSeqImpl< TValue, Begin, Begin+(End - Begin)/2,(End - Begin)/2==1 >::TResult, typename IntSeqImpl< TValue, Begin+(End - Begin)/2, End,(End - Begin+1)/2==1 >::TResult >::TResult TResult
Definition: robin_hood.h:270
robin_hood::detail::Table::find
const_iterator find(const key_type &key) const
Definition: robin_hood.h:1934
robin_hood::ROBIN_HOOD_STD::integer_sequence
Definition: robin_hood.h:240
ROBIN_HOOD_COUNT
#define ROBIN_HOOD_COUNT(x)
Definition: robin_hood.h:91
robin_hood::ROBIN_HOOD_HASH_INT
ROBIN_HOOD_HASH_INT(bool)
robin_hood::detail::Table::reserve
void reserve(size_t c)
Definition: robin_hood.h:2064
robin_hood::pair::pair
pair(std::tuple< U1... > &a, std::tuple< U2... > &b, ROBIN_HOOD_STD::index_sequence< I1... >, ROBIN_HOOD_STD::index_sequence< I2... >) noexcept(noexcept(T1(std::forward< U1 >(std::get< I1 >(std::declval< std::tuple< U1... > & >()))...)) &&noexcept(T2(std::forward< U2 >(std::get< I2 >(std::declval< std::tuple< U2... > & >()))...)))
Definition: robin_hood.h:633
robin_hood::detail::Table::insert_or_assign
std::pair< iterator, bool > insert_or_assign(const_iterator hint, key_type &&key, Mapped &&obj)
Definition: robin_hood.h:1863
robin_hood::detail::Table::is_transparent
static constexpr bool is_transparent
Definition: robin_hood.h:920
robin_hood::detail::Table::at
std::enable_if<!std::is_void< Q >::value, Q & >::type at(key_type const &key)
Definition: robin_hood.h:1912
robin_hood::detail::BulkPoolAllocator::BulkPoolAllocator
BulkPoolAllocator(BulkPoolAllocator &&o) noexcept
Definition: robin_hood.h:375
robin_hood::ROBIN_HOOD_STD::detail_::IntSeqImpl
Definition: robin_hood.h:253
robin_hood::pair::pair
constexpr pair(U1 &&a, U2 &&b) noexcept(noexcept(T1(std::forward< U1 >(std::declval< U1 && >()))) &&noexcept(T2(std::forward< U2 >(std::declval< U2 && >()))))
Definition: robin_hood.h:610
robin_hood::detail::BulkPoolAllocator::swap
void swap(BulkPoolAllocator< T, MinNumAllocs, MaxNumAllocs > &other) noexcept
Definition: robin_hood.h:450
robin_hood::detail::Table::insert_or_assign
std::pair< iterator, bool > insert_or_assign(const_iterator hint, const key_type &key, Mapped &&obj)
Definition: robin_hood.h:1856
robin_hood::detail::Table::count
std::enable_if< Self_::is_transparent, size_t >::type count(const OtherKey &key) const
Definition: robin_hood.h:1889
robin_hood::ROBIN_HOOD_STD::integer_sequence::size
static constexpr std::size_t size() noexcept
Definition: robin_hood.h:244
robin_hood::detail::rotr
T rotr(T x, unsigned k)
Definition: robin_hood.h:313
ROBIN_HOOD_LOG
#define ROBIN_HOOD_LOG(x)
Definition: robin_hood.h:60
robin_hood::detail::Table::key_type
Key key_type
Definition: robin_hood.h:923
robin_hood::pair::second_type
T2 second_type
Definition: robin_hood.h:583
robin_hood::detail::Table::find
std::enable_if< Self_::is_transparent, iterator >::type find(const OtherKey &key)
Definition: robin_hood.h:1970
robin_hood::detail::Table::operator=
Table & operator=(Table const &o)
Definition: robin_hood.h:1611
robin_hood::detail::Table::count
size_t count(const key_type &key) const
Definition: robin_hood.h:1878
robin_hood::detail::Table::insert
std::pair< iterator, bool > insert(const value_type &keyval)
Definition: robin_hood.h:1868
robin_hood::detail::Table::Table
Table(size_t ROBIN_HOOD_UNUSED(bucket_count), const Hash &h=Hash{}, const KeyEqual &equal=KeyEqual{}) noexcept(noexcept(Hash(h)) &&noexcept(KeyEqual(equal)))
Definition: robin_hood.h:1507
robin_hood::detail::WrapKeyEqual::WrapKeyEqual
WrapKeyEqual()=default
robin_hood::detail::Table::~Table
~Table()
Definition: robin_hood.h:1702
robin_hood::detail::Table::key_equal
KeyEqual key_equal
Definition: robin_hood.h:930
robin_hood::detail::Table::find
std::enable_if< Self_::is_transparent, const_iterator >::type find(const OtherKey &key) const
Definition: robin_hood.h:1950
robin_hood::detail::Table::const_iterator
Iter< true > const_iterator
Definition: robin_hood.h:1494
robin_hood::detail::has_is_transparent
Definition: robin_hood.h:858
robin_hood::detail::unaligned_load
T unaligned_load(void const *ptr) noexcept
Definition: robin_hood.h:354
robin_hood::detail::Table
Definition: robin_hood.h:908
robin_hood::detail::Table::Table
Table(const Table &o)
Definition: robin_hood.h:1580
robin_hood::detail::swappable::nothrow
Definition: robin_hood.h:562
robin_hood::detail::Table::erase
iterator erase(const_iterator pos)
Definition: robin_hood.h:2010
robin_hood::swap
void swap(pair< A, B > &a, pair< A, B > &b) noexcept(noexcept(std::declval< pair< A, B > & >().swap(std::declval< pair< A, B > & >())))
Definition: robin_hood.h:659
ROBIN_HOOD_UNUSED
#define ROBIN_HOOD_UNUSED(identifier)
Definition: robin_hood.h:99
robin_hood::operator==
constexpr bool operator==(pair< A, B > const &x, pair< A, B > const &y)
Definition: robin_hood.h:665
robin_hood::ROBIN_HOOD_STD::detail_::IntSeqImpl< T, Begin, End, true >::TValue
T TValue
Definition: robin_hood.h:283
robin_hood::ROBIN_HOOD_STD::integer_sequence::value_type
T value_type
Definition: robin_hood.h:242