Back to home page

EIC code displayed by LXR

 
 

    


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

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_DoubleMap_HeaderFile
0017 #define NCollection_DoubleMap_HeaderFile
0018 
0019 #include <NCollection_BaseMap.hxx>
0020 #include <NCollection_TListNode.hxx>
0021 #include <Standard_MultiplyDefined.hxx>
0022 #include <Standard_NoSuchObject.hxx>
0023 
0024 #include <NCollection_DefaultHasher.hxx>
0025 
0026 /**
0027 * Purpose:     The DoubleMap  is used to  bind  pairs (Key1,Key2)
0028 *              and retrieve them in linear time.
0029 *              
0030 *              See Map from NCollection for a discussion about the number
0031 *              of buckets
0032 */              
0033 
0034 template < class TheKey1Type, 
0035            class TheKey2Type, 
0036            class Hasher1 = NCollection_DefaultHasher<TheKey1Type>, 
0037            class Hasher2 = NCollection_DefaultHasher<TheKey2Type> >
0038 class NCollection_DoubleMap : public NCollection_BaseMap
0039 {
0040 public:
0041   //! STL-compliant typedef for key1 type
0042   typedef TheKey1Type key1_type;
0043   //! STL-compliant typedef for key2 type
0044   typedef TheKey2Type key2_type;
0045 
0046 public:
0047   // **************** Adaptation of the TListNode to the DOUBLEmap
0048   class DoubleMapNode : public NCollection_TListNode<TheKey2Type>
0049   {
0050   public:
0051     //! Constructor with 'Next'
0052     DoubleMapNode (const TheKey1Type&    theKey1, 
0053                    const TheKey2Type&    theKey2, 
0054                    NCollection_ListNode* theNext1, 
0055                    NCollection_ListNode* theNext2) :
0056       NCollection_TListNode<TheKey2Type> (theKey2, theNext1),
0057       myKey1(theKey1),
0058       myNext2((DoubleMapNode*)theNext2)
0059     { 
0060     }
0061     //! Key1
0062     const TheKey1Type& Key1 (void)
0063     { return myKey1; }
0064     //! Key2
0065     const TheKey2Type& Key2 (void)
0066     { return this->myValue; }
0067     //! Next2
0068     DoubleMapNode*& Next2 (void)
0069     { return myNext2; }
0070     
0071     //! Static deleter to be passed to BaseList
0072     static void delNode (NCollection_ListNode * theNode, 
0073                          Handle(NCollection_BaseAllocator)& theAl)
0074     {
0075       ((DoubleMapNode *) theNode)->~DoubleMapNode();
0076       theAl->Free(theNode);
0077     }
0078 
0079   private:
0080     TheKey1Type    myKey1;
0081     DoubleMapNode *myNext2;
0082   };
0083 
0084  public:
0085   // **************** Implementation of the Iterator interface.
0086   class Iterator : public NCollection_BaseMap::Iterator
0087   {
0088   public:
0089     //! Empty constructor
0090     Iterator (void) {}
0091     //! Constructor
0092     Iterator (const NCollection_DoubleMap& 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     //! Key1 inquiry
0101     const TheKey1Type& Key1(void) const
0102     {
0103       Standard_NoSuchObject_Raise_if (!More(), "NCollection_DoubleMap::Iterator::Key1");
0104       return ((DoubleMapNode *) myNode)->Key1();
0105     }
0106     //! Key2 inquiry
0107     const TheKey2Type& Key2(void) const
0108     {  
0109       Standard_NoSuchObject_Raise_if (!More(), "NCollection_DoubleMap::Iterator::Key2");
0110       return ((DoubleMapNode *) myNode)->Key2();
0111     }
0112     //! Value access
0113     const TheKey2Type& Value(void) const
0114     {  
0115       Standard_NoSuchObject_Raise_if (!More(), "NCollection_DoubleMap::Iterator::Value");
0116       return ((DoubleMapNode *) myNode)->Value();
0117     }
0118   };
0119 
0120  public:
0121   // ---------- PUBLIC METHODS ------------
0122 
0123   //! Empty constructor.
0124   NCollection_DoubleMap() : NCollection_BaseMap (1, Standard_False, Handle(NCollection_BaseAllocator)()) {}
0125 
0126   //! Constructor
0127   explicit NCollection_DoubleMap (const Standard_Integer theNbBuckets,
0128                                   const Handle(NCollection_BaseAllocator)& theAllocator = 0L)
0129   : NCollection_BaseMap (theNbBuckets, Standard_False, theAllocator) {}
0130 
0131   //! Copy constructor
0132   NCollection_DoubleMap (const NCollection_DoubleMap& theOther)
0133     : NCollection_BaseMap (theOther.NbBuckets(), Standard_False, theOther.myAllocator) 
0134   { *this = theOther; }
0135 
0136   //! Exchange the content of two maps without re-allocations.
0137   //! Notice that allocators will be swapped as well!
0138   void Exchange (NCollection_DoubleMap& theOther)
0139   {
0140     this->exchangeMapsData (theOther);
0141   }
0142 
0143   //! Assignment.
0144   //! This method does not change the internal allocator.
0145   NCollection_DoubleMap& Assign (const NCollection_DoubleMap& theOther)
0146   { 
0147     if (this == &theOther)
0148       return *this;
0149 
0150     Clear();
0151     Standard_Integer anExt = theOther.Extent();
0152     if (anExt)
0153     {
0154       ReSize (anExt-1);
0155       Iterator anIter(theOther);
0156       for (; anIter.More(); anIter.Next())
0157       {
0158         TheKey1Type aKey1 = anIter.Key1();
0159         TheKey2Type aKey2 = anIter.Key2();
0160         const size_t iK1 = HashCode1 (aKey1, NbBuckets());
0161         const size_t iK2 = HashCode2 (aKey2, NbBuckets());
0162         DoubleMapNode * pNode = new (this->myAllocator) DoubleMapNode (aKey1, aKey2, 
0163           myData1[iK1], 
0164           myData2[iK2]);
0165         myData1[iK1] = pNode;
0166         myData2[iK2] = pNode;
0167         Increment();
0168       }
0169     }
0170     return *this;
0171   }
0172 
0173   //! Assignment operator
0174   NCollection_DoubleMap& operator= (const NCollection_DoubleMap& theOther)
0175   {
0176     return Assign (theOther);
0177   }
0178 
0179   //! ReSize
0180   void ReSize (const Standard_Integer N)
0181   {
0182     NCollection_ListNode** ppNewData1 = NULL;
0183     NCollection_ListNode** ppNewData2 = NULL;
0184     Standard_Integer newBuck;
0185     if (BeginResize (N, newBuck, ppNewData1, ppNewData2))
0186     {
0187       if (myData1) 
0188       {
0189         DoubleMapNode *p, *q;
0190         for (int i = 0; i <= NbBuckets(); i++) 
0191         {
0192           if (myData1[i]) 
0193           {
0194             p = (DoubleMapNode *) myData1[i];
0195             while (p) 
0196             {
0197               const size_t iK1 = HashCode1 (p->Key1(), newBuck);
0198               const size_t iK2 = HashCode2 (p->Key2(), newBuck);
0199               q = (DoubleMapNode*) p->Next();
0200               p->Next()  = ppNewData1[iK1];
0201               p->Next2() = (DoubleMapNode*)ppNewData2[iK2];
0202               ppNewData1[iK1] = p;
0203               ppNewData2[iK2] = p;
0204               p = q;
0205             }
0206           }
0207         }
0208       }
0209       EndResize (N, newBuck, ppNewData1, ppNewData2);
0210     }
0211   }
0212 
0213   //! Bind
0214   void Bind (const TheKey1Type& theKey1, const TheKey2Type& theKey2)
0215   {
0216     if (Resizable()) 
0217       ReSize(Extent());
0218     const size_t iK1 = HashCode1 (theKey1, NbBuckets());
0219     const size_t iK2 = HashCode2 (theKey2, NbBuckets());
0220     DoubleMapNode * pNode;
0221     pNode = (DoubleMapNode *) myData1[iK1];
0222     while (pNode) 
0223     {
0224       if (IsEqual1 (pNode->Key1(), theKey1))
0225         throw Standard_MultiplyDefined("NCollection_DoubleMap:Bind");
0226       pNode = (DoubleMapNode *) pNode->Next();
0227     }
0228     pNode = (DoubleMapNode *) myData2[iK2];
0229     while (pNode) 
0230     {
0231       if (IsEqual2 (pNode->Key2(), theKey2))
0232         throw Standard_MultiplyDefined("NCollection_DoubleMap:Bind");
0233       pNode = (DoubleMapNode *) pNode->Next();
0234     }
0235     pNode = new (this->myAllocator) DoubleMapNode (theKey1, theKey2, 
0236                                                    myData1[iK1], myData2[iK2]);
0237     myData1[iK1] = pNode;
0238     myData2[iK2] = pNode;
0239     Increment();
0240   }
0241 
0242   //!* AreBound
0243   Standard_Boolean AreBound (const TheKey1Type& theKey1,
0244                              const TheKey2Type& theKey2) const
0245   {
0246     if (IsEmpty()) 
0247       return Standard_False;
0248     const size_t iK1 = HashCode1 (theKey1, NbBuckets());
0249     const size_t iK2 = HashCode2 (theKey2, NbBuckets());
0250     DoubleMapNode * pNode1, * pNode2;
0251     pNode1 = (DoubleMapNode *) myData1[iK1];
0252     while (pNode1) 
0253     {
0254       if (IsEqual1(pNode1->Key1(), theKey1)) 
0255         break;
0256       pNode1 = (DoubleMapNode *) pNode1->Next();
0257     }
0258     if (pNode1 == NULL)
0259       return Standard_False;
0260     pNode2 = (DoubleMapNode *) myData2[iK2];
0261     while (pNode2) 
0262     {
0263       if (IsEqual2(pNode2->Key2(), theKey2)) 
0264         break;
0265       pNode2 = (DoubleMapNode *) pNode2->Next();
0266     }
0267     if (pNode2 == NULL)
0268       return Standard_False;
0269 
0270     return (pNode1 == pNode2);
0271   }
0272 
0273   //! IsBound1
0274   Standard_Boolean IsBound1 (const TheKey1Type& theKey1) const
0275   {
0276     if (IsEmpty()) 
0277       return Standard_False;
0278     const size_t iK1 = HashCode1 (theKey1, NbBuckets());
0279     DoubleMapNode * pNode1;
0280     pNode1 = (DoubleMapNode *) myData1[iK1];
0281     while (pNode1) 
0282     {
0283       if (IsEqual1(pNode1->Key1(), theKey1)) 
0284         return Standard_True;
0285       pNode1 = (DoubleMapNode *) pNode1->Next();
0286     }
0287     return Standard_False;
0288   }
0289 
0290   //! IsBound2
0291   Standard_Boolean IsBound2 (const TheKey2Type& theKey2) const
0292   {
0293     if (IsEmpty()) 
0294       return Standard_False;
0295     const size_t iK2 = HashCode2 (theKey2, NbBuckets());
0296     DoubleMapNode * pNode2;
0297     pNode2 = (DoubleMapNode *) myData2[iK2];
0298     while (pNode2) 
0299     {
0300       if (IsEqual2(pNode2->Key2(), theKey2)) 
0301         return Standard_True;
0302       pNode2 = (DoubleMapNode *) pNode2->Next2();
0303     }
0304     return Standard_False;
0305   }
0306 
0307   //! UnBind1
0308   Standard_Boolean UnBind1 (const TheKey1Type& theKey1)
0309   {
0310     if (IsEmpty()) 
0311       return Standard_False;
0312     const size_t iK1 = HashCode1 (theKey1, NbBuckets());
0313     DoubleMapNode * p1, * p2, * q1, *q2;
0314     q1 = q2 = NULL;
0315     p1 = (DoubleMapNode *) myData1[iK1];
0316     while (p1) 
0317     {
0318       if (IsEqual1 (p1->Key1(), theKey1)) 
0319       {
0320         // remove from the data1
0321         if (q1) 
0322           q1->Next() = p1->Next();
0323         else
0324           myData1[iK1] = (DoubleMapNode*) p1->Next();
0325         const size_t iK2 = HashCode2 (p1->Key2(), NbBuckets());
0326         p2 = (DoubleMapNode *) myData2[iK2];
0327         while (p2)
0328         {
0329           if (p2 == p1) 
0330           {
0331             // remove from the data2
0332             if (q2) 
0333               q2->Next2() = p2->Next2();
0334             else
0335               myData2[iK2] = (DoubleMapNode*) p2->Next2();
0336             break;
0337           }
0338           q2 = p2;
0339           p2 = (DoubleMapNode*) p2->Next2();
0340         }
0341         p1->~DoubleMapNode();
0342         this->myAllocator->Free(p1);
0343         Decrement();
0344         return Standard_True;
0345       }
0346       q1 = p1;
0347       p1 = (DoubleMapNode*) p1->Next();
0348     }
0349     return Standard_False;
0350   }
0351 
0352   //! UnBind2
0353   Standard_Boolean UnBind2 (const TheKey2Type& theKey2)
0354   {
0355     if (IsEmpty()) 
0356       return Standard_False;
0357     const size_t iK2 = HashCode2 (theKey2, NbBuckets());
0358     DoubleMapNode * p1, * p2, * q1, *q2;
0359     q1 = q2 = NULL;
0360     p2 = (DoubleMapNode *) myData2[iK2];
0361     while (p2) 
0362     {
0363       if (IsEqual2 (p2->Key2(), theKey2)) 
0364       {
0365         // remove from the data2
0366         if (q2)
0367         {
0368           q2->Next2() = p2->Next2();
0369         }
0370         else
0371           myData2[iK2] = (DoubleMapNode*) p2->Next2();
0372         const size_t iK1 = HashCode1 (p2->Key1(), NbBuckets());
0373         p1 = (DoubleMapNode *) myData1[iK1];
0374         while (p1)
0375         {
0376           if (p1 == p2) 
0377           {
0378             // remove from the data1
0379             if (q1)
0380               q1->Next() = p1->Next();
0381             else
0382               myData1[iK1] = (DoubleMapNode*) p1->Next();
0383             break;
0384           }
0385           q1 = p1;
0386           p1 = (DoubleMapNode*) p1->Next();
0387         }
0388         p2->~DoubleMapNode();
0389         this->myAllocator->Free(p2);
0390         Decrement();
0391         return Standard_True;
0392       }
0393       q2 = p2;
0394       p2 = (DoubleMapNode*) p2->Next2();
0395     }
0396     return Standard_False;
0397   }
0398 
0399   //! Find the Key1 and return Key2 value.
0400   //! Raises an exception if Key1 was not bound.
0401   const TheKey2Type& Find1(const TheKey1Type& theKey1) const
0402   {
0403     if (const TheKey2Type* aKey2 = Seek1 (theKey1))
0404     {
0405       return *aKey2;
0406     }
0407     throw Standard_NoSuchObject("NCollection_DoubleMap::Find1");
0408   }
0409 
0410   //! Find the Key1 and return Key2 value (by copying its value).
0411   //! @param [in]  theKey1 Key1 to find
0412   //! @param [out] theKey2 Key2 to return
0413   //! @return TRUE if Key1 has been found
0414   Standard_Boolean Find1 (const TheKey1Type& theKey1,
0415                           TheKey2Type& theKey2) const
0416   {
0417     if (const TheKey2Type* aKey2 = Seek1 (theKey1))
0418     {
0419       theKey2 = *aKey2;
0420       return true;
0421     }
0422     return false;
0423   }
0424 
0425   //! Find the Key1 and return pointer to Key2 or NULL if Key1 is not bound.
0426   //! @param [in]  theKey1 Key1 to find
0427   //! @return pointer to Key2 or NULL if Key1 is not found
0428   const TheKey2Type* Seek1 (const TheKey1Type& theKey1) const
0429   {
0430     for (DoubleMapNode* aNode1 = !IsEmpty() ? (DoubleMapNode* )myData1[HashCode1 (theKey1, NbBuckets())] : NULL;
0431          aNode1 != NULL; aNode1 = (DoubleMapNode* )aNode1->Next())
0432     {
0433       if (IsEqual1 (aNode1->Key1(), theKey1))
0434       {
0435         return &aNode1->Key2();
0436       }
0437     }
0438     return NULL;
0439   }
0440 
0441   //! Find the Key2 and return Key1 value.
0442   //! Raises an exception if Key2 was not bound.
0443   const TheKey1Type& Find2(const TheKey2Type& theKey2) const
0444   {
0445     if (const TheKey1Type* aVal1 = Seek2 (theKey2))
0446     {
0447       return *aVal1;
0448     }
0449     throw Standard_NoSuchObject("NCollection_DoubleMap::Find2");
0450   }
0451 
0452   //! Find the Key2 and return Key1 value (by copying its value).
0453   //! @param [in]  theKey2 Key2 to find
0454   //! @param [out] theKey1 Key1 to return
0455   //! @return TRUE if Key2 has been found
0456   Standard_Boolean Find2 (const TheKey2Type& theKey2,
0457                           TheKey1Type& theKey1) const
0458   {
0459     if (const TheKey1Type* aVal1 = Seek2 (theKey2))
0460     {
0461       theKey1 = *aVal1;
0462       return Standard_True;
0463     }
0464     return Standard_False;
0465   }
0466 
0467   //! Find the Key2 and return pointer to Key1 or NULL if not bound.
0468   //! @param [in] theKey2 Key2 to find
0469   //! @return pointer to Key1 if Key2 has been found
0470   const TheKey1Type* Seek2 (const TheKey2Type& theKey2) const
0471   {
0472     for (DoubleMapNode* aNode2 = !IsEmpty() ? (DoubleMapNode* )myData2[HashCode2 (theKey2, NbBuckets())] : NULL;
0473          aNode2 != NULL; aNode2 = (DoubleMapNode* )aNode2->Next2())
0474     {
0475       if (IsEqual2 (aNode2->Key2(), theKey2))
0476       {
0477         return &aNode2->Key1();
0478       }
0479     }
0480     return NULL;
0481   }
0482 
0483   //! Clear data. If doReleaseMemory is false then the table of
0484   //! buckets is not released and will be reused.
0485   void Clear(const Standard_Boolean doReleaseMemory = Standard_False)
0486   { Destroy (DoubleMapNode::delNode, doReleaseMemory); }
0487 
0488   //! Clear data and reset allocator
0489   void Clear (const Handle(NCollection_BaseAllocator)& theAllocator)
0490   { 
0491     Clear(true);
0492     this->myAllocator = ( ! theAllocator.IsNull() ? theAllocator :
0493                     NCollection_BaseAllocator::CommonBaseAllocator() );
0494   }
0495 
0496   //! Destructor
0497   ~NCollection_DoubleMap (void)
0498   { Clear(true); }
0499 
0500   //! Size
0501   Standard_Integer Size(void) const
0502   { return Extent(); }
0503 protected:
0504 
0505   bool IsEqual1(const TheKey1Type& theKey1,
0506                 const TheKey1Type& theKey2) const
0507   {
0508     return myHasher1(theKey1, theKey2);
0509   }
0510 
0511   size_t HashCode1(const TheKey1Type& theKey,
0512                    const int theUpperBound) const
0513   {
0514     return myHasher1(theKey) % theUpperBound + 1;
0515   }
0516 
0517   bool IsEqual2(const TheKey2Type& theKey1,
0518                 const TheKey2Type& theKey2) const
0519   {
0520     return myHasher2(theKey1, theKey2);
0521   }
0522 
0523   size_t HashCode2(const TheKey2Type& theKey,
0524                    const int theUpperBound) const
0525   {
0526     return myHasher2(theKey) % theUpperBound + 1;
0527   }
0528 
0529 protected:
0530 
0531   Hasher1 myHasher1;
0532   Hasher2 myHasher2;
0533 };
0534 
0535 #endif