0024911: Avoid using virtual functions in NCollection classes
[occt.git] / src / NCollection / NCollection_DataMap.hxx
1 // Created on: 2002-04-24
2 // Created by: Alexander KARTOMIN (akm)
3 // Copyright (c) 2002-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #ifndef NCollection_DataMap_HeaderFile
17 #define NCollection_DataMap_HeaderFile
18
19 #include <NCollection_BaseMap.hxx>
20 #include <NCollection_TListNode.hxx>
21 #include <NCollection_StlIterator.hxx>
22 #include <NCollection_DefaultHasher.hxx>
23
24 #include <Standard_TypeMismatch.hxx>
25 #include <Standard_NoSuchObject.hxx>
26
27 /**
28 * Purpose:     The DataMap is a Map to store keys with associated
29 *              Items. See Map  from NCollection for  a discussion
30 *              about the number of buckets.
31 *
32 *              The DataMap can be seen as an extended array where
33 *              the Keys  are the   indices.  For this reason  the
34 *              operator () is defined on DataMap to fetch an Item
35 *              from a Key. So the following syntax can be used :
36 *
37 *              anItem = aMap(aKey);
38 *              aMap(aKey) = anItem;
39 *
40 *              This analogy has its  limit.   aMap(aKey) = anItem
41 *              can  be done only  if aKey was previously bound to
42 *              an item in the map.
43 */              
44
45 template < class TheKeyType, 
46            class TheItemType, 
47            class Hasher = NCollection_DefaultHasher<TheKeyType> >
48 class NCollection_DataMap : public NCollection_BaseMap
49 {
50   // **************** Adaptation of the TListNode to the DATAmap
51  public:
52   class DataMapNode : public NCollection_TListNode<TheItemType>
53   {
54   public:
55     //! Constructor with 'Next'
56     DataMapNode (const TheKeyType&     theKey, 
57                  const TheItemType&    theItem, 
58                  NCollection_ListNode* theNext) :
59                    NCollection_TListNode<TheItemType> (theItem, theNext) 
60     { myKey = theKey; }
61     //! Key
62     const TheKeyType& Key (void) const
63     { return myKey; }
64     
65     //! Static deleter to be passed to BaseMap
66     static void delNode (NCollection_ListNode * theNode, 
67                          Handle(NCollection_BaseAllocator)& theAl)
68     {
69       ((DataMapNode *) theNode)->~DataMapNode();
70       theAl->Free(theNode);
71     }
72
73   private:
74     TheKeyType    myKey;
75   };
76
77  public:
78   // **************** Implementation of the Iterator interface.
79   class Iterator : public NCollection_BaseMap::Iterator
80   {
81   public:
82     //! Empty constructor
83     Iterator (void) :
84       NCollection_BaseMap::Iterator() {}
85     //! Constructor
86     Iterator (const NCollection_DataMap& theMap) :
87       NCollection_BaseMap::Iterator(theMap) {}
88     //! Query if the end of collection is reached by iterator
89     Standard_Boolean More(void) const
90     { return PMore(); }
91     //! Make a step along the collection
92     void Next(void)
93     { PNext(); }
94     //! Value inquiry
95     const TheItemType& Value(void) const
96     {  
97 #if !defined No_Exception && !defined No_Standard_NoSuchObject
98       if (!More())
99         Standard_NoSuchObject::Raise("NCollection_DataMap::Iterator::Value");  
100 #endif
101       return ((DataMapNode *) myNode)->Value();
102     }
103     //! Value change access
104     TheItemType& ChangeValue(void) const
105     {  
106 #if !defined No_Exception && !defined No_Standard_NoSuchObject
107       if (!More())
108         Standard_NoSuchObject::Raise("NCollection_DataMap::Iterator::ChangeValue");  
109 #endif
110       return ((DataMapNode *) myNode)->ChangeValue();
111     }
112     //! Key
113     const TheKeyType& Key (void) const
114     { 
115 #if !defined No_Exception && !defined No_Standard_NoSuchObject
116       if (!More())
117         Standard_NoSuchObject::Raise("NCollection_DataMap::Iterator::Key");  
118 #endif
119       return ((DataMapNode *) myNode)->Key();
120     }
121   };
122   
123   //! Shorthand for a regular iterator type.
124   typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheItemType, false> iterator;
125
126   //! Shorthand for a constant iterator type.
127   typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheItemType, true> const_iterator;
128
129   //! Returns an iterator pointing to the first element in the map.
130   iterator begin() const { return Iterator (*this); }
131
132   //! Returns an iterator referring to the past-the-end element in the map.
133   iterator end() const { return Iterator(); }
134
135   //! Returns a const iterator pointing to the first element in the map.
136   const_iterator cbegin() const { return Iterator (*this); }
137
138   //! Returns a const iterator referring to the past-the-end element in the map.
139   const_iterator cend() const { return Iterator(); }
140
141  public:
142   // ---------- PUBLIC METHODS ------------
143
144   //! Constructor
145   NCollection_DataMap (const Standard_Integer NbBuckets=1,
146                      const Handle(NCollection_BaseAllocator)& theAllocator = 0L)
147     : NCollection_BaseMap (NbBuckets, Standard_True, theAllocator) {}
148
149   //! Copy constructor
150   NCollection_DataMap (const NCollection_DataMap& theOther)
151     : NCollection_BaseMap (theOther.NbBuckets(), Standard_True, theOther.myAllocator) 
152   { *this = theOther; }
153
154   //! Exchange the content of two maps without re-allocations.
155   //! Notice that allocators will be swapped as well!
156   void Exchange (NCollection_DataMap& theOther)
157   {
158     this->exchangeMapsData (theOther);
159   }
160
161   //! Assignment
162   NCollection_DataMap& Assign (const NCollection_DataMap& theOther)
163   { 
164     if (this == &theOther)
165       return *this;
166
167     Clear(theOther.myAllocator);
168     ReSize (theOther.Extent()-1);
169     Iterator anIter(theOther);
170     for (; anIter.More(); anIter.Next())
171       Bind (anIter.Key(), anIter.Value());
172     return *this;
173   }
174
175   //! Assignment operator
176   NCollection_DataMap& operator= (const NCollection_DataMap& theOther)
177   { 
178     return Assign (theOther);
179   }
180
181   //! ReSize
182   void ReSize (const Standard_Integer N)
183   {
184     NCollection_ListNode** newdata = NULL;
185     NCollection_ListNode** dummy   = NULL;
186     Standard_Integer newBuck;
187     if (BeginResize (N, newBuck, newdata, dummy))
188     {
189       if (myData1) 
190       {
191         DataMapNode** olddata = (DataMapNode**) myData1;
192         DataMapNode *p, *q;
193         Standard_Integer i,k;
194         for (i = 0; i <= NbBuckets(); i++) 
195         {
196           if (olddata[i]) 
197           {
198             p = olddata[i];
199             while (p) 
200             {
201               k = Hasher::HashCode(p->Key(),newBuck);
202               q = (DataMapNode*) p->Next();
203               p->Next() = newdata[k];
204               newdata[k] = p;
205               p = q;
206             }
207           }
208         }
209       }
210       EndResize (N, newBuck, newdata, dummy);
211     }
212   }
213
214   //! Bind
215   Standard_Boolean Bind (const TheKeyType& theKey, const TheItemType& theItem)
216   {
217     if (Resizable()) 
218       ReSize(Extent());
219     DataMapNode** data = (DataMapNode**)myData1;
220     Standard_Integer k = Hasher::HashCode (theKey, NbBuckets());
221     DataMapNode* p = data[k];
222     while (p) 
223     {
224       if (Hasher::IsEqual(p->Key(), theKey))
225       {
226         p->ChangeValue() = theItem;
227         return Standard_False;
228       }
229       p = (DataMapNode *) p->Next();
230     }
231     data[k] = new (this->myAllocator) DataMapNode (theKey, theItem, data[k]);
232     Increment();
233     return Standard_True;
234   }
235
236   //! IsBound
237   Standard_Boolean IsBound(const TheKeyType& K) const
238   {
239     if (IsEmpty()) 
240       return Standard_False;
241     DataMapNode** data = (DataMapNode**) myData1;
242     DataMapNode* p = data[Hasher::HashCode(K,NbBuckets())];
243     while (p) 
244     {
245       if (Hasher::IsEqual(p->Key(),K)) 
246         return Standard_True;
247       p = (DataMapNode *) p->Next();
248     }
249     return Standard_False;
250   }
251
252   //! UnBind
253   Standard_Boolean UnBind(const TheKeyType& K)
254   {
255     if (IsEmpty()) 
256       return Standard_False;
257     DataMapNode** data = (DataMapNode**) myData1;
258     Standard_Integer k = Hasher::HashCode(K,NbBuckets());
259     DataMapNode* p = data[k];
260     DataMapNode* q = NULL;
261     while (p) 
262     {
263       if (Hasher::IsEqual(p->Key(),K)) 
264       {
265         Decrement();
266         if (q) 
267           q->Next() = p->Next();
268         else
269           data[k] = (DataMapNode*) p->Next();
270         p->~DataMapNode();
271         this->myAllocator->Free(p);
272         return Standard_True;
273       }
274       q = p;
275       p = (DataMapNode*) p->Next();
276     }
277     return Standard_False;
278   }
279
280   //! Find
281   const TheItemType& Find(const TheKeyType& theKey) const
282   {
283 #if !defined No_Exception && !defined No_Standard_NoSuchObject
284     if (IsEmpty())
285       Standard_NoSuchObject::Raise ("NCollection_DataMap::Find");
286 #endif
287     DataMapNode* p = (DataMapNode*) myData1[Hasher::HashCode(theKey,NbBuckets())];
288     while (p) 
289     {
290       if (Hasher::IsEqual(p->Key(),theKey)) 
291         return p->Value();
292       p = (DataMapNode*) p->Next();
293     }
294     Standard_NoSuchObject::Raise("NCollection_DataMap::Find");
295     return p->Value(); // This for compiler
296   }
297
298   //! Find value for key with copying.
299   //! @return true if key was found
300   Standard_Boolean Find (const TheKeyType& theKey,
301                          TheItemType&      theValue) const
302   {
303     if (IsEmpty())
304     {
305       return Standard_False;
306     }
307
308     for (DataMapNode* aNodeIter = (DataMapNode* )myData1[Hasher::HashCode (theKey, NbBuckets())];
309          aNodeIter != NULL;
310          aNodeIter = (DataMapNode* )aNodeIter->Next())
311     {
312       if (Hasher::IsEqual (aNodeIter->Key(), theKey))
313       {
314         theValue = aNodeIter->Value();
315         return Standard_True;
316       }
317     }
318     return Standard_False;
319   }
320
321   //! operator ()
322   const TheItemType& operator() (const TheKeyType& theKey) const
323   { return Find(theKey); }
324
325   //! ChangeFind
326   TheItemType& ChangeFind (const TheKeyType& theKey)
327   {
328 #if !defined No_Exception && !defined No_Standard_NoSuchObject
329     if (IsEmpty())
330       Standard_NoSuchObject::Raise ("NCollection_DataMap::Find");
331 #endif
332     DataMapNode*  p = (DataMapNode*) myData1[Hasher::HashCode(theKey,NbBuckets())];
333     while (p) 
334     {
335       if (Hasher::IsEqual(p->Key(),theKey)) 
336         return p->ChangeValue();
337       p = (DataMapNode*) p->Next();
338     }
339     Standard_NoSuchObject::Raise("NCollection_DataMap::Find");
340     return p->ChangeValue(); // This for compiler
341   }
342
343   //! operator ()
344   TheItemType& operator() (const TheKeyType& theKey)
345   { return ChangeFind(theKey); }
346
347   //! Clear data. If doReleaseMemory is false then the table of
348   //! buckets is not released and will be reused.
349   void Clear(const Standard_Boolean doReleaseMemory = Standard_True)
350   { Destroy (DataMapNode::delNode, doReleaseMemory); }
351
352   //! Clear data and reset allocator
353   void Clear (const Handle(NCollection_BaseAllocator)& theAllocator)
354   { 
355     Clear();
356     this->myAllocator = ( ! theAllocator.IsNull() ? theAllocator :
357                     NCollection_BaseAllocator::CommonBaseAllocator() );
358   }
359
360   //! Destructor
361   ~NCollection_DataMap (void)
362   { Clear(); }
363
364   //! Size
365   Standard_Integer Size(void) const
366   { return Extent(); }
367 };
368
369 #endif
370