File indexing completed on 2026-09-14 09:15:19
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #ifndef NCollection_IndexedMap_HeaderFile
0017 #define NCollection_IndexedMap_HeaderFile
0018
0019 #include <NCollection_BaseMap.hxx>
0020 #include <NCollection_TListNode.hxx>
0021 #include <NCollection_StlIterator.hxx>
0022 #include <NCollection_ItemsView.hxx>
0023 #include <Standard_NoSuchObject.hxx>
0024
0025 #include <NCollection_DefaultHasher.hxx>
0026
0027 #include <Standard_OutOfRange.hxx>
0028 #include <functional>
0029 #include <optional>
0030 #include <type_traits>
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 template <class TheKeyType, class Hasher = NCollection_DefaultHasher<TheKeyType>>
0044 class NCollection_IndexedMap : public NCollection_BaseMap
0045 {
0046 public:
0047
0048 typedef TheKeyType key_type;
0049
0050 protected:
0051
0052 class IndexedMapNode : public NCollection_TListNode<TheKeyType>
0053 {
0054 public:
0055
0056 IndexedMapNode(const TheKeyType& theKey1, const int theIndex, NCollection_ListNode* theNext1)
0057 : NCollection_TListNode<TheKeyType>(theKey1, theNext1),
0058 myIndex(theIndex)
0059 {
0060 }
0061
0062
0063 IndexedMapNode(TheKeyType&& theKey1, const int theIndex, NCollection_ListNode* theNext1)
0064 : NCollection_TListNode<TheKeyType>(std::forward<TheKeyType>(theKey1), theNext1),
0065 myIndex(theIndex)
0066 {
0067 }
0068
0069
0070 template <typename... Args>
0071 IndexedMapNode(std::in_place_t,
0072 const int theIndex,
0073 NCollection_ListNode* theNext1,
0074 Args&&... theArgs)
0075 : NCollection_TListNode<TheKeyType>(std::in_place,
0076 theNext1,
0077 std::forward<Args>(theArgs)...),
0078 myIndex(theIndex)
0079 {
0080 }
0081
0082
0083 TheKeyType& Key1() noexcept { return this->ChangeValue(); }
0084
0085
0086 int& Index() noexcept { return myIndex; }
0087
0088
0089 static void delNode(NCollection_ListNode* theNode,
0090 occ::handle<NCollection_BaseAllocator>& theAl) noexcept
0091 {
0092 ((IndexedMapNode*)theNode)->~IndexedMapNode();
0093 theAl->Free(theNode);
0094 }
0095
0096 private:
0097 int myIndex;
0098 };
0099
0100 public:
0101
0102 class Iterator
0103 {
0104 public:
0105
0106 Iterator()
0107 : myMap(nullptr),
0108 myIndex(0)
0109 {
0110 }
0111
0112
0113 Iterator(const NCollection_IndexedMap& theMap)
0114 : myMap((NCollection_IndexedMap*)&theMap),
0115 myIndex(1)
0116 {
0117 }
0118
0119
0120 bool More() const noexcept { return (myMap != nullptr) && (myIndex <= myMap->Extent()); }
0121
0122
0123 void Next() noexcept { myIndex++; }
0124
0125
0126 const TheKeyType& Value() const
0127 {
0128 Standard_NoSuchObject_Raise_if(!More(), "NCollection_IndexedMap::Iterator::Value");
0129 return myMap->FindKey(myIndex);
0130 }
0131
0132
0133 bool IsEqual(const Iterator& theOther) const noexcept
0134 {
0135 return myMap == theOther.myMap && myIndex == theOther.myIndex;
0136 }
0137
0138
0139 int Index() const noexcept { return myIndex; }
0140
0141 private:
0142 NCollection_IndexedMap* myMap;
0143 int myIndex;
0144 };
0145
0146
0147 typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheKeyType, true>
0148 const_iterator;
0149
0150
0151 typedef const_iterator iterator;
0152
0153
0154 iterator begin() const noexcept { return Iterator(*this); }
0155
0156
0157 iterator end() const noexcept { return Iterator(); }
0158
0159
0160 const_iterator cbegin() const noexcept { return Iterator(*this); }
0161
0162
0163 const_iterator cend() const noexcept { return Iterator(); }
0164
0165 public:
0166
0167
0168
0169
0170 using KeyIndexRef = NCollection_ItemsView::KeyIndexRef<TheKeyType>;
0171
0172 private:
0173
0174 struct IndexedItemsExtractor
0175 {
0176 static KeyIndexRef Extract(const Iterator& theIter)
0177 {
0178 return {theIter.Value(), theIter.Index()};
0179 }
0180 };
0181
0182 public:
0183
0184 using IndexedItemsView =
0185 NCollection_ItemsView::View<NCollection_IndexedMap, KeyIndexRef, IndexedItemsExtractor, true>;
0186
0187
0188
0189 IndexedItemsView IndexedItems() const { return IndexedItemsView(*this); }
0190
0191 public:
0192
0193
0194
0195 NCollection_IndexedMap()
0196 : NCollection_BaseMap(1, true, occ::handle<NCollection_BaseAllocator>())
0197 {
0198 }
0199
0200
0201 explicit NCollection_IndexedMap(
0202 const size_t theNbBuckets,
0203 const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0204 : NCollection_BaseMap(theNbBuckets, true, theAllocator)
0205 {
0206 }
0207
0208
0209 explicit NCollection_IndexedMap(
0210 const int theNbBuckets,
0211 const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0212 : NCollection_IndexedMap(NCollection_BaseMap::NbBucketsFromInt(theNbBuckets), theAllocator)
0213 {
0214 }
0215
0216
0217
0218
0219
0220 explicit NCollection_IndexedMap(
0221 const Hasher& theHasher,
0222 const size_t theNbBuckets = 1,
0223 const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0224 : NCollection_BaseMap(theNbBuckets, true, theAllocator),
0225 myHasher(theHasher)
0226 {
0227 }
0228
0229
0230 explicit NCollection_IndexedMap(
0231 const Hasher& theHasher,
0232 const int theNbBuckets,
0233 const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0234 : NCollection_IndexedMap(theHasher,
0235 NCollection_BaseMap::NbBucketsFromInt(theNbBuckets),
0236 theAllocator)
0237 {
0238 }
0239
0240
0241
0242
0243
0244 explicit NCollection_IndexedMap(
0245 Hasher&& theHasher,
0246 const size_t theNbBuckets = 1,
0247 const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0248 : NCollection_BaseMap(theNbBuckets, true, theAllocator),
0249 myHasher(std::move(theHasher))
0250 {
0251 }
0252
0253
0254 explicit NCollection_IndexedMap(
0255 Hasher&& theHasher,
0256 const int theNbBuckets,
0257 const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0258 : NCollection_IndexedMap(std::move(theHasher),
0259 NCollection_BaseMap::NbBucketsFromInt(theNbBuckets),
0260 theAllocator)
0261 {
0262 }
0263
0264
0265 NCollection_IndexedMap(const NCollection_IndexedMap& theOther)
0266 : NCollection_BaseMap(theOther.NbBuckets(), true, theOther.myAllocator),
0267 myHasher(theOther.myHasher)
0268 {
0269 *this = theOther;
0270 }
0271
0272
0273 NCollection_IndexedMap(NCollection_IndexedMap&& theOther) noexcept
0274 : NCollection_BaseMap(std::forward<NCollection_BaseMap>(theOther)),
0275 myHasher(std::move(theOther.myHasher))
0276 {
0277 }
0278
0279
0280
0281 void Exchange(NCollection_IndexedMap& theOther) noexcept
0282 {
0283 this->exchangeMapsData(theOther);
0284 std::swap(myHasher, theOther.myHasher);
0285 }
0286
0287
0288 const Hasher& GetHasher() const noexcept { return myHasher; }
0289
0290
0291
0292 NCollection_IndexedMap& Assign(const NCollection_IndexedMap& theOther)
0293 {
0294 if (this == &theOther)
0295 return *this;
0296
0297 Clear();
0298 int anExt = theOther.Extent();
0299 if (anExt)
0300 {
0301 ReSize(anExt - 1);
0302 for (int anIndexIter = 1; anIndexIter <= anExt; ++anIndexIter)
0303 {
0304 const TheKeyType& aKey1 = theOther.FindKey(anIndexIter);
0305 const size_t iK1 = HashCode(aKey1, NbBuckets());
0306 IndexedMapNode* pNode =
0307 new (this->myAllocator) IndexedMapNode(aKey1, anIndexIter, myData1[iK1]);
0308 myData1[iK1] = pNode;
0309 myData2[anIndexIter - 1] = pNode;
0310 Increment();
0311 }
0312 }
0313 return *this;
0314 }
0315
0316
0317 NCollection_IndexedMap& operator=(const NCollection_IndexedMap& theOther)
0318 {
0319 return Assign(theOther);
0320 }
0321
0322
0323 NCollection_IndexedMap& operator=(NCollection_IndexedMap&& theOther) noexcept
0324 {
0325 if (this == &theOther)
0326 return *this;
0327 exchangeMapsData(theOther);
0328 return *this;
0329 }
0330
0331
0332 void ReSize(const size_t theExtent)
0333 {
0334 NCollection_ListNode** ppNewData1 = nullptr;
0335 NCollection_ListNode** ppNewData2 = nullptr;
0336 size_t newBuck;
0337 if (BeginResize(theExtent, newBuck, ppNewData1, ppNewData2))
0338 {
0339 if (myData1)
0340 {
0341 for (size_t aBucketIter = 0; aBucketIter <= NbBuckets(); ++aBucketIter)
0342 {
0343 if (myData1[aBucketIter])
0344 {
0345 IndexedMapNode* p = (IndexedMapNode*)myData1[aBucketIter];
0346 while (p)
0347 {
0348 const size_t iK1 = HashCode(p->Key1(), newBuck);
0349 IndexedMapNode* q = (IndexedMapNode*)p->Next();
0350 p->Next() = ppNewData1[iK1];
0351 ppNewData1[iK1] = p;
0352 p = q;
0353 }
0354 }
0355 }
0356 }
0357 EndResize(theExtent,
0358 newBuck,
0359 ppNewData1,
0360 (NCollection_ListNode**)
0361 Standard::Reallocate(myData2, (newBuck + 1) * sizeof(NCollection_ListNode*)));
0362 }
0363 }
0364
0365 void ReSize(const int theExtent) { ReSize(static_cast<size_t>(theExtent < 0 ? 0 : theExtent)); }
0366
0367
0368
0369
0370 int Add(const TheKeyType& theKey1) { return addImpl(theKey1, std::false_type{}); }
0371
0372
0373
0374
0375 int Add(TheKeyType&& theKey1) { return addImpl(std::move(theKey1), std::false_type{}); }
0376
0377
0378
0379
0380
0381 const TheKeyType& Added(const TheKeyType& theKey1) { return addImpl(theKey1, std::true_type{}); }
0382
0383
0384
0385
0386
0387 const TheKeyType& Added(TheKeyType&& theKey1)
0388 {
0389 return addImpl(std::move(theKey1), std::true_type{});
0390 }
0391
0392
0393
0394
0395 template <typename... Args>
0396 int Emplace(Args&&... theArgs)
0397 {
0398 return emplaceImpl(std::false_type{}, std::false_type{}, std::forward<Args>(theArgs)...);
0399 }
0400
0401
0402
0403
0404 template <typename... Args>
0405 const TheKeyType& Emplaced(Args&&... theArgs)
0406 {
0407 return emplaceImpl(std::false_type{}, std::true_type{}, std::forward<Args>(theArgs)...);
0408 }
0409
0410
0411
0412
0413 template <typename... Args>
0414 int TryEmplace(Args&&... theArgs)
0415 {
0416 return emplaceImpl(std::true_type{}, std::false_type{}, std::forward<Args>(theArgs)...);
0417 }
0418
0419
0420
0421
0422 template <typename... Args>
0423 const TheKeyType& TryEmplaced(Args&&... theArgs)
0424 {
0425 return emplaceImpl(std::true_type{}, std::true_type{}, std::forward<Args>(theArgs)...);
0426 }
0427
0428
0429 bool Contains(const TheKeyType& theKey1) const
0430 {
0431 IndexedMapNode* p;
0432 return lookup(theKey1, p);
0433 }
0434
0435
0436
0437 std::optional<std::reference_wrapper<const TheKeyType>> Contained(const TheKeyType& theKey1) const
0438 {
0439 IndexedMapNode* p;
0440 if (!lookup(theKey1, p))
0441 return std::nullopt;
0442 return std::cref(p->Value());
0443 }
0444
0445
0446 void Substitute(const size_t theIndex, const TheKeyType& theKey1)
0447 {
0448 Standard_OutOfRange_Raise_if(theIndex == 0 || theIndex > Size(),
0449 "NCollection_IndexedMap::Substitute : "
0450 "Index is out of range");
0451
0452
0453 IndexedMapNode* aNode;
0454 size_t aHash;
0455 if (lookup(theKey1, aNode, aHash))
0456 {
0457 if (static_cast<size_t>(aNode->Index()) != theIndex)
0458 {
0459 throw Standard_DomainError("NCollection_IndexedMap::Substitute : "
0460 "Attempt to substitute existing key");
0461 }
0462 aNode->Key1() = theKey1;
0463 return;
0464 }
0465
0466 aNode = (IndexedMapNode*)myData2[theIndex - 1];
0467
0468
0469 const size_t iK = HashCode(aNode->Key1(), NbBuckets());
0470 IndexedMapNode* q = (IndexedMapNode*)myData1[iK];
0471 if (q == aNode)
0472 myData1[iK] = (IndexedMapNode*)aNode->Next();
0473 else
0474 {
0475 while (q->Next() != aNode)
0476 q = (IndexedMapNode*)q->Next();
0477 q->Next() = aNode->Next();
0478 }
0479
0480
0481 aNode->Key1() = theKey1;
0482 aNode->Next() = myData1[aHash];
0483 myData1[aHash] = aNode;
0484 }
0485
0486 void Substitute(const int theIndex, const TheKeyType& theKey1)
0487 {
0488 Standard_OutOfRange_Raise_if(theIndex < 0,
0489 "NCollection_IndexedMap::Substitute: negative index");
0490 Substitute(static_cast<size_t>(theIndex), theKey1);
0491 }
0492
0493
0494 void Swap(const size_t theIndex1, const size_t theIndex2)
0495 {
0496 Standard_OutOfRange_Raise_if(theIndex1 == 0 || theIndex1 > Size() || theIndex2 == 0
0497 || theIndex2 > Size(),
0498 "NCollection_IndexedMap::Swap");
0499
0500 if (theIndex1 == theIndex2)
0501 {
0502 return;
0503 }
0504
0505 IndexedMapNode* aP1 = (IndexedMapNode*)myData2[theIndex1 - 1];
0506 IndexedMapNode* aP2 = (IndexedMapNode*)myData2[theIndex2 - 1];
0507 std::swap(aP1->Index(), aP2->Index());
0508 myData2[theIndex2 - 1] = aP1;
0509 myData2[theIndex1 - 1] = aP2;
0510 }
0511
0512 void Swap(const int theIndex1, const int theIndex2)
0513 {
0514 Standard_OutOfRange_Raise_if(theIndex1 < 0 || theIndex2 < 0,
0515 "NCollection_IndexedMap::Swap: negative index");
0516 Swap(static_cast<size_t>(theIndex1), static_cast<size_t>(theIndex2));
0517 }
0518
0519
0520 void RemoveLast()
0521 {
0522 const size_t aLastIndex = Size();
0523 Standard_OutOfRange_Raise_if(aLastIndex == 0, "NCollection_IndexedMap::RemoveLast");
0524
0525
0526 IndexedMapNode* p = (IndexedMapNode*)myData2[aLastIndex - 1];
0527 myData2[aLastIndex - 1] = nullptr;
0528
0529
0530 const size_t iK1 = HashCode(p->Key1(), NbBuckets());
0531 IndexedMapNode* q = (IndexedMapNode*)myData1[iK1];
0532 if (q == p)
0533 myData1[iK1] = (IndexedMapNode*)p->Next();
0534 else
0535 {
0536 while (q->Next() != p)
0537 q = (IndexedMapNode*)q->Next();
0538 q->Next() = p->Next();
0539 }
0540 p->~IndexedMapNode();
0541 this->myAllocator->Free(p);
0542 Decrement();
0543 }
0544
0545
0546
0547 void RemoveFromIndex(const size_t theIndex)
0548 {
0549 Standard_OutOfRange_Raise_if(theIndex == 0 || theIndex > Size(),
0550 "NCollection_IndexedMap::RemoveFromIndex");
0551 const size_t aLastInd = Size();
0552 if (theIndex != aLastInd)
0553 {
0554 Swap(theIndex, aLastInd);
0555 }
0556 RemoveLast();
0557 }
0558
0559 void RemoveFromIndex(const int theIndex)
0560 {
0561 Standard_OutOfRange_Raise_if(theIndex < 0,
0562 "NCollection_IndexedMap::RemoveFromIndex: negative index");
0563 RemoveFromIndex(static_cast<size_t>(theIndex));
0564 }
0565
0566
0567
0568 bool RemoveKey(const TheKeyType& theKey1)
0569 {
0570 int anIndToRemove = FindIndex(theKey1);
0571 if (anIndToRemove < 1)
0572 {
0573 return false;
0574 }
0575
0576 RemoveFromIndex(static_cast<size_t>(anIndToRemove));
0577 return true;
0578 }
0579
0580
0581 const TheKeyType& FindKey(const size_t theIndex) const
0582 {
0583 Standard_OutOfRange_Raise_if(theIndex == 0 || theIndex > Size(),
0584 "NCollection_IndexedMap::FindKey");
0585 IndexedMapNode* pNode2 = (IndexedMapNode*)myData2[theIndex - 1];
0586 return pNode2->Key1();
0587 }
0588
0589 const TheKeyType& FindKey(const int theIndex) const
0590 {
0591 Standard_OutOfRange_Raise_if(theIndex < 0, "NCollection_IndexedMap::FindKey: negative index");
0592 return FindKey(static_cast<size_t>(theIndex));
0593 }
0594
0595
0596 const TheKeyType& operator()(const size_t theIndex) const { return FindKey(theIndex); }
0597
0598 const TheKeyType& operator()(const int theIndex) const { return FindKey(theIndex); }
0599
0600
0601 int FindIndex(const TheKeyType& theKey1) const
0602 {
0603 IndexedMapNode* aNode;
0604 if (lookup(theKey1, aNode))
0605 {
0606 return aNode->Index();
0607 }
0608 return 0;
0609 }
0610
0611
0612
0613 void Clear(const bool doReleaseMemory = false)
0614 {
0615 Destroy(IndexedMapNode::delNode, doReleaseMemory);
0616 }
0617
0618
0619 void Clear(const occ::handle<NCollection_BaseAllocator>& theAllocator)
0620 {
0621 Clear(theAllocator != this->myAllocator);
0622 this->myAllocator =
0623 (!theAllocator.IsNull() ? theAllocator : NCollection_BaseAllocator::CommonBaseAllocator());
0624 }
0625
0626
0627 ~NCollection_IndexedMap() override { Clear(true); }
0628
0629 protected:
0630
0631
0632
0633
0634
0635 bool lookup(const TheKeyType& theKey, IndexedMapNode*& theNode, size_t& theHash) const
0636 {
0637 theHash = HashCode(theKey, NbBuckets());
0638 if (IsEmpty())
0639 return false;
0640 for (theNode = (IndexedMapNode*)myData1[theHash]; theNode;
0641 theNode = (IndexedMapNode*)theNode->Next())
0642 {
0643 if (IsEqual(theNode->Key1(), theKey))
0644 return true;
0645 }
0646 return false;
0647 }
0648
0649
0650
0651
0652
0653 bool lookup(const TheKeyType& theKey, IndexedMapNode*& theNode) const
0654 {
0655 if (IsEmpty())
0656 return false;
0657 for (theNode = (IndexedMapNode*)myData1[HashCode(theKey, NbBuckets())]; theNode;
0658 theNode = (IndexedMapNode*)theNode->Next())
0659 {
0660 if (IsEqual(theNode->Key1(), theKey))
0661 {
0662 return true;
0663 }
0664 }
0665 return false;
0666 }
0667
0668 bool IsEqual(const TheKeyType& theKey1, const TheKeyType& theKey2) const
0669 {
0670 return myHasher(theKey1, theKey2);
0671 }
0672
0673 size_t HashCode(const TheKeyType& theKey, const size_t theUpperBound) const
0674 {
0675 return myHasher(theKey) % theUpperBound + 1;
0676 }
0677
0678
0679
0680
0681
0682
0683 template <typename K, bool ReturnRef>
0684 auto addImpl(K&& theKey1, std::bool_constant<ReturnRef>)
0685 -> std::conditional_t<ReturnRef, const TheKeyType&, int>
0686 {
0687 if (Resizable())
0688 {
0689 ReSize(Extent());
0690 }
0691 IndexedMapNode* aNode;
0692 size_t aHash;
0693 if (lookup(theKey1, aNode, aHash))
0694 {
0695 if constexpr (ReturnRef)
0696 return aNode->Key1();
0697 else
0698 return aNode->Index();
0699 }
0700 const int aNewIndex = Extent() + 1;
0701 aNode =
0702 new (this->myAllocator) IndexedMapNode(std::forward<K>(theKey1), aNewIndex, myData1[aHash]);
0703 myData1[aHash] = aNode;
0704 myData2[aNewIndex - 1] = aNode;
0705 Increment();
0706 if constexpr (ReturnRef)
0707 return aNode->Key1();
0708 else
0709 return aNewIndex;
0710 }
0711
0712
0713
0714
0715
0716
0717 template <bool IsTry, bool ReturnRef, typename... Args>
0718 auto emplaceImpl(std::bool_constant<IsTry>, std::bool_constant<ReturnRef>, Args&&... theArgs)
0719 -> std::conditional_t<ReturnRef, const TheKeyType&, int>
0720 {
0721 if (Resizable())
0722 ReSize(Extent());
0723
0724 TheKeyType aTempKey(std::forward<Args>(theArgs)...);
0725 IndexedMapNode* aNode;
0726 size_t aHash;
0727 if (lookup(aTempKey, aNode, aHash))
0728 {
0729 if constexpr (!IsTry)
0730 aNode->Key1() = std::move(aTempKey);
0731 if constexpr (ReturnRef)
0732 return aNode->Key1();
0733 else
0734 return aNode->Index();
0735 }
0736 const int aNewIndex = Extent() + 1;
0737 aNode = new (this->myAllocator) IndexedMapNode(std::move(aTempKey), aNewIndex, myData1[aHash]);
0738 myData1[aHash] = aNode;
0739 myData2[aNewIndex - 1] = aNode;
0740 Increment();
0741 if constexpr (ReturnRef)
0742 return aNode->Key1();
0743 else
0744 return aNewIndex;
0745 }
0746
0747 protected:
0748 Hasher myHasher;
0749 };
0750
0751 #endif