Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-14 09:15:19

0001 // Created on: 2002-04-24
0002 // Created by: Alexander KARTOMIN (akm)
0003 // Copyright (c) 2002-2014 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
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  * Purpose:     An indexed map is used to  store  keys and to bind
0034  *              an index to them.  Each new key stored in  the map
0035  *              gets an index.  Index are incremented  as keys are
0036  *              stored in the map. A key can be found by the index
0037  *              and an index by the  key. No key  but the last can
0038  *              be removed so the indices are in the range 1..Extent.
0039  *              See  the  class   Map   from NCollection   for   a
0040  *              discussion about the number of buckets.
0041  */
0042 
0043 template <class TheKeyType, class Hasher = NCollection_DefaultHasher<TheKeyType>>
0044 class NCollection_IndexedMap : public NCollection_BaseMap
0045 {
0046 public:
0047   //! STL-compliant typedef for key type
0048   typedef TheKeyType key_type;
0049 
0050 protected:
0051   //! Adaptation of the TListNode to the INDEXEDmap
0052   class IndexedMapNode : public NCollection_TListNode<TheKeyType>
0053   {
0054   public:
0055     //! Constructor with 'Next'
0056     IndexedMapNode(const TheKeyType& theKey1, const int theIndex, NCollection_ListNode* theNext1)
0057         : NCollection_TListNode<TheKeyType>(theKey1, theNext1),
0058           myIndex(theIndex)
0059     {
0060     }
0061 
0062     //! Constructor with 'Next'
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     //! Constructor with in-place key construction
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     //! Key1
0083     TheKeyType& Key1() noexcept { return this->ChangeValue(); }
0084 
0085     //! Index
0086     int& Index() noexcept { return myIndex; }
0087 
0088     //! Static deleter to be passed to BaseList
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   // **************** Implementation of the Iterator interface.
0102   class Iterator
0103   {
0104   public:
0105     //! Empty constructor
0106     Iterator()
0107         : myMap(nullptr),
0108           myIndex(0)
0109     {
0110     }
0111 
0112     //! Constructor
0113     Iterator(const NCollection_IndexedMap& theMap)
0114         : myMap((NCollection_IndexedMap*)&theMap),
0115           myIndex(1)
0116     {
0117     }
0118 
0119     //! Query if the end of collection is reached by iterator
0120     bool More() const noexcept { return (myMap != nullptr) && (myIndex <= myMap->Extent()); }
0121 
0122     //! Make a step along the collection
0123     void Next() noexcept { myIndex++; }
0124 
0125     //! Value access
0126     const TheKeyType& Value() const
0127     {
0128       Standard_NoSuchObject_Raise_if(!More(), "NCollection_IndexedMap::Iterator::Value");
0129       return myMap->FindKey(myIndex);
0130     }
0131 
0132     //! Performs comparison of two iterators.
0133     bool IsEqual(const Iterator& theOther) const noexcept
0134     {
0135       return myMap == theOther.myMap && myIndex == theOther.myIndex;
0136     }
0137 
0138     //! Returns current index (1-based).
0139     int Index() const noexcept { return myIndex; }
0140 
0141   private:
0142     NCollection_IndexedMap* myMap;   // Pointer to the map being iterated
0143     int                     myIndex; // Current index
0144   };
0145 
0146   //! Shorthand for a constant iterator type.
0147   typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheKeyType, true>
0148     const_iterator;
0149 
0150   //! Shorthand for iterator type (same as const_iterator for key-only maps).
0151   typedef const_iterator iterator;
0152 
0153   //! Returns an iterator pointing to the first element in the map.
0154   iterator begin() const noexcept { return Iterator(*this); }
0155 
0156   //! Returns an iterator referring to the past-the-end element in the map.
0157   iterator end() const noexcept { return Iterator(); }
0158 
0159   //! Returns a const iterator pointing to the first element in the map.
0160   const_iterator cbegin() const noexcept { return Iterator(*this); }
0161 
0162   //! Returns a const iterator referring to the past-the-end element in the map.
0163   const_iterator cend() const noexcept { return Iterator(); }
0164 
0165 public:
0166   // **************** Key-index pair iteration support for structured bindings
0167 
0168   //! Key-index pair reference for structured binding support.
0169   //! Enables: for (auto [key, index] : map.IndexedItems())
0170   using KeyIndexRef = NCollection_ItemsView::KeyIndexRef<TheKeyType>;
0171 
0172 private:
0173   //! Extractor for key-index pairs
0174   struct IndexedItemsExtractor
0175   {
0176     static KeyIndexRef Extract(const Iterator& theIter)
0177     {
0178       return {theIter.Value(), theIter.Index()};
0179     }
0180   };
0181 
0182 public:
0183   //! View class for key-index pair iteration.
0184   using IndexedItemsView =
0185     NCollection_ItemsView::View<NCollection_IndexedMap, KeyIndexRef, IndexedItemsExtractor, true>;
0186 
0187   //! Returns a view for key-index pair iteration.
0188   //! Usage: for (auto [aKey, anIndex] : aMap.IndexedItems())
0189   IndexedItemsView IndexedItems() const { return IndexedItemsView(*this); }
0190 
0191 public:
0192   // ---------- PUBLIC METHODS ------------
0193 
0194   //! Empty constructor.
0195   NCollection_IndexedMap()
0196       : NCollection_BaseMap(1, true, occ::handle<NCollection_BaseAllocator>())
0197   {
0198   }
0199 
0200   //! Constructor
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   //! Constructor (legacy int-taking).
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   //! Constructor with custom hasher (copy).
0217   //! @param theHasher custom hasher instance
0218   //! @param theNbBuckets initial number of buckets
0219   //! @param theAllocator custom memory allocator
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   //! Constructor with custom hasher (copy, legacy int-taking).
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   //! Constructor with custom hasher (move).
0241   //! @param theHasher custom hasher instance (moved)
0242   //! @param theNbBuckets initial number of buckets
0243   //! @param theAllocator custom memory allocator
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   //! Constructor with custom hasher (move, legacy int-taking).
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   //! Copy constructor
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   //! Move constructor
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   //! Exchange the content of two maps without re-allocations.
0280   //! Notice that allocators will be swapped as well!
0281   void Exchange(NCollection_IndexedMap& theOther) noexcept
0282   {
0283     this->exchangeMapsData(theOther);
0284     std::swap(myHasher, theOther.myHasher);
0285   }
0286 
0287   //! Returns const reference to the hasher.
0288   const Hasher& GetHasher() const noexcept { return myHasher; }
0289 
0290   //! Assign.
0291   //! This method does not change the internal allocator.
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); // mySize is same after resize
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   //! Assignment operator
0317   NCollection_IndexedMap& operator=(const NCollection_IndexedMap& theOther)
0318   {
0319     return Assign(theOther);
0320   }
0321 
0322   //! Move operator
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   //! ReSize
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   //! Add adds a new key to the map.
0368   //! @param theKey1 key to add
0369   //! @return index of the key (new or existing)
0370   int Add(const TheKeyType& theKey1) { return addImpl(theKey1, std::false_type{}); }
0371 
0372   //! Add adds a new key to the map.
0373   //! @param theKey1 key to add
0374   //! @return index of the key (new or existing)
0375   int Add(TheKeyType&& theKey1) { return addImpl(std::move(theKey1), std::false_type{}); }
0376 
0377   //! Added: add a new key if not yet in the map, and return
0378   //! reference to either newly added or previously existing key.
0379   //! @param theKey1 key to add
0380   //! @return const reference to the key in the map
0381   const TheKeyType& Added(const TheKeyType& theKey1) { return addImpl(theKey1, std::true_type{}); }
0382 
0383   //! Added: add a new key if not yet in the map, and return
0384   //! reference to either newly added or previously existing key.
0385   //! @param theKey1 key to add
0386   //! @return const reference to the key in the map
0387   const TheKeyType& Added(TheKeyType&& theKey1)
0388   {
0389     return addImpl(std::move(theKey1), std::true_type{});
0390   }
0391 
0392   //! Emplace constructs key in-place; if key exists, destroys and reconstructs.
0393   //! @param theArgs arguments forwarded to key constructor
0394   //! @return index of the key (new or existing)
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   //! Emplaced constructs key in-place; if key exists, overwrites.
0402   //! @param theArgs arguments forwarded to key constructor
0403   //! @return const reference to the key in the map
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   //! TryEmplace constructs key in-place only if not already present.
0411   //! @param theArgs arguments forwarded to key constructor
0412   //! @return index of the key (new or existing)
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   //! TryEmplaced constructs key in-place only if not already present.
0420   //! @param theArgs arguments forwarded to key constructor
0421   //! @return const reference to the key (existing or newly added)
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   //! Contains
0429   bool Contains(const TheKeyType& theKey1) const
0430   {
0431     IndexedMapNode* p;
0432     return lookup(theKey1, p);
0433   }
0434 
0435   //! Contained returns optional const reference to the key in the map.
0436   //! Returns std::nullopt if the key is not found.
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   //! Substitute
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     // check if theKey1 is not already in the map
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     // Find the node for the index I
0466     aNode = (IndexedMapNode*)myData2[theIndex - 1];
0467 
0468     // remove the old key
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     // update the node
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   //! Swaps two elements with the given indices.
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   //! RemoveLast
0520   void RemoveLast()
0521   {
0522     const size_t aLastIndex = Size();
0523     Standard_OutOfRange_Raise_if(aLastIndex == 0, "NCollection_IndexedMap::RemoveLast");
0524 
0525     // Find the node for the last index and remove it
0526     IndexedMapNode* p       = (IndexedMapNode*)myData2[aLastIndex - 1];
0527     myData2[aLastIndex - 1] = nullptr;
0528 
0529     // remove the key
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   //! Remove the key of the given index.
0546   //! Caution! The index of the last key can be changed.
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   //! Remove the given key.
0567   //! Caution! The index of the last key can be changed.
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   //! FindKey
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   //! operator ()
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   //! FindIndex
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   //! Clear data. If doReleaseMemory is false then the table of
0612   //! buckets is not released and will be reused.
0613   void Clear(const bool doReleaseMemory = false)
0614   {
0615     Destroy(IndexedMapNode::delNode, doReleaseMemory);
0616   }
0617 
0618   //! Clear data and reset allocator
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   //! Destructor
0627   ~NCollection_IndexedMap() override { Clear(true); }
0628 
0629 protected:
0630   //! Lookup for particular key in map.
0631   //! @param[in] theKey key to compute hash
0632   //! @param[out] theNode the detected node with equal key. Can be null.
0633   //! @param[out] theHash computed bounded hash code for current key.
0634   //! @return true if key is found
0635   bool lookup(const TheKeyType& theKey, IndexedMapNode*& theNode, size_t& theHash) const
0636   {
0637     theHash = HashCode(theKey, NbBuckets());
0638     if (IsEmpty())
0639       return false; // Not found
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; // Not found
0647   }
0648 
0649   //! Lookup for particular key in map.
0650   //! @param[in] theKey key to compute hash
0651   //! @param[out] theNode the detected node with equal key. Can be null.
0652   //! @return true if key is found
0653   bool lookup(const TheKeyType& theKey, IndexedMapNode*& theNode) const
0654   {
0655     if (IsEmpty())
0656       return false; // Not found
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; // Not found
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   //! Implementation helper for Add/Added (uses TryEmplace behavior - no modification on existing).
0679   //! @tparam K forwarding reference type for key
0680   //! @tparam ReturnRef if true, returns const reference to key; if false, returns int (index)
0681   //! @param theKey1 key to add
0682   //! @return int (Add) or const TheKeyType& (Added)
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   //! Implementation helper for Emplace/Emplaced.
0713   //! @tparam IsTry if true, does not modify existing; if false, overwrites
0714   //! @tparam ReturnRef if true, returns const reference to key; if false, returns int (index)
0715   //! @param theArgs arguments forwarded to key constructor
0716   //! @return int or const TheKeyType& depending on ReturnRef
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     // First construct the key to compute hash and check for existence
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