0024526: Guide on Automatic Test System is obsolete
[occt.git] / src / NCollection / NCollection_IndexedMap.hxx
CommitLineData
b311480e 1// Created on: 2002-04-24
2// Created by: Alexander KARTOMIN (akm)
973c2be1 3// Copyright (c) 2002-2014 OPEN CASCADE SAS
b311480e 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
b311480e 6//
973c2be1 7// This library is free software; you can redistribute it and / or modify it
8// under the terms of the GNU Lesser General Public 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.
b311480e 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
b311480e 15
7fd59977 16#ifndef NCollection_IndexedMap_HeaderFile
17#define NCollection_IndexedMap_HeaderFile
18
19#include <NCollection_BaseCollection.hxx>
20#include <NCollection_BaseMap.hxx>
21#include <NCollection_TListNode.hxx>
22#include <Standard_NoSuchObject.hxx>
23#include <Standard_ImmutableObject.hxx>
24
9991c9c2 25#include <NCollection_DefaultHasher.hxx>
26
7fd59977 27#if !defined No_Exception && !defined No_Standard_OutOfRange
28#include <Standard_OutOfRange.hxx>
29#endif
30
7fd59977 31/**
32 * Purpose: An indexed map is used to store keys and to bind
33 * an index to them. Each new key stored in the map
34 * gets an index. Index are incremented as keys are
35 * stored in the map. A key can be found by the index
36 * and an index by the key. No key but the last can
37 * be removed so the indices are in the range 1..Extent.
38 * See the class Map from NCollection for a
39 * discussion about the number of buckets.
40 */
9991c9c2 41
42template < class TheKeyType,
43 class Hasher = NCollection_DefaultHasher<TheKeyType> >
44 class NCollection_IndexedMap
7fd59977 45 : public NCollection_BaseCollection<TheKeyType>,
46 public NCollection_BaseMap
47{
48 // **************** Adaptation of the TListNode to the INDEXEDmap
49 private:
50 class IndexedMapNode : public NCollection_TListNode<TheKeyType>
51 {
52 public:
53 //! Constructor with 'Next'
54 IndexedMapNode (const TheKeyType& theKey1,
55 const Standard_Integer theKey2,
56 NCollection_ListNode* theNext1,
57 NCollection_ListNode* theNext2) :
58 NCollection_TListNode<TheKeyType> (theKey1, theNext1)
59 {
60 myKey2 = theKey2;
61 myNext2 = (IndexedMapNode *) theNext2;
62 }
63 //! Key1
64 TheKeyType& Key1 (void)
65 { return this->ChangeValue(); }
66 //! Key2
67 const Standard_Integer& Key2 (void)
68 { return myKey2; }
69 //! Next2
70 IndexedMapNode*& Next2 (void)
71 { return myNext2; }
72
73 //! Static deleter to be passed to BaseList
74 static void delNode (NCollection_ListNode * theNode,
75 Handle(NCollection_BaseAllocator)& theAl)
76 {
77 ((IndexedMapNode *) theNode)->~IndexedMapNode();
78 theAl->Free(theNode);
79 }
80
81 private:
82 Standard_Integer myKey2;
83 IndexedMapNode * myNext2;
84 };
85
86 public:
87 // **************** Implementation of the Iterator interface.
88 class Iterator
89 : public NCollection_BaseCollection<TheKeyType>::Iterator
90 {
91 public:
92 //! Empty constructor
93 Iterator (void) :
94 myMap(NULL),
95 myIndex(0) {}
96 //! Constructor
97 Iterator (const NCollection_IndexedMap& theMap) :
98 myMap((NCollection_IndexedMap *) &theMap),
99 myIndex(1) {}
100 //! Query if the end of collection is reached by iterator
101 virtual Standard_Boolean More(void) const
102 { return (myIndex <= myMap->Extent()); }
103 //! Make a step along the collection
104 virtual void Next(void)
105 { myIndex++; }
106 //! Value access
107 virtual const TheKeyType& Value(void) const
108 {
109#if !defined No_Exception && !defined No_Standard_NoSuchObject
110 if (!More())
111 Standard_NoSuchObject::Raise("NCollection_IndexedMap::Iterator::Value");
112#endif
113 return myMap->FindKey(myIndex);
114 }
115 //! Value change access denied - use Substitute
116 virtual TheKeyType& ChangeValue(void) const
117 {
118 Standard_ImmutableObject::Raise ("impossible to ChangeValue");
119 return * (TheKeyType *) NULL; // This for compiler
120 }
121
7fd59977 122 private:
123 NCollection_IndexedMap * myMap; // Pointer to the map being iterated
124 Standard_Integer myIndex; // Current index
125 };
126
127 public:
128 // ---------- PUBLIC METHODS ------------
129
130 //! Constructor
131 NCollection_IndexedMap (const Standard_Integer NbBuckets=1,
132 const Handle(NCollection_BaseAllocator)& theAllocator=0L) :
133 NCollection_BaseCollection<TheKeyType>(theAllocator),
134 NCollection_BaseMap (NbBuckets, Standard_False) {}
135
136 //! Copy constructor
137 NCollection_IndexedMap (const NCollection_IndexedMap& theOther) :
138 NCollection_BaseCollection<TheKeyType>(theOther.myAllocator),
139 NCollection_BaseMap (theOther.NbBuckets(), Standard_False)
140 { *this = theOther; }
141
142 //! Assign another collection
143 virtual void Assign (const NCollection_BaseCollection<TheKeyType>& theOther)
144 {
145 if (this == &theOther)
146 return;
147 Clear();
148 ReSize (theOther.Size()-1);
149 TYPENAME NCollection_BaseCollection<TheKeyType>::Iterator& anIter =
150 theOther.CreateIterator();
151 for (; anIter.More(); anIter.Next())
152 Add(anIter.Value());
153 }
154
ab2db9a5 155 //! Exchange the content of two maps without re-allocations.
156 //! Notice that allocators will be swapped as well!
157 void Exchange (NCollection_IndexedMap& theOther)
158 {
159 this->exchangeAllocators (theOther);
160 this->exchangeMapsData (theOther);
161 }
162
7fd59977 163 //! = another map
164 NCollection_IndexedMap& operator= (const NCollection_IndexedMap& theOther)
165 {
166 if (this == &theOther)
167 return *this;
168
169 Clear(theOther.myAllocator);
170 ReSize (theOther.Extent()-1);
171 Standard_Integer i, iLength=theOther.Extent();
172 for (i=1; i<=iLength; i++)
173 {
174 TheKeyType aKey1 = theOther(i);
9991c9c2 175 Standard_Integer iK1 = Hasher::HashCode (aKey1, NbBuckets());
176 Standard_Integer iK2 = ::HashCode (i, NbBuckets());
7fd59977 177 IndexedMapNode * pNode = new (this->myAllocator) IndexedMapNode (aKey1, i,
178 myData1[iK1],
179 myData2[iK2]);
180 myData1[iK1] = pNode;
181 myData2[iK2] = pNode;
182 Increment();
183 }
184 return *this;
185 }
186
187 //! ReSize
188 void ReSize (const Standard_Integer N)
189 {
190 IndexedMapNode** ppNewData1 = NULL;
191 IndexedMapNode** ppNewData2 = NULL;
192 Standard_Integer newBuck;
193 if (BeginResize (N, newBuck,
194 (NCollection_ListNode**&)ppNewData1,
195 (NCollection_ListNode**&)ppNewData2,
196 this->myAllocator))
197 {
198 if (myData1)
199 {
200 IndexedMapNode *p, *q;
201 Standard_Integer i, iK1, iK2;
202 for (i = 0; i <= NbBuckets(); i++)
203 {
204 if (myData1[i])
205 {
206 p = (IndexedMapNode *) myData1[i];
207 while (p)
208 {
9991c9c2 209 iK1 =Hasher::HashCode(p->Key1(), newBuck);
7fd59977 210 q = (IndexedMapNode*) p->Next();
211 p->Next() = ppNewData1[iK1];
212 ppNewData1[iK1] = p;
213 if (p->Key2() > 0)
214 {
9991c9c2 215 iK2 = ::HashCode (p->Key2(), newBuck);
7fd59977 216 p->Next2() = ppNewData2[iK2];
217 ppNewData2[iK2] = p;
218 }
219 p = q;
220 }
221 }
222 }
223 }
224 EndResize(N,newBuck,
225 (NCollection_ListNode**&)ppNewData1,
226 (NCollection_ListNode**&)ppNewData2,
227 this->myAllocator);
228 }
229 }
230
231 //! Add
232 Standard_Integer Add (const TheKeyType& theKey1)
233 {
234 if (Resizable())
235 ReSize(Extent());
9991c9c2 236 Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
7fd59977 237 IndexedMapNode * pNode;
238 pNode = (IndexedMapNode *) myData1[iK1];
239 while (pNode)
240 {
9991c9c2 241 if (Hasher::IsEqual (pNode->Key1(), theKey1))
7fd59977 242 return pNode->Key2();
243 pNode = (IndexedMapNode *) pNode->Next();
244 }
245 Increment();
9991c9c2 246 Standard_Integer iK2 = ::HashCode(Extent(),NbBuckets());
7fd59977 247 pNode = new (this->myAllocator) IndexedMapNode (theKey1, Extent(),
248 myData1[iK1], myData2[iK2]);
249 myData1[iK1] = pNode;
250 myData2[iK2] = pNode;
251 return Extent();
252 }
253
254 //! Contains
255 Standard_Boolean Contains (const TheKeyType& theKey1) const
256 {
257 if (IsEmpty())
258 return Standard_False;
9991c9c2 259 Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
7fd59977 260 IndexedMapNode * pNode1;
261 pNode1 = (IndexedMapNode *) myData1[iK1];
262 while (pNode1)
263 {
9991c9c2 264 if (Hasher::IsEqual(pNode1->Key1(), theKey1))
7fd59977 265 return Standard_True;
266 pNode1 = (IndexedMapNode *) pNode1->Next();
267 }
268 return Standard_False;
269 }
270
271 //! Substitute
272 void Substitute (const Standard_Integer theIndex,
273 const TheKeyType& theKey1)
274 {
275#if !defined No_Exception && !defined No_Standard_OutOfRange
276 if (theIndex < 1 || theIndex > Extent())
277 Standard_OutOfRange::Raise ("NCollection_IndexedMap::Substitute");
278#endif
279 IndexedMapNode * p;
280 // check if theKey1 is not already in the map
9991c9c2 281 Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
7fd59977 282 p = (IndexedMapNode *) myData1[iK1];
283 while (p)
284 {
9991c9c2 285 if (Hasher::IsEqual (p->Key1(), theKey1))
7fd59977 286 Standard_DomainError::Raise("NCollection_IndexedMap::Substitute");
287 p = (IndexedMapNode *) p->Next();
288 }
289
290 // Find the node for the index I
9991c9c2 291 Standard_Integer iK2 = ::HashCode (theIndex, NbBuckets());
7fd59977 292 p = (IndexedMapNode *) myData2[iK2];
293 while (p)
294 {
295 if (p->Key2() == theIndex)
296 break;
297 p = (IndexedMapNode*) p->Next2();
298 }
299
300 // remove the old key
9991c9c2 301 Standard_Integer iK = Hasher::HashCode (p->Key1(), NbBuckets());
7fd59977 302 IndexedMapNode * q = (IndexedMapNode *) myData1[iK];
303 if (q == p)
304 myData1[iK] = (IndexedMapNode *) p->Next();
305 else
306 {
307 while (q->Next() != p)
308 q = (IndexedMapNode *) q->Next();
309 q->Next() = p->Next();
310 }
311
312 // update the node
313 p->Key1() = theKey1;
314 p->Next() = myData1[iK1];
315 myData1[iK1] = p;
316 }
317
318 //! RemoveLast
319 void RemoveLast (void)
320 {
321#if !defined No_Exception && !defined No_Standard_OutOfRange
322 if (Extent() == 0)
323 Standard_OutOfRange::Raise ("NCollection_IndexedMap::RemoveLast");
324#endif
325 IndexedMapNode * p, * q;
326 // Find the node for the last index and remove it
9991c9c2 327 Standard_Integer iK2 = ::HashCode (Extent(), NbBuckets());
7fd59977 328 p = (IndexedMapNode *) myData2[iK2];
329 q = NULL;
330 while (p)
331 {
332 if (p->Key2() == Extent())
333 break;
334 q = p;
335 p = (IndexedMapNode*) p->Next2();
336 }
337 if (q == NULL)
338 myData2[iK2] = (IndexedMapNode *) p->Next2();
339 else
340 q->Next2() = p->Next2();
341
342 // remove the key
9991c9c2 343 Standard_Integer iK1 = Hasher::HashCode (p->Key1(), NbBuckets());
7fd59977 344 q = (IndexedMapNode *) myData1[iK1];
345 if (q == p)
346 myData1[iK1] = (IndexedMapNode *) p->Next();
347 else
348 {
349 while (q->Next() != p)
350 q = (IndexedMapNode *) q->Next();
351 q->Next() = p->Next();
352 }
353 p->~IndexedMapNode();
354 this->myAllocator->Free(p);
355 Decrement();
356 }
357
358 //! FindKey
359 const TheKeyType& FindKey (const Standard_Integer theKey2) const
360 {
361#if !defined No_Exception && !defined No_Standard_OutOfRange
362 if (theKey2 < 1 || theKey2 > Extent())
363 Standard_OutOfRange::Raise ("NCollection_IndexedMap::FindKey");
364#endif
365 IndexedMapNode * pNode2 =
9991c9c2 366 (IndexedMapNode *) myData2[::HashCode(theKey2,NbBuckets())];
7fd59977 367 while (pNode2)
368 {
369 if (pNode2->Key2() == theKey2)
370 return pNode2->Key1();
371 pNode2 = (IndexedMapNode*) pNode2->Next2();
372 }
373 Standard_NoSuchObject::Raise("NCollection_IndexedMap::FindKey");
374 return pNode2->Key1(); // This for compiler
375 }
376
377 //! operator ()
378 const TheKeyType& operator() (const Standard_Integer theKey2) const
379 { return FindKey (theKey2); }
380
381 //! FindIndex
382 Standard_Integer FindIndex(const TheKeyType& theKey1) const
383 {
384 if (IsEmpty()) return 0;
385 IndexedMapNode * pNode1 =
9991c9c2 386 (IndexedMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
7fd59977 387 while (pNode1)
388 {
9991c9c2 389 if (Hasher::IsEqual (pNode1->Key1(), theKey1))
7fd59977 390 return pNode1->Key2();
391 pNode1 = (IndexedMapNode*) pNode1->Next();
392 }
393 return 0;
394 }
395
396 //! Clear data. If doReleaseMemory is false then the table of
397 //! buckets is not released and will be reused.
398 void Clear(const Standard_Boolean doReleaseMemory = Standard_True)
399 { Destroy (IndexedMapNode::delNode, this->myAllocator, doReleaseMemory); }
400
401 //! Clear data and reset allocator
402 void Clear (const Handle(NCollection_BaseAllocator)& theAllocator)
403 {
404 Clear();
405 this->myAllocator = ( ! theAllocator.IsNull() ? theAllocator :
406 NCollection_BaseAllocator::CommonBaseAllocator() );
407 }
408
409 //! Destructor
410 ~NCollection_IndexedMap (void)
411 { Clear(); }
412
413 //! Size
414 virtual Standard_Integer Size(void) const
415 { return Extent(); }
416
417 private:
418 // ----------- PRIVATE METHODS -----------
419
420 //! Creates Iterator for use on BaseCollection
421 virtual TYPENAME NCollection_BaseCollection<TheKeyType>::Iterator&
422 CreateIterator(void) const
423 { return *(new (this->IterAllocator()) Iterator(*this)); }
424
425};
426
7fd59977 427#endif