33#ifndef ROBIN_HOOD_H_INCLUDED
34#define ROBIN_HOOD_H_INCLUDED
37#define ROBIN_HOOD_VERSION_MAJOR 3
38#define ROBIN_HOOD_VERSION_MINOR 11
39#define ROBIN_HOOD_VERSION_PATCH 5
51#if __cplusplus >= 201703L
52# include <string_view>
56#ifdef ROBIN_HOOD_LOG_ENABLED
58# define ROBIN_HOOD_LOG(...) \
59 std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << __VA_ARGS__ << std::endl;
61# define ROBIN_HOOD_LOG(x)
65#ifdef ROBIN_HOOD_TRACE_ENABLED
67# define ROBIN_HOOD_TRACE(...) \
68 std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << __VA_ARGS__ << std::endl;
70# define ROBIN_HOOD_TRACE(x)
74#ifdef ROBIN_HOOD_COUNT_ENABLED
76# define ROBIN_HOOD_COUNT(x) ++counts().x;
82inline std::ostream& operator<<(std::ostream& os, Counts
const& c) {
83 return os << c.shiftUp <<
" shiftUp" << std::endl << c.shiftDown <<
" shiftDown" << std::endl;
86static Counts& counts() {
87 static Counts counts{};
92# define ROBIN_HOOD_COUNT(x)
97#define ROBIN_HOOD(x) ROBIN_HOOD_PRIVATE_DEFINITION_##x()
100#define ROBIN_HOOD_UNUSED(identifier)
103#if SIZE_MAX == UINT32_MAX
104# define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 32
105#elif SIZE_MAX == UINT64_MAX
106# define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 64
108# error Unsupported bitness
113# define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() 1
114# define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() 0
116# define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() \
117 (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
118# define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
123# define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __declspec(noinline)
125# define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __attribute__((noinline))
129#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND)
130# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 0
132# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 1
136#if !defined(ROBIN_HOOD_DISABLE_INTRINSICS)
138# if ROBIN_HOOD(BITNESS) == 32
139# define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward
141# define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward64
144# pragma intrinsic(ROBIN_HOOD(BITSCANFORWARD))
145# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) \
146 [](size_t mask) noexcept -> int { \
147 unsigned long index; \
148 return ROBIN_HOOD(BITSCANFORWARD)(&index, mask) ? static_cast<int>(index) \
149 : ROBIN_HOOD(BITNESS); \
152# if ROBIN_HOOD(BITNESS) == 32
153# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzl
154# define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzl
156# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzll
157# define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzll
159# define ROBIN_HOOD_COUNT_LEADING_ZEROES(x) ((x) ? ROBIN_HOOD(CLZ)(x) : ROBIN_HOOD(BITNESS))
160# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ((x) ? ROBIN_HOOD(CTZ)(x) : ROBIN_HOOD(BITNESS))
165#ifndef __has_cpp_attribute
166# define __has_cpp_attribute(x) 0
168#if __has_cpp_attribute(clang::fallthrough)
169# define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[clang::fallthrough]]
170#elif __has_cpp_attribute(gnu::fallthrough)
171# define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[gnu::fallthrough]]
173# define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH()
178# define ROBIN_HOOD_LIKELY(condition) condition
179# define ROBIN_HOOD_UNLIKELY(condition) condition
181# define ROBIN_HOOD_LIKELY(condition) __builtin_expect(condition, 1)
182# define ROBIN_HOOD_UNLIKELY(condition) __builtin_expect(condition, 0)
187# ifdef _NATIVE_WCHAR_T_DEFINED
188# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1
190# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 0
193# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1
199# define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 1
201# define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0
204# define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0
209#if defined(__GNUC__) && __GNUC__ < 5
210# define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)
212# define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value
215#if defined(__clang__)
216#pragma clang diagnostic push
217#pragma clang diagnostic ignored "-Wdeprecated-builtins"
221#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX() __cplusplus
222#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX98() 199711L
223#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX11() 201103L
224#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX14() 201402L
225#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX17() 201703L
227#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)
228# define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD() [[nodiscard]]
230# define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD()
235#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)
236# define ROBIN_HOOD_STD std
240namespace ROBIN_HOOD_STD {
243 : std::integral_constant<std::size_t, alignof(typename std::remove_all_extents<T>::type)> {};
245template <
class T, T... Ints>
249 static_assert(std::is_integral<value_type>::value,
"not integral type");
250 static constexpr std::size_t
size() noexcept {
251 return sizeof...(Ints);
254template <std::size_t... Inds>
258template <
class T, T Begin, T End,
bool>
261 static_assert(std::is_integral<TValue>::value,
"not integral type");
262 static_assert(Begin >= 0 && Begin < End,
"unexpected argument (Begin<0 || Begin<=End)");
264 template <
class,
class>
279template <
class T, T Begin>
282 static_assert(std::is_integral<TValue>::value,
"not integral type");
283 static_assert(Begin >= 0,
"unexpected argument (Begin<0)");
287template <
class T, T Begin, T End>
290 static_assert(std::is_integral<TValue>::value,
"not integral type");
291 static_assert(Begin >= 0,
"unexpected argument (Begin<0)");
296template <
class T, T N>
299template <std::
size_t N>
312#if ROBIN_HOOD(BITNESS) == 64
313using SizeT = uint64_t;
320 return (x >> k) | (x << (8U *
sizeof(T) - k));
328 return reinterpret_cast<T
>(ptr);
333 return reinterpret_cast<T
>(ptr);
338template <
typename E,
typename... Args>
340#if ROBIN_HOOD(HAS_EXCEPTIONS)
341 void doThrow(Args&&... args) {
343 throw E(std::forward<Args>(args)...);
351template <
typename E,
typename T,
typename... Args>
354 doThrow<E>(std::forward<Args>(args)...);
364 std::memcpy(&t, ptr,
sizeof(T));
371template <
typename T,
size_t MinNumAllocs = 4,
size_t MaxNumAllocs = 256>
379 , mListForFree(
nullptr) {}
383 , mListForFree(o.mListForFree) {
384 o.mListForFree =
nullptr;
391 mListForFree = o.mListForFree;
392 o.mListForFree =
nullptr;
410 while (mListForFree) {
411 T* tmp = *mListForFree;
413 std::free(mListForFree);
414 mListForFree = reinterpret_cast_no_cast_align_warning<T**>(tmp);
425 tmp = performAllocation();
428 mHead = *reinterpret_cast_no_cast_align_warning<T**>(tmp);
437 *reinterpret_cast_no_cast_align_warning<T**>(obj) = mHead;
444 void addOrFree(
void* ptr,
const size_t numBytes)
noexcept {
446 if (numBytes < ALIGNMENT + ALIGNED_SIZE) {
458 swap(mHead, other.mHead);
459 swap(mListForFree, other.mListForFree);
467 ROBIN_HOOD(NODISCARD)
size_t calcNumElementsToAlloc() const noexcept {
468 auto tmp = mListForFree;
469 size_t numAllocs = MinNumAllocs;
471 while (numAllocs * 2 <= MaxNumAllocs && tmp) {
472 auto x =
reinterpret_cast<T***
>(tmp);
481 void add(
void* ptr,
const size_t numBytes)
noexcept {
482 const size_t numElements = (numBytes - ALIGNMENT) / ALIGNED_SIZE;
484 auto data =
reinterpret_cast<T**
>(ptr);
487 auto x =
reinterpret_cast<T***
>(data);
493 reinterpret_cast_no_cast_align_warning<T*>(
reinterpret_cast<char*
>(ptr) + ALIGNMENT);
495 auto*
const head =
reinterpret_cast<char*
>(headT);
498 for (
size_t i = 0; i < numElements; ++i) {
499 *reinterpret_cast_no_cast_align_warning<char**>(head + i * ALIGNED_SIZE) =
500 head + (i + 1) * ALIGNED_SIZE;
504 *reinterpret_cast_no_cast_align_warning<T**>(head + (numElements - 1) * ALIGNED_SIZE) =
512 size_t const numElementsToAlloc = calcNumElementsToAlloc();
515 size_t const bytes = ALIGNMENT + ALIGNED_SIZE * numElementsToAlloc;
516 ROBIN_HOOD_LOG(
"std::malloc " << bytes <<
" = " << ALIGNMENT <<
" + " << ALIGNED_SIZE
517 <<
" * " << numElementsToAlloc)
518 add(assertNotNull<std::bad_alloc>(std::malloc(bytes)), bytes);
523#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)
524 static constexpr size_t ALIGNMENT =
525 (std::max)(std::alignment_of<T>::value, std::alignment_of<T*>::value);
527 static const size_t ALIGNMENT =
528 (ROBIN_HOOD_STD::alignment_of<T>::value > ROBIN_HOOD_STD::alignment_of<T*>::value)
529 ? ROBIN_HOOD_STD::alignment_of<T>::value
530 : +ROBIN_HOOD_STD::alignment_of<T*>::value;
533 static constexpr size_t ALIGNED_SIZE = ((
sizeof(T) - 1) / ALIGNMENT + 1) * ALIGNMENT;
535 static_assert(MinNumAllocs >= 1,
"MinNumAllocs");
536 static_assert(MaxNumAllocs >= MinNumAllocs,
"MaxNumAllocs");
537 static_assert(ALIGNED_SIZE >=
sizeof(T*),
"ALIGNED_SIZE");
538 static_assert(0 == (ALIGNED_SIZE %
sizeof(T*)),
"ALIGNED_SIZE mod");
539 static_assert(ALIGNMENT >=
sizeof(T*),
"ALIGNMENT");
542 T** mListForFree{
nullptr};
545template <
typename T,
size_t MinSize,
size_t MaxSize,
bool IsFlat>
549template <
typename T,
size_t MinSize,
size_t MaxSize>
559template <
typename T,
size_t MinSize,
size_t MaxSize>
565#if ROBIN_HOOD(CXX) < ROBIN_HOOD(CXX17)
569 static const bool value =
noexcept(
swap(std::declval<T&>(), std::declval<T&>()));
574 static const bool value = std::is_nothrow_swappable<T>::value;
586template <
typename T1,
typename T2>
591 template <
typename U1 = T1,
typename U2 = T2,
592 typename =
typename std::enable_if<std::is_default_constructible<U1>::value &&
593 std::is_default_constructible<U2>::value>::type>
594 constexpr pair() noexcept(noexcept(U1()) && noexcept(U2()))
599 explicit constexpr pair(std::pair<T1, T2>
const& o)
noexcept(
600 noexcept(T1(std::declval<T1 const&>())) &&
noexcept(T2(std::declval<T2 const&>())))
605 explicit constexpr pair(std::pair<T1, T2>&& o)
noexcept(
noexcept(
606 T1(std::move(std::declval<T1&&>()))) &&
noexcept(T2(std::move(std::declval<T2&&>()))))
607 :
first(std::move(o.first))
608 ,
second(std::move(o.second)) {}
610 constexpr pair(T1&& a, T2&& b)
noexcept(
noexcept(
611 T1(std::move(std::declval<T1&&>()))) &&
noexcept(T2(std::move(std::declval<T2&&>()))))
612 :
first(std::move(a))
615 template <
typename U1,
typename U2>
616 constexpr pair(U1&& a, U2&& b)
noexcept(
noexcept(T1(std::forward<U1>(
617 std::declval<U1&&>()))) &&
noexcept(T2(std::forward<U2>(std::declval<U2&&>()))))
618 :
first(std::forward<U1>(a))
619 ,
second(std::forward<U2>(b)) {}
621 template <
typename... U1,
typename... U2>
624#if !ROBIN_HOOD(BROKEN_CONSTEXPR)
627 pair(std::piecewise_construct_t , std::tuple<U1...> a,
629 b)
noexcept(
noexcept(
pair(std::declval<std::tuple<U1...>&>(),
630 std::declval<std::tuple<U2...>&>(),
638 template <
typename... U1,
size_t... I1,
typename... U2,
size_t... I2>
640 noexcept(T1(std::forward<U1>(std::get<I1>(
641 std::declval<std::tuple<
642 U1...>&>()))...)) &&
noexcept(T2(
std::
643 forward<U2>(
std::get<I2>(
644 std::declval<
std::tuple<U2...>&>()))...)))
664template <
typename A,
typename B>
666 noexcept(std::declval<pair<A, B>&>().
swap(std::declval<
pair<A, B>&>()))) {
670template <
typename A,
typename B>
674template <
typename A,
typename B>
678template <
typename A,
typename B>
680 std::declval<A const&>() < std::declval<A const&>()) &&
noexcept(std::declval<B const&>() <
681 std::declval<B const&>())) {
682 return x.first < y.first || (!(y.first < x.first) && x.second < y.second);
684template <
typename A,
typename B>
688template <
typename A,
typename B>
692template <
typename A,
typename B>
697inline size_t hash_bytes(
void const* ptr,
size_t len)
noexcept {
698 static constexpr uint64_t m = UINT64_C(0xc6a4a7935bd1e995);
699 static constexpr uint64_t seed = UINT64_C(0xe17a1465);
700 static constexpr unsigned int r = 47;
702 auto const*
const data64 =
static_cast<uint64_t const*
>(ptr);
703 uint64_t h = seed ^ (len * m);
705 size_t const n_blocks = len / 8;
706 for (
size_t i = 0; i < n_blocks; ++i) {
707 auto k = detail::unaligned_load<uint64_t>(data64 + i);
717 auto const*
const data8 =
reinterpret_cast<uint8_t const*
>(data64 + n_blocks);
720 h ^=
static_cast<uint64_t
>(data8[6]) << 48U;
723 h ^=
static_cast<uint64_t
>(data8[5]) << 40U;
726 h ^=
static_cast<uint64_t
>(data8[4]) << 32U;
729 h ^=
static_cast<uint64_t
>(data8[3]) << 24U;
732 h ^=
static_cast<uint64_t
>(data8[2]) << 16U;
735 h ^=
static_cast<uint64_t
>(data8[1]) << 8U;
738 h ^=
static_cast<uint64_t
>(data8[0]);
750 return static_cast<size_t>(h);
757 x *= UINT64_C(0xff51afd7ed558ccd);
763 return static_cast<size_t>(x);
767template <
typename T,
typename Enable =
void>
768struct hash :
public std::hash<T> {
770 noexcept(
noexcept(std::declval<std::hash<T>>().
operator()(std::declval<T const&>()))) {
772 auto result = std::hash<T>::operator()(obj);
778template <
typename CharT>
780 size_t operator()(std::basic_string<CharT>
const& str)
const noexcept {
781 return hash_bytes(str.data(),
sizeof(CharT) * str.size());
785#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)
786template <
typename CharT>
787struct hash<
std::basic_string_view<CharT>> {
788 size_t operator()(std::basic_string_view<CharT>
const& sv)
const noexcept {
789 return hash_bytes(sv.data(),
sizeof(CharT) * sv.size());
803 size_t operator()(std::unique_ptr<T>
const& ptr)
const noexcept {
810 size_t operator()(std::shared_ptr<T>
const& ptr)
const noexcept {
815template <
typename Enum>
816struct hash<Enum, typename
std::enable_if<std::is_enum<Enum>::value>::type> {
818 using Underlying =
typename std::underlying_type<Enum>::type;
823#define ROBIN_HOOD_HASH_INT(T) \
826 size_t operator()(T const& obj) const noexcept { \
827 return hash_int(static_cast<uint64_t>(obj)); \
831#if defined(__GNUC__) && !defined(__clang__)
832# pragma GCC diagnostic push
833# pragma GCC diagnostic ignored "-Wuseless-cast"
842#if ROBIN_HOOD(HAS_NATIVE_WCHART)
853#if defined(__GNUC__) && !defined(__clang__)
854# pragma GCC diagnostic pop
863template <
typename T,
typename =
void>
868 :
public std::true_type {};
875 explicit WrapHash(T
const& o)
noexcept(
noexcept(T(std::declval<T const&>())))
882 explicit WrapKeyEqual(T
const& o)
noexcept(
noexcept(T(std::declval<T const&>())))
912template <
bool IsFlat,
size_t MaxLoadFactor100,
typename Key,
typename T,
typename Hash,
918 typename std::conditional<
919 std::is_void<T>::value, Key,
920 robin_hood::pair<typename std::conditional<IsFlat, Key, Key const>::type, T>>::type,
924 static constexpr bool is_map = !std::is_void<T>::value;
940 static_assert(MaxLoadFactor100 > 10 && MaxLoadFactor100 < 100,
941 "MaxLoadFactor100 needs to be >10 && < 100");
949 static constexpr size_t InitialNumElements =
sizeof(uint64_t);
950 static constexpr uint32_t InitialInfoNumBits = 5;
951 static constexpr uint8_t InitialInfoInc = 1U << InitialInfoNumBits;
952 static constexpr size_t InfoMask = InitialInfoInc - 1U;
953 static constexpr uint8_t InitialInfoHashShift = 0;
957 using InfoType = uint32_t;
964 template <
typename M,
bool>
968 template <
typename M>
969 class DataNode<M, true> final {
971 template <
typename... Args>
973 noexcept(
value_type(std::forward<Args>(args)...)))
974 : mData(std::forward<Args>(args)...) {}
977 std::is_nothrow_move_constructible<value_type>::value)
978 : mData(
std::move(n.mData)) {}
982 void destroyDoNotDeallocate() noexcept {}
984 value_type const* operator->() const noexcept {
991 const value_type& operator*() const noexcept {
999 template <
typename VT = value_type>
1001 typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {
1004 template <
typename VT = value_type>
1006 typename std::enable_if<is_set, VT&>::type getFirst() noexcept {
1010 template <
typename VT = value_type>
1012 typename std::enable_if<is_map, typename VT::first_type const&>::type
1013 getFirst() const noexcept {
1016 template <
typename VT = value_type>
1018 typename std::enable_if<is_set, VT const&>::type getFirst() const noexcept {
1022 template <
typename MT = mapped_type>
1024 typename std::enable_if<is_map, MT&>::type getSecond() noexcept {
1025 return mData.second;
1028 template <
typename MT = mapped_type>
1030 typename std::enable_if<is_set, MT const&>::type getSecond() const noexcept {
1031 return mData.second;
1034 void swap(DataNode<M, true>& o)
noexcept(
1035 noexcept(std::declval<value_type>().swap(std::declval<value_type>()))) {
1036 mData.swap(o.mData);
1044 template <
typename M>
1045 class DataNode<M, false> {
1047 template <
typename... Args>
1048 explicit DataNode(M& map, Args&&... args)
1049 : mData(map.allocate()) {
1050 ::new (
static_cast<void*
>(mData))
value_type(std::forward<Args>(args)...);
1054 : mData(std::move(n.mData)) {}
1056 void destroy(M& map)
noexcept {
1058 mData->~value_type();
1059 map.deallocate(mData);
1062 void destroyDoNotDeallocate() noexcept {
1063 mData->~value_type();
1066 value_type const* operator->() const noexcept {
1082 template <
typename VT = value_type>
1084 typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {
1085 return mData->first;
1087 template <
typename VT = value_type>
1089 typename std::enable_if<is_set, VT&>::type getFirst() noexcept {
1093 template <
typename VT = value_type>
1095 typename std::enable_if<is_map, typename VT::first_type const&>::type
1096 getFirst() const noexcept {
1097 return mData->first;
1099 template <
typename VT = value_type>
1101 typename std::enable_if<is_set, VT const&>::type getFirst() const noexcept {
1105 template <
typename MT = mapped_type>
1107 typename std::enable_if<is_map, MT&>::type getSecond() noexcept {
1108 return mData->second;
1111 template <
typename MT = mapped_type>
1113 typename std::enable_if<is_map, MT const&>::type getSecond() const noexcept {
1114 return mData->second;
1117 void swap(DataNode<M, false>& o)
noexcept {
1119 swap(mData, o.mData);
1126 using Node = DataNode<Self, IsFlat>;
1130 return n.getFirst();
1140 template <
typename Q = mapped_type>
1142 typename std::enable_if<!std::is_void<Q>::value,
key_type const&>::type
1143 getFirstConst(
value_type const& vt)
const noexcept {
1149 template <
typename M,
bool UseMemcpy>
1153 template <
typename M>
1154 struct Cloner<M, true> {
1155 void operator()(M
const& source, M& target)
const {
1156 auto const*
const src =
reinterpret_cast<char const*
>(source.mKeyVals);
1157 auto* tgt =
reinterpret_cast<char*
>(target.mKeyVals);
1158 auto const numElementsWithBuffer = target.calcNumElementsWithBuffer(target.mMask + 1);
1159 std::copy(src, src + target.calcNumBytesTotal(numElementsWithBuffer), tgt);
1163 template <
typename M>
1164 struct Cloner<M, false> {
1165 void operator()(M
const& s, M& t)
const {
1166 auto const numElementsWithBuffer = t.calcNumElementsWithBuffer(t.mMask + 1);
1167 std::copy(s.mInfo, s.mInfo + t.calcNumBytesInfo(numElementsWithBuffer), t.mInfo);
1169 for (
size_t i = 0; i < numElementsWithBuffer; ++i) {
1171 ::new (
static_cast<void*
>(t.mKeyVals + i)) Node(t, *s.mKeyVals[i]);
1179 template <
typename M,
bool IsFlatAndTrivial>
1180 struct Destroyer {};
1182 template <
typename M>
1183 struct Destroyer<M, true> {
1184 void nodes(M& m)
const noexcept {
1188 void nodesDoNotDeallocate(M& m)
const noexcept {
1193 template <
typename M>
1194 struct Destroyer<M, false> {
1195 void nodes(M& m)
const noexcept {
1198 auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
1200 for (
size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
1201 if (0 != m.mInfo[idx]) {
1202 Node& n = m.mKeyVals[idx];
1209 void nodesDoNotDeallocate(M& m)
const noexcept {
1212 auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
1213 for (
size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
1214 if (0 != m.mInfo[idx]) {
1215 Node& n = m.mKeyVals[idx];
1216 n.destroyDoNotDeallocate();
1225 struct fast_forward_tag {};
1228 template <
bool IsConst>
1232 using NodePtr =
typename std::conditional<IsConst, Node const*, Node*>::type;
1235 using difference_type = std::ptrdiff_t;
1237 using reference =
typename std::conditional<IsConst, value_type const&, value_type&>::type;
1238 using pointer =
typename std::conditional<IsConst, value_type const*, value_type*>::type;
1239 using iterator_category = std::forward_iterator_tag;
1249 template <
bool OtherIsConst,
1250 typename =
typename std::enable_if<IsConst && !OtherIsConst>::type>
1252 Iter(Iter<OtherIsConst>
const& other) noexcept
1253 : mKeyVals(other.mKeyVals)
1254 , mInfo(other.mInfo) {}
1256 Iter(NodePtr valPtr, uint8_t
const* infoPtr) noexcept
1260 Iter(NodePtr valPtr, uint8_t
const* infoPtr,
1267 template <
bool OtherIsConst,
1268 typename =
typename std::enable_if<IsConst && !OtherIsConst>::type>
1269 Iter& operator=(Iter<OtherIsConst>
const& other)
noexcept {
1270 mKeyVals = other.mKeyVals;
1271 mInfo = other.mInfo;
1276 Iter& operator++() noexcept {
1283 Iter operator++(
int)
noexcept {
1289 reference operator*()
const {
1293 pointer operator->()
const {
1298 bool operator==(Iter<O>
const& o)
const noexcept {
1299 return mKeyVals == o.mKeyVals;
1303 bool operator!=(Iter<O>
const& o)
const noexcept {
1304 return mKeyVals != o.mKeyVals;
1311 void fastForward() noexcept {
1313 while (0U == (n = detail::unaligned_load<size_t>(mInfo))) {
1314 mInfo +=
sizeof(size_t);
1315 mKeyVals +=
sizeof(size_t);
1317#if defined(ROBIN_HOOD_DISABLE_INTRINSICS)
1332# if ROBIN_HOOD(LITTLE_ENDIAN)
1343 NodePtr mKeyVals{
nullptr};
1344 uint8_t
const* mInfo{
nullptr};
1352 template <
typename HashKey>
1353 void keyToIdx(HashKey&& key,
size_t* idx, InfoType* info)
const {
1357 auto h =
static_cast<uint64_t
>(WHash::operator()(key));
1359 h *= mHashMultiplier;
1363 *info = mInfoInc +
static_cast<InfoType
>((h & InfoMask) >> mInfoHashShift);
1364 *idx = (
static_cast<size_t>(h) >> InitialInfoNumBits) & mMask;
1368 void next(InfoType* info,
size_t* idx)
const noexcept {
1373 void nextWhileLess(InfoType* info,
size_t* idx)
const noexcept {
1375 while (*info < mInfo[*idx]) {
1382 shiftUp(
size_t startIdx,
1383 size_t const insertion_idx)
noexcept(std::is_nothrow_move_assignable<Node>::value) {
1384 auto idx = startIdx;
1385 ::new (
static_cast<void*
>(mKeyVals + idx)) Node(std::move(mKeyVals[idx - 1]));
1386 while (--idx != insertion_idx) {
1387 mKeyVals[idx] = std::move(mKeyVals[idx - 1]);
1391 while (idx != insertion_idx) {
1393 mInfo[idx] =
static_cast<uint8_t
>(mInfo[idx - 1] + mInfoInc);
1395 mMaxNumElementsAllowed = 0;
1401 void shiftDown(
size_t idx)
noexcept(std::is_nothrow_move_assignable<Node>::value) {
1405 mKeyVals[idx].destroy(*
this);
1408 while (mInfo[idx + 1] >= 2 * mInfoInc) {
1410 mInfo[idx] =
static_cast<uint8_t
>(mInfo[idx + 1] - mInfoInc);
1411 mKeyVals[idx] = std::move(mKeyVals[idx + 1]);
1418 mKeyVals[idx].~Node();
1422 template <
typename Other>
1424 size_t findIdx(Other
const& key)
const {
1427 keyToIdx(key, &idx, &info);
1431 if (info == mInfo[idx] &&
1436 if (info == mInfo[idx] &&
1441 }
while (info <= mInfo[idx]);
1444 return mMask == 0 ? 0
1445 :
static_cast<size_t>(std::distance(
1446 mKeyVals, reinterpret_cast_no_cast_align_warning<Node*>(mInfo)));
1449 void cloneData(
const Table& o) {
1450 Cloner<Table, IsFlat && ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(Node)>()(o, *
this);
1455 void insert_move(Node&& keyval) {
1458 if (0 == mMaxNumElementsAllowed && !try_increase_info()) {
1459 throwOverflowError();
1464 keyToIdx(keyval.getFirst(), &idx, &info);
1467 while (info <= mInfo[idx]) {
1473 auto const insertion_idx = idx;
1474 auto const insertion_info =
static_cast<uint8_t
>(info);
1476 mMaxNumElementsAllowed = 0;
1480 while (0 != mInfo[idx]) {
1484 auto& l = mKeyVals[insertion_idx];
1485 if (idx == insertion_idx) {
1486 ::new (
static_cast<void*
>(&l)) Node(std::move(keyval));
1488 shiftUp(idx, insertion_idx);
1489 l = std::move(keyval);
1493 mInfo[insertion_idx] = insertion_info;
1502 Table() noexcept(noexcept(Hash()) && noexcept(KeyEqual()))
1515 const KeyEqual& equal = KeyEqual{})
noexcept(
noexcept(Hash(h)) &&
noexcept(KeyEqual(equal)))
1517 , WKeyEqual(equal) {
1521 template <
typename Iter>
1523 const Hash& h = Hash{},
const KeyEqual& equal = KeyEqual{})
1525 , WKeyEqual(equal) {
1532 const KeyEqual& equal = KeyEqual{})
1534 , WKeyEqual(equal) {
1545 mHashMultiplier = std::move(o.mHashMultiplier);
1546 mKeyVals = std::move(o.mKeyVals);
1547 mInfo = std::move(o.mInfo);
1548 mNumElements = std::move(o.mNumElements);
1549 mMask = std::move(o.mMask);
1550 mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);
1551 mInfoInc = std::move(o.mInfoInc);
1552 mInfoHashShift = std::move(o.mInfoHashShift);
1564 mHashMultiplier = std::move(o.mHashMultiplier);
1565 mKeyVals = std::move(o.mKeyVals);
1566 mInfo = std::move(o.mInfo);
1567 mNumElements = std::move(o.mNumElements);
1568 mMask = std::move(o.mMask);
1569 mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);
1570 mInfoInc = std::move(o.mInfoInc);
1571 mInfoHashShift = std::move(o.mInfoHashShift);
1572 WHash::operator=(std::move(
static_cast<WHash&
>(o)));
1573 WKeyEqual::operator=(std::move(
static_cast<WKeyEqual&
>(o)));
1574 DataPool::operator=(std::move(
static_cast<DataPool&
>(o)));
1596 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
1598 ROBIN_HOOD_LOG(
"std::malloc " << numBytesTotal <<
" = calcNumBytesTotal("
1599 << numElementsWithBuffer <<
")")
1600 mHashMultiplier = o.mHashMultiplier;
1601 mKeyVals =
static_cast<Node*
>(
1602 detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
1604 mInfo =
reinterpret_cast<uint8_t*
>(mKeyVals + numElementsWithBuffer);
1605 mNumElements = o.mNumElements;
1607 mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;
1608 mInfoInc = o.mInfoInc;
1609 mInfoHashShift = o.mInfoHashShift;
1636 WHash::operator=(
static_cast<const WHash&
>(o));
1637 WKeyEqual::operator=(
static_cast<const WKeyEqual&
>(o));
1638 DataPool::operator=(
static_cast<DataPool const&
>(o));
1644 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*
this);
1646 if (mMask != o.mMask) {
1651 std::free(mKeyVals);
1655 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
1656 ROBIN_HOOD_LOG(
"std::malloc " << numBytesTotal <<
" = calcNumBytesTotal("
1657 << numElementsWithBuffer <<
")")
1658 mKeyVals =
static_cast<Node*
>(
1659 detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
1662 mInfo =
reinterpret_cast<uint8_t*
>(mKeyVals + numElementsWithBuffer);
1665 WHash::operator=(
static_cast<const WHash&
>(o));
1666 WKeyEqual::operator=(
static_cast<const WKeyEqual&
>(o));
1667 DataPool::operator=(
static_cast<DataPool const&
>(o));
1668 mHashMultiplier = o.mHashMultiplier;
1669 mNumElements = o.mNumElements;
1671 mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;
1672 mInfoInc = o.mInfoInc;
1673 mInfoHashShift = o.mInfoHashShift;
1695 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*
this);
1699 uint8_t
const z = 0;
1700 std::fill(mInfo, mInfo + calcNumBytesInfo(numElementsWithBuffer), z);
1701 mInfo[numElementsWithBuffer] = 1;
1703 mInfoInc = InitialInfoInc;
1704 mInfoHashShift = InitialInfoHashShift;
1719 for (
auto const& otherEntry : other) {
1720 if (!has(otherEntry)) {
1733 template <
typename Q = mapped_type>
1736 auto idxAndState = insertKeyPrepareEmptySpot(key);
1737 switch (idxAndState.second) {
1738 case InsertionState::key_found:
1741 case InsertionState::new_node:
1742 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first]))
1743 Node(*
this, std::piecewise_construct, std::forward_as_tuple(key),
1744 std::forward_as_tuple());
1747 case InsertionState::overwrite_node:
1748 mKeyVals[idxAndState.first] = Node(*
this, std::piecewise_construct,
1749 std::forward_as_tuple(key), std::forward_as_tuple());
1752 case InsertionState::overflow_error:
1753 throwOverflowError();
1756 return mKeyVals[idxAndState.first].getSecond();
1759 template <
typename Q = mapped_type>
1762 auto idxAndState = insertKeyPrepareEmptySpot(key);
1763 switch (idxAndState.second) {
1764 case InsertionState::key_found:
1767 case InsertionState::new_node:
1768 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first]))
1769 Node(*
this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),
1770 std::forward_as_tuple());
1773 case InsertionState::overwrite_node:
1774 mKeyVals[idxAndState.first] =
1775 Node(*
this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),
1776 std::forward_as_tuple());
1779 case InsertionState::overflow_error:
1780 throwOverflowError();
1783 return mKeyVals[idxAndState.first].getSecond();
1786 template <
typename Iter>
1788 for (; first != last; ++first) {
1794 void insert(std::initializer_list<value_type> ilist) {
1795 for (
auto&& vt : ilist) {
1800 template <
typename... Args>
1801 std::pair<iterator, bool>
emplace(Args&&... args) {
1803 Node n{*
this, std::forward<Args>(args)...};
1804 auto idxAndState = insertKeyPrepareEmptySpot(getFirstConst(n));
1805 switch (idxAndState.second) {
1806 case InsertionState::key_found:
1810 case InsertionState::new_node:
1811 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(*
this, std::move(n));
1814 case InsertionState::overwrite_node:
1815 mKeyVals[idxAndState.first] = std::move(n);
1818 case InsertionState::overflow_error:
1820 throwOverflowError();
1824 return std::make_pair(
iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
1825 InsertionState::key_found != idxAndState.second);
1828 template <
typename... Args>
1831 return emplace(std::forward<Args>(args)...).first;
1834 template <
typename... Args>
1836 return try_emplace_impl(key, std::forward<Args>(args)...);
1839 template <
typename... Args>
1841 return try_emplace_impl(std::move(key), std::forward<Args>(args)...);
1844 template <
typename... Args>
1847 return try_emplace_impl(key, std::forward<Args>(args)...).first;
1850 template <
typename... Args>
1853 return try_emplace_impl(std::move(key), std::forward<Args>(args)...).first;
1856 template <
typename Mapped>
1858 return insertOrAssignImpl(key, std::forward<Mapped>(obj));
1861 template <
typename Mapped>
1863 return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj));
1866 template <
typename Mapped>
1869 return insertOrAssignImpl(key, std::forward<Mapped>(obj)).first;
1872 template <
typename Mapped>
1875 return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj)).first;
1889 return emplace(std::move(keyval));
1894 return emplace(std::move(keyval)).first;
1900 auto kv = mKeyVals + findIdx(key);
1901 if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1907 template <
typename OtherKey,
typename Self_ = Self>
1909 typename std::enable_if<Self_::is_transparent, size_t>::type
count(
const OtherKey& key)
const {
1911 auto kv = mKeyVals + findIdx(key);
1912 if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1919 return 1U ==
count(key);
1922 template <
typename OtherKey,
typename Self_ = Self>
1924 typename std::enable_if<Self_::is_transparent, bool>::type
contains(
const OtherKey& key)
const {
1925 return 1U ==
count(key);
1930 template <
typename Q = mapped_type>
1932 typename std::enable_if<!std::is_void<Q>::value, Q&>::type
at(
key_type const& key) {
1934 auto kv = mKeyVals + findIdx(key);
1935 if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1936 doThrow<std::out_of_range>(
"key not found");
1938 return kv->getSecond();
1943 template <
typename Q = mapped_type>
1945 typename std::enable_if<!std::is_void<Q>::value, Q
const&>::type
at(
key_type const& key)
const {
1947 auto kv = mKeyVals + findIdx(key);
1948 if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1949 doThrow<std::out_of_range>(
"key not found");
1951 return kv->getSecond();
1956 const size_t idx = findIdx(key);
1960 template <
typename OtherKey>
1963 const size_t idx = findIdx(key);
1967 template <
typename OtherKey,
typename Self_ = Self>
1968 typename std::enable_if<Self_::is_transparent,
1972 const size_t idx = findIdx(key);
1978 const size_t idx = findIdx(key);
1979 return iterator{mKeyVals + idx, mInfo + idx};
1982 template <
typename OtherKey>
1985 const size_t idx = findIdx(key);
1986 return iterator{mKeyVals + idx, mInfo + idx};
1989 template <
typename OtherKey,
typename Self_ = Self>
1990 typename std::enable_if<Self_::is_transparent, iterator>::type
find(
const OtherKey& key) {
1992 const size_t idx = findIdx(key);
1993 return iterator{mKeyVals + idx, mInfo + idx};
2001 return iterator(mKeyVals, mInfo, fast_forward_tag{});
2019 return iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo),
nullptr};
2027 return const_iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo),
nullptr};
2034 return erase(
iterator{
const_cast<Node*
>(pos.mKeyVals),
const_cast<uint8_t*
>(pos.mInfo)});
2041 auto const idx =
static_cast<size_t>(pos.mKeyVals - mKeyVals);
2059 keyToIdx(key, &idx, &info);
2063 if (info == mInfo[idx] && WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
2069 }
while (info <= mInfo[idx]);
2093 auto newSize = InitialNumElements;
2094 while (calcMaxNumElementsAllowed(newSize) < mNumElements && newSize != 0) {
2098 throwOverflowError();
2101 ROBIN_HOOD_LOG(
"newSize > mMask + 1: " << newSize <<
" > " << mMask <<
" + 1")
2105 if (newSize < mMask + 1) {
2106 rehashPowerOfTwo(newSize,
true);
2112 return mNumElements;
2122 return 0 == mNumElements;
2127 return MaxLoadFactor100 / 100.0F;
2133 return static_cast<float>(
size()) /
static_cast<float>(mMask + 1);
2141 ROBIN_HOOD(NODISCARD)
size_t calcMaxNumElementsAllowed(
size_t maxElements)
const noexcept {
2142 if (
ROBIN_HOOD_LIKELY(maxElements <= (std::numeric_limits<size_t>::max)() / 100)) {
2143 return maxElements * MaxLoadFactor100 / 100;
2147 return (maxElements / 100) * MaxLoadFactor100;
2150 ROBIN_HOOD(NODISCARD)
size_t calcNumBytesInfo(
size_t numElements)
const noexcept {
2153 return numElements +
sizeof(uint64_t);
2158 auto maxNumElementsAllowed = calcMaxNumElementsAllowed(numElements);
2159 return numElements + (std::min)(maxNumElementsAllowed, (
static_cast<size_t>(0xFF)));
2163 ROBIN_HOOD(NODISCARD)
size_t calcNumBytesTotal(
size_t numElements)
const {
2164#if ROBIN_HOOD(BITNESS) == 64
2165 return numElements *
sizeof(Node) + calcNumBytesInfo(numElements);
2168 auto const ne =
static_cast<uint64_t
>(numElements);
2169 auto const s =
static_cast<uint64_t
>(
sizeof(Node));
2170 auto const infos =
static_cast<uint64_t
>(calcNumBytesInfo(numElements));
2172 auto const total64 = ne * s + infos;
2173 auto const total =
static_cast<size_t>(total64);
2176 throwOverflowError();
2183 template <
typename Q = mapped_type>
2185 typename std::enable_if<!std::is_void<Q>::value,
bool>::type has(
const value_type& e)
const {
2187 auto it =
find(e.first);
2188 return it !=
end() && it->second == e.second;
2193 typename
std::enable_if<
std::is_void<Q>::value,
bool>::type has(const
value_type& e)
const {
2198 void reserve(
size_t c,
bool forceRehash) {
2200 auto const minElementsAllowed = (
std::max)(c, mNumElements);
2201 auto newSize = InitialNumElements;
2202 while (calcMaxNumElementsAllowed(newSize) < minElementsAllowed && newSize != 0) {
2206 throwOverflowError();
2209 ROBIN_HOOD_LOG(
"newSize > mMask + 1: " << newSize <<
" > " << mMask <<
" + 1")
2213 if (forceRehash || newSize > mMask + 1) {
2214 rehashPowerOfTwo(newSize,
false);
2221 void rehashPowerOfTwo(
size_t numBuckets,
bool forceFree) {
2224 Node* const oldKeyVals = mKeyVals;
2225 uint8_t const* const oldInfo = mInfo;
2230 initData(numBuckets);
2231 if (oldMaxElementsWithBuffer > 1) {
2232 for (
size_t i = 0; i < oldMaxElementsWithBuffer; ++i) {
2233 if (oldInfo[i] != 0) {
2236 insert_move(std::move(oldKeyVals[i]));
2238 oldKeyVals[i].~Node();
2245 if (oldKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
2248 std::free(oldKeyVals);
2250 DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer));
2256 ROBIN_HOOD(NOINLINE)
void throwOverflowError()
const {
2257#if ROBIN_HOOD(HAS_EXCEPTIONS)
2258 throw std::overflow_error(
"robin_hood::map overflow");
2264 template <
typename OtherKey,
typename... Args>
2265 std::pair<iterator, bool> try_emplace_impl(OtherKey&& key, Args&&... args) {
2267 auto idxAndState = insertKeyPrepareEmptySpot(key);
2268 switch (idxAndState.second) {
2269 case InsertionState::key_found:
2272 case InsertionState::new_node:
2273 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(
2274 *
this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
2275 std::forward_as_tuple(std::forward<Args>(args)...));
2278 case InsertionState::overwrite_node:
2279 mKeyVals[idxAndState.first] = Node(*
this, std::piecewise_construct,
2280 std::forward_as_tuple(std::forward<OtherKey>(key)),
2281 std::forward_as_tuple(std::forward<Args>(args)...));
2284 case InsertionState::overflow_error:
2285 throwOverflowError();
2289 return std::make_pair(
iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
2290 InsertionState::key_found != idxAndState.second);
2293 template <
typename OtherKey,
typename Mapped>
2294 std::pair<iterator, bool> insertOrAssignImpl(OtherKey&& key, Mapped&& obj) {
2296 auto idxAndState = insertKeyPrepareEmptySpot(key);
2297 switch (idxAndState.second) {
2298 case InsertionState::key_found:
2299 mKeyVals[idxAndState.first].getSecond() = std::forward<Mapped>(obj);
2302 case InsertionState::new_node:
2303 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(
2304 *
this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
2305 std::forward_as_tuple(std::forward<Mapped>(obj)));
2308 case InsertionState::overwrite_node:
2309 mKeyVals[idxAndState.first] = Node(*
this, std::piecewise_construct,
2310 std::forward_as_tuple(std::forward<OtherKey>(key)),
2311 std::forward_as_tuple(std::forward<Mapped>(obj)));
2314 case InsertionState::overflow_error:
2315 throwOverflowError();
2319 return std::make_pair(
iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
2320 InsertionState::key_found != idxAndState.second);
2323 void initData(
size_t max_elements) {
2325 mMask = max_elements - 1;
2326 mMaxNumElementsAllowed = calcMaxNumElementsAllowed(max_elements);
2331 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
2332 ROBIN_HOOD_LOG(
"std::calloc " << numBytesTotal <<
" = calcNumBytesTotal("
2333 << numElementsWithBuffer <<
")")
2334 mKeyVals = reinterpret_cast<Node*>(
2336 mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);
2337 std::memset(mInfo, 0, numBytesTotal - numElementsWithBuffer * sizeof(Node));
2340 mInfo[numElementsWithBuffer] = 1;
2342 mInfoInc = InitialInfoInc;
2343 mInfoHashShift = InitialInfoHashShift;
2346 enum class InsertionState { overflow_error, key_found, new_node, overwrite_node };
2351 template <
typename OtherKey>
2352 std::pair<size_t, InsertionState> insertKeyPrepareEmptySpot(OtherKey&& key) {
2353 for (
int i = 0; i < 256; ++i) {
2356 keyToIdx(key, &idx, &info);
2357 nextWhileLess(&info, &idx);
2360 while (info == mInfo[idx]) {
2361 if (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
2364 return std::make_pair(idx, InsertionState::key_found);
2371 if (!increase_size()) {
2372 return std::make_pair(
size_t(0), InsertionState::overflow_error);
2378 auto const insertion_idx = idx;
2379 auto const insertion_info = info;
2381 mMaxNumElementsAllowed = 0;
2385 while (0 != mInfo[idx]) {
2389 if (idx != insertion_idx) {
2390 shiftUp(idx, insertion_idx);
2393 mInfo[insertion_idx] =
static_cast<uint8_t
>(insertion_info);
2395 return std::make_pair(insertion_idx, idx == insertion_idx
2396 ? InsertionState::new_node
2397 : InsertionState::overwrite_node);
2401 return std::make_pair(
size_t(0), InsertionState::overflow_error);
2404 bool try_increase_info() {
2405 ROBIN_HOOD_LOG(
"mInfoInc=" << mInfoInc <<
", numElements=" << mNumElements
2406 <<
", maxNumElementsAllowed="
2407 << calcMaxNumElementsAllowed(mMask + 1))
2408 if (mInfoInc <= 2) {
2413 mInfoInc =
static_cast<uint8_t
>(mInfoInc >> 1U);
2420 for (
size_t i = 0; i < numElementsWithBuffer; i += 8) {
2421 auto val = unaligned_load<uint64_t>(mInfo + i);
2422 val = (val >> 1U) & UINT64_C(0x7f7f7f7f7f7f7f7f);
2423 std::memcpy(mInfo + i, &val,
sizeof(val));
2426 mInfo[numElementsWithBuffer] = 1;
2428 mMaxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
2433 bool increase_size() {
2436 initData(InitialNumElements);
2440 auto const maxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
2441 if (mNumElements < maxNumElementsAllowed && try_increase_info()) {
2445 ROBIN_HOOD_LOG(
"mNumElements=" << mNumElements <<
", maxNumElementsAllowed="
2446 << maxNumElementsAllowed <<
", load="
2447 << (
static_cast<double>(mNumElements) * 100.0 /
2448 (
static_cast<double>(mMask) + 1)))
2450 if (mNumElements * 2 < calcMaxNumElementsAllowed(mMask + 1)) {
2454 nextHashMultiplier();
2455 rehashPowerOfTwo(mMask + 1,
true);
2458 rehashPowerOfTwo((mMask + 1) * 2,
false);
2463 void nextHashMultiplier() {
2466 mHashMultiplier += UINT64_C(0xc4ceb9fe1a85ec54);
2475 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}
2476 .nodesDoNotDeallocate(*
this);
2482 if (mKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
2484 std::free(mKeyVals);
2488 void init() noexcept {
2489 mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);
2490 mInfo =
reinterpret_cast<uint8_t*
>(&mMask);
2493 mMaxNumElementsAllowed = 0;
2494 mInfoInc = InitialInfoInc;
2495 mInfoHashShift = InitialInfoHashShift;
2499 uint64_t mHashMultiplier = UINT64_C(0xc4ceb9fe1a85ec53);
2500 Node* mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);
2501 uint8_t* mInfo =
reinterpret_cast<uint8_t*
>(&mMask);
2502 size_t mNumElements = 0;
2504 size_t mMaxNumElementsAllowed = 0;
2505 InfoType mInfoInc = InitialInfoInc;
2506 InfoType mInfoHashShift = InitialInfoHashShift;
2513#if defined(__clang__)
2514#pragma clang diagnostic pop
2519template <
typename Key,
typename T,
typename Hash = hash<Key>,
2520 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2523template <
typename Key,
typename T,
typename Hash = hash<Key>,
2524 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2527template <
typename Key,
typename T,
typename Hash = hash<Key>,
2528 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2531 std::is_nothrow_move_constructible<robin_hood::pair<Key, T>>::value &&
2532 std::is_nothrow_move_assignable<robin_hood::pair<Key, T>>::value,
2533 MaxLoadFactor100, Key, T, Hash, KeyEqual>;
2537template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2538 size_t MaxLoadFactor100 = 80>
2541template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2542 size_t MaxLoadFactor100 = 80>
2545template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2546 size_t MaxLoadFactor100 = 80>
2548 std::is_nothrow_move_constructible<Key>::value &&
2549 std::is_nothrow_move_assignable<Key>::value,
2550 MaxLoadFactor100, Key, void, Hash, KeyEqual>;
Definition robin_hood.h:246
static constexpr std::size_t size() noexcept
Definition robin_hood.h:250
T value_type
Definition robin_hood.h:248
Definition robin_hood.h:372
~BulkPoolAllocator() noexcept
Definition robin_hood.h:404
BulkPoolAllocator & operator=(BulkPoolAllocator &&o) noexcept
Definition robin_hood.h:388
void swap(BulkPoolAllocator< T, MinNumAllocs, MaxNumAllocs > &other) noexcept
Definition robin_hood.h:456
void reset() noexcept
Definition robin_hood.h:409
void deallocate(T *obj) noexcept
Definition robin_hood.h:436
BulkPoolAllocator & operator=(const BulkPoolAllocator &ROBIN_HOOD_UNUSED(o)) noexcept
Definition robin_hood.h:399
BulkPoolAllocator() noexcept=default
BulkPoolAllocator(BulkPoolAllocator &&o) noexcept
Definition robin_hood.h:381
T * allocate()
Definition robin_hood.h:422
void addOrFree(void *ptr, const size_t numBytes) noexcept
Definition robin_hood.h:444
Definition robin_hood.h:921
void rehash(size_t c)
Definition robin_hood.h:2077
std::enable_if< Self_::is_transparent, const_iterator >::type find(const OtherKey &key) const
Definition robin_hood.h:1970
iterator find(const key_type &key)
Definition robin_hood.h:1976
iterator erase(const_iterator pos)
Definition robin_hood.h:2030
const_iterator cend() const
Definition robin_hood.h:2025
static constexpr bool is_map
Definition robin_hood.h:924
Hash hasher
Definition robin_hood.h:935
std::pair< iterator, bool > try_emplace(const key_type &key, Args &&... args)
Definition robin_hood.h:1835
Iter< true > const_iterator
Definition robin_hood.h:1500
std::pair< iterator, bool > try_emplace(key_type &&key, Args &&... args)
Definition robin_hood.h:1840
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:1513
void swap(Table &o)
Definition robin_hood.h:1680
const_iterator end() const
Definition robin_hood.h:2021
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:1522
Table & operator=(Table const &o)
Definition robin_hood.h:1617
void compact()
Definition robin_hood.h:2091
ROBIN_HOOD(NODISCARD) size_t calcMaxNumElementsAllowed(size_t maxElements) const noexcept
Definition robin_hood.h:2141
iterator insert(const_iterator hint, value_type &&keyval)
Definition robin_hood.h:1892
std::pair< iterator, bool > insert(value_type &&keyval)
Definition robin_hood.h:1888
Iter< false > iterator
Definition robin_hood.h:1499
bool operator==(const Table &other) const
Definition robin_hood.h:1714
std::pair< iterator, bool > insert_or_assign(key_type &&key, Mapped &&obj)
Definition robin_hood.h:1862
std::pair< iterator, bool > insert_or_assign(const key_type &key, Mapped &&obj)
Definition robin_hood.h:1857
ROBIN_HOOD(NODISCARD) bool empty() const noexcept
Definition robin_hood.h:2120
void clear()
Definition robin_hood.h:1687
ROBIN_HOOD(NODISCARD) size_t calcNumBytesInfo(size_t numElements) const noexcept
Definition robin_hood.h:2150
void reserve(size_t c)
Definition robin_hood.h:2084
bool operator!=(const Table &other) const
Definition robin_hood.h:1728
Key key_type
Definition robin_hood.h:929
const_iterator find(const key_type &key) const
Definition robin_hood.h:1954
iterator end()
Definition robin_hood.h:2015
bool contains(const key_type &key) const
Definition robin_hood.h:1918
iterator find(const OtherKey &key, is_transparent_tag)
Definition robin_hood.h:1983
size_t size_type
Definition robin_hood.h:934
size_t erase(const key_type &key)
Definition robin_hood.h:2055
std::enable_if<!std::is_void< Q >::value, Q & >::type operator[](const key_type &key)
Definition robin_hood.h:1734
const_iterator begin() const
Definition robin_hood.h:2003
size_t count(const key_type &key) const
Definition robin_hood.h:1898
iterator try_emplace(const_iterator hint, const key_type &key, Args &&... args)
Definition robin_hood.h:1845
const_iterator cbegin() const
Definition robin_hood.h:2007
std::enable_if<!std::is_void< Q >::value, Qconst & >::type at(key_type const &key) const
Definition robin_hood.h:1945
~Table()
Definition robin_hood.h:1708
size_type size() const noexcept
Definition robin_hood.h:2110
size_t calcNumElementsWithBuffer(size_t numElements) const noexcept
Definition robin_hood.h:2157
KeyEqual key_equal
Definition robin_hood.h:936
void insert(std::initializer_list< value_type > ilist)
Definition robin_hood.h:1794
iterator insert_or_assign(const_iterator hint, const key_type &key, Mapped &&obj)
Definition robin_hood.h:1867
iterator emplace_hint(const_iterator position, Args &&... args)
Definition robin_hood.h:1829
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:933
float load_factor() const noexcept
Definition robin_hood.h:2131
std::enable_if< Self_::is_transparent, iterator >::type find(const OtherKey &key)
Definition robin_hood.h:1990
float max_load_factor() const noexcept
Definition robin_hood.h:2125
ROBIN_HOOD(NODISCARD) size_t calcNumBytesTotal(size_t numElements) const
Definition robin_hood.h:2163
ROBIN_HOOD(NODISCARD) size_t mask() const noexcept
Definition robin_hood.h:2136
std::pair< iterator, bool > insert(const value_type &keyval)
Definition robin_hood.h:1878
size_type max_size() const noexcept
Definition robin_hood.h:2115
iterator insert(const_iterator hint, const value_type &keyval)
Definition robin_hood.h:1883
static constexpr bool is_flat
Definition robin_hood.h:923
std::pair< iterator, bool > emplace(Args &&... args)
Definition robin_hood.h:1801
T mapped_type
Definition robin_hood.h:930
Table() noexcept(noexcept(Hash()) &&noexcept(KeyEqual()))
Definition robin_hood.h:1502
iterator begin()
Definition robin_hood.h:1996
Table & operator=(Table &&o) noexcept
Definition robin_hood.h:1558
const_iterator find(const OtherKey &key, is_transparent_tag) const
Definition robin_hood.h:1961
std::enable_if< Self_::is_transparent, bool >::type contains(const OtherKey &key) const
Definition robin_hood.h:1924
iterator try_emplace(const_iterator hint, key_type &&key, Args &&... args)
Definition robin_hood.h:1851
std::enable_if< Self_::is_transparent, size_t >::type count(const OtherKey &key) const
Definition robin_hood.h:1909
Table(const Table &o)
Definition robin_hood.h:1586
iterator insert_or_assign(const_iterator hint, key_type &&key, Mapped &&obj)
Definition robin_hood.h:1873
static constexpr bool is_transparent
Definition robin_hood.h:926
static constexpr bool is_set
Definition robin_hood.h:925
iterator erase(iterator pos)
Definition robin_hood.h:2038
std::enable_if<!std::is_void< Q >::value, Q & >::type operator[](key_type &&key)
Definition robin_hood.h:1760
void insert(Iter first, Iter last)
Definition robin_hood.h:1787
std::enable_if<!std::is_void< Q >::value, Q & >::type at(key_type const &key)
Definition robin_hood.h:1932
typename detail_::IntSeqImpl< T, 0, N,(N - 0)==1 >::TResult make_integer_sequence
Definition robin_hood.h:297
make_index_sequence< sizeof...(T)> index_sequence_for
Definition robin_hood.h:303
make_integer_sequence< std::size_t, N > make_index_sequence
Definition robin_hood.h:300
T reinterpret_cast_no_cast_align_warning(void *ptr) noexcept
Definition robin_hood.h:327
T unaligned_load(void const *ptr) noexcept
Definition robin_hood.h:360
T * assertNotNull(T *t, Args &&... args)
Definition robin_hood.h:352
uint32_t SizeT
Definition robin_hood.h:315
T rotr(T x, unsigned k)
Definition robin_hood.h:319
Definition robin_hood.h:233
constexpr bool operator==(pair< A, B > const &x, pair< A, B > const &y)
Definition robin_hood.h:671
constexpr bool operator<=(pair< A, B > const &x, pair< A, B > const &y)
Definition robin_hood.h:689
constexpr bool operator>(pair< A, B > const &x, pair< A, B > const &y)
Definition robin_hood.h:685
constexpr bool operator!=(pair< A, B > const &x, pair< A, B > const &y)
Definition robin_hood.h:675
size_t hash_int(uint64_t x) noexcept
Definition robin_hood.h:753
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:665
size_t hash_bytes(void const *ptr, size_t len) noexcept
Definition robin_hood.h:697
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:679
constexpr bool operator>=(pair< A, B > const &x, pair< A, B > const &y)
Definition robin_hood.h:693
Definition jobManagement.cpp:168
#define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x)
Definition robin_hood.h:160
#define ROBIN_HOOD_COUNT_LEADING_ZEROES(x)
Definition robin_hood.h:159
#define ROBIN_HOOD_UNUSED(identifier)
Definition robin_hood.h:100
#define ROBIN_HOOD_COUNT(x)
Definition robin_hood.h:92
#define ROBIN_HOOD_TRACE(x)
Definition robin_hood.h:70
#define ROBIN_HOOD_HASH_INT(T)
Definition robin_hood.h:823
#define ROBIN_HOOD(x)
Definition robin_hood.h:97
#define ROBIN_HOOD_UNLIKELY(condition)
Definition robin_hood.h:182
#define ROBIN_HOOD_LIKELY(condition)
Definition robin_hood.h:181
#define ROBIN_HOOD_LOG(x)
Definition robin_hood.h:61
Definition robin_hood.h:243
Definition robin_hood.h:265
T TValue
Definition robin_hood.h:281
T TValue
Definition robin_hood.h:289
Definition robin_hood.h:259
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:276
T TValue
Definition robin_hood.h:260
void addOrFree(void *ptr, size_t ROBIN_HOOD_UNUSED(numBytes)) noexcept
Definition robin_hood.h:553
Definition robin_hood.h:546
Definition robin_hood.h:873
WrapHash(T const &o) noexcept(noexcept(T(std::declval< T const & >())))
Definition robin_hood.h:875
Definition robin_hood.h:880
WrapKeyEqual(T const &o) noexcept(noexcept(T(std::declval< T const & >())))
Definition robin_hood.h:882
Definition robin_hood.h:864
Definition robin_hood.h:568
static const bool value
Definition robin_hood.h:569
Definition robin_hood.h:859
void type
Definition robin_hood.h:860
size_t operator()(Enum e) const noexcept
Definition robin_hood.h:817
size_t operator()(T *ptr) const noexcept
Definition robin_hood.h:796
size_t operator()(std::basic_string< CharT > const &str) const noexcept
Definition robin_hood.h:780
size_t operator()(std::shared_ptr< T > const &ptr) const noexcept
Definition robin_hood.h:810
size_t operator()(std::unique_ptr< T > const &ptr) const noexcept
Definition robin_hood.h:803
Definition robin_hood.h:768
size_t operator()(T const &obj) const noexcept(noexcept(std::declval< std::hash< T > >().operator()(std::declval< T const & >())))
Definition robin_hood.h:769
Definition robin_hood.h:581
Definition robin_hood.h:587
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:627
void swap(pair< T1, T2 > &o) noexcept((detail::swappable::nothrow< T1 >::value) &&(detail::swappable::nothrow< T2 >::value))
Definition robin_hood.h:653
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:605
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:639
T2 second
Definition robin_hood.h:661
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:610
T1 first
Definition robin_hood.h:660
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:616
T2 second_type
Definition robin_hood.h:589
T1 first_type
Definition robin_hood.h:588
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:599
constexpr pair() noexcept(noexcept(U1()) &&noexcept(U2()))
Definition robin_hood.h:594