0023951: Visibility of free, simple shapes not saved when writing XCAF Document into...
[occt.git] / src / NCollection / NCollection_IndexedDataMap.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//
d5f74e42 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
973c2be1 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.
7fd59977 15
16#ifndef NCollection_IndexedDataMap_HeaderFile
17#define NCollection_IndexedDataMap_HeaderFile
18
19#include <NCollection_BaseCollection.hxx>
20#include <NCollection_BaseMap.hxx>
21#include <NCollection_TListNode.hxx>
22#include <Standard_TypeMismatch.hxx>
23#include <Standard_NoSuchObject.hxx>
9991c9c2 24
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..
38 * Extent. An Item is stored with each key.
39 *
40 * This class is similar to IndexedMap from
41 * NCollection with the Item as a new feature. Note
42 * the important difference on the operator (). In
43 * the IndexedMap this operator returns the Key. In
44 * the IndexedDataMap this operator returns the Item.
45 *
46 * See the class Map from NCollection for a
47 * discussion about the number of buckets.
48 */
9991c9c2 49
50template < class TheKeyType,
51 class TheItemType,
52 class Hasher = NCollection_DefaultHasher<TheKeyType> >
53 class NCollection_IndexedDataMap
7fd59977 54 : public NCollection_BaseCollection<TheItemType>,
55 public NCollection_BaseMap
56{
57 //! Adaptation of the TListNode to the INDEXEDDatamap
58 private:
59 class IndexedDataMapNode : public NCollection_TListNode<TheItemType>
60 {
61 public:
62 //! Constructor with 'Next'
63 IndexedDataMapNode (const TheKeyType& theKey1,
64 const Standard_Integer theKey2,
65 const TheItemType& theItem,
66 NCollection_ListNode* theNext1,
67 NCollection_ListNode* theNext2) :
68 NCollection_TListNode<TheItemType>(theItem,theNext1)
69 {
70 myKey1 = theKey1;
71 myKey2 = theKey2;
72 myNext2 = (IndexedDataMapNode *) theNext2;
73 }
74 //! Key1
75 TheKeyType& Key1 (void)
76 { return myKey1; }
77 //! Key2
78 const Standard_Integer& Key2 (void)
79 { return myKey2; }
80 //! Next2
81 IndexedDataMapNode*& Next2 (void)
82 { return myNext2; }
83
84 //! Static deleter to be passed to BaseList
85 static void delNode (NCollection_ListNode * theNode,
86 Handle(NCollection_BaseAllocator)& theAl)
87 {
88 ((IndexedDataMapNode *) theNode)->~IndexedDataMapNode();
89 theAl->Free(theNode);
90 }
91 private:
92 TheKeyType myKey1;
93 Standard_Integer myKey2;
94 IndexedDataMapNode * myNext2;
95 };
96
97 public:
98 //! Implementation of the Iterator interface.
99 class Iterator : public NCollection_BaseCollection<TheItemType>::Iterator
100 {
101 public:
102 //! Empty constructor
103 Iterator (void) :
104 myMap(NULL),
105 myIndex(0) {}
106 //! Constructor
ad3217cd 107 Iterator (const NCollection_IndexedDataMap& theMap)
108 : myMap ((NCollection_IndexedDataMap* )&theMap),
109 myNode (myMap->nodeFromIndex (1)),
110 myIndex (1) {}
7fd59977 111 //! Query if the end of collection is reached by iterator
112 virtual Standard_Boolean More(void) const
113 { return (myIndex <= myMap->Extent()); }
114 //! Make a step along the collection
115 virtual void Next(void)
ad3217cd 116 {
117 myNode = myMap->nodeFromIndex (++myIndex);
118 }
7fd59977 119 //! Value access
120 virtual const TheItemType& Value(void) const
121 {
122#if !defined No_Exception && !defined No_Standard_NoSuchObject
123 if (!More())
124 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::Iterator::Value");
125#endif
ad3217cd 126 return myNode->Value();
7fd59977 127 }
128 //! ChangeValue access
129 virtual TheItemType& ChangeValue(void) const
130 {
131#if !defined No_Exception && !defined No_Standard_NoSuchObject
132 if (!More())
133 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::Iterator::ChangeValue");
134#endif
ad3217cd 135 return myNode->ChangeValue();
136 }
137 //! Key
138 const TheKeyType& Key() const
139 {
140#if !defined No_Exception && !defined No_Standard_NoSuchObject
141 if (!More())
142 Standard_NoSuchObject::Raise("NCollection_DataMap::Iterator::Key");
143#endif
144 return myNode->Key1();
7fd59977 145 }
7fd59977 146 private:
ad3217cd 147 NCollection_IndexedDataMap* myMap; //!< Pointer to the map being iterated
148 IndexedDataMapNode* myNode; //!< Current node
149 Standard_Integer myIndex; //!< Current index
7fd59977 150 };
151
152 public:
153 // ---------- PUBLIC METHODS ------------
154
155 //! Constructor
156 NCollection_IndexedDataMap (const Standard_Integer NbBuckets=1,
157 const Handle(NCollection_BaseAllocator)& theAllocator = 0L)
158 : NCollection_BaseCollection<TheItemType>(theAllocator),
159 NCollection_BaseMap (NbBuckets, Standard_False) {}
160
161 //! Copy constructor
162 NCollection_IndexedDataMap (const NCollection_IndexedDataMap& theOther)
163 : NCollection_BaseCollection<TheItemType>(theOther.myAllocator),
164 NCollection_BaseMap (theOther.NbBuckets(), Standard_False)
165 { *this = theOther; }
166
167 //! Assign another collection
168 virtual void Assign(const NCollection_BaseCollection<TheItemType>& theOther)
169 {
170 if (this == &theOther)
171 return;
172 Standard_TypeMismatch::Raise("NCollection_IndexedDataMap::Assign");
173 }
174
ab2db9a5 175 //! Exchange the content of two maps without re-allocations.
176 //! Notice that allocators will be swapped as well!
177 void Exchange (NCollection_IndexedDataMap& theOther)
178 {
179 this->exchangeAllocators (theOther);
180 this->exchangeMapsData (theOther);
181 }
182
7fd59977 183 //! = another map
184 NCollection_IndexedDataMap& operator=
185 (const NCollection_IndexedDataMap& theOther)
186 {
187 if (this == &theOther)
188 return *this;
189
190 Clear(theOther.myAllocator);
191 ReSize (theOther.Extent()-1);
192 Standard_Integer i;
193 for (i=1; i<=theOther.Extent(); i++)
194 {
195 TheKeyType aKey1 = theOther.FindKey(i);
196 TheItemType anItem = theOther.FindFromIndex(i);
9991c9c2 197 Standard_Integer iK1 = Hasher::HashCode (aKey1, NbBuckets());
198 Standard_Integer iK2 = ::HashCode (i, NbBuckets());
7fd59977 199 IndexedDataMapNode * pNode =
200 new (this->myAllocator) IndexedDataMapNode (aKey1, i, anItem,
201 myData1[iK1], myData2[iK2]);
202 myData1[iK1] = pNode;
203 myData2[iK2] = pNode;
204 Increment();
205 }
206 return *this;
207 }
208
209 //! ReSize
210 void ReSize (const Standard_Integer N)
211 {
fd03ee4b 212 NCollection_ListNode** ppNewData1 = NULL;
213 NCollection_ListNode** ppNewData2 = NULL;
7fd59977 214 Standard_Integer newBuck;
fd03ee4b 215 if (BeginResize (N, newBuck, ppNewData1, ppNewData2, this->myAllocator))
7fd59977 216 {
217 if (myData1)
218 {
219 IndexedDataMapNode *p, *q;
220 Standard_Integer i, iK1, iK2;
221 for (i = 0; i <= NbBuckets(); i++)
222 {
223 if (myData1[i])
224 {
225 p = (IndexedDataMapNode *) myData1[i];
226 while (p)
227 {
9991c9c2 228 iK1 = Hasher::HashCode (p->Key1(), newBuck);
229 iK2 = ::HashCode (p->Key2(), newBuck);
7fd59977 230 q = (IndexedDataMapNode*) p->Next();
231 p->Next() = ppNewData1[iK1];
fd03ee4b 232 p->Next2() = (IndexedDataMapNode*)ppNewData2[iK2];
7fd59977 233 ppNewData1[iK1] = p;
234 ppNewData2[iK2] = p;
235 p = q;
236 }
237 }
238 }
239 }
fd03ee4b 240 EndResize (N, newBuck, ppNewData1, ppNewData2, this->myAllocator);
7fd59977 241 }
242 }
243
244 //! Add
245 Standard_Integer Add (const TheKeyType& theKey1, const TheItemType& theItem)
246 {
247 if (Resizable())
248 ReSize(Extent());
9991c9c2 249 Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
7fd59977 250 IndexedDataMapNode * pNode;
251 pNode = (IndexedDataMapNode *) myData1[iK1];
252 while (pNode)
253 {
9991c9c2 254 if (Hasher::IsEqual (pNode->Key1(), theKey1))
7fd59977 255 return pNode->Key2();
256 pNode = (IndexedDataMapNode *) pNode->Next();
257 }
258 Increment();
9991c9c2 259 Standard_Integer iK2 = ::HashCode(Extent(),NbBuckets());
7fd59977 260 pNode = new (this->myAllocator) IndexedDataMapNode (theKey1, Extent(), theItem,
261 myData1[iK1], myData2[iK2]);
262 myData1[iK1] = pNode;
263 myData2[iK2] = pNode;
264 return Extent();
265 }
266
267 //! Contains
268 Standard_Boolean Contains (const TheKeyType& theKey1) const
269 {
270 if (IsEmpty())
271 return Standard_False;
9991c9c2 272 Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
7fd59977 273 IndexedDataMapNode * pNode1;
274 pNode1 = (IndexedDataMapNode *) myData1[iK1];
275 while (pNode1)
276 {
9991c9c2 277 if (Hasher::IsEqual(pNode1->Key1(), theKey1))
7fd59977 278 return Standard_True;
279 pNode1 = (IndexedDataMapNode *) pNode1->Next();
280 }
281 return Standard_False;
282 }
283
284 //! Substitute
285 void Substitute (const Standard_Integer theIndex,
286 const TheKeyType& theKey1,
287 const TheItemType& theItem)
288 {
289#if !defined No_Exception && !defined No_Standard_OutOfRange
290 if (theIndex < 1 || theIndex > Extent())
291 Standard_OutOfRange::Raise ("NCollection_IndexedDataMap::Substitute");
292#endif
293 IndexedDataMapNode * p;
294 // check if theKey1 is not already in the map
9991c9c2 295 Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
7fd59977 296 p = (IndexedDataMapNode *) myData1[iK1];
297 while (p)
298 {
9991c9c2 299 if (Hasher::IsEqual (p->Key1(), theKey1))
7fd59977 300 Standard_DomainError::Raise("NCollection_IndexedDataMap::Substitute");
301 p = (IndexedDataMapNode *) p->Next();
302 }
303
304 // Find the node for the index I
9991c9c2 305 Standard_Integer iK2 = ::HashCode (theIndex, NbBuckets());
7fd59977 306 p = (IndexedDataMapNode *) myData2[iK2];
307 while (p)
308 {
309 if (p->Key2() == theIndex)
310 break;
311 p = (IndexedDataMapNode*) p->Next2();
312 }
313
314 // remove the old key
9991c9c2 315 Standard_Integer iK = Hasher::HashCode (p->Key1(), NbBuckets());
7fd59977 316 IndexedDataMapNode * q = (IndexedDataMapNode *) myData1[iK];
317 if (q == p)
318 myData1[iK] = (IndexedDataMapNode *) p->Next();
319 else
320 {
321 while (q->Next() != p)
322 q = (IndexedDataMapNode *) q->Next();
323 q->Next() = p->Next();
324 }
325
326 // update the node
327 p->Key1() = theKey1;
328 p->ChangeValue() = theItem;
329 p->Next() = myData1[iK1];
330 myData1[iK1] = p;
331 }
332
333 //! RemoveLast
334 void RemoveLast (void)
335 {
336#if !defined No_Exception && !defined No_Standard_OutOfRange
337 if (Extent() == 0)
338 Standard_OutOfRange::Raise ("NCollection_IndexedDataMap::RemoveLast");
339#endif
340 IndexedDataMapNode * p, * q;
341 // Find the node for the last index and remove it
9991c9c2 342 Standard_Integer iK2 = ::HashCode (Extent(), NbBuckets());
7fd59977 343 p = (IndexedDataMapNode *) myData2[iK2];
344 q = NULL;
345 while (p)
346 {
347 if (p->Key2() == Extent())
348 break;
349 q = p;
350 p = (IndexedDataMapNode*) p->Next2();
351 }
352 if (q == NULL)
353 myData2[iK2] = (IndexedDataMapNode *) p->Next2();
354 else
355 q->Next2() = p->Next2();
356
357 // remove the key
9991c9c2 358 Standard_Integer iK1 = Hasher::HashCode (p->Key1(), NbBuckets());
7fd59977 359 q = (IndexedDataMapNode *) myData1[iK1];
360 if (q == p)
361 myData1[iK1] = (IndexedDataMapNode *) p->Next();
362 else
363 {
364 while (q->Next() != p)
365 q = (IndexedDataMapNode *) q->Next();
366 q->Next() = p->Next();
367 }
368 p->~IndexedDataMapNode();
369 this->myAllocator->Free(p);
370 Decrement();
371 }
372
373 //! FindKey
374 const TheKeyType& FindKey (const Standard_Integer theKey2) const
375 {
376#if !defined No_Exception && !defined No_Standard_OutOfRange
377 if (theKey2 < 1 || theKey2 > Extent())
378 Standard_OutOfRange::Raise ("NCollection_IndexedDataMap::FindKey");
379#endif
ad3217cd 380 IndexedDataMapNode* aNode = nodeFromIndex (theKey2);
381 if (aNode == NULL)
7fd59977 382 {
ad3217cd 383 Standard_NoSuchObject::Raise ("NCollection_IndexedDataMap::FindKey");
7fd59977 384 }
ad3217cd 385 return aNode->Key1();
7fd59977 386 }
387
388 //! FindFromIndex
389 const TheItemType& FindFromIndex (const Standard_Integer theKey2) const
390 {
391#if !defined No_Exception && !defined No_Standard_OutOfRange
392 if (theKey2 < 1 || theKey2 > Extent())
393 Standard_OutOfRange::Raise ("NCollection_IndexedDataMap::FindFromIndex");
394#endif
ad3217cd 395 IndexedDataMapNode* aNode = nodeFromIndex (theKey2);
396 if (aNode == NULL)
7fd59977 397 {
ad3217cd 398 Standard_NoSuchObject::Raise ("NCollection_IndexedDataMap::FindFromIndex");
7fd59977 399 }
ad3217cd 400 return aNode->Value();
7fd59977 401 }
402
403 //! operator ()
404 const TheItemType& operator() (const Standard_Integer theKey2) const
405 { return FindFromIndex (theKey2); }
406
407 //! ChangeFromIndex
408 TheItemType& ChangeFromIndex (const Standard_Integer theKey2)
409 {
410#if !defined No_Exception && !defined No_Standard_OutOfRange
411 if (theKey2 < 1 || theKey2 > Extent())
412 Standard_OutOfRange::Raise("NCollection_IndexedDataMap::ChangeFromIndex");
413#endif
ad3217cd 414 IndexedDataMapNode* aNode = nodeFromIndex (theKey2);
415 if (aNode == NULL)
7fd59977 416 {
ad3217cd 417 Standard_NoSuchObject::Raise ("NCollection_IndexedDataMap::ChangeFromIndex");
7fd59977 418 }
ad3217cd 419 return aNode->ChangeValue();
7fd59977 420 }
421
422 //! operator ()
423 TheItemType& operator() (const Standard_Integer theKey2)
424 { return ChangeFromIndex (theKey2); }
425
426 //! FindIndex
427 Standard_Integer FindIndex(const TheKeyType& theKey1) const
428 {
429 if (IsEmpty()) return 0;
430 IndexedDataMapNode * pNode1 =
9991c9c2 431 (IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
7fd59977 432 while (pNode1)
433 {
9991c9c2 434 if (Hasher::IsEqual (pNode1->Key1(), theKey1))
7fd59977 435 return pNode1->Key2();
436 pNode1 = (IndexedDataMapNode*) pNode1->Next();
437 }
438 return 0;
439 }
440
441 //! FindFromKey
442 const TheItemType& FindFromKey(const TheKeyType& theKey1) const
443 {
444#if !defined No_Exception && !defined No_Standard_NoSuchObject
445 if (IsEmpty())
446 Standard_NoSuchObject::Raise ("NCollection_IndexedDataMap::FindFromKey");
447#endif
448 IndexedDataMapNode * pNode1 =
9991c9c2 449 (IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
7fd59977 450 while (pNode1)
451 {
9991c9c2 452 if (Hasher::IsEqual (pNode1->Key1(), theKey1))
7fd59977 453 return pNode1->Value();
454 pNode1 = (IndexedDataMapNode*) pNode1->Next();
455 }
456 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::FindFromKey");
457 return pNode1->Value();
458 }
459
460 //! ChangeFromKey
461 TheItemType& ChangeFromKey (const TheKeyType& theKey1)
462 {
463#if !defined No_Exception && !defined No_Standard_NoSuchObject
464 if (IsEmpty())
465 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::ChangeFromKey");
466#endif
467 IndexedDataMapNode * pNode1 =
9991c9c2 468 (IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
7fd59977 469 while (pNode1)
470 {
9991c9c2 471 if (Hasher::IsEqual (pNode1->Key1(), theKey1))
7fd59977 472 return pNode1->ChangeValue();
473 pNode1 = (IndexedDataMapNode*) pNode1->Next();
474 }
475 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::ChangeFromKey");
476 return pNode1->ChangeValue();
477 }
478
ad3217cd 479 //! Find value for key with copying.
480 //! @return true if key was found
481 Standard_Boolean FindFromKey (const TheKeyType& theKey1,
482 TheItemType& theValue) const
483 {
484 if (IsEmpty())
485 {
486 return Standard_False;
487 }
488 for (IndexedDataMapNode* aNode = (IndexedDataMapNode* )myData1[Hasher::HashCode (theKey1, NbBuckets())];
489 aNode != NULL; aNode = (IndexedDataMapNode* )aNode->Next())
490 {
491 if (Hasher::IsEqual (aNode->Key1(), theKey1))
492 {
493 theValue = aNode->Value();
494 return Standard_True;
495 }
496 }
497 return Standard_False;
498 }
499
7fd59977 500 //! Clear data. If doReleaseMemory is false then the table of
501 //! buckets is not released and will be reused.
502 void Clear(const Standard_Boolean doReleaseMemory = Standard_True)
503 { Destroy (IndexedDataMapNode::delNode, this->myAllocator, doReleaseMemory); }
504
505 //! Clear data and reset allocator
506 void Clear (const Handle(NCollection_BaseAllocator)& theAllocator)
507 {
508 Clear();
509 this->myAllocator = ( ! theAllocator.IsNull() ? theAllocator :
510 NCollection_BaseAllocator::CommonBaseAllocator() );
511 }
512
513 //! Destructor
514 ~NCollection_IndexedDataMap (void)
515 { Clear(); }
516
517 //! Size
518 virtual Standard_Integer Size(void) const
519 { return Extent(); }
520
521 private:
522 // ----------- PRIVATE METHODS -----------
523
524 //! Creates Iterator for use on BaseCollection
525 virtual TYPENAME NCollection_BaseCollection<TheItemType>::Iterator&
526 CreateIterator(void) const
527 { return *(new (this->IterAllocator()) Iterator(*this)); }
528
ad3217cd 529 //! Find map node associated with specified index.
530 //! Return NULL if not found (exception-free internal implementation).
531 IndexedDataMapNode* nodeFromIndex (const Standard_Integer theKey2) const
532 {
533 if (Extent() == 0)
534 {
535 return NULL;
536 }
537 for (IndexedDataMapNode* aNode = (IndexedDataMapNode* )myData2[::HashCode (theKey2, NbBuckets())];
538 aNode != NULL; aNode = (IndexedDataMapNode* )aNode->Next2())
539 {
540 if (aNode->Key2() == theKey2)
541 {
542 return aNode;
543 }
544 }
545 return NULL;
546 }
547
7fd59977 548};
549
7fd59977 550#endif