Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-28 09:21:01

0001 // Copyright (c) 2026 OPEN CASCADE SAS
0002 //
0003 // This file is part of Open CASCADE Technology software library.
0004 //
0005 // This library is free software; you can redistribute it and/or modify it under
0006 // the terms of the GNU Lesser General Public License version 2.1 as published
0007 // by the Free Software Foundation, with special exception defined in the file
0008 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0009 // distribution for complete text of the license and disclaimer of any warranty.
0010 //
0011 // Alternatively, this file may be used under the terms of Open CASCADE
0012 // commercial license or contractual agreement.
0013 
0014 #ifndef NCollection_OrderedMap_HeaderFile
0015 #define NCollection_OrderedMap_HeaderFile
0016 
0017 #include <NCollection_BaseMap.hxx>
0018 #include <NCollection_DefaultHasher.hxx>
0019 #include <NCollection_StlIterator.hxx>
0020 #include <NCollection_TListNode.hxx>
0021 #include <Standard_NoSuchObject.hxx>
0022 #include <Standard_OutOfRange.hxx>
0023 
0024 #include <functional>
0025 #include <optional>
0026 #include <type_traits>
0027 #include <utility>
0028 
0029 //! @brief Hash set that preserves insertion order.
0030 //!
0031 //! NCollection_OrderedMap is an alternative to NCollection_Map that maintains
0032 //! a doubly-linked list threaded through the hash nodes, so iteration always
0033 //! follows the order in which keys were inserted.
0034 //!
0035 //! Key features:
0036 //! - O(1) hash lookup (Contains, Contained)
0037 //! - O(1) insertion at tail (Add, Emplace)
0038 //! - O(1) removal with linked-list unlink (Remove)
0039 //! - O(1) access to first/last inserted keys (First, Last)
0040 //! - Deterministic iteration order across platforms
0041 //!
0042 //! Best suited for:
0043 //! - Membership sets that require stable iteration order
0044 //! - Serialization-friendly key sets (deterministic output)
0045 //! - Cases where NCollection_IndexedMap overhead is unnecessary
0046 //!
0047 //! Compared to NCollection_IndexedMap:
0048 //! - Remove is O(1) instead of O(n) (no swap-and-shrink on dense array)
0049 //! - No integer index access (use IndexedMap if indices are needed)
0050 //!
0051 //! The number of buckets is managed automatically and grows when the number
0052 //! of keys exceeds the bucket count.
0053 //!
0054 //! @note This class is NOT thread-safe. External synchronization is required
0055 //!       for concurrent access from multiple threads.
0056 //!
0057 //! @tparam TheKeyType Type of keys
0058 //! @tparam Hasher     Hash and equality functor (default: NCollection_DefaultHasher)
0059 template <class TheKeyType, class Hasher = NCollection_DefaultHasher<TheKeyType>>
0060 class NCollection_OrderedMap : public NCollection_BaseMap
0061 {
0062 public:
0063   //! STL-compliant typedef for key type
0064   typedef TheKeyType key_type;
0065   typedef Hasher     hasher;
0066 
0067 public:
0068   //! Adaptation of the TListNode to the ordered map notations.
0069   //! Extends the hash-chain node with insertion-order linked list pointers.
0070   class OrderedMapNode : public NCollection_TListNode<TheKeyType>
0071   {
0072   public:
0073     //! Constructor with copy key
0074     OrderedMapNode(const TheKeyType& theKey, NCollection_ListNode* theNext)
0075         : NCollection_TListNode<TheKeyType>(theKey, theNext),
0076           myOrderPrev(nullptr),
0077           myOrderNext(nullptr)
0078     {
0079     }
0080 
0081     //! Constructor with move key
0082     OrderedMapNode(TheKeyType&& theKey, NCollection_ListNode* theNext)
0083         : NCollection_TListNode<TheKeyType>(std::forward<TheKeyType>(theKey), theNext),
0084           myOrderPrev(nullptr),
0085           myOrderNext(nullptr)
0086     {
0087     }
0088 
0089     //! Constructor with in-place key construction
0090     template <typename... Args>
0091     OrderedMapNode(std::in_place_t, NCollection_ListNode* theNext, Args&&... theArgs)
0092         : NCollection_TListNode<TheKeyType>(std::in_place, theNext, std::forward<Args>(theArgs)...),
0093           myOrderPrev(nullptr),
0094           myOrderNext(nullptr)
0095     {
0096     }
0097 
0098     //! Key
0099     const TheKeyType& Key() noexcept { return this->Value(); }
0100 
0101     //! Static deleter to be passed to BaseMap
0102     static void delNode(NCollection_ListNode*                   theNode,
0103                         occ::handle<NCollection_BaseAllocator>& theAl) noexcept
0104     {
0105       ((OrderedMapNode*)theNode)->~OrderedMapNode();
0106       theAl->Free(theNode);
0107     }
0108 
0109     OrderedMapNode* myOrderPrev; //!< Previous node in insertion order
0110     OrderedMapNode* myOrderNext; //!< Next node in insertion order
0111   };
0112 
0113 public:
0114   //! Implementation of the Iterator interface.
0115   //! Iterates in insertion order by walking the doubly-linked list.
0116   class Iterator
0117   {
0118   public:
0119     //! Empty constructor
0120     Iterator() noexcept
0121         : myNode(nullptr)
0122     {
0123     }
0124 
0125     //! Constructor
0126     Iterator(const NCollection_OrderedMap& theMap) noexcept
0127         : myNode(theMap.myFirst)
0128     {
0129     }
0130 
0131     //! Query if the end of collection is reached by iterator
0132     bool More() const noexcept { return myNode != nullptr; }
0133 
0134     //! Make a step along the collection (in insertion order)
0135     void Next() noexcept
0136     {
0137       if (myNode)
0138         myNode = myNode->myOrderNext;
0139     }
0140 
0141     //! Value inquiry
0142     const TheKeyType& Value() const
0143     {
0144       Standard_NoSuchObject_Raise_if(!More(), "NCollection_OrderedMap::Iterator::Value");
0145       return myNode->Value();
0146     }
0147 
0148     //! Key
0149     const TheKeyType& Key() const
0150     {
0151       Standard_NoSuchObject_Raise_if(!More(), "NCollection_OrderedMap::Iterator::Key");
0152       return myNode->Value();
0153     }
0154 
0155     //! Performs comparison of two iterators.
0156     bool IsEqual(const Iterator& theOther) const noexcept { return myNode == theOther.myNode; }
0157 
0158     //! Initialize
0159     void Initialize(const NCollection_OrderedMap& theMap) noexcept { myNode = theMap.myFirst; }
0160 
0161     //! Reset
0162     void Reset() noexcept { myNode = nullptr; }
0163 
0164   private:
0165     OrderedMapNode* myNode; //!< Current node in insertion-order list
0166   };
0167 
0168   //! Shorthand for a constant iterator type.
0169   typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheKeyType, true>
0170     const_iterator;
0171 
0172   //! Shorthand for iterator type (same as const_iterator for key-only maps).
0173   typedef const_iterator iterator;
0174 
0175   //! Returns an iterator pointing to the first element in the map.
0176   iterator begin() const noexcept { return Iterator(*this); }
0177 
0178   //! Returns an iterator referring to the past-the-end element in the map.
0179   iterator end() const noexcept { return Iterator(); }
0180 
0181   //! Returns a const iterator pointing to the first element in the map.
0182   const_iterator cbegin() const noexcept { return Iterator(*this); }
0183 
0184   //! Returns a const iterator referring to the past-the-end element in the map.
0185   const_iterator cend() const noexcept { return Iterator(); }
0186 
0187 public:
0188   // ---------- PUBLIC METHODS ------------
0189 
0190   //! Empty constructor.
0191   NCollection_OrderedMap()
0192       : NCollection_BaseMap(1, true, occ::handle<NCollection_BaseAllocator>()),
0193         myFirst(nullptr),
0194         myLast(nullptr)
0195   {
0196   }
0197 
0198   //! Constructor
0199   explicit NCollection_OrderedMap(
0200     const size_t                                  theNbBuckets,
0201     const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0202       : NCollection_BaseMap(theNbBuckets, true, theAllocator),
0203         myFirst(nullptr),
0204         myLast(nullptr)
0205   {
0206   }
0207 
0208   //! Constructor (legacy int-taking).
0209   explicit NCollection_OrderedMap(
0210     const int                                     theNbBuckets,
0211     const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0212       : NCollection_OrderedMap(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_OrderedMap(
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         myFirst(nullptr),
0227         myLast(nullptr)
0228   {
0229   }
0230 
0231   //! Constructor with custom hasher (copy, legacy int-taking).
0232   explicit NCollection_OrderedMap(
0233     const Hasher&                                 theHasher,
0234     const int                                     theNbBuckets,
0235     const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0236       : NCollection_OrderedMap(theHasher,
0237                                NCollection_BaseMap::NbBucketsFromInt(theNbBuckets),
0238                                theAllocator)
0239   {
0240   }
0241 
0242   //! Constructor with custom hasher (move).
0243   //! @param theHasher custom hasher instance (moved)
0244   //! @param theNbBuckets initial number of buckets
0245   //! @param theAllocator custom memory allocator
0246   explicit NCollection_OrderedMap(
0247     Hasher&&                                      theHasher,
0248     const size_t                                  theNbBuckets = 1,
0249     const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0250       : NCollection_BaseMap(theNbBuckets, true, theAllocator),
0251         myHasher(std::move(theHasher)),
0252         myFirst(nullptr),
0253         myLast(nullptr)
0254   {
0255   }
0256 
0257   //! Constructor with custom hasher (move, legacy int-taking).
0258   explicit NCollection_OrderedMap(
0259     Hasher&&                                      theHasher,
0260     const int                                     theNbBuckets,
0261     const occ::handle<NCollection_BaseAllocator>& theAllocator = nullptr)
0262       : NCollection_OrderedMap(std::move(theHasher),
0263                                NCollection_BaseMap::NbBucketsFromInt(theNbBuckets),
0264                                theAllocator)
0265   {
0266   }
0267 
0268   //! Copy constructor
0269   NCollection_OrderedMap(const NCollection_OrderedMap& theOther)
0270       : NCollection_BaseMap(theOther.NbBuckets(), true, theOther.myAllocator),
0271         myHasher(theOther.myHasher),
0272         myFirst(nullptr),
0273         myLast(nullptr)
0274   {
0275     const int anExt = theOther.Extent();
0276     if (anExt <= 0)
0277       return;
0278     ReSize(anExt - 1);
0279     for (Iterator anIter(theOther); anIter.More(); anIter.Next())
0280       Add(anIter.Key());
0281   }
0282 
0283   //! Move constructor
0284   NCollection_OrderedMap(NCollection_OrderedMap&& theOther) noexcept
0285       : NCollection_BaseMap(std::forward<NCollection_BaseMap>(theOther)),
0286         myHasher(std::move(theOther.myHasher)),
0287         myFirst(theOther.myFirst),
0288         myLast(theOther.myLast)
0289   {
0290     theOther.myFirst = nullptr;
0291     theOther.myLast  = nullptr;
0292   }
0293 
0294   //! Exchange the content of two maps without re-allocations.
0295   //! Notice that allocators will be swapped as well!
0296   void Exchange(NCollection_OrderedMap& theOther) noexcept
0297   {
0298     this->exchangeMapsData(theOther);
0299     std::swap(myFirst, theOther.myFirst);
0300     std::swap(myLast, theOther.myLast);
0301     std::swap(myHasher, theOther.myHasher);
0302   }
0303 
0304   //! Returns const reference to the hasher.
0305   const Hasher& GetHasher() const noexcept { return myHasher; }
0306 
0307   //! Assign.
0308   //! This method does not change the internal allocator.
0309   NCollection_OrderedMap& Assign(const NCollection_OrderedMap& theOther)
0310   {
0311     if (this == &theOther)
0312       return *this;
0313 
0314     Clear();
0315     int anExt = theOther.Extent();
0316     if (anExt)
0317     {
0318       ReSize(anExt - 1);
0319       Iterator anIter(theOther);
0320       for (; anIter.More(); anIter.Next())
0321         Add(anIter.Key());
0322     }
0323     return *this;
0324   }
0325 
0326   //! Assign operator
0327   NCollection_OrderedMap& operator=(const NCollection_OrderedMap& theOther)
0328   {
0329     return Assign(theOther);
0330   }
0331 
0332   //! Move operator
0333   NCollection_OrderedMap& operator=(NCollection_OrderedMap&& theOther) noexcept
0334   {
0335     if (this == &theOther)
0336       return *this;
0337     exchangeMapsData(theOther);
0338     std::swap(myFirst, theOther.myFirst);
0339     std::swap(myLast, theOther.myLast);
0340     return *this;
0341   }
0342 
0343   //! ReSize
0344   void ReSize(const size_t N)
0345   {
0346     NCollection_ListNode** newdata = nullptr;
0347     NCollection_ListNode** dummy   = nullptr;
0348     size_t                 newBuck;
0349     if (BeginResize(N, newBuck, newdata, dummy))
0350     {
0351       if (myData1)
0352       {
0353         OrderedMapNode** olddata = (OrderedMapNode**)myData1;
0354         OrderedMapNode * p, *q;
0355         for (size_t i = 0; i <= NbBuckets(); ++i)
0356         {
0357           if (olddata[i])
0358           {
0359             p = olddata[i];
0360             while (p)
0361             {
0362               const size_t k = HashCode(p->Key(), newBuck);
0363               q              = (OrderedMapNode*)p->Next();
0364               p->Next()      = newdata[k];
0365               newdata[k]     = p;
0366               p              = q;
0367             }
0368           }
0369         }
0370       }
0371       EndResize(N, newBuck, newdata, dummy);
0372     }
0373   }
0374 
0375   void ReSize(const int N)
0376   {
0377     Standard_OutOfRange_Raise_if(N < 0, "NCollection_OrderedMap::ReSize: negative size");
0378     ReSize(static_cast<size_t>(N));
0379   }
0380 
0381   //! Add
0382   bool Add(const TheKeyType& theKey) { return addImpl(theKey, std::false_type{}); }
0383 
0384   //! Add
0385   bool Add(TheKeyType&& theKey) { return addImpl(std::move(theKey), std::false_type{}); }
0386 
0387   //! Added: add a new key if not yet in the map, and return
0388   //! reference to either newly added or previously existing object
0389   const TheKeyType& Added(const TheKeyType& theKey) { return addImpl(theKey, std::true_type{}); }
0390 
0391   //! Added: add a new key if not yet in the map, and return
0392   //! reference to either newly added or previously existing object
0393   const TheKeyType& Added(TheKeyType&& theKey)
0394   {
0395     return addImpl(std::move(theKey), std::true_type{});
0396   }
0397 
0398   //! Emplace constructs key in-place; if key exists, destroys and reconstructs.
0399   //! @param theArgs arguments forwarded to key constructor
0400   //! @return true if key was newly added, false if key already existed (and was reconstructed)
0401   template <typename... Args>
0402   bool Emplace(Args&&... theArgs)
0403   {
0404     return emplaceImpl(std::false_type{}, std::false_type{}, std::forward<Args>(theArgs)...);
0405   }
0406 
0407   //! Emplaced constructs key in-place; if key exists, destroys and reconstructs.
0408   //! @param theArgs arguments forwarded to key constructor
0409   //! @return const reference to the key in the map
0410   template <typename... Args>
0411   const TheKeyType& Emplaced(Args&&... theArgs)
0412   {
0413     return emplaceImpl(std::false_type{}, std::true_type{}, std::forward<Args>(theArgs)...);
0414   }
0415 
0416   //! TryEmplace constructs key in-place only if not already present.
0417   //! @param theArgs arguments forwarded to key constructor
0418   //! @return true if key was newly added, false if key already existed
0419   template <typename... Args>
0420   bool TryEmplace(Args&&... theArgs)
0421   {
0422     return emplaceImpl(std::true_type{}, std::false_type{}, std::forward<Args>(theArgs)...);
0423   }
0424 
0425   //! TryEmplaced constructs key in-place only if not already present.
0426   //! @param theArgs arguments forwarded to key constructor
0427   //! @return const reference to the key (existing or newly added)
0428   template <typename... Args>
0429   const TheKeyType& TryEmplaced(Args&&... theArgs)
0430   {
0431     return emplaceImpl(std::true_type{}, std::true_type{}, std::forward<Args>(theArgs)...);
0432   }
0433 
0434   //! Contains
0435   bool Contains(const TheKeyType& theKey) const
0436   {
0437     OrderedMapNode* p;
0438     return lookup(theKey, p);
0439   }
0440 
0441   //! Contained returns optional const reference to the key in the map.
0442   //! Returns std::nullopt if the key is not found.
0443   std::optional<std::reference_wrapper<const TheKeyType>> Contained(const TheKeyType& theKey) const
0444   {
0445     OrderedMapNode* p;
0446     if (!lookup(theKey, p))
0447       return std::nullopt;
0448     return std::cref(p->Key());
0449   }
0450 
0451   //! Remove
0452   bool Remove(const TheKeyType& K)
0453   {
0454     if (IsEmpty())
0455       return false;
0456     OrderedMapNode** data = (OrderedMapNode**)myData1;
0457     const size_t     k    = HashCode(K, NbBuckets());
0458     OrderedMapNode*  p    = data[k];
0459     OrderedMapNode*  q    = nullptr;
0460     while (p)
0461     {
0462       if (IsEqual(p->Key(), K))
0463       {
0464         Decrement();
0465         if (q)
0466           q->Next() = p->Next();
0467         else
0468           data[k] = (OrderedMapNode*)p->Next();
0469         unlinkFromList(p);
0470         p->~OrderedMapNode();
0471         this->myAllocator->Free(p);
0472         return true;
0473       }
0474       q = p;
0475       p = (OrderedMapNode*)p->Next();
0476     }
0477     return false;
0478   }
0479 
0480   //! Clear data. If doReleaseMemory is false then the table of
0481   //! buckets is not released and will be reused.
0482   void Clear(const bool doReleaseMemory = false)
0483   {
0484     Destroy(OrderedMapNode::delNode, doReleaseMemory);
0485     myFirst = nullptr;
0486     myLast  = nullptr;
0487   }
0488 
0489   //! Clear data and reset allocator
0490   void Clear(const occ::handle<NCollection_BaseAllocator>& theAllocator)
0491   {
0492     Clear(theAllocator != this->myAllocator);
0493     this->myAllocator =
0494       (!theAllocator.IsNull() ? theAllocator : NCollection_BaseAllocator::CommonBaseAllocator());
0495   }
0496 
0497   //! Destructor
0498   ~NCollection_OrderedMap() override { Clear(true); }
0499 
0500   //! Returns the first key in insertion order.
0501   //! @return const reference to the first key
0502   //! @throws Standard_NoSuchObject if map is empty
0503   const TheKeyType& First() const
0504   {
0505     if (IsEmpty())
0506       throw Standard_NoSuchObject("NCollection_OrderedMap::First");
0507     return myFirst->Value();
0508   }
0509 
0510   //! Returns the last key in insertion order.
0511   //! @return const reference to the last key
0512   //! @throws Standard_NoSuchObject if map is empty
0513   const TheKeyType& Last() const
0514   {
0515     if (IsEmpty())
0516       throw Standard_NoSuchObject("NCollection_OrderedMap::Last");
0517     return myLast->Value();
0518   }
0519 
0520 protected:
0521   //! Lookup for particular key in map.
0522   //! @param[in] theKey key to compute hash
0523   //! @param[out] theNode the detected node with equal key. Can be null.
0524   //! @param[out] theHash computed bounded hash code for current key.
0525   //! @return true if key is found
0526   bool lookup(const TheKeyType& theKey, OrderedMapNode*& theNode, size_t& theHash) const
0527   {
0528     theHash = HashCode(theKey, NbBuckets());
0529     if (IsEmpty())
0530       return false;
0531     for (theNode = (OrderedMapNode*)myData1[theHash]; theNode;
0532          theNode = (OrderedMapNode*)theNode->Next())
0533     {
0534       if (IsEqual(theNode->Key(), theKey))
0535         return true;
0536     }
0537     return false;
0538   }
0539 
0540   //! Lookup for particular key in map.
0541   //! @param[in] theKey key to compute hash
0542   //! @param[out] theNode the detected node with equal key. Can be null.
0543   //! @return true if key is found
0544   bool lookup(const TheKeyType& theKey, OrderedMapNode*& theNode) const
0545   {
0546     if (IsEmpty())
0547       return false;
0548     for (theNode = (OrderedMapNode*)myData1[HashCode(theKey, NbBuckets())]; theNode;
0549          theNode = (OrderedMapNode*)theNode->Next())
0550     {
0551       if (IsEqual(theNode->Key(), theKey))
0552       {
0553         return true;
0554       }
0555     }
0556     return false;
0557   }
0558 
0559   bool IsEqual(const TheKeyType& theKey1, const TheKeyType& theKey2) const
0560   {
0561     return myHasher(theKey1, theKey2);
0562   }
0563 
0564   size_t HashCode(const TheKeyType& theKey, const size_t theUpperBound) const
0565   {
0566     return myHasher(theKey) % theUpperBound + 1;
0567   }
0568 
0569   //! Append a node to the tail of the insertion-order linked list.
0570   void appendToList(OrderedMapNode* theNode)
0571   {
0572     theNode->myOrderPrev = myLast;
0573     theNode->myOrderNext = nullptr;
0574     if (myLast)
0575       myLast->myOrderNext = theNode;
0576     else
0577       myFirst = theNode;
0578     myLast = theNode;
0579   }
0580 
0581   //! Unlink a node from the insertion-order linked list.
0582   void unlinkFromList(OrderedMapNode* theNode)
0583   {
0584     OrderedMapNode* aPrev = theNode->myOrderPrev;
0585     OrderedMapNode* aNext = theNode->myOrderNext;
0586     if (aPrev)
0587       aPrev->myOrderNext = aNext;
0588     else
0589       myFirst = aNext;
0590     if (aNext)
0591       aNext->myOrderPrev = aPrev;
0592     else
0593       myLast = aPrev;
0594   }
0595 
0596   //! Implementation helper for Add/Added.
0597   //! @tparam K forwarding reference type for key
0598   //! @tparam ReturnRef if true, returns const reference to key; if false, returns bool
0599   //! @param theKey key to add
0600   //! @return bool (Add) or const TheKeyType& (Added)
0601   template <typename K, bool ReturnRef>
0602   auto addImpl(K&& theKey, std::bool_constant<ReturnRef>)
0603     -> std::conditional_t<ReturnRef, const TheKeyType&, bool>
0604   {
0605     if (Resizable())
0606       ReSize(Extent());
0607     OrderedMapNode* aNode;
0608     size_t          aHash;
0609     if (lookup(theKey, aNode, aHash))
0610     {
0611       if constexpr (ReturnRef)
0612         return aNode->Key();
0613       else
0614         return false;
0615     }
0616     OrderedMapNode** data = (OrderedMapNode**)myData1;
0617     data[aHash] = new (this->myAllocator) OrderedMapNode(std::forward<K>(theKey), data[aHash]);
0618     appendToList(data[aHash]);
0619     Increment();
0620     if constexpr (ReturnRef)
0621       return data[aHash]->Key();
0622     else
0623       return true;
0624   }
0625 
0626   //! Implementation helper for Emplace/TryEmplace/Emplaced/TryEmplaced.
0627   //! @tparam IsTry if true, does not modify existing; if false, destroys and reconstructs
0628   //! @tparam ReturnRef if true, returns const reference to key; if false, returns bool
0629   //! @param theArgs arguments forwarded to key constructor
0630   //! @return bool or const TheKeyType& depending on ReturnRef
0631   template <bool IsTry, bool ReturnRef, typename... Args>
0632   auto emplaceImpl(std::bool_constant<IsTry>, std::bool_constant<ReturnRef>, Args&&... theArgs)
0633     -> std::conditional_t<ReturnRef, const TheKeyType&, bool>
0634   {
0635     if (Resizable())
0636       ReSize(Extent());
0637     TheKeyType      aTempKey(std::forward<Args>(theArgs)...);
0638     OrderedMapNode* aNode;
0639     size_t          aHash;
0640     if (lookup(aTempKey, aNode, aHash))
0641     {
0642       if constexpr (!IsTry)
0643       {
0644         aNode->ChangeValue().~TheKeyType();
0645         new (&aNode->ChangeValue()) TheKeyType(std::move(aTempKey));
0646       }
0647       if constexpr (ReturnRef)
0648         return aNode->Key();
0649       else
0650         return false;
0651     }
0652     OrderedMapNode** data = (OrderedMapNode**)myData1;
0653     data[aHash] = new (this->myAllocator) OrderedMapNode(std::move(aTempKey), data[aHash]);
0654     appendToList(data[aHash]);
0655     Increment();
0656     if constexpr (ReturnRef)
0657       return data[aHash]->Key();
0658     else
0659       return true;
0660   }
0661 
0662 protected:
0663   Hasher          myHasher;
0664   OrderedMapNode* myFirst; //!< Head of insertion-order linked list
0665   OrderedMapNode* myLast;  //!< Tail of insertion-order linked list
0666 };
0667 
0668 #endif