Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 08:43:56

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 
0024 #include <Standard_TypeMismatch.hxx>
0025 #include <Standard_NoSuchObject.hxx>
0026 #include <utility>
0027 
0028 #include <Message.hxx>
0029 
0030 /**
0031 * Purpose:     The DataMap is a Map to store keys with associated
0032 *              Items. See Map  from NCollection for  a discussion
0033 *              about the number of buckets.
0034 *
0035 *              The DataMap can be seen as an extended array where
0036 *              the Keys  are the   indices.  For this reason  the
0037 *              operator () is defined on DataMap to fetch an Item
0038 *              from a Key. So the following syntax can be used :
0039 *
0040 *              anItem = aMap(aKey);
0041 *              aMap(aKey) = anItem;
0042 *
0043 *              This analogy has its  limit.   aMap(aKey) = anItem
0044 *              can  be done only  if aKey was previously bound to
0045 *              an item in the map.
0046 */              
0047 
0048 template < class TheKeyType, 
0049            class TheItemType, 
0050            class Hasher = NCollection_DefaultHasher<TheKeyType> >
0051 class NCollection_DataMap : public NCollection_BaseMap
0052 {
0053 public:
0054   //! STL-compliant typedef for key type
0055   typedef TheKeyType key_type;
0056   //! STL-compliant typedef for value type
0057   typedef TheItemType value_type;
0058 
0059 public:
0060   // **************** Adaptation of the TListNode to the DATAmap
0061   class DataMapNode : public NCollection_TListNode<TheItemType>
0062   {
0063   public:
0064     //! Constructor with 'Next'
0065     DataMapNode (const TheKeyType&     theKey, 
0066                  const TheItemType&    theItem, 
0067                  NCollection_ListNode* theNext) :
0068       NCollection_TListNode<TheItemType> (theItem, theNext),
0069       myKey(theKey)
0070     {}
0071     //! Constructor with 'Next'
0072     DataMapNode (const TheKeyType&     theKey, 
0073                  TheItemType&&         theItem, 
0074                  NCollection_ListNode* theNext) :
0075       NCollection_TListNode<TheItemType> (std::forward<TheItemType>(theItem), theNext),
0076       myKey(theKey)
0077     {}
0078     //! Constructor with 'Next'
0079     DataMapNode (TheKeyType&&          theKey, 
0080                  const TheItemType&    theItem, 
0081                  NCollection_ListNode* theNext) :
0082       NCollection_TListNode<TheItemType> (theItem, theNext),
0083       myKey(std::forward<TheKeyType>(theKey))
0084     {}
0085     //! Constructor with 'Next'
0086     DataMapNode (TheKeyType&&          theKey, 
0087                  TheItemType&&         theItem, 
0088                  NCollection_ListNode* theNext) :
0089       NCollection_TListNode<TheItemType> (std::forward<TheItemType>(theItem), theNext),
0090       myKey(std::forward<TheKeyType>(theKey))
0091     {}
0092 
0093     //! Key
0094     const TheKeyType& Key (void) const
0095     { return myKey; }
0096     
0097     //! Static deleter to be passed to BaseMap
0098     static void delNode (NCollection_ListNode * theNode, 
0099                          Handle(NCollection_BaseAllocator)& theAl)
0100     {
0101       ((DataMapNode *) theNode)->~DataMapNode();
0102       theAl->Free(theNode);
0103     }
0104 
0105   private:
0106     TheKeyType    myKey;
0107   };
0108 
0109  public:
0110   // **************** Implementation of the Iterator interface.
0111   class Iterator : public NCollection_BaseMap::Iterator
0112   {
0113   public:
0114     //! Empty constructor
0115     Iterator (void) :
0116       NCollection_BaseMap::Iterator() {}
0117     //! Constructor
0118     Iterator (const NCollection_DataMap& theMap) :
0119       NCollection_BaseMap::Iterator(theMap) {}
0120     //! Query if the end of collection is reached by iterator
0121     Standard_Boolean More(void) const
0122     { return PMore(); }
0123     //! Make a step along the collection
0124     void Next(void)
0125     { PNext(); }
0126     //! Value inquiry
0127     const TheItemType& Value(void) const
0128     {  
0129       Standard_NoSuchObject_Raise_if(!More(), "NCollection_DataMap::Iterator::Value");  
0130       return ((DataMapNode *) myNode)->Value();
0131     }
0132     //! Value change access
0133     TheItemType& ChangeValue(void) const
0134     {  
0135       Standard_NoSuchObject_Raise_if(!More(), "NCollection_DataMap::Iterator::ChangeValue");  
0136       return ((DataMapNode *) myNode)->ChangeValue();
0137     }
0138     //! Key
0139     const TheKeyType& Key (void) const
0140     { 
0141       Standard_NoSuchObject_Raise_if(!More(), "NCollection_DataMap::Iterator::Key");  
0142       return ((DataMapNode *) myNode)->Key();
0143     }
0144   };
0145   
0146   //! Shorthand for a regular iterator type.
0147   typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheItemType, false> iterator;
0148 
0149   //! Shorthand for a constant iterator type.
0150   typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheItemType, true> const_iterator;
0151 
0152   //! Returns an iterator pointing to the first element in the map.
0153   iterator begin() const { return Iterator (*this); }
0154 
0155   //! Returns an iterator referring to the past-the-end element in the map.
0156   iterator end() const { return Iterator(); }
0157 
0158   //! Returns a const iterator pointing to the first element in the map.
0159   const_iterator cbegin() const { return Iterator (*this); }
0160 
0161   //! Returns a const iterator referring to the past-the-end element in the map.
0162   const_iterator cend() const { return Iterator(); }
0163 
0164  public:
0165   // ---------- PUBLIC METHODS ------------
0166 
0167   //! Empty Constructor.
0168   NCollection_DataMap() : NCollection_BaseMap (1, Standard_True, Handle(NCollection_BaseAllocator)()) {}
0169 
0170   //! Constructor
0171   explicit NCollection_DataMap (const Standard_Integer theNbBuckets,
0172                                 const Handle(NCollection_BaseAllocator)& theAllocator = 0L)
0173   : NCollection_BaseMap (theNbBuckets, Standard_True, theAllocator) {}
0174 
0175   //! Copy constructor
0176   NCollection_DataMap (const NCollection_DataMap& theOther)
0177     : NCollection_BaseMap (theOther.NbBuckets(), Standard_True, theOther.myAllocator) 
0178   { 
0179     const int anExt = theOther.Extent();
0180     if (anExt <= 0)
0181       return;
0182     ReSize(anExt - 1);
0183     for (Iterator anIter(theOther); anIter.More(); anIter.Next())
0184       Bind(anIter.Key(), anIter.Value());
0185   }
0186 
0187   //! Move constructor
0188   NCollection_DataMap(NCollection_DataMap&& theOther) noexcept :
0189     NCollection_BaseMap(std::forward<NCollection_BaseMap>(theOther))
0190   {}
0191 
0192   //! Exchange the content of two maps without re-allocations.
0193   //! Notice that allocators will be swapped as well!
0194   void Exchange (NCollection_DataMap& theOther)
0195   {
0196     this->exchangeMapsData (theOther);
0197   }
0198 
0199   //! Assignment.
0200   //! This method does not change the internal allocator.
0201   NCollection_DataMap& Assign (const NCollection_DataMap& theOther)
0202   { 
0203     if (this == &theOther)
0204       return *this;
0205 
0206     Clear();
0207     Standard_Integer anExt = theOther.Extent();
0208     if (anExt)
0209     {
0210       ReSize (anExt-1);
0211       Iterator anIter(theOther);
0212       for (; anIter.More(); anIter.Next())
0213         Bind (anIter.Key(), anIter.Value());
0214     }
0215     return *this;
0216   }
0217 
0218   //! Assignment operator
0219   NCollection_DataMap& operator= (const NCollection_DataMap& theOther)
0220   { 
0221     return Assign (theOther);
0222   }
0223 
0224   //! Move operator
0225   NCollection_DataMap& operator= (NCollection_DataMap&& theOther) noexcept
0226   {
0227     if (this == &theOther)
0228       return *this;
0229     exchangeMapsData(theOther);
0230     return *this;
0231   }
0232 
0233   //! ReSize
0234   void ReSize (const Standard_Integer N)
0235   {
0236     NCollection_ListNode** newdata = NULL;
0237     NCollection_ListNode** dummy   = NULL;
0238     Standard_Integer newBuck;
0239     if (BeginResize (N, newBuck, newdata, dummy))
0240     {
0241       if (myData1) 
0242       {
0243         DataMapNode** olddata = (DataMapNode**) myData1;
0244         DataMapNode *p, *q;
0245         for (int i = 0; i <= NbBuckets(); i++) 
0246         {
0247           if (olddata[i]) 
0248           {
0249             p = olddata[i];
0250             while (p) 
0251             {
0252               const size_t k = HashCode(p->Key(),newBuck);
0253               q = (DataMapNode*) p->Next();
0254               p->Next() = newdata[k];
0255               newdata[k] = p;
0256               p = q;
0257             }
0258           }
0259         }
0260       }
0261       EndResize (N, newBuck, newdata, dummy);
0262     }
0263   }
0264 
0265   //! Bind binds Item to Key in map.
0266   //! @param theKey  key to add/update
0267   //! @param theItem new item; overrides value previously bound to the key
0268   //! @return Standard_True if Key was not bound already
0269   Standard_Boolean Bind (const TheKeyType& theKey, const TheItemType& theItem)
0270   {
0271     if (Resizable()) 
0272       ReSize(Extent());
0273     size_t aHash;
0274     DataMapNode* aNode;
0275     if (lookup(theKey, aNode, aHash))
0276     {
0277       aNode->ChangeValue() = theItem;
0278       return Standard_False;
0279     }
0280     DataMapNode** data = (DataMapNode**)myData1;
0281     data[aHash] = new (this->myAllocator) DataMapNode (theKey, theItem, data[aHash]);
0282     Increment();
0283     return Standard_True;
0284   }
0285 
0286   //! Bind binds Item to Key in map.
0287   //! @param theKey  key to add/update
0288   //! @param theItem new item; overrides value previously bound to the key
0289   //! @return Standard_True if Key was not bound already
0290   Standard_Boolean Bind (TheKeyType&& theKey, const TheItemType& theItem)
0291   {
0292     if (Resizable()) 
0293       ReSize(Extent());
0294     size_t aHash;
0295     DataMapNode* aNode;
0296     if (lookup(theKey, aNode, aHash))
0297     {
0298       aNode->ChangeValue() = theItem;
0299       return Standard_False;
0300     }
0301     DataMapNode** data = (DataMapNode**)myData1;
0302     data[aHash] = new (this->myAllocator) DataMapNode (std::forward<TheKeyType>(theKey), theItem, data[aHash]);
0303     Increment();
0304     return Standard_True;
0305   }
0306 
0307   //! Bind binds Item to Key in map.
0308   //! @param theKey  key to add/update
0309   //! @param theItem new item; overrides value previously bound to the key
0310   //! @return Standard_True if Key was not bound already
0311   Standard_Boolean Bind (const TheKeyType& theKey, TheItemType&& theItem)
0312   {
0313     if (Resizable()) 
0314       ReSize(Extent());
0315     size_t aHash;
0316     DataMapNode* aNode;
0317     if (lookup(theKey, aNode, aHash))
0318     {
0319       aNode->ChangeValue() = std::forward<TheItemType>(theItem);
0320       return Standard_False;
0321     }
0322     DataMapNode** data = (DataMapNode**)myData1;
0323     data[aHash] = new (this->myAllocator) DataMapNode (theKey, std::forward<TheItemType>(theItem), data[aHash]);
0324     Increment();
0325     return Standard_True;
0326   }
0327 
0328   //! Bind binds Item to Key in map.
0329   //! @param theKey  key to add/update
0330   //! @param theItem new item; overrides value previously bound to the key
0331   //! @return Standard_True if Key was not bound already
0332   Standard_Boolean Bind (TheKeyType&& theKey, TheItemType&& theItem)
0333   {
0334     if (Resizable()) 
0335       ReSize(Extent());
0336     size_t aHash;
0337     DataMapNode* aNode;
0338     if (lookup(theKey, aNode, aHash))
0339     {
0340       aNode->ChangeValue() = theItem;
0341       return Standard_False;
0342     }
0343     DataMapNode** data = (DataMapNode**)myData1;
0344     data[aHash] = new (this->myAllocator) DataMapNode (std::forward<TheKeyType>(theKey),
0345                                                        std::forward<TheItemType>(theItem), data[aHash]);
0346     Increment();
0347     return Standard_True;
0348   }
0349 
0350   //! Bound binds Item to Key in map.
0351   //! @param theKey  key to add/update
0352   //! @param theItem new item; overrides value previously bound to the key
0353   //! @return pointer to modifiable Item
0354   TheItemType* Bound (const TheKeyType& theKey, const TheItemType& theItem)
0355   {
0356     if (Resizable()) 
0357       ReSize(Extent());
0358     size_t aHash;
0359     DataMapNode* aNode;
0360     if (lookup(theKey, aNode, aHash))
0361     {
0362       aNode->ChangeValue() = theItem;
0363       return &aNode->ChangeValue();
0364     }
0365     DataMapNode** data = (DataMapNode**)myData1;
0366     data[aHash] = new (this->myAllocator) DataMapNode (theKey, theItem, data[aHash]);
0367     Increment();
0368     return &data[aHash]->ChangeValue();
0369   }
0370 
0371   //! Bound binds Item to Key in map.
0372   //! @param theKey  key to add/update
0373   //! @param theItem new item; overrides value previously bound to the key
0374   //! @return pointer to modifiable Item
0375   TheItemType* Bound (TheKeyType&& theKey, const TheItemType& theItem)
0376   {
0377     if (Resizable()) 
0378       ReSize(Extent());
0379     size_t aHash;
0380     DataMapNode* aNode;
0381     if (lookup(theKey, aNode, aHash))
0382     {
0383       aNode->ChangeValue() = theItem;
0384       return &aNode->ChangeValue();
0385     }
0386     DataMapNode** data = (DataMapNode**)myData1;
0387     data[aHash] = new (this->myAllocator) DataMapNode (std::forward<TheKeyType>(theKey), theItem, data[aHash]);
0388     Increment();
0389     return &data[aHash]->ChangeValue();
0390   }
0391 
0392   //! Bound binds Item to Key in map.
0393   //! @param theKey  key to add/update
0394   //! @param theItem new item; overrides value previously bound to the key
0395   //! @return pointer to modifiable Item
0396   TheItemType* Bound (const TheKeyType& theKey, TheItemType&& theItem)
0397   {
0398     if (Resizable()) 
0399       ReSize(Extent());
0400     size_t aHash;
0401     DataMapNode* aNode;
0402     if (lookup(theKey, aNode, aHash))
0403     {
0404       aNode->ChangeValue() = std::forward<TheItemType>(theItem);
0405       return &aNode->ChangeValue();
0406     }
0407     DataMapNode** data = (DataMapNode**)myData1;
0408     data[aHash] = new (this->myAllocator) DataMapNode (theKey, std::forward<TheItemType>(theItem), data[aHash]);
0409     Increment();
0410     return &data[aHash]->ChangeValue();
0411   }
0412 
0413   //! Bound binds Item to Key in map.
0414   //! @param theKey  key to add/update
0415   //! @param theItem new item; overrides value previously bound to the key
0416   //! @return pointer to modifiable Item
0417   TheItemType* Bound (TheKeyType&& theKey, TheItemType&& theItem)
0418   {
0419     if (Resizable()) 
0420       ReSize(Extent());
0421     size_t aHash;
0422     DataMapNode* aNode;
0423     if (lookup(theKey, aNode, aHash))
0424     {
0425       aNode->ChangeValue() = std::forward<TheItemType>(theItem);
0426       return &aNode->ChangeValue();
0427     }
0428     DataMapNode** data = (DataMapNode**)myData1;
0429     data[aHash] = new (this->myAllocator) DataMapNode (std::forward<TheKeyType>(theKey), 
0430                                                        std::forward<TheItemType>(theItem), data[aHash]);
0431     Increment();
0432     return &data[aHash]->ChangeValue();
0433   }
0434 
0435   //! IsBound
0436   Standard_Boolean IsBound(const TheKeyType& theKey) const
0437   {
0438     DataMapNode* p;
0439     return lookup(theKey, p);
0440   }
0441 
0442   //! UnBind removes Item Key pair from map
0443   Standard_Boolean UnBind(const TheKeyType& theKey)
0444   {
0445     if (IsEmpty()) 
0446       return Standard_False;
0447     DataMapNode** data = (DataMapNode**) myData1;
0448     const size_t k = HashCode(theKey,NbBuckets());
0449     DataMapNode* p = data[k];
0450     DataMapNode* q = NULL;
0451     while (p) 
0452     {
0453       if (IsEqual(p->Key(), theKey))
0454       {
0455         Decrement();
0456         if (q) 
0457           q->Next() = p->Next();
0458         else
0459           data[k] = (DataMapNode*) p->Next();
0460         p->~DataMapNode();
0461         this->myAllocator->Free(p);
0462         return Standard_True;
0463       }
0464       q = p;
0465       p = (DataMapNode*) p->Next();
0466     }
0467     return Standard_False;
0468   }
0469 
0470   //! Seek returns pointer to Item by Key. Returns
0471   //! NULL is Key was not bound.
0472   const TheItemType* Seek(const TheKeyType& theKey) const
0473   {
0474     DataMapNode* p = 0;
0475     if (!lookup(theKey, p))
0476       return 0L;
0477     return &p->Value();
0478   }
0479 
0480   //! Find returns the Item for Key. Raises if Key was not bound
0481   const TheItemType& Find(const TheKeyType& theKey) const
0482   {
0483     DataMapNode* p = 0;
0484     if (!lookup(theKey, p))
0485       throw Standard_NoSuchObject("NCollection_DataMap::Find");
0486     return p->Value();
0487   }
0488 
0489   //! Find Item for key with copying.
0490   //! @return true if key was found
0491   Standard_Boolean Find (const TheKeyType& theKey,
0492                          TheItemType&      theValue) const
0493   {
0494     DataMapNode* p = 0;
0495     if (!lookup(theKey, p))
0496       return Standard_False;
0497 
0498     theValue = p->Value();
0499     return Standard_True;
0500   }
0501 
0502   //! operator ()
0503   const TheItemType& operator() (const TheKeyType& theKey) const
0504   { return Find(theKey); }
0505 
0506   //! ChangeSeek returns modifiable pointer to Item by Key. Returns
0507   //! NULL is Key was not bound.
0508   TheItemType* ChangeSeek(const TheKeyType& theKey)
0509   {
0510     DataMapNode* p = 0;
0511     if (!lookup(theKey, p))
0512       return 0L;
0513     return &p->ChangeValue();
0514   }
0515 
0516   //! ChangeFind returns mofifiable Item by Key. Raises if Key was not bound
0517   TheItemType& ChangeFind (const TheKeyType& theKey)
0518   {
0519     DataMapNode* p = 0;
0520     if (!lookup(theKey, p))
0521       throw Standard_NoSuchObject("NCollection_DataMap::Find");
0522     return p->ChangeValue();
0523   }
0524 
0525   //! operator ()
0526   TheItemType& operator() (const TheKeyType& theKey)
0527   { return ChangeFind(theKey); }
0528 
0529   //! Clear data. If doReleaseMemory is false then the table of
0530   //! buckets is not released and will be reused.
0531   void Clear(const Standard_Boolean doReleaseMemory = Standard_False)
0532   { Destroy (DataMapNode::delNode, doReleaseMemory); }
0533 
0534   //! Clear data and reset allocator
0535   void Clear (const Handle(NCollection_BaseAllocator)& theAllocator)
0536   { 
0537     Clear(theAllocator != this->myAllocator);
0538     this->myAllocator = ( ! theAllocator.IsNull() ? theAllocator :
0539                     NCollection_BaseAllocator::CommonBaseAllocator() );
0540   }
0541 
0542   //! Destructor
0543   virtual ~NCollection_DataMap (void)
0544   { Clear(true); }
0545 
0546   //! Size
0547   Standard_Integer Size(void) const
0548   { return Extent(); }
0549 
0550   
0551  protected:
0552 
0553   //! Lookup for particular key in map.
0554   //! @param[in] theKey key to compute hash
0555   //! @param[out] theNode the detected node with equal key. Can be null.
0556   //! @return true if key is found
0557   Standard_Boolean lookup(const TheKeyType& theKey,DataMapNode*& theNode) const
0558   {
0559     if (IsEmpty())
0560       return Standard_False; // Not found
0561     for (theNode = (DataMapNode*)myData1[HashCode(theKey, NbBuckets())];
0562          theNode; theNode = (DataMapNode*)theNode->Next())
0563     {
0564       if (IsEqual(theNode->Key(), theKey))
0565         return Standard_True;
0566     }
0567     return Standard_False; // Not found
0568   }
0569 
0570   //! Lookup for particular key in map.
0571   //! @param[in] theKey key to compute hash
0572   //! @param[out] theNode the detected node with equal key. Can be null.
0573   //! @param[out] theHash computed bounded hash code for current key.
0574   //! @return true if key is found
0575   Standard_Boolean lookup(const TheKeyType& theKey, DataMapNode*& theNode, size_t& theHash) const
0576   {
0577     theHash = HashCode(theKey, NbBuckets());
0578     if (IsEmpty())
0579       return Standard_False; // Not found
0580     for (theNode = (DataMapNode*)myData1[theHash];
0581          theNode; theNode = (DataMapNode*)theNode->Next())
0582     {
0583       if (IsEqual(theNode->Key(), theKey))
0584       {
0585         return Standard_True;
0586       }
0587     }
0588     return Standard_False; // Not found
0589   }
0590 
0591   bool IsEqual(const TheKeyType& theKey1,
0592                const TheKeyType& theKey2) const
0593   {
0594     return myHasher(theKey1, theKey2);
0595   }
0596 
0597   size_t HashCode(const TheKeyType& theKey,
0598                   const int theUpperBound) const
0599   {
0600     return myHasher(theKey) % theUpperBound + 1;
0601   }
0602 
0603 private:
0604 
0605   Hasher myHasher;
0606 };
0607 
0608 #endif
0609