Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:04:19

0001 // Created on: 2002-04-24
0002 // Created by: Alexander KARTOMIN (akm)
0003 // Copyright (c) 2002-2014 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
0015 
0016 #ifndef NCollection_IndexedMap_HeaderFile
0017 #define NCollection_IndexedMap_HeaderFile
0018 
0019 #include <NCollection_BaseMap.hxx>
0020 #include <NCollection_TListNode.hxx>
0021 #include <NCollection_StlIterator.hxx>
0022 #include <Standard_NoSuchObject.hxx>
0023 
0024 #include <NCollection_DefaultHasher.hxx>
0025 
0026 #include <Standard_OutOfRange.hxx>
0027 
0028 /**
0029  * Purpose:     An indexed map is used to  store  keys and to bind
0030  *              an index to them.  Each new key stored in  the map
0031  *              gets an index.  Index are incremented  as keys are
0032  *              stored in the map. A key can be found by the index
0033  *              and an index by the  key. No key  but the last can
0034  *              be removed so the indices are in the range 1..Extent.
0035  *              See  the  class   Map   from NCollection   for   a
0036  *              discussion about the number of buckets.
0037  */            
0038 
0039 template < class TheKeyType, 
0040            class Hasher = NCollection_DefaultHasher<TheKeyType> > 
0041 class NCollection_IndexedMap : public NCollection_BaseMap
0042 {
0043 public:
0044   //! STL-compliant typedef for key type
0045   typedef TheKeyType key_type;
0046 
0047 protected:
0048   //! Adaptation of the TListNode to the INDEXEDmap
0049   class IndexedMapNode : public NCollection_TListNode<TheKeyType>
0050   {
0051   public:
0052     //! Constructor with 'Next'
0053     IndexedMapNode (const TheKeyType&      theKey1, 
0054                     const Standard_Integer theIndex,
0055                     NCollection_ListNode*  theNext1)
0056     : NCollection_TListNode<TheKeyType> (theKey1, theNext1),
0057       myIndex (theIndex)
0058     {}
0059     //! Constructor with 'Next'
0060     IndexedMapNode (TheKeyType&&           theKey1,
0061                     const Standard_Integer theIndex,
0062                     NCollection_ListNode*  theNext1)
0063     : NCollection_TListNode<TheKeyType> (std::forward<TheKeyType>(theKey1), theNext1),
0064       myIndex (theIndex)
0065     {}
0066     //! Key1
0067     TheKeyType& Key1() { return this->ChangeValue(); }
0068 
0069     //! Index
0070     Standard_Integer& Index() { return myIndex; }
0071     
0072     //! Static deleter to be passed to BaseList
0073     static void delNode (NCollection_ListNode * theNode, 
0074                          Handle(NCollection_BaseAllocator)& theAl)
0075     {
0076       ((IndexedMapNode *) theNode)->~IndexedMapNode();
0077       theAl->Free(theNode);
0078     }
0079 
0080   private:
0081     Standard_Integer myIndex;
0082   };
0083 
0084  public:
0085   // **************** Implementation of the Iterator interface.
0086   class Iterator
0087   {
0088   public:
0089     //! Empty constructor
0090     Iterator (void) :
0091       myMap(NULL),
0092       myIndex(0) {}
0093     //! Constructor
0094     Iterator (const NCollection_IndexedMap& theMap) :
0095       myMap((NCollection_IndexedMap *) &theMap),
0096       myIndex(1) {}
0097     //! Query if the end of collection is reached by iterator
0098     Standard_Boolean More(void) const
0099     { return (myMap != NULL) && (myIndex <= myMap->Extent()); }
0100     //! Make a step along the collection
0101     void Next(void)
0102     { myIndex++; }
0103     //! Value access
0104     const TheKeyType& Value(void) const
0105     {
0106       Standard_NoSuchObject_Raise_if(!More(), "NCollection_IndexedMap::Iterator::Value");
0107       return myMap->FindKey(myIndex);
0108     }
0109 
0110     //! Performs comparison of two iterators.
0111     Standard_Boolean IsEqual (const Iterator& theOther) const
0112     {
0113       return myMap == theOther.myMap && myIndex == theOther.myIndex;
0114     }
0115     
0116   private:
0117     NCollection_IndexedMap * myMap;   // Pointer to the map being iterated
0118     Standard_Integer         myIndex; // Current index
0119   };
0120   
0121   //! Shorthand for a constant iterator type.
0122   typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheKeyType, true> const_iterator;
0123 
0124   //! Returns a const iterator pointing to the first element in the map.
0125   const_iterator cbegin() const { return Iterator (*this); }
0126 
0127   //! Returns a const iterator referring to the past-the-end element in the map.
0128   const_iterator cend() const { return Iterator(); }
0129   
0130  public:
0131   // ---------- PUBLIC METHODS ------------
0132 
0133   //! Empty constructor.
0134   NCollection_IndexedMap() : NCollection_BaseMap (1, true, Handle(NCollection_BaseAllocator)()) {}
0135 
0136   //! Constructor
0137   explicit NCollection_IndexedMap (const Standard_Integer theNbBuckets,
0138                                    const Handle(NCollection_BaseAllocator)& theAllocator=0L)
0139   : NCollection_BaseMap (theNbBuckets, true, theAllocator) {}
0140 
0141   //! Copy constructor
0142   NCollection_IndexedMap (const NCollection_IndexedMap& theOther)
0143   : NCollection_BaseMap (theOther.NbBuckets(), true, theOther.myAllocator)
0144   { *this = theOther; }
0145 
0146   //! Move constructor
0147   NCollection_IndexedMap(NCollection_IndexedMap&& theOther) noexcept :
0148     NCollection_BaseMap(std::forward<NCollection_BaseMap>(theOther))
0149   {}
0150 
0151   //! Exchange the content of two maps without re-allocations.
0152   //! Notice that allocators will be swapped as well!
0153   void Exchange (NCollection_IndexedMap& theOther)
0154   {
0155     this->exchangeMapsData (theOther);
0156   }
0157 
0158   //! Assign.
0159   //! This method does not change the internal allocator.
0160   NCollection_IndexedMap& Assign (const NCollection_IndexedMap& theOther)
0161   { 
0162     if (this == &theOther)
0163       return *this;
0164 
0165     Clear();
0166     Standard_Integer anExt = theOther.Extent();
0167     if (anExt)
0168     {
0169       ReSize (anExt-1); //mySize is same after resize
0170       for (Standard_Integer anIndexIter = 1; anIndexIter <= anExt; ++anIndexIter)
0171       {
0172         const TheKeyType& aKey1 = theOther.FindKey (anIndexIter);
0173         const size_t iK1 = HashCode (aKey1, NbBuckets());
0174         IndexedMapNode* pNode = new (this->myAllocator) IndexedMapNode (aKey1, anIndexIter, myData1[iK1]);
0175         myData1[iK1]             = pNode;
0176         myData2[anIndexIter - 1] = pNode;
0177         Increment();
0178       }
0179     }
0180     return *this;
0181   }
0182 
0183   //! Assignment operator
0184   NCollection_IndexedMap& operator= (const NCollection_IndexedMap& theOther)
0185   {
0186     return Assign (theOther);
0187   }
0188 
0189   //! Move operator
0190   NCollection_IndexedMap& operator= (NCollection_IndexedMap&& theOther) noexcept
0191   {
0192     if (this == &theOther)
0193       return *this;
0194     exchangeMapsData(theOther);
0195     return *this;
0196   }
0197 
0198   //! ReSize
0199   void ReSize (const Standard_Integer theExtent)
0200   {
0201     NCollection_ListNode** ppNewData1 = NULL;
0202     NCollection_ListNode** ppNewData2 = NULL;
0203     Standard_Integer newBuck;
0204     if (BeginResize (theExtent, newBuck, ppNewData1, ppNewData2))
0205     {
0206       if (myData1) 
0207       {
0208         for (Standard_Integer aBucketIter = 0; aBucketIter <= NbBuckets(); ++aBucketIter)
0209         {
0210           if (myData1[aBucketIter])
0211           {
0212             IndexedMapNode* p = (IndexedMapNode* )myData1[aBucketIter];
0213             while (p) 
0214             {
0215               const size_t iK1 = HashCode (p->Key1(), newBuck);
0216               IndexedMapNode* q = (IndexedMapNode* )p->Next();
0217               p->Next() = ppNewData1[iK1];
0218               ppNewData1[iK1] = p;
0219               p = q;
0220             }
0221           }
0222         }
0223       }
0224       EndResize (theExtent, newBuck, ppNewData1, (NCollection_ListNode**)
0225         Standard::Reallocate(myData2, (newBuck + 1) * sizeof(NCollection_ListNode*)));
0226     }
0227   }
0228 
0229   //! Add
0230   Standard_Integer Add (const TheKeyType& theKey1)
0231   {
0232     if (Resizable())
0233     {
0234       ReSize (Extent());
0235     }
0236     IndexedMapNode* aNode;
0237     size_t aHash;
0238     if (lookup(theKey1, aNode, aHash))
0239     {
0240       return aNode->Index();
0241     }
0242     const Standard_Integer aNewIndex = Increment();
0243     aNode = new (this->myAllocator) IndexedMapNode (theKey1, aNewIndex, myData1[aHash]);
0244     myData1[aHash]         = aNode;
0245     myData2[aNewIndex - 1] = aNode;
0246     return aNewIndex;
0247   }
0248 
0249   //! Add
0250   Standard_Integer Add (TheKeyType&& theKey1)
0251   {
0252     if (Resizable())
0253     {
0254       ReSize(Extent());
0255     }
0256     size_t aHash;
0257     IndexedMapNode* aNode;
0258     if (lookup(theKey1, aNode, aHash))
0259     {
0260       return aNode->Index();
0261     }
0262     const Standard_Integer aNewIndex = Increment();
0263     aNode = new (this->myAllocator) IndexedMapNode(std::forward<TheKeyType>(theKey1),
0264                                                    aNewIndex, myData1[aHash]);
0265     myData1[aHash] = aNode;
0266     myData2[aNewIndex - 1] = aNode;
0267     return aNewIndex;
0268   }
0269 
0270   //! Contains
0271   Standard_Boolean Contains (const TheKeyType& theKey1) const
0272   {
0273     IndexedMapNode* p;
0274     return lookup(theKey1, p);
0275   }
0276 
0277   //! Substitute
0278   void Substitute (const Standard_Integer theIndex,
0279                    const TheKeyType& theKey1)
0280   {
0281     Standard_OutOfRange_Raise_if (theIndex < 1 || theIndex > Extent(),
0282                                   "NCollection_IndexedMap::Substitute : "
0283                                   "Index is out of range");
0284 
0285     // check if theKey1 is not already in the map
0286     IndexedMapNode* aNode;
0287     size_t aHash;
0288     if (lookup(theKey1, aNode, aHash))
0289     {
0290       if (aNode->Index() != theIndex)
0291       {
0292         throw Standard_DomainError ("NCollection_IndexedMap::Substitute : "
0293                                     "Attempt to substitute existing key");
0294       }
0295       aNode->Key1() = theKey1;
0296       return;
0297     }
0298     // Find the node for the index I
0299     aNode = (IndexedMapNode* )myData2[theIndex - 1];
0300     
0301     // remove the old key
0302     const size_t iK = HashCode (aNode->Key1(), NbBuckets());
0303     IndexedMapNode * q = (IndexedMapNode *) myData1[iK];
0304     if (q == aNode)
0305       myData1[iK] = (IndexedMapNode *) aNode->Next();
0306     else 
0307     {
0308       while (q->Next() != aNode) 
0309         q = (IndexedMapNode *) q->Next();
0310       q->Next() = aNode->Next();
0311     }
0312 
0313     // update the node
0314     aNode->Key1() = theKey1;
0315     aNode->Next() = myData1[aHash];
0316     myData1[aHash] = aNode;
0317   }
0318 
0319   //! Swaps two elements with the given indices.
0320   void Swap (const Standard_Integer theIndex1,
0321              const Standard_Integer theIndex2)
0322   {
0323     Standard_OutOfRange_Raise_if (theIndex1 < 1 || theIndex1 > Extent()
0324                                || theIndex2 < 1 || theIndex2 > Extent(), "NCollection_IndexedMap::Swap");
0325 
0326     if (theIndex1 == theIndex2)
0327     {
0328       return;
0329     }
0330 
0331     IndexedMapNode* aP1 = (IndexedMapNode* )myData2[theIndex1 - 1];
0332     IndexedMapNode* aP2 = (IndexedMapNode* )myData2[theIndex2 - 1];
0333     std::swap (aP1->Index(), aP2->Index());
0334     myData2[theIndex2 - 1] = aP1;
0335     myData2[theIndex1 - 1] = aP2;
0336   }
0337 
0338   //! RemoveLast
0339   void RemoveLast (void)
0340   {
0341     const Standard_Integer aLastIndex = Extent();
0342     Standard_OutOfRange_Raise_if (aLastIndex == 0, "NCollection_IndexedMap::RemoveLast");
0343 
0344     // Find the node for the last index and remove it
0345     IndexedMapNode* p = (IndexedMapNode* )myData2[aLastIndex - 1];
0346     myData2[aLastIndex - 1] = NULL;
0347 
0348     // remove the key
0349     const size_t iK1 = HashCode (p->Key1(), NbBuckets());
0350     IndexedMapNode* q = (IndexedMapNode *) myData1[iK1];
0351     if (q == p)
0352       myData1[iK1] = (IndexedMapNode *) p->Next();
0353     else 
0354     {
0355       while (q->Next() != p) 
0356         q = (IndexedMapNode *) q->Next();
0357       q->Next() = p->Next();
0358     }
0359     p->~IndexedMapNode();
0360     this->myAllocator->Free(p);
0361     Decrement();
0362   }
0363 
0364   //! Remove the key of the given index.
0365   //! Caution! The index of the last key can be changed.
0366   void RemoveFromIndex(const Standard_Integer theIndex)
0367   {
0368     Standard_OutOfRange_Raise_if(theIndex < 1 || theIndex > Extent(), "NCollection_IndexedMap::RemoveFromIndex");
0369     const Standard_Integer aLastInd = Extent();
0370     if (theIndex != aLastInd)
0371     {
0372       Swap(theIndex, aLastInd);
0373     }
0374     RemoveLast();
0375   }
0376 
0377   //! Remove the given key.
0378   //! Caution! The index of the last key can be changed.
0379   Standard_Boolean RemoveKey (const TheKeyType& theKey1)
0380   {
0381     Standard_Integer anIndToRemove = FindIndex(theKey1);
0382     if (anIndToRemove < 1)
0383     {
0384       return Standard_False;
0385     }
0386 
0387     RemoveFromIndex (anIndToRemove);
0388     return Standard_True;
0389   }
0390 
0391   //! FindKey
0392   const TheKeyType& FindKey (const Standard_Integer theIndex) const
0393   {
0394     Standard_OutOfRange_Raise_if (theIndex < 1 || theIndex > Extent(), "NCollection_IndexedMap::FindKey");
0395     IndexedMapNode* pNode2 = (IndexedMapNode* )myData2[theIndex - 1];
0396     return pNode2->Key1();
0397   }
0398 
0399   //! operator ()
0400   const TheKeyType& operator() (const Standard_Integer theIndex) const
0401   { return FindKey (theIndex); }
0402 
0403   //! FindIndex
0404   Standard_Integer FindIndex(const TheKeyType& theKey1) const
0405   {
0406     IndexedMapNode* aNode;
0407     if (lookup(theKey1, aNode))
0408     {
0409       return aNode->Index();
0410     }
0411     return 0;
0412   }
0413 
0414   //! Clear data. If doReleaseMemory is false then the table of
0415   //! buckets is not released and will be reused.
0416   void Clear(const Standard_Boolean doReleaseMemory = Standard_False)
0417   { Destroy (IndexedMapNode::delNode, doReleaseMemory); }
0418 
0419   //! Clear data and reset allocator
0420   void Clear (const Handle(NCollection_BaseAllocator)& theAllocator)
0421   { 
0422     Clear(theAllocator != this->myAllocator);
0423     this->myAllocator = ( ! theAllocator.IsNull() ? theAllocator :
0424                     NCollection_BaseAllocator::CommonBaseAllocator() );
0425   }
0426 
0427   //! Destructor
0428   virtual ~NCollection_IndexedMap (void)
0429   { Clear(true); }
0430 
0431   //! Size
0432   Standard_Integer Size(void) const
0433   { return Extent(); }
0434 
0435 protected:
0436 
0437   //! Lookup for particular key in map.
0438   //! @param[in] theKey key to compute hash
0439   //! @param[out] theNode the detected node with equal key. Can be null.
0440   //! @param[out] theHash computed bounded hash code for current key.
0441   //! @return true if key is found
0442   Standard_Boolean lookup(const TheKeyType& theKey, IndexedMapNode*& theNode, size_t& theHash) const
0443   {
0444     theHash = HashCode(theKey, NbBuckets());
0445     if (IsEmpty())
0446       return Standard_False; // Not found
0447     for (theNode = (IndexedMapNode*)myData1[theHash];
0448          theNode; theNode = (IndexedMapNode*)theNode->Next())
0449     {
0450       if (IsEqual(theNode->Key1(), theKey))
0451         return Standard_True;
0452     }
0453     return Standard_False; // Not found
0454   }
0455 
0456   //! Lookup for particular key in map.
0457   //! @param[in] theKey key to compute hash
0458   //! @param[out] theNode the detected node with equal key. Can be null.
0459   //! @return true if key is found
0460   Standard_Boolean lookup(const TheKeyType& theKey, IndexedMapNode*& theNode) const
0461   {
0462     if (IsEmpty())
0463       return Standard_False; // Not found
0464     for (theNode = (IndexedMapNode*)myData1[HashCode(theKey, NbBuckets())];
0465          theNode; theNode = (IndexedMapNode*)theNode->Next())
0466     {
0467       if (IsEqual(theNode->Key1(), theKey))
0468       {
0469         return Standard_True;
0470       }
0471     }
0472     return Standard_False; // Not found
0473   }
0474 
0475   bool IsEqual(const TheKeyType& theKey1,
0476                const TheKeyType& theKey2) const
0477   {
0478     return myHasher(theKey1, theKey2);
0479   }
0480 
0481   size_t HashCode(const TheKeyType& theKey,
0482                   const int theUpperBound) const
0483   {
0484     return myHasher(theKey) % theUpperBound + 1;
0485   }
0486 
0487 protected:
0488 
0489   Hasher myHasher;
0490 };
0491 
0492 #endif