Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-29 09:19:57

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_IndexedDataMap_HeaderFile
0017 #define NCollection_IndexedDataMap_HeaderFile
0018 
0019 #include <NCollection_BaseMap.hxx>
0020 #include <NCollection_TListNode.hxx>
0021 #include <Standard_TypeMismatch.hxx>
0022 #include <Standard_NoSuchObject.hxx>
0023 #include <NCollection_StlIterator.hxx>
0024 #include <NCollection_DefaultHasher.hxx>
0025 #include <NCollection_ItemsView.hxx>
0026 
0027 #include <Standard_OutOfRange.hxx>
0028 #include <functional>
0029 #include <optional>
0030 #include <type_traits>
0031 #include <utility>
0032 
0033 /**
0034  * Purpose:     An indexed map is used  to store keys and to  bind
0035  *              an index to them.  Each  new key stored in the map
0036  *              gets an index.  Index are  incremented as keys are
0037  *              stored in the map. A key can be found by the index
0038  *              and an index by the key.  No  key but the last can
0039  *              be  removed so the  indices   are in the range 1..
0040  *              Extent.  An Item is stored with each key.
0041  *
0042  *              This   class is   similar  to  IndexedMap     from
0043  *              NCollection  with the Item as  a new feature. Note
0044  *              the important difference on  the operator  ().  In
0045  *              the IndexedMap this operator returns  the Key.  In
0046  *              the IndexedDataMap this operator returns the Item.
0047  *
0048  *              See  the  class   Map   from NCollection   for   a
0049  *              discussion about the number of buckets.
0050  */
0051 
0052 template <class TheKeyType, class TheItemType, class Hasher = NCollection_DefaultHasher<TheKeyType>>
0053 class NCollection_IndexedDataMap : public NCollection_BaseMap
0054 {
0055 public:
0056   //! STL-compliant typedef for key type
0057   typedef TheKeyType key_type;
0058   //! STL-compliant typedef for value type
0059   typedef TheItemType value_type;
0060   typedef Hasher      hasher;
0061 
0062 private:
0063   //!    Adaptation of the TListNode to the INDEXEDDatamap
0064   class IndexedDataMapNode : public NCollection_TListNode<TheItemType>
0065   {
0066   public:
0067     //! Constructor with 'Next'
0068     IndexedDataMapNode(const TheKeyType&     theKey1,
0069                        const int             theIndex,
0070                        const TheItemType&    theItem,
0071                        NCollection_ListNode* theNext1)
0072         : NCollection_TListNode<TheItemType>(theItem, theNext1),
0073           myKey1(theKey1),
0074           myIndex(theIndex)
0075     {
0076     }
0077 
0078     //! Constructor with 'Next'
0079     IndexedDataMapNode(TheKeyType&&          theKey1,
0080                        const int             theIndex,
0081                        const TheItemType&    theItem,
0082                        NCollection_ListNode* theNext1)
0083         : NCollection_TListNode<TheItemType>(theItem, theNext1),
0084           myKey1(std::forward<TheKeyType>(theKey1)),
0085           myIndex(theIndex)
0086     {
0087     }
0088 
0089     //! Constructor with 'Next'
0090     IndexedDataMapNode(const TheKeyType&     theKey1,
0091                        const int             theIndex,
0092                        TheItemType&&         theItem,
0093                        NCollection_ListNode* theNext1)
0094         : NCollection_TListNode<TheItemType>(std::forward<TheItemType>(theItem), theNext1),
0095           myKey1(theKey1),
0096           myIndex(theIndex)
0097     {
0098     }
0099 
0100     //! Constructor with 'Next'
0101     IndexedDataMapNode(TheKeyType&&          theKey1,
0102                        const int             theIndex,
0103                        TheItemType&&         theItem,
0104                        NCollection_ListNode* theNext1)
0105         : NCollection_TListNode<TheItemType>(std::forward<TheItemType>(theItem), theNext1),
0106           myKey1(std::forward<TheKeyType>(theKey1)),
0107           myIndex(theIndex)
0108     {
0109     }
0110 
0111     //! Constructor with in-place value construction
0112     template <typename K, typename... Args>
0113     IndexedDataMapNode(K&&       theKey1,
0114                        const int theIndex,
0115                        std::in_place_t,
0116                        NCollection_ListNode* theNext1,
0117                        Args&&... theArgs)
0118         : NCollection_TListNode<TheItemType>(std::in_place,
0119                                              theNext1,
0120                                              std::forward<Args>(theArgs)...),
0121           myKey1(std::forward<K>(theKey1)),
0122           myIndex(theIndex)
0123     {
0124     }
0125 
0126     //! Key1
0127     TheKeyType& Key1() noexcept { return myKey1; }
0128 
0129     //! Index
0130     int& Index() noexcept { return myIndex; }
0131 
0132     //! Static deleter to be passed to BaseList
0133     static void delNode(NCollection_ListNode*                   theNode,
0134                         occ::handle<NCollection_BaseAllocator>& theAl) noexcept
0135     {
0136       ((IndexedDataMapNode*)theNode)->~IndexedDataMapNode();
0137       theAl->Free(theNode);
0138     }
0139 
0140   private:
0141     TheKeyType myKey1;
0142     int        myIndex;
0143   };
0144 
0145 public:
0146   //!   Implementation of the Iterator interface.
0147   class Iterator
0148   {
0149   public:
0150     //! Empty constructor
0151     Iterator()
0152         : myMap(nullptr),
0153           myIndex(0)
0154     {
0155     }
0156 
0157     //! Constructor
0158     Iterator(const NCollection_IndexedDataMap& theMap)
0159         : myMap((NCollection_IndexedDataMap*)&theMap),
0160           myIndex(1)
0161     {
0162     }
0163 
0164     //! Query if the end of collection is reached by iterator
0165     bool More() const noexcept { return (myMap != nullptr) && (myIndex <= myMap->Extent()); }
0166 
0167     //! Make a step along the collection
0168     void Next() noexcept { ++myIndex; }
0169 
0170     //! Value access
0171     const TheItemType& Value() const
0172     {
0173       Standard_NoSuchObject_Raise_if(!More(), "NCollection_IndexedDataMap::Iterator::Value");
0174       return myMap->FindFromIndex(myIndex);
0175     }
0176 
0177     //! ChangeValue access
0178     TheItemType& ChangeValue() const
0179     {
0180       Standard_NoSuchObject_Raise_if(!More(), "NCollection_IndexedDataMap::Iterator::ChangeValue");
0181       return myMap->ChangeFromIndex(myIndex);
0182     }
0183 
0184     //! Key
0185     const TheKeyType& Key() const
0186     {
0187       Standard_NoSuchObject_Raise_if(!More(), "NCollection_IndexedDataMap::Iterator::Key");
0188       return myMap->FindKey(myIndex);
0189     }
0190 
0191     //! Performs comparison of two iterators.
0192     bool IsEqual(const Iterator& theOther) const noexcept
0193     {
0194       return myMap == theOther.myMap && myIndex == theOther.myIndex;
0195     }
0196 
0197     //! Returns current index (1-based).
0198     int Index() const noexcept { return myIndex; }
0199 
0200   private:
0201     NCollection_IndexedDataMap* myMap;   //!< Pointer to current node
0202     int                         myIndex; //!< Current index
0203   };
0204 
0205   //! Shorthand for a regular iterator type.
0206   typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheItemType, false> iterator;
0207 
0208   //! Shorthand for a constant iterator type.
0209   typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheItemType, true>
0210     const_iterator;
0211 
0212   //! Returns an iterator pointing to the first element in the map.
0213   iterator begin() const noexcept { return Iterator(*this); }
0214 
0215   //! Returns an iterator referring to the past-the-end element in the map.
0216   iterator end() const noexcept { return Iterator(); }
0217 
0218   //! Returns a const iterator pointing to the first element in the map.
0219   const_iterator cbegin() const noexcept { return Iterator(*this); }
0220 
0221   //! Returns a const iterator referring to the past-the-end element in the map.
0222   const_iterator cend() const noexcept { return Iterator(); }
0223 
0224 public:
0225   // **************** Key-value pair iteration support for structured bindings
0226 
0227   //! Key-value pair reference for structured binding support.
0228   //! Enables: for (auto [key, value] : map.Items())
0229   using KeyValueRef = NCollection_ItemsView::KeyValueRef<TheKeyType, TheItemType, false>;
0230 
0231   //! Const key-value pair reference for structured binding support.
0232   using ConstKeyValueRef = NCollection_ItemsView::KeyValueRef<TheKeyType, TheItemType, true>;
0233 
0234   //! Key-value-index tuple reference for structured binding support.
0235   //! Enables: for (auto [key, value, index] : map.IndexedItems())
0236   using KeyValueIndexRef = NCollection_ItemsView::KeyValueIndexRef<TheKeyType, TheItemType, false>;
0237 
0238   //! Const key-value-index tuple reference for structured binding support.
0239   using ConstKeyValueIndexRef =
0240     NCollection_ItemsView::KeyValueIndexRef<TheKeyType, TheItemType, true>;
0241 
0242 private:
0243   //! Extractor for mutable key-value pairs
0244   struct ItemsExtractor
0245   {
0246     static KeyValueRef Extract(const Iterator& theIter)
0247     {
0248       return {theIter.Key(), theIter.ChangeValue()};
0249     }
0250   };
0251 
0252   //! Extractor for const key-value pairs
0253   struct ConstItemsExtractor
0254   {
0255     static ConstKeyValueRef Extract(const Iterator& theIter)
0256     {
0257       return {theIter.Key(), theIter.Value()};
0258     }
0259   };
0260 
0261   //! Extractor for mutable key-value-index tuples
0262   struct IndexedItemsExtractor
0263   {
0264     static KeyValueIndexRef Extract(const Iterator& theIter)
0265     {
0266       return {theIter.Key(), theIter.ChangeValue(), theIter.Index()};
0267     }
0268   };
0269 
0270   //! Extractor for const key-value-index tuples
0271   struct ConstIndexedItemsExtractor
0272   {
0273     static ConstKeyValueIndexRef Extract(const Iterator& theIter)
0274     {
0275       return {theIter.Key(), theIter.Value(), theIter.Index()};
0276     }
0277   };
0278 
0279 public:
0280   //! View class for key-value pair iteration (mutable).
0281   using ItemsView =
0282     NCollection_ItemsView::View<NCollection_IndexedDataMap, KeyValueRef, ItemsExtractor, false>;
0283 
0284   //! View class for key-value pair iteration (const).
0285   using ConstItemsView = NCollection_ItemsView::
0286     View<NCollection_IndexedDataMap, ConstKeyValueRef, ConstItemsExtractor, true>;
0287 
0288   //! View class for key-value-index tuple iteration (mutable).
0289   using IndexedItemsView = NCollection_ItemsView::
0290     View<NCollection_IndexedDataMap, KeyValueIndexRef, IndexedItemsExtractor, false>;
0291 
0292   //! View class for key-value-index tuple iteration (const).
0293   using ConstIndexedItemsView = NCollection_ItemsView::
0294     View<NCollection_IndexedDataMap, ConstKeyValueIndexRef, ConstIndexedItemsExtractor, true>;
0295 
0296   //! Returns a view for key-value pair iteration.
0297   //! Usage: for (auto [aKey, aValue] : aMap.Items())
0298   ItemsView Items() { return ItemsView(*this); }
0299 
0300   //! Returns a const view for key-value pair iteration.
0301   //! Usage: for (const auto& [aKey, aValue] : aMap.Items())
0302   ConstItemsView Items() const { return ConstItemsView(*this); }
0303 
0304   //! Returns a view for key-value-index tuple iteration.
0305   //! Usage: for (auto [aKey, aValue, anIndex] : aMap.IndexedItems())
0306   IndexedItemsView IndexedItems() { return IndexedItemsView(*this); }
0307 
0308   //! Returns a const view for key-value-index tuple iteration.
0309   //! Usage: for (const auto& [aKey, aValue, anIndex] : aMap.IndexedItems())
0310   ConstIndexedItemsView IndexedItems() const { return ConstIndexedItemsView(*this); }
0311 
0312 public:
0313   // ---------- PUBLIC METHODS ------------
0314 
0315   //! Empty constructor.
0316   NCollection_IndexedDataMap()
0317       : NCollection_BaseMap(1, true, occ::handle<NCollection_BaseAllocator>())
0318   {
0319   }
0320 
0321   //! Constructor
0322   explicit NCollection_IndexedDataMap(
0323     const size_t                                  theNbBuckets,
0324     const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0325       : NCollection_BaseMap(theNbBuckets, true, theAllocator)
0326   {
0327   }
0328 
0329   //! Constructor (legacy int-taking).
0330   explicit NCollection_IndexedDataMap(
0331     const int                                     theNbBuckets,
0332     const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0333       : NCollection_IndexedDataMap(NCollection_BaseMap::NbBucketsFromInt(theNbBuckets),
0334                                    theAllocator)
0335   {
0336   }
0337 
0338   //! Constructor with custom hasher (copy).
0339   //! @param theHasher custom hasher instance
0340   //! @param theNbBuckets initial number of buckets
0341   //! @param theAllocator custom memory allocator
0342   explicit NCollection_IndexedDataMap(
0343     const Hasher&                                 theHasher,
0344     const size_t                                  theNbBuckets = 1,
0345     const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0346       : NCollection_BaseMap(theNbBuckets, true, theAllocator),
0347         myHasher(theHasher)
0348   {
0349   }
0350 
0351   //! Constructor with custom hasher (copy, legacy int-taking).
0352   explicit NCollection_IndexedDataMap(
0353     const Hasher&                                 theHasher,
0354     const int                                     theNbBuckets,
0355     const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0356       : NCollection_IndexedDataMap(theHasher,
0357                                    NCollection_BaseMap::NbBucketsFromInt(theNbBuckets),
0358                                    theAllocator)
0359   {
0360   }
0361 
0362   //! Constructor with custom hasher (move).
0363   //! @param theHasher custom hasher instance (moved)
0364   //! @param theNbBuckets initial number of buckets
0365   //! @param theAllocator custom memory allocator
0366   explicit NCollection_IndexedDataMap(
0367     Hasher&&                                      theHasher,
0368     const size_t                                  theNbBuckets = 1,
0369     const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0370       : NCollection_BaseMap(theNbBuckets, true, theAllocator),
0371         myHasher(std::move(theHasher))
0372   {
0373   }
0374 
0375   //! Constructor with custom hasher (move, legacy int-taking).
0376   explicit NCollection_IndexedDataMap(
0377     Hasher&&                                      theHasher,
0378     const int                                     theNbBuckets,
0379     const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0380       : NCollection_IndexedDataMap(std::move(theHasher),
0381                                    NCollection_BaseMap::NbBucketsFromInt(theNbBuckets),
0382                                    theAllocator)
0383   {
0384   }
0385 
0386   //! Copy constructor
0387   NCollection_IndexedDataMap(const NCollection_IndexedDataMap& theOther)
0388       : NCollection_BaseMap(theOther.NbBuckets(), true, theOther.myAllocator),
0389         myHasher(theOther.myHasher)
0390   {
0391     *this = theOther;
0392   }
0393 
0394   //! Move constructor
0395   NCollection_IndexedDataMap(NCollection_IndexedDataMap&& theOther) noexcept
0396       : NCollection_BaseMap(std::forward<NCollection_BaseMap>(theOther)),
0397         myHasher(std::move(theOther.myHasher))
0398   {
0399   }
0400 
0401   //! Exchange the content of two maps without re-allocations.
0402   //! Notice that allocators will be swapped as well!
0403   void Exchange(NCollection_IndexedDataMap& theOther) noexcept
0404   {
0405     this->exchangeMapsData(theOther);
0406     std::swap(myHasher, theOther.myHasher);
0407   }
0408 
0409   //! Returns const reference to the hasher.
0410   const Hasher& GetHasher() const noexcept { return myHasher; }
0411 
0412   //! Assignment.
0413   //! This method does not change the internal allocator.
0414   NCollection_IndexedDataMap& Assign(const NCollection_IndexedDataMap& theOther)
0415   {
0416     if (this == &theOther)
0417       return *this;
0418 
0419     Clear();
0420     int anExt = theOther.Extent();
0421     if (anExt)
0422     {
0423       ReSize(anExt - 1); // mySize is same after resize
0424       for (int anIndexIter = 1; anIndexIter <= anExt; ++anIndexIter)
0425       {
0426         const TheKeyType&   aKey1  = theOther.FindKey(anIndexIter);
0427         const TheItemType&  anItem = theOther.FindFromIndex(anIndexIter);
0428         const size_t        iK1    = HashCode(aKey1, NbBuckets());
0429         IndexedDataMapNode* pNode =
0430           new (this->myAllocator) IndexedDataMapNode(aKey1, anIndexIter, anItem, myData1[iK1]);
0431         myData1[iK1]             = pNode;
0432         myData2[anIndexIter - 1] = pNode;
0433         Increment();
0434       }
0435     }
0436     return *this;
0437   }
0438 
0439   //! Assignment operator
0440   NCollection_IndexedDataMap& operator=(const NCollection_IndexedDataMap& theOther)
0441   {
0442     return Assign(theOther);
0443   }
0444 
0445   //! Move operator
0446   NCollection_IndexedDataMap& operator=(NCollection_IndexedDataMap&& theOther) noexcept
0447   {
0448     if (this == &theOther)
0449       return *this;
0450     exchangeMapsData(theOther);
0451     return *this;
0452   }
0453 
0454   //! ReSize
0455   void ReSize(const size_t N)
0456   {
0457     NCollection_ListNode** ppNewData1 = nullptr;
0458     NCollection_ListNode** ppNewData2 = nullptr;
0459     size_t                 newBuck;
0460     if (BeginResize(N, newBuck, ppNewData1, ppNewData2))
0461     {
0462       if (myData1)
0463       {
0464         for (size_t aBucketIter = 0; aBucketIter <= NbBuckets(); ++aBucketIter)
0465         {
0466           if (myData1[aBucketIter])
0467           {
0468             IndexedDataMapNode* p = (IndexedDataMapNode*)myData1[aBucketIter];
0469             while (p)
0470             {
0471               const size_t        iK1 = HashCode(p->Key1(), newBuck);
0472               IndexedDataMapNode* q   = (IndexedDataMapNode*)p->Next();
0473               p->Next()               = ppNewData1[iK1];
0474               ppNewData1[iK1]         = p;
0475               p                       = q;
0476             }
0477           }
0478         }
0479       }
0480       EndResize(N,
0481                 newBuck,
0482                 ppNewData1,
0483                 (NCollection_ListNode**)
0484                   Standard::Reallocate(myData2, (newBuck + 1) * sizeof(NCollection_ListNode*)));
0485     }
0486   }
0487 
0488   void ReSize(const int N)
0489   {
0490     Standard_OutOfRange_Raise_if(N < 0, "NCollection_IndexedDataMap::ReSize: negative size");
0491     ReSize(static_cast<size_t>(N));
0492   }
0493 
0494   //! Returns the Index of already bound Key or appends new Key with specified Item value.
0495   //! @param theKey1 Key to search (and to bind, if it was not bound already)
0496   //! @param theItem Item value to set for newly bound Key; ignored if Key was already bound
0497   //! @return index of Key
0498   int Add(const TheKeyType& theKey1, const TheItemType& theItem)
0499   {
0500     return addImpl(theKey1, theItem);
0501   }
0502 
0503   //! Returns the Index of already bound Key or appends new Key with specified Item value.
0504   //! @param theKey1 Key to search (and to bind, if it was not bound already)
0505   //! @param theItem Item value to set for newly bound Key; ignored if Key was already bound
0506   //! @return index of Key
0507   int Add(TheKeyType&& theKey1, const TheItemType& theItem)
0508   {
0509     return addImpl(std::move(theKey1), theItem);
0510   }
0511 
0512   //! Returns the Index of already bound Key or appends new Key with specified Item value.
0513   //! @param theKey1 Key to search (and to bind, if it was not bound already)
0514   //! @param theItem Item value to set for newly bound Key; ignored if Key was already bound
0515   //! @return index of Key
0516   int Add(const TheKeyType& theKey1, TheItemType&& theItem)
0517   {
0518     return addImpl(theKey1, std::move(theItem));
0519   }
0520 
0521   //! Returns the Index of already bound Key or appends new Key with specified Item value.
0522   //! @param theKey1 Key to search (and to bind, if it was not bound already)
0523   //! @param theItem Item value to set for newly bound Key; ignored if Key was already bound
0524   //! @return index of Key
0525   int Add(TheKeyType&& theKey1, TheItemType&& theItem)
0526   {
0527     return addImpl(std::move(theKey1), std::move(theItem));
0528   }
0529 
0530   //! TryBound binds Item to Key only if Key is not yet bound.
0531   //! @param theKey1 key to add
0532   //! @param theItem item to bind if Key is not yet bound
0533   //! @return reference to existing or newly bound Item
0534   TheItemType& TryBound(const TheKeyType& theKey1, const TheItemType& theItem)
0535   {
0536     return bindImpl(theKey1, theItem, std::true_type{}, std::true_type{});
0537   }
0538 
0539   //! TryBound binds Item to Key only if Key is not yet bound.
0540   TheItemType& TryBound(TheKeyType&& theKey1, const TheItemType& theItem)
0541   {
0542     return bindImpl(std::move(theKey1), theItem, std::true_type{}, std::true_type{});
0543   }
0544 
0545   //! TryBound binds Item to Key only if Key is not yet bound.
0546   TheItemType& TryBound(const TheKeyType& theKey1, TheItemType&& theItem)
0547   {
0548     return bindImpl(theKey1, std::move(theItem), std::true_type{}, std::true_type{});
0549   }
0550 
0551   //! TryBound binds Item to Key only if Key is not yet bound.
0552   TheItemType& TryBound(TheKeyType&& theKey1, TheItemType&& theItem)
0553   {
0554     return bindImpl(std::move(theKey1), std::move(theItem), std::true_type{}, std::true_type{});
0555   }
0556 
0557   //! TryBind binds Item to Key only if Key is not yet bound.
0558   //! @param theKey1 key to add
0559   //! @param theItem item to bind if Key is not yet bound
0560   //! @return true if key was newly added, false if key already existed
0561   bool TryBind(const TheKeyType& theKey1, const TheItemType& theItem)
0562   {
0563     return bindImpl(theKey1, theItem, std::true_type{}, std::false_type{});
0564   }
0565 
0566   //! TryBind binds Item to Key only if Key is not yet bound.
0567   bool TryBind(TheKeyType&& theKey1, const TheItemType& theItem)
0568   {
0569     return bindImpl(std::move(theKey1), theItem, std::true_type{}, std::false_type{});
0570   }
0571 
0572   //! TryBind binds Item to Key only if Key is not yet bound.
0573   bool TryBind(const TheKeyType& theKey1, TheItemType&& theItem)
0574   {
0575     return bindImpl(theKey1, std::move(theItem), std::true_type{}, std::false_type{});
0576   }
0577 
0578   //! TryBind binds Item to Key only if Key is not yet bound.
0579   bool TryBind(TheKeyType&& theKey1, TheItemType&& theItem)
0580   {
0581     return bindImpl(std::move(theKey1), std::move(theItem), std::true_type{}, std::false_type{});
0582   }
0583 
0584   //! Bind binds Item to Key in map; overwrites value if Key already exists.
0585   //! @param theKey1 key to add/update
0586   //! @param theItem new item; overrides value previously bound to the key
0587   //! @return true if Key was not bound already
0588   bool Bind(const TheKeyType& theKey1, const TheItemType& theItem)
0589   {
0590     return bindImpl(theKey1, theItem, std::false_type{}, std::false_type{});
0591   }
0592 
0593   //! Bind binds Item to Key in map; overwrites value if Key already exists.
0594   bool Bind(TheKeyType&& theKey1, const TheItemType& theItem)
0595   {
0596     return bindImpl(std::move(theKey1), theItem, std::false_type{}, std::false_type{});
0597   }
0598 
0599   //! Bind binds Item to Key in map; overwrites value if Key already exists.
0600   bool Bind(const TheKeyType& theKey1, TheItemType&& theItem)
0601   {
0602     return bindImpl(theKey1, std::move(theItem), std::false_type{}, std::false_type{});
0603   }
0604 
0605   //! Bind binds Item to Key in map; overwrites value if Key already exists.
0606   bool Bind(TheKeyType&& theKey1, TheItemType&& theItem)
0607   {
0608     return bindImpl(std::move(theKey1), std::move(theItem), std::false_type{}, std::false_type{});
0609   }
0610 
0611   //! Bound binds Item to Key in map; overwrites value if Key already exists.
0612   //! @param theKey1 key to add/update
0613   //! @param theItem new item; overrides value previously bound to the key
0614   //! @return pointer to modifiable Item
0615   TheItemType* Bound(const TheKeyType& theKey1, const TheItemType& theItem)
0616   {
0617     return &bindImpl(theKey1, theItem, std::false_type{}, std::true_type{});
0618   }
0619 
0620   //! Bound binds Item to Key in map; overwrites value if Key already exists.
0621   TheItemType* Bound(TheKeyType&& theKey1, const TheItemType& theItem)
0622   {
0623     return &bindImpl(std::move(theKey1), theItem, std::false_type{}, std::true_type{});
0624   }
0625 
0626   //! Bound binds Item to Key in map; overwrites value if Key already exists.
0627   TheItemType* Bound(const TheKeyType& theKey1, TheItemType&& theItem)
0628   {
0629     return &bindImpl(theKey1, std::move(theItem), std::false_type{}, std::true_type{});
0630   }
0631 
0632   //! Bound binds Item to Key in map; overwrites value if Key already exists.
0633   TheItemType* Bound(TheKeyType&& theKey1, TheItemType&& theItem)
0634   {
0635     return &bindImpl(std::move(theKey1), std::move(theItem), std::false_type{}, std::true_type{});
0636   }
0637 
0638   //! Emplace constructs value in-place; if key exists, overwrites value.
0639   //! @param theKey1 key to add/update
0640   //! @param theArgs arguments forwarded to value constructor
0641   //! @return index of the key (new or existing)
0642   template <typename K, typename... Args>
0643   int Emplace(K&& theKey1, Args&&... theArgs)
0644   {
0645     return emplaceImpl(std::forward<K>(theKey1),
0646                        std::false_type{},
0647                        std::false_type{},
0648                        std::forward<Args>(theArgs)...);
0649   }
0650 
0651   //! Emplaced constructs value in-place; if key exists, destroys and reconstructs value.
0652   //! @param theKey1 key to add/update
0653   //! @param theArgs arguments forwarded to value constructor
0654   //! @return reference to the value (existing reconstructed or newly added)
0655   template <typename K, typename... Args>
0656   TheItemType& Emplaced(K&& theKey1, Args&&... theArgs)
0657   {
0658     return emplaceImpl(std::forward<K>(theKey1),
0659                        std::false_type{},
0660                        std::true_type{},
0661                        std::forward<Args>(theArgs)...);
0662   }
0663 
0664   //! TryEmplace constructs value in-place only if key not already bound.
0665   //! @param theKey1 key to add
0666   //! @param theArgs arguments forwarded to value constructor
0667   //! @return index of the key (new or existing)
0668   template <typename K, typename... Args>
0669   int TryEmplace(K&& theKey1, Args&&... theArgs)
0670   {
0671     return emplaceImpl(std::forward<K>(theKey1),
0672                        std::true_type{},
0673                        std::false_type{},
0674                        std::forward<Args>(theArgs)...);
0675   }
0676 
0677   //! TryEmplaced constructs value in-place only if key not already bound.
0678   //! @param theKey1 key to add
0679   //! @param theArgs arguments forwarded to value constructor
0680   //! @return reference to the value (existing or newly added)
0681   template <typename K, typename... Args>
0682   TheItemType& TryEmplaced(K&& theKey1, Args&&... theArgs)
0683   {
0684     return emplaceImpl(std::forward<K>(theKey1),
0685                        std::true_type{},
0686                        std::true_type{},
0687                        std::forward<Args>(theArgs)...);
0688   }
0689 
0690   //! Contains
0691   bool Contains(const TheKeyType& theKey1) const
0692   {
0693     IndexedDataMapNode* aNode;
0694     return static_cast<bool>(lookup(theKey1, aNode));
0695   }
0696 
0697   //! Contained returns optional pair of const references to key and value.
0698   //! Returns std::nullopt if the key is not found.
0699   std::optional<
0700     std::pair<std::reference_wrapper<const TheKeyType>, std::reference_wrapper<const TheItemType>>>
0701     Contained(const TheKeyType& theKey1) const
0702   {
0703     IndexedDataMapNode* aNode;
0704     if (!lookup(theKey1, aNode))
0705       return std::nullopt;
0706     return std::make_pair(std::cref(aNode->Key()), std::cref(aNode->Value()));
0707   }
0708 
0709   //! Contained returns optional pair of const key reference and mutable value reference.
0710   //! Returns std::nullopt if the key is not found.
0711   std::optional<
0712     std::pair<std::reference_wrapper<const TheKeyType>, std::reference_wrapper<TheItemType>>>
0713     Contained(const TheKeyType& theKey1)
0714   {
0715     IndexedDataMapNode* aNode;
0716     if (!lookup(theKey1, aNode))
0717       return std::nullopt;
0718     return std::make_pair(std::cref(aNode->Key()), std::ref(aNode->ChangeValue()));
0719   }
0720 
0721   //! Substitute
0722   void Substitute(const size_t theIndex, const TheKeyType& theKey1, const TheItemType& theItem)
0723   {
0724     Standard_OutOfRange_Raise_if(theIndex == 0 || theIndex > Size(),
0725                                  "NCollection_IndexedDataMap::Substitute : "
0726                                  "Index is out of range");
0727 
0728     // check if theKey1 is not already in the map
0729     size_t              aHash;
0730     IndexedDataMapNode* aNode;
0731     if (lookup(theKey1, aNode, aHash))
0732     {
0733       if (static_cast<size_t>(aNode->Index()) != theIndex)
0734       {
0735         throw Standard_DomainError("NCollection_IndexedDataMap::Substitute : "
0736                                    "Attempt to substitute existing key");
0737       }
0738       aNode->Key1()        = theKey1;
0739       aNode->ChangeValue() = theItem;
0740       return;
0741     }
0742 
0743     // Find the node for the index I
0744     aNode = (IndexedDataMapNode*)myData2[theIndex - 1];
0745 
0746     // remove the old key
0747     const size_t        iK = HashCode(aNode->Key1(), NbBuckets());
0748     IndexedDataMapNode* q  = (IndexedDataMapNode*)myData1[iK];
0749     if (q == aNode)
0750       myData1[iK] = (IndexedDataMapNode*)aNode->Next();
0751     else
0752     {
0753       while (q->Next() != aNode)
0754         q = (IndexedDataMapNode*)q->Next();
0755       q->Next() = aNode->Next();
0756     }
0757 
0758     // update the node
0759     aNode->Key1()        = theKey1;
0760     aNode->ChangeValue() = theItem;
0761     aNode->Next()        = myData1[aHash];
0762     myData1[aHash]       = aNode;
0763   }
0764 
0765   void Substitute(const int theIndex, const TheKeyType& theKey1, const TheItemType& theItem)
0766   {
0767     Standard_OutOfRange_Raise_if(theIndex < 0,
0768                                  "NCollection_IndexedDataMap::Substitute: negative index");
0769     Substitute(static_cast<size_t>(theIndex), theKey1, theItem);
0770   }
0771 
0772   //! Swaps two elements with the given indices.
0773   void Swap(const size_t theIndex1, const size_t theIndex2)
0774   {
0775     Standard_OutOfRange_Raise_if(theIndex1 == 0 || theIndex1 > Size() || theIndex2 == 0
0776                                    || theIndex2 > Size(),
0777                                  "NCollection_IndexedDataMap::Swap");
0778 
0779     if (theIndex1 == theIndex2)
0780     {
0781       return;
0782     }
0783 
0784     IndexedDataMapNode* aP1 = (IndexedDataMapNode*)myData2[theIndex1 - 1];
0785     IndexedDataMapNode* aP2 = (IndexedDataMapNode*)myData2[theIndex2 - 1];
0786     std::swap(aP1->Index(), aP2->Index());
0787     myData2[theIndex2 - 1] = aP1;
0788     myData2[theIndex1 - 1] = aP2;
0789   }
0790 
0791   void Swap(const int theIndex1, const int theIndex2)
0792   {
0793     Standard_OutOfRange_Raise_if(theIndex1 < 0 || theIndex2 < 0,
0794                                  "NCollection_IndexedDataMap::Swap: negative index");
0795     Swap(static_cast<size_t>(theIndex1), static_cast<size_t>(theIndex2));
0796   }
0797 
0798   //! RemoveLast
0799   void RemoveLast()
0800   {
0801     const size_t aLastIndex = Size();
0802     Standard_OutOfRange_Raise_if(aLastIndex == 0, "NCollection_IndexedDataMap::RemoveLast");
0803 
0804     // Find the node for the last index and remove it
0805     IndexedDataMapNode* p   = (IndexedDataMapNode*)myData2[aLastIndex - 1];
0806     myData2[aLastIndex - 1] = nullptr;
0807 
0808     // remove the key
0809     const size_t        iK1 = HashCode(p->Key1(), NbBuckets());
0810     IndexedDataMapNode* q   = (IndexedDataMapNode*)myData1[iK1];
0811     if (q == p)
0812       myData1[iK1] = (IndexedDataMapNode*)p->Next();
0813     else
0814     {
0815       while (q->Next() != p)
0816         q = (IndexedDataMapNode*)q->Next();
0817       q->Next() = p->Next();
0818     }
0819     p->~IndexedDataMapNode();
0820     this->myAllocator->Free(p);
0821     Decrement();
0822   }
0823 
0824   //! Remove the key of the given index.
0825   //! Caution! The index of the last key can be changed.
0826   void RemoveFromIndex(const size_t theIndex)
0827   {
0828     const size_t aLastInd = Size();
0829     Standard_OutOfRange_Raise_if(theIndex == 0 || theIndex > aLastInd,
0830                                  "NCollection_IndexedDataMap::Remove");
0831     if (theIndex != aLastInd)
0832     {
0833       Swap(theIndex, aLastInd);
0834     }
0835     RemoveLast();
0836   }
0837 
0838   void RemoveFromIndex(const int theIndex)
0839   {
0840     Standard_OutOfRange_Raise_if(theIndex < 0,
0841                                  "NCollection_IndexedDataMap::RemoveFromIndex: negative index");
0842     RemoveFromIndex(static_cast<size_t>(theIndex));
0843   }
0844 
0845   //! Remove the given key.
0846   //! Caution! The index of the last key can be changed.
0847   void RemoveKey(const TheKeyType& theKey1)
0848   {
0849     int anIndToRemove = FindIndex(theKey1);
0850     if (anIndToRemove > 0)
0851     {
0852       RemoveFromIndex(static_cast<size_t>(anIndToRemove));
0853     }
0854   }
0855 
0856   //! FindKey
0857   const TheKeyType& FindKey(const size_t theIndex) const
0858   {
0859     Standard_OutOfRange_Raise_if(theIndex == 0 || theIndex > Size(),
0860                                  "NCollection_IndexedDataMap::FindKey");
0861     IndexedDataMapNode* aNode = (IndexedDataMapNode*)myData2[theIndex - 1];
0862     return aNode->Key1();
0863   }
0864 
0865   const TheKeyType& FindKey(const int theIndex) const
0866   {
0867     Standard_OutOfRange_Raise_if(theIndex < 0,
0868                                  "NCollection_IndexedDataMap::FindKey: negative index");
0869     return FindKey(static_cast<size_t>(theIndex));
0870   }
0871 
0872   //! FindFromIndex
0873   const TheItemType& FindFromIndex(const size_t theIndex) const
0874   {
0875     Standard_OutOfRange_Raise_if(theIndex == 0 || theIndex > Size(),
0876                                  "NCollection_IndexedDataMap::FindFromIndex");
0877     IndexedDataMapNode* aNode = (IndexedDataMapNode*)myData2[theIndex - 1];
0878     return aNode->Value();
0879   }
0880 
0881   const TheItemType& FindFromIndex(const int theIndex) const
0882   {
0883     Standard_OutOfRange_Raise_if(theIndex < 0,
0884                                  "NCollection_IndexedDataMap::FindFromIndex: negative index");
0885     return FindFromIndex(static_cast<size_t>(theIndex));
0886   }
0887 
0888   //! operator ()
0889   const TheItemType& operator()(const size_t theIndex) const { return FindFromIndex(theIndex); }
0890 
0891   const TheItemType& operator()(const int theIndex) const { return FindFromIndex(theIndex); }
0892 
0893   //! ChangeFromIndex
0894   TheItemType& ChangeFromIndex(const size_t theIndex)
0895   {
0896     Standard_OutOfRange_Raise_if(theIndex == 0 || theIndex > Size(),
0897                                  "NCollection_IndexedDataMap::ChangeFromIndex");
0898     IndexedDataMapNode* aNode = (IndexedDataMapNode*)myData2[theIndex - 1];
0899     return aNode->ChangeValue();
0900   }
0901 
0902   TheItemType& ChangeFromIndex(const int theIndex)
0903   {
0904     Standard_OutOfRange_Raise_if(theIndex < 0,
0905                                  "NCollection_IndexedDataMap::ChangeFromIndex: negative index");
0906     return ChangeFromIndex(static_cast<size_t>(theIndex));
0907   }
0908 
0909   //! operator ()
0910   TheItemType& operator()(const size_t theIndex) { return ChangeFromIndex(theIndex); }
0911 
0912   TheItemType& operator()(const int theIndex) { return ChangeFromIndex(theIndex); }
0913 
0914   //! FindIndex
0915   int FindIndex(const TheKeyType& theKey1) const
0916   {
0917     IndexedDataMapNode* aNode;
0918     if (lookup(theKey1, aNode))
0919     {
0920       return aNode->Index();
0921     }
0922     return 0;
0923   }
0924 
0925   //! FindFromKey
0926   const TheItemType& FindFromKey(const TheKeyType& theKey1) const
0927   {
0928     Standard_NoSuchObject_Raise_if(IsEmpty(), "NCollection_IndexedDataMap::FindFromKey");
0929     IndexedDataMapNode* aNode;
0930     if (lookup(theKey1, aNode))
0931     {
0932       return aNode->Value();
0933     }
0934     throw Standard_NoSuchObject("NCollection_IndexedDataMap::FindFromKey");
0935   }
0936 
0937   //! ChangeFromKey
0938   TheItemType& ChangeFromKey(const TheKeyType& theKey1)
0939   {
0940     Standard_NoSuchObject_Raise_if(IsEmpty(), "NCollection_IndexedDataMap::ChangeFromKey");
0941     IndexedDataMapNode* aNode;
0942     if (lookup(theKey1, aNode))
0943     {
0944       return aNode->ChangeValue();
0945     }
0946     throw Standard_NoSuchObject("NCollection_IndexedDataMap::ChangeFromKey");
0947   }
0948 
0949   //! Seek returns pointer to Item by Key. Returns
0950   //! NULL if Key was not found.
0951   const TheItemType* Seek(const TheKeyType& theKey1) const
0952   {
0953     return const_cast<NCollection_IndexedDataMap*>(this)->ChangeSeek(theKey1);
0954   }
0955 
0956   //! ChangeSeek returns modifiable pointer to Item by Key. Returns
0957   //! NULL if Key was not found.
0958   TheItemType* ChangeSeek(const TheKeyType& theKey1)
0959   {
0960     IndexedDataMapNode* aNode;
0961     if (lookup(theKey1, aNode))
0962     {
0963       return &aNode->ChangeValue();
0964     }
0965     return nullptr;
0966   }
0967 
0968   //! Find value for key with copying.
0969   //! @return true if key was found
0970   bool FindFromKey(const TheKeyType& theKey1, TheItemType& theValue) const
0971   {
0972     IndexedDataMapNode* aNode;
0973     if (lookup(theKey1, aNode))
0974     {
0975       theValue = aNode->Value();
0976       return true;
0977     }
0978     return false;
0979   }
0980 
0981   //! Clear data. If doReleaseMemory is false then the table of
0982   //! buckets is not released and will be reused.
0983   void Clear(const bool doReleaseMemory = false)
0984   {
0985     Destroy(IndexedDataMapNode::delNode, doReleaseMemory);
0986   }
0987 
0988   //! Clear data and reset allocator
0989   void Clear(const occ::handle<NCollection_BaseAllocator>& theAllocator)
0990   {
0991     Clear(theAllocator != this->myAllocator);
0992     this->myAllocator =
0993       (!theAllocator.IsNull() ? theAllocator : NCollection_BaseAllocator::CommonBaseAllocator());
0994   }
0995 
0996   //! Destructor
0997   ~NCollection_IndexedDataMap() override { Clear(true); }
0998 
0999 protected:
1000   //! Lookup for particular key in map.
1001   //! @param[in] theKey key to compute hash
1002   //! @param[out] theNode the detected node with equal key. Can be null.
1003   //! @param[out] theHash computed bounded hash code for current key.
1004   //! @return true if key is found
1005   bool lookup(const TheKeyType& theKey, IndexedDataMapNode*& theNode, size_t& theHash) const
1006   {
1007     theHash = HashCode(theKey, NbBuckets());
1008     if (IsEmpty())
1009       return false; // Not found
1010     for (theNode = (IndexedDataMapNode*)myData1[theHash]; theNode;
1011          theNode = (IndexedDataMapNode*)theNode->Next())
1012     {
1013       if (IsEqual(theNode->Key1(), theKey))
1014         return true;
1015     }
1016     return false; // Not found
1017   }
1018 
1019   //! Lookup for particular key in map.
1020   //! @param[in] theKey key to compute hash
1021   //! @param[out] theNode the detected node with equal key. Can be null.
1022   //! @return true if key is found
1023   bool lookup(const TheKeyType& theKey, IndexedDataMapNode*& theNode) const
1024   {
1025     if (IsEmpty())
1026       return false; // Not found
1027     for (theNode = (IndexedDataMapNode*)myData1[HashCode(theKey, NbBuckets())]; theNode;
1028          theNode = (IndexedDataMapNode*)theNode->Next())
1029     {
1030       if (IsEqual(theNode->Key1(), theKey))
1031       {
1032         return true;
1033       }
1034     }
1035     return false; // Not found
1036   }
1037 
1038   bool IsEqual(const TheKeyType& theKey1, const TheKeyType& theKey2) const
1039   {
1040     return myHasher(theKey1, theKey2);
1041   }
1042 
1043   size_t HashCode(const TheKeyType& theKey, const size_t theUpperBound) const
1044   {
1045     return myHasher(theKey) % theUpperBound + 1;
1046   }
1047 
1048   //! Implementation helper for Add (returns index).
1049   //! @tparam K forwarding reference type for key
1050   //! @tparam V forwarding reference type for value
1051   //! @param theKey1 key to add
1052   //! @param theItem item to bind
1053   //! @return index of the key (new or existing)
1054   template <typename K, typename V>
1055   int addImpl(K&& theKey1, V&& theItem)
1056   {
1057     if (Resizable())
1058     {
1059       ReSize(Extent());
1060     }
1061     IndexedDataMapNode* aNode;
1062     size_t              aHash;
1063     if (lookup(theKey1, aNode, aHash))
1064     {
1065       return aNode->Index();
1066     }
1067     const int aNewIndex    = Extent() + 1;
1068     aNode                  = new (this->myAllocator) IndexedDataMapNode(std::forward<K>(theKey1),
1069                                                        aNewIndex,
1070                                                        std::forward<V>(theItem),
1071                                                        myData1[aHash]);
1072     myData1[aHash]         = aNode;
1073     myData2[aNewIndex - 1] = aNode;
1074     Increment();
1075     return aNewIndex;
1076   }
1077 
1078   //! Implementation helper for Emplace/TryEmplace operations.
1079   //! @tparam K forwarding reference type for key
1080   //! @tparam IsTry if true, does not modify existing; if false, overwrites
1081   //! @tparam ReturnRef if true, returns reference; if false, returns int (index)
1082   //! @param theKey1 key to add/update
1083   //! @param theArgs arguments forwarded to value constructor
1084   //! @return int (index) or TheItemType& depending on ReturnRef
1085   template <typename K, bool IsTry, bool ReturnRef, typename... Args>
1086   auto emplaceImpl(K&& theKey1,
1087                    std::bool_constant<IsTry>,
1088                    std::bool_constant<ReturnRef>,
1089                    Args&&... theArgs) -> std::conditional_t<ReturnRef, TheItemType&, int>
1090   {
1091     if (Resizable())
1092       ReSize(Extent());
1093     IndexedDataMapNode* aNode;
1094     size_t              aHash;
1095     if (lookup(theKey1, aNode, aHash))
1096     {
1097       if constexpr (!IsTry)
1098         aNode->ChangeValue() = TheItemType(std::forward<Args>(theArgs)...);
1099       if constexpr (ReturnRef)
1100         return aNode->ChangeValue();
1101       else
1102         return aNode->Index();
1103     }
1104     const int aNewIndex    = Extent() + 1;
1105     aNode                  = new (this->myAllocator) IndexedDataMapNode(std::forward<K>(theKey1),
1106                                                        aNewIndex,
1107                                                        std::in_place,
1108                                                        myData1[aHash],
1109                                                        std::forward<Args>(theArgs)...);
1110     myData1[aHash]         = aNode;
1111     myData2[aNewIndex - 1] = aNode;
1112     Increment();
1113     if constexpr (ReturnRef)
1114       return aNode->ChangeValue();
1115     else
1116       return aNewIndex;
1117   }
1118 
1119   //! Implementation helper for Bind/TryBind/Bound/TryBound operations.
1120   //! @tparam K forwarding reference type for key
1121   //! @tparam V forwarding reference type for value
1122   //! @tparam IsTry if true, does not modify existing; if false, overwrites
1123   //! @tparam ReturnRef if true, returns reference; if false, returns bool
1124   //! @return bool or TheItemType& depending on ReturnRef
1125   template <typename K, typename V, bool IsTry, bool ReturnRef>
1126   auto bindImpl(K&& theKey1, V&& theItem, std::bool_constant<IsTry>, std::bool_constant<ReturnRef>)
1127     -> std::conditional_t<ReturnRef, TheItemType&, bool>
1128   {
1129     if (Resizable())
1130       ReSize(Extent());
1131     IndexedDataMapNode* aNode;
1132     size_t              aHash;
1133     if (lookup(theKey1, aNode, aHash))
1134     {
1135       if constexpr (!IsTry)
1136         aNode->ChangeValue() = std::forward<V>(theItem);
1137       if constexpr (ReturnRef)
1138         return aNode->ChangeValue();
1139       else
1140         return false;
1141     }
1142     const int aNewIndex    = Extent() + 1;
1143     aNode                  = new (this->myAllocator) IndexedDataMapNode(std::forward<K>(theKey1),
1144                                                        aNewIndex,
1145                                                        std::forward<V>(theItem),
1146                                                        myData1[aHash]);
1147     myData1[aHash]         = aNode;
1148     myData2[aNewIndex - 1] = aNode;
1149     Increment();
1150     if constexpr (ReturnRef)
1151       return aNode->ChangeValue();
1152     else
1153       return true;
1154   }
1155 
1156 protected:
1157   Hasher myHasher;
1158 };
1159 
1160 #endif