Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/opencascade/NCollection_Map.hxx was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // Created on: 2002-04-23
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_Map_HeaderFile
0017 #define NCollection_Map_HeaderFile
0018 
0019 #include <NCollection_DataMap.hxx>
0020 #include <NCollection_TListNode.hxx>
0021 #include <NCollection_StlIterator.hxx>
0022 #include <NCollection_DefaultHasher.hxx>
0023 
0024 #include <Standard_NoSuchObject.hxx>
0025 #include <utility>
0026 
0027 /**
0028  * Purpose:     Single hashed Map. This  Map is used  to store and
0029  *              retrieve keys in linear time.
0030  *              
0031  *              The ::Iterator class can be  used to explore  the
0032  *              content of the map. It is not  wise to iterate and
0033  *              modify a map in parallel.
0034  *               
0035  *              To compute  the hashcode of  the key the  function
0036  *              ::HashCode must be defined in the global namespace
0037  *               
0038  *              To compare two keys the function ::IsEqual must be
0039  *              defined in the global namespace.
0040  *               
0041  *              The performance of  a Map is conditioned  by  its
0042  *              number of buckets that  should be kept greater  to
0043  *              the number   of keys.  This  map has  an automatic
0044  *              management of the number of buckets. It is resized
0045  *              when  the number of Keys  becomes greater than the
0046  *              number of buckets.
0047  *              
0048  *              If you have a fair  idea of the number of  objects
0049  *              you  can save on automatic   resizing by giving  a
0050  *              number of buckets  at creation or using the ReSize
0051  *              method. This should be  consider only for  crucial
0052  *              optimisation issues.
0053  */            
0054 
0055 template < class TheKeyType, 
0056            class Hasher = NCollection_DefaultHasher<TheKeyType> >
0057 class NCollection_Map : public NCollection_BaseMap
0058 {
0059 public:
0060   //! STL-compliant typedef for key type
0061   typedef TheKeyType key_type;
0062   typedef Hasher hasher;
0063 
0064 public:
0065   //!   Adaptation of the TListNode to the map notations
0066   class MapNode : public NCollection_TListNode<TheKeyType>
0067   {
0068   public:
0069     //! Constructor with 'Next'
0070     MapNode (const TheKeyType& theKey, 
0071              NCollection_ListNode* theNext) :
0072       NCollection_TListNode<TheKeyType> (theKey, theNext) {}
0073     //! Constructor with 'Next'
0074     MapNode (TheKeyType&& theKey,
0075              NCollection_ListNode* theNext) :
0076       NCollection_TListNode<TheKeyType> (std::forward<TheKeyType>(theKey), theNext) {}
0077     //! Key
0078     const TheKeyType& Key (void)
0079     { return this->Value(); }
0080 
0081   };
0082 
0083  public:
0084   //!   Implementation of the Iterator interface.
0085   class Iterator : public NCollection_BaseMap::Iterator
0086   {
0087   public:
0088     //! Empty constructor
0089     Iterator (void) :
0090       NCollection_BaseMap::Iterator() {}
0091     //! Constructor
0092     Iterator (const NCollection_Map& theMap) :
0093       NCollection_BaseMap::Iterator(theMap) {}
0094     //! Query if the end of collection is reached by iterator
0095     Standard_Boolean More(void) const
0096     { return PMore(); }
0097     //! Make a step along the collection
0098     void Next(void)
0099     { PNext(); }
0100     //! Value inquiry
0101     const TheKeyType& Value(void) const
0102     {
0103       Standard_NoSuchObject_Raise_if (!More(), "NCollection_Map::Iterator::Value");  
0104       return ((MapNode *) myNode)->Value();
0105     }
0106 
0107     //! Key
0108     const TheKeyType& Key (void) const
0109     { 
0110       Standard_NoSuchObject_Raise_if (!More(), "NCollection_Map::Iterator::Key");  
0111       return ((MapNode *) myNode)->Value();
0112     }
0113   };
0114   
0115   //! Shorthand for a constant iterator type.
0116   typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheKeyType, true> const_iterator;
0117 
0118   //! Returns a const iterator pointing to the first element in the map.
0119   const_iterator cbegin() const { return Iterator (*this); }
0120 
0121   //! Returns a const iterator referring to the past-the-end element in the map.
0122   const_iterator cend() const { return Iterator(); }
0123 
0124  public:
0125   // ---------- PUBLIC METHODS ------------
0126 
0127   //! Empty constructor.
0128   NCollection_Map() : NCollection_BaseMap (1, Standard_True, Handle(NCollection_BaseAllocator)()) {}
0129 
0130   //! Constructor
0131   explicit NCollection_Map (const Standard_Integer theNbBuckets,
0132                             const Handle(NCollection_BaseAllocator)& theAllocator = 0L)
0133   : NCollection_BaseMap (theNbBuckets, Standard_True, theAllocator) {}
0134 
0135   //! Copy constructor
0136   NCollection_Map(const NCollection_Map& theOther) :
0137     NCollection_BaseMap(theOther.NbBuckets(), Standard_True, theOther.myAllocator)
0138   {
0139     const int anExt = theOther.Extent();
0140     if (anExt <= 0)
0141       return;
0142     ReSize(anExt - 1);
0143     for (Iterator anIter(theOther); anIter.More(); anIter.Next())
0144       Add(anIter.Key());
0145   }
0146 
0147   //! Move constructor
0148   NCollection_Map (NCollection_Map&& theOther) noexcept :
0149     NCollection_BaseMap (std::forward<NCollection_BaseMap>(theOther))
0150   {}
0151 
0152   //! Exchange the content of two maps without re-allocations.
0153   //! Notice that allocators will be swapped as well!
0154   void Exchange (NCollection_Map& theOther)
0155   {
0156     this->exchangeMapsData (theOther);
0157   }
0158 
0159   //! Assign.
0160   //! This method does not change the internal allocator.
0161   NCollection_Map& Assign (const NCollection_Map& theOther)
0162   { 
0163     if (this == &theOther)
0164       return *this;
0165 
0166     Clear();
0167     int anExt = theOther.Extent();
0168     if (anExt)
0169     {
0170       ReSize (anExt-1);
0171       Iterator anIter(theOther);
0172       for (; anIter.More(); anIter.Next())
0173         Add (anIter.Key());
0174     }
0175     return *this;
0176   }
0177 
0178   //! Assign operator
0179   NCollection_Map& operator= (const NCollection_Map& theOther)
0180   {
0181     return Assign(theOther);
0182   }
0183 
0184   //! Move operator
0185   NCollection_Map& operator= (NCollection_Map&& theOther) noexcept
0186   {
0187     if (this == &theOther)
0188       return *this;
0189     exchangeMapsData(theOther);
0190     return *this;
0191   }
0192 
0193   //! ReSize
0194   void ReSize (const Standard_Integer N)
0195   {
0196     NCollection_ListNode** newdata = 0L;
0197     NCollection_ListNode** dummy = 0L;
0198     Standard_Integer newBuck;
0199     if (BeginResize (N, newBuck, newdata, dummy))
0200     {
0201       if (myData1) 
0202       {
0203         MapNode** olddata = (MapNode**) myData1;
0204         MapNode *p, *q;
0205         for (int i = 0; i <= NbBuckets(); i++) 
0206         {
0207           if (olddata[i]) 
0208           {
0209             p = olddata[i];
0210             while (p) 
0211             {
0212               const size_t k = HashCode(p->Key(),newBuck);
0213               q = (MapNode*) p->Next();
0214               p->Next() = newdata[k];
0215               newdata[k] = p;
0216               p = q;
0217             }
0218           }
0219         }
0220       }
0221       EndResize (N, newBuck, newdata, dummy);
0222     }
0223   }
0224 
0225   //! Add
0226   Standard_Boolean Add(const TheKeyType& theKey)
0227   {
0228     if (Resizable()) 
0229       ReSize(Extent());
0230     MapNode* aNode;
0231     size_t aHash;
0232     if (lookup(theKey, aNode, aHash))
0233     {
0234       return Standard_False;
0235     }
0236     MapNode** data = (MapNode**)myData1;
0237     data[aHash] = new (this->myAllocator) MapNode(theKey,data[aHash]);
0238     Increment();
0239     return Standard_True;
0240   }
0241 
0242   //! Add
0243   Standard_Boolean Add(TheKeyType&& theKey)
0244   {
0245     if (Resizable()) 
0246       ReSize(Extent());
0247     MapNode* aNode;
0248     size_t aHash;
0249     if (lookup(theKey, aNode, aHash))
0250     {
0251       return Standard_False;
0252     }
0253     MapNode** data = (MapNode**)myData1;
0254     data[aHash] = new (this->myAllocator) MapNode(std::forward<TheKeyType>(theKey),data[aHash]);
0255     Increment();
0256     return Standard_True;
0257   }
0258 
0259   //! Added: add a new key if not yet in the map, and return 
0260   //! reference to either newly added or previously existing object
0261   const TheKeyType& Added(const TheKeyType& theKey)
0262   {
0263     if (Resizable()) 
0264       ReSize(Extent());
0265     MapNode* aNode;
0266     size_t aHash;
0267     if (lookup(theKey, aNode, aHash))
0268     {
0269       return aNode->Key();
0270     }
0271     MapNode** data = (MapNode**)myData1;
0272     data[aHash] = new (this->myAllocator) MapNode(theKey,data[aHash]);
0273     Increment();
0274     return data[aHash]->Key();
0275   }
0276 
0277   //! Added: add a new key if not yet in the map, and return 
0278   //! reference to either newly added or previously existing object
0279   const TheKeyType& Added(TheKeyType&& theKey)
0280   {
0281     if (Resizable()) 
0282       ReSize(Extent());
0283     MapNode* aNode;
0284     size_t aHash;
0285     if (lookup(theKey, aNode, aHash))
0286     {
0287       return aNode->Key();
0288     }
0289     MapNode** data = (MapNode**)myData1;
0290     data[aHash] = new (this->myAllocator) MapNode(std::forward<TheKeyType>(theKey),data[aHash]);
0291     Increment();
0292     return data[aHash]->Key();
0293   }
0294 
0295   //! Contains
0296   Standard_Boolean Contains(const TheKeyType& theKey) const
0297   {
0298     MapNode* p;
0299     return lookup(theKey, p);
0300   }
0301 
0302   //! Remove
0303   Standard_Boolean Remove(const TheKeyType& K)
0304   {
0305     if (IsEmpty()) 
0306       return Standard_False;
0307     MapNode** data = (MapNode**) myData1;
0308     const size_t k = HashCode(K,NbBuckets());
0309     MapNode* p = data[k];
0310     MapNode* q = NULL;
0311     while (p) 
0312     {
0313       if (IsEqual(p->Key(),K)) 
0314       {
0315         Decrement();
0316         if (q) 
0317           q->Next() = p->Next();
0318         else
0319           data[k] = (MapNode*) p->Next();
0320         p->~MapNode();
0321         this->myAllocator->Free(p);
0322         return Standard_True;
0323       }
0324       q = p;
0325       p = (MapNode*) p->Next();
0326     }
0327     return Standard_False;
0328   }
0329 
0330   //! Clear data. If doReleaseMemory is false then the table of
0331   //! buckets is not released and will be reused.
0332   void Clear(const Standard_Boolean doReleaseMemory = Standard_False)
0333   { Destroy (MapNode::delNode, doReleaseMemory); }
0334 
0335   //! Clear data and reset allocator
0336   void Clear (const Handle(NCollection_BaseAllocator)& theAllocator)
0337   { 
0338     Clear(theAllocator != this->myAllocator);
0339     this->myAllocator = ( ! theAllocator.IsNull() ? theAllocator :
0340                     NCollection_BaseAllocator::CommonBaseAllocator() );
0341   }
0342 
0343   //! Destructor
0344   virtual ~NCollection_Map (void)
0345   { Clear(true); }
0346 
0347   //! Size
0348   Standard_Integer Size(void) const
0349   { return Extent(); }
0350 
0351  public:
0352   //!@name Boolean operations with maps as sets of keys
0353   //!@{
0354 
0355   //! @return true if two maps contains exactly the same keys
0356   Standard_Boolean IsEqual (const NCollection_Map& theOther) const
0357   {
0358     return Extent() == theOther.Extent()
0359         && Contains (theOther);
0360   }
0361 
0362   //! @return true if this map contains ALL keys of another map.
0363   Standard_Boolean Contains (const NCollection_Map& theOther) const
0364   {
0365     if (this == &theOther
0366      || theOther.IsEmpty())
0367     {
0368       return Standard_True;
0369     }
0370     else if (Extent() < theOther.Extent())
0371     {
0372       return Standard_False;
0373     }
0374 
0375     for (Iterator anIter (theOther); anIter.More(); anIter.Next())
0376     {
0377       if (!Contains (anIter.Key()))
0378       {
0379         return Standard_False;
0380       }
0381     }
0382 
0383     return Standard_True;
0384   }
0385 
0386   //! Sets this Map to be the result of union (aka addition, fuse, merge, boolean OR) operation between two given Maps
0387   //! The new Map contains the values that are contained either in the first map or in the second map or in both.
0388   //! All previous content of this Map is cleared.
0389   //! This map (result of the boolean operation) can also be passed as one of operands.
0390   void Union (const NCollection_Map& theLeft,
0391               const NCollection_Map& theRight)
0392   {
0393     if (&theLeft == &theRight)
0394     {
0395       Assign (theLeft);
0396       return;
0397     }
0398 
0399     if (this != &theLeft
0400      && this != &theRight)
0401     {
0402       Clear();
0403     }
0404 
0405     if (this != &theLeft)
0406     {
0407       for (Iterator anIter (theLeft); anIter.More(); anIter.Next())
0408       {
0409         Add (anIter.Key());
0410       }
0411     }
0412     if (this != &theRight)
0413     {
0414       for (Iterator anIter (theRight); anIter.More(); anIter.Next())
0415       {
0416         Add (anIter.Key());
0417       }
0418     }
0419   }
0420 
0421   //! Apply to this Map the boolean operation union (aka addition, fuse, merge, boolean OR) with another (given) Map.
0422   //! The result contains the values that were previously contained in this map or contained in the given (operand) map.
0423   //! This algorithm is similar to method Union().
0424   //! Returns True if contents of this map is changed.
0425   Standard_Boolean Unite (const NCollection_Map& theOther)
0426   {
0427     if (this == &theOther)
0428     {
0429       return Standard_False;
0430     }
0431 
0432     const Standard_Integer anOldExtent = Extent();
0433     Union (*this, theOther);
0434     return anOldExtent != Extent();
0435   }
0436 
0437   //! Returns true if this and theMap have common elements.
0438   Standard_Boolean HasIntersection (const NCollection_Map& theMap) const
0439   {
0440     const NCollection_Map* aMap1 = this;
0441     const NCollection_Map* aMap2 = &theMap;
0442     if (theMap.Size() < Size())
0443     {
0444       aMap1 = &theMap;
0445       aMap2 = this;
0446     }
0447 
0448     for (NCollection_Map::Iterator aIt(*aMap1); aIt.More(); aIt.Next())
0449     {
0450       if (aMap2->Contains(aIt.Value()))
0451       {
0452         return Standard_True;
0453       }
0454     }
0455 
0456     return Standard_False;
0457   }
0458 
0459   //! Sets this Map to be the result of intersection (aka multiplication, common, boolean AND) operation between two given Maps.
0460   //! The new Map contains only the values that are contained in both map operands.
0461   //! All previous content of this Map is cleared.
0462   //! This same map (result of the boolean operation) can also be used as one of operands.
0463   void Intersection (const NCollection_Map& theLeft,
0464                      const NCollection_Map& theRight)
0465   {
0466     if (&theLeft == &theRight)
0467     {
0468       Assign (theLeft);
0469       return;
0470     }
0471 
0472     if (this == &theLeft)
0473     {
0474       NCollection_Map aCopy (1, this->myAllocator);
0475       Exchange     (aCopy);
0476       Intersection (aCopy, theRight);
0477       return;
0478     }
0479     else if (this == &theRight)
0480     {
0481       NCollection_Map aCopy (1, this->myAllocator);
0482       Exchange     (aCopy);
0483       Intersection (theLeft, aCopy);
0484       return;
0485     }
0486 
0487     Clear();
0488     if (theLeft.Extent() < theRight.Extent())
0489     {
0490       for (Iterator anIter (theLeft); anIter.More(); anIter.Next())
0491       {
0492         if (theRight.Contains (anIter.Key()))
0493         {
0494           Add (anIter.Key());
0495         }
0496       }
0497     }
0498     else
0499     {
0500       for (Iterator anIter (theRight); anIter.More(); anIter.Next())
0501       {
0502         if (theLeft.Contains (anIter.Key()))
0503         {
0504           Add (anIter.Key());
0505         }
0506       }
0507     }
0508   }
0509 
0510   //! Apply to this Map the intersection operation (aka multiplication, common, boolean AND) with another (given) Map.
0511   //! The result contains only the values that are contained in both this and the given maps.
0512   //! This algorithm is similar to method Intersection().
0513   //! Returns True if contents of this map is changed.
0514   Standard_Boolean Intersect (const NCollection_Map& theOther)
0515   {
0516     if (this == &theOther
0517      || IsEmpty())
0518     {
0519       return Standard_False;
0520     }
0521 
0522     const Standard_Integer anOldExtent = Extent();
0523     Intersection (*this, theOther);
0524     return anOldExtent != Extent();
0525   }
0526 
0527   //! Sets this Map to be the result of subtraction (aka set-theoretic difference, relative complement,
0528   //! exclude, cut, boolean NOT) operation between two given Maps.
0529   //! The new Map contains only the values that are contained in the first map operands and not contained in the second one.
0530   //! All previous content of this Map is cleared.
0531   void Subtraction (const NCollection_Map& theLeft,
0532                     const NCollection_Map& theRight)
0533   {
0534     if (this == &theLeft)
0535     {
0536       Subtract (theRight);
0537       return;
0538     }
0539     else if (this == &theRight)
0540     {
0541       NCollection_Map aCopy (1, this->myAllocator);
0542       Exchange    (aCopy);
0543       Subtraction (theLeft, aCopy);
0544       return;
0545     }
0546 
0547     Assign   (theLeft);
0548     Subtract (theRight);
0549   }
0550 
0551   //! Apply to this Map the subtraction (aka set-theoretic difference, relative complement,
0552   //! exclude, cut, boolean NOT) operation with another (given) Map.
0553   //! The result contains only the values that were previously contained in this map and not contained in this map.
0554   //! This algorithm is similar to method Subtract() with two operands.
0555   //! Returns True if contents of this map is changed.
0556   Standard_Boolean Subtract (const NCollection_Map& theOther)
0557   {
0558     if (this == &theOther)
0559     {
0560       if (IsEmpty())
0561       {
0562         return Standard_False;
0563       }
0564 
0565       Clear();
0566       return Standard_True;
0567     }
0568 
0569     const Standard_Integer anOldExtent = Extent();
0570     for (Iterator anIter (theOther); anIter.More(); anIter.Next())
0571     {
0572       Remove (anIter.Key());
0573     }
0574     return anOldExtent != Extent();
0575   }
0576 
0577   //! Sets this Map to be the result of symmetric difference (aka exclusive disjunction, boolean XOR) operation between two given Maps.
0578   //! The new Map contains the values that are contained only in the first or the second operand maps but not in both.
0579   //! All previous content of this Map is cleared. This map (result of the boolean operation) can also be used as one of operands.
0580   void Difference (const NCollection_Map& theLeft,
0581                    const NCollection_Map& theRight)
0582   {
0583     if (&theLeft == &theRight)
0584     {
0585       Clear();
0586       return;
0587     }
0588     else if (this == &theLeft)
0589     {
0590       NCollection_Map aCopy (1, this->myAllocator);
0591       Exchange   (aCopy);
0592       Difference (aCopy, theRight);
0593       return;
0594     }
0595     else if (this == &theRight)
0596     {
0597       NCollection_Map aCopy (1, this->myAllocator);
0598       Exchange   (aCopy);
0599       Difference (theLeft, aCopy);
0600       return;
0601     }
0602 
0603     Clear();
0604     for (Iterator anIter (theLeft); anIter.More(); anIter.Next())
0605     {
0606       if (!theRight.Contains (anIter.Key()))
0607       {
0608         Add (anIter.Key());
0609       }
0610     }
0611     for (Iterator anIter (theRight); anIter.More(); anIter.Next())
0612     {
0613       if (!theLeft.Contains (anIter.Key()))
0614       {
0615         Add (anIter.Key());
0616       }
0617     }
0618   }
0619 
0620   //! Apply to this Map the symmetric difference (aka exclusive disjunction, boolean XOR) operation with another (given) Map.
0621   //! The result contains the values that are contained only in this or the operand map, but not in both.
0622   //! This algorithm is similar to method Difference().
0623   //! Returns True if contents of this map is changed.
0624   Standard_Boolean Differ (const NCollection_Map& theOther)
0625   {
0626     if (this == &theOther)
0627     {
0628       if (IsEmpty())
0629       {
0630         return Standard_False;
0631       }
0632       Clear();
0633       return Standard_True;
0634     }
0635 
0636     const Standard_Integer anOldExtent = Extent();
0637     Difference (*this, theOther);
0638     return anOldExtent != Extent();
0639   }
0640 
0641 protected:
0642 
0643   //! Lookup for particular key in map.
0644   //! @param[in] theKey key to compute hash
0645   //! @param[out] theNode the detected node with equal key. Can be null.
0646   //! @param[out] theHash computed bounded hash code for current key.
0647   //! @return true if key is found
0648   Standard_Boolean lookup(const TheKeyType& theKey, MapNode*& theNode, size_t& theHash) const
0649   {
0650     theHash = HashCode(theKey, NbBuckets());
0651     if (IsEmpty())
0652       return Standard_False; // Not found
0653     for (theNode = (MapNode*)myData1[theHash];
0654          theNode; theNode = (MapNode*)theNode->Next())
0655     {
0656       if (IsEqual(theNode->Key(), theKey)) 
0657         return Standard_True;
0658     }
0659     return Standard_False; // Not found
0660   }
0661 
0662   //! Lookup for particular key in map.
0663   //! @param[in] theKey key to compute hash
0664   //! @param[out] theNode the detected node with equal key. Can be null.
0665   //! @return true if key is found
0666   Standard_Boolean lookup(const TheKeyType& theKey, MapNode*& theNode) const
0667   {
0668     if (IsEmpty())
0669       return Standard_False; // Not found
0670     for (theNode = (MapNode*)myData1[HashCode(theKey, NbBuckets())];
0671          theNode; theNode = (MapNode*)theNode->Next())
0672     {
0673       if (IsEqual(theNode->Key(), theKey))
0674       {
0675         return Standard_True;
0676       }
0677     }
0678     return Standard_False; // Not found
0679   }
0680 
0681   bool IsEqual(const TheKeyType& theKey1,
0682                const TheKeyType& theKey2) const
0683   {
0684     return myHasher(theKey1, theKey2);
0685   }
0686 
0687   size_t HashCode(const TheKeyType& theKey,
0688                   const int theUpperBound) const
0689   {
0690     return myHasher(theKey) % theUpperBound + 1;
0691   }
0692 protected:
0693 
0694   Hasher myHasher;
0695 };
0696 
0697 #endif