File indexing completed on 2026-09-28 09:20:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef NCollection_FlatDataMap_HeaderFile
0015 #define NCollection_FlatDataMap_HeaderFile
0016
0017 #include <Standard.hxx>
0018 #include <Standard_OutOfRange.hxx>
0019 #include <Standard_NoSuchObject.hxx>
0020 #include <NCollection_DefaultHasher.hxx>
0021 #include <NCollection_ItemsView.hxx>
0022
0023 #include <functional>
0024 #include <new>
0025 #include <optional>
0026 #include <type_traits>
0027 #include <utility>
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070 template <class TheKeyType, class TheItemType, class Hasher = NCollection_DefaultHasher<TheKeyType>>
0071 class NCollection_FlatDataMap
0072 {
0073 public:
0074
0075 using key_type = TheKeyType;
0076
0077
0078 using value_type = TheItemType;
0079
0080 private:
0081
0082 static constexpr size_t THE_DEFAULT_CAPACITY = 8;
0083
0084 static constexpr size_t THE_MAX_LOAD_NUMERATOR = 13;
0085
0086 static constexpr size_t THE_MAX_LOAD_DENOMINATOR = 16;
0087
0088
0089
0090 #ifdef _MSC_VER
0091 #pragma warning(push)
0092 #pragma warning(disable : 4324)
0093 #endif
0094 struct Slot
0095 {
0096 size_t myHash;
0097
0098 size_t myProbeDistancePlus1;
0099 alignas(TheKeyType) char myKeyStorage[sizeof(TheKeyType)];
0100 alignas(TheItemType) char myItemStorage[sizeof(TheItemType)];
0101
0102 Slot() noexcept
0103 : myHash(0),
0104 myProbeDistancePlus1(0)
0105 {
0106 }
0107
0108 TheKeyType& Key() noexcept { return *reinterpret_cast<TheKeyType*>(myKeyStorage); }
0109
0110 const TheKeyType& Key() const noexcept
0111 {
0112 return *reinterpret_cast<const TheKeyType*>(myKeyStorage);
0113 }
0114
0115 TheItemType& Item() noexcept { return *reinterpret_cast<TheItemType*>(myItemStorage); }
0116
0117 const TheItemType& Item() const noexcept
0118 {
0119 return *reinterpret_cast<const TheItemType*>(myItemStorage);
0120 }
0121
0122 bool IsEmpty() const noexcept { return myProbeDistancePlus1 == 0; }
0123
0124 bool IsUsed() const noexcept { return myProbeDistancePlus1 != 0; }
0125
0126 size_t ProbeDistance() const noexcept { return myProbeDistancePlus1 - 1; }
0127
0128 void SetProbeDistance(const size_t theProbeDistance) noexcept
0129 {
0130 myProbeDistancePlus1 = theProbeDistance + 1;
0131 }
0132
0133 void SetEmpty() noexcept { myProbeDistancePlus1 = 0; }
0134 };
0135 #ifdef _MSC_VER
0136 #pragma warning(pop)
0137 #endif
0138
0139 public:
0140
0141
0142
0143 class Iterator
0144 {
0145 public:
0146
0147 Iterator() noexcept
0148 : mySlots(nullptr),
0149 myCapacity(0),
0150 myIndex(0)
0151 {
0152 }
0153
0154
0155 Iterator(const NCollection_FlatDataMap& theMap) noexcept
0156 : mySlots(theMap.mySlots),
0157 myCapacity(theMap.myCapacity),
0158 myIndex(0)
0159 {
0160
0161 while (myIndex < myCapacity && !mySlots[myIndex].IsUsed())
0162 {
0163 ++myIndex;
0164 }
0165 }
0166
0167
0168 bool More() const noexcept { return myIndex < myCapacity; }
0169
0170
0171 void Next() noexcept
0172 {
0173 ++myIndex;
0174 while (myIndex < myCapacity && !mySlots[myIndex].IsUsed())
0175 {
0176 ++myIndex;
0177 }
0178 }
0179
0180
0181 const TheKeyType& Key() const
0182 {
0183 Standard_OutOfRange_Raise_if(!More(), "NCollection_FlatDataMap::Iterator::Key");
0184 return mySlots[myIndex].Key();
0185 }
0186
0187
0188 const TheItemType& Value() const
0189 {
0190 Standard_OutOfRange_Raise_if(!More(), "NCollection_FlatDataMap::Iterator::Value");
0191 return mySlots[myIndex].Item();
0192 }
0193
0194
0195 TheItemType& ChangeValue() const
0196 {
0197 Standard_OutOfRange_Raise_if(!More(), "NCollection_FlatDataMap::Iterator::ChangeValue");
0198 return const_cast<Slot*>(mySlots)[myIndex].Item();
0199 }
0200
0201
0202 bool IsEqual(const Iterator& theOther) const noexcept
0203 {
0204 return mySlots == theOther.mySlots && myIndex == theOther.myIndex;
0205 }
0206
0207 private:
0208 const Slot* mySlots;
0209 size_t myCapacity;
0210 size_t myIndex;
0211 };
0212
0213 public:
0214
0215
0216
0217 NCollection_FlatDataMap()
0218 : mySlots(nullptr),
0219 myCapacity(0),
0220 mySize(0)
0221 {
0222 }
0223
0224
0225
0226 explicit NCollection_FlatDataMap(const size_t theNbBuckets)
0227 : mySlots(nullptr),
0228 myCapacity(0),
0229 mySize(0)
0230 {
0231 if (theNbBuckets > 0)
0232 {
0233 reserve(static_cast<size_t>(theNbBuckets));
0234 }
0235 }
0236
0237
0238
0239
0240 explicit NCollection_FlatDataMap(const Hasher& theHasher, const size_t theNbBuckets = 0)
0241 : mySlots(nullptr),
0242 myCapacity(0),
0243 mySize(0),
0244 myHasher(theHasher)
0245 {
0246 if (theNbBuckets > 0)
0247 {
0248 reserve(static_cast<size_t>(theNbBuckets));
0249 }
0250 }
0251
0252
0253
0254
0255 explicit NCollection_FlatDataMap(Hasher&& theHasher, const size_t theNbBuckets = 0)
0256 : mySlots(nullptr),
0257 myCapacity(0),
0258 mySize(0),
0259 myHasher(std::move(theHasher))
0260 {
0261 if (theNbBuckets > 0)
0262 {
0263 reserve(static_cast<size_t>(theNbBuckets));
0264 }
0265 }
0266
0267
0268 NCollection_FlatDataMap(const NCollection_FlatDataMap& theOther)
0269 : mySlots(nullptr),
0270 myCapacity(0),
0271 mySize(0),
0272 myHasher(theOther.myHasher)
0273 {
0274 if (theOther.mySize > 0)
0275 {
0276
0277 mySlots = static_cast<Slot*>(Standard::Allocate(theOther.myCapacity * sizeof(Slot)));
0278 for (size_t i = 0; i < theOther.myCapacity; ++i)
0279 {
0280 new (&mySlots[i]) Slot();
0281 }
0282 myCapacity = theOther.myCapacity;
0283
0284 for (size_t i = 0; i < theOther.myCapacity; ++i)
0285 {
0286 if (theOther.mySlots[i].IsUsed())
0287 {
0288 new (&mySlots[i].Key()) TheKeyType(theOther.mySlots[i].Key());
0289 new (&mySlots[i].Item()) TheItemType(theOther.mySlots[i].Item());
0290 mySlots[i].myHash = theOther.mySlots[i].myHash;
0291 mySlots[i].myProbeDistancePlus1 = theOther.mySlots[i].myProbeDistancePlus1;
0292 }
0293 }
0294 mySize = theOther.mySize;
0295 }
0296 }
0297
0298
0299 NCollection_FlatDataMap(NCollection_FlatDataMap&& theOther) noexcept
0300 : mySlots(theOther.mySlots),
0301 myCapacity(theOther.myCapacity),
0302 mySize(theOther.mySize),
0303 myHasher(std::move(theOther.myHasher))
0304 {
0305 theOther.mySlots = nullptr;
0306 theOther.myCapacity = 0;
0307 theOther.mySize = 0;
0308 }
0309
0310
0311 ~NCollection_FlatDataMap() { Clear(true); }
0312
0313
0314 NCollection_FlatDataMap& operator=(const NCollection_FlatDataMap& theOther)
0315 {
0316 if (this != &theOther)
0317 {
0318 Clear(true);
0319 myHasher = theOther.myHasher;
0320 if (theOther.mySize > 0)
0321 {
0322
0323 mySlots = static_cast<Slot*>(Standard::Allocate(theOther.myCapacity * sizeof(Slot)));
0324 for (size_t i = 0; i < theOther.myCapacity; ++i)
0325 {
0326 new (&mySlots[i]) Slot();
0327 }
0328 myCapacity = theOther.myCapacity;
0329
0330 for (size_t i = 0; i < theOther.myCapacity; ++i)
0331 {
0332 if (theOther.mySlots[i].IsUsed())
0333 {
0334 new (&mySlots[i].Key()) TheKeyType(theOther.mySlots[i].Key());
0335 new (&mySlots[i].Item()) TheItemType(theOther.mySlots[i].Item());
0336 mySlots[i].myHash = theOther.mySlots[i].myHash;
0337 mySlots[i].myProbeDistancePlus1 = theOther.mySlots[i].myProbeDistancePlus1;
0338 }
0339 }
0340 mySize = theOther.mySize;
0341 }
0342 }
0343 return *this;
0344 }
0345
0346
0347 NCollection_FlatDataMap& operator=(NCollection_FlatDataMap&& theOther) noexcept
0348 {
0349 if (this != &theOther)
0350 {
0351 Clear(true);
0352 mySlots = theOther.mySlots;
0353 myCapacity = theOther.myCapacity;
0354 mySize = theOther.mySize;
0355 myHasher = std::move(theOther.myHasher);
0356 theOther.mySlots = nullptr;
0357 theOther.myCapacity = 0;
0358 theOther.mySize = 0;
0359 }
0360 return *this;
0361 }
0362
0363 public:
0364
0365
0366
0367 size_t Size() const noexcept { return mySize; }
0368
0369
0370 int Extent() const noexcept { return static_cast<int>(mySize); }
0371
0372
0373 bool IsEmpty() const noexcept { return mySize == 0; }
0374
0375
0376 size_t Capacity() const noexcept { return myCapacity; }
0377
0378
0379 bool IsBound(const TheKeyType& theKey) const
0380 {
0381 if (mySize == 0)
0382 return false;
0383 size_t anIndex = 0;
0384 return findSlotIndex(theKey, anIndex);
0385 }
0386
0387
0388
0389 std::optional<
0390 std::pair<std::reference_wrapper<const TheKeyType>, std::reference_wrapper<const TheItemType>>>
0391 Contained(const TheKeyType& theKey) const
0392 {
0393 if (mySize == 0)
0394 return std::nullopt;
0395 size_t aIdx = 0;
0396 if (!findSlotIndex(theKey, aIdx))
0397 return std::nullopt;
0398 return std::make_pair(std::cref(mySlots[aIdx].Key()), std::cref(mySlots[aIdx].Item()));
0399 }
0400
0401
0402
0403 std::optional<
0404 std::pair<std::reference_wrapper<const TheKeyType>, std::reference_wrapper<TheItemType>>>
0405 Contained(const TheKeyType& theKey)
0406 {
0407 if (mySize == 0)
0408 return std::nullopt;
0409 size_t aIdx = 0;
0410 if (!findSlotIndex(theKey, aIdx))
0411 return std::nullopt;
0412 return std::make_pair(std::cref(mySlots[aIdx].Key()), std::ref(mySlots[aIdx].Item()));
0413 }
0414
0415
0416 const TheItemType* Seek(const TheKeyType& theKey) const
0417 {
0418 if (mySize == 0)
0419 return nullptr;
0420 size_t aFoundIndex = 0;
0421 if (findSlotIndex(theKey, aFoundIndex))
0422 {
0423 return &mySlots[aFoundIndex].Item();
0424 }
0425 return nullptr;
0426 }
0427
0428
0429 TheItemType* ChangeSeek(const TheKeyType& theKey)
0430 {
0431 if (mySize == 0)
0432 return nullptr;
0433 size_t aFoundIndex = 0;
0434 if (findSlotIndex(theKey, aFoundIndex))
0435 {
0436 return &mySlots[aFoundIndex].Item();
0437 }
0438 return nullptr;
0439 }
0440
0441
0442 const TheItemType& Find(const TheKeyType& theKey) const
0443 {
0444 const TheItemType* aPtr = Seek(theKey);
0445 if (aPtr == nullptr)
0446 {
0447 throw Standard_NoSuchObject("NCollection_FlatDataMap::Find");
0448 }
0449 return *aPtr;
0450 }
0451
0452
0453 TheItemType& ChangeFind(const TheKeyType& theKey)
0454 {
0455 TheItemType* aPtr = ChangeSeek(theKey);
0456 if (aPtr == nullptr)
0457 {
0458 throw Standard_NoSuchObject("NCollection_FlatDataMap::ChangeFind");
0459 }
0460 return *aPtr;
0461 }
0462
0463
0464 const TheItemType& operator()(const TheKeyType& theKey) const { return Find(theKey); }
0465
0466
0467 TheItemType& operator()(const TheKeyType& theKey) { return ChangeFind(theKey); }
0468
0469 public:
0470
0471
0472
0473
0474 bool Bind(const TheKeyType& theKey, const TheItemType& theItem)
0475 {
0476 ensureCapacity();
0477 return insertImpl(theKey, theItem);
0478 }
0479
0480
0481 bool Bind(const TheKeyType& theKey, TheItemType&& theItem)
0482 {
0483 ensureCapacity();
0484 return insertImpl(theKey, std::forward<TheItemType>(theItem));
0485 }
0486
0487
0488 bool Bind(TheKeyType&& theKey, const TheItemType& theItem)
0489 {
0490 ensureCapacity();
0491 return insertImpl(std::forward<TheKeyType>(theKey), theItem);
0492 }
0493
0494
0495 bool Bind(TheKeyType&& theKey, TheItemType&& theItem)
0496 {
0497 ensureCapacity();
0498 return insertImpl(std::forward<TheKeyType>(theKey), std::forward<TheItemType>(theItem));
0499 }
0500
0501
0502
0503
0504
0505 bool TryBind(const TheKeyType& theKey, const TheItemType& theItem)
0506 {
0507 ensureCapacity();
0508 return tryInsertImpl(theKey, theItem);
0509 }
0510
0511
0512 bool TryBind(const TheKeyType& theKey, TheItemType&& theItem)
0513 {
0514 ensureCapacity();
0515 return tryInsertImpl(theKey, std::move(theItem));
0516 }
0517
0518
0519 bool TryBind(TheKeyType&& theKey, const TheItemType& theItem)
0520 {
0521 ensureCapacity();
0522 return tryInsertImpl(std::move(theKey), theItem);
0523 }
0524
0525
0526 bool TryBind(TheKeyType&& theKey, TheItemType&& theItem)
0527 {
0528 ensureCapacity();
0529 return tryInsertImpl(std::move(theKey), std::move(theItem));
0530 }
0531
0532
0533
0534
0535
0536 TheItemType& Bound(const TheKeyType& theKey, const TheItemType& theItem)
0537 {
0538 ensureCapacity();
0539 return insertRefImpl(theKey, theItem, std::false_type{});
0540 }
0541
0542
0543 TheItemType& Bound(const TheKeyType& theKey, TheItemType&& theItem)
0544 {
0545 ensureCapacity();
0546 return insertRefImpl(theKey, std::move(theItem), std::false_type{});
0547 }
0548
0549
0550 TheItemType& Bound(TheKeyType&& theKey, const TheItemType& theItem)
0551 {
0552 ensureCapacity();
0553 return insertRefImpl(std::move(theKey), theItem, std::false_type{});
0554 }
0555
0556
0557 TheItemType& Bound(TheKeyType&& theKey, TheItemType&& theItem)
0558 {
0559 ensureCapacity();
0560 return insertRefImpl(std::move(theKey), std::move(theItem), std::false_type{});
0561 }
0562
0563
0564
0565
0566
0567 TheItemType& TryBound(const TheKeyType& theKey, const TheItemType& theItem)
0568 {
0569 ensureCapacity();
0570 return insertRefImpl(theKey, theItem, std::true_type{});
0571 }
0572
0573
0574 TheItemType& TryBound(const TheKeyType& theKey, TheItemType&& theItem)
0575 {
0576 ensureCapacity();
0577 return insertRefImpl(theKey, std::move(theItem), std::true_type{});
0578 }
0579
0580
0581 TheItemType& TryBound(TheKeyType&& theKey, const TheItemType& theItem)
0582 {
0583 ensureCapacity();
0584 return insertRefImpl(std::move(theKey), theItem, std::true_type{});
0585 }
0586
0587
0588 TheItemType& TryBound(TheKeyType&& theKey, TheItemType&& theItem)
0589 {
0590 ensureCapacity();
0591 return insertRefImpl(std::move(theKey), std::move(theItem), std::true_type{});
0592 }
0593
0594
0595
0596
0597
0598 template <typename K, typename... Args>
0599 bool Emplace(K&& theKey, Args&&... theArgs)
0600 {
0601 ensureCapacity();
0602 return emplaceImpl(std::forward<K>(theKey), std::false_type{}, std::forward<Args>(theArgs)...);
0603 }
0604
0605
0606
0607
0608
0609 template <typename K, typename... Args>
0610 TheItemType& Emplaced(K&& theKey, Args&&... theArgs)
0611 {
0612 ensureCapacity();
0613 return emplacedImpl(std::forward<K>(theKey), std::false_type{}, std::forward<Args>(theArgs)...);
0614 }
0615
0616
0617
0618
0619
0620 template <typename K, typename... Args>
0621 bool TryEmplace(K&& theKey, Args&&... theArgs)
0622 {
0623 ensureCapacity();
0624 return emplaceImpl(std::forward<K>(theKey), std::true_type{}, std::forward<Args>(theArgs)...);
0625 }
0626
0627
0628
0629
0630
0631 template <typename K, typename... Args>
0632 TheItemType& TryEmplaced(K&& theKey, Args&&... theArgs)
0633 {
0634 ensureCapacity();
0635 return emplacedImpl(std::forward<K>(theKey), std::true_type{}, std::forward<Args>(theArgs)...);
0636 }
0637
0638
0639
0640 bool UnBind(const TheKeyType& theKey)
0641 {
0642 if (mySize == 0)
0643 return false;
0644
0645 size_t aFoundIndex = 0;
0646 if (!findSlotIndex(theKey, aFoundIndex))
0647 {
0648 return false;
0649 }
0650
0651 const size_t aIndex = aFoundIndex;
0652
0653 mySlots[aIndex].Key().~TheKeyType();
0654 mySlots[aIndex].Item().~TheItemType();
0655 mySlots[aIndex].SetEmpty();
0656 --mySize;
0657
0658 backwardShiftDelete(aIndex);
0659
0660 return true;
0661 }
0662
0663
0664
0665 void Clear(bool doReleaseMemory = false)
0666 {
0667 if (mySlots != nullptr)
0668 {
0669 for (size_t i = 0; i < myCapacity; ++i)
0670 {
0671 if (mySlots[i].IsUsed())
0672 {
0673 mySlots[i].Key().~TheKeyType();
0674 mySlots[i].Item().~TheItemType();
0675 mySlots[i].SetEmpty();
0676 }
0677 }
0678 mySize = 0;
0679
0680 if (doReleaseMemory)
0681 {
0682 Standard::Free(mySlots);
0683 mySlots = nullptr;
0684 myCapacity = 0;
0685 }
0686 }
0687 }
0688
0689
0690 void Exchange(NCollection_FlatDataMap& theOther) noexcept
0691 {
0692 std::swap(mySlots, theOther.mySlots);
0693 std::swap(myCapacity, theOther.myCapacity);
0694 std::swap(mySize, theOther.mySize);
0695 std::swap(myHasher, theOther.myHasher);
0696 }
0697
0698
0699 const Hasher& GetHasher() const noexcept { return myHasher; }
0700
0701
0702 void reserve(size_t theN)
0703 {
0704 const size_t aMinCapacity =
0705 (theN * THE_MAX_LOAD_DENOMINATOR + THE_MAX_LOAD_NUMERATOR - 1) / THE_MAX_LOAD_NUMERATOR;
0706 size_t aNewCapacity = nextPowerOf2(aMinCapacity);
0707 if (aNewCapacity > myCapacity)
0708 {
0709 rehash(aNewCapacity);
0710 }
0711 }
0712
0713
0714 void Reserve(const size_t theN) { reserve(theN); }
0715
0716 public:
0717
0718
0719
0720 Iterator begin() const noexcept { return Iterator(*this); }
0721
0722
0723 Iterator end() const noexcept { return Iterator(); }
0724
0725
0726 Iterator cbegin() const noexcept { return Iterator(*this); }
0727
0728
0729 Iterator cend() const noexcept { return Iterator(); }
0730
0731 public:
0732
0733
0734
0735
0736 using KeyValueRef = NCollection_ItemsView::KeyValueRef<TheKeyType, TheItemType, false>;
0737
0738
0739 using ConstKeyValueRef = NCollection_ItemsView::KeyValueRef<TheKeyType, TheItemType, true>;
0740
0741 private:
0742
0743 struct ItemsExtractor
0744 {
0745 static KeyValueRef Extract(const Iterator& theIter)
0746 {
0747 return {theIter.Key(), theIter.ChangeValue()};
0748 }
0749 };
0750
0751
0752 struct ConstItemsExtractor
0753 {
0754 static ConstKeyValueRef Extract(const Iterator& theIter)
0755 {
0756 return {theIter.Key(), theIter.Value()};
0757 }
0758 };
0759
0760 public:
0761
0762 using ItemsView =
0763 NCollection_ItemsView::View<NCollection_FlatDataMap, KeyValueRef, ItemsExtractor, false>;
0764
0765
0766 using ConstItemsView = NCollection_ItemsView::
0767 View<NCollection_FlatDataMap, ConstKeyValueRef, ConstItemsExtractor, true>;
0768
0769
0770
0771 ItemsView Items() { return ItemsView(*this); }
0772
0773
0774
0775 ConstItemsView Items() const { return ConstItemsView(*this); }
0776
0777 private:
0778
0779
0780
0781 static size_t nextPowerOf2(size_t n) noexcept
0782 {
0783 if (n == 0)
0784 return THE_DEFAULT_CAPACITY;
0785 --n;
0786 n |= n >> 1;
0787 n |= n >> 2;
0788 n |= n >> 4;
0789 n |= n >> 8;
0790 n |= n >> 16;
0791 if constexpr (sizeof(size_t) > 4)
0792 {
0793 n |= n >> 32;
0794 }
0795 return n + 1;
0796 }
0797
0798
0799 void ensureCapacity()
0800 {
0801
0802 if (myCapacity == 0
0803 || (mySize + 1) * THE_MAX_LOAD_DENOMINATOR > myCapacity * THE_MAX_LOAD_NUMERATOR)
0804 {
0805 size_t aNewCapacity = myCapacity == 0 ? THE_DEFAULT_CAPACITY : myCapacity * 2;
0806 rehash(aNewCapacity);
0807 }
0808 }
0809
0810
0811 void rehash(size_t theNewCapacity)
0812 {
0813 Slot* aOldSlots = mySlots;
0814 size_t aOldCapacity = myCapacity;
0815
0816
0817 mySlots = static_cast<Slot*>(Standard::Allocate(theNewCapacity * sizeof(Slot)));
0818 for (size_t i = 0; i < theNewCapacity; ++i)
0819 {
0820 new (&mySlots[i]) Slot();
0821 }
0822 myCapacity = theNewCapacity;
0823 mySize = 0;
0824
0825 if (aOldSlots != nullptr)
0826 {
0827 for (size_t i = 0; i < aOldCapacity; ++i)
0828 {
0829 if (aOldSlots[i].IsUsed())
0830 {
0831 insertRehashedImpl(std::move(aOldSlots[i].Key()),
0832 std::move(aOldSlots[i].Item()),
0833 aOldSlots[i].myHash);
0834 aOldSlots[i].Key().~TheKeyType();
0835 aOldSlots[i].Item().~TheItemType();
0836 }
0837 }
0838 Standard::Free(aOldSlots);
0839 }
0840 }
0841
0842
0843
0844
0845
0846 bool findSlotIndex(const TheKeyType& theKey, size_t& theIndex) const
0847 {
0848 const size_t aHash = myHasher(theKey);
0849 const size_t aMask = myCapacity - 1;
0850 size_t aIndex = aHash & aMask;
0851
0852 while (true)
0853 {
0854 const Slot& aSlot = mySlots[aIndex];
0855
0856 if (aSlot.IsEmpty())
0857 {
0858 return false;
0859 }
0860
0861 if (aSlot.myHash == aHash && myHasher(aSlot.Key(), theKey))
0862 {
0863 theIndex = aIndex;
0864 return true;
0865 }
0866 aIndex = (aIndex + 1) & aMask;
0867 }
0868 }
0869
0870 template <typename K, typename V, bool CheckExisting, bool UpdateExisting>
0871 bool insertRehashedImpl(K&& theKey,
0872 V&& theItem,
0873 const size_t theHash,
0874 std::bool_constant<CheckExisting>,
0875 std::bool_constant<UpdateExisting>,
0876 size_t* theInsertedIndex = nullptr)
0877 {
0878 const size_t aMask = myCapacity - 1;
0879 size_t aIndex = theHash & aMask;
0880 size_t aProbe = 0;
0881 size_t anInsertedIndex = 0;
0882 bool aHasInsertedIndex = false;
0883
0884 TheKeyType aKeyToInsert = std::forward<K>(theKey);
0885 TheItemType aItemToInsert = std::forward<V>(theItem);
0886 size_t aHashToInsert = theHash;
0887
0888 while (true)
0889 {
0890 Slot& aSlot = mySlots[aIndex];
0891 if (aSlot.IsEmpty())
0892 {
0893 new (&aSlot.Key()) TheKeyType(std::move(aKeyToInsert));
0894 new (&aSlot.Item()) TheItemType(std::move(aItemToInsert));
0895 aSlot.myHash = aHashToInsert;
0896 aSlot.SetProbeDistance(aProbe);
0897 ++mySize;
0898 if (theInsertedIndex != nullptr)
0899 {
0900 *theInsertedIndex = aHasInsertedIndex ? anInsertedIndex : aIndex;
0901 }
0902 return true;
0903 }
0904
0905 if constexpr (CheckExisting)
0906 {
0907 if (aSlot.myHash == aHashToInsert && myHasher(aSlot.Key(), aKeyToInsert))
0908 {
0909 if constexpr (UpdateExisting)
0910 {
0911 aSlot.Item() = std::move(aItemToInsert);
0912 }
0913 if (theInsertedIndex != nullptr)
0914 {
0915 *theInsertedIndex = aIndex;
0916 }
0917 return false;
0918 }
0919 }
0920
0921 if (aProbe > aSlot.ProbeDistance())
0922 {
0923 std::swap(aKeyToInsert, aSlot.Key());
0924 std::swap(aItemToInsert, aSlot.Item());
0925 std::swap(aHashToInsert, aSlot.myHash);
0926 const size_t aTmp = aProbe;
0927 aProbe = aSlot.ProbeDistance();
0928 aSlot.SetProbeDistance(aTmp);
0929 if (!aHasInsertedIndex)
0930 {
0931 anInsertedIndex = aIndex;
0932 aHasInsertedIndex = true;
0933 }
0934 }
0935
0936 ++aProbe;
0937 aIndex = (aIndex + 1) & aMask;
0938 }
0939 }
0940
0941 template <typename K, typename V>
0942 void insertRehashedImpl(K&& theKey, V&& theItem, const size_t theHash)
0943 {
0944 (void)insertRehashedImpl(std::forward<K>(theKey),
0945 std::forward<V>(theItem),
0946 theHash,
0947 std::false_type{},
0948 std::false_type{});
0949 }
0950
0951 template <typename K, typename V>
0952 bool insertImpl(K&& theKey, V&& theItem)
0953 {
0954 const size_t aHash = myHasher(theKey);
0955 return insertRehashedImpl(std::forward<K>(theKey),
0956 std::forward<V>(theItem),
0957 aHash,
0958 std::true_type{},
0959 std::true_type{});
0960 }
0961
0962 template <typename K, typename V>
0963 bool tryInsertImpl(K&& theKey, V&& theItem)
0964 {
0965 const size_t aHash = myHasher(theKey);
0966 return insertRehashedImpl(std::forward<K>(theKey),
0967 std::forward<V>(theItem),
0968 aHash,
0969 std::true_type{},
0970 std::false_type{});
0971 }
0972
0973 template <typename K, typename V, bool IsTry>
0974 TheItemType& insertRefImpl(K&& theKey, V&& theItem, std::bool_constant<IsTry>)
0975 {
0976 const size_t aHash = myHasher(theKey);
0977 size_t aIndex = 0;
0978 if constexpr (IsTry)
0979 {
0980 (void)insertRehashedImpl(std::forward<K>(theKey),
0981 std::forward<V>(theItem),
0982 aHash,
0983 std::true_type{},
0984 std::false_type{},
0985 &aIndex);
0986 }
0987 else
0988 {
0989 (void)insertRehashedImpl(std::forward<K>(theKey),
0990 std::forward<V>(theItem),
0991 aHash,
0992 std::true_type{},
0993 std::true_type{},
0994 &aIndex);
0995 }
0996 return mySlots[aIndex].Item();
0997 }
0998
0999 template <typename K, bool IsTry, typename... Args>
1000 bool emplaceImpl(K&& theKey, std::bool_constant<IsTry>, Args&&... theArgs)
1001 {
1002 const size_t aHash = myHasher(theKey);
1003 const size_t aMask = myCapacity - 1;
1004 size_t aIndex = aHash & aMask;
1005 size_t aProbe = 0;
1006
1007 TheKeyType aKeyToInsert = std::forward<K>(theKey);
1008 size_t aHashToInsert = aHash;
1009
1010 while (true)
1011 {
1012 Slot& aSlot = mySlots[aIndex];
1013
1014 if (aSlot.IsEmpty())
1015 {
1016 new (&aSlot.Key()) TheKeyType(std::move(aKeyToInsert));
1017 new (&aSlot.Item()) TheItemType(std::forward<Args>(theArgs)...);
1018 aSlot.myHash = aHashToInsert;
1019 aSlot.SetProbeDistance(aProbe);
1020 ++mySize;
1021 return true;
1022 }
1023
1024 if (aSlot.myHash == aHashToInsert && myHasher(aSlot.Key(), aKeyToInsert))
1025 {
1026 if constexpr (!IsTry)
1027 aSlot.Item() = TheItemType(std::forward<Args>(theArgs)...);
1028 return false;
1029 }
1030
1031 if (aProbe > aSlot.ProbeDistance())
1032 {
1033 TheItemType aItemToInsert(std::forward<Args>(theArgs)...);
1034
1035 std::swap(aKeyToInsert, aSlot.Key());
1036 std::swap(aItemToInsert, aSlot.Item());
1037 std::swap(aHashToInsert, aSlot.myHash);
1038 const size_t aTmp = aProbe;
1039 aProbe = aSlot.ProbeDistance();
1040 aSlot.SetProbeDistance(aTmp);
1041
1042 ++aProbe;
1043 aIndex = (aIndex + 1) & aMask;
1044
1045 while (true)
1046 {
1047 Slot& aSlot2 = mySlots[aIndex];
1048
1049 if (aSlot2.IsEmpty())
1050 {
1051 new (&aSlot2.Key()) TheKeyType(std::move(aKeyToInsert));
1052 new (&aSlot2.Item()) TheItemType(std::move(aItemToInsert));
1053 aSlot2.myHash = aHashToInsert;
1054 aSlot2.SetProbeDistance(aProbe);
1055 ++mySize;
1056 return true;
1057 }
1058
1059 if (aProbe > aSlot2.ProbeDistance())
1060 {
1061 std::swap(aKeyToInsert, aSlot2.Key());
1062 std::swap(aItemToInsert, aSlot2.Item());
1063 std::swap(aHashToInsert, aSlot2.myHash);
1064 const size_t aTmp2 = aProbe;
1065 aProbe = aSlot2.ProbeDistance();
1066 aSlot2.SetProbeDistance(aTmp2);
1067 }
1068
1069 ++aProbe;
1070 aIndex = (aIndex + 1) & aMask;
1071 }
1072 }
1073
1074 ++aProbe;
1075 aIndex = (aIndex + 1) & aMask;
1076 }
1077 }
1078
1079 template <typename K, bool IsTry, typename... Args>
1080 TheItemType& emplacedImpl(K&& theKey, std::bool_constant<IsTry>, Args&&... theArgs)
1081 {
1082 const size_t aHash = myHasher(theKey);
1083 const size_t aMask = myCapacity - 1;
1084 size_t aIndex = aHash & aMask;
1085 size_t aProbe = 0;
1086
1087 TheKeyType aKeyToInsert = std::forward<K>(theKey);
1088 size_t aHashToInsert = aHash;
1089
1090 while (true)
1091 {
1092 Slot& aSlot = mySlots[aIndex];
1093
1094 if (aSlot.IsEmpty())
1095 {
1096 new (&aSlot.Key()) TheKeyType(std::move(aKeyToInsert));
1097 new (&aSlot.Item()) TheItemType(std::forward<Args>(theArgs)...);
1098 aSlot.myHash = aHashToInsert;
1099 aSlot.SetProbeDistance(aProbe);
1100 ++mySize;
1101 return aSlot.Item();
1102 }
1103
1104 if (aSlot.myHash == aHashToInsert && myHasher(aSlot.Key(), aKeyToInsert))
1105 {
1106 if constexpr (!IsTry)
1107 aSlot.Item() = TheItemType(std::forward<Args>(theArgs)...);
1108 return aSlot.Item();
1109 }
1110
1111 if (aProbe > aSlot.ProbeDistance())
1112 {
1113 TheItemType aItemToInsert(std::forward<Args>(theArgs)...);
1114
1115 std::swap(aKeyToInsert, aSlot.Key());
1116 std::swap(aItemToInsert, aSlot.Item());
1117 std::swap(aHashToInsert, aSlot.myHash);
1118 const size_t aTmp = aProbe;
1119 aProbe = aSlot.ProbeDistance();
1120 aSlot.SetProbeDistance(aTmp);
1121
1122 TheItemType& aResult = aSlot.Item();
1123
1124 ++aProbe;
1125 aIndex = (aIndex + 1) & aMask;
1126
1127 while (true)
1128 {
1129 Slot& aSlot2 = mySlots[aIndex];
1130
1131 if (aSlot2.IsEmpty())
1132 {
1133 new (&aSlot2.Key()) TheKeyType(std::move(aKeyToInsert));
1134 new (&aSlot2.Item()) TheItemType(std::move(aItemToInsert));
1135 aSlot2.myHash = aHashToInsert;
1136 aSlot2.SetProbeDistance(aProbe);
1137 ++mySize;
1138 return aResult;
1139 }
1140
1141 if (aProbe > aSlot2.ProbeDistance())
1142 {
1143 std::swap(aKeyToInsert, aSlot2.Key());
1144 std::swap(aItemToInsert, aSlot2.Item());
1145 std::swap(aHashToInsert, aSlot2.myHash);
1146 const size_t aTmp2 = aProbe;
1147 aProbe = aSlot2.ProbeDistance();
1148 aSlot2.SetProbeDistance(aTmp2);
1149 }
1150
1151 ++aProbe;
1152 aIndex = (aIndex + 1) & aMask;
1153 }
1154 }
1155
1156 ++aProbe;
1157 aIndex = (aIndex + 1) & aMask;
1158 }
1159 }
1160
1161 void backwardShiftDelete(size_t theIndex)
1162 {
1163 const size_t aMask = myCapacity - 1;
1164 size_t aCurrent = theIndex;
1165 size_t aNext = (aCurrent + 1) & aMask;
1166
1167 while (mySlots[aNext].IsUsed() && mySlots[aNext].ProbeDistance() > 0)
1168 {
1169 new (&mySlots[aCurrent].Key()) TheKeyType(std::move(mySlots[aNext].Key()));
1170 new (&mySlots[aCurrent].Item()) TheItemType(std::move(mySlots[aNext].Item()));
1171 mySlots[aCurrent].myHash = mySlots[aNext].myHash;
1172 mySlots[aCurrent].SetProbeDistance(mySlots[aNext].ProbeDistance() - 1);
1173
1174 mySlots[aNext].Key().~TheKeyType();
1175 mySlots[aNext].Item().~TheItemType();
1176
1177 aCurrent = aNext;
1178 aNext = (aNext + 1) & aMask;
1179 }
1180
1181 mySlots[aCurrent].SetEmpty();
1182 }
1183
1184 private:
1185 Slot* mySlots;
1186 size_t myCapacity;
1187 size_t mySize;
1188 Hasher myHasher;
1189 };
1190
1191 #endif