Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-09 09:16:09

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