33 #ifndef ROBIN_HOOD_H_INCLUDED
34 #define ROBIN_HOOD_H_INCLUDED
37 #define ROBIN_HOOD_VERSION_MAJOR 3 // for incompatible API changes
38 #define ROBIN_HOOD_VERSION_MINOR 11 // for adding functionality in a backwards-compatible manner
39 #define ROBIN_HOOD_VERSION_PATCH 1 // for backwards-compatible bug fixes
48 #include <type_traits>
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;
82 inline std::ostream&
operator<<(std::ostream& os, Counts
const&
c) {
83 return os <<
c.shiftUp <<
" shiftUp" << std::endl <<
c.shiftDown <<
" shiftDown" << std::endl;
86 static 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 // For backwards compatibility
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
198 # if _MSC_VER <= 1900
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
235 namespace ROBIN_HOOD_STD {
238 : std::integral_constant<std::size_t, alignof(typename std::remove_all_extents<T>::type)> {};
240 template <
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);
249 template <std::size_t... Inds>
253 template <
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>
274 template <
class T, T Begin>
277 static_assert(std::is_integral<TValue>::value,
"not integral type");
278 static_assert(Begin >= 0,
"unexpected argument (Begin<0)");
282 template <
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)");
291 template <
class T, T N>
294 template <std::
size_t N>
297 template <
class... T>
307 #if ROBIN_HOOD(BITNESS) == 64
308 using SizeT = uint64_t;
313 template <
typename T>
315 return (x >> k) | (x << (8U *
sizeof(T) - k));
321 template <
typename T>
323 return reinterpret_cast<T
>(ptr);
326 template <
typename T>
328 return reinterpret_cast<T
>(ptr);
333 template <
typename E,
typename... Args>
335 #if ROBIN_HOOD(HAS_EXCEPTIONS)
336 void doThrow(Args&&... args) {
338 throw E(std::forward<Args>(args)...);
346 template <
typename E,
typename T,
typename... Args>
349 doThrow<E>(std::forward<Args>(args)...);
354 template <
typename T>
359 std::memcpy(&t, ptr,
sizeof(T));
366 template <
typename T,
size_t MinNumAllocs = 4,
size_t MaxNumAllocs = 256>
379 o.mListForFree =
nullptr;
387 o.mListForFree =
nullptr;
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 {
462 ROBIN_HOOD(NODISCARD)
size_t calcNumElementsToAlloc() const noexcept {
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 {
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) =
499 *reinterpret_cast_no_cast_align_warning<T**>(head + (numElements - 1) *
ALIGNED_SIZE) =
507 size_t const numElementsToAlloc = calcNumElementsToAlloc();
512 <<
" * " << numElementsToAlloc)
513 add(assertNotNull<std::bad_alloc>(std::malloc(bytes)), bytes);
518 #if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)
520 (std::max)(std::alignment_of<T>::value, std::alignment_of<T*>::value);
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");
540 template <
typename T,
size_t MinSize,
size_t MaxSize,
bool IsFlat>
544 template <
typename T,
size_t MinSize,
size_t MaxSize>
554 template <
typename T,
size_t MinSize,
size_t MaxSize>
559 namespace swappable {
560 #if ROBIN_HOOD(CXX) < ROBIN_HOOD(CXX17)
562 template <
typename T>
564 static const bool value = noexcept(
swap(std::declval<T&>(), std::declval<T&>()));
567 template <
typename T>
569 static const bool value = std::is_nothrow_swappable<T>::value;
581 template <
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&&>()))))
605 constexpr
pair(T1&& a, T2&& b) noexcept(noexcept(
606 T1(std::move(std::declval<T1&&>()))) && noexcept(T2(std::move(std::declval<T2&&>()))))
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&&>()))))
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...>&>()))...)))
659 template <
typename A,
typename B>
665 template <
typename A,
typename B>
669 template <
typename A,
typename B>
673 template <
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);
679 template <
typename A,
typename B>
683 template <
typename A,
typename B>
687 template <
typename A,
typename B>
692 inline 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);
762 template <
typename T,
typename Enable =
void>
763 struct 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);
773 template <
typename 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)
781 template <
typename CharT>
782 struct 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());
798 size_t operator()(std::unique_ptr<T>
const& ptr)
const noexcept {
805 size_t operator()(std::shared_ptr<T>
const& ptr)
const noexcept {
810 template <
typename Enum>
811 struct 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
853 template <
typename T>
858 template <
typename T,
typename =
void>
861 template <
typename T>
863 :
public std::true_type {};
867 template <
typename T>
870 explicit WrapHash(T
const& o) noexcept(noexcept(T(std::declval<T const&>())))
874 template <
typename T>
877 explicit WrapKeyEqual(T
const& o) noexcept(noexcept(T(std::declval<T const&>())))
907 template <
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");
959 template <
typename M,
bool>
963 template <
typename M>
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)) {}
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
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;
1030 noexcept(std::declval<value_type>().
swap(std::declval<value_type>()))) {
1031 mData.swap(o.mData);
1039 template <
typename M>
1042 template <
typename... Args>
1045 ::new (
static_cast<void*
>(mData))
value_type(std::forward<Args>(args)...);
1049 : mData(std::move(n.mData)) {}
1053 mData->~value_type();
1054 map.deallocate(mData);
1058 mData->~value_type();
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
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;
1114 swap(mData, o.mData);
1125 return n.getFirst();
1135 template <
typename Q = mapped_type>
1137 typename std::enable_if<!std::is_void<Q>::value,
key_type const&>::type
1144 template <
typename M,
bool UseMemcpy>
1148 template <
typename M>
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>
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>
1177 template <
typename M>
1188 template <
typename M>
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];
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();
1223 template <
bool IsConst>
1227 using NodePtr =
typename std::conditional<IsConst, Node const*, Node*>::type;
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;
1244 template <
bool OtherIsConst,
1245 typename =
typename std::enable_if<IsConst && !OtherIsConst>::type>
1249 ,
mInfo(other.mInfo) {}
1262 template <
bool OtherIsConst,
1263 typename =
typename std::enable_if<IsConst && !OtherIsConst>::type>
1266 mInfo = other.mInfo;
1308 while (0U == (n = detail::unaligned_load<size_t>(
mInfo))) {
1309 mInfo +=
sizeof(size_t);
1312 #if defined(ROBIN_HOOD_DISABLE_INTRINSICS)
1327 # if ROBIN_HOOD(LITTLE_ENDIAN)
1347 template <
typename HashKey>
1352 auto h =
static_cast<uint64_t
>(WHash::operator()(key));
1370 while (*info <
mInfo[*idx]) {
1378 size_t const insertion_idx) noexcept(std::is_nothrow_move_assignable<Node>::value) {
1379 auto idx = startIdx;
1381 while (--idx != insertion_idx) {
1386 while (idx != insertion_idx) {
1396 void shiftDown(
size_t idx) noexcept(std::is_nothrow_move_assignable<Node>::value) {
1417 template <
typename Other>
1426 if (info ==
mInfo[idx] &&
1431 if (info ==
mInfo[idx] &&
1436 }
while (info <=
mInfo[idx]);
1439 return mMask == 0 ? 0
1441 mKeyVals, reinterpret_cast_no_cast_align_warning<Node*>(
mInfo)));
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);
1475 while (0 !=
mInfo[idx]) {
1480 if (idx == insertion_idx) {
1481 ::new (
static_cast<void*
>(&l))
Node(std::move(keyval));
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)))
1516 template <
typename Iter>
1518 const Hash& h = Hash{},
const KeyEqual& equal = KeyEqual{})
1527 const KeyEqual& equal = KeyEqual{})
1542 mInfo = std::move(o.mInfo);
1544 mMask = std::move(o.mMask);
1561 mInfo = std::move(o.mInfo);
1563 mMask = std::move(o.mMask);
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 <<
")")
1597 detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
1599 mInfo =
reinterpret_cast<uint8_t*
>(
mKeyVals + numElementsWithBuffer);
1631 WHash::operator=(
static_cast<const WHash&
>(o));
1632 WKeyEqual::operator=(
static_cast<const WKeyEqual&
>(o));
1633 DataPool::operator=(
static_cast<DataPool const&
>(o));
1650 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
1651 ROBIN_HOOD_LOG(
"std::malloc " << numBytesTotal <<
" = calcNumBytesTotal("
1652 << numElementsWithBuffer <<
")")
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));
1694 uint8_t
const z = 0;
1695 std::fill(
mInfo,
mInfo + calcNumBytesInfo(numElementsWithBuffer),
z);
1696 mInfo[numElementsWithBuffer] = 1;
1714 for (
auto const& otherEntry : other) {
1715 if (!
has(otherEntry)) {
1728 template <
typename Q = mapped_type>
1732 switch (idxAndState.second) {
1737 ::new (
static_cast<void*
>(&
mKeyVals[idxAndState.first]))
1738 Node(*
this, std::piecewise_construct, std::forward_as_tuple(key),
1739 std::forward_as_tuple());
1743 mKeyVals[idxAndState.first] =
Node(*
this, std::piecewise_construct,
1744 std::forward_as_tuple(key), std::forward_as_tuple());
1748 throwOverflowError();
1751 return mKeyVals[idxAndState.first].getSecond();
1754 template <
typename Q = mapped_type>
1758 switch (idxAndState.second) {
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());
1770 Node(*
this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),
1771 std::forward_as_tuple());
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)...};
1800 switch (idxAndState.second) {
1806 ::new (
static_cast<void*
>(&
mKeyVals[idxAndState.first]))
Node(*
this, std::move(n));
1810 mKeyVals[idxAndState.first] = std::move(n);
1815 throwOverflowError();
1823 template <
typename... Args>
1828 template <
typename... Args>
1833 template <
typename... Args>
1840 template <
typename... Args>
1846 template <
typename Mapped>
1851 template <
typename Mapped>
1856 template <
typename Mapped>
1863 template <
typename Mapped>
1875 return emplace(std::move(keyval));
1882 if (kv != reinterpret_cast_no_cast_align_warning<Node*>(
mInfo)) {
1888 template <
typename OtherKey,
typename Self_ = Self>
1890 typename std::enable_if<Self_::is_transparent, size_t>::type
count(
const OtherKey& key)
const {
1893 if (kv != reinterpret_cast_no_cast_align_warning<Node*>(
mInfo)) {
1900 return 1U ==
count(key);
1903 template <
typename OtherKey,
typename Self_ = Self>
1905 typename std::enable_if<Self_::is_transparent, bool>::type
contains(
const OtherKey& key)
const {
1906 return 1U ==
count(key);
1911 template <
typename Q = mapped_type>
1913 typename std::enable_if<!std::is_void<Q>::value, Q&>::type
at(
key_type const& key) {
1916 if (kv == reinterpret_cast_no_cast_align_warning<Node*>(
mInfo)) {
1917 doThrow<std::out_of_range>(
"key not found");
1919 return kv->getSecond();
1924 template <
typename Q = mapped_type>
1926 typename std::enable_if<!std::is_void<Q>::value, Q
const&>::type
at(
key_type const& key)
const {
1929 if (kv == reinterpret_cast_no_cast_align_warning<Node*>(
mInfo)) {
1930 doThrow<std::out_of_range>(
"key not found");
1932 return kv->getSecond();
1937 const size_t idx =
findIdx(key);
1941 template <
typename OtherKey>
1944 const size_t idx =
findIdx(key);
1948 template <
typename OtherKey,
typename Self_ = Self>
1949 typename std::enable_if<Self_::is_transparent,
1953 const size_t idx =
findIdx(key);
1959 const size_t idx =
findIdx(key);
1963 template <
typename OtherKey>
1966 const size_t idx =
findIdx(key);
1970 template <
typename OtherKey,
typename Self_ = Self>
1971 typename std::enable_if<Self_::is_transparent, iterator>::type
find(
const OtherKey& key) {
1973 const size_t idx =
findIdx(key);
2000 return iterator{reinterpret_cast_no_cast_align_warning<Node*>(
mInfo),
nullptr};
2044 if (info ==
mInfo[idx] && WKeyEqual::operator()(key,
mKeyVals[idx].getFirst())) {
2050 }
while (info <=
mInfo[idx]);
2075 while (calcMaxNumElementsAllowed(newSize) <
mNumElements && newSize != 0) {
2079 throwOverflowError();
2086 if (newSize <
mMask + 1) {
2108 return MaxLoadFactor100 / 100.0F;
2114 return static_cast<float>(
size()) /
static_cast<float>(
mMask + 1);
2122 ROBIN_HOOD(NODISCARD)
size_t calcMaxNumElementsAllowed(
size_t maxElements)
const noexcept {
2123 if (
ROBIN_HOOD_LIKELY(maxElements <= (std::numeric_limits<size_t>::max)() / 100)) {
2124 return maxElements * MaxLoadFactor100 / 100;
2128 return (maxElements / 100) * MaxLoadFactor100;
2131 ROBIN_HOOD(NODISCARD)
size_t calcNumBytesInfo(
size_t numElements)
const noexcept {
2134 return numElements +
sizeof(uint64_t);
2139 auto maxNumElementsAllowed = calcMaxNumElementsAllowed(numElements);
2140 return numElements + (std::min)(maxNumElementsAllowed, (
static_cast<size_t>(0xFF)));
2144 ROBIN_HOOD(NODISCARD)
size_t calcNumBytesTotal(
size_t numElements)
const {
2145 #if ROBIN_HOOD(BITNESS) == 64
2146 return numElements *
sizeof(
Node) + calcNumBytesInfo(numElements);
2149 auto const ne =
static_cast<uint64_t
>(numElements);
2150 auto const s =
static_cast<uint64_t
>(
sizeof(
Node));
2151 auto const infos =
static_cast<uint64_t
>(calcNumBytesInfo(numElements));
2153 auto const total64 = ne * s + infos;
2154 auto const total =
static_cast<size_t>(total64);
2157 throwOverflowError();
2164 template <
typename Q = mapped_type>
2168 auto it =
find(e.first);
2169 return it !=
end() && it->second == e.second;
2172 template <
typename Q = mapped_type>
2181 auto const minElementsAllowed = (std::max)(
c,
mNumElements);
2183 while (calcMaxNumElementsAllowed(newSize) < minElementsAllowed && newSize != 0) {
2187 throwOverflowError();
2194 if (forceRehash || newSize >
mMask + 1) {
2206 uint8_t
const*
const oldInfo =
mInfo;
2212 if (oldMaxElementsWithBuffer > 1) {
2213 for (
size_t i = 0; i < oldMaxElementsWithBuffer; ++i) {
2214 if (oldInfo[i] != 0) {
2219 oldKeyVals[i].~Node();
2226 if (oldKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&
mMask)) {
2229 std::free(oldKeyVals);
2231 DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer));
2238 #if ROBIN_HOOD(HAS_EXCEPTIONS)
2239 throw std::overflow_error(
"robin_hood::map overflow");
2245 template <
typename OtherKey,
typename... Args>
2249 switch (idxAndState.second) {
2254 ::new (
static_cast<void*
>(&
mKeyVals[idxAndState.first]))
Node(
2255 *
this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
2256 std::forward_as_tuple(std::forward<Args>(args)...));
2260 mKeyVals[idxAndState.first] =
Node(*
this, std::piecewise_construct,
2261 std::forward_as_tuple(std::forward<OtherKey>(key)),
2262 std::forward_as_tuple(std::forward<Args>(args)...));
2266 throwOverflowError();
2274 template <
typename OtherKey,
typename Mapped>
2278 switch (idxAndState.second) {
2280 mKeyVals[idxAndState.first].getSecond() = std::forward<Mapped>(obj);
2284 ::new (
static_cast<void*
>(&
mKeyVals[idxAndState.first]))
Node(
2285 *
this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
2286 std::forward_as_tuple(std::forward<Mapped>(obj)));
2290 mKeyVals[idxAndState.first] =
Node(*
this, std::piecewise_construct,
2291 std::forward_as_tuple(std::forward<OtherKey>(key)),
2292 std::forward_as_tuple(std::forward<Mapped>(obj)));
2296 throwOverflowError();
2306 mMask = max_elements - 1;
2312 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
2313 ROBIN_HOOD_LOG(
"std::calloc " << numBytesTotal <<
" = calcNumBytesTotal("
2314 << numElementsWithBuffer <<
")")
2316 detail::assertNotNull<std::bad_alloc>(std::calloc(1, numBytesTotal)));
2317 mInfo =
reinterpret_cast<uint8_t*
>(
mKeyVals + numElementsWithBuffer);
2320 mInfo[numElementsWithBuffer] = 1;
2331 template <
typename OtherKey>
2333 for (
int i = 0; i < 256; ++i) {
2340 while (info ==
mInfo[idx]) {
2341 if (WKeyEqual::operator()(key,
mKeyVals[idx].getFirst())) {
2358 auto const insertion_idx = idx;
2359 auto const insertion_info = info;
2365 while (0 !=
mInfo[idx]) {
2369 if (idx != insertion_idx) {
2373 mInfo[insertion_idx] =
static_cast<uint8_t
>(insertion_info);
2375 return std::make_pair(insertion_idx, idx == insertion_idx
2386 <<
", maxNumElementsAllowed="
2387 << calcMaxNumElementsAllowed(
mMask + 1))
2400 for (
size_t i = 0; i < numElementsWithBuffer; i += 8) {
2401 auto val = unaligned_load<uint64_t>(
mInfo + i);
2402 val = (val >> 1U) & UINT64_C(0x7f7f7f7f7f7f7f7f);
2403 std::memcpy(
mInfo + i, &val,
sizeof(val));
2406 mInfo[numElementsWithBuffer] = 1;
2420 auto const maxNumElementsAllowed = calcMaxNumElementsAllowed(
mMask + 1);
2426 << maxNumElementsAllowed <<
", load="
2428 (
static_cast<double>(
mMask) + 1)))
2457 .nodesDoNotDeallocate(*
this);
2463 if (
mKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&
mMask)) {
2470 mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&
mMask);
2495 template <
typename Key,
typename T,
typename Hash = hash<Key>,
2496 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2499 template <
typename Key,
typename T,
typename Hash = hash<Key>,
2500 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2503 template <
typename Key,
typename T,
typename Hash = hash<Key>,
2504 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2507 std::is_nothrow_move_constructible<robin_hood::pair<Key, T>>::value &&
2508 std::is_nothrow_move_assignable<robin_hood::pair<Key, T>>::value,
2509 MaxLoadFactor100, Key, T, Hash, KeyEqual>;
2513 template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2514 size_t MaxLoadFactor100 = 80>
2517 template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2518 size_t MaxLoadFactor100 = 80>
2521 template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2522 size_t MaxLoadFactor100 = 80>
2524 std::is_nothrow_move_constructible<Key>::value &&
2525 std::is_nothrow_move_assignable<Key>::value,
2526 MaxLoadFactor100, Key, void, Hash, KeyEqual>;