34 #ifndef NAV2_SMAC_PLANNER__THIRDPARTY__ROBIN_HOOD_H_
35 #define NAV2_SMAC_PLANNER__THIRDPARTY__ROBIN_HOOD_H_
38 #define ROBIN_HOOD_VERSION_MAJOR 3
39 #define ROBIN_HOOD_VERSION_MINOR 11
40 #define ROBIN_HOOD_VERSION_PATCH 5
50 #include <type_traits>
53 #if __cplusplus >= 201703L
54 # include <string_view>
59 #ifdef ROBIN_HOOD_LOG_ENABLED
61 # define ROBIN_HOOD_LOG(...) \
62 std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << __VA_ARGS__ << std::endl;
64 # define ROBIN_HOOD_LOG(x)
68 #ifdef ROBIN_HOOD_TRACE_ENABLED
70 # define ROBIN_HOOD_TRACE(...) \
71 std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << __VA_ARGS__ << std::endl;
73 # define ROBIN_HOOD_TRACE(x)
77 #ifdef ROBIN_HOOD_COUNT_ENABLED
79 # define ROBIN_HOOD_COUNT(x) ++counts().x;
80 namespace robin_hood {
85 inline std::ostream& operator<<(std::ostream& os, Counts
const& c) {
86 return os << c.shiftUp <<
" shiftUp" << std::endl << c.shiftDown <<
" shiftDown" << std::endl;
89 static Counts& counts() {
90 static Counts counts{};
95 # define ROBIN_HOOD_COUNT(x)
100 #define ROBIN_HOOD(x) ROBIN_HOOD_PRIVATE_DEFINITION_##x()
103 #define ROBIN_HOOD_UNUSED(identifier)
106 #if SIZE_MAX == UINT32_MAX
107 # define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 32
108 #elif SIZE_MAX == UINT64_MAX
109 # define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 64
111 # error Unsupported bitness
116 # define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() 1
117 # define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() 0
119 # define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() \
120 (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
121 # define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
126 # define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __declspec(noinline)
128 # define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __attribute__((noinline))
132 #if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND)
133 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 0
135 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 1
139 #if !defined(ROBIN_HOOD_DISABLE_INTRINSICS)
141 # if ROBIN_HOOD(BITNESS) == 32
142 # define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward
144 # define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward64
147 # pragma intrinsic(ROBIN_HOOD(BITSCANFORWARD))
148 # define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) \
149 [](size_t mask) noexcept -> int { \
155 # if ROBIN_HOOD(BITNESS) == 32
156 # define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzl
157 # define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzl
159 # define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzll
160 # define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzll
162 # define ROBIN_HOOD_COUNT_LEADING_ZEROES(x) ((x) ? ROBIN_HOOD(CLZ)(x) : ROBIN_HOOD(BITNESS))
163 # define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ((x) ? ROBIN_HOOD(CTZ)(x) : ROBIN_HOOD(BITNESS))
168 #ifndef __has_cpp_attribute
169 # define __has_cpp_attribute(x) 0
171 #if __has_cpp_attribute(clang::fallthrough)
172 # define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[clang::fallthrough]]
173 #elif __has_cpp_attribute(gnu::fallthrough)
174 # define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[gnu::fallthrough]]
176 # define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH()
181 # define ROBIN_HOOD_LIKELY(condition) condition
182 # define ROBIN_HOOD_UNLIKELY(condition) condition
184 # define ROBIN_HOOD_LIKELY(condition) __builtin_expect(condition, 1)
185 # define ROBIN_HOOD_UNLIKELY(condition) __builtin_expect(condition, 0)
190 # ifdef _NATIVE_WCHAR_T_DEFINED
191 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1
193 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 0
196 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1
201 # if _MSC_VER <= 1900
202 # define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 1
204 # define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0
207 # define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0
212 #if defined(__GNUC__) && __GNUC__ < 5
213 # define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)
215 # define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value
219 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX() __cplusplus
220 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX98() 199711L
221 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX11() 201103L
222 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX14() 201402L
223 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX17() 201703L
225 #if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)
226 # define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD() [[nodiscard]]
228 # define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD()
231 namespace robin_hood {
233 #if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)
234 # define ROBIN_HOOD_STD std
238 namespace ROBIN_HOOD_STD {
241 : std::integral_constant<std::size_t, alignof(typename std::remove_all_extents<T>::type)> {};
243 template <
class T, T... Ints>
246 using value_type = T;
247 static_assert(std::is_integral<value_type>::value,
"not integral type");
248 static constexpr std::size_t size() noexcept {
249 return sizeof...(Ints);
252 template <std::size_t... Inds>
256 template <
class T, T Begin, T End,
bool>
259 static_assert(std::is_integral<TValue>::value,
"not integral type");
260 static_assert(Begin >= 0 && Begin < End,
"unexpected argument (Begin<0 || Begin<=End)");
262 template <
class,
class>
265 template <TValue... Inds0, TValue... Inds1>
272 (End - Begin) / 2 == 1>::TResult,
273 typename IntSeqImpl<TValue, Begin + (End - Begin) / 2, End,
274 (End - Begin + 1) / 2 == 1>::TResult>::TResult;
277 template <
class T, T Begin>
280 static_assert(std::is_integral<TValue>::value,
"not integral type");
281 static_assert(Begin >= 0,
"unexpected argument (Begin<0)");
285 template <
class T, T Begin, T End>
288 static_assert(std::is_integral<TValue>::value,
"not integral type");
289 static_assert(Begin >= 0,
"unexpected argument (Begin<0)");
294 template <
class T, T N>
295 using make_integer_sequence =
typename detail_::IntSeqImpl<T, 0, N, (N - 0) == 1>::TResult;
297 template <std::
size_t N>
298 using make_index_sequence = make_integer_sequence<std::size_t, N>;
300 template <
class... T>
301 using index_sequence_for = make_index_sequence<
sizeof...(T)>;
310 #if ROBIN_HOOD(BITNESS) == 64
311 using SizeT = uint64_t;
313 using SizeT = uint32_t;
316 template <
typename T>
317 T rotr(T x,
unsigned k) {
318 return (x >> k) | (x << (8U *
sizeof(T) - k));
324 template <
typename T>
325 inline T reinterpret_cast_no_cast_align_warning(
void* ptr) noexcept {
326 return reinterpret_cast<T
>(ptr);
329 template <
typename T>
330 inline T reinterpret_cast_no_cast_align_warning(
void const* ptr) noexcept {
331 return reinterpret_cast<T
>(ptr);
336 template <
typename E,
typename... Args>
337 [[noreturn]] ROBIN_HOOD(NOINLINE)
338 #if ROBIN_HOOD(HAS_EXCEPTIONS)
339 void doThrow(Args&&... args) {
340 throw E(std::forward<Args>(args)...);
343 void doThrow(Args&&... ROBIN_HOOD_UNUSED(args) ) {
348 template <
typename E,
typename T,
typename... Args>
349 T* assertNotNull(T* t, Args&&... args) {
350 if (ROBIN_HOOD_UNLIKELY(
nullptr == t)) {
351 doThrow<E>(std::forward<Args>(args)...);
356 template <
typename T>
357 inline T unaligned_load(
void const* ptr) noexcept {
361 std::memcpy(&t, ptr,
sizeof(T));
368 template <
typename T,
size_t MinNumAllocs = 4,
size_t MaxNumAllocs = 256>
376 , mListForFree(
nullptr) {}
380 , mListForFree(o.mListForFree) {
381 o.mListForFree =
nullptr;
388 mListForFree = o.mListForFree;
389 o.mListForFree =
nullptr;
405 void reset() noexcept {
406 while (mListForFree) {
407 T* tmp = *mListForFree;
408 ROBIN_HOOD_LOG(
"std::free")
409 std::free(mListForFree);
410 mListForFree = reinterpret_cast_no_cast_align_warning<T**>(tmp);
421 tmp = performAllocation();
424 mHead = *reinterpret_cast_no_cast_align_warning<T**>(tmp);
432 void deallocate(T* obj) noexcept {
433 *reinterpret_cast_no_cast_align_warning<T**>(obj) = mHead;
440 void addOrFree(
void* ptr,
const size_t numBytes) noexcept {
442 if (numBytes < ALIGNMENT + ALIGNED_SIZE) {
444 ROBIN_HOOD_LOG(
"std::free")
447 ROBIN_HOOD_LOG(
"add to buffer")
454 swap(mHead, other.mHead);
455 swap(mListForFree, other.mListForFree);
463 ROBIN_HOOD(NODISCARD)
size_t calcNumElementsToAlloc()
const noexcept {
464 auto tmp = mListForFree;
465 size_t numAllocs = MinNumAllocs;
467 while (numAllocs * 2 <= MaxNumAllocs && tmp) {
468 auto x =
reinterpret_cast<T***
>(tmp);
477 void add(
void* ptr,
const size_t numBytes) noexcept {
478 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) =
506 ROBIN_HOOD(NOINLINE) T* performAllocation() {
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 =
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};
540 template <
typename T,
size_t MinSize,
size_t MaxSize,
bool IsFlat>
544 template <
typename T,
size_t MinSize,
size_t MaxSize>
547 void addOrFree(
void* ptr,
size_t ROBIN_HOOD_UNUSED(numBytes)) noexcept {
548 ROBIN_HOOD_LOG(
"std::free")
553 template <
typename T,
size_t MinSize,
size_t MaxSize>
558 namespace swappable {
559 #if ROBIN_HOOD(CXX) < ROBIN_HOOD(CXX17)
561 template <
typename T>
563 static const bool value = noexcept(swap(std::declval<T&>(), std::declval<T&>()));
566 template <
typename T>
568 static const bool value = std::is_nothrow_swappable<T>::value;
580 template <
typename T1,
typename T2>
582 using first_type = T1;
583 using second_type = T2;
585 template <
typename U1 = T1,
typename U2 = T2,
586 typename =
typename std::enable_if<std::is_default_constructible<U1>::value &&
587 std::is_default_constructible<U2>::value>::type>
588 constexpr
pair() noexcept(noexcept(U1()) && noexcept(U2()))
593 explicit constexpr
pair(std::pair<T1, T2>
const& o) noexcept(
594 noexcept(T1(std::declval<T1 const&>())) && noexcept(T2(std::declval<T2 const&>())))
596 , second(o.second) {}
599 explicit constexpr
pair(std::pair<T1, T2>&& o) noexcept(noexcept(
600 T1(std::move(std::declval<T1&&>()))) && noexcept(T2(std::move(std::declval<T2&&>()))))
601 : first(std::move(o.first))
602 , second(std::move(o.second)) {}
604 constexpr
pair(T1&& a, T2&& b) noexcept(noexcept(
605 T1(std::move(std::declval<T1&&>()))) && noexcept(T2(std::move(std::declval<T2&&>()))))
606 : first(std::move(a))
607 , second(std::move(b)) {}
609 template <
typename U1,
typename U2>
610 constexpr
pair(U1&& a, U2&& b) noexcept(noexcept(T1(std::forward<U1>(
611 std::declval<U1&&>()))) && noexcept(T2(std::forward<U2>(std::declval<U2&&>()))))
612 : first(std::forward<U1>(a))
613 , second(std::forward<U2>(b)) {}
615 template <
typename... U1,
typename... U2>
618 #if !ROBIN_HOOD(BROKEN_CONSTEXPR)
621 pair(std::piecewise_construct_t , std::tuple<U1...> a,
623 b) noexcept(noexcept(
pair(std::declval<std::tuple<U1...>&>(),
624 std::declval<std::tuple<U2...>&>(),
625 ROBIN_HOOD_STD::index_sequence_for<U1...>(),
626 ROBIN_HOOD_STD::index_sequence_for<U2...>())))
627 :
pair(a, b, ROBIN_HOOD_STD::index_sequence_for<U1...>(),
628 ROBIN_HOOD_STD::index_sequence_for<U2...>()) {
632 template <
typename... U1,
size_t... I1,
typename... U2,
size_t... I2>
634 std::tuple<U1...>& a, std::tuple<U2...>& b,
637 noexcept(T1(std::forward<U1>(std::get<I1>(
638 std::declval<std::tuple<
639 U1...>&>()))...)) && noexcept(T2(std::
640 forward<U2>(std::get<I2>(
641 std::declval<std::tuple<U2...>&>()))...)))
642 : first(std::forward<U1>(std::get<I1>(a))...)
643 , second(std::forward<U2>(std::get<I2>(b))...) {
653 swap(first, o.first);
654 swap(second, o.second);
661 template <
typename A,
typename B>
667 template <
typename A,
typename B>
668 inline constexpr
bool operator==(pair<A, B>
const& x, pair<A, B>
const& y) {
669 return (x.first == y.first) && (x.second == y.second);
671 template <
typename A,
typename B>
672 inline constexpr
bool operator!=(pair<A, B>
const& x, pair<A, B>
const& y) {
675 template <
typename A,
typename B>
676 inline constexpr
bool operator<(pair<A, B>
const& x, pair<A, B>
const& y) noexcept(noexcept(
677 std::declval<A const&>() < std::declval<A const&>()) && noexcept(std::declval<B const&>() <
678 std::declval<B const&>())) {
679 return x.first < y.first || (!(y.first < x.first) && x.second < y.second);
681 template <
typename A,
typename B>
682 inline constexpr
bool operator>(pair<A, B>
const& x, pair<A, B>
const& y) {
685 template <
typename A,
typename B>
686 inline constexpr
bool operator<=(pair<A, B>
const& x, pair<A, B>
const& y) {
689 template <
typename A,
typename B>
690 inline constexpr
bool operator>=(pair<A, B>
const& x, pair<A, B>
const& y) {
694 inline size_t hash_bytes(
void const* ptr,
size_t len) noexcept {
695 static constexpr uint64_t m = UINT64_C(0xc6a4a7935bd1e995);
696 static constexpr uint64_t seed = UINT64_C(0xe17a1465);
697 static constexpr
unsigned int r = 47;
699 auto const*
const data64 =
static_cast<uint64_t const*
>(ptr);
700 uint64_t h = seed ^ (len * m);
702 size_t const n_blocks = len / 8;
703 for (
size_t i = 0; i < n_blocks; ++i) {
704 auto k = detail::unaligned_load<uint64_t>(data64 + i);
714 auto const*
const data8 =
reinterpret_cast<uint8_t const*
>(data64 + n_blocks);
717 h ^=
static_cast<uint64_t
>(data8[6]) << 48U;
718 ROBIN_HOOD(FALLTHROUGH);
720 h ^=
static_cast<uint64_t
>(data8[5]) << 40U;
721 ROBIN_HOOD(FALLTHROUGH);
723 h ^=
static_cast<uint64_t
>(data8[4]) << 32U;
724 ROBIN_HOOD(FALLTHROUGH);
726 h ^=
static_cast<uint64_t
>(data8[3]) << 24U;
727 ROBIN_HOOD(FALLTHROUGH);
729 h ^=
static_cast<uint64_t
>(data8[2]) << 16U;
730 ROBIN_HOOD(FALLTHROUGH);
732 h ^=
static_cast<uint64_t
>(data8[1]) << 8U;
733 ROBIN_HOOD(FALLTHROUGH);
735 h ^=
static_cast<uint64_t
>(data8[0]);
737 ROBIN_HOOD(FALLTHROUGH);
747 return static_cast<size_t>(h);
750 inline size_t hash_int(uint64_t x) noexcept {
754 x *= UINT64_C(0xff51afd7ed558ccd);
760 return static_cast<size_t>(x);
764 template <
typename T,
typename Enable =
void>
765 struct hash :
public std::hash<T> {
766 size_t operator()(T
const& obj)
const
767 noexcept(noexcept(std::declval<std::hash<T>>().
operator()(std::declval<T const&>()))) {
769 auto result = std::hash<T>::operator()(obj);
771 return hash_int(
static_cast<detail::SizeT
>(result));
775 template <
typename CharT>
776 struct hash<std::basic_string<CharT>> {
777 size_t operator()(std::basic_string<CharT>
const& str)
const noexcept {
778 return hash_bytes(str.data(),
sizeof(CharT) * str.size());
782 #if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)
783 template <
typename CharT>
784 struct hash<std::basic_string_view<CharT>> {
785 size_t operator()(std::basic_string_view<CharT>
const& sv)
const noexcept {
786 return hash_bytes(sv.data(),
sizeof(CharT) * sv.size());
793 size_t operator()(T* ptr)
const noexcept {
794 return hash_int(
reinterpret_cast<detail::SizeT
>(ptr));
799 struct hash<std::unique_ptr<T>> {
800 size_t operator()(std::unique_ptr<T>
const& ptr)
const noexcept {
801 return hash_int(
reinterpret_cast<detail::SizeT
>(ptr.get()));
806 struct hash<std::shared_ptr<T>> {
807 size_t operator()(std::shared_ptr<T>
const& ptr)
const noexcept {
808 return hash_int(
reinterpret_cast<detail::SizeT
>(ptr.get()));
812 template <
typename Enum>
813 struct hash<Enum, typename std::enable_if<std::is_enum<Enum>::value>::type> {
814 size_t operator()(Enum e)
const noexcept {
815 using Underlying =
typename std::underlying_type<Enum>::type;
820 #define ROBIN_HOOD_HASH_INT(T) \
823 size_t operator()(T const& obj) const noexcept { \
824 return hash_int(static_cast<uint64_t>(obj)); \
828 #if defined(__GNUC__) && !defined(__clang__)
829 # pragma GCC diagnostic push
830 # pragma GCC diagnostic ignored "-Wuseless-cast"
833 ROBIN_HOOD_HASH_INT(
bool);
834 ROBIN_HOOD_HASH_INT(
char);
835 ROBIN_HOOD_HASH_INT(
signed char);
836 ROBIN_HOOD_HASH_INT(
unsigned char);
837 ROBIN_HOOD_HASH_INT(char16_t);
838 ROBIN_HOOD_HASH_INT(char32_t);
839 #if ROBIN_HOOD(HAS_NATIVE_WCHART)
840 ROBIN_HOOD_HASH_INT(
wchar_t);
842 ROBIN_HOOD_HASH_INT(
short);
843 ROBIN_HOOD_HASH_INT(
unsigned short);
844 ROBIN_HOOD_HASH_INT(
int);
845 ROBIN_HOOD_HASH_INT(
unsigned int);
846 ROBIN_HOOD_HASH_INT(
long);
847 ROBIN_HOOD_HASH_INT(
long long);
848 ROBIN_HOOD_HASH_INT(
unsigned long);
849 ROBIN_HOOD_HASH_INT(
unsigned long long);
850 #if defined(__GNUC__) && !defined(__clang__)
851 # pragma GCC diagnostic pop
855 template <
typename T>
860 template <
typename T,
typename =
void>
863 template <
typename T>
865 :
public std::true_type {};
869 template <
typename T>
872 explicit WrapHash(T
const& o) noexcept(noexcept(T(std::declval<T const&>())))
876 template <
typename T>
879 explicit WrapKeyEqual(T
const& o) noexcept(noexcept(T(std::declval<T const&>())))
909 template <
bool IsFlat,
size_t MaxLoadFactor100,
typename Key,
typename T,
typename Hash,
915 typename std::conditional<
916 std::is_void<T>::value, Key,
917 robin_hood::pair<typename std::conditional<IsFlat, Key, Key const>::type, T>>::type,
920 static constexpr
bool is_flat = IsFlat;
921 static constexpr
bool is_map = !std::is_void<T>::value;
922 static constexpr
bool is_set = !is_map;
923 static constexpr
bool is_transparent =
926 using key_type = Key;
927 using mapped_type = T;
928 using value_type =
typename std::conditional<
931 using size_type = size_t;
933 using key_equal = KeyEqual;
937 static_assert(MaxLoadFactor100 > 10 && MaxLoadFactor100 < 100,
938 "MaxLoadFactor100 needs to be >10 && < 100");
946 static constexpr
size_t InitialNumElements =
sizeof(uint64_t);
947 static constexpr uint32_t InitialInfoNumBits = 5;
948 static constexpr uint8_t InitialInfoInc = 1U << InitialInfoNumBits;
949 static constexpr
size_t InfoMask = InitialInfoInc - 1U;
950 static constexpr uint8_t InitialInfoHashShift = 0;
954 using InfoType = uint32_t;
961 template <
typename M,
bool>
965 template <
typename M>
966 class DataNode<M, true> final {
968 template <
typename... Args>
969 explicit DataNode(M& ROBIN_HOOD_UNUSED(map) , Args&&... args) noexcept(
970 noexcept(value_type(std::forward<Args>(args)...)))
971 : mData(std::forward<Args>(args)...) {}
973 DataNode(M& ROBIN_HOOD_UNUSED(map) , DataNode<M, true>&& n) noexcept(
974 std::is_nothrow_move_constructible<value_type>::value)
975 : mData(std::move(n.mData)) {}
978 void destroy(M& ROBIN_HOOD_UNUSED(map) ) noexcept {}
979 void destroyDoNotDeallocate() noexcept {}
981 value_type
const* operator->()
const noexcept {
984 value_type* operator->() noexcept {
988 const value_type& operator*()
const noexcept {
992 value_type& operator*() noexcept {
996 template <
typename VT = value_type>
997 ROBIN_HOOD(NODISCARD)
998 typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {
1001 template <
typename VT = value_type>
1002 ROBIN_HOOD(NODISCARD)
1003 typename std::enable_if<is_set, VT&>::type getFirst() noexcept {
1007 template <
typename VT = value_type>
1008 ROBIN_HOOD(NODISCARD)
1009 typename std::enable_if<is_map, typename VT::first_type const&>::type
1010 getFirst()
const noexcept {
1013 template <
typename VT = value_type>
1014 ROBIN_HOOD(NODISCARD)
1015 typename std::enable_if<is_set, VT const&>::type getFirst()
const noexcept {
1019 template <
typename MT = mapped_type>
1020 ROBIN_HOOD(NODISCARD)
1021 typename std::enable_if<is_map, MT&>::type getSecond() noexcept {
1022 return mData.second;
1025 template <
typename MT = mapped_type>
1026 ROBIN_HOOD(NODISCARD)
1027 typename std::enable_if<is_set, MT const&>::type getSecond()
const noexcept {
1028 return mData.second;
1031 void swap(DataNode<M, true>& o) noexcept(
1032 noexcept(std::declval<value_type>().swap(std::declval<value_type>()))) {
1033 mData.swap(o.mData);
1041 template <
typename M>
1042 class DataNode<M, false> {
1044 template <
typename... Args>
1045 explicit DataNode(M& map, Args&&... args)
1046 : mData(map.allocate()) {
1047 ::new (
static_cast<void*
>(mData)) value_type(std::forward<Args>(args)...);
1050 DataNode(M& ROBIN_HOOD_UNUSED(map) , DataNode<M, false>&& n) noexcept
1051 : mData(std::move(n.mData)) {}
1053 void destroy(M& map) noexcept {
1055 mData->~value_type();
1056 map.deallocate(mData);
1059 void destroyDoNotDeallocate() noexcept {
1060 mData->~value_type();
1063 value_type
const* operator->()
const noexcept {
1067 value_type* operator->() noexcept {
1071 const value_type& operator*()
const {
1075 value_type& operator*() {
1079 template <
typename VT = value_type>
1080 ROBIN_HOOD(NODISCARD)
1081 typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {
1082 return mData->first;
1084 template <
typename VT = value_type>
1085 ROBIN_HOOD(NODISCARD)
1086 typename std::enable_if<is_set, VT&>::type getFirst() noexcept {
1090 template <
typename VT = value_type>
1091 ROBIN_HOOD(NODISCARD)
1092 typename std::enable_if<is_map, typename VT::first_type const&>::type
1093 getFirst()
const noexcept {
1094 return mData->first;
1096 template <
typename VT = value_type>
1097 ROBIN_HOOD(NODISCARD)
1098 typename std::enable_if<is_set, VT const&>::type getFirst()
const noexcept {
1102 template <
typename MT = mapped_type>
1103 ROBIN_HOOD(NODISCARD)
1104 typename std::enable_if<is_map, MT&>::type getSecond() noexcept {
1105 return mData->second;
1108 template <
typename MT = mapped_type>
1109 ROBIN_HOOD(NODISCARD)
1110 typename std::enable_if<is_map, MT const&>::type getSecond()
const noexcept {
1111 return mData->second;
1114 void swap(DataNode<M, false>& o) noexcept {
1116 swap(mData, o.mData);
1123 using Node = DataNode<Self, IsFlat>;
1126 ROBIN_HOOD(NODISCARD) key_type
const& getFirstConst(Node
const& n)
const noexcept {
1127 return n.getFirst();
1132 ROBIN_HOOD(NODISCARD) key_type
const& getFirstConst(key_type
const& k)
const noexcept {
1137 template <
typename Q = mapped_type>
1138 ROBIN_HOOD(NODISCARD)
1139 typename std::enable_if<!std::is_void<Q>::value, key_type
const&>::type
1140 getFirstConst(value_type
const& vt)
const noexcept {
1146 template <
typename M,
bool UseMemcpy>
1150 template <
typename M>
1151 struct Cloner<M, true> {
1152 void operator()(M
const& source, M& target)
const {
1153 auto const*
const src =
reinterpret_cast<char const*
>(source.mKeyVals);
1154 auto* tgt =
reinterpret_cast<char*
>(target.mKeyVals);
1155 auto const numElementsWithBuffer = target.calcNumElementsWithBuffer(target.mMask + 1);
1156 std::copy(src, src + target.calcNumBytesTotal(numElementsWithBuffer), tgt);
1160 template <
typename M>
1161 struct Cloner<M, false> {
1162 void operator()(M
const& s, M& t)
const {
1163 auto const numElementsWithBuffer = t.calcNumElementsWithBuffer(t.mMask + 1);
1164 std::copy(s.mInfo, s.mInfo + t.calcNumBytesInfo(numElementsWithBuffer), t.mInfo);
1166 for (
size_t i = 0; i < numElementsWithBuffer; ++i) {
1168 ::new (
static_cast<void*
>(t.mKeyVals + i)) Node(t, *s.mKeyVals[i]);
1176 template <
typename M,
bool IsFlatAndTrivial>
1177 struct Destroyer {};
1179 template <
typename M>
1180 struct Destroyer<M, true> {
1181 void nodes(M& m)
const noexcept {
1185 void nodesDoNotDeallocate(M& m)
const noexcept {
1190 template <
typename M>
1191 struct Destroyer<M, false> {
1192 void nodes(M& m)
const noexcept {
1195 auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
1197 for (
size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
1198 if (0 != m.mInfo[idx]) {
1199 Node& n = m.mKeyVals[idx];
1206 void nodesDoNotDeallocate(M& m)
const noexcept {
1209 auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
1210 for (
size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
1211 if (0 != m.mInfo[idx]) {
1212 Node& n = m.mKeyVals[idx];
1213 n.destroyDoNotDeallocate();
1222 struct fast_forward_tag {};
1225 template <
bool IsConst>
1228 using NodePtr =
typename std::conditional<IsConst, Node const*, Node*>::type;
1231 using difference_type = std::ptrdiff_t;
1232 using value_type =
typename Self::value_type;
1233 using reference =
typename std::conditional<IsConst, value_type const&, value_type&>::type;
1234 using pointer =
typename std::conditional<IsConst, value_type const*, value_type*>::type;
1235 using iterator_category = std::forward_iterator_tag;
1245 template <
bool OtherIsConst,
1246 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,
1256 fast_forward_tag ROBIN_HOOD_UNUSED(tag) ) noexcept
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)
1314 if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint32_t>(mInfo))) {
1318 if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint16_t>(mInfo))) {
1322 if (ROBIN_HOOD_UNLIKELY(0U == *mInfo)) {
1327 # if ROBIN_HOOD(LITTLE_ENDIAN)
1328 auto inc = ROBIN_HOOD_COUNT_TRAILING_ZEROES(n) / 8;
1330 auto inc = ROBIN_HOOD_COUNT_LEADING_ZEROES(n) / 8;
1337 friend class Table<IsFlat, MaxLoadFactor100, key_type, mapped_type, hasher, key_equal>;
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) {
1387 ROBIN_HOOD_COUNT(shiftUp)
1388 mInfo[idx] =
static_cast<uint8_t
>(mInfo[idx - 1] + mInfoInc);
1389 if (ROBIN_HOOD_UNLIKELY(mInfo[idx] + mInfoInc > 0xFF)) {
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) {
1404 ROBIN_HOOD_COUNT(shiftDown)
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>
1418 ROBIN_HOOD(NODISCARD)
1419 size_t findIdx(Other
const& key)
const {
1422 keyToIdx(key, &idx, &info);
1426 if (info == mInfo[idx] &&
1427 ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) {
1431 if (info == mInfo[idx] &&
1432 ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) {
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);
1470 if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {
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;
1494 using iterator = Iter<false>;
1495 using const_iterator = Iter<true>;
1497 Table() noexcept(noexcept(Hash()) && noexcept(KeyEqual()))
1500 ROBIN_HOOD_TRACE(
this)
1509 size_t ROBIN_HOOD_UNUSED(bucket_count) ,
const Hash& h = Hash{},
1510 const KeyEqual& equal = KeyEqual{}) noexcept(noexcept(Hash(h)) && noexcept(KeyEqual(equal)))
1513 ROBIN_HOOD_TRACE(
this)
1516 template <
typename Iter>
1517 Table(Iter first, Iter last,
size_t ROBIN_HOOD_UNUSED(bucket_count) = 0,
1518 const Hash& h = Hash{},
const KeyEqual& equal = KeyEqual{})
1521 ROBIN_HOOD_TRACE(
this)
1522 insert(first, last);
1525 Table(std::initializer_list<value_type> initlist,
1526 size_t ROBIN_HOOD_UNUSED(bucket_count) = 0,
const Hash& h = Hash{},
1527 const KeyEqual& equal = KeyEqual{})
1530 ROBIN_HOOD_TRACE(
this)
1531 insert(initlist.begin(), initlist.end());
1538 ROBIN_HOOD_TRACE(
this)
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);
1554 ROBIN_HOOD_TRACE(
this)
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)));
1585 ROBIN_HOOD_TRACE(
this)
1590 auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);
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;
1612 ROBIN_HOOD_TRACE(
this)
1630 WHash::operator=(
static_cast<const WHash&
>(o));
1631 WKeyEqual::operator=(
static_cast<const WKeyEqual&
>(o));
1632 DataPool::operator=(
static_cast<DataPool const&
>(o));
1638 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*
this);
1640 if (mMask != o.mMask) {
1644 ROBIN_HOOD_LOG(
"std::free")
1645 std::free(mKeyVals);
1648 auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);
1649 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
1650 ROBIN_HOOD_LOG(
"std::malloc " << numBytesTotal <<
" = calcNumBytesTotal("
1651 << numElementsWithBuffer <<
")")
1652 mKeyVals =
static_cast<Node*
>(
1653 detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
1656 mInfo =
reinterpret_cast<uint8_t*
>(mKeyVals + numElementsWithBuffer);
1659 WHash::operator=(
static_cast<const WHash&
>(o));
1660 WKeyEqual::operator=(
static_cast<const WKeyEqual&
>(o));
1661 DataPool::operator=(
static_cast<DataPool const&
>(o));
1662 mHashMultiplier = o.mHashMultiplier;
1663 mNumElements = o.mNumElements;
1665 mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;
1666 mInfoInc = o.mInfoInc;
1667 mInfoHashShift = o.mInfoHashShift;
1674 void swap(
Table& o) {
1675 ROBIN_HOOD_TRACE(
this)
1682 ROBIN_HOOD_TRACE(
this)
1689 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*
this);
1691 auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
1693 uint8_t
const z = 0;
1694 std::fill(mInfo, mInfo + calcNumBytesInfo(numElementsWithBuffer), z);
1695 mInfo[numElementsWithBuffer] = 1;
1697 mInfoInc = InitialInfoInc;
1698 mInfoHashShift = InitialInfoHashShift;
1703 ROBIN_HOOD_TRACE(
this)
1708 bool operator==(
const Table& other)
const {
1709 ROBIN_HOOD_TRACE(
this)
1710 if (other.size() != size()) {
1713 for (
auto const& otherEntry : other) {
1714 if (!has(otherEntry)) {
1722 bool operator!=(
const Table& other)
const {
1723 ROBIN_HOOD_TRACE(
this)
1724 return !operator==(other);
1727 template <
typename Q = mapped_type>
1728 typename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](
const key_type& key) {
1729 ROBIN_HOOD_TRACE(
this)
1730 auto idxAndState = insertKeyPrepareEmptySpot(key);
1731 switch (idxAndState.second) {
1732 case InsertionState::key_found:
1735 case InsertionState::new_node:
1736 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first]))
1737 Node(*
this, std::piecewise_construct, std::forward_as_tuple(key),
1738 std::forward_as_tuple());
1741 case InsertionState::overwrite_node:
1742 mKeyVals[idxAndState.first] = Node(*
this, std::piecewise_construct,
1743 std::forward_as_tuple(key), std::forward_as_tuple());
1746 case InsertionState::overflow_error:
1747 throwOverflowError();
1750 return mKeyVals[idxAndState.first].getSecond();
1753 template <
typename Q = mapped_type>
1754 typename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](key_type&& key) {
1755 ROBIN_HOOD_TRACE(
this)
1756 auto idxAndState = insertKeyPrepareEmptySpot(key);
1757 switch (idxAndState.second) {
1758 case InsertionState::key_found:
1761 case InsertionState::new_node:
1762 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first]))
1763 Node(*
this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),
1764 std::forward_as_tuple());
1767 case InsertionState::overwrite_node:
1768 mKeyVals[idxAndState.first] =
1769 Node(*
this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),
1770 std::forward_as_tuple());
1773 case InsertionState::overflow_error:
1774 throwOverflowError();
1777 return mKeyVals[idxAndState.first].getSecond();
1780 template <
typename Iter>
1781 void insert(Iter first, Iter last) {
1782 for (; first != last; ++first) {
1784 insert(value_type(*first));
1788 void insert(std::initializer_list<value_type> ilist) {
1789 for (
auto&& vt : ilist) {
1790 insert(std::move(vt));
1794 template <
typename... Args>
1795 std::pair<iterator, bool> emplace(Args&&... args) {
1796 ROBIN_HOOD_TRACE(
this)
1797 Node n{*
this, std::forward<Args>(args)...};
1798 auto idxAndState = insertKeyPrepareEmptySpot(getFirstConst(n));
1799 switch (idxAndState.second) {
1800 case InsertionState::key_found:
1804 case InsertionState::new_node:
1805 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(*
this, std::move(n));
1808 case InsertionState::overwrite_node:
1809 mKeyVals[idxAndState.first] = std::move(n);
1812 case InsertionState::overflow_error:
1814 throwOverflowError();
1818 return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
1819 InsertionState::key_found != idxAndState.second);
1822 template <
typename... Args>
1823 iterator emplace_hint(const_iterator position, Args&&... args) {
1825 return emplace(std::forward<Args>(args)...).first;
1828 template <
typename... Args>
1829 std::pair<iterator, bool> try_emplace(
const key_type& key, Args&&... args) {
1830 return try_emplace_impl(key, std::forward<Args>(args)...);
1833 template <
typename... Args>
1834 std::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args) {
1835 return try_emplace_impl(std::move(key), std::forward<Args>(args)...);
1838 template <
typename... Args>
1839 iterator try_emplace(const_iterator hint,
const key_type& key, Args&&... args) {
1841 return try_emplace_impl(key, std::forward<Args>(args)...).first;
1844 template <
typename... Args>
1845 iterator try_emplace(const_iterator hint, key_type&& key, Args&&... args) {
1847 return try_emplace_impl(std::move(key), std::forward<Args>(args)...).first;
1850 template <
typename Mapped>
1851 std::pair<iterator, bool> insert_or_assign(
const key_type& key, Mapped&& obj) {
1852 return insertOrAssignImpl(key, std::forward<Mapped>(obj));
1855 template <
typename Mapped>
1856 std::pair<iterator, bool> insert_or_assign(key_type&& key, Mapped&& obj) {
1857 return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj));
1860 template <
typename Mapped>
1861 iterator insert_or_assign(const_iterator hint,
const key_type& key, Mapped&& obj) {
1863 return insertOrAssignImpl(key, std::forward<Mapped>(obj)).first;
1866 template <
typename Mapped>
1867 iterator insert_or_assign(const_iterator hint, key_type&& key, Mapped&& obj) {
1869 return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj)).first;
1872 std::pair<iterator, bool> insert(
const value_type& keyval) {
1873 ROBIN_HOOD_TRACE(
this)
1874 return emplace(keyval);
1877 iterator insert(const_iterator hint,
const value_type& keyval) {
1879 return emplace(keyval).first;
1882 std::pair<iterator, bool> insert(value_type&& keyval) {
1883 return emplace(std::move(keyval));
1886 iterator insert(const_iterator hint, value_type&& keyval) {
1888 return emplace(std::move(keyval)).first;
1892 size_t count(
const key_type& key)
const {
1893 ROBIN_HOOD_TRACE(
this)
1894 auto kv = mKeyVals + findIdx(key);
1895 if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1901 template <
typename OtherKey,
typename Self_ = Self>
1902 typename std::enable_if<Self_::is_transparent, size_t>::type count(
const OtherKey& key)
const {
1903 ROBIN_HOOD_TRACE(
this)
1904 auto kv = mKeyVals + findIdx(key);
1905 if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1911 bool contains(
const key_type& key)
const {
1912 return 1U == count(key);
1915 template <
typename OtherKey,
typename Self_ = Self>
1916 typename std::enable_if<Self_::is_transparent, bool>::type contains(
const OtherKey& key)
const {
1917 return 1U == count(key);
1922 template <
typename Q = mapped_type>
1923 typename std::enable_if<!std::is_void<Q>::value, Q&>::type at(key_type
const& key) {
1924 ROBIN_HOOD_TRACE(
this)
1925 auto kv = mKeyVals + findIdx(key);
1926 if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1927 doThrow<std::out_of_range>(
"key not found");
1929 return kv->getSecond();
1934 template <
typename Q = mapped_type>
1935 typename std::enable_if<!std::is_void<Q>::value, Q
const&>::type at(key_type
const& key)
const {
1936 ROBIN_HOOD_TRACE(
this)
1937 auto kv = mKeyVals + findIdx(key);
1938 if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1939 doThrow<std::out_of_range>(
"key not found");
1941 return kv->getSecond();
1944 const_iterator find(
const key_type& key)
const {
1945 ROBIN_HOOD_TRACE(
this)
1946 const size_t idx = findIdx(key);
1947 return const_iterator{mKeyVals + idx, mInfo + idx};
1950 template <
typename OtherKey>
1952 ROBIN_HOOD_TRACE(
this)
1953 const size_t idx = findIdx(key);
1954 return const_iterator{mKeyVals + idx, mInfo + idx};
1957 template <
typename OtherKey,
typename Self_ = Self>
1958 typename std::enable_if<Self_::is_transparent,
1959 const_iterator>::type
1960 find(
const OtherKey& key)
const {
1961 ROBIN_HOOD_TRACE(
this)
1962 const size_t idx = findIdx(key);
1963 return const_iterator{mKeyVals + idx, mInfo + idx};
1966 iterator find(
const key_type& key) {
1967 ROBIN_HOOD_TRACE(
this)
1968 const size_t idx = findIdx(key);
1969 return iterator{mKeyVals + idx, mInfo + idx};
1972 template <
typename OtherKey>
1974 ROBIN_HOOD_TRACE(
this)
1975 const size_t idx = findIdx(key);
1976 return iterator{mKeyVals + idx, mInfo + idx};
1979 template <
typename OtherKey,
typename Self_ = Self>
1980 typename std::enable_if<Self_::is_transparent, iterator>::type find(
const OtherKey& key) {
1981 ROBIN_HOOD_TRACE(
this)
1982 const size_t idx = findIdx(key);
1983 return iterator{mKeyVals + idx, mInfo + idx};
1987 ROBIN_HOOD_TRACE(
this)
1991 return iterator(mKeyVals, mInfo, fast_forward_tag{});
1993 const_iterator begin()
const {
1994 ROBIN_HOOD_TRACE(
this)
1997 const_iterator cbegin()
const {
1998 ROBIN_HOOD_TRACE(
this)
2002 return const_iterator(mKeyVals, mInfo, fast_forward_tag{});
2006 ROBIN_HOOD_TRACE(
this)
2009 return iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo),
nullptr};
2011 const_iterator end()
const {
2012 ROBIN_HOOD_TRACE(
this)
2015 const_iterator cend()
const {
2016 ROBIN_HOOD_TRACE(
this)
2017 return const_iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo),
nullptr};
2020 iterator erase(const_iterator pos) {
2021 ROBIN_HOOD_TRACE(
this)
2023 return erase(iterator{
const_cast<Node*
>(pos.mKeyVals),
const_cast<uint8_t*
>(pos.mInfo)});
2027 iterator erase(iterator pos) {
2028 ROBIN_HOOD_TRACE(
this)
2030 auto const idx =
static_cast<size_t>(pos.mKeyVals - mKeyVals);
2044 size_t erase(
const key_type& key) {
2045 ROBIN_HOOD_TRACE(
this)
2048 keyToIdx(key, &idx, &info);
2052 if (info == mInfo[idx] && WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
2058 }
while (info <= mInfo[idx]);
2066 void rehash(
size_t c) {
2073 void reserve(
size_t c) {
2081 ROBIN_HOOD_TRACE(
this)
2082 auto newSize = InitialNumElements;
2083 while (calcMaxNumElementsAllowed(newSize) < mNumElements && newSize != 0) {
2086 if (ROBIN_HOOD_UNLIKELY(newSize == 0)) {
2087 throwOverflowError();
2090 ROBIN_HOOD_LOG(
"newSize > mMask + 1: " << newSize <<
" > " << mMask <<
" + 1")
2094 if (newSize < mMask + 1) {
2095 rehashPowerOfTwo(newSize,
true);
2099 size_type size()
const noexcept {
2100 ROBIN_HOOD_TRACE(
this)
2101 return mNumElements;
2104 size_type max_size()
const noexcept {
2105 ROBIN_HOOD_TRACE(
this)
2106 return static_cast<size_type
>(-1);
2109 ROBIN_HOOD(NODISCARD)
bool empty()
const noexcept {
2110 ROBIN_HOOD_TRACE(
this)
2111 return 0 == mNumElements;
2114 float max_load_factor()
const noexcept {
2115 ROBIN_HOOD_TRACE(
this)
2116 return MaxLoadFactor100 / 100.0F;
2120 float load_factor()
const noexcept {
2121 ROBIN_HOOD_TRACE(
this)
2122 return static_cast<float>(size()) /
static_cast<float>(mMask + 1);
2125 ROBIN_HOOD(NODISCARD)
size_t mask()
const noexcept {
2126 ROBIN_HOOD_TRACE(
this)
2130 ROBIN_HOOD(NODISCARD)
size_t calcMaxNumElementsAllowed(
size_t maxElements)
const noexcept {
2131 if (ROBIN_HOOD_LIKELY(maxElements <= (std::numeric_limits<size_t>::max)() / 100)) {
2132 return maxElements * MaxLoadFactor100 / 100;
2136 return (maxElements / 100) * MaxLoadFactor100;
2139 ROBIN_HOOD(NODISCARD)
size_t calcNumBytesInfo(
size_t numElements)
const noexcept {
2142 return numElements +
sizeof(uint64_t);
2145 ROBIN_HOOD(NODISCARD)
2146 size_t calcNumElementsWithBuffer(
size_t numElements)
const noexcept {
2147 auto maxNumElementsAllowed = calcMaxNumElementsAllowed(numElements);
2148 return numElements + (std::min)(maxNumElementsAllowed, (
static_cast<size_t>(0xFF)));
2152 ROBIN_HOOD(NODISCARD)
size_t calcNumBytesTotal(
size_t numElements)
const {
2153 #if ROBIN_HOOD(BITNESS) == 64
2154 return numElements *
sizeof(Node) + calcNumBytesInfo(numElements);
2157 auto const ne =
static_cast<uint64_t
>(numElements);
2158 auto const s =
static_cast<uint64_t
>(
sizeof(Node));
2159 auto const infos =
static_cast<uint64_t
>(calcNumBytesInfo(numElements));
2161 auto const total64 = ne * s + infos;
2162 auto const total =
static_cast<size_t>(total64);
2164 if (ROBIN_HOOD_UNLIKELY(
static_cast<uint64_t
>(total) != total64)) {
2165 throwOverflowError();
2172 template <
typename Q = mapped_type>
2173 ROBIN_HOOD(NODISCARD)
2174 typename std::enable_if<!std::is_void<Q>::value,
bool>::type has(
const value_type& e)
const {
2175 ROBIN_HOOD_TRACE(
this)
2176 auto it = find(e.first);
2177 return it != end() && it->second == e.second;
2180 template <
typename Q = mapped_type>
2181 ROBIN_HOOD(NODISCARD)
2182 typename std::enable_if<std::is_void<Q>::value,
bool>::type has(
const value_type& e)
const {
2183 ROBIN_HOOD_TRACE(
this)
2184 return find(e) != end();
2187 void reserve(
size_t c,
bool forceRehash) {
2188 ROBIN_HOOD_TRACE(
this)
2189 auto const minElementsAllowed = (std::max)(c, mNumElements);
2190 auto newSize = InitialNumElements;
2191 while (calcMaxNumElementsAllowed(newSize) < minElementsAllowed && newSize != 0) {
2194 if (ROBIN_HOOD_UNLIKELY(newSize == 0)) {
2195 throwOverflowError();
2198 ROBIN_HOOD_LOG(
"newSize > mMask + 1: " << newSize <<
" > " << mMask <<
" + 1")
2202 if (forceRehash || newSize > mMask + 1) {
2203 rehashPowerOfTwo(newSize,
false);
2210 void rehashPowerOfTwo(
size_t numBuckets,
bool forceFree) {
2211 ROBIN_HOOD_TRACE(
this)
2213 Node*
const oldKeyVals = mKeyVals;
2214 uint8_t
const*
const oldInfo = mInfo;
2216 const size_t oldMaxElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
2219 initData(numBuckets);
2220 if (oldMaxElementsWithBuffer > 1) {
2221 for (
size_t i = 0; i < oldMaxElementsWithBuffer; ++i) {
2222 if (oldInfo[i] != 0) {
2225 insert_move(std::move(oldKeyVals[i]));
2227 oldKeyVals[i].~Node();
2234 if (oldKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
2237 std::free(oldKeyVals);
2239 DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer));
2245 ROBIN_HOOD(NOINLINE)
void throwOverflowError()
const {
2246 #if ROBIN_HOOD(HAS_EXCEPTIONS)
2247 throw std::overflow_error(
"robin_hood::map overflow");
2253 template <
typename OtherKey,
typename... Args>
2254 std::pair<iterator, bool> try_emplace_impl(OtherKey&& key, Args&&... args) {
2255 ROBIN_HOOD_TRACE(
this)
2256 auto idxAndState = insertKeyPrepareEmptySpot(key);
2257 switch (idxAndState.second) {
2258 case InsertionState::key_found:
2261 case InsertionState::new_node:
2262 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(
2263 *
this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
2264 std::forward_as_tuple(std::forward<Args>(args)...));
2267 case InsertionState::overwrite_node:
2268 mKeyVals[idxAndState.first] = Node(*
this, std::piecewise_construct,
2269 std::forward_as_tuple(std::forward<OtherKey>(key)),
2270 std::forward_as_tuple(std::forward<Args>(args)...));
2273 case InsertionState::overflow_error:
2274 throwOverflowError();
2278 return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
2279 InsertionState::key_found != idxAndState.second);
2282 template <
typename OtherKey,
typename Mapped>
2283 std::pair<iterator, bool> insertOrAssignImpl(OtherKey&& key, Mapped&& obj) {
2284 ROBIN_HOOD_TRACE(
this)
2285 auto idxAndState = insertKeyPrepareEmptySpot(key);
2286 switch (idxAndState.second) {
2287 case InsertionState::key_found:
2288 mKeyVals[idxAndState.first].getSecond() = std::forward<Mapped>(obj);
2291 case InsertionState::new_node:
2292 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(
2293 *
this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
2294 std::forward_as_tuple(std::forward<Mapped>(obj)));
2297 case InsertionState::overwrite_node:
2298 mKeyVals[idxAndState.first] = Node(*
this, std::piecewise_construct,
2299 std::forward_as_tuple(std::forward<OtherKey>(key)),
2300 std::forward_as_tuple(std::forward<Mapped>(obj)));
2303 case InsertionState::overflow_error:
2304 throwOverflowError();
2308 return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
2309 InsertionState::key_found != idxAndState.second);
2312 void initData(
size_t max_elements) {
2314 mMask = max_elements - 1;
2315 mMaxNumElementsAllowed = calcMaxNumElementsAllowed(max_elements);
2317 auto const numElementsWithBuffer = calcNumElementsWithBuffer(max_elements);
2320 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
2321 ROBIN_HOOD_LOG(
"std::calloc " << numBytesTotal <<
" = calcNumBytesTotal("
2322 << numElementsWithBuffer <<
")")
2323 mKeyVals =
reinterpret_cast<Node*
>(
2324 detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
2325 mInfo =
reinterpret_cast<uint8_t*
>(mKeyVals + numElementsWithBuffer);
2326 std::memset(mInfo, 0, numBytesTotal - numElementsWithBuffer *
sizeof(Node));
2329 mInfo[numElementsWithBuffer] = 1;
2331 mInfoInc = InitialInfoInc;
2332 mInfoHashShift = InitialInfoHashShift;
2335 enum class InsertionState { overflow_error, key_found, new_node, overwrite_node };
2340 template <
typename OtherKey>
2341 std::pair<size_t, InsertionState> insertKeyPrepareEmptySpot(OtherKey&& key) {
2342 for (
int i = 0; i < 256; ++i) {
2345 keyToIdx(key, &idx, &info);
2346 nextWhileLess(&info, &idx);
2349 while (info == mInfo[idx]) {
2350 if (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
2353 return std::make_pair(idx, InsertionState::key_found);
2359 if (ROBIN_HOOD_UNLIKELY(mNumElements >= mMaxNumElementsAllowed)) {
2360 if (!increase_size()) {
2361 return std::make_pair(
size_t(0), InsertionState::overflow_error);
2367 auto const insertion_idx = idx;
2368 auto const insertion_info = info;
2369 if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {
2370 mMaxNumElementsAllowed = 0;
2374 while (0 != mInfo[idx]) {
2378 if (idx != insertion_idx) {
2379 shiftUp(idx, insertion_idx);
2382 mInfo[insertion_idx] =
static_cast<uint8_t
>(insertion_info);
2384 return std::make_pair(insertion_idx, idx == insertion_idx
2385 ? InsertionState::new_node
2386 : InsertionState::overwrite_node);
2390 return std::make_pair(
size_t(0), InsertionState::overflow_error);
2393 bool try_increase_info() {
2394 ROBIN_HOOD_LOG(
"mInfoInc=" << mInfoInc <<
", numElements=" << mNumElements
2395 <<
", maxNumElementsAllowed="
2396 << calcMaxNumElementsAllowed(mMask + 1))
2397 if (mInfoInc <= 2) {
2402 mInfoInc =
static_cast<uint8_t
>(mInfoInc >> 1U);
2407 auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
2409 for (
size_t i = 0; i < numElementsWithBuffer; i += 8) {
2410 auto val = unaligned_load<uint64_t>(mInfo + i);
2411 val = (val >> 1U) & UINT64_C(0x7f7f7f7f7f7f7f7f);
2412 std::memcpy(mInfo + i, &val,
sizeof(val));
2415 mInfo[numElementsWithBuffer] = 1;
2417 mMaxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
2422 bool increase_size() {
2425 initData(InitialNumElements);
2429 auto const maxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
2430 if (mNumElements < maxNumElementsAllowed && try_increase_info()) {
2434 ROBIN_HOOD_LOG(
"mNumElements=" << mNumElements <<
", maxNumElementsAllowed="
2435 << maxNumElementsAllowed <<
", load="
2436 << (
static_cast<double>(mNumElements) * 100.0 /
2437 (
static_cast<double>(mMask) + 1)))
2439 if (mNumElements * 2 < calcMaxNumElementsAllowed(mMask + 1)) {
2443 nextHashMultiplier();
2444 rehashPowerOfTwo(mMask + 1,
true);
2447 rehashPowerOfTwo((mMask + 1) * 2,
false);
2452 void nextHashMultiplier() {
2455 mHashMultiplier += UINT64_C(0xc4ceb9fe1a85ec54);
2464 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}
2465 .nodesDoNotDeallocate(*
this);
2471 if (mKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
2472 ROBIN_HOOD_LOG(
"std::free")
2473 std::free(mKeyVals);
2477 void init() noexcept {
2478 mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);
2479 mInfo =
reinterpret_cast<uint8_t*
>(&mMask);
2482 mMaxNumElementsAllowed = 0;
2483 mInfoInc = InitialInfoInc;
2484 mInfoHashShift = InitialInfoHashShift;
2488 uint64_t mHashMultiplier = UINT64_C(0xc4ceb9fe1a85ec53);
2489 Node* mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);
2490 uint8_t* mInfo =
reinterpret_cast<uint8_t*
>(&mMask);
2491 size_t mNumElements = 0;
2493 size_t mMaxNumElementsAllowed = 0;
2494 InfoType mInfoInc = InitialInfoInc;
2495 InfoType mInfoHashShift = InitialInfoHashShift;
2503 template <
typename Key,
typename T,
typename Hash = hash<Key>,
2504 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2507 template <
typename Key,
typename T,
typename Hash = hash<Key>,
2508 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2511 template <
typename Key,
typename T,
typename Hash = hash<Key>,
2512 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2515 std::is_nothrow_move_constructible<robin_hood::pair<Key, T>>::value &&
2516 std::is_nothrow_move_assignable<robin_hood::pair<Key, T>>::value,
2517 MaxLoadFactor100, Key, T, Hash, KeyEqual>;
2521 template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2522 size_t MaxLoadFactor100 = 80>
2525 template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2526 size_t MaxLoadFactor100 = 80>
2529 template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2530 size_t MaxLoadFactor100 = 80>
2532 std::is_nothrow_move_constructible<Key>::value &&
2533 std::is_nothrow_move_assignable<Key>::value,
2534 MaxLoadFactor100, Key, void, Hash, KeyEqual>;