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 { \
151 unsigned long index; \
152 return ROBIN_HOOD(BITSCANFORWARD)(&index, mask) ? static_cast<int>(index) \
153 : ROBIN_HOOD(BITNESS); \
156 # if ROBIN_HOOD(BITNESS) == 32
157 # define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzl
158 # define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzl
160 # define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzll
161 # define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzll
163 # define ROBIN_HOOD_COUNT_LEADING_ZEROES(x) ((x) ? ROBIN_HOOD(CLZ)(x) : ROBIN_HOOD(BITNESS))
164 # define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ((x) ? ROBIN_HOOD(CTZ)(x) : ROBIN_HOOD(BITNESS))
169 #ifndef __has_cpp_attribute
170 # define __has_cpp_attribute(x) 0
172 #if __has_cpp_attribute(clang::fallthrough)
173 # define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[clang::fallthrough]]
174 #elif __has_cpp_attribute(gnu::fallthrough)
175 # define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[gnu::fallthrough]]
177 # define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH()
182 # define ROBIN_HOOD_LIKELY(condition) condition
183 # define ROBIN_HOOD_UNLIKELY(condition) condition
185 # define ROBIN_HOOD_LIKELY(condition) __builtin_expect(condition, 1)
186 # define ROBIN_HOOD_UNLIKELY(condition) __builtin_expect(condition, 0)
191 # ifdef _NATIVE_WCHAR_T_DEFINED
192 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1
194 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 0
197 # define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1
202 # if _MSC_VER <= 1900
203 # define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 1
205 # define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0
208 # define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0
213 #if defined(__GNUC__) && __GNUC__ < 5
214 # define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)
216 # define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value
220 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX() __cplusplus
221 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX98() 199711L
222 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX11() 201103L
223 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX14() 201402L
224 #define ROBIN_HOOD_PRIVATE_DEFINITION_CXX17() 201703L
226 #if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)
227 # define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD() [[nodiscard]]
229 # define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD()
232 namespace robin_hood {
234 #if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)
235 # define ROBIN_HOOD_STD std
239 namespace ROBIN_HOOD_STD {
242 : std::integral_constant<std::size_t, alignof(typename std::remove_all_extents<T>::type)> {};
244 template <
class T, T... Ints>
247 using value_type = T;
248 static_assert(std::is_integral<value_type>::value,
"not integral type");
249 static constexpr std::size_t size() noexcept {
250 return sizeof...(Ints);
253 template <std::size_t... Inds>
257 template <
class T, T Begin, T End,
bool>
260 static_assert(std::is_integral<TValue>::value,
"not integral type");
261 static_assert(Begin >= 0 && Begin < End,
"unexpected argument (Begin<0 || Begin<=End)");
263 template <
class,
class>
266 template <TValue... Inds0, TValue... Inds1>
273 (End - Begin) / 2 == 1>::TResult,
274 typename IntSeqImpl<TValue, Begin + (End - Begin) / 2, End,
275 (End - Begin + 1) / 2 == 1>::TResult>::TResult;
278 template <
class T, T Begin>
281 static_assert(std::is_integral<TValue>::value,
"not integral type");
282 static_assert(Begin >= 0,
"unexpected argument (Begin<0)");
286 template <
class T, T Begin, T End>
289 static_assert(std::is_integral<TValue>::value,
"not integral type");
290 static_assert(Begin >= 0,
"unexpected argument (Begin<0)");
295 template <
class T, T N>
296 using make_integer_sequence =
typename detail_::IntSeqImpl<T, 0, N, (N - 0) == 1>::TResult;
298 template <std::
size_t N>
299 using make_index_sequence = make_integer_sequence<std::size_t, N>;
301 template <
class... T>
302 using index_sequence_for = make_index_sequence<
sizeof...(T)>;
311 #if ROBIN_HOOD(BITNESS) == 64
312 using SizeT = uint64_t;
314 using SizeT = uint32_t;
317 template <
typename T>
318 T rotr(T x,
unsigned k) {
319 return (x >> k) | (x << (8U *
sizeof(T) - k));
325 template <
typename T>
326 inline T reinterpret_cast_no_cast_align_warning(
void* ptr) noexcept {
327 return reinterpret_cast<T
>(ptr);
330 template <
typename T>
331 inline T reinterpret_cast_no_cast_align_warning(
void const* ptr) noexcept {
332 return reinterpret_cast<T
>(ptr);
337 template <
typename E,
typename... Args>
338 [[noreturn]] ROBIN_HOOD(NOINLINE)
339 #if ROBIN_HOOD(HAS_EXCEPTIONS)
340 void doThrow(Args&&... args) {
341 throw E(std::forward<Args>(args)...);
344 void doThrow(Args&&... ROBIN_HOOD_UNUSED(args) ) {
349 template <
typename E,
typename T,
typename... Args>
350 T* assertNotNull(T* t, Args&&... args) {
351 if (ROBIN_HOOD_UNLIKELY(
nullptr == t)) {
352 doThrow<E>(std::forward<Args>(args)...);
357 template <
typename T>
358 inline T unaligned_load(
void const* ptr) noexcept {
362 std::memcpy(&t, ptr,
sizeof(T));
369 template <
typename T,
size_t MinNumAllocs = 4,
size_t MaxNumAllocs = 256>
377 , mListForFree(
nullptr) {}
381 , mListForFree(o.mListForFree) {
382 o.mListForFree =
nullptr;
389 mListForFree = o.mListForFree;
390 o.mListForFree =
nullptr;
406 void reset() noexcept {
407 while (mListForFree) {
408 T* tmp = *mListForFree;
409 ROBIN_HOOD_LOG(
"std::free")
410 std::free(mListForFree);
411 mListForFree = reinterpret_cast_no_cast_align_warning<T**>(tmp);
422 tmp = performAllocation();
425 mHead = *reinterpret_cast_no_cast_align_warning<T**>(tmp);
433 void deallocate(T* obj) noexcept {
434 *reinterpret_cast_no_cast_align_warning<T**>(obj) = mHead;
441 void addOrFree(
void* ptr,
const size_t numBytes) noexcept {
443 if (numBytes < ALIGNMENT + ALIGNED_SIZE) {
445 ROBIN_HOOD_LOG(
"std::free")
448 ROBIN_HOOD_LOG(
"add to buffer")
455 swap(mHead, other.mHead);
456 swap(mListForFree, other.mListForFree);
464 ROBIN_HOOD(NODISCARD)
size_t calcNumElementsToAlloc()
const noexcept {
465 auto tmp = mListForFree;
466 size_t numAllocs = MinNumAllocs;
468 while (numAllocs * 2 <= MaxNumAllocs && tmp) {
469 auto x =
reinterpret_cast<T***
>(tmp);
478 void add(
void* ptr,
const size_t numBytes) noexcept {
479 const size_t numElements = (numBytes - ALIGNMENT) / ALIGNED_SIZE;
480 auto data =
reinterpret_cast<T**
>(ptr);
483 auto x =
reinterpret_cast<T***
>(data);
489 reinterpret_cast_no_cast_align_warning<T*>(
reinterpret_cast<char*
>(ptr) + ALIGNMENT);
491 auto*
const head =
reinterpret_cast<char*
>(headT);
494 for (
size_t i = 0; i < numElements; ++i) {
495 *reinterpret_cast_no_cast_align_warning<char**>(head + i * ALIGNED_SIZE) =
496 head + (i + 1) * ALIGNED_SIZE;
500 *reinterpret_cast_no_cast_align_warning<T**>(head + (numElements - 1) * ALIGNED_SIZE) =
507 ROBIN_HOOD(NOINLINE) T* performAllocation() {
508 size_t const numElementsToAlloc = calcNumElementsToAlloc();
511 size_t const bytes = ALIGNMENT + ALIGNED_SIZE * numElementsToAlloc;
512 ROBIN_HOOD_LOG(
"std::malloc " << bytes <<
" = " << ALIGNMENT <<
" + " << ALIGNED_SIZE
513 <<
" * " << numElementsToAlloc)
514 add(assertNotNull<std::bad_alloc>(std::malloc(bytes)), bytes);
519 #if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)
520 static constexpr
size_t ALIGNMENT =
521 (std::max)(std::alignment_of<T>::value, std::alignment_of<T*>::value);
523 static const size_t ALIGNMENT =
529 static constexpr
size_t ALIGNED_SIZE = ((
sizeof(T) - 1) / ALIGNMENT + 1) * ALIGNMENT;
531 static_assert(MinNumAllocs >= 1,
"MinNumAllocs");
532 static_assert(MaxNumAllocs >= MinNumAllocs,
"MaxNumAllocs");
533 static_assert(ALIGNED_SIZE >=
sizeof(T*),
"ALIGNED_SIZE");
534 static_assert(0 == (ALIGNED_SIZE %
sizeof(T*)),
"ALIGNED_SIZE mod");
535 static_assert(ALIGNMENT >=
sizeof(T*),
"ALIGNMENT");
538 T** mListForFree{
nullptr};
541 template <
typename T,
size_t MinSize,
size_t MaxSize,
bool IsFlat>
545 template <
typename T,
size_t MinSize,
size_t MaxSize>
548 void addOrFree(
void* ptr,
size_t ROBIN_HOOD_UNUSED(numBytes)) noexcept {
549 ROBIN_HOOD_LOG(
"std::free")
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>
583 using first_type = T1;
584 using second_type = 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&>())))
597 , second(o.second) {}
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))
608 , second(std::move(b)) {}
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...>&>(),
626 ROBIN_HOOD_STD::index_sequence_for<U1...>(),
627 ROBIN_HOOD_STD::index_sequence_for<U2...>())))
628 :
pair(a, b, ROBIN_HOOD_STD::index_sequence_for<U1...>(),
629 ROBIN_HOOD_STD::index_sequence_for<U2...>()) {
633 template <
typename... U1,
size_t... I1,
typename... U2,
size_t... I2>
635 std::tuple<U1...>& a, std::tuple<U2...>& b,
638 noexcept(T1(std::forward<U1>(std::get<I1>(
639 std::declval<std::tuple<
640 U1...>&>()))...)) && noexcept(T2(std::
641 forward<U2>(std::get<I2>(
642 std::declval<std::tuple<U2...>&>()))...)))
643 : first(std::forward<U1>(std::get<I1>(a))...)
644 , second(std::forward<U2>(std::get<I2>(b))...) {
654 swap(first, o.first);
655 swap(second, o.second);
662 template <
typename A,
typename B>
668 template <
typename A,
typename B>
669 inline constexpr
bool operator==(pair<A, B>
const& x, pair<A, B>
const& y) {
670 return (x.first == y.first) && (x.second == y.second);
672 template <
typename A,
typename B>
673 inline constexpr
bool operator!=(pair<A, B>
const& x, pair<A, B>
const& y) {
676 template <
typename A,
typename B>
677 inline constexpr
bool operator<(pair<A, B>
const& x, pair<A, B>
const& y) noexcept(noexcept(
678 std::declval<A const&>() < std::declval<A const&>()) && noexcept(std::declval<B const&>() <
679 std::declval<B const&>())) {
680 return x.first < y.first || (!(y.first < x.first) && x.second < y.second);
682 template <
typename A,
typename B>
683 inline constexpr
bool operator>(pair<A, B>
const& x, pair<A, B>
const& y) {
686 template <
typename A,
typename B>
687 inline constexpr
bool operator<=(pair<A, B>
const& x, pair<A, B>
const& y) {
690 template <
typename A,
typename B>
691 inline constexpr
bool operator>=(pair<A, B>
const& x, pair<A, B>
const& y) {
695 inline size_t hash_bytes(
void const* ptr,
size_t len) noexcept {
696 static constexpr uint64_t m = UINT64_C(0xc6a4a7935bd1e995);
697 static constexpr uint64_t seed = UINT64_C(0xe17a1465);
698 static constexpr
unsigned int r = 47;
700 auto const*
const data64 =
static_cast<uint64_t const*
>(ptr);
701 uint64_t h = seed ^ (len * m);
703 size_t const n_blocks = len / 8;
704 for (
size_t i = 0; i < n_blocks; ++i) {
705 auto k = detail::unaligned_load<uint64_t>(data64 + i);
715 auto const*
const data8 =
reinterpret_cast<uint8_t const*
>(data64 + n_blocks);
718 h ^=
static_cast<uint64_t
>(data8[6]) << 48U;
719 ROBIN_HOOD(FALLTHROUGH);
721 h ^=
static_cast<uint64_t
>(data8[5]) << 40U;
722 ROBIN_HOOD(FALLTHROUGH);
724 h ^=
static_cast<uint64_t
>(data8[4]) << 32U;
725 ROBIN_HOOD(FALLTHROUGH);
727 h ^=
static_cast<uint64_t
>(data8[3]) << 24U;
728 ROBIN_HOOD(FALLTHROUGH);
730 h ^=
static_cast<uint64_t
>(data8[2]) << 16U;
731 ROBIN_HOOD(FALLTHROUGH);
733 h ^=
static_cast<uint64_t
>(data8[1]) << 8U;
734 ROBIN_HOOD(FALLTHROUGH);
736 h ^=
static_cast<uint64_t
>(data8[0]);
738 ROBIN_HOOD(FALLTHROUGH);
748 return static_cast<size_t>(h);
751 inline size_t hash_int(uint64_t x) noexcept {
755 x *= UINT64_C(0xff51afd7ed558ccd);
761 return static_cast<size_t>(x);
765 template <
typename T,
typename Enable =
void>
766 struct hash :
public std::hash<T> {
767 size_t operator()(T
const& obj)
const
768 noexcept(noexcept(std::declval<std::hash<T>>().
operator()(std::declval<T const&>()))) {
770 auto result = std::hash<T>::operator()(obj);
772 return hash_int(
static_cast<detail::SizeT
>(result));
776 template <
typename CharT>
777 struct hash<std::basic_string<CharT>> {
778 size_t operator()(std::basic_string<CharT>
const& str)
const noexcept {
779 return hash_bytes(str.data(),
sizeof(CharT) * str.size());
783 #if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)
784 template <
typename CharT>
785 struct hash<std::basic_string_view<CharT>> {
786 size_t operator()(std::basic_string_view<CharT>
const& sv)
const noexcept {
787 return hash_bytes(sv.data(),
sizeof(CharT) * sv.size());
794 size_t operator()(T* ptr)
const noexcept {
795 return hash_int(
reinterpret_cast<detail::SizeT
>(ptr));
800 struct hash<std::unique_ptr<T>> {
801 size_t operator()(std::unique_ptr<T>
const& ptr)
const noexcept {
802 return hash_int(
reinterpret_cast<detail::SizeT
>(ptr.get()));
807 struct hash<std::shared_ptr<T>> {
808 size_t operator()(std::shared_ptr<T>
const& ptr)
const noexcept {
809 return hash_int(
reinterpret_cast<detail::SizeT
>(ptr.get()));
813 template <
typename Enum>
814 struct hash<Enum, typename std::enable_if<std::is_enum<Enum>::value>::type> {
815 size_t operator()(Enum e)
const noexcept {
816 using Underlying =
typename std::underlying_type<Enum>::type;
821 #define ROBIN_HOOD_HASH_INT(T) \
824 size_t operator()(T const& obj) const noexcept { \
825 return hash_int(static_cast<uint64_t>(obj)); \
829 #if defined(__GNUC__) && !defined(__clang__)
830 # pragma GCC diagnostic push
831 # pragma GCC diagnostic ignored "-Wuseless-cast"
834 ROBIN_HOOD_HASH_INT(
bool);
835 ROBIN_HOOD_HASH_INT(
char);
836 ROBIN_HOOD_HASH_INT(
signed char);
837 ROBIN_HOOD_HASH_INT(
unsigned char);
838 ROBIN_HOOD_HASH_INT(char16_t);
839 ROBIN_HOOD_HASH_INT(char32_t);
840 #if ROBIN_HOOD(HAS_NATIVE_WCHART)
841 ROBIN_HOOD_HASH_INT(
wchar_t);
843 ROBIN_HOOD_HASH_INT(
short);
844 ROBIN_HOOD_HASH_INT(
unsigned short);
845 ROBIN_HOOD_HASH_INT(
int);
846 ROBIN_HOOD_HASH_INT(
unsigned int);
847 ROBIN_HOOD_HASH_INT(
long);
848 ROBIN_HOOD_HASH_INT(
long long);
849 ROBIN_HOOD_HASH_INT(
unsigned long);
850 ROBIN_HOOD_HASH_INT(
unsigned long long);
851 #if defined(__GNUC__) && !defined(__clang__)
852 # pragma GCC diagnostic pop
856 template <
typename T>
861 template <
typename T,
typename =
void>
864 template <
typename T>
866 :
public std::true_type {};
870 template <
typename T>
873 explicit WrapHash(T
const& o) noexcept(noexcept(T(std::declval<T const&>())))
877 template <
typename T>
880 explicit WrapKeyEqual(T
const& o) noexcept(noexcept(T(std::declval<T const&>())))
910 template <
bool IsFlat,
size_t MaxLoadFactor100,
typename Key,
typename T,
typename Hash,
916 typename std::conditional<
917 std::is_void<T>::value, Key,
918 robin_hood::pair<typename std::conditional<IsFlat, Key, Key const>::type, T>>::type,
921 static constexpr
bool is_flat = IsFlat;
922 static constexpr
bool is_map = !std::is_void<T>::value;
923 static constexpr
bool is_set = !is_map;
924 static constexpr
bool is_transparent =
927 using key_type = Key;
928 using mapped_type = T;
929 using value_type =
typename std::conditional<
932 using size_type = size_t;
934 using key_equal = KeyEqual;
938 static_assert(MaxLoadFactor100 > 10 && MaxLoadFactor100 < 100,
939 "MaxLoadFactor100 needs to be >10 && < 100");
947 static constexpr
size_t InitialNumElements =
sizeof(uint64_t);
948 static constexpr uint32_t InitialInfoNumBits = 5;
949 static constexpr uint8_t InitialInfoInc = 1U << InitialInfoNumBits;
950 static constexpr
size_t InfoMask = InitialInfoInc - 1U;
951 static constexpr uint8_t InitialInfoHashShift = 0;
955 using InfoType = uint32_t;
962 template <
typename M,
bool>
966 template <
typename M>
967 class DataNode<M, true> final {
969 template <
typename... Args>
970 explicit DataNode(M& ROBIN_HOOD_UNUSED(map) , Args&&... args) noexcept(
971 noexcept(value_type(std::forward<Args>(args)...)))
972 : mData(std::forward<Args>(args)...) {}
974 DataNode(M& ROBIN_HOOD_UNUSED(map) , DataNode<M, true>&& n) noexcept(
975 std::is_nothrow_move_constructible<value_type>::value)
976 : mData(std::move(n.mData)) {}
979 void destroy(M& ROBIN_HOOD_UNUSED(map) ) noexcept {}
980 void destroyDoNotDeallocate() noexcept {}
982 value_type
const* operator->()
const noexcept {
985 value_type* operator->() noexcept {
989 const value_type& operator*()
const noexcept {
993 value_type& operator*() noexcept {
997 template <
typename VT = value_type>
998 ROBIN_HOOD(NODISCARD)
999 typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {
1002 template <
typename VT = value_type>
1003 ROBIN_HOOD(NODISCARD)
1004 typename std::enable_if<is_set, VT&>::type getFirst() noexcept {
1008 template <
typename VT = value_type>
1009 ROBIN_HOOD(NODISCARD)
1010 typename std::enable_if<is_map, typename VT::first_type const&>::type
1011 getFirst()
const noexcept {
1014 template <
typename VT = value_type>
1015 ROBIN_HOOD(NODISCARD)
1016 typename std::enable_if<is_set, VT const&>::type getFirst()
const noexcept {
1020 template <
typename MT = mapped_type>
1021 ROBIN_HOOD(NODISCARD)
1022 typename std::enable_if<is_map, MT&>::type getSecond() noexcept {
1023 return mData.second;
1026 template <
typename MT = mapped_type>
1027 ROBIN_HOOD(NODISCARD)
1028 typename std::enable_if<is_set, MT const&>::type getSecond()
const noexcept {
1029 return mData.second;
1032 void swap(DataNode<M, true>& o) noexcept(
1033 noexcept(std::declval<value_type>().swap(std::declval<value_type>()))) {
1034 mData.swap(o.mData);
1042 template <
typename M>
1043 class DataNode<M, false> {
1045 template <
typename... Args>
1046 explicit DataNode(M& map, Args&&... args)
1047 : mData(map.allocate()) {
1048 ::new (
static_cast<void*
>(mData)) value_type(std::forward<Args>(args)...);
1051 DataNode(M& ROBIN_HOOD_UNUSED(map) , DataNode<M, false>&& n) noexcept
1052 : mData(std::move(n.mData)) {}
1054 void destroy(M& map) noexcept {
1056 mData->~value_type();
1057 map.deallocate(mData);
1060 void destroyDoNotDeallocate() noexcept {
1061 mData->~value_type();
1064 value_type
const* operator->()
const noexcept {
1068 value_type* operator->() noexcept {
1072 const value_type& operator*()
const {
1076 value_type& operator*() {
1080 template <
typename VT = value_type>
1081 ROBIN_HOOD(NODISCARD)
1082 typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {
1083 return mData->first;
1085 template <
typename VT = value_type>
1086 ROBIN_HOOD(NODISCARD)
1087 typename std::enable_if<is_set, VT&>::type getFirst() noexcept {
1091 template <
typename VT = value_type>
1092 ROBIN_HOOD(NODISCARD)
1093 typename std::enable_if<is_map, typename VT::first_type const&>::type
1094 getFirst()
const noexcept {
1095 return mData->first;
1097 template <
typename VT = value_type>
1098 ROBIN_HOOD(NODISCARD)
1099 typename std::enable_if<is_set, VT const&>::type getFirst()
const noexcept {
1103 template <
typename MT = mapped_type>
1104 ROBIN_HOOD(NODISCARD)
1105 typename std::enable_if<is_map, MT&>::type getSecond() noexcept {
1106 return mData->second;
1109 template <
typename MT = mapped_type>
1110 ROBIN_HOOD(NODISCARD)
1111 typename std::enable_if<is_map, MT const&>::type getSecond()
const noexcept {
1112 return mData->second;
1115 void swap(DataNode<M, false>& o) noexcept {
1117 swap(mData, o.mData);
1124 using Node = DataNode<Self, IsFlat>;
1127 ROBIN_HOOD(NODISCARD) key_type
const& getFirstConst(Node
const& n)
const noexcept {
1128 return n.getFirst();
1133 ROBIN_HOOD(NODISCARD) key_type
const& getFirstConst(key_type
const& k)
const noexcept {
1138 template <
typename Q = mapped_type>
1139 ROBIN_HOOD(NODISCARD)
1140 typename std::enable_if<!std::is_void<Q>::value, key_type
const&>::type
1141 getFirstConst(value_type
const& vt)
const noexcept {
1147 template <
typename M,
bool UseMemcpy>
1151 template <
typename M>
1152 struct Cloner<M, true> {
1153 void operator()(M
const& source, M& target)
const {
1154 auto const*
const src =
reinterpret_cast<char const*
>(source.mKeyVals);
1155 auto* tgt =
reinterpret_cast<char*
>(target.mKeyVals);
1156 auto const numElementsWithBuffer = target.calcNumElementsWithBuffer(target.mMask + 1);
1157 std::copy(src, src + target.calcNumBytesTotal(numElementsWithBuffer), tgt);
1161 template <
typename M>
1162 struct Cloner<M, false> {
1163 void operator()(M
const& s, M& t)
const {
1164 auto const numElementsWithBuffer = t.calcNumElementsWithBuffer(t.mMask + 1);
1165 std::copy(s.mInfo, s.mInfo + t.calcNumBytesInfo(numElementsWithBuffer), t.mInfo);
1167 for (
size_t i = 0; i < numElementsWithBuffer; ++i) {
1169 ::new (
static_cast<void*
>(t.mKeyVals + i)) Node(t, *s.mKeyVals[i]);
1177 template <
typename M,
bool IsFlatAndTrivial>
1178 struct Destroyer {};
1180 template <
typename M>
1181 struct Destroyer<M, true> {
1182 void nodes(M& m)
const noexcept {
1186 void nodesDoNotDeallocate(M& m)
const noexcept {
1191 template <
typename M>
1192 struct Destroyer<M, false> {
1193 void nodes(M& m)
const noexcept {
1196 auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
1198 for (
size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
1199 if (0 != m.mInfo[idx]) {
1200 Node& n = m.mKeyVals[idx];
1207 void nodesDoNotDeallocate(M& m)
const noexcept {
1210 auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
1211 for (
size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
1212 if (0 != m.mInfo[idx]) {
1213 Node& n = m.mKeyVals[idx];
1214 n.destroyDoNotDeallocate();
1223 struct fast_forward_tag {};
1226 template <
bool IsConst>
1229 using NodePtr =
typename std::conditional<IsConst, Node const*, Node*>::type;
1232 using difference_type = std::ptrdiff_t;
1233 using value_type =
typename Self::value_type;
1234 using reference =
typename std::conditional<IsConst, value_type const&, value_type&>::type;
1235 using pointer =
typename std::conditional<IsConst, value_type const*, value_type*>::type;
1236 using iterator_category = std::forward_iterator_tag;
1246 template <
bool OtherIsConst,
1247 typename =
typename std::enable_if<IsConst && !OtherIsConst>::type>
1248 Iter(Iter<OtherIsConst>
const& other) noexcept
1249 : mKeyVals(other.mKeyVals)
1250 , mInfo(other.mInfo) {}
1252 Iter(NodePtr valPtr, uint8_t
const* infoPtr) noexcept
1256 Iter(NodePtr valPtr, uint8_t
const* infoPtr,
1257 fast_forward_tag ROBIN_HOOD_UNUSED(tag) ) noexcept
1263 template <
bool OtherIsConst,
1264 typename =
typename std::enable_if<IsConst && !OtherIsConst>::type>
1265 Iter& operator=(Iter<OtherIsConst>
const& other) noexcept {
1266 mKeyVals = other.mKeyVals;
1267 mInfo = other.mInfo;
1272 Iter& operator++() noexcept {
1279 Iter operator++(
int) noexcept {
1285 reference operator*()
const {
1289 pointer operator->()
const {
1294 bool operator==(Iter<O>
const& o)
const noexcept {
1295 return mKeyVals == o.mKeyVals;
1299 bool operator!=(Iter<O>
const& o)
const noexcept {
1300 return mKeyVals != o.mKeyVals;
1307 void fastForward() noexcept {
1309 while (0U == (n = detail::unaligned_load<size_t>(mInfo))) {
1310 mInfo +=
sizeof(size_t);
1311 mKeyVals +=
sizeof(size_t);
1313 #if defined(ROBIN_HOOD_DISABLE_INTRINSICS)
1315 if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint32_t>(mInfo))) {
1319 if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint16_t>(mInfo))) {
1323 if (ROBIN_HOOD_UNLIKELY(0U == *mInfo)) {
1328 # if ROBIN_HOOD(LITTLE_ENDIAN)
1329 auto inc = ROBIN_HOOD_COUNT_TRAILING_ZEROES(n) / 8;
1331 auto inc = ROBIN_HOOD_COUNT_LEADING_ZEROES(n) / 8;
1338 friend class Table<IsFlat, MaxLoadFactor100, key_type, mapped_type, hasher, key_equal>;
1339 NodePtr mKeyVals{
nullptr};
1340 uint8_t
const* mInfo{
nullptr};
1348 template <
typename HashKey>
1349 void keyToIdx(HashKey&& key,
size_t* idx, InfoType* info)
const {
1353 auto h =
static_cast<uint64_t
>(WHash::operator()(key));
1355 h *= mHashMultiplier;
1359 *info = mInfoInc +
static_cast<InfoType
>((h & InfoMask) >> mInfoHashShift);
1360 *idx = (
static_cast<size_t>(h) >> InitialInfoNumBits) & mMask;
1364 void next(InfoType* info,
size_t* idx)
const noexcept {
1369 void nextWhileLess(InfoType* info,
size_t* idx)
const noexcept {
1371 while (*info < mInfo[*idx]) {
1378 shiftUp(
size_t startIdx,
1379 size_t const insertion_idx) noexcept(std::is_nothrow_move_assignable<Node>::value) {
1380 auto idx = startIdx;
1381 ::new (
static_cast<void*
>(mKeyVals + idx)) Node(std::move(mKeyVals[idx - 1]));
1382 while (--idx != insertion_idx) {
1383 mKeyVals[idx] = std::move(mKeyVals[idx - 1]);
1387 while (idx != insertion_idx) {
1388 ROBIN_HOOD_COUNT(shiftUp)
1389 mInfo[idx] =
static_cast<uint8_t
>(mInfo[idx - 1] + mInfoInc);
1390 if (ROBIN_HOOD_UNLIKELY(mInfo[idx] + mInfoInc > 0xFF)) {
1391 mMaxNumElementsAllowed = 0;
1397 void shiftDown(
size_t idx) noexcept(std::is_nothrow_move_assignable<Node>::value) {
1401 mKeyVals[idx].destroy(*
this);
1404 while (mInfo[idx + 1] >= 2 * mInfoInc) {
1405 ROBIN_HOOD_COUNT(shiftDown)
1406 mInfo[idx] =
static_cast<uint8_t
>(mInfo[idx + 1] - mInfoInc);
1407 mKeyVals[idx] = std::move(mKeyVals[idx + 1]);
1414 mKeyVals[idx].~Node();
1418 template <
typename Other>
1419 ROBIN_HOOD(NODISCARD)
1420 size_t findIdx(Other
const& key)
const {
1423 keyToIdx(key, &idx, &info);
1427 if (info == mInfo[idx] &&
1428 ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) {
1432 if (info == mInfo[idx] &&
1433 ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) {
1437 }
while (info <= mInfo[idx]);
1440 return mMask == 0 ? 0
1441 :
static_cast<size_t>(std::distance(
1442 mKeyVals, reinterpret_cast_no_cast_align_warning<Node*>(mInfo)));
1445 void cloneData(
const Table& o) {
1446 Cloner<Table, IsFlat && ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(Node)>()(o, *
this);
1451 void insert_move(Node&& keyval) {
1454 if (0 == mMaxNumElementsAllowed && !try_increase_info()) {
1455 throwOverflowError();
1460 keyToIdx(keyval.getFirst(), &idx, &info);
1463 while (info <= mInfo[idx]) {
1469 auto const insertion_idx = idx;
1470 auto const insertion_info =
static_cast<uint8_t
>(info);
1471 if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {
1472 mMaxNumElementsAllowed = 0;
1476 while (0 != mInfo[idx]) {
1480 auto& l = mKeyVals[insertion_idx];
1481 if (idx == insertion_idx) {
1482 ::new (
static_cast<void*
>(&l)) Node(std::move(keyval));
1484 shiftUp(idx, insertion_idx);
1485 l = std::move(keyval);
1489 mInfo[insertion_idx] = insertion_info;
1495 using iterator = Iter<false>;
1496 using const_iterator = Iter<true>;
1498 Table() noexcept(noexcept(Hash()) && noexcept(KeyEqual()))
1501 ROBIN_HOOD_TRACE(
this)
1510 size_t ROBIN_HOOD_UNUSED(bucket_count) ,
const Hash& h = Hash{},
1511 const KeyEqual& equal = KeyEqual{}) noexcept(noexcept(Hash(h)) && noexcept(KeyEqual(equal)))
1514 ROBIN_HOOD_TRACE(
this)
1517 template <
typename Iter>
1518 Table(Iter first, Iter last,
size_t ROBIN_HOOD_UNUSED(bucket_count) = 0,
1519 const Hash& h = Hash{},
const KeyEqual& equal = KeyEqual{})
1522 ROBIN_HOOD_TRACE(
this)
1523 insert(first, last);
1526 Table(std::initializer_list<value_type> initlist,
1527 size_t ROBIN_HOOD_UNUSED(bucket_count) = 0,
const Hash& h = Hash{},
1528 const KeyEqual& equal = KeyEqual{})
1531 ROBIN_HOOD_TRACE(
this)
1532 insert(initlist.begin(), initlist.end());
1539 ROBIN_HOOD_TRACE(
this)
1541 mHashMultiplier = std::move(o.mHashMultiplier);
1542 mKeyVals = std::move(o.mKeyVals);
1543 mInfo = std::move(o.mInfo);
1544 mNumElements = std::move(o.mNumElements);
1545 mMask = std::move(o.mMask);
1546 mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);
1547 mInfoInc = std::move(o.mInfoInc);
1548 mInfoHashShift = std::move(o.mInfoHashShift);
1555 ROBIN_HOOD_TRACE(
this)
1560 mHashMultiplier = std::move(o.mHashMultiplier);
1561 mKeyVals = std::move(o.mKeyVals);
1562 mInfo = std::move(o.mInfo);
1563 mNumElements = std::move(o.mNumElements);
1564 mMask = std::move(o.mMask);
1565 mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);
1566 mInfoInc = std::move(o.mInfoInc);
1567 mInfoHashShift = std::move(o.mInfoHashShift);
1568 WHash::operator=(std::move(
static_cast<WHash&
>(o)));
1569 WKeyEqual::operator=(std::move(
static_cast<WKeyEqual&
>(o)));
1570 DataPool::operator=(std::move(
static_cast<DataPool&
>(o)));
1586 ROBIN_HOOD_TRACE(
this)
1591 auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);
1592 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
1594 ROBIN_HOOD_LOG(
"std::malloc " << numBytesTotal <<
" = calcNumBytesTotal("
1595 << numElementsWithBuffer <<
")")
1596 mHashMultiplier = o.mHashMultiplier;
1597 mKeyVals =
static_cast<Node*
>(
1598 detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
1600 mInfo =
reinterpret_cast<uint8_t*
>(mKeyVals + numElementsWithBuffer);
1601 mNumElements = o.mNumElements;
1603 mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;
1604 mInfoInc = o.mInfoInc;
1605 mInfoHashShift = o.mInfoHashShift;
1613 ROBIN_HOOD_TRACE(
this)
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) {
1645 ROBIN_HOOD_LOG(
"std::free")
1646 std::free(mKeyVals);
1649 auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);
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;
1675 void swap(
Table& o) {
1676 ROBIN_HOOD_TRACE(
this)
1683 ROBIN_HOOD_TRACE(
this)
1690 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*
this);
1692 auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
1694 uint8_t
const z = 0;
1695 std::fill(mInfo, mInfo + calcNumBytesInfo(numElementsWithBuffer), z);
1696 mInfo[numElementsWithBuffer] = 1;
1698 mInfoInc = InitialInfoInc;
1699 mInfoHashShift = InitialInfoHashShift;
1704 ROBIN_HOOD_TRACE(
this)
1709 bool operator==(
const Table& other)
const {
1710 ROBIN_HOOD_TRACE(
this)
1711 if (other.size() != size()) {
1714 for (
auto const& otherEntry : other) {
1715 if (!has(otherEntry)) {
1723 bool operator!=(
const Table& other)
const {
1724 ROBIN_HOOD_TRACE(
this)
1725 return !operator==(other);
1728 template <
typename Q = mapped_type>
1729 typename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](
const key_type& key) {
1730 ROBIN_HOOD_TRACE(
this)
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>
1755 typename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](key_type&& key) {
1756 ROBIN_HOOD_TRACE(
this)
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>
1782 void insert(Iter first, Iter last) {
1783 for (; first != last; ++first) {
1785 insert(value_type(*first));
1789 void insert(std::initializer_list<value_type> ilist) {
1790 for (
auto&& vt : ilist) {
1791 insert(std::move(vt));
1795 template <
typename... Args>
1796 std::pair<iterator, bool> emplace(Args&&... args) {
1797 ROBIN_HOOD_TRACE(
this)
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>
1824 iterator emplace_hint(const_iterator position, Args&&... args) {
1826 return emplace(std::forward<Args>(args)...).first;
1829 template <
typename... Args>
1830 std::pair<iterator, bool> try_emplace(
const key_type& key, Args&&... args) {
1831 return try_emplace_impl(key, std::forward<Args>(args)...);
1834 template <
typename... Args>
1835 std::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args) {
1836 return try_emplace_impl(std::move(key), std::forward<Args>(args)...);
1839 template <
typename... Args>
1840 iterator try_emplace(const_iterator hint,
const key_type& key, Args&&... args) {
1842 return try_emplace_impl(key, std::forward<Args>(args)...).first;
1845 template <
typename... Args>
1846 iterator try_emplace(const_iterator hint, key_type&& key, Args&&... args) {
1848 return try_emplace_impl(std::move(key), std::forward<Args>(args)...).first;
1851 template <
typename Mapped>
1852 std::pair<iterator, bool> insert_or_assign(
const key_type& key, Mapped&& obj) {
1853 return insertOrAssignImpl(key, std::forward<Mapped>(obj));
1856 template <
typename Mapped>
1857 std::pair<iterator, bool> insert_or_assign(key_type&& key, Mapped&& obj) {
1858 return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj));
1861 template <
typename Mapped>
1862 iterator insert_or_assign(const_iterator hint,
const key_type& key, Mapped&& obj) {
1864 return insertOrAssignImpl(key, std::forward<Mapped>(obj)).first;
1867 template <
typename Mapped>
1868 iterator insert_or_assign(const_iterator hint, key_type&& key, Mapped&& obj) {
1870 return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj)).first;
1873 std::pair<iterator, bool> insert(
const value_type& keyval) {
1874 ROBIN_HOOD_TRACE(
this)
1875 return emplace(keyval);
1878 iterator insert(const_iterator hint,
const value_type& keyval) {
1880 return emplace(keyval).first;
1883 std::pair<iterator, bool> insert(value_type&& keyval) {
1884 return emplace(std::move(keyval));
1887 iterator insert(const_iterator hint, value_type&& keyval) {
1889 return emplace(std::move(keyval)).first;
1893 size_t count(
const key_type& key)
const {
1894 ROBIN_HOOD_TRACE(
this)
1895 auto kv = mKeyVals + findIdx(key);
1896 if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1902 template <
typename OtherKey,
typename Self_ = Self>
1903 typename std::enable_if<Self_::is_transparent, size_t>::type count(
const OtherKey& key)
const {
1904 ROBIN_HOOD_TRACE(
this)
1905 auto kv = mKeyVals + findIdx(key);
1906 if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1912 bool contains(
const key_type& key)
const {
1913 return 1U == count(key);
1916 template <
typename OtherKey,
typename Self_ = Self>
1917 typename std::enable_if<Self_::is_transparent, bool>::type contains(
const OtherKey& key)
const {
1918 return 1U == count(key);
1923 template <
typename Q = mapped_type>
1924 typename std::enable_if<!std::is_void<Q>::value, Q&>::type at(key_type
const& key) {
1925 ROBIN_HOOD_TRACE(
this)
1926 auto kv = mKeyVals + findIdx(key);
1927 if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1928 doThrow<std::out_of_range>(
"key not found");
1930 return kv->getSecond();
1935 template <
typename Q = mapped_type>
1936 typename std::enable_if<!std::is_void<Q>::value, Q
const&>::type at(key_type
const& key)
const {
1937 ROBIN_HOOD_TRACE(
this)
1938 auto kv = mKeyVals + findIdx(key);
1939 if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1940 doThrow<std::out_of_range>(
"key not found");
1942 return kv->getSecond();
1945 const_iterator find(
const key_type& key)
const {
1946 ROBIN_HOOD_TRACE(
this)
1947 const size_t idx = findIdx(key);
1948 return const_iterator{mKeyVals + idx, mInfo + idx};
1951 template <
typename OtherKey>
1953 ROBIN_HOOD_TRACE(
this)
1954 const size_t idx = findIdx(key);
1955 return const_iterator{mKeyVals + idx, mInfo + idx};
1958 template <
typename OtherKey,
typename Self_ = Self>
1959 typename std::enable_if<Self_::is_transparent,
1960 const_iterator>::type
1961 find(
const OtherKey& key)
const {
1962 ROBIN_HOOD_TRACE(
this)
1963 const size_t idx = findIdx(key);
1964 return const_iterator{mKeyVals + idx, mInfo + idx};
1967 iterator find(
const key_type& key) {
1968 ROBIN_HOOD_TRACE(
this)
1969 const size_t idx = findIdx(key);
1970 return iterator{mKeyVals + idx, mInfo + idx};
1973 template <
typename OtherKey>
1975 ROBIN_HOOD_TRACE(
this)
1976 const size_t idx = findIdx(key);
1977 return iterator{mKeyVals + idx, mInfo + idx};
1980 template <
typename OtherKey,
typename Self_ = Self>
1981 typename std::enable_if<Self_::is_transparent, iterator>::type find(
const OtherKey& key) {
1982 ROBIN_HOOD_TRACE(
this)
1983 const size_t idx = findIdx(key);
1984 return iterator{mKeyVals + idx, mInfo + idx};
1988 ROBIN_HOOD_TRACE(
this)
1992 return iterator(mKeyVals, mInfo, fast_forward_tag{});
1994 const_iterator begin()
const {
1995 ROBIN_HOOD_TRACE(
this)
1998 const_iterator cbegin()
const {
1999 ROBIN_HOOD_TRACE(
this)
2003 return const_iterator(mKeyVals, mInfo, fast_forward_tag{});
2007 ROBIN_HOOD_TRACE(
this)
2010 return iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo),
nullptr};
2012 const_iterator end()
const {
2013 ROBIN_HOOD_TRACE(
this)
2016 const_iterator cend()
const {
2017 ROBIN_HOOD_TRACE(
this)
2018 return const_iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo),
nullptr};
2021 iterator erase(const_iterator pos) {
2022 ROBIN_HOOD_TRACE(
this)
2024 return erase(iterator{
const_cast<Node*
>(pos.mKeyVals),
const_cast<uint8_t*
>(pos.mInfo)});
2028 iterator erase(iterator pos) {
2029 ROBIN_HOOD_TRACE(
this)
2031 auto const idx =
static_cast<size_t>(pos.mKeyVals - mKeyVals);
2045 size_t erase(
const key_type& key) {
2046 ROBIN_HOOD_TRACE(
this)
2049 keyToIdx(key, &idx, &info);
2053 if (info == mInfo[idx] && WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
2059 }
while (info <= mInfo[idx]);
2067 void rehash(
size_t c) {
2074 void reserve(
size_t c) {
2082 ROBIN_HOOD_TRACE(
this)
2083 auto newSize = InitialNumElements;
2084 while (calcMaxNumElementsAllowed(newSize) < mNumElements && newSize != 0) {
2087 if (ROBIN_HOOD_UNLIKELY(newSize == 0)) {
2088 throwOverflowError();
2091 ROBIN_HOOD_LOG(
"newSize > mMask + 1: " << newSize <<
" > " << mMask <<
" + 1")
2095 if (newSize < mMask + 1) {
2096 rehashPowerOfTwo(newSize,
true);
2100 size_type size()
const noexcept {
2101 ROBIN_HOOD_TRACE(
this)
2102 return mNumElements;
2105 size_type max_size()
const noexcept {
2106 ROBIN_HOOD_TRACE(
this)
2107 return static_cast<size_type
>(-1);
2110 ROBIN_HOOD(NODISCARD)
bool empty()
const noexcept {
2111 ROBIN_HOOD_TRACE(
this)
2112 return 0 == mNumElements;
2115 float max_load_factor()
const noexcept {
2116 ROBIN_HOOD_TRACE(
this)
2117 return MaxLoadFactor100 / 100.0F;
2121 float load_factor()
const noexcept {
2122 ROBIN_HOOD_TRACE(
this)
2123 return static_cast<float>(size()) /
static_cast<float>(mMask + 1);
2126 ROBIN_HOOD(NODISCARD)
size_t mask()
const noexcept {
2127 ROBIN_HOOD_TRACE(
this)
2131 ROBIN_HOOD(NODISCARD)
size_t calcMaxNumElementsAllowed(
size_t maxElements)
const noexcept {
2132 if (ROBIN_HOOD_LIKELY(maxElements <= (std::numeric_limits<size_t>::max)() / 100)) {
2133 return maxElements * MaxLoadFactor100 / 100;
2137 return (maxElements / 100) * MaxLoadFactor100;
2140 ROBIN_HOOD(NODISCARD)
size_t calcNumBytesInfo(
size_t numElements)
const noexcept {
2143 return numElements +
sizeof(uint64_t);
2146 ROBIN_HOOD(NODISCARD)
2147 size_t calcNumElementsWithBuffer(
size_t numElements)
const noexcept {
2148 auto maxNumElementsAllowed = calcMaxNumElementsAllowed(numElements);
2149 return numElements + (std::min)(maxNumElementsAllowed, (
static_cast<size_t>(0xFF)));
2153 ROBIN_HOOD(NODISCARD)
size_t calcNumBytesTotal(
size_t numElements)
const {
2154 #if ROBIN_HOOD(BITNESS) == 64
2155 return numElements *
sizeof(Node) + calcNumBytesInfo(numElements);
2158 auto const ne =
static_cast<uint64_t
>(numElements);
2159 auto const s =
static_cast<uint64_t
>(
sizeof(Node));
2160 auto const infos =
static_cast<uint64_t
>(calcNumBytesInfo(numElements));
2162 auto const total64 = ne * s + infos;
2163 auto const total =
static_cast<size_t>(total64);
2165 if (ROBIN_HOOD_UNLIKELY(
static_cast<uint64_t
>(total) != total64)) {
2166 throwOverflowError();
2173 template <
typename Q = mapped_type>
2174 ROBIN_HOOD(NODISCARD)
2175 typename std::enable_if<!std::is_void<Q>::value,
bool>::type has(
const value_type& e)
const {
2176 ROBIN_HOOD_TRACE(
this)
2177 auto it = find(e.first);
2178 return it != end() && it->second == e.second;
2181 template <
typename Q = mapped_type>
2182 ROBIN_HOOD(NODISCARD)
2183 typename std::enable_if<std::is_void<Q>::value,
bool>::type has(
const value_type& e)
const {
2184 ROBIN_HOOD_TRACE(
this)
2185 return find(e) != end();
2188 void reserve(
size_t c,
bool forceRehash) {
2189 ROBIN_HOOD_TRACE(
this)
2190 auto const minElementsAllowed = (std::max)(c, mNumElements);
2191 auto newSize = InitialNumElements;
2192 while (calcMaxNumElementsAllowed(newSize) < minElementsAllowed && newSize != 0) {
2195 if (ROBIN_HOOD_UNLIKELY(newSize == 0)) {
2196 throwOverflowError();
2199 ROBIN_HOOD_LOG(
"newSize > mMask + 1: " << newSize <<
" > " << mMask <<
" + 1")
2203 if (forceRehash || newSize > mMask + 1) {
2204 rehashPowerOfTwo(newSize,
false);
2211 void rehashPowerOfTwo(
size_t numBuckets,
bool forceFree) {
2212 ROBIN_HOOD_TRACE(
this)
2214 Node*
const oldKeyVals = mKeyVals;
2215 uint8_t
const*
const oldInfo = mInfo;
2217 const size_t oldMaxElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
2220 initData(numBuckets);
2221 if (oldMaxElementsWithBuffer > 1) {
2222 for (
size_t i = 0; i < oldMaxElementsWithBuffer; ++i) {
2223 if (oldInfo[i] != 0) {
2226 insert_move(std::move(oldKeyVals[i]));
2228 oldKeyVals[i].~Node();
2235 if (oldKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
2238 std::free(oldKeyVals);
2240 DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer));
2246 ROBIN_HOOD(NOINLINE)
void throwOverflowError()
const {
2247 #if ROBIN_HOOD(HAS_EXCEPTIONS)
2248 throw std::overflow_error(
"robin_hood::map overflow");
2254 template <
typename OtherKey,
typename... Args>
2255 std::pair<iterator, bool> try_emplace_impl(OtherKey&& key, Args&&... args) {
2256 ROBIN_HOOD_TRACE(
this)
2257 auto idxAndState = insertKeyPrepareEmptySpot(key);
2258 switch (idxAndState.second) {
2259 case InsertionState::key_found:
2262 case InsertionState::new_node:
2263 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(
2264 *
this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
2265 std::forward_as_tuple(std::forward<Args>(args)...));
2268 case InsertionState::overwrite_node:
2269 mKeyVals[idxAndState.first] = Node(*
this, std::piecewise_construct,
2270 std::forward_as_tuple(std::forward<OtherKey>(key)),
2271 std::forward_as_tuple(std::forward<Args>(args)...));
2274 case InsertionState::overflow_error:
2275 throwOverflowError();
2279 return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
2280 InsertionState::key_found != idxAndState.second);
2283 template <
typename OtherKey,
typename Mapped>
2284 std::pair<iterator, bool> insertOrAssignImpl(OtherKey&& key, Mapped&& obj) {
2285 ROBIN_HOOD_TRACE(
this)
2286 auto idxAndState = insertKeyPrepareEmptySpot(key);
2287 switch (idxAndState.second) {
2288 case InsertionState::key_found:
2289 mKeyVals[idxAndState.first].getSecond() = std::forward<Mapped>(obj);
2292 case InsertionState::new_node:
2293 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(
2294 *
this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
2295 std::forward_as_tuple(std::forward<Mapped>(obj)));
2298 case InsertionState::overwrite_node:
2299 mKeyVals[idxAndState.first] = Node(*
this, std::piecewise_construct,
2300 std::forward_as_tuple(std::forward<OtherKey>(key)),
2301 std::forward_as_tuple(std::forward<Mapped>(obj)));
2304 case InsertionState::overflow_error:
2305 throwOverflowError();
2309 return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
2310 InsertionState::key_found != idxAndState.second);
2313 void initData(
size_t max_elements) {
2315 mMask = max_elements - 1;
2316 mMaxNumElementsAllowed = calcMaxNumElementsAllowed(max_elements);
2318 auto const numElementsWithBuffer = calcNumElementsWithBuffer(max_elements);
2321 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
2322 ROBIN_HOOD_LOG(
"std::calloc " << numBytesTotal <<
" = calcNumBytesTotal("
2323 << numElementsWithBuffer <<
")")
2324 mKeyVals =
reinterpret_cast<Node*
>(
2325 detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
2326 mInfo =
reinterpret_cast<uint8_t*
>(mKeyVals + numElementsWithBuffer);
2327 std::memset(mInfo, 0, numBytesTotal - numElementsWithBuffer *
sizeof(Node));
2330 mInfo[numElementsWithBuffer] = 1;
2332 mInfoInc = InitialInfoInc;
2333 mInfoHashShift = InitialInfoHashShift;
2336 enum class InsertionState { overflow_error, key_found, new_node, overwrite_node };
2341 template <
typename OtherKey>
2342 std::pair<size_t, InsertionState> insertKeyPrepareEmptySpot(OtherKey&& key) {
2343 for (
int i = 0; i < 256; ++i) {
2346 keyToIdx(key, &idx, &info);
2347 nextWhileLess(&info, &idx);
2350 while (info == mInfo[idx]) {
2351 if (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
2354 return std::make_pair(idx, InsertionState::key_found);
2360 if (ROBIN_HOOD_UNLIKELY(mNumElements >= mMaxNumElementsAllowed)) {
2361 if (!increase_size()) {
2362 return std::make_pair(
size_t(0), InsertionState::overflow_error);
2368 auto const insertion_idx = idx;
2369 auto const insertion_info = info;
2370 if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {
2371 mMaxNumElementsAllowed = 0;
2375 while (0 != mInfo[idx]) {
2379 if (idx != insertion_idx) {
2380 shiftUp(idx, insertion_idx);
2383 mInfo[insertion_idx] =
static_cast<uint8_t
>(insertion_info);
2385 return std::make_pair(insertion_idx, idx == insertion_idx
2386 ? InsertionState::new_node
2387 : InsertionState::overwrite_node);
2391 return std::make_pair(
size_t(0), InsertionState::overflow_error);
2394 bool try_increase_info() {
2395 ROBIN_HOOD_LOG(
"mInfoInc=" << mInfoInc <<
", numElements=" << mNumElements
2396 <<
", maxNumElementsAllowed="
2397 << calcMaxNumElementsAllowed(mMask + 1))
2398 if (mInfoInc <= 2) {
2403 mInfoInc =
static_cast<uint8_t
>(mInfoInc >> 1U);
2408 auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
2410 for (
size_t i = 0; i < numElementsWithBuffer; i += 8) {
2411 auto val = unaligned_load<uint64_t>(mInfo + i);
2412 val = (val >> 1U) & UINT64_C(0x7f7f7f7f7f7f7f7f);
2413 std::memcpy(mInfo + i, &val,
sizeof(val));
2416 mInfo[numElementsWithBuffer] = 1;
2418 mMaxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
2423 bool increase_size() {
2426 initData(InitialNumElements);
2430 auto const maxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
2431 if (mNumElements < maxNumElementsAllowed && try_increase_info()) {
2435 ROBIN_HOOD_LOG(
"mNumElements=" << mNumElements <<
", maxNumElementsAllowed="
2436 << maxNumElementsAllowed <<
", load="
2437 << (
static_cast<double>(mNumElements) * 100.0 /
2438 (
static_cast<double>(mMask) + 1)))
2440 if (mNumElements * 2 < calcMaxNumElementsAllowed(mMask + 1)) {
2444 nextHashMultiplier();
2445 rehashPowerOfTwo(mMask + 1,
true);
2448 rehashPowerOfTwo((mMask + 1) * 2,
false);
2453 void nextHashMultiplier() {
2456 mHashMultiplier += UINT64_C(0xc4ceb9fe1a85ec54);
2465 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}
2466 .nodesDoNotDeallocate(*
this);
2472 if (mKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
2473 ROBIN_HOOD_LOG(
"std::free")
2474 std::free(mKeyVals);
2478 void init() noexcept {
2479 mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);
2480 mInfo =
reinterpret_cast<uint8_t*
>(&mMask);
2483 mMaxNumElementsAllowed = 0;
2484 mInfoInc = InitialInfoInc;
2485 mInfoHashShift = InitialInfoHashShift;
2489 uint64_t mHashMultiplier = UINT64_C(0xc4ceb9fe1a85ec53);
2490 Node* mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);
2491 uint8_t* mInfo =
reinterpret_cast<uint8_t*
>(&mMask);
2492 size_t mNumElements = 0;
2494 size_t mMaxNumElementsAllowed = 0;
2495 InfoType mInfoInc = InitialInfoInc;
2496 InfoType mInfoHashShift = InitialInfoHashShift;
2504 template <
typename Key,
typename T,
typename Hash = hash<Key>,
2505 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2508 template <
typename Key,
typename T,
typename Hash = hash<Key>,
2509 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2512 template <
typename Key,
typename T,
typename Hash = hash<Key>,
2513 typename KeyEqual = std::equal_to<Key>,
size_t MaxLoadFactor100 = 80>
2516 std::is_nothrow_move_constructible<robin_hood::pair<Key, T>>::value &&
2517 std::is_nothrow_move_assignable<robin_hood::pair<Key, T>>::value,
2518 MaxLoadFactor100, Key, T, Hash, KeyEqual>;
2522 template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2523 size_t MaxLoadFactor100 = 80>
2526 template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2527 size_t MaxLoadFactor100 = 80>
2530 template <
typename Key,
typename Hash = hash<Key>,
typename KeyEqual = std::equal_to<Key>,
2531 size_t MaxLoadFactor100 = 80>
2533 std::is_nothrow_move_constructible<Key>::value &&
2534 std::is_nothrow_move_assignable<Key>::value,
2535 MaxLoadFactor100, Key, void, Hash, KeyEqual>;