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
216#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX() __cplusplus
217#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX98() 199711L
218#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX11() 201103L
219#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX14() 201402L
220#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX17() 201703L
222#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)
223# define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD() [[nodiscard]]
225# define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD()
230#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)
231# define ROBIN_HOOD_STD std
235namespace ROBIN_HOOD_STD {
238 : std::integral_constant<std::size_t, alignof(typename std::remove_all_extents<T>::type)> {};
240template <
class T, T... Ints>
244 static_assert(std::is_integral<value_type>::value,
"not integral type");
245 static constexpr std::size_t
size() noexcept {
246 return sizeof...(Ints);
249template <std::size_t... Inds>
253template <
class T, T Begin, T End,
bool>
256 static_assert(std::is_integral<TValue>::value,
"not integral type");
257 static_assert(Begin >= 0 && Begin < End,
"unexpected argument (Begin<0 || Begin<=End)");
259 template <
class,
class>
274template <
class T, T Begin>
277 static_assert(std::is_integral<TValue>::value,
"not integral type");
278 static_assert(Begin >= 0,
"unexpected argument (Begin<0)");
282template <
class T, T Begin, T End>
285 static_assert(std::is_integral<TValue>::value,
"not integral type");
286 static_assert(Begin >= 0,
"unexpected argument (Begin<0)");
291template <
class T, T N>
294template <std::
size_t N>
307#if ROBIN_HOOD(BITNESS) == 64
308using SizeT = uint64_t;
315 return (x >> k) | (x << (8U *
sizeof(T) - k));
323 return reinterpret_cast<T
>(ptr);
328 return reinterpret_cast<T
>(ptr);
333template <
typename E,
typename... Args>
335#if ROBIN_HOOD(HAS_EXCEPTIONS)
336 void doThrow(Args&&... args) {
338 throw E(std::forward<Args>(args)...);
346template <
typename E,
typename T,
typename... Args>
349 doThrow<E>(std::forward<Args>(args)...);
359 std::memcpy(&t, ptr,
sizeof(T));
366template <
typename T,
size_t MinNumAllocs = 4,
size_t MaxNumAllocs = 256>
374 , mListForFree(
nullptr) {}
378 , mListForFree(o.mListForFree) {
379 o.mListForFree =
nullptr;
386 mListForFree = o.mListForFree;
387 o.mListForFree =
nullptr;
405 while (mListForFree) {
406 T* tmp = *mListForFree;
408 std::free(mListForFree);
409 mListForFree = reinterpret_cast_no_cast_align_warning<T**>(tmp);
420 tmp = performAllocation();
423 mHead = *reinterpret_cast_no_cast_align_warning<T**>(tmp);
432 *reinterpret_cast_no_cast_align_warning<T**>(obj) = mHead;
439 void addOrFree(
void* ptr,
const size_t numBytes)
noexcept {
441 if (numBytes < ALIGNMENT + ALIGNED_SIZE) {
453 swap(mHead, other.mHead);
454 swap(mListForFree, other.mListForFree);
462 ROBIN_HOOD(NODISCARD)
size_t calcNumElementsToAlloc() const noexcept {
463 auto tmp = mListForFree;
464 size_t numAllocs = MinNumAllocs;
466 while (numAllocs * 2 <= MaxNumAllocs && tmp) {
467 auto x =
reinterpret_cast<T***
>(tmp);
476 void add(
void* ptr,
const size_t numBytes)
noexcept {
477 const size_t numElements = (numBytes - ALIGNMENT) / ALIGNED_SIZE;
479 auto data =
reinterpret_cast<T**
>(ptr);
482 auto x =
reinterpret_cast<T***
>(data);
488 reinterpret_cast_no_cast_align_warning<T*>(
reinterpret_cast<char*
>(ptr) + ALIGNMENT);
490 auto*
const head =
reinterpret_cast<char*
>(headT);
493 for (
size_t i = 0; i < numElements; ++i) {
494 *reinterpret_cast_no_cast_align_warning<char**>(head + i * ALIGNED_SIZE) =
495 head + (i + 1) * ALIGNED_SIZE;
499 *reinterpret_cast_no_cast_align_warning<T**>(head + (numElements - 1) * ALIGNED_SIZE) =
507 size_t const numElementsToAlloc = calcNumElementsToAlloc();
510 size_t const bytes = ALIGNMENT + ALIGNED_SIZE * numElementsToAlloc;
511 ROBIN_HOOD_LOG(
"std::malloc " << bytes <<
" = " << ALIGNMENT <<
" + " << ALIGNED_SIZE
512 <<
" * " << numElementsToAlloc)
513 add(assertNotNull<std::bad_alloc>(std::malloc(bytes)), bytes);
518#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)
519 static constexpr size_t ALIGNMENT =
520 (std::max)(std::alignment_of<T>::value, std::alignment_of<T*>::value);
522 static const size_t ALIGNMENT =
523 (ROBIN_HOOD_STD::alignment_of<T>::value > ROBIN_HOOD_STD::alignment_of<T*>::value)
524 ? ROBIN_HOOD_STD::alignment_of<T>::value
525 : +ROBIN_HOOD_STD::alignment_of<T*>::value;
528 static constexpr size_t ALIGNED_SIZE = ((
sizeof(T) - 1) / ALIGNMENT + 1) * ALIGNMENT;
530 static_assert(MinNumAllocs >= 1,
"MinNumAllocs");
531 static_assert(MaxNumAllocs >= MinNumAllocs,
"MaxNumAllocs");
532 static_assert(ALIGNED_SIZE >=
sizeof(T*),
"ALIGNED_SIZE");
533 static_assert(0 == (ALIGNED_SIZE %
sizeof(T*)),
"ALIGNED_SIZE mod");
534 static_assert(ALIGNMENT >=
sizeof(T*),
"ALIGNMENT");
537 T** mListForFree{
nullptr};
540template <
typename T,
size_t MinSize,
size_t MaxSize,
bool IsFlat>
544template <
typename T,
size_t MinSize,
size_t MaxSize>
554template <
typename T,
size_t MinSize,
size_t MaxSize>
560#if ROBIN_HOOD(CXX) < ROBIN_HOOD(CXX17)
564 static const bool value =
noexcept(
swap(std::declval<T&>(), std::declval<T&>()));
569 static const bool value = std::is_nothrow_swappable<T>::value;
581template <
typename T1,
typename T2>
586 template <
typename U1 = T1,
typename U2 = T2,
587 typename =
typename std::enable_if<std::is_default_constructible<U1>::value &&
588 std::is_default_constructible<U2>::value>::type>
589 constexpr pair() noexcept(noexcept(U1()) && noexcept(U2()))
594 explicit constexpr pair(std::pair<T1, T2>
const& o)
noexcept(
595 noexcept(T1(std::declval<T1 const&>())) &&
noexcept(T2(std::declval<T2 const&>())))
600 explicit constexpr pair(std::pair<T1, T2>&& o)
noexcept(
noexcept(
601 T1(std::move(std::declval<T1&&>()))) &&
noexcept(T2(std::move(std::declval<T2&&>()))))
602 :
first(std::move(o.first))
603 ,
second(std::move(o.second)) {}
605 constexpr pair(T1&& a, T2&& b)
noexcept(
noexcept(
606 T1(std::move(std::declval<T1&&>()))) &&
noexcept(T2(std::move(std::declval<T2&&>()))))
607 :
first(std::move(a))
610 template <
typename U1,
typename U2>
611 constexpr pair(U1&& a, U2&& b)
noexcept(
noexcept(T1(std::forward<U1>(
612 std::declval<U1&&>()))) &&
noexcept(T2(std::forward<U2>(std::declval<U2&&>()))))
613 :
first(std::forward<U1>(a))
614 ,
second(std::forward<U2>(b)) {}
616 template <
typename... U1,
typename... U2>
619#if !ROBIN_HOOD(BROKEN_CONSTEXPR)
622 pair(std::piecewise_construct_t , std::tuple<U1...> a,
624 b)
noexcept(
noexcept(
pair(std::declval<std::tuple<U1...>&>(),
625 std::declval<std::tuple<U2...>&>(),
633 template <
typename... U1,
size_t... I1,
typename... U2,
size_t... I2>
635 noexcept(T1(std::forward<U1>(std::get<I1>(
636 std::declval<std::tuple<
637 U1...>&>()))...)) &&
noexcept(T2(std::
638 forward<U2>(std::get<I2>(
639 std::declval<std::tuple<U2...>&>()))...)))
640 :
first(std::forward<U1>(std::get<I1>(a))...)
641 ,
second(std::forward<U2>(std::get<I2>(b))...) {
659template <
typename A,
typename B>
661 noexcept(std::declval<pair<A, B>&>().
swap(std::declval<
pair<A, B>&>()))) {
665template <
typename A,
typename B>
669template <
typename A,
typename B>
673template <
typename A,
typename B>
675 std::declval<A const&>() < std::declval<A const&>()) &&
noexcept(std::declval<B const&>() <
676 std::declval<B const&>())) {
677 return x.first < y.first || (!(y.first < x.first) && x.second < y.second);
679template <
typename A,
typename B>
683template <
typename A,
typename B>
687template <
typename A,
typename B>
692inline size_t hash_bytes(
void const* ptr,
size_t len)
noexcept {
693 static constexpr uint64_t m = UINT64_C(0xc6a4a7935bd1e995);
694 static constexpr uint64_t seed = UINT64_C(0xe17a1465);
695 static constexpr unsigned int r = 47;
697 auto const*
const data64 =
static_cast<uint64_t const*
>(ptr);
698 uint64_t h = seed ^ (len * m);
700 size_t const n_blocks = len / 8;
701 for (
size_t i = 0; i < n_blocks; ++i) {
702 auto k = detail::unaligned_load<uint64_t>(data64 + i);
712 auto const*
const data8 =
reinterpret_cast<uint8_t const*
>(data64 + n_blocks);
715 h ^=
static_cast<uint64_t
>(data8[6]) << 48U;
718 h ^=
static_cast<uint64_t
>(data8[5]) << 40U;
721 h ^=
static_cast<uint64_t
>(data8[4]) << 32U;
724 h ^=
static_cast<uint64_t
>(data8[3]) << 24U;
727 h ^=
static_cast<uint64_t
>(data8[2]) << 16U;
730 h ^=
static_cast<uint64_t
>(data8[1]) << 8U;
733 h ^=
static_cast<uint64_t
>(data8[0]);
745 return static_cast<size_t>(h);
752 x *= UINT64_C(0xff51afd7ed558ccd);
758 return static_cast<size_t>(x);
762template <
typename T,
typename Enable =
void>
763struct hash :
public std::hash<T> {
765 noexcept(
noexcept(std::declval<std::hash<T>>().
operator()(std::declval<T const&>()))) {
767 auto result = std::hash<T>::operator()(obj);
773template <
typename CharT>
774struct hash<std::basic_string<CharT>> {
775 size_t operator()(std::basic_string<CharT>
const& str)
const noexcept {
776 return hash_bytes(str.data(),
sizeof(CharT) * str.size());
780#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)
781template <
typename CharT>
782struct hash<std::basic_string_view<CharT>> {
783 size_t operator()(std::basic_string_view<CharT>
const& sv)
const noexcept {
784 return hash_bytes(sv.data(),
sizeof(CharT) * sv.size());
797struct hash<std::unique_ptr<T>> {
798 size_t operator()(std::unique_ptr<T>
const& ptr)
const noexcept {
804struct hash<std::shared_ptr<T>> {
805 size_t operator()(std::shared_ptr<T>
const& ptr)
const noexcept {
810template <
typename Enum>
811struct hash<Enum, typename std::enable_if<std::is_enum<Enum>::value>::type> {
813 using Underlying =
typename std::underlying_type<Enum>::type;
818#define ROBIN_HOOD_HASH_INT(T) \
821 size_t operator()(T const& obj) const noexcept { \
822 return hash_int(static_cast<uint64_t>(obj)); \
826#if defined(__GNUC__) && !defined(__clang__)
827# pragma GCC diagnostic push
828# pragma GCC diagnostic ignored "-Wuseless-cast"
837#if ROBIN_HOOD(HAS_NATIVE_WCHART)
848#if defined(__GNUC__) && !defined(__clang__)
849# pragma GCC diagnostic pop
858template <
typename T,
typename =
void>
863 :
public std::true_type {};
870 explicit WrapHash(T
const& o)
noexcept(
noexcept(T(std::declval<T const&>())))
877 explicit WrapKeyEqual(T
const& o)
noexcept(
noexcept(T(std::declval<T const&>())))
907template <
bool IsFlat,
size_t MaxLoadFactor100,
typename Key,
typename T,
typename Hash,
913 typename std::conditional<
914 std::is_void<T>::value, Key,
915 robin_hood::pair<typename std::conditional<IsFlat, Key, Key const>::type, T>>::type,
919 static constexpr bool is_map = !std::is_void<T>::value;
935 static_assert(MaxLoadFactor100 > 10 && MaxLoadFactor100 < 100,
936 "MaxLoadFactor100 needs to be >10 && < 100");
944 static constexpr size_t InitialNumElements =
sizeof(uint64_t);
945 static constexpr uint32_t InitialInfoNumBits = 5;
946 static constexpr uint8_t InitialInfoInc = 1U << InitialInfoNumBits;
947 static constexpr size_t InfoMask = InitialInfoInc - 1U;
948 static constexpr uint8_t InitialInfoHashShift = 0;
952 using InfoType = uint32_t;
959 template <
typename M,
bool>
963 template <
typename M>
964 class DataNode<M, true> final {
966 template <
typename... Args>
968 noexcept(
value_type(std::forward<Args>(args)...)))
969 : mData(std::forward<Args>(args)...) {}
972 std::is_nothrow_move_constructible<value_type>::value)
973 : mData(std::move(n.mData)) {}
977 void destroyDoNotDeallocate() noexcept {}
979 value_type const* operator->() const noexcept {
986 const value_type& operator*() const noexcept {
994 template <
typename VT = value_type>
996 typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {
999 template <
typename VT = value_type>
1001 typename std::enable_if<is_set, VT&>::type getFirst() noexcept {
1005 template <
typename VT = value_type>
1007 typename std::enable_if<is_map, typename VT::first_type const&>::type
1008 getFirst() const noexcept {
1011 template <
typename VT = value_type>
1013 typename std::enable_if<is_set, VT const&>::type getFirst() const noexcept {
1017 template <
typename MT = mapped_type>
1019 typename std::enable_if<is_map, MT&>::type getSecond() noexcept {
1020 return mData.second;
1023 template <
typename MT = mapped_type>
1025 typename std::enable_if<is_set, MT const&>::type getSecond() const noexcept {
1026 return mData.second;
1029 void swap(DataNode<M, true>& o)
noexcept(
1030 noexcept(std::declval<value_type>().swap(std::declval<value_type>()))) {
1031 mData.swap(o.mData);
1039 template <
typename M>
1040 class DataNode<M, false> {
1042 template <
typename... Args>
1043 explicit DataNode(M& map, Args&&... args)
1044 : mData(map.allocate()) {
1045 ::new (
static_cast<void*
>(mData))
value_type(std::forward<Args>(args)...);
1049 : mData(std::move(n.mData)) {}
1051 void destroy(M& map)
noexcept {
1053 mData->~value_type();
1054 map.deallocate(mData);
1057 void destroyDoNotDeallocate() noexcept {
1058 mData->~value_type();
1061 value_type const* operator->() const noexcept {
1077 template <
typename VT = value_type>
1079 typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {
1080 return mData->first;
1082 template <
typename VT = value_type>
1084 typename std::enable_if<is_set, VT&>::type getFirst() noexcept {
1088 template <
typename VT = value_type>
1090 typename std::enable_if<is_map, typename VT::first_type const&>::type
1091 getFirst() const noexcept {
1092 return mData->first;
1094 template <
typename VT = value_type>
1096 typename std::enable_if<is_set, VT const&>::type getFirst() const noexcept {
1100 template <
typename MT = mapped_type>
1102 typename std::enable_if<is_map, MT&>::type getSecond() noexcept {
1103 return mData->second;
1106 template <
typename MT = mapped_type>
1108 typename std::enable_if<is_map, MT const&>::type getSecond() const noexcept {
1109 return mData->second;
1112 void swap(DataNode<M, false>& o)
noexcept {
1114 swap(mData, o.mData);
1121 using Node = DataNode<Self, IsFlat>;
1125 return n.getFirst();
1135 template <
typename Q = mapped_type>
1137 typename std::enable_if<!std::is_void<Q>::value,
key_type const&>::type
1138 getFirstConst(
value_type const& vt)
const noexcept {
1144 template <
typename M,
bool UseMemcpy>
1148 template <
typename M>
1149 struct Cloner<M, true> {
1150 void operator()(M
const& source, M& target)
const {
1151 auto const*
const src =
reinterpret_cast<char const*
>(source.mKeyVals);
1152 auto* tgt =
reinterpret_cast<char*
>(target.mKeyVals);
1153 auto const numElementsWithBuffer = target.calcNumElementsWithBuffer(target.mMask + 1);
1154 std::copy(src, src + target.calcNumBytesTotal(numElementsWithBuffer), tgt);
1158 template <
typename M>
1159 struct Cloner<M, false> {
1160 void operator()(M
const& s, M& t)
const {
1161 auto const numElementsWithBuffer = t.calcNumElementsWithBuffer(t.mMask + 1);
1162 std::copy(s.mInfo, s.mInfo + t.calcNumBytesInfo(numElementsWithBuffer), t.mInfo);
1164 for (
size_t i = 0; i < numElementsWithBuffer; ++i) {
1166 ::new (
static_cast<void*
>(t.mKeyVals + i)) Node(t, *s.mKeyVals[i]);
1174 template <
typename M,
bool IsFlatAndTrivial>
1175 struct Destroyer {};
1177 template <
typename M>
1178 struct Destroyer<M, true> {
1179 void nodes(M& m)
const noexcept {
1183 void nodesDoNotDeallocate(M& m)
const noexcept {
1188 template <
typename M>
1189 struct Destroyer<M, false> {
1190 void nodes(M& m)
const noexcept {
1193 auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
1195 for (
size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
1196 if (0 != m.mInfo[idx]) {
1197 Node& n = m.mKeyVals[idx];
1204 void nodesDoNotDeallocate(M& m)
const noexcept {
1207 auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
1208 for (
size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
1209 if (0 != m.mInfo[idx]) {
1210 Node& n = m.mKeyVals[idx];
1211 n.destroyDoNotDeallocate();
1220 struct fast_forward_tag {};
1223 template <
bool IsConst>
1227 using NodePtr =
typename std::conditional<IsConst, Node const*, Node*>::type;
1230 using difference_type = std::ptrdiff_t;
1232 using reference =
typename std::conditional<IsConst, value_type const&, value_type&>::type;
1233 using pointer =
typename std::conditional<IsConst, value_type const*, value_type*>::type;
1234 using iterator_category = std::forward_iterator_tag;
1244 template <
bool OtherIsConst,
1245 typename =
typename std::enable_if<IsConst && !OtherIsConst>::type>
1247 Iter(Iter<OtherIsConst>
const& other) noexcept
1248 : mKeyVals(other.mKeyVals)
1249 , mInfo(other.mInfo) {}
1251 Iter(NodePtr valPtr, uint8_t
const* infoPtr) noexcept
1255 Iter(NodePtr valPtr, uint8_t
const* infoPtr,
1262 template <
bool OtherIsConst,
1263 typename =
typename std::enable_if<IsConst && !OtherIsConst>::type>
1264 Iter& operator=(Iter<OtherIsConst>
const& other)
noexcept {
1265 mKeyVals = other.mKeyVals;
1266 mInfo = other.mInfo;
1271 Iter& operator++() noexcept {
1278 Iter operator++(
int)
noexcept {
1284 reference operator*()
const {
1288 pointer operator->()
const {
1293 bool operator==(Iter<O>
const& o)
const noexcept {
1294 return mKeyVals == o.mKeyVals;
1298 bool operator!=(Iter<O>
const& o)
const noexcept {
1299 return mKeyVals != o.mKeyVals;
1306 void fastForward() noexcept {
1308 while (0U == (n = detail::unaligned_load<size_t>(mInfo))) {
1309 mInfo +=
sizeof(size_t);
1310 mKeyVals +=
sizeof(size_t);
1312#if defined(ROBIN_HOOD_DISABLE_INTRINSICS)
1327# if ROBIN_HOOD(LITTLE_ENDIAN)
1338 NodePtr mKeyVals{
nullptr};
1339 uint8_t
const* mInfo{
nullptr};
1347 template <
typename HashKey>
1348 void keyToIdx(HashKey&& key,
size_t* idx, InfoType* info)
const {
1352 auto h =
static_cast<uint64_t
>(WHash::operator()(key));
1354 h *= mHashMultiplier;
1358 *info = mInfoInc +
static_cast<InfoType
>((h & InfoMask) >> mInfoHashShift);
1359 *idx = (
static_cast<size_t>(h) >> InitialInfoNumBits) & mMask;
1363 void next(InfoType* info,
size_t* idx)
const noexcept {
1368 void nextWhileLess(InfoType* info,
size_t* idx)
const noexcept {
1370 while (*info < mInfo[*idx]) {
1377 shiftUp(
size_t startIdx,
1378 size_t const insertion_idx)
noexcept(std::is_nothrow_move_assignable<Node>::value) {
1379 auto idx = startIdx;
1380 ::new (
static_cast<void*
>(mKeyVals + idx)) Node(std::move(mKeyVals[idx - 1]));
1381 while (--idx != insertion_idx) {
1382 mKeyVals[idx] = std::move(mKeyVals[idx - 1]);
1386 while (idx != insertion_idx) {
1388 mInfo[idx] =
static_cast<uint8_t
>(mInfo[idx - 1] + mInfoInc);
1390 mMaxNumElementsAllowed = 0;
1396 void shiftDown(
size_t idx)
noexcept(std::is_nothrow_move_assignable<Node>::value) {
1400 mKeyVals[idx].destroy(*
this);
1403 while (mInfo[idx + 1] >= 2 * mInfoInc) {
1405 mInfo[idx] =
static_cast<uint8_t
>(mInfo[idx + 1] - mInfoInc);
1406 mKeyVals[idx] = std::move(mKeyVals[idx + 1]);
1413 mKeyVals[idx].~Node();
1417 template <
typename Other>
1419 size_t findIdx(Other
const& key)
const {
1422 keyToIdx(key, &idx, &info);
1426 if (info == mInfo[idx] &&
1431 if (info == mInfo[idx] &&
1436 }
while (info <= mInfo[idx]);
1439 return mMask == 0 ? 0
1440 :
static_cast<size_t>(std::distance(
1441 mKeyVals, reinterpret_cast_no_cast_align_warning<Node*>(mInfo)));
1444 void cloneData(
const Table& o) {
1445 Cloner<Table, IsFlat && ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(Node)>()(o, *
this);
1450 void insert_move(Node&& keyval) {
1453 if (0 == mMaxNumElementsAllowed && !try_increase_info()) {
1454 throwOverflowError();
1459 keyToIdx(keyval.getFirst(), &idx, &info);
1462 while (info <= mInfo[idx]) {
1468 auto const insertion_idx = idx;
1469 auto const insertion_info =
static_cast<uint8_t
>(info);
1471 mMaxNumElementsAllowed = 0;
1475 while (0 != mInfo[idx]) {
1479 auto& l = mKeyVals[insertion_idx];
1480 if (idx == insertion_idx) {
1481 ::new (
static_cast<void*
>(&l)) Node(std::move(keyval));
1483 shiftUp(idx, insertion_idx);
1484 l = std::move(keyval);
1488 mInfo[insertion_idx] = insertion_info;
1497 Table() noexcept(noexcept(Hash()) && noexcept(KeyEqual()))
1510 const KeyEqual& equal = KeyEqual{})
noexcept(
noexcept(Hash(h)) &&
noexcept(KeyEqual(equal)))
1512 , WKeyEqual(equal) {
1516 template <
typename Iter>
1518 const Hash& h = Hash{},
const KeyEqual& equal = KeyEqual{})
1520 , WKeyEqual(equal) {
1527 const KeyEqual& equal = KeyEqual{})
1529 , WKeyEqual(equal) {
1540 mHashMultiplier = std::move(o.mHashMultiplier);
1541 mKeyVals = std::move(o.mKeyVals);
1542 mInfo = std::move(o.mInfo);
1543 mNumElements = std::move(o.mNumElements);
1544 mMask = std::move(o.mMask);
1545 mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);
1546 mInfoInc = std::move(o.mInfoInc);
1547 mInfoHashShift = std::move(o.mInfoHashShift);
1559 mHashMultiplier = std::move(o.mHashMultiplier);
1560 mKeyVals = std::move(o.mKeyVals);
1561 mInfo = std::move(o.mInfo);
1562 mNumElements = std::move(o.mNumElements);
1563 mMask = std::move(o.mMask);
1564 mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);
1565 mInfoInc = std::move(o.mInfoInc);
1566 mInfoHashShift = std::move(o.mInfoHashShift);
1567 WHash::operator=(std::move(
static_cast<WHash&
>(o)));
1568 WKeyEqual::operator=(std::move(
static_cast<WKeyEqual&
>(o)));
1569 DataPool::operator=(std::move(
static_cast<DataPool&
>(o)));
1591 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
1593 ROBIN_HOOD_LOG(
"std::malloc " << numBytesTotal <<
" = calcNumBytesTotal("
1594 << numElementsWithBuffer <<
")")
1595 mHashMultiplier = o.mHashMultiplier;
1596 mKeyVals =
static_cast<Node*
>(
1597 detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
1599 mInfo =
reinterpret_cast<uint8_t*
>(mKeyVals + numElementsWithBuffer);
1600 mNumElements = o.mNumElements;
1602 mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;
1603 mInfoInc = o.mInfoInc;
1604 mInfoHashShift = o.mInfoHashShift;
1631 WHash::operator=(
static_cast<const WHash&
>(o));
1632 WKeyEqual::operator=(
static_cast<const WKeyEqual&
>(o));
1633 DataPool::operator=(
static_cast<DataPool const&
>(o));
1639 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*
this);
1641 if (mMask != o.mMask) {
1646 std::free(mKeyVals);
1650 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
1651 ROBIN_HOOD_LOG(
"std::malloc " << numBytesTotal <<
" = calcNumBytesTotal("
1652 << numElementsWithBuffer <<
")")
1653 mKeyVals =
static_cast<Node*
>(
1654 detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
1657 mInfo =
reinterpret_cast<uint8_t*
>(mKeyVals + numElementsWithBuffer);
1660 WHash::operator=(
static_cast<const WHash&
>(o));
1661 WKeyEqual::operator=(
static_cast<const WKeyEqual&
>(o));
1662 DataPool::operator=(
static_cast<DataPool const&
>(o));
1663 mHashMultiplier = o.mHashMultiplier;
1664 mNumElements = o.mNumElements;
1666 mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;
1667 mInfoInc = o.mInfoInc;
1668 mInfoHashShift = o.mInfoHashShift;
1690 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*
this);
1694 uint8_t
const z = 0;
1695 std::fill(mInfo, mInfo + calcNumBytesInfo(numElementsWithBuffer), z);
1696 mInfo[numElementsWithBuffer] = 1;
1698 mInfoInc = InitialInfoInc;
1699 mInfoHashShift = InitialInfoHashShift;
1714 for (
auto const& otherEntry : other) {
1715 if (!has(otherEntry)) {
1728 template <
typename Q = mapped_type>
1731 auto idxAndState = insertKeyPrepareEmptySpot(key);
1732 switch (idxAndState.second) {
1733 case InsertionState::key_found:
1736 case InsertionState::new_node:
1737 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first]))
1738 Node(*
this, std::piecewise_construct, std::forward_as_tuple(key),
1739 std::forward_as_tuple());
1742 case InsertionState::overwrite_node:
1743 mKeyVals[idxAndState.first] = Node(*
this, std::piecewise_construct,
1744 std::forward_as_tuple(key), std::forward_as_tuple());
1747 case InsertionState::overflow_error:
1748 throwOverflowError();
1751 return mKeyVals[idxAndState.first].getSecond();
1754 template <
typename Q = mapped_type>
1757 auto idxAndState = insertKeyPrepareEmptySpot(key);
1758 switch (idxAndState.second) {
1759 case InsertionState::key_found:
1762 case InsertionState::new_node:
1763 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first]))
1764 Node(*
this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),
1765 std::forward_as_tuple());
1768 case InsertionState::overwrite_node:
1769 mKeyVals[idxAndState.first] =
1770 Node(*
this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),
1771 std::forward_as_tuple());
1774 case InsertionState::overflow_error:
1775 throwOverflowError();
1778 return mKeyVals[idxAndState.first].getSecond();
1781 template <
typename Iter>
1783 for (; first != last; ++first) {
1789 void insert(std::initializer_list<value_type> ilist) {
1790 for (
auto&& vt : ilist) {
1795 template <
typename... Args>
1796 std::pair<iterator, bool>
emplace(Args&&... args) {
1798 Node n{*
this, std::forward<Args>(args)...};
1799 auto idxAndState = insertKeyPrepareEmptySpot(getFirstConst(n));
1800 switch (idxAndState.second) {
1801 case InsertionState::key_found:
1805 case InsertionState::new_node:
1806 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(*
this, std::move(n));
1809 case InsertionState::overwrite_node:
1810 mKeyVals[idxAndState.first] = std::move(n);
1813 case InsertionState::overflow_error:
1815 throwOverflowError();
1819 return std::make_pair(
iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
1820 InsertionState::key_found != idxAndState.second);
1823 template <
typename... Args>
1826 return emplace(std::forward<Args>(args)...).first;
1829 template <
typename... Args>
1831 return try_emplace_impl(key, std::forward<Args>(args)...);
1834 template <
typename... Args>
1836 return try_emplace_impl(std::move(key), std::forward<Args>(args)...);
1839 template <
typename... Args>
1842 return try_emplace_impl(key, std::forward<Args>(args)...).first;
1845 template <
typename... Args>
1848 return try_emplace_impl(std::move(key), std::forward<Args>(args)...).first;
1851 template <
typename Mapped>
1853 return insertOrAssignImpl(key, std::forward<Mapped>(obj));
1856 template <
typename Mapped>
1858 return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj));
1861 template <
typename Mapped>
1864 return insertOrAssignImpl(key, std::forward<Mapped>(obj)).first;
1867 template <
typename Mapped>
1870 return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj)).first;
1884 return emplace(std::move(keyval));
1889 return emplace(std::move(keyval)).first;
1895 auto kv = mKeyVals + findIdx(key);
1896 if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1902 template <
typename OtherKey,
typename Self_ = Self>
1904 typename std::enable_if<Self_::is_transparent, size_t>::type
count(
const OtherKey& key)
const {
1906 auto kv = mKeyVals + findIdx(key);
1907 if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1914 return 1U ==
count(key);
1917 template <
typename OtherKey,
typename Self_ = Self>
1919 typename std::enable_if<Self_::is_transparent, bool>::type
contains(
const OtherKey& key)
const {
1920 return 1U ==
count(key);
1925 template <
typename Q = mapped_type>
1927 typename std::enable_if<!std::is_void<Q>::value, Q&>::type
at(
key_type const& key) {
1929 auto kv = mKeyVals + findIdx(key);
1930 if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1931 doThrow<std::out_of_range>(
"key not found");
1933 return kv->getSecond();
1938 template <
typename Q = mapped_type>
1940 typename std::enable_if<!std::is_void<Q>::value, Q
const&>::type
at(
key_type const& key)
const {
1942 auto kv = mKeyVals + findIdx(key);
1943 if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1944 doThrow<std::out_of_range>(
"key not found");
1946 return kv->getSecond();
1951 const size_t idx = findIdx(key);
1955 template <
typename OtherKey>
1958 const size_t idx = findIdx(key);
1962 template <
typename OtherKey,
typename Self_ = Self>
1963 typename std::enable_if<Self_::is_transparent,
1967 const size_t idx = findIdx(key);
1973 const size_t idx = findIdx(key);
1974 return iterator{mKeyVals + idx, mInfo + idx};
1977 template <
typename OtherKey>
1980 const size_t idx = findIdx(key);
1981 return iterator{mKeyVals + idx, mInfo + idx};
1984 template <
typename OtherKey,
typename Self_ = Self>
1985 typename std::enable_if<Self_::is_transparent, iterator>::type
find(
const OtherKey& key) {
1987 const size_t idx = findIdx(key);
1988 return iterator{mKeyVals + idx, mInfo + idx};
1996 return iterator(mKeyVals, mInfo, fast_forward_tag{});
2014 return iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo),
nullptr};
2022 return const_iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo),
nullptr};
2029 return erase(
iterator{
const_cast<Node*
>(pos.mKeyVals),
const_cast<uint8_t*
>(pos.mInfo)});
2036 auto const idx =
static_cast<size_t>(pos.mKeyVals - mKeyVals);
2054 keyToIdx(key, &idx, &info);
2058 if (info == mInfo[idx] && WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
2064 }
while (info <= mInfo[idx]);
2088 auto newSize = InitialNumElements;
2089 while (calcMaxNumElementsAllowed(newSize) < mNumElements && newSize != 0) {
2093 throwOverflowError();
2096 ROBIN_HOOD_LOG(
"newSize > mMask + 1: " << newSize <<
" > " << mMask <<
" + 1")
2100 if (newSize < mMask + 1) {
2101 rehashPowerOfTwo(newSize,
true);
2107 return mNumElements;
2117 return 0 == mNumElements;
2122 return MaxLoadFactor100 / 100.0F;
2128 return static_cast<float>(
size()) /
static_cast<float>(mMask + 1);
2136 ROBIN_HOOD(NODISCARD)
size_t calcMaxNumElementsAllowed(
size_t maxElements)
const noexcept {
2137 if (
ROBIN_HOOD_LIKELY(maxElements <= (std::numeric_limits<size_t>::max)() / 100)) {
2138 return maxElements * MaxLoadFactor100 / 100;
2142 return (maxElements / 100) * MaxLoadFactor100;
2145 ROBIN_HOOD(NODISCARD)
size_t calcNumBytesInfo(
size_t numElements)
const noexcept {
2148 return numElements +
sizeof(uint64_t);
2153 auto maxNumElementsAllowed = calcMaxNumElementsAllowed(numElements);
2154 return numElements + (std::min)(maxNumElementsAllowed, (
static_cast<size_t>(0xFF)));
2158 ROBIN_HOOD(NODISCARD)
size_t calcNumBytesTotal(
size_t numElements)
const {
2159#if ROBIN_HOOD(BITNESS) == 64
2160 return numElements *
sizeof(Node) + calcNumBytesInfo(numElements);
2163 auto const ne =
static_cast<uint64_t
>(numElements);
2164 auto const s =
static_cast<uint64_t
>(
sizeof(Node));
2165 auto const infos =
static_cast<uint64_t
>(calcNumBytesInfo(numElements));
2167 auto const total64 = ne * s + infos;
2168 auto const total =
static_cast<size_t>(total64);
2171 throwOverflowError();
2178 template <
typename Q = mapped_type>
2180 typename std::enable_if<!std::is_void<Q>::value,
bool>::type has(
const value_type& e)
const {
2182 auto it =
find(e.first);
2183 return it !=
end() && it->second == e.second;
2188 typename std::enable_if<std::is_void<Q>::value,
bool>::type has(const
value_type& e)
const {
2193 void reserve(
size_t c,
bool forceRehash) {
2195 auto const minElementsAllowed = (std::max)(c, mNumElements);
2196 auto newSize = InitialNumElements;
2197 while (calcMaxNumElementsAllowed(newSize) < minElementsAllowed && newSize != 0) {
2201 throwOverflowError();
2204 ROBIN_HOOD_LOG(
"newSize > mMask + 1: " << newSize <<
" > " << mMask <<
" + 1")
2208 if (forceRehash || newSize > mMask + 1) {
2209 rehashPowerOfTwo(newSize,
false);
2216 void rehashPowerOfTwo(
size_t numBuckets,
bool forceFree) {
2219 Node* const oldKeyVals = mKeyVals;
2220 uint8_t const* const oldInfo = mInfo;
2225 initData(numBuckets);
2226 if (oldMaxElementsWithBuffer > 1) {
2227 for (
size_t i = 0; i < oldMaxElementsWithBuffer; ++i) {
2228 if (oldInfo[i] != 0) {
2231 insert_move(std::move(oldKeyVals[i]));
2233 oldKeyVals[i].~Node();
2240 if (oldKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
2243 std::free(oldKeyVals);
2245 DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer));
2251 ROBIN_HOOD(NOINLINE)
void throwOverflowError()
const {
2252#if ROBIN_HOOD(HAS_EXCEPTIONS)
2253 throw std::overflow_error(
"robin_hood::map overflow");
2259 template <
typename OtherKey,
typename... Args>
2260 std::pair<iterator, bool> try_emplace_impl(OtherKey&& key, Args&&... args) {
2262 auto idxAndState = insertKeyPrepareEmptySpot(key);
2263 switch (idxAndState.second) {
2264 case InsertionState::key_found:
2267 case InsertionState::new_node:
2268 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(
2269 *
this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
2270 std::forward_as_tuple(std::forward<Args>(args)...));
2273 case InsertionState::overwrite_node:
2274 mKeyVals[idxAndState.first] = Node(*
this, std::piecewise_construct,
2275 std::forward_as_tuple(std::forward<OtherKey>(key)),
2276 std::forward_as_tuple(std::forward<Args>(args)...));
2279 case InsertionState::overflow_error:
2280 throwOverflowError();
2284 return std::make_pair(
iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
2285 InsertionState::key_found != idxAndState.second);
2288 template <
typename OtherKey,
typename Mapped>
2289 std::pair<iterator, bool> insertOrAssignImpl(OtherKey&& key, Mapped&& obj) {
2291 auto idxAndState = insertKeyPrepareEmptySpot(key);
2292 switch (idxAndState.second) {
2293 case InsertionState::key_found:
2294 mKeyVals[idxAndState.first].getSecond() = std::forward<Mapped>(obj);
2297 case InsertionState::new_node:
2298 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(
2299 *
this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
2300 std::forward_as_tuple(std::forward<Mapped>(obj)));
2303 case InsertionState::overwrite_node:
2304 mKeyVals[idxAndState.first] = Node(*
this, std::piecewise_construct,
2305 std::forward_as_tuple(std::forward<OtherKey>(key)),
2306 std::forward_as_tuple(std::forward<Mapped>(obj)));
2309 case InsertionState::overflow_error:
2310 throwOverflowError();
2314 return std::make_pair(
iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
2315 InsertionState::key_found != idxAndState.second);
2318 void initData(
size_t max_elements) {
2320 mMask = max_elements - 1;
2321 mMaxNumElementsAllowed = calcMaxNumElementsAllowed(max_elements);
2326 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
2327 ROBIN_HOOD_LOG(
"std::calloc " << numBytesTotal <<
" = calcNumBytesTotal("
2328 << numElementsWithBuffer <<
")")
2329 mKeyVals = reinterpret_cast<Node*>(
2330 detail::
assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
2331 mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);
2332 std::memset(mInfo, 0, numBytesTotal - numElementsWithBuffer * sizeof(Node));
2335 mInfo[numElementsWithBuffer] = 1;
2337 mInfoInc = InitialInfoInc;
2338 mInfoHashShift = InitialInfoHashShift;
2341 enum class InsertionState { overflow_error, key_found, new_node, overwrite_node };
2346 template <
typename OtherKey>
2347 std::pair<size_t, InsertionState> insertKeyPrepareEmptySpot(OtherKey&& key) {
2348 for (
int i = 0; i < 256; ++i) {
2351 keyToIdx(key, &idx, &info);
2352 nextWhileLess(&info, &idx);
2355 while (info == mInfo[idx]) {
2356 if (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
2359 return std::make_pair(idx, InsertionState::key_found);
2366 if (!increase_size()) {
2367 return std::make_pair(
size_t(0), InsertionState::overflow_error);
2373 auto const insertion_idx = idx;
2374 auto const insertion_info = info;
2376 mMaxNumElementsAllowed = 0;
2380 while (0 != mInfo[idx]) {
2384 if (idx != insertion_idx) {
2385 shiftUp(idx, insertion_idx);
2388 mInfo[insertion_idx] =
static_cast<uint8_t
>(insertion_info);
2390 return std::make_pair(insertion_idx, idx == insertion_idx
2391 ? InsertionState::new_node
2392 : InsertionState::overwrite_node);
2396 return std::make_pair(
size_t(0), InsertionState::overflow_error);
2399 bool try_increase_info() {
2400 ROBIN_HOOD_LOG(
"mInfoInc=" << mInfoInc <<
", numElements=" << mNumElements
2401 <<
", maxNumElementsAllowed="
2402 << calcMaxNumElementsAllowed(mMask + 1))
2403 if (mInfoInc <= 2) {
2408 mInfoInc =
static_cast<uint8_t
>(mInfoInc >> 1U);
2415 for (
size_t i = 0; i < numElementsWithBuffer; i += 8) {
2416 auto val = unaligned_load<uint64_t>(mInfo + i);
2417 val = (val >> 1U) & UINT64_C(0x7f7f7f7f7f7f7f7f);
2418 std::memcpy(mInfo + i, &val,
sizeof(val));
2421 mInfo[numElementsWithBuffer] = 1;
2423 mMaxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
2428 bool increase_size() {
2431 initData(InitialNumElements);
2435 auto const maxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
2436 if (mNumElements < maxNumElementsAllowed && try_increase_info()) {
2440 ROBIN_HOOD_LOG(
"mNumElements=" << mNumElements <<
", maxNumElementsAllowed="
2441 << maxNumElementsAllowed <<
", load="
2442 << (
static_cast<double>(mNumElements) * 100.0 /
2443 (
static_cast<double>(mMask) + 1)))
2445 if (mNumElements * 2 < calcMaxNumElementsAllowed(mMask + 1)) {
2449 nextHashMultiplier();
2450 rehashPowerOfTwo(mMask + 1,
true);
2453 rehashPowerOfTwo((mMask + 1) * 2,
false);
2458 void nextHashMultiplier() {
2461 mHashMultiplier += UINT64_C(0xc4ceb9fe1a85ec54);
2470 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}
2471 .nodesDoNotDeallocate(*
this);
2477 if (mKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
2479 std::free(mKeyVals);
2483 void init() noexcept {
2484 mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);
2485 mInfo =
reinterpret_cast<uint8_t*
>(&mMask);
2488 mMaxNumElementsAllowed = 0;
2489 mInfoInc = InitialInfoInc;
2490 mInfoHashShift = InitialInfoHashShift;
2494 uint64_t mHashMultiplier = UINT64_C(0xc4ceb9fe1a85ec53);
2495 Node* mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);
2496 uint8_t* mInfo =
reinterpret_cast<uint8_t*
>(&mMask);
2497 size_t mNumElements = 0;
2499 size_t mMaxNumElementsAllowed = 0;
2500 InfoType mInfoInc = InitialInfoInc;
2501 InfoType mInfoHashShift = InitialInfoHashShift;
2509template <
typename Key,
typename T,
typename Hash = hash<Key>,
2510 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2513template <
typename Key,
typename T,
typename Hash = hash<Key>,
2514 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2517template <
typename Key,
typename T,
typename Hash = hash<Key>,
2518 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2521 std::is_nothrow_move_constructible<robin_hood::pair<Key, T>>::value &&
2522 std::is_nothrow_move_assignable<robin_hood::pair<Key, T>>::value,
2523 MaxLoadFactor100, Key, T, Hash, KeyEqual>;
2527template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2528 size_t MaxLoadFactor100 = 80>
2531template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2532 size_t MaxLoadFactor100 = 80>
2535template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2536 size_t MaxLoadFactor100 = 80>
2538 std::is_nothrow_move_constructible<Key>::value &&
2539 std::is_nothrow_move_assignable<Key>::value,
2540 MaxLoadFactor100, Key, void, Hash, KeyEqual>;
Definition robin_hood.h:241
static constexpr std::size_t size() noexcept
Definition robin_hood.h:245
T value_type
Definition robin_hood.h:243
Definition robin_hood.h:367
~BulkPoolAllocator() noexcept
Definition robin_hood.h:399
BulkPoolAllocator & operator=(BulkPoolAllocator &&o) noexcept
Definition robin_hood.h:383
void swap(BulkPoolAllocator< T, MinNumAllocs, MaxNumAllocs > &other) noexcept
Definition robin_hood.h:451
void reset() noexcept
Definition robin_hood.h:404
void deallocate(T *obj) noexcept
Definition robin_hood.h:431
BulkPoolAllocator & operator=(const BulkPoolAllocator &ROBIN_HOOD_UNUSED(o)) noexcept
Definition robin_hood.h:394
BulkPoolAllocator() noexcept=default
BulkPoolAllocator(BulkPoolAllocator &&o) noexcept
Definition robin_hood.h:376
T * allocate()
Definition robin_hood.h:417
void addOrFree(void *ptr, const size_t numBytes) noexcept
Definition robin_hood.h:439
Definition robin_hood.h:916
void rehash(size_t c)
Definition robin_hood.h:2072
std::enable_if< Self_::is_transparent, const_iterator >::type find(const OtherKey &key) const
Definition robin_hood.h:1965
iterator find(const key_type &key)
Definition robin_hood.h:1971
iterator erase(const_iterator pos)
Definition robin_hood.h:2025
const_iterator cend() const
Definition robin_hood.h:2020
static constexpr bool is_map
Definition robin_hood.h:919
Hash hasher
Definition robin_hood.h:930
std::pair< iterator, bool > try_emplace(const key_type &key, Args &&... args)
Definition robin_hood.h:1830
Iter< true > const_iterator
Definition robin_hood.h:1495
std::pair< iterator, bool > try_emplace(key_type &&key, Args &&... args)
Definition robin_hood.h:1835
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:1508
void swap(Table &o)
Definition robin_hood.h:1675
const_iterator end() const
Definition robin_hood.h:2016
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:1517
Table & operator=(Table const &o)
Definition robin_hood.h:1612
void compact()
Definition robin_hood.h:2086
ROBIN_HOOD(NODISCARD) size_t calcMaxNumElementsAllowed(size_t maxElements) const noexcept
Definition robin_hood.h:2136
iterator insert(const_iterator hint, value_type &&keyval)
Definition robin_hood.h:1887
std::pair< iterator, bool > insert(value_type &&keyval)
Definition robin_hood.h:1883
Iter< false > iterator
Definition robin_hood.h:1494
bool operator==(const Table &other) const
Definition robin_hood.h:1709
std::pair< iterator, bool > insert_or_assign(key_type &&key, Mapped &&obj)
Definition robin_hood.h:1857
std::pair< iterator, bool > insert_or_assign(const key_type &key, Mapped &&obj)
Definition robin_hood.h:1852
ROBIN_HOOD(NODISCARD) bool empty() const noexcept
Definition robin_hood.h:2115
void clear()
Definition robin_hood.h:1682
ROBIN_HOOD(NODISCARD) size_t calcNumBytesInfo(size_t numElements) const noexcept
Definition robin_hood.h:2145
void reserve(size_t c)
Definition robin_hood.h:2079
bool operator!=(const Table &other) const
Definition robin_hood.h:1723
Key key_type
Definition robin_hood.h:924
const_iterator find(const key_type &key) const
Definition robin_hood.h:1949
iterator end()
Definition robin_hood.h:2010
bool contains(const key_type &key) const
Definition robin_hood.h:1913
iterator find(const OtherKey &key, is_transparent_tag)
Definition robin_hood.h:1978
size_t size_type
Definition robin_hood.h:929
size_t erase(const key_type &key)
Definition robin_hood.h:2050
std::enable_if<!std::is_void< Q >::value, Q & >::type operator[](const key_type &key)
Definition robin_hood.h:1729
const_iterator begin() const
Definition robin_hood.h:1998
size_t count(const key_type &key) const
Definition robin_hood.h:1893
iterator try_emplace(const_iterator hint, const key_type &key, Args &&... args)
Definition robin_hood.h:1840
const_iterator cbegin() const
Definition robin_hood.h:2002
std::enable_if<!std::is_void< Q >::value, Qconst & >::type at(key_type const &key) const
Definition robin_hood.h:1940
~Table()
Definition robin_hood.h:1703
size_type size() const noexcept
Definition robin_hood.h:2105
size_t calcNumElementsWithBuffer(size_t numElements) const noexcept
Definition robin_hood.h:2152
KeyEqual key_equal
Definition robin_hood.h:931
void insert(std::initializer_list< value_type > ilist)
Definition robin_hood.h:1789
iterator insert_or_assign(const_iterator hint, const key_type &key, Mapped &&obj)
Definition robin_hood.h:1862
iterator emplace_hint(const_iterator position, Args &&... args)
Definition robin_hood.h:1824
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:928
float load_factor() const noexcept
Definition robin_hood.h:2126
std::enable_if< Self_::is_transparent, iterator >::type find(const OtherKey &key)
Definition robin_hood.h:1985
float max_load_factor() const noexcept
Definition robin_hood.h:2120
ROBIN_HOOD(NODISCARD) size_t calcNumBytesTotal(size_t numElements) const
Definition robin_hood.h:2158
ROBIN_HOOD(NODISCARD) size_t mask() const noexcept
Definition robin_hood.h:2131
std::pair< iterator, bool > insert(const value_type &keyval)
Definition robin_hood.h:1873
size_type max_size() const noexcept
Definition robin_hood.h:2110
iterator insert(const_iterator hint, const value_type &keyval)
Definition robin_hood.h:1878
static constexpr bool is_flat
Definition robin_hood.h:918
std::pair< iterator, bool > emplace(Args &&... args)
Definition robin_hood.h:1796
T mapped_type
Definition robin_hood.h:925
Table() noexcept(noexcept(Hash()) &&noexcept(KeyEqual()))
Definition robin_hood.h:1497
iterator begin()
Definition robin_hood.h:1991
Table & operator=(Table &&o) noexcept
Definition robin_hood.h:1553
const_iterator find(const OtherKey &key, is_transparent_tag) const
Definition robin_hood.h:1956
std::enable_if< Self_::is_transparent, bool >::type contains(const OtherKey &key) const
Definition robin_hood.h:1919
iterator try_emplace(const_iterator hint, key_type &&key, Args &&... args)
Definition robin_hood.h:1846
std::enable_if< Self_::is_transparent, size_t >::type count(const OtherKey &key) const
Definition robin_hood.h:1904
Table(const Table &o)
Definition robin_hood.h:1581
iterator insert_or_assign(const_iterator hint, key_type &&key, Mapped &&obj)
Definition robin_hood.h:1868
static constexpr bool is_transparent
Definition robin_hood.h:921
static constexpr bool is_set
Definition robin_hood.h:920
iterator erase(iterator pos)
Definition robin_hood.h:2033
std::enable_if<!std::is_void< Q >::value, Q & >::type operator[](key_type &&key)
Definition robin_hood.h:1755
void insert(Iter first, Iter last)
Definition robin_hood.h:1782
std::enable_if<!std::is_void< Q >::value, Q & >::type at(key_type const &key)
Definition robin_hood.h:1927
typename detail_::IntSeqImpl< T, 0, N,(N - 0)==1 >::TResult make_integer_sequence
Definition robin_hood.h:292
make_index_sequence< sizeof...(T)> index_sequence_for
Definition robin_hood.h:298
make_integer_sequence< std::size_t, N > make_index_sequence
Definition robin_hood.h:295
T reinterpret_cast_no_cast_align_warning(void *ptr) noexcept
Definition robin_hood.h:322
T unaligned_load(void const *ptr) noexcept
Definition robin_hood.h:355
T * assertNotNull(T *t, Args &&... args)
Definition robin_hood.h:347
uint32_t SizeT
Definition robin_hood.h:310
T rotr(T x, unsigned k)
Definition robin_hood.h:314
Definition robin_hood.h:228
constexpr bool operator==(pair< A, B > const &x, pair< A, B > const &y)
Definition robin_hood.h:666
constexpr bool operator<=(pair< A, B > const &x, pair< A, B > const &y)
Definition robin_hood.h:684
constexpr bool operator>(pair< A, B > const &x, pair< A, B > const &y)
Definition robin_hood.h:680
constexpr bool operator!=(pair< A, B > const &x, pair< A, B > const &y)
Definition robin_hood.h:670
size_t hash_int(uint64_t x) noexcept
Definition robin_hood.h:748
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:660
size_t hash_bytes(void const *ptr, size_t len) noexcept
Definition robin_hood.h:692
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:674
constexpr bool operator>=(pair< A, B > const &x, pair< A, B > const &y)
Definition robin_hood.h:688
#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:818
#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:238
Definition robin_hood.h:260
T TValue
Definition robin_hood.h:276
T TValue
Definition robin_hood.h:284
Definition robin_hood.h:254
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:271
T TValue
Definition robin_hood.h:255
void addOrFree(void *ptr, size_t ROBIN_HOOD_UNUSED(numBytes)) noexcept
Definition robin_hood.h:548
Definition robin_hood.h:541
Definition robin_hood.h:868
WrapHash(T const &o) noexcept(noexcept(T(std::declval< T const & >())))
Definition robin_hood.h:870
Definition robin_hood.h:875
WrapKeyEqual(T const &o) noexcept(noexcept(T(std::declval< T const & >())))
Definition robin_hood.h:877
Definition robin_hood.h:859
Definition robin_hood.h:563
static const bool value
Definition robin_hood.h:564
Definition robin_hood.h:854
void type
Definition robin_hood.h:855
size_t operator()(Enum e) const noexcept
Definition robin_hood.h:812
size_t operator()(T *ptr) const noexcept
Definition robin_hood.h:791
size_t operator()(std::basic_string< CharT > const &str) const noexcept
Definition robin_hood.h:775
size_t operator()(std::shared_ptr< T > const &ptr) const noexcept
Definition robin_hood.h:805
size_t operator()(std::unique_ptr< T > const &ptr) const noexcept
Definition robin_hood.h:798
Definition robin_hood.h:763
size_t operator()(T const &obj) const noexcept(noexcept(std::declval< std::hash< T > >().operator()(std::declval< T const & >())))
Definition robin_hood.h:764
Definition robin_hood.h:576
Definition robin_hood.h:582
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:622
void swap(pair< T1, T2 > &o) noexcept((detail::swappable::nothrow< T1 >::value) &&(detail::swappable::nothrow< T2 >::value))
Definition robin_hood.h:648
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:600
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:634
T2 second
Definition robin_hood.h:656
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:605
T1 first
Definition robin_hood.h:655
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:611
T2 second_type
Definition robin_hood.h:584
T1 first_type
Definition robin_hood.h:583
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:594
constexpr pair() noexcept(noexcept(U1()) &&noexcept(U2()))
Definition robin_hood.h:589