717 typename std::conditional<
718 std::is_void<T>::value, Key,
719 robin_hood::pair<typename std::conditional<IsFlat, Key, Key const>::type, T>>::type,
722 static constexpr bool is_flat = IsFlat;
723 static constexpr bool is_map = !std::is_void<T>::value;
724 static constexpr bool is_set = !is_map;
727 using key_type = Key;
728 using mapped_type = T;
729 using value_type =
typename std::conditional<
731 using size_type = size_t;
733 using key_equal = KeyEqual;
737 static_assert(MaxLoadFactor100 > 10 && MaxLoadFactor100 < 100,
"MaxLoadFactor100 needs to be >10 && < 100");
745 static constexpr size_t InitialNumElements =
sizeof(uint64_t);
746 static constexpr uint32_t InitialInfoNumBits = 5;
747 static constexpr uint8_t InitialInfoInc = 1U << InitialInfoNumBits;
748 static constexpr size_t InfoMask = InitialInfoInc - 1U;
749 static constexpr uint8_t InitialInfoHashShift = 64U - InitialInfoNumBits;
753 using InfoType = uint32_t;
760 template <
typename M,
bool>
764 template <
typename M>
765 class DataNode<M, true> final {
767 template <
typename... Args>
768 explicit DataNode(M& ROBIN_HOOD_UNUSED(map) , Args&&... args)
noexcept(
769 noexcept(value_type(GAIA_FWD(args)...))): mData(GAIA_FWD(args)...) {}
771 DataNode(M& ROBIN_HOOD_UNUSED(map) , DataNode<M, true>&& n)
noexcept(
772 std::is_nothrow_move_constructible<value_type>::value): mData(GAIA_MOV(n.mData)) {}
775 void destroy(M& ROBIN_HOOD_UNUSED(map) )
noexcept {}
776 void destroyDoNotDeallocate()
noexcept {}
778 value_type
const* operator->()
const noexcept {
781 value_type* operator->()
noexcept {
785 const value_type& operator*()
const noexcept {
789 value_type& operator*()
noexcept {
793 template <
typename VT = value_type>
794 GAIA_NODISCARD
typename std::enable_if<is_map, typename VT::first_type&>::type getFirst()
noexcept {
797 template <
typename VT = value_type>
798 GAIA_NODISCARD
typename std::enable_if<is_set, VT&>::type getFirst()
noexcept {
802 template <
typename VT = value_type>
803 GAIA_NODISCARD
typename std::enable_if<is_map, typename VT::first_type const&>::type getFirst()
const noexcept {
806 template <
typename VT = value_type>
807 GAIA_NODISCARD
typename std::enable_if<is_set, VT const&>::type getFirst()
const noexcept {
811 template <
typename MT = mapped_type>
812 GAIA_NODISCARD
typename std::enable_if<is_map, MT&>::type getSecond()
noexcept {
816 template <
typename MT = mapped_type>
817 GAIA_NODISCARD
typename std::enable_if<is_set, MT const&>::type getSecond()
const noexcept {
822 swap(DataNode<M, true>& o)
noexcept(
noexcept(std::declval<value_type>().swap(std::declval<value_type>()))) {
831 template <
typename M>
832 class DataNode<M, false> {
834 template <
typename... Args>
835 explicit DataNode(M& map, Args&&... args): mData(map.allocate()) {
836 ::new (
static_cast<void*
>(mData)) value_type(GAIA_FWD(args)...);
839 DataNode(M& ROBIN_HOOD_UNUSED(map) , DataNode<M, false>&& n)
noexcept: mData(GAIA_MOV(n.mData)) {}
841 void destroy(M& map)
noexcept {
843 mData->~value_type();
844 map.deallocate(mData);
847 void destroyDoNotDeallocate()
noexcept {
848 mData->~value_type();
851 value_type
const* operator->()
const noexcept {
855 value_type* operator->()
noexcept {
859 const value_type& operator*()
const {
863 value_type& operator*() {
867 template <
typename VT = value_type>
868 GAIA_NODISCARD
typename std::enable_if<is_map, typename VT::first_type&>::type getFirst()
noexcept {
871 template <
typename VT = value_type>
872 GAIA_NODISCARD
typename std::enable_if<is_set, VT&>::type getFirst()
noexcept {
876 template <
typename VT = value_type>
877 GAIA_NODISCARD
typename std::enable_if<is_map, typename VT::first_type const&>::type getFirst()
const noexcept {
880 template <
typename VT = value_type>
881 GAIA_NODISCARD
typename std::enable_if<is_set, VT const&>::type getFirst()
const noexcept {
885 template <
typename MT = mapped_type>
886 GAIA_NODISCARD
typename std::enable_if<is_map, MT&>::type getSecond()
noexcept {
887 return mData->second;
890 template <
typename MT = mapped_type>
891 GAIA_NODISCARD
typename std::enable_if<is_map, MT const&>::type getSecond()
const noexcept {
892 return mData->second;
895 void swap(DataNode<M, false>& o)
noexcept {
896 using gaia::core::swap;
897 swap(mData, o.mData);
904 using Node = DataNode<Self, IsFlat>;
907 GAIA_NODISCARD key_type
const& getFirstConst(Node
const& n)
const noexcept {
913 GAIA_NODISCARD key_type
const& getFirstConst(key_type
const& k)
const noexcept {
918 template <
typename Q = mapped_type>
919 GAIA_NODISCARD
typename std::enable_if<!std::is_void<Q>::value, key_type
const&>::type
920 getFirstConst(value_type
const& vt)
const noexcept {
926 template <
typename M,
bool UseMemcpy>
930 template <
typename M>
931 struct Cloner<M, true> {
932 void operator()(M
const& source, M& target)
const {
933 auto const*
const src =
reinterpret_cast<uint8_t const*
>(source.mKeyVals);
934 auto* tgt =
reinterpret_cast<uint8_t*
>(target.mKeyVals);
935 auto const numElementsWithBuffer = target.calcNumElementsWithBuffer(target.mMask + 1);
936 gaia::mem::copy_elements<uint8_t, false>(
937 tgt, src, (uint32_t)target.calcNumBytesTotal(numElementsWithBuffer), 0, 0, 0);
941 template <
typename M>
942 struct Cloner<M, false> {
943 void operator()(M
const& s, M& t)
const {
944 auto const numElementsWithBuffer = t.calcNumElementsWithBuffer(t.mMask + 1);
945 gaia::mem::copy_elements<uint8_t, false>(
946 t.mInfo, s.mInfo, (uint32_t)t.calcNumBytesInfo(numElementsWithBuffer), 0, 0, 0);
948 for (
size_t i = 0; i < numElementsWithBuffer; ++i) {
950 ::new (
static_cast<void*
>(t.mKeyVals + i)) Node(t, *s.mKeyVals[i]);
958 template <
typename M,
bool IsFlatAndTrivial>
961 template <
typename M>
962 struct Destroyer<M, true> {
963 void nodes(M& m)
const noexcept {
967 void nodesDoNotDeallocate(M& m)
const noexcept {
972 template <
typename M>
973 struct Destroyer<M, false> {
974 void nodes(M& m)
const noexcept {
977 auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
979 for (
size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
980 if (0 != m.mInfo[idx]) {
981 Node& n = m.mKeyVals[idx];
988 void nodesDoNotDeallocate(M& m)
const noexcept {
991 auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
992 for (
size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
993 if (0 != m.mInfo[idx]) {
994 Node& n = m.mKeyVals[idx];
995 n.destroyDoNotDeallocate();
1004 struct fast_forward_tag {};
1007 template <
bool IsConst>
1011 using NodePtr =
typename std::conditional<IsConst, Node const*, Node*>::type;
1014 using difference_type = std::ptrdiff_t;
1015 using value_type =
typename Self::value_type;
1016 using reference =
typename std::conditional<IsConst, value_type const&, value_type&>::type;
1017 using pointer =
typename std::conditional<IsConst, value_type const*, value_type*>::type;
1028 template <bool OtherIsConst, typename = typename std::enable_if<IsConst && !OtherIsConst>::type>
1030 Iter(Iter<OtherIsConst>
const& other)
noexcept: mKeyVals(other.mKeyVals), mInfo(other.mInfo) {}
1032 Iter(NodePtr valPtr, uint8_t
const* infoPtr)
noexcept: mKeyVals(valPtr), mInfo(infoPtr) {}
1034 Iter(NodePtr valPtr, uint8_t
const* infoPtr, fast_forward_tag ROBIN_HOOD_UNUSED(tag) )
noexcept:
1035 mKeyVals(valPtr), mInfo(infoPtr) {
1039 template <bool OtherIsConst, typename = typename std::enable_if<IsConst && !OtherIsConst>::type>
1040 Iter& operator=(Iter<OtherIsConst>
const& other)
noexcept {
1041 mKeyVals = other.mKeyVals;
1042 mInfo = other.mInfo;
1047 Iter& operator++()
noexcept {
1054 Iter operator++(
int)
noexcept {
1060 reference operator*()
const {
1064 pointer operator->()
const {
1069 bool operator==(Iter<O>
const& o)
const noexcept {
1070 return mKeyVals == o.mKeyVals;
1074 bool operator!=(Iter<O>
const& o)
const noexcept {
1075 return mKeyVals != o.mKeyVals;
1082 void fastForward()
noexcept {
1084 while (0U == (n = detail::unaligned_load<size_t>(mInfo))) {
1085 GAIA_MSVC_WARNING_PUSH()
1086 GAIA_MSVC_WARNING_DISABLE(6305)
1087 mInfo +=
sizeof(size_t);
1088 mKeyVals +=
sizeof(size_t);
1089 GAIA_MSVC_WARNING_POP()
1091#if defined(ROBIN_HOOD_DISABLE_INTRINSICS)
1093 if GAIA_UNLIKELY (0U == detail::unaligned_load<uint32_t>(mInfo)) {
1097 if GAIA_UNLIKELY (0U == detail::unaligned_load<uint16_t>(mInfo)) {
1101 if GAIA_UNLIKELY (0U == *mInfo) {
1106 #if GAIA_LITTLE_ENDIAN
1107 auto inc = ROBIN_HOOD_COUNT_TRAILING_ZEROES(n) / 8;
1109 auto inc = ROBIN_HOOD_COUNT_LEADING_ZEROES(n) / 8;
1116 friend class Table<IsFlat, MaxLoadFactor100, key_type, mapped_type, hasher, key_equal>;
1117 NodePtr mKeyVals{
nullptr};
1118 uint8_t
const* mInfo{
nullptr};
1126 template <
typename HashKey>
1127 void keyToIdx(HashKey&& key,
size_t* idx, InfoType* info)
const {
1128 auto h =
static_cast<uint64_t
>(WHash::operator()(key));
1131 using HashKeyRaw = std::decay_t<HashKey>;
1132 if constexpr (!gaia::core::is_direct_hash_key_v<HashKeyRaw>) {
1136 h *= mHashMultiplier;
1141 *info = mInfoInc +
static_cast<InfoType
>(h >> mInfoHashShift);
1142 *idx = (
static_cast<size_t>(h)) & mMask;
1146 void next(InfoType* info,
size_t* idx)
const noexcept {
1151 void nextWhileLess(InfoType* info,
size_t* idx)
const noexcept {
1153 while (*info < mInfo[*idx]) {
1159 void shiftUp(
size_t startIdx,
size_t const insertion_idx)
noexcept(std::is_nothrow_move_assignable<Node>::value) {
1160 auto idx = startIdx;
1161 ::new (
static_cast<void*
>(mKeyVals + idx)) Node(GAIA_MOV(mKeyVals[idx - 1]));
1162 while (--idx != insertion_idx) {
1163 mKeyVals[idx] = GAIA_MOV(mKeyVals[idx - 1]);
1167 while (idx != insertion_idx) {
1168 mInfo[idx] =
static_cast<uint8_t
>(mInfo[idx - 1] + mInfoInc);
1169 if GAIA_UNLIKELY (mInfo[idx] + mInfoInc > 0xFF) {
1170 mMaxNumElementsAllowed = 0;
1176 void shiftDown(
size_t idx)
noexcept(std::is_nothrow_move_assignable<Node>::value) {
1180 mKeyVals[idx].destroy(*
this);
1183 while (mInfo[idx + 1] >= 2 * mInfoInc) {
1184 mInfo[idx] =
static_cast<uint8_t
>(mInfo[idx + 1] - mInfoInc);
1185 mKeyVals[idx] = GAIA_MOV(mKeyVals[idx + 1]);
1192 mKeyVals[idx].~Node();
1196 template <
typename Other>
1197 GAIA_NODISCARD
size_t findIdx(Other
const& key)
const {
1200 keyToIdx(key, &idx, &info);
1204 if (info == mInfo[idx]) {
1205 if GAIA_LIKELY (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
1210 if (info == mInfo[idx]) {
1211 if GAIA_LIKELY (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
1216 }
while (info <= mInfo[idx]);
1219 return mMask == 0 ? 0
1220 :
static_cast<size_t>(
1221 gaia::core::distance(mKeyVals, reinterpret_cast_no_cast_align_warning<Node*>(mInfo)));
1224 void cloneData(
const Table& o) {
1225 Cloner<Table, IsFlat && ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(Node)>()(o, *
this);
1230 void insert_move(Node&& keyval) {
1233 if (0 == mMaxNumElementsAllowed && !try_increase_info()) {
1234 throwOverflowError();
1239 keyToIdx(keyval.getFirst(), &idx, &info);
1242 while (info <= mInfo[idx]) {
1248 auto const insertion_idx = idx;
1249 auto const insertion_info =
static_cast<uint8_t
>(info);
1250 if GAIA_UNLIKELY (insertion_info + mInfoInc > 0xFF) {
1251 mMaxNumElementsAllowed = 0;
1255 while (0 != mInfo[idx]) {
1259 auto& l = mKeyVals[insertion_idx];
1260 if (idx == insertion_idx) {
1261 ::new (
static_cast<void*
>(&l)) Node(GAIA_MOV(keyval));
1263 shiftUp(idx, insertion_idx);
1264 l = GAIA_MOV(keyval);
1268 mInfo[insertion_idx] = insertion_info;
1274 using iterator = Iter<false>;
1275 using const_iterator = Iter<true>;
1278 ROBIN_HOOD_TRACE(
"%p",
this);
1279 GAIA_ASSERT(gaia::CheckEndianess());
1288 size_t ROBIN_HOOD_UNUSED(bucket_count) ,
const Hash& h = Hash{},
1289 const KeyEqual& equal = KeyEqual{})
noexcept(
noexcept(Hash(h)) &&
noexcept(KeyEqual(equal))):
1291 ROBIN_HOOD_TRACE(
"%p",
this);
1292 GAIA_ASSERT(gaia::CheckEndianess());
1295 template <
typename Iter>
1297 Iter first, Iter last,
size_t ROBIN_HOOD_UNUSED(bucket_count) = 0,
const Hash& h = Hash{},
1298 const KeyEqual& equal = KeyEqual{}):
WHash(h),
WKeyEqual(equal) {
1299 ROBIN_HOOD_TRACE(
"%p",
this);
1300 GAIA_ASSERT(gaia::CheckEndianess());
1301 insert(first, last);
1305 std::initializer_list<value_type> initlist,
size_t ROBIN_HOOD_UNUSED(bucket_count) = 0,
1306 const Hash& h = Hash{},
const KeyEqual& equal = KeyEqual{}):
WHash(h),
WKeyEqual(equal) {
1307 ROBIN_HOOD_TRACE(
"%p",
this);
1308 GAIA_ASSERT(gaia::CheckEndianess());
1309 insert(initlist.begin(), initlist.end());
1315 ROBIN_HOOD_TRACE(
"%p",
this);
1317 mHashMultiplier = GAIA_MOV(o.mHashMultiplier);
1318 mKeyVals = GAIA_MOV(o.mKeyVals);
1319 mInfo = GAIA_MOV(o.mInfo);
1320 mNumElements = GAIA_MOV(o.mNumElements);
1321 mMask = GAIA_MOV(o.mMask);
1322 mMaxNumElementsAllowed = GAIA_MOV(o.mMaxNumElementsAllowed);
1323 mInfoInc = GAIA_MOV(o.mInfoInc);
1324 mInfoHashShift = GAIA_MOV(o.mInfoHashShift);
1331 ROBIN_HOOD_TRACE(
"%p",
this);
1336 mHashMultiplier = GAIA_MOV(o.mHashMultiplier);
1337 mKeyVals = GAIA_MOV(o.mKeyVals);
1338 mInfo = GAIA_MOV(o.mInfo);
1339 mNumElements = GAIA_MOV(o.mNumElements);
1340 mMask = GAIA_MOV(o.mMask);
1341 mMaxNumElementsAllowed = GAIA_MOV(o.mMaxNumElementsAllowed);
1342 mInfoInc = GAIA_MOV(o.mInfoInc);
1343 mInfoHashShift = GAIA_MOV(o.mInfoHashShift);
1344 WHash::operator=(GAIA_MOV(
static_cast<WHash&
>(o)));
1345 WKeyEqual::operator=(GAIA_MOV(
static_cast<WKeyEqual&
>(o)));
1346 DataPool::operator=(GAIA_MOV(
static_cast<DataPool&
>(o)));
1361 ROBIN_HOOD_TRACE(
"%p",
this);
1366 auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);
1367 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
1369 ROBIN_HOOD_LOG(
"gaia::mem::mem_alloc %zu = calcNumBytesTotal(%zu)", numBytesTotal, numElementsWithBuffer);
1370 mHashMultiplier = o.mHashMultiplier;
1371 mKeyVals =
static_cast<Node*
>(detail::assertNotNull<std::bad_alloc>(gaia::mem::mem_alloc(numBytesTotal)));
1373 mInfo =
reinterpret_cast<uint8_t*
>(mKeyVals + numElementsWithBuffer);
1374 mNumElements = o.mNumElements;
1376 mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;
1377 mInfoInc = o.mInfoInc;
1378 mInfoHashShift = o.mInfoHashShift;
1387 ROBIN_HOOD_TRACE(
"%p",
this);
1405 WHash::operator=(
static_cast<const WHash&
>(o));
1406 WKeyEqual::operator=(
static_cast<const WKeyEqual&
>(o));
1407 DataPool::operator=(
static_cast<DataPool const&
>(o));
1413 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*
this);
1415 if (mMask != o.mMask) {
1419 ROBIN_HOOD_LOG(
"gaia::mem::mem_free");
1420 gaia::mem::mem_free(mKeyVals);
1423 auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);
1424 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
1425 ROBIN_HOOD_LOG(
"gaia::mem::mem_alloc %zu = calcNumBytesTotal(%zu)", numBytesTotal, numElementsWithBuffer);
1426 mKeyVals =
static_cast<Node*
>(detail::assertNotNull<std::bad_alloc>(gaia::mem::mem_alloc(numBytesTotal)));
1429 mInfo =
reinterpret_cast<uint8_t*
>(mKeyVals + numElementsWithBuffer);
1432 WHash::operator=(
static_cast<const WHash&
>(o));
1433 WKeyEqual::operator=(
static_cast<const WKeyEqual&
>(o));
1434 DataPool::operator=(
static_cast<DataPool const&
>(o));
1435 mHashMultiplier = o.mHashMultiplier;
1436 mNumElements = o.mNumElements;
1438 mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;
1439 mInfoInc = o.mInfoInc;
1440 mInfoHashShift = o.mInfoHashShift;
1447 void swap(
Table& o) {
1448 ROBIN_HOOD_TRACE(
"%p",
this);
1449 using gaia::core::swap;
1455 ROBIN_HOOD_TRACE(
"%p",
this);
1462 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*
this);
1464 auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
1466 uint8_t
const z = 0;
1467 gaia::core::fill(mInfo, mInfo + calcNumBytesInfo(numElementsWithBuffer), z);
1468 mInfo[numElementsWithBuffer] = 1;
1470 mInfoInc = InitialInfoInc;
1471 mInfoHashShift = InitialInfoHashShift;
1476 ROBIN_HOOD_TRACE(
"%p",
this);
1481 bool operator==(
const Table& other)
const {
1482 ROBIN_HOOD_TRACE(
"%p",
this);
1483 if (other.size() != size()) {
1486 for (
auto const& otherEntry: other) {
1487 if (!has(otherEntry)) {
1495 bool operator!=(
const Table& other)
const {
1496 ROBIN_HOOD_TRACE(
"%p",
this);
1497 return !operator==(other);
1500 template <
typename Q = mapped_type>
1501 typename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](
const key_type& key) {
1502 ROBIN_HOOD_TRACE(
"%p",
this);
1503 auto idxAndState = insertKeyPrepareEmptySpot(key);
1504 switch (idxAndState.second) {
1505 case InsertionState::key_found:
1508 case InsertionState::new_node:
1509 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first]))
1510 Node(*
this, std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple());
1513 case InsertionState::overwrite_node:
1514 mKeyVals[idxAndState.first] =
1515 Node(*
this, std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple());
1518 case InsertionState::overflow_error:
1519 throwOverflowError();
1522 return mKeyVals[idxAndState.first].getSecond();
1525 template <
typename Q = mapped_type>
1526 typename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](key_type&& key) {
1527 ROBIN_HOOD_TRACE(
"%p",
this);
1528 auto idxAndState = insertKeyPrepareEmptySpot(key);
1529 switch (idxAndState.second) {
1530 case InsertionState::key_found:
1533 case InsertionState::new_node:
1534 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first]))
1535 Node(*
this, std::piecewise_construct, std::forward_as_tuple(GAIA_MOV(key)), std::forward_as_tuple());
1538 case InsertionState::overwrite_node:
1539 mKeyVals[idxAndState.first] =
1540 Node(*
this, std::piecewise_construct, std::forward_as_tuple(GAIA_MOV(key)), std::forward_as_tuple());
1543 case InsertionState::overflow_error:
1544 throwOverflowError();
1547 return mKeyVals[idxAndState.first].getSecond();
1550 template <
typename Iter>
1551 void insert(Iter first, Iter last) {
1552 for (; first != last; ++first) {
1554 insert(value_type(*first));
1558 void insert(std::initializer_list<value_type> ilist) {
1559 for (
auto&& vt: ilist) {
1560 insert(GAIA_MOV(vt));
1564 template <
typename... Args>
1565 std::pair<iterator, bool> emplace(Args&&... args) {
1566 ROBIN_HOOD_TRACE(
"%p",
this);
1567 Node n{*
this, GAIA_FWD(args)...};
1568 auto idxAndState = insertKeyPrepareEmptySpot(getFirstConst(n));
1569 switch (idxAndState.second) {
1570 case InsertionState::key_found:
1574 case InsertionState::new_node:
1575 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(*
this, GAIA_MOV(n));
1578 case InsertionState::overwrite_node:
1579 mKeyVals[idxAndState.first] = GAIA_MOV(n);
1582 case InsertionState::overflow_error:
1584 throwOverflowError();
1588 return std::make_pair(
1589 iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
1590 InsertionState::key_found != idxAndState.second);
1593 template <
typename... Args>
1594 iterator emplace_hint(const_iterator position, Args&&... args) {
1596 return emplace(GAIA_FWD(args)...).first;
1599 template <
typename... Args>
1600 std::pair<iterator, bool> try_emplace(
const key_type& key, Args&&... args) {
1601 return try_emplace_impl(key, GAIA_FWD(args)...);
1604 template <
typename... Args>
1605 std::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args) {
1606 return try_emplace_impl(GAIA_MOV(key), GAIA_FWD(args)...);
1609 template <
typename... Args>
1610 iterator try_emplace(const_iterator hint,
const key_type& key, Args&&... args) {
1612 return try_emplace_impl(key, GAIA_FWD(args)...).first;
1615 template <
typename... Args>
1616 iterator try_emplace(const_iterator hint, key_type&& key, Args&&... args) {
1618 return try_emplace_impl(GAIA_MOV(key), GAIA_FWD(args)...).first;
1621 template <
typename Mapped>
1622 std::pair<iterator, bool> insert_or_assign(
const key_type& key, Mapped&& obj) {
1623 return insertOrAssignImpl(key, GAIA_FWD(obj));
1626 template <
typename Mapped>
1627 std::pair<iterator, bool> insert_or_assign(key_type&& key, Mapped&& obj) {
1628 return insertOrAssignImpl(GAIA_MOV(key), GAIA_FWD(obj));
1631 template <
typename Mapped>
1632 iterator insert_or_assign(const_iterator hint,
const key_type& key, Mapped&& obj) {
1634 return insertOrAssignImpl(key, GAIA_FWD(obj)).first;
1637 template <
typename Mapped>
1638 iterator insert_or_assign(const_iterator hint, key_type&& key, Mapped&& obj) {
1640 return insertOrAssignImpl(GAIA_MOV(key), GAIA_FWD(obj)).first;
1643 std::pair<iterator, bool> insert(
const value_type& keyval) {
1644 ROBIN_HOOD_TRACE(
"%p",
this);
1645 return emplace(keyval);
1648 iterator insert(const_iterator hint,
const value_type& keyval) {
1650 return emplace(keyval).first;
1653 std::pair<iterator, bool> insert(value_type&& keyval) {
1654 return emplace(GAIA_MOV(keyval));
1657 iterator insert(const_iterator hint, value_type&& keyval) {
1659 return emplace(GAIA_MOV(keyval)).first;
1663 GAIA_NODISCARD
size_t count(
const key_type& key)
const {
1664 ROBIN_HOOD_TRACE(
"%p",
this);
1665 auto kv = mKeyVals + findIdx(key);
1666 if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1672 template <
typename OtherKey,
typename Self_ = Self>
1673 GAIA_NODISCARD
typename std::enable_if<Self_::is_transparent, size_t>::type count(
const OtherKey& key)
const {
1674 ROBIN_HOOD_TRACE(
"%p",
this);
1675 auto kv = mKeyVals + findIdx(key);
1676 if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1682 GAIA_NODISCARD
bool contains(
const key_type& key)
const {
1683 return 1U == count(key);
1686 template <
typename OtherKey,
typename Self_ = Self>
1687 GAIA_NODISCARD
typename std::enable_if<Self_::is_transparent, bool>::type contains(
const OtherKey& key)
const {
1688 return 1U == count(key);
1693 template <
typename Q = mapped_type>
1694 GAIA_NODISCARD
typename std::enable_if<!std::is_void<Q>::value, Q&>::type at(key_type
const& key) {
1695 ROBIN_HOOD_TRACE(
"%p",
this);
1696 auto kv = mKeyVals + findIdx(key);
1697 if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1698 doThrow<ROBIN_HOOD_STD_OUT_OF_RANGE>(
"key not found");
1700 return kv->getSecond();
1705 template <
typename Q = mapped_type>
1706 GAIA_NODISCARD
typename std::enable_if<!std::is_void<Q>::value, Q
const&>::type at(key_type
const& key)
const {
1707 ROBIN_HOOD_TRACE(
"%p",
this);
1708 auto kv = mKeyVals + findIdx(key);
1709 if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
1710 doThrow<ROBIN_HOOD_STD_OUT_OF_RANGE>(
"key not found");
1712 return kv->getSecond();
1715 GAIA_NODISCARD const_iterator find(
const key_type& key)
const {
1716 ROBIN_HOOD_TRACE(
"%p",
this);
1717 const size_t idx = findIdx(key);
1718 return const_iterator{mKeyVals + idx, mInfo + idx};
1721 template <
typename OtherKey>
1723 ROBIN_HOOD_TRACE(
"%p",
this);
1724 const size_t idx = findIdx(key);
1725 return const_iterator{mKeyVals + idx, mInfo + idx};
1728 template <
typename OtherKey,
typename Self_ = Self>
1729 GAIA_NODISCARD
typename std::enable_if<Self_::is_transparent, const_iterator>::type
1730 find(
const OtherKey& key)
const {
1731 ROBIN_HOOD_TRACE(
"%p",
this);
1732 const size_t idx = findIdx(key);
1733 return const_iterator{mKeyVals + idx, mInfo + idx};
1736 GAIA_NODISCARD iterator find(
const key_type& key) {
1737 ROBIN_HOOD_TRACE(
"%p",
this);
1738 const size_t idx = findIdx(key);
1739 return iterator{mKeyVals + idx, mInfo + idx};
1742 template <
typename OtherKey>
1744 ROBIN_HOOD_TRACE(
"%p",
this);
1745 const size_t idx = findIdx(key);
1746 return iterator{mKeyVals + idx, mInfo + idx};
1749 template <
typename OtherKey,
typename Self_ = Self>
1750 GAIA_NODISCARD
typename std::enable_if<Self_::is_transparent, iterator>::type find(
const OtherKey& key) {
1751 ROBIN_HOOD_TRACE(
"%p",
this);
1752 const size_t idx = findIdx(key);
1753 return iterator{mKeyVals + idx, mInfo + idx};
1756 GAIA_NODISCARD iterator begin() {
1757 ROBIN_HOOD_TRACE(
"%p",
this);
1761 return iterator(mKeyVals, mInfo, fast_forward_tag{});
1763 GAIA_NODISCARD const_iterator begin()
const {
1764 ROBIN_HOOD_TRACE(
"%p",
this);
1767 GAIA_NODISCARD const_iterator cbegin()
const {
1768 ROBIN_HOOD_TRACE(
"%p",
this);
1772 return const_iterator(mKeyVals, mInfo, fast_forward_tag{});
1775 GAIA_NODISCARD iterator end() {
1776 ROBIN_HOOD_TRACE(
"%p",
this);
1779 return iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo),
nullptr};
1781 GAIA_NODISCARD const_iterator end()
const {
1782 ROBIN_HOOD_TRACE(
"%p",
this);
1785 GAIA_NODISCARD const_iterator cend()
const {
1786 ROBIN_HOOD_TRACE(
"%p",
this);
1787 return const_iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo),
nullptr};
1790 iterator erase(const_iterator pos) {
1791 ROBIN_HOOD_TRACE(
"%p",
this);
1794 return erase(iterator{
const_cast<Node*
>(pos.mKeyVals),
const_cast<uint8_t*
>(pos.mInfo)});
1798 iterator erase(iterator pos) {
1799 ROBIN_HOOD_TRACE(
"%p",
this);
1801 auto const idx =
static_cast<size_t>(pos.mKeyVals - mKeyVals);
1815 size_t erase(
const key_type& key) {
1816 ROBIN_HOOD_TRACE(
"%p",
this);
1819 keyToIdx(key, &idx, &info);
1823 if (info == mInfo[idx] && WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
1829 }
while (info <= mInfo[idx]);
1837 void rehash(
size_t c) {
1844 void reserve(
size_t c) {
1852 ROBIN_HOOD_TRACE(
"%p",
this);
1853 auto newSize = InitialNumElements;
1854 while (calcMaxNumElementsAllowed(newSize) < mNumElements && newSize != 0) {
1857 if GAIA_UNLIKELY (newSize == 0) {
1858 throwOverflowError();
1861 ROBIN_HOOD_LOG(
"newSize > mMask + 1: %zu > %zu + 1", newSize, mMask);
1865 if (newSize < mMask + 1) {
1866 rehashPowerOfTwo(newSize,
true);
1870 constexpr uint32_t bytes()
const noexcept {
1871 if constexpr (is_map) {
1872 return sizeof(key_type) +
sizeof(value_type);
1874 return sizeof(key_type);
1878 template <
typename Serializer>
1879 void save(Serializer& s)
const {
1880 const auto cnt = (uint32_t)size();
1883 if constexpr (is_map) {
1884 for (
auto& p: *
this) {
1885 ::gaia::ser::save(s, p.first);
1886 ::gaia::ser::save(s, p.second);
1889 for (
auto& p: *
this) {
1890 ::gaia::ser::save(s, p);
1895 template <
typename Serializer>
1896 void load(Serializer& s) {
1903 if constexpr (is_map) {
1904 for (uint32_t i = 0; i < cnt; ++i) {
1905 typename Table::key_type key;
1906 typename Table::mapped_type value;
1907 ::gaia::ser::load(s, key);
1908 ::gaia::ser::load(s, value);
1909 insert({key, value});
1912 for (uint32_t i = 0; i < cnt; ++i) {
1913 typename Table::key_type key;
1914 ::gaia::ser::load(s, key);
1920 GAIA_NODISCARD size_type capacity()
const noexcept {
1921 return calcMaxNumElementsAllowed(mMask);
1924 GAIA_NODISCARD size_type size()
const noexcept {
1925 ROBIN_HOOD_TRACE(
"%p",
this);
1926 return mNumElements;
1929 GAIA_NODISCARD size_type max_size()
const noexcept {
1930 ROBIN_HOOD_TRACE(
"%p",
this);
1931 return static_cast<size_type
>(-1);
1934 GAIA_NODISCARD
bool empty()
const noexcept {
1935 ROBIN_HOOD_TRACE(
"%p",
this);
1936 return 0 == mNumElements;
1939 GAIA_NODISCARD
float max_load_factor()
const noexcept {
1940 ROBIN_HOOD_TRACE(
"%p",
this);
1941 return MaxLoadFactor100 / 100.0f;
1945 GAIA_NODISCARD
float load_factor()
const noexcept {
1946 ROBIN_HOOD_TRACE(
"%p",
this);
1947 return static_cast<float>(size()) /
static_cast<float>(mMask + 1);
1950 GAIA_NODISCARD
size_t mask()
const noexcept {
1951 ROBIN_HOOD_TRACE(
"%p",
this);
1955 GAIA_NODISCARD
size_t calcMaxNumElementsAllowed(
size_t maxElements)
const noexcept {
1956 if GAIA_LIKELY (maxElements <= (
size_t(-1) / 100)) {
1957 return maxElements * MaxLoadFactor100 / 100;
1961 return (maxElements / 100) * MaxLoadFactor100;
1964 GAIA_NODISCARD
size_t calcNumBytesInfo(
size_t numElements)
const noexcept {
1967 return numElements +
sizeof(uint64_t);
1970 GAIA_NODISCARD
size_t calcNumElementsWithBuffer(
size_t numElements)
const noexcept {
1971 auto maxNumElementsAllowed = calcMaxNumElementsAllowed(numElements);
1972 return numElements + gaia::core::get_min(maxNumElementsAllowed, (
static_cast<size_t>(0xFF)));
1976 GAIA_NODISCARD
size_t calcNumBytesTotal(
size_t numElements)
const {
1977#if ROBIN_HOOD(BITNESS) == 64
1978 return (numElements *
sizeof(Node)) + calcNumBytesInfo(numElements);
1981 auto const ne =
static_cast<uint64_t
>(numElements);
1982 auto const s =
static_cast<uint64_t
>(
sizeof(Node));
1983 auto const infos =
static_cast<uint64_t
>(calcNumBytesInfo(numElements));
1985 auto const total64 = ne * s + infos;
1986 auto const total =
static_cast<size_t>(total64);
1988 if GAIA_UNLIKELY (
static_cast<uint64_t
>(total) != total64) {
1989 throwOverflowError();
1996 template <
typename Q = mapped_type>
1997 GAIA_NODISCARD
typename std::enable_if<!std::is_void<Q>::value,
bool>::type has(
const value_type& e)
const {
1998 ROBIN_HOOD_TRACE(
"%p",
this);
1999 auto it = find(e.first);
2000 return it != end() && it->second == e.second;
2003 template <
typename Q = mapped_type>
2004 GAIA_NODISCARD
typename std::enable_if<std::is_void<Q>::value,
bool>::type has(
const value_type& e)
const {
2005 ROBIN_HOOD_TRACE(
"%p",
this);
2006 return find(e) != end();
2009 void reserve(
size_t c,
bool forceRehash) {
2010 ROBIN_HOOD_TRACE(
"%p",
this);
2011 auto const minElementsAllowed = gaia::core::get_max(c, mNumElements);
2012 auto newSize = InitialNumElements;
2013 while (calcMaxNumElementsAllowed(newSize) < minElementsAllowed && newSize != 0) {
2016 if GAIA_UNLIKELY (newSize == 0) {
2017 throwOverflowError();
2020 ROBIN_HOOD_LOG(
"newSize > mMask + 1: %zu > %zu + 1", newSize, mMask);
2024 if (forceRehash || newSize > mMask + 1) {
2025 rehashPowerOfTwo(newSize,
false);
2032 void rehashPowerOfTwo(
size_t numBuckets,
bool forceFree) {
2033 ROBIN_HOOD_TRACE(
"%p",
this);
2035 Node*
const oldKeyVals = mKeyVals;
2036 uint8_t
const*
const oldInfo = mInfo;
2038 const size_t oldMaxElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
2041 initData(numBuckets);
2042 if (oldMaxElementsWithBuffer > 1) {
2043 for (
size_t i = 0; i < oldMaxElementsWithBuffer; ++i) {
2044 if (oldInfo[i] != 0) {
2047 insert_move(GAIA_MOV(oldKeyVals[i]));
2049 oldKeyVals[i].~Node();
2056 if (oldKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
2059 gaia::mem::mem_free(oldKeyVals);
2061 DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer));
2067 GAIA_NOINLINE
void throwOverflowError()
const {
2068#if ROBIN_HOOD(HAS_EXCEPTIONS)
2069 throw std::overflow_error(
"robin_hood::map overflow");
2075 template <
typename OtherKey,
typename... Args>
2076 std::pair<iterator, bool> try_emplace_impl(OtherKey&& key, Args&&... args) {
2077 ROBIN_HOOD_TRACE(
"%p",
this);
2078 auto idxAndState = insertKeyPrepareEmptySpot(key);
2079 switch (idxAndState.second) {
2080 case InsertionState::key_found:
2083 case InsertionState::new_node:
2084 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(
2085 *
this, std::piecewise_construct, std::forward_as_tuple(GAIA_FWD(key)),
2086 std::forward_as_tuple(GAIA_FWD(args)...));
2089 case InsertionState::overwrite_node:
2090 mKeyVals[idxAndState.first] = Node(
2091 *
this, std::piecewise_construct, std::forward_as_tuple(GAIA_FWD(key)),
2092 std::forward_as_tuple(GAIA_FWD(args)...));
2095 case InsertionState::overflow_error:
2096 throwOverflowError();
2100 return std::make_pair(
2101 iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
2102 InsertionState::key_found != idxAndState.second);
2105 template <
typename OtherKey,
typename Mapped>
2106 std::pair<iterator, bool> insertOrAssignImpl(OtherKey&& key, Mapped&& obj) {
2107 ROBIN_HOOD_TRACE(
"%p",
this);
2108 auto idxAndState = insertKeyPrepareEmptySpot(key);
2109 switch (idxAndState.second) {
2110 case InsertionState::key_found:
2111 mKeyVals[idxAndState.first].getSecond() = GAIA_FWD(obj);
2114 case InsertionState::new_node:
2115 ::new (
static_cast<void*
>(&mKeyVals[idxAndState.first])) Node(
2116 *
this, std::piecewise_construct, std::forward_as_tuple(GAIA_FWD(key)),
2117 std::forward_as_tuple(GAIA_FWD(obj)));
2120 case InsertionState::overwrite_node:
2121 mKeyVals[idxAndState.first] = Node(
2122 *
this, std::piecewise_construct, std::forward_as_tuple(GAIA_FWD(key)),
2123 std::forward_as_tuple(GAIA_FWD(obj)));
2126 case InsertionState::overflow_error:
2127 throwOverflowError();
2131 return std::make_pair(
2132 iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
2133 InsertionState::key_found != idxAndState.second);
2136 void initData(
size_t max_elements) {
2138 mMask = max_elements - 1;
2139 mMaxNumElementsAllowed = calcMaxNumElementsAllowed(max_elements);
2141 auto const numElementsWithBuffer = calcNumElementsWithBuffer(max_elements);
2144 auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
2146 ROBIN_HOOD_LOG(
"gaia::mem::mem_alloc %zu = calcNumBytesTotal(%zu)", numBytesTotal, numElementsWithBuffer);
2147 mKeyVals =
reinterpret_cast<Node*
>(detail::assertNotNull<std::bad_alloc>(gaia::mem::mem_alloc(numBytesTotal)));
2148 mInfo =
reinterpret_cast<uint8_t*
>(mKeyVals + numElementsWithBuffer);
2149 std::memset(mInfo, 0, numBytesTotal - (numElementsWithBuffer *
sizeof(Node)));
2152 mInfo[numElementsWithBuffer] = 1;
2154 mInfoInc = InitialInfoInc;
2155 mInfoHashShift = InitialInfoHashShift;
2158 enum class InsertionState { overflow_error, key_found, new_node, overwrite_node };
2163 template <
typename OtherKey>
2164 std::pair<size_t, InsertionState> insertKeyPrepareEmptySpot(OtherKey&& key) {
2165 for (
int i = 0; i < 256; ++i) {
2168 keyToIdx(key, &idx, &info);
2169 nextWhileLess(&info, &idx);
2172 while (info == mInfo[idx]) {
2173 if (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
2176 return std::make_pair(idx, InsertionState::key_found);
2182 if GAIA_UNLIKELY (mNumElements >= mMaxNumElementsAllowed) {
2183 if (!increase_size()) {
2184 return std::make_pair(
size_t(0), InsertionState::overflow_error);
2190 auto const insertion_idx = idx;
2191 auto const insertion_info = info;
2192 if GAIA_UNLIKELY (insertion_info + mInfoInc > 0xFF) {
2193 mMaxNumElementsAllowed = 0;
2197 while (0 != mInfo[idx]) {
2201 if (idx != insertion_idx) {
2202 shiftUp(idx, insertion_idx);
2205 mInfo[insertion_idx] =
static_cast<uint8_t
>(insertion_info);
2207 return std::make_pair(
2208 insertion_idx, idx == insertion_idx ? InsertionState::new_node : InsertionState::overwrite_node);
2212 return std::make_pair(
size_t(0), InsertionState::overflow_error);
2215 bool try_increase_info() {
2217 "mInfoInc %zu, numElements=%zu, maxNumElementsAllowed=%zu", mInfoInc, mNumElements,
2218 calcMaxNumElementsAllowed(mMask + 1));
2219 if (mInfoInc <= 2) {
2224 mInfoInc =
static_cast<uint8_t
>(mInfoInc >> 1U);
2229 auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
2231 for (
size_t i = 0; i < numElementsWithBuffer; i += 8) {
2232 auto val = unaligned_load<uint64_t>(mInfo + i);
2233 val = (val >> 1U) & UINT64_C(0x7f7f7f7f7f7f7f7f);
2234 memcpy(mInfo + i, &val,
sizeof(val));
2237 mInfo[numElementsWithBuffer] = 1;
2239 mMaxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
2244 bool increase_size() {
2247 initData(InitialNumElements);
2251 auto const maxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
2252 if (mNumElements < maxNumElementsAllowed && try_increase_info()) {
2257 "mNumElements=%zu, maxNumElementsAllowed=%zu, load=%f", mNumElements, maxNumElementsAllowed,
2258 (
static_cast<double>(mNumElements) * 100.0 / (
static_cast<double>(mMask) + 1)))
2260 if (mNumElements * 2 < calcMaxNumElementsAllowed(mMask + 1)) {
2264 nextHashMultiplier();
2265 rehashPowerOfTwo(mMask + 1,
true);
2268 rehashPowerOfTwo((mMask + 1) * 2,
false);
2273 void nextHashMultiplier() {
2276 mHashMultiplier += UINT64_C(0xc4ceb9fe1a85ec54);
2285 Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodesDoNotDeallocate(*
this);
2291 if (mKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
2292 ROBIN_HOOD_LOG(
"gaia::mem::mem_free");
2293 gaia::mem::mem_free(mKeyVals);
2297 void init()
noexcept {
2298 mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);
2299 mInfo =
reinterpret_cast<uint8_t*
>(&mMask);
2302 mMaxNumElementsAllowed = 0;
2303 mInfoInc = InitialInfoInc;
2304 mInfoHashShift = InitialInfoHashShift;
2308 uint64_t mHashMultiplier = UINT64_C(0xc4ceb9fe1a85ec53);
2309 Node* mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);
2310 uint8_t* mInfo =
reinterpret_cast<uint8_t*
>(&mMask);
2311 size_t mNumElements = 0;
2313 size_t mMaxNumElementsAllowed = 0;
2314 InfoType mInfoInc = InitialInfoInc;
2315 InfoType mInfoHashShift = InitialInfoHashShift;