Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-26 09:04:03

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_DataMap_HeaderFile
0017 #define NCollection_DataMap_HeaderFile
0018 
0019 #include <NCollection_BaseMap.hxx>
0020 #include <NCollection_TListNode.hxx>
0021 #include <NCollection_StlIterator.hxx>
0022 #include <NCollection_DefaultHasher.hxx>
0023 #include <NCollection_ItemsView.hxx>
0024 
0025 #include <Standard_TypeMismatch.hxx>
0026 #include <Standard_NoSuchObject.hxx>
0027 #include <Standard_OutOfRange.hxx>
0028 #include <functional>
0029 #include <optional>
0030 #include <type_traits>
0031 #include <utility>
0032 
0033 #include <Message.hxx>
0034 
0035 /**
0036  * Purpose:     The DataMap is a Map to store keys with associated
0037  *              Items. See Map  from NCollection for  a discussion
0038  *              about the number of buckets.
0039  *
0040  *              The DataMap can be seen as an extended array where
0041  *              the Keys  are the   indices.  For this reason  the
0042  *              operator () is defined on DataMap to fetch an Item
0043  *              from a Key. So the following syntax can be used :
0044  *
0045  *              anItem = aMap(aKey);
0046  *              aMap(aKey) = anItem;
0047  *
0048  *              This analogy has its  limit.   aMap(aKey) = anItem
0049  *              can  be done only  if aKey was previously bound to
0050  *              an item in the map.
0051  */
0052 
0053 template <class TheKeyType, class TheItemType, class Hasher = NCollection_DefaultHasher<TheKeyType>>
0054 class NCollection_DataMap : public NCollection_BaseMap
0055 {
0056 public:
0057   //! STL-compliant typedef for key type
0058   typedef TheKeyType key_type;
0059   //! STL-compliant typedef for value type
0060   typedef TheItemType value_type;
0061 
0062 public:
0063   // **************** Adaptation of the TListNode to the DATAmap
0064   class DataMapNode : public NCollection_TListNode<TheItemType>
0065   {
0066   public:
0067     //! Constructor with 'Next'
0068     DataMapNode(const TheKeyType& theKey, const TheItemType& theItem, NCollection_ListNode* theNext)
0069         : NCollection_TListNode<TheItemType>(theItem, theNext),
0070           myKey(theKey)
0071     {
0072     }
0073 
0074     //! Constructor with 'Next'
0075     DataMapNode(const TheKeyType& theKey, TheItemType&& theItem, NCollection_ListNode* theNext)
0076         : NCollection_TListNode<TheItemType>(std::forward<TheItemType>(theItem), theNext),
0077           myKey(theKey)
0078     {
0079     }
0080 
0081     //! Constructor with 'Next'
0082     DataMapNode(TheKeyType&& theKey, const TheItemType& theItem, NCollection_ListNode* theNext)
0083         : NCollection_TListNode<TheItemType>(theItem, theNext),
0084           myKey(std::forward<TheKeyType>(theKey))
0085     {
0086     }
0087 
0088     //! Constructor with 'Next'
0089     DataMapNode(TheKeyType&& theKey, TheItemType&& theItem, NCollection_ListNode* theNext)
0090         : NCollection_TListNode<TheItemType>(std::forward<TheItemType>(theItem), theNext),
0091           myKey(std::forward<TheKeyType>(theKey))
0092     {
0093     }
0094 
0095     //! Constructor with in-place value construction
0096     template <typename K, typename... Args>
0097     DataMapNode(K&& theKey, std::in_place_t, NCollection_ListNode* theNext, Args&&... theArgs)
0098         : NCollection_TListNode<TheItemType>(std::in_place,
0099                                              theNext,
0100                                              std::forward<Args>(theArgs)...),
0101           myKey(std::forward<K>(theKey))
0102     {
0103     }
0104 
0105     //! Key
0106     const TheKeyType& Key() const noexcept { return myKey; }
0107 
0108     //! Static deleter to be passed to BaseMap
0109     static void delNode(NCollection_ListNode*                   theNode,
0110                         occ::handle<NCollection_BaseAllocator>& theAl) noexcept
0111     {
0112       ((DataMapNode*)theNode)->~DataMapNode();
0113       theAl->Free(theNode);
0114     }
0115 
0116   private:
0117     TheKeyType myKey;
0118   };
0119 
0120 public:
0121   // **************** Implementation of the Iterator interface.
0122   class Iterator : public NCollection_BaseMap::Iterator
0123   {
0124   public:
0125     //! Empty constructor
0126     Iterator()
0127         : NCollection_BaseMap::Iterator()
0128     {
0129     }
0130 
0131     //! Constructor
0132     Iterator(const NCollection_DataMap& theMap)
0133         : NCollection_BaseMap::Iterator(theMap)
0134     {
0135     }
0136 
0137     //! Query if the end of collection is reached by iterator
0138     bool More() const noexcept { return PMore(); }
0139 
0140     //! Make a step along the collection
0141     void Next() noexcept { PNext(); }
0142 
0143     //! Value inquiry
0144     const TheItemType& Value() const
0145     {
0146       Standard_NoSuchObject_Raise_if(!More(), "NCollection_DataMap::Iterator::Value");
0147       return ((DataMapNode*)myNode)->Value();
0148     }
0149 
0150     //! Value change access
0151     TheItemType& ChangeValue() const
0152     {
0153       Standard_NoSuchObject_Raise_if(!More(), "NCollection_DataMap::Iterator::ChangeValue");
0154       return ((DataMapNode*)myNode)->ChangeValue();
0155     }
0156 
0157     //! Key
0158     const TheKeyType& Key() const
0159     {
0160       Standard_NoSuchObject_Raise_if(!More(), "NCollection_DataMap::Iterator::Key");
0161       return ((DataMapNode*)myNode)->Key();
0162     }
0163   };
0164 
0165   //! Shorthand for a regular iterator type.
0166   typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheItemType, false> iterator;
0167 
0168   //! Shorthand for a constant iterator type.
0169   typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheItemType, true>
0170     const_iterator;
0171 
0172   //! Returns an iterator pointing to the first element in the map.
0173   iterator begin() const noexcept { return Iterator(*this); }
0174 
0175   //! Returns an iterator referring to the past-the-end element in the map.
0176   iterator end() const noexcept { return Iterator(); }
0177 
0178   //! Returns a const iterator pointing to the first element in the map.
0179   const_iterator cbegin() const noexcept { return Iterator(*this); }
0180 
0181   //! Returns a const iterator referring to the past-the-end element in the map.
0182   const_iterator cend() const noexcept { return Iterator(); }
0183 
0184 public:
0185   // **************** Key-value pair iteration support for structured bindings
0186 
0187   //! Key-value pair reference for structured binding support.
0188   //! Enables: for (auto [key, value] : map.Items())
0189   using KeyValueRef = NCollection_ItemsView::KeyValueRef<TheKeyType, TheItemType, false>;
0190 
0191   //! Const key-value pair reference for structured binding support.
0192   using ConstKeyValueRef = NCollection_ItemsView::KeyValueRef<TheKeyType, TheItemType, true>;
0193 
0194 private:
0195   //! Extractor for mutable key-value pairs
0196   struct ItemsExtractor
0197   {
0198     static KeyValueRef Extract(const Iterator& theIter)
0199     {
0200       return {theIter.Key(), theIter.ChangeValue()};
0201     }
0202   };
0203 
0204   //! Extractor for const key-value pairs
0205   struct ConstItemsExtractor
0206   {
0207     static ConstKeyValueRef Extract(const Iterator& theIter)
0208     {
0209       return {theIter.Key(), theIter.Value()};
0210     }
0211   };
0212 
0213 public:
0214   //! View class for key-value pair iteration (mutable).
0215   using ItemsView =
0216     NCollection_ItemsView::View<NCollection_DataMap, KeyValueRef, ItemsExtractor, false>;
0217 
0218   //! View class for key-value pair iteration (const).
0219   using ConstItemsView =
0220     NCollection_ItemsView::View<NCollection_DataMap, ConstKeyValueRef, ConstItemsExtractor, true>;
0221 
0222   //! Returns a view for key-value pair iteration.
0223   //! Usage: for (auto [aKey, aValue] : aMap.Items())
0224   ItemsView Items() { return ItemsView(*this); }
0225 
0226   //! Returns a const view for key-value pair iteration.
0227   //! Usage: for (const auto& [aKey, aValue] : aMap.Items())
0228   ConstItemsView Items() const { return ConstItemsView(*this); }
0229 
0230 public:
0231   // ---------- PUBLIC METHODS ------------
0232 
0233   //! Empty Constructor.
0234   NCollection_DataMap()
0235       : NCollection_BaseMap(1, true, occ::handle<NCollection_BaseAllocator>())
0236   {
0237   }
0238 
0239   //! Constructor
0240   explicit NCollection_DataMap(const size_t                                  theNbBuckets,
0241                                const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0242       : NCollection_BaseMap(theNbBuckets, true, theAllocator)
0243   {
0244   }
0245 
0246   //! Constructor (legacy int-taking).
0247   explicit NCollection_DataMap(const int                                     theNbBuckets,
0248                                const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0249       : NCollection_DataMap(NCollection_BaseMap::NbBucketsFromInt(theNbBuckets), theAllocator)
0250   {
0251   }
0252 
0253   //! Constructor with custom hasher (copy).
0254   //! @param theHasher custom hasher instance
0255   //! @param theNbBuckets initial number of buckets
0256   //! @param theAllocator custom memory allocator
0257   explicit NCollection_DataMap(const Hasher&                                 theHasher,
0258                                const size_t                                  theNbBuckets = 1,
0259                                const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0260       : NCollection_BaseMap(theNbBuckets, true, theAllocator),
0261         myHasher(theHasher)
0262   {
0263   }
0264 
0265   //! Constructor with custom hasher (copy, legacy int-taking).
0266   explicit NCollection_DataMap(const Hasher&                                 theHasher,
0267                                const int                                     theNbBuckets,
0268                                const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0269       : NCollection_DataMap(theHasher,
0270                             NCollection_BaseMap::NbBucketsFromInt(theNbBuckets),
0271                             theAllocator)
0272   {
0273   }
0274 
0275   //! Constructor with custom hasher (move).
0276   //! @param theHasher custom hasher instance (moved)
0277   //! @param theNbBuckets initial number of buckets
0278   //! @param theAllocator custom memory allocator
0279   explicit NCollection_DataMap(Hasher&&                                      theHasher,
0280                                const size_t                                  theNbBuckets = 1,
0281                                const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0282       : NCollection_BaseMap(theNbBuckets, true, theAllocator),
0283         myHasher(std::move(theHasher))
0284   {
0285   }
0286 
0287   //! Constructor with custom hasher (move, legacy int-taking).
0288   explicit NCollection_DataMap(Hasher&&                                      theHasher,
0289                                const int                                     theNbBuckets,
0290                                const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0291       : NCollection_DataMap(std::move(theHasher),
0292                             NCollection_BaseMap::NbBucketsFromInt(theNbBuckets),
0293                             theAllocator)
0294   {
0295   }
0296 
0297   //! Copy constructor
0298   NCollection_DataMap(const NCollection_DataMap& theOther)
0299       : NCollection_BaseMap(theOther.NbBuckets(), true, theOther.myAllocator),
0300         myHasher(theOther.myHasher)
0301   {
0302     const int anExt = theOther.Extent();
0303     if (anExt <= 0)
0304       return;
0305     ReSize(anExt - 1);
0306     for (Iterator anIter(theOther); anIter.More(); anIter.Next())
0307       Bind(anIter.Key(), anIter.Value());
0308   }
0309 
0310   //! Move constructor
0311   NCollection_DataMap(NCollection_DataMap&& theOther) noexcept
0312       : NCollection_BaseMap(std::forward<NCollection_BaseMap>(theOther)),
0313         myHasher(std::move(theOther.myHasher))
0314   {
0315   }
0316 
0317   //! Exchange the content of two maps without re-allocations.
0318   //! Notice that allocators will be swapped as well!
0319   void Exchange(NCollection_DataMap& theOther) noexcept
0320   {
0321     this->exchangeMapsData(theOther);
0322     std::swap(myHasher, theOther.myHasher);
0323   }
0324 
0325   //! Returns const reference to the hasher.
0326   const Hasher& GetHasher() const noexcept { return myHasher; }
0327 
0328   //! Assignment.
0329   //! This method does not change the internal allocator.
0330   NCollection_DataMap& Assign(const NCollection_DataMap& theOther)
0331   {
0332     if (this == &theOther)
0333       return *this;
0334 
0335     Clear();
0336     int anExt = theOther.Extent();
0337     if (anExt)
0338     {
0339       ReSize(anExt - 1);
0340       Iterator anIter(theOther);
0341       for (; anIter.More(); anIter.Next())
0342         Bind(anIter.Key(), anIter.Value());
0343     }
0344     return *this;
0345   }
0346 
0347   //! Assignment operator
0348   NCollection_DataMap& operator=(const NCollection_DataMap& theOther) { return Assign(theOther); }
0349 
0350   //! Move operator
0351   NCollection_DataMap& operator=(NCollection_DataMap&& theOther) noexcept
0352   {
0353     if (this == &theOther)
0354       return *this;
0355     exchangeMapsData(theOther);
0356     return *this;
0357   }
0358 
0359   //! ReSize
0360   void ReSize(const size_t N)
0361   {
0362     NCollection_ListNode** newdata = nullptr;
0363     NCollection_ListNode** dummy   = nullptr;
0364     size_t                 newBuck;
0365     if (BeginResize(N, newBuck, newdata, dummy))
0366     {
0367       if (myData1)
0368       {
0369         DataMapNode** olddata = (DataMapNode**)myData1;
0370         DataMapNode * p, *q;
0371         for (size_t i = 0; i <= NbBuckets(); ++i)
0372         {
0373           if (olddata[i])
0374           {
0375             p = olddata[i];
0376             while (p)
0377             {
0378               const size_t k = HashCode(p->Key(), newBuck);
0379               q              = (DataMapNode*)p->Next();
0380               p->Next()      = newdata[k];
0381               newdata[k]     = p;
0382               p              = q;
0383             }
0384           }
0385         }
0386       }
0387       EndResize(N, newBuck, newdata, dummy);
0388     }
0389   }
0390 
0391   void ReSize(const int N)
0392   {
0393     Standard_OutOfRange_Raise_if(N < 0, "NCollection_DataMap::ReSize: negative size");
0394     ReSize(static_cast<size_t>(N));
0395   }
0396 
0397   //! Bind binds Item to Key in map.
0398   //! @param theKey  key to add/update
0399   //! @param theItem new item; overrides value previously bound to the key (uses
0400   //! destroy+reconstruct)
0401   //! @return true if Key was not bound already
0402   bool Bind(const TheKeyType& theKey, const TheItemType& theItem)
0403   {
0404     return emplaceImpl(theKey, std::false_type{}, std::false_type{}, theItem);
0405   }
0406 
0407   //! Bind binds Item to Key in map.
0408   //! @param theKey  key to add/update
0409   //! @param theItem new item; overrides value previously bound to the key (uses
0410   //! destroy+reconstruct)
0411   //! @return true if Key was not bound already
0412   bool Bind(TheKeyType&& theKey, const TheItemType& theItem)
0413   {
0414     return emplaceImpl(std::move(theKey), std::false_type{}, std::false_type{}, theItem);
0415   }
0416 
0417   //! Bind binds Item to Key in map.
0418   //! @param theKey  key to add/update
0419   //! @param theItem new item; overrides value previously bound to the key (uses
0420   //! destroy+reconstruct)
0421   //! @return true if Key was not bound already
0422   bool Bind(const TheKeyType& theKey, TheItemType&& theItem)
0423   {
0424     return emplaceImpl(theKey, std::false_type{}, std::false_type{}, std::move(theItem));
0425   }
0426 
0427   //! Bind binds Item to Key in map.
0428   //! @param theKey  key to add/update
0429   //! @param theItem new item; overrides value previously bound to the key (uses
0430   //! destroy+reconstruct)
0431   //! @return true if Key was not bound already
0432   bool Bind(TheKeyType&& theKey, TheItemType&& theItem)
0433   {
0434     return emplaceImpl(std::move(theKey), std::false_type{}, std::false_type{}, std::move(theItem));
0435   }
0436 
0437   //! Bound binds Item to Key in map.
0438   //! @param theKey  key to add/update
0439   //! @param theItem new item; overrides value previously bound to the key (uses
0440   //! destroy+reconstruct)
0441   //! @return pointer to modifiable Item
0442   TheItemType* Bound(const TheKeyType& theKey, const TheItemType& theItem)
0443   {
0444     return &emplaceImpl(theKey, std::false_type{}, std::true_type{}, theItem);
0445   }
0446 
0447   //! Bound binds Item to Key in map.
0448   //! @param theKey  key to add/update
0449   //! @param theItem new item; overrides value previously bound to the key (uses
0450   //! destroy+reconstruct)
0451   //! @return pointer to modifiable Item
0452   TheItemType* Bound(TheKeyType&& theKey, const TheItemType& theItem)
0453   {
0454     return &emplaceImpl(std::move(theKey), std::false_type{}, std::true_type{}, theItem);
0455   }
0456 
0457   //! Bound binds Item to Key in map.
0458   //! @param theKey  key to add/update
0459   //! @param theItem new item; overrides value previously bound to the key (uses
0460   //! destroy+reconstruct)
0461   //! @return pointer to modifiable Item
0462   TheItemType* Bound(const TheKeyType& theKey, TheItemType&& theItem)
0463   {
0464     return &emplaceImpl(theKey, std::false_type{}, std::true_type{}, std::move(theItem));
0465   }
0466 
0467   //! Bound binds Item to Key in map.
0468   //! @param theKey  key to add/update
0469   //! @param theItem new item; overrides value previously bound to the key (uses
0470   //! destroy+reconstruct)
0471   //! @return pointer to modifiable Item
0472   TheItemType* Bound(TheKeyType&& theKey, TheItemType&& theItem)
0473   {
0474     return &emplaceImpl(std::move(theKey), std::false_type{}, std::true_type{}, std::move(theItem));
0475   }
0476 
0477   //! TryBind binds Item to Key in map only if Key is not yet bound.
0478   //! @param theKey  key to add
0479   //! @param theItem item to bind if Key is not yet bound
0480   //! @return true if Key was newly bound, false if Key already existed (no replacement)
0481   bool TryBind(const TheKeyType& theKey, const TheItemType& theItem)
0482   {
0483     return emplaceImpl(theKey, std::true_type{}, std::false_type{}, theItem);
0484   }
0485 
0486   //! TryBind binds Item to Key in map only if Key is not yet bound.
0487   //! @param theKey  key to add
0488   //! @param theItem item to bind if Key is not yet bound
0489   //! @return true if Key was newly bound, false if Key already existed (no replacement)
0490   bool TryBind(TheKeyType&& theKey, const TheItemType& theItem)
0491   {
0492     return emplaceImpl(std::move(theKey), std::true_type{}, std::false_type{}, theItem);
0493   }
0494 
0495   //! TryBind binds Item to Key in map only if Key is not yet bound.
0496   //! @param theKey  key to add
0497   //! @param theItem item to bind if Key is not yet bound
0498   //! @return true if Key was newly bound, false if Key already existed (no replacement)
0499   bool TryBind(const TheKeyType& theKey, TheItemType&& theItem)
0500   {
0501     return emplaceImpl(theKey, std::true_type{}, std::false_type{}, std::move(theItem));
0502   }
0503 
0504   //! TryBind binds Item to Key in map only if Key is not yet bound.
0505   //! @param theKey  key to add
0506   //! @param theItem item to bind if Key is not yet bound
0507   //! @return true if Key was newly bound, false if Key already existed (no replacement)
0508   bool TryBind(TheKeyType&& theKey, TheItemType&& theItem)
0509   {
0510     return emplaceImpl(std::move(theKey), std::true_type{}, std::false_type{}, std::move(theItem));
0511   }
0512 
0513   //! TryBound binds Item to Key in map only if Key is not yet bound.
0514   //! @param theKey  key to add
0515   //! @param theItem item to bind if Key is not yet bound
0516   //! @return reference to existing or newly bound Item
0517   TheItemType& TryBound(const TheKeyType& theKey, const TheItemType& theItem)
0518   {
0519     return emplaceImpl(theKey, std::true_type{}, std::true_type{}, theItem);
0520   }
0521 
0522   //! TryBound binds Item to Key in map only if Key is not yet bound.
0523   //! @param theKey  key to add
0524   //! @param theItem item to bind if Key is not yet bound
0525   //! @return reference to existing or newly bound Item
0526   TheItemType& TryBound(TheKeyType&& theKey, const TheItemType& theItem)
0527   {
0528     return emplaceImpl(std::move(theKey), std::true_type{}, std::true_type{}, theItem);
0529   }
0530 
0531   //! TryBound binds Item to Key in map only if Key is not yet bound.
0532   //! @param theKey  key to add
0533   //! @param theItem item to bind if Key is not yet bound
0534   //! @return reference to existing or newly bound Item
0535   TheItemType& TryBound(const TheKeyType& theKey, TheItemType&& theItem)
0536   {
0537     return emplaceImpl(theKey, std::true_type{}, std::true_type{}, std::move(theItem));
0538   }
0539 
0540   //! TryBound binds Item to Key in map only if Key is not yet bound.
0541   //! @param theKey  key to add
0542   //! @param theItem item to bind if Key is not yet bound
0543   //! @return reference to existing or newly bound Item
0544   TheItemType& TryBound(TheKeyType&& theKey, TheItemType&& theItem)
0545   {
0546     return emplaceImpl(std::move(theKey), std::true_type{}, std::true_type{}, std::move(theItem));
0547   }
0548 
0549   //! Emplace constructs value in-place; if key exists, destroys and reconstructs value.
0550   //! @param theKey  key to add/update
0551   //! @param theArgs arguments forwarded to value constructor
0552   //! @return true if key was newly added, false if key already existed (and value was
0553   //! reconstructed)
0554   template <typename K, typename... Args>
0555   bool Emplace(K&& theKey, Args&&... theArgs)
0556   {
0557     return emplaceImpl(std::forward<K>(theKey),
0558                        std::false_type{},
0559                        std::false_type{},
0560                        std::forward<Args>(theArgs)...);
0561   }
0562 
0563   //! Emplaced constructs value in-place; if key exists, destroys and reconstructs value.
0564   //! @param theKey  key to add/update
0565   //! @param theArgs arguments forwarded to value constructor
0566   //! @return reference to the value (existing reconstructed or newly added)
0567   template <typename K, typename... Args>
0568   TheItemType& Emplaced(K&& theKey, Args&&... theArgs)
0569   {
0570     return emplaceImpl(std::forward<K>(theKey),
0571                        std::false_type{},
0572                        std::true_type{},
0573                        std::forward<Args>(theArgs)...);
0574   }
0575 
0576   //! TryEmplace constructs value in-place only if key not already bound.
0577   //! @param theKey  key to add
0578   //! @param theArgs arguments forwarded to value constructor
0579   //! @return true if key was newly added, false if key already existed
0580   template <typename K, typename... Args>
0581   bool TryEmplace(K&& theKey, Args&&... theArgs)
0582   {
0583     return emplaceImpl(std::forward<K>(theKey),
0584                        std::true_type{},
0585                        std::false_type{},
0586                        std::forward<Args>(theArgs)...);
0587   }
0588 
0589   //! TryEmplaced constructs value in-place only if key not already bound.
0590   //! @param theKey  key to add
0591   //! @param theArgs arguments forwarded to value constructor
0592   //! @return reference to the value (existing or newly added)
0593   template <typename K, typename... Args>
0594   TheItemType& TryEmplaced(K&& theKey, Args&&... theArgs)
0595   {
0596     return emplaceImpl(std::forward<K>(theKey),
0597                        std::true_type{},
0598                        std::true_type{},
0599                        std::forward<Args>(theArgs)...);
0600   }
0601 
0602   //! IsBound
0603   bool IsBound(const TheKeyType& theKey) const
0604   {
0605     DataMapNode* p;
0606     return lookup(theKey, p);
0607   }
0608 
0609   //! Contained returns optional pair of const references to key and value.
0610   //! Returns std::nullopt if the key is not found.
0611   std::optional<
0612     std::pair<std::reference_wrapper<const TheKeyType>, std::reference_wrapper<const TheItemType>>>
0613     Contained(const TheKeyType& theKey) const
0614   {
0615     DataMapNode* p = nullptr;
0616     if (!lookup(theKey, p))
0617       return std::nullopt;
0618     return std::make_pair(std::cref(p->Key()), std::cref(p->Value()));
0619   }
0620 
0621   //! Contained returns optional pair of const key reference and mutable value reference.
0622   //! Returns std::nullopt if the key is not found.
0623   std::optional<
0624     std::pair<std::reference_wrapper<const TheKeyType>, std::reference_wrapper<TheItemType>>>
0625     Contained(const TheKeyType& theKey)
0626   {
0627     DataMapNode* p = nullptr;
0628     if (!lookup(theKey, p))
0629       return std::nullopt;
0630     return std::make_pair(std::cref(p->Key()), std::ref(p->ChangeValue()));
0631   }
0632 
0633   //! UnBind removes Item Key pair from map
0634   bool UnBind(const TheKeyType& theKey)
0635   {
0636     if (IsEmpty())
0637       return false;
0638     DataMapNode** data = (DataMapNode**)myData1;
0639     const size_t  k    = HashCode(theKey, NbBuckets());
0640     DataMapNode*  p    = data[k];
0641     DataMapNode*  q    = nullptr;
0642     while (p)
0643     {
0644       if (IsEqual(p->Key(), theKey))
0645       {
0646         Decrement();
0647         if (q)
0648           q->Next() = p->Next();
0649         else
0650           data[k] = (DataMapNode*)p->Next();
0651         p->~DataMapNode();
0652         this->myAllocator->Free(p);
0653         return true;
0654       }
0655       q = p;
0656       p = (DataMapNode*)p->Next();
0657     }
0658     return false;
0659   }
0660 
0661   //! Seek returns pointer to Item by Key. Returns
0662   //! NULL is Key was not bound.
0663   const TheItemType* Seek(const TheKeyType& theKey) const
0664   {
0665     DataMapNode* p = nullptr;
0666     if (!lookup(theKey, p))
0667       return nullptr;
0668     return &p->Value();
0669   }
0670 
0671   //! Find returns the Item for Key. Raises if Key was not bound
0672   const TheItemType& Find(const TheKeyType& theKey) const
0673   {
0674     DataMapNode* p = nullptr;
0675     if (!lookup(theKey, p))
0676       throw Standard_NoSuchObject("NCollection_DataMap::Find");
0677     return p->Value();
0678   }
0679 
0680   //! Find Item for key with copying.
0681   //! @return true if key was found
0682   bool Find(const TheKeyType& theKey, TheItemType& theValue) const
0683   {
0684     DataMapNode* p = nullptr;
0685     if (!lookup(theKey, p))
0686       return false;
0687 
0688     theValue = p->Value();
0689     return true;
0690   }
0691 
0692   //! operator ()
0693   const TheItemType& operator()(const TheKeyType& theKey) const { return Find(theKey); }
0694 
0695   //! ChangeSeek returns modifiable pointer to Item by Key. Returns
0696   //! NULL is Key was not bound.
0697   TheItemType* ChangeSeek(const TheKeyType& theKey)
0698   {
0699     DataMapNode* p = nullptr;
0700     if (!lookup(theKey, p))
0701       return nullptr;
0702     return &p->ChangeValue();
0703   }
0704 
0705   //! ChangeFind returns modifiable Item by Key. Raises if Key was not bound
0706   TheItemType& ChangeFind(const TheKeyType& theKey)
0707   {
0708     DataMapNode* p = nullptr;
0709     if (!lookup(theKey, p))
0710       throw Standard_NoSuchObject("NCollection_DataMap::Find");
0711     return p->ChangeValue();
0712   }
0713 
0714   //! operator ()
0715   TheItemType& operator()(const TheKeyType& theKey) { return ChangeFind(theKey); }
0716 
0717   //! Clear data. If doReleaseMemory is false then the table of
0718   //! buckets is not released and will be reused.
0719   void Clear(const bool doReleaseMemory = false) { Destroy(DataMapNode::delNode, doReleaseMemory); }
0720 
0721   //! Clear data and reset allocator
0722   void Clear(const occ::handle<NCollection_BaseAllocator>& theAllocator)
0723   {
0724     Clear(theAllocator != this->myAllocator);
0725     this->myAllocator =
0726       (!theAllocator.IsNull() ? theAllocator : NCollection_BaseAllocator::CommonBaseAllocator());
0727   }
0728 
0729   //! Destructor
0730   ~NCollection_DataMap() override { Clear(true); }
0731 
0732 protected:
0733   //! Lookup for particular key in map.
0734   //! @param[in] theKey key to compute hash
0735   //! @param[out] theNode the detected node with equal key. Can be null.
0736   //! @return true if key is found
0737   bool lookup(const TheKeyType& theKey, DataMapNode*& theNode) const
0738   {
0739     if (IsEmpty())
0740       return false; // Not found
0741     for (theNode = (DataMapNode*)myData1[HashCode(theKey, NbBuckets())]; theNode;
0742          theNode = (DataMapNode*)theNode->Next())
0743     {
0744       if (IsEqual(theNode->Key(), theKey))
0745         return true;
0746     }
0747     return false; // Not found
0748   }
0749 
0750   //! Lookup for particular key in map.
0751   //! @param[in] theKey key to compute hash
0752   //! @param[out] theNode the detected node with equal key. Can be null.
0753   //! @param[out] theHash computed bounded hash code for current key.
0754   //! @return true if key is found
0755   bool lookup(const TheKeyType& theKey, DataMapNode*& theNode, size_t& theHash) const
0756   {
0757     theHash = HashCode(theKey, NbBuckets());
0758     if (IsEmpty())
0759       return false; // Not found
0760     for (theNode = (DataMapNode*)myData1[theHash]; theNode; theNode = (DataMapNode*)theNode->Next())
0761     {
0762       if (IsEqual(theNode->Key(), theKey))
0763       {
0764         return true;
0765       }
0766     }
0767     return false; // Not found
0768   }
0769 
0770   bool IsEqual(const TheKeyType& theKey1, const TheKeyType& theKey2) const
0771   {
0772     return myHasher(theKey1, theKey2);
0773   }
0774 
0775   size_t HashCode(const TheKeyType& theKey, const size_t theUpperBound) const
0776   {
0777     return myHasher(theKey) % theUpperBound + 1;
0778   }
0779 
0780   //! Implementation helper for Bind/TryBind/Bound/TryBound/Emplace/TryEmplace/Emplaced/TryEmplaced.
0781   //! Uses destroy + reconstruct in-place instead of assignment operator.
0782   //! @tparam K forwarding reference type for key
0783   //! @tparam IsTry if true, does not overwrite existing; if false, destroys and reconstructs
0784   //! @tparam ReturnRef if true, returns reference; if false, returns bool
0785   //! @param theKey  key to add/update
0786   //! @param theArgs arguments forwarded to value constructor
0787   //! @return bool or TheItemType& depending on ReturnRef
0788   template <typename K, bool IsTry, bool ReturnRef, typename... Args>
0789   auto emplaceImpl(K&& theKey,
0790                    std::bool_constant<IsTry>,
0791                    std::bool_constant<ReturnRef>,
0792                    Args&&... theArgs) -> std::conditional_t<ReturnRef, TheItemType&, bool>
0793   {
0794     if (Resizable())
0795       ReSize(Extent());
0796     size_t       aHash;
0797     DataMapNode* aNode;
0798     if (lookup(theKey, aNode, aHash))
0799     {
0800       if constexpr (!IsTry)
0801       {
0802         aNode->ChangeValue() = TheItemType(std::forward<Args>(theArgs)...);
0803       }
0804       if constexpr (ReturnRef)
0805         return aNode->ChangeValue();
0806       else
0807         return false;
0808     }
0809     DataMapNode** data = (DataMapNode**)myData1;
0810     data[aHash]        = new (this->myAllocator) DataMapNode(std::forward<K>(theKey),
0811                                                       std::in_place,
0812                                                       data[aHash],
0813                                                       std::forward<Args>(theArgs)...);
0814     Increment();
0815     if constexpr (ReturnRef)
0816       return data[aHash]->ChangeValue();
0817     else
0818       return true;
0819   }
0820 
0821 private:
0822   Hasher myHasher;
0823 };
0824 
0825 #endif