Polygon Crucher SDK - Documentation
Documentation
Loading...
Searching...
No Matches
Collection.h
1#ifndef CCOLLECTION_CLASS_H
2#define CCOLLECTION_CLASS_H
3
4#ifdef _MSC_VER
5#pragma once
6#endif // _MSC_VER
7
8#include "OffsetArray.h"
9
10BEGIN_MOOTOOLS_NAMESPACE
11
12 #if 0
13 DLL_TOOLSFUNCTION void TestCollection();
14 #define COLLECTION_STATS
15 #endif
16
17 template<class DATATYPE, class SIZETYPE> class CSimpleCollection;
18 template<class DATATYPE, class SIZETYPE> class CObjectCollection;
19
20 /////////////////////////////////////////////////////
21 // CCollectionElement
22 //
23 // This class handles a safe way of accessing an entry
24 // in a CSimpleCollection or CObjectCollection
25 // The bounds is checked, so no buffer overrun is possible.
26 //
27
28 template<class DATATYPE, class SIZETYPE>
30 {
32
33 private:
35 int entryIndex, elementsSize;
36 DATATYPE *elementData;
37
38 void Init(CSimpleCollection<DATATYPE, SIZETYPE> *collection, int index, int size, DATATYPE *data);
39
40 protected:
42
43 public:
44 void Reset(); // Reset to a void element (without altering the collection itself). Same as a void initialization
45 bool IsEmpty() const; // Return false after a reset. Reset/IsEmpty is a useful mecanism to make the element empty. If HasIndex return false, this means that the element as no data or a 0 index size.
46 int GetEntryIndex() const;
47 int GetSize() const;
48 DATATYPE *GetData(int& size);
49 const DATATYPE *GetData(int& size) const;
50 DATATYPE& GetAt(int i) const;
51 DATATYPE& operator[](int i);
52 int Add(const DATATYPE& type);
53 void RemoveAt(int i);
54 void SetAt(int i, const DATATYPE& type);
55 DATATYPE *SetSize(int newsize);
57 void Copy(unsigned int srcindex);
58 };
59
60
61 /////////////////////////////////////////////////
62 // CCollectionElement implementation
63
64 template<class DATATYPE, class SIZETYPE>
66 {
67 elementCollection = NULL;
68 elementData = NULL;
69 elementsSize = entryIndex = 0;
70 }
71
72 template<class DATATYPE, class SIZETYPE>
74 {
75 elementCollection = collection;
76 entryIndex = index;
77 elementsSize = size;
78 elementData = size > 0 ? data : NULL;
79 }
80
81 template<class DATATYPE, class SIZETYPE>
83 {
84 elementCollection = NULL;
85 elementData = NULL;
86 elementsSize = entryIndex = 0;
87 }
88
89 template<class DATATYPE, class SIZETYPE>
91 {
92 return (elementsSize == 0) || (elementData == NULL);
93 }
94
95 template<class DATATYPE, class SIZETYPE>
97 {
98 return elementsSize;
99 }
100
101 template<class DATATYPE, class SIZETYPE>
103 {
104 return entryIndex;
105 }
106
107 template<class DATATYPE, class SIZETYPE>
109 {
110 size = this->elementsSize;
111 return elementData;
112 }
113
114 template<class DATATYPE, class SIZETYPE>
115 inline const DATATYPE *CCollectionElement<DATATYPE, SIZETYPE>::GetData(int& size) const
116 {
117 size = this->elementsSize;
118 return elementData;
119 }
120
121 template<class DATATYPE, class SIZETYPE>
123 {
124 if (i < elementsSize)
125 return elementData[i];
126
127 XASSERT(0);
128 return elementData[0];
129 }
130
131 template<class DATATYPE, class SIZETYPE>
133 {
134 if (i < elementsSize)
135 return elementData[i];
136
137 XASSERT(0);
138 return elementData[0];
139 }
140
141 template<class DATATYPE, class SIZETYPE>
142 inline void CCollectionElement<DATATYPE, SIZETYPE>::SetAt(int i, const DATATYPE& type)
143 {
144 if (i < elementsSize)
145 {
146 elementData[i] = type;
147 return;
148 }
149
150 XASSERT(0);
151 }
152
153 template<class DATATYPE, class SIZETYPE>
155 {
156 XASSERT(elementCollection);
157
158 #ifdef _DEBUG
159 int tmp;
160 elementCollection->GetEntry(entryIndex, tmp);
161 XASSERT(tmp == elementsSize);
162 #endif
163
164 elementData = elementCollection->SetEntrySize(entryIndex, elementsSize++);
165 elementData[elementsSize] = type;
166
167 return elementsSize;
168 }
169
170 template<class DATATYPE, class SIZETYPE>
172 {
173 XASSERT(elementCollection);
174 elementData = elementCollection->SetEntry(entryIndex, copy);
175 elementsSize = copy.GetSize();
176 }
177
178 template<class DATATYPE, class SIZETYPE>
180 {
181 XASSERT(elementCollection);
182 elementCollection->SetEntry(entryIndex, srcindex);
183 elementData = elementCollection->GetEntry(entryIndex, elementsSize);
184 }
185
186 template<class DATATYPE, class SIZETYPE>
188 {
189 XASSERT(elementCollection);
190 if (index < elementsSize)
191 {
192 elementsSize = elementCollection->RemoveElementInEntry(entryIndex, index);
193 return;
194 }
195
196 XASSERT(0);
197 }
198
199 template<class DATATYPE, class SIZETYPE>
201 {
202 XASSERT(elementCollection);
203 if (elementsSize == newsize)
204 return elementData;
205
206 elementData = elementCollection->SetEntrySize(entryIndex, newsize);
207 elementsSize = newsize;
208
209 return elementData;
210 }
211
212 /////////////////////////////////////////////////////
213 // CSimpleCollection
214 //
215 // This class handles an array of entries
216 // each entries contains a given number of data elements
217 // All is stored in a raw array
218 //
219
220 // SetEntriesSize modes
221 typedef enum _CollectionInitializeMode
222 {
223 COL_EMPTY_NEW_ENTRIES = 0x01, // new entries are preallocated (defaultElementsNbr) but are kept empty. GetSize() return required number of elements. elements are defined using GetEntry()
224 COL_EMPTY_COLLECTION = 0x02, // collection is freed. new entries are preallocated (defaultElementsNbr) and collection is empty. GetSize() return 0 and elements are added using AddElementInEntry()
225 COL_KEEP_ENTRIES = 0x04, // entries are not modified when collection is resized
226 COL_SHRINK_ENTRIES = 0x08, // entries are adjusted to defaultElementsNbr when collection is resized
227 COL_GROWING_ENTRIES = 0x10, // entries are growing. This prevent the buffer to be resized down when resizing. This allows to fix a size at the beginning of a process, then call SetSize without making reallocation if size lower than initial value.
228 COL_EXACTSIZE_ENTRIES = 0x20, // don't allocate extra size when allocating entries
230
231 // SetEntrySize modes
232 typedef enum _CollectionElementsMode
233 {
234 COL_CREATE_ELEMENTS = 0x01, // new elements are created
235 COL_COMPRESS = 0x02, // if array is not large enough, the buffer is compressed before being grow. Useful to avoid array oversize, when we know the data should fit in the already allocated buffer
236 } _CollectionElementsMode;
237
238 typedef struct CSCOffsetRange
239 {
240 unsigned int offset;
241 unsigned int length;
242 unsigned int start, end;
243 } CSCOffsetRange;
244
245 template<class TYPE, class SIZETYPE>
247 {
249
250 protected:
251 struct CElementHeader
252 {
253 SIZETYPE size;
254 SIZETYPE maxsize;
255 };
256
257 private :
258 unsigned char *data;
259 unsigned int entriesNbr;
260 SIZETYPE defaultElementsNbr;
261 SIZET dataOffset, dataSize;
262 COffsetArray offsetArray;
263
264 #ifdef COLLECTION_STATS
265 // Statistics information
267 unsigned int maxElements, curElements;
268 unsigned int maxEntries;
269 SIZET maxSize;
271 float minWastedRatio;
272
273 void UpdateStatistics(bool recompute = FALSE);
274 #endif
275
276 TYPE *InitElementsSize(unsigned int index, unsigned int size, unsigned int creationMode);
277
278 void Init();
279 SIZET GetDataSize(bool keepElementSize = false);
280 void Compress(SIZET newSize, SIZET minimumSize);
281 void Grow(SIZET newDataSize, bool allocExtraSpace = true);
282
283 virtual void DestroyElement(TYPE *element, unsigned int number);
284 virtual void CreateElement(TYPE *element, unsigned int number);
285
286 virtual void DestroyEntries(unsigned int first, unsigned int number);
287 virtual void CreateEntries(unsigned int first, unsigned int number);
288 virtual void CopyEntry(TYPE *dst, const TYPE *src, int elementNbr);
289 virtual void CopyEntries(const CSimpleCollection<TYPE, SIZETYPE>& collection, unsigned int dstindex);
290
291 public:
292 CSimpleCollection(unsigned int defaultElementsNbr = 3);
293 virtual ~CSimpleCollection();
294
295 unsigned int GetDefaultEntrySize() { return defaultElementsNbr; };
296
297 // Access methods to elements
298 void Copy(const CSimpleCollection<TYPE, SIZETYPE>& collection, bool preallocateOnly = false, bool removeAll = true);
299 void Serialize(CXArchive& archive);
300 void Compress();
301 bool FreeExtra(bool allocExtraSpace = false);
302 unsigned int GetEntriesSize() const; // The number of entries of the collection
303 unsigned int *GetSizes(unsigned int& size) const; // Return an array containing the number of element for each entry of the collection (size is the number of entries of the collection)
304 void SetEntriesSize(unsigned int entriesNbr, unsigned int defaultElementsNbr, unsigned int mode, unsigned int *elementsSize = NULL);
305 void PreAllocate(unsigned int maxEntriesNbr, SIZET maxElementsNbr);
306
307 unsigned int AddEntry(bool createElements, unsigned int elementNbr = -1);
308 unsigned int AddEntry(const CCollectionElement<TYPE, SIZETYPE>& element);
309
310 TYPE *SetEntry(unsigned int index, const CCollectionElement<TYPE, SIZETYPE>& element);
311 TYPE *SetEntry(unsigned int dstindex, unsigned int srcindex);
312 TYPE *SetEntry(unsigned int dstindex, const TYPE *data, int size); // Beware data can't belong to the collection itself
313 void GetEntry(unsigned int index, CCollectionElement<TYPE, SIZETYPE>& element);
314 void GetEntry(unsigned int index, const CCollectionElement<TYPE, SIZETYPE>& element) const;
315 TYPE *GetEntry(unsigned int index, int& size) const;
316 void RemoveEntry(unsigned int index, unsigned int nCount = 1);
317 void Free();
318
319 // Access methods to elements
320 TYPE *SetEntrySize(unsigned int index, unsigned int elementsNbr, bool createElements = true);
321 TYPE *SetEntrySizeCompressed(unsigned int index, unsigned int elementsNbr, bool createElements = true);
322 unsigned int AddElementInEntry(unsigned int index, const TYPE& element, unsigned int newCreatedElementNumber = 1, bool createExtraElements = false);
323 unsigned int RemoveElementInEntry(unsigned int index, unsigned elementIndex);
324
325 #ifdef _DEBUG
326 unsigned int CountElements() const;
327 #endif
328 };
329
330 #define COL_TYPE_PTR(data, offset) ((TYPE *)((unsigned char *)data+offset+sizeof(typename CSimpleCollection<TYPE, SIZETYPE>::CElementHeader)))
331 #define COL_HEADER_PTR(data, offset) ((typename CSimpleCollection<TYPE, SIZETYPE>::CElementHeader *)((unsigned char *)data+offset))
332 #define COL_DATA_SIZE(elementnbr) ((SIZET)((elementnbr)*sizeof(TYPE)+sizeof(typename CSimpleCollection<TYPE, SIZETYPE>::CElementHeader))) // parenthesis between (elementnbr) is important for such call: COL_DATA_SIZE(size-cursize)
333
334 /////////////////////////////////////////////////
335 // CSimpleCollection
336
337 template<class TYPE, class SIZETYPE>
339 {
340 XASSERT(newDefaultElementsNbr > 0 && newDefaultElementsNbr <= 0xFFFF);
341 if (newDefaultElementsNbr > 0)
342 this->defaultElementsNbr = (SIZETYPE)newDefaultElementsNbr;
343 else
344 this->defaultElementsNbr = 3;
345
346 Init();
347 }
348
349 template<class TYPE, class SIZETYPE>
351 {
352 Free();
353 }
354
355 #ifdef _DEBUG
356 template<class TYPE, class SIZETYPE>
358 {
359 SIZET offset;
360 unsigned int count = 0;
361 CElementHeader *header;
362
363 for (unsigned int i=0; i<entriesNbr; i++)
364 {
365 offset = offsetArray[i];
366 header = COL_HEADER_PTR(data, offset);
367 count += header->size;
368 }
369 #ifdef COLLECTION_STATS
370 XASSERT(count == curElements);
371 #endif
372
373 return count;
374 }
375 #endif
376
377 #ifdef COLLECTION_STATS
378 template<class TYPE, class SIZETYPE>
380 {
381 if (recompute)
382 {
383 unsigned int i, elements = 0, totalsize = 0;
384 SIZET offset;
385 CElementHeader *header;
386 for (i=0; i<entriesNbr; i++)
387 {
388 offset = offsetArray[i];
389
390 header = COL_HEADER_PTR(data, offset);
391 totalsize += COL_DATA_SIZE(header->size);
392 elements += header->size;
393 }
394
395 if (totalsize && (minWastedRatio == 0.0 || (minWastedRatio > (dataSize/(float)totalsize))))
396 minWastedRatio = (dataSize/(float)totalsize);
397
399 }
400 else
401 {
402 SIZET totalsize = (curElements*sizeof(TYPE)+entriesNbr*sizeof(CElementHeader));
403 if (totalsize && (minWastedRatio == 0.0 || (minWastedRatio > (dataSize /(float)totalsize))))
404 minWastedRatio = (dataSize/(float)totalsize);
405 }
406
407 if (maxEntries < entriesNbr)
408 maxEntries = entriesNbr;
409
412 }
413 #endif
414
415 // Destroy a particular element
416 template<class TYPE, class SIZETYPE>
418 {
419 #ifdef COLLECTION_STATS
421 #endif
422 }
423
424 // Destroy collection elements
425 template<class TYPE, class SIZETYPE>
426 inline void CSimpleCollection<TYPE, SIZETYPE>::DestroyEntries(unsigned int first, unsigned int number)
427 {
428 #ifdef COLLECTION_STATS
429 SIZET offset;
430 CElementHeader *header;
431
432 number += first;
433 for (unsigned int i=first; i<number; i++)
434 {
435 offset = offsetArray[i];
436 header = COL_HEADER_PTR(data, offset);
437 curElements -= header->size;
438 }
439 #endif
440 }
441
442 // Create a particular elements
443 template<class TYPE, class SIZETYPE>
445 {
446 #ifdef COLLECTION_STATS
448 UpdateStatistics(); // update maxElements / maxEntries
449 #endif
450 }
451
452 // Create collection elements
453 template<class TYPE, class SIZETYPE>
454 inline void CSimpleCollection<TYPE, SIZETYPE>::CreateEntries(unsigned int first, unsigned int number)
455 {
456 #ifdef COLLECTION_STATS
457 SIZET offset;
458 CElementHeader *header;
459
460 number += first;
461 for (unsigned int i=first; i<number; i++)
462 {
463 offset = offsetArray[i];
464 header = COL_HEADER_PTR(data, offset);
465 curElements += header->size;
466 }
467 #endif
468 }
469
470 template<class TYPE, class SIZETYPE>
472 {
473 xmemcpy_s(dst, elementNbr*sizeof(TYPE), src, elementNbr*sizeof(TYPE)); // dst should have at least elementNbr before calling
474 }
475
476 template<class TYPE, class SIZETYPE>
478 {
479 XASSERT(dstindex+collection.entriesNbr <= entriesNbr); // Elements must have been created and preallocated
480
481 CElementHeader *srcheader;
482 SIZET srcoffset, dstoffset;
483 for (unsigned int i = 0; i<collection.entriesNbr; i++)
484 {
485 srcoffset = collection.offsetArray[i];
486 dstoffset = offsetArray[dstindex+i];
487
488 srcheader = COL_HEADER_PTR(collection.data, srcoffset);
489
490 xmemcpy_s(COL_TYPE_PTR(data, dstoffset), dataSize-dstoffset, COL_TYPE_PTR(collection.data, srcoffset), srcheader->size*sizeof(TYPE));
491 }
492 }
493
494 template<class TYPE, class SIZETYPE>
496 {
497 data = NULL;
498 dataSize = 0;
499 dataOffset = 0;
500 entriesNbr = 0;
501
502 offsetArray.RemoveAll();
503
504 #ifdef COLLECTION_STATS
505 // Statistics information
507 maxSize = 0;
509 minWastedRatio = 0.0f;
510 #endif
511 }
512
513 template<class TYPE, class SIZETYPE>
515 {
516 if (!data)
517 {
518 XASSERT(!dataSize);
519 XASSERT(!entriesNbr);
520 XASSERT(!offsetArray.GetSize());
521 return;
522 }
523
524 #ifdef COLLECTION_STATS
525 if (maxElements != 0 || maxSize != 0)
526 {
527 XTRACE(traceStruct, 0, "CSimpleCollection (current size: %d - element size: %d)\n", dataSize, sizeof(TYPE));
528 XTRACE(traceStruct, 0, "%d - %d (Entries (current) - elements (current))\n", entriesNbr, curElements);
529 XTRACE(traceStruct, 0, "%d - %d (Entries (maximum) - elements (maximum))\n", maxEntries, maxElements);
530 XTRACE(traceStruct, 0, "%d - %d - %lld (Array reallocation - Compressed time - Rearranged time - Readjusted entries)\n", growTime, compressedTime, rearrangedTime, readjustedEntries);
531 XTRACE(traceStruct, 0, "%d - %.2f (Maximum bytes size - Allocated/Needed size (wasted space))\n\n", maxSize, minWastedRatio);
532 }
533 #endif
534
535 DestroyEntries(0, entriesNbr);
536
537 #ifdef COLLECTION_STATS
538 XASSERT(curElements == 0);
539 #endif
540
541 xDeallocateArray(data);
542 Init();
543 }
544
545 // if preallocateOnly = TRUE, we use collection entries for preallocating the current object. The data content is not copied.
546 // if preallocateOnly = FALSE, the data content is copied.
547 // If removeAll = true, the list is reset with the new content, otherwise it is expanded with the new content
548 template<class TYPE, class SIZETYPE>
550 {
551 if (removeAll)
552 {
553 Free();
554 defaultElementsNbr = collection.defaultElementsNbr;
555 }
556
557 unsigned int i;
558 SIZET srcoffset, size = dataOffset; // Copy the collection after the last entry we have
559 CElementHeader *srcheader, *dstheader;
560
561 // Compute the destination required size. We set it to minimum size
562 for (i=0; i<collection.entriesNbr; i++)
563 {
564 srcoffset = collection.offsetArray[i];
565
566 srcheader = COL_HEADER_PTR(collection.data, srcoffset);
567 size += COL_DATA_SIZE(srcheader->maxsize);
568 }
569
570 Grow(size, false);
571
572 // Copy headers and entries
573 unsigned int entryOffset = entriesNbr;
574 entriesNbr += collection.entriesNbr;
575 XASSERT((entriesNbr-entryOffset) == collection.entriesNbr);
576 offsetArray.SetSize(entriesNbr);
577 for (i = 0; i<collection.entriesNbr; i++)
578 {
579 srcoffset = collection.offsetArray[i];
580 srcheader = COL_HEADER_PTR(collection.data, srcoffset);
581
582 offsetArray.SetAt(entryOffset+i, dataOffset);
583
584 dstheader = COL_HEADER_PTR(data, dataOffset);
585 dstheader->size = srcheader->size;
586 dstheader->maxsize = srcheader->maxsize;
587
588 dataOffset += COL_DATA_SIZE(srcheader->maxsize);
589 }
590
591 if (preallocateOnly)
592 {
593 // We only use the size given by collection to preallocate the array
594 // but we don't copy the content.
595 for (i = 0; i<collection.entriesNbr; i++)
596 {
597 dstheader = COL_HEADER_PTR(data, offsetArray[i+entryOffset]);
598 dstheader->size = 0;
599 }
600 }
601 else
602 {
603 // Now create and copy entries
604 CopyEntries(collection, entryOffset);
605 }
606
607 #ifdef COLLECTION_STATS
609 #endif
610 }
611
612 template<class TYPE, class SIZETYPE>
614 {
615 if (ar.IsStoring())
616 {
617 FreeExtra(false);
618
619 ar << entriesNbr;
620 if (entriesNbr)
621 {
622 longuint tmp = dataOffset; // use unsigned int for x32 / x64 bits compatibility
623 ar.Write(&tmp, sizeof(tmp));
624 tmp = dataSize; // use unsigned int for x32 / x64 bits compatibility
625 ar.Write(&tmp, sizeof(tmp));
626
627 ar.Write(data, static_cast<unsigned int>(dataSize*sizeof(unsigned char)));
628 offsetArray.Serialize(ar);
629 }
630 }
631 else
632 {
633 Free();
634
635 ar >> entriesNbr;
636 if (entriesNbr)
637 {
638 longuint tmp = dataOffset; // use unsigned __int64 for x32 / x64 bits compatibility
639 ar.Read(&tmp, sizeof(tmp));
640 dataOffset = (SIZET)tmp;
641
642 ar.Read(&tmp, sizeof(tmp));
643 dataSize = (SIZET)tmp;
644
645 data = xAllocateArray(unsigned char, dataSize);
646 ar.Read(data, static_cast<unsigned int>(dataSize*sizeof(unsigned char)));
647 offsetArray.Serialize(ar);
648
649 #ifdef COLLECTION_STATS
651 #endif
652 }
653 }
654 }
655
656#ifdef SC_REUSED_MEMORY // This code is verified and allows to reused the same piece of memory when compressing
657static int rangeCompareProc(const void *elem1, const void *elem2)
658 {
659 if (((const CSCOffsetRange *)elem1)->offset == ((const CSCOffsetRange *)elem2)->offset)
660 return 0;
661
662 return ((const CSCOffsetRange *)elem1)->offset > ((const CSCOffsetRange *)elem2)->offset ? 1 : -1;
663 }
664#endif
665
666 // Remove unused memory that might have been lost using RemoveAt, SetAt
667 template<class TYPE, class SIZETYPE>
669 {
670 if (!newSize)
671 {
672 xDeallocateArray(data);
673 data = NULL;
674 dataSize = 0;
675 dataOffset = 0;
676 offsetArray.SetSize(0); // Remove preallocated entries if any
677 return;
678 }
679
680 #ifdef SC_REUSED_MEMORY // This code is verified and allows to reused the same piece of memory when compressing
681 if (newSize == dataSize)
682 {
683 unsigned int i, j, rangeCount = 0;
684 CElementHeader *header;
685 CSCOffsetRange range;
687
688 XASSERT(minimumSize <= dataSize);
689 i = (dataSize-minimumSize)/(minimumSize/entriesNbr);
690 if (i < 10)
691 i = 10;
692 else if (i > entriesNbr*0.01f)
693 i = (unsigned int)(entriesNbr*0.01f);
694 ranges.SetSize(i, (entriesNbr*0.01f) < 1024 ? -1 : (INT_PTR)(entriesNbr*0.01f));
695
696 XASSERT(entriesNbr);
697 SIZET offset = offsetArray[0];
698 header = COL_HEADER_PTR(data, offset);
699 header->maxsize = header->size;
700
701 range.offset = offsetArray[0];
702 range.length = COL_DATA_SIZE(header->size);
703 range.start = 0;
704
705 for (i=1; i<entriesNbr; i++)
706 {
707 offset = offsetArray[i];
708 header = COL_HEADER_PTR(data, offset);
709 header->maxsize = header->size;
710
711 if (offset == range.offset+range.length) // Continuous block
712 range.length += COL_DATA_SIZE(header->size);
713 else
714 {
715 range.end = i;
716 ranges.SetAtGrow(rangeCount++, range);
717
718 range.start = i;
719 range.offset = offset;
720 range.length = COL_DATA_SIZE(header->size);
721 range.start = i;
722 }
723 }
724
725 // Store the last range
726 range.end = entriesNbr;
727 ranges.SetAtGrow(rangeCount++, range);
728
729 CSCOffsetRange *rangePtr = ranges.GetData();
730 qsort(rangePtr, rangeCount, sizeof(CSCOffsetRange), rangeCompareProc);
731
732 SIZET delta, newoffset = 0;
733 for (i=0; i<rangeCount; i++)
734 {
735 xmemcpy_s(data+newoffset, dataSize-newoffset, data+rangePtr[i].offset, rangePtr[i].length);
736
737 // update offset
738 XASSERT(newoffset <= rangePtr[i].offset);
739 delta = rangePtr[i].offset-newoffset;
740 if (delta)
741 {
742 for (j=rangePtr[i].start; j<rangePtr[i].end; j++)
743 offsetArray[j] = offsetArray[j]-delta;
744 }
745
746 newoffset += rangePtr[i].length;
747 }
748
749 dataOffset = newoffset;
750 offsetArray.SetSize(entriesNbr); // Remove preallocated entries if any
751
752 XASSERT(dataOffset == GetDataSize());
753
754 #ifdef COLLECTION_STATS
756 #endif
757
758 return;
759 }
760 #endif
761
762 CElementHeader *oldheader, *newheader;
763 SIZET offset, newOffset = 0;
764 unsigned char *newdata = xAllocateArray(unsigned char, newSize);
765
766 for (unsigned int i=0; i<entriesNbr; i++)
767 {
768 offset = offsetArray[i];
769
770 // copy headers
771 oldheader = COL_HEADER_PTR(data, offset);
772 newheader = COL_HEADER_PTR(newdata, newOffset);
773 newheader->maxsize = newheader->size = oldheader->size;
774
775 offsetArray.SetAt(i, newOffset);
776
777 // copy data
778 offset += sizeof(CElementHeader);
779 newOffset += sizeof(CElementHeader);
780
781 xmemcpy_s(newdata+newOffset, newSize-newOffset, data+offset, oldheader->size*sizeof(TYPE));
782
783 newOffset += oldheader->size*sizeof(TYPE);
784 }
785
786 XASSERT((dataOffset != newOffset) || (newSize < dataSize)); // This means that Compress removes some entries and was useful, or Compress mimize allocated size
787
788 xDeallocateArray(data);
789 data = newdata;
790 dataSize = newSize;
791
792 dataOffset = newOffset;
793 offsetArray.SetSize(entriesNbr); // Remove preallocated entries if any
794 offsetArray.FreeExtra();
795
796 #ifdef COLLECTION_STATS
798 #endif
799 }
800
801 template<class TYPE, class SIZETYPE>
803 {
804 if (!data)
805 return 0;
806
807 unsigned int i;
808 SIZET offset, totalsize = 0;
809 CElementHeader *header;
810
811 // Compute the new required size
812 if (keepElementSize)
813 {
814 for (i=0; i<entriesNbr; i++)
815 {
816 offset = offsetArray[i];
817 header = COL_HEADER_PTR(data, offset);
818 totalsize += COL_DATA_SIZE(header->maxsize);
819 }
820 }
821 else
822 {
823 for (i=0; i<entriesNbr; i++)
824 {
825 offset = offsetArray[i];
826 header = COL_HEADER_PTR(data, offset);
827 totalsize += COL_DATA_SIZE(header->size);
828 }
829 }
830
831 return totalsize;
832 }
833
834 // Remove unused memory but keep the same allocated space
835 template<class TYPE, class SIZETYPE>
837 {
838 SIZET newsize = GetDataSize();
839
840 // Our array cannot be concatenated
841 if (newsize == dataOffset)
842 return;
843
844 Compress(dataSize, newsize);
845 }
846
847 // Remove unused memory that might have been lost using RemoveAt, SetAt
848 // return true if memory something was free, false if the size is already optimal
849 template<class TYPE, class SIZETYPE>
851 {
852 SIZET newsize = GetDataSize(keepElementSizeAndExtraSpace);
854 {
855 SIZET extraSize = (newsize/4);
856 extraSize = (extraSize < COL_DATA_SIZE(defaultElementsNbr)) ? COL_DATA_SIZE(defaultElementsNbr) : extraSize;
858 }
859
860 // If keepElementSizeAndExtraSpace, resize only if the buffer is bigger than the needed buffer with is extra size. Occurs when the number of elements has been sized down
861 if (newsize == dataSize || (keepElementSizeAndExtraSpace && dataSize < newsize))
862 return false;
863
864 Compress(newsize, newsize);
865 return true;
866 }
867
868 template<class TYPE, class SIZETYPE>
870 {
871 if (!maxEntriesNbr)
872 maxEntriesNbr = 1;
873
874 Free();
875 unsigned int elementsPerEntry = (unsigned int)(ceilf(maxElementsNbr/(float)maxEntriesNbr));
876 if (elementsPerEntry < defaultElementsNbr)
877 elementsPerEntry = defaultElementsNbr;
878
879 SIZET size = COL_DATA_SIZE(elementsPerEntry)*maxEntriesNbr;
880 Grow(size);
881
882 offsetArray.PreAllocate(maxEntriesNbr);
883 }
884
885 // Reallocate the array
886 template<class TYPE, class SIZETYPE>
888 {
889 if (newDataSize <= dataSize)
890 return;
891
892 // Allocate 20% more than the needed array
893 if (allocExtraSpace)
894 {
895 SIZET extraSize = (newDataSize/4);
896 extraSize = (extraSize < COL_DATA_SIZE(defaultElementsNbr)) ? COL_DATA_SIZE(defaultElementsNbr) : extraSize;
898 }
899
900 unsigned char *newData = xAllocateArray(unsigned char, newDataSize);
901 if (dataSize)
902 xmemcpy_s(newData, newDataSize, data, dataSize < newDataSize ? dataSize : newDataSize);
903
904 #ifdef COLLECTION_STATS
905 if (dataSize)
906 growTime++;
907
908 if (maxSize < newDataSize)
910 #endif
911
912 xDeallocateArray(data);
913 data = newData;
914 dataSize = newDataSize;
915 // dataOffset is an offset. It remains valid...
916
917 #ifdef COLLECTION_STATS
919 #endif
920 }
921
922 template<class TYPE, class SIZETYPE>
923 void CSimpleCollection<TYPE, SIZETYPE>::SetEntriesSize(unsigned int elements, unsigned int newDefaultElementsNbr, unsigned int mode, unsigned int *elementsSize)
924 {
925 XASSERT((newDefaultElementsNbr >= 0 && newDefaultElementsNbr <= 0xFFFF));
926 if (newDefaultElementsNbr > 0) // if defaultElementsNbr == 0, we keep the previous value but created empty elements as it was required
927 this->defaultElementsNbr = (SIZETYPE)newDefaultElementsNbr;
928
929 if (!elements || (mode & COL_EMPTY_COLLECTION))
930 {
931 if (!(mode & COL_GROWING_ENTRIES))
932 Free();
933
934 if (!elements)
935 return;
936 }
937
938 // No initialization yet...
939 SIZETYPE headerSizeNbr = (mode & (COL_EMPTY_NEW_ENTRIES|COL_EMPTY_COLLECTION)) ? 0 : defaultElementsNbr;
940 if (!dataSize)
941 {
942 SIZET newSize = 0;
943 if (elementsSize)
944 {
945 for (unsigned int i=0; i<elements; i++)
946 {
947 XASSERT(elementsSize[i] <= (SIZETYPE)(-1));
948 newSize += COL_DATA_SIZE(elementsSize[i]);
949 }
950 }
951 else
952 newSize = COL_DATA_SIZE(defaultElementsNbr)*elements;
953
954 Grow(newSize, elementsSize ? false : true); // If sizes are provided, we consider user knows exactly the size he needs
955
956 offsetArray.SetSize(elements);
957
958 CElementHeader *header;
959 for (unsigned int i = 0; i<elements; i++)
960 {
961 header = COL_HEADER_PTR(data, dataOffset);
962
963 offsetArray.SetAt(i, dataOffset);
964 header->size = headerSizeNbr;
965 if (elementsSize)
966 header->maxsize = (SIZETYPE)(elementsSize[i]);
967 else
968 header->maxsize = defaultElementsNbr;
969
970 dataOffset += COL_DATA_SIZE(header->maxsize);
971 }
972
973 if (defaultElementsNbr) // if size is 0, don't need to create an elements
974 CreateEntries(0, elements);
975
976 if (mode & COL_EMPTY_COLLECTION)
977 entriesNbr = 0;
978 else
979 entriesNbr = elements;
980 }
981 else
982 {
983 XASSERT(!elementsSize); // only possible at creation
984 XASSERT(mode & (COL_KEEP_ENTRIES|COL_SHRINK_ENTRIES));
985 XASSERT(!(mode & COL_EMPTY_COLLECTION));
986
987 // We first set the number of entries to the required size
988 // Then we will set each entry to have the required defaultElementsNbr
989
990 // Compute the new buffer size for avoiding many reallocation
991 // In the worst case, we have the same number of entries,
992 // buf each entries contains a smaller number of elements.
993 // Which means that all data are lost (dataOffset), and all entries
994 // should be reallocated
995 SIZET newSize;
996
997 if (mode & COL_KEEP_ENTRIES)
998 {
999 // New entries are created, each one has the defaultElementsNbr
1000 if (elements > entriesNbr)
1001 newSize = dataOffset+COL_DATA_SIZE(defaultElementsNbr)*(elements-entriesNbr);
1002 else
1003 newSize = dataSize; // Entries are removed. size is not modified
1004 }
1005 else // Shrink mode
1006 {
1007 newSize = dataOffset+COL_DATA_SIZE(defaultElementsNbr)*elements;
1008
1009 unsigned int tmpsize = elements < entriesNbr ? elements : entriesNbr;
1010 CElementHeader *header;
1011 for (unsigned int i = 0; i<tmpsize; i++)
1012 {
1013 SIZET offset = offsetArray[i];
1014 header = COL_HEADER_PTR(data, offset);
1016 {
1017 // this entry has enough space to store the number of elements.
1018 newSize -= COL_DATA_SIZE(defaultElementsNbr);
1019 }
1020 }
1021 }
1022
1023 Grow(newSize, (mode & COL_EXACTSIZE_ENTRIES) ? false : true);
1024
1025 // Our buffer is large enough to get or remove the new data
1026 if (elements > entriesNbr)
1027 {
1028 offsetArray.SetSize(elements);
1029
1030 CElementHeader *header;
1031 for (unsigned int i = entriesNbr; i<elements; i++)
1032 {
1033 header = COL_HEADER_PTR(data, dataOffset);
1034 offsetArray.SetAt(i, dataOffset);
1035 header->size = headerSizeNbr;
1036 header->maxsize = defaultElementsNbr;
1037 dataOffset += COL_DATA_SIZE(header->maxsize);
1038 }
1039
1040 // Create new elements
1041 if (defaultElementsNbr) // if size is 0, don't need to create an elements
1042 CreateEntries(entriesNbr, elements-entriesNbr);
1043
1044 if (mode & COL_SHRINK_ENTRIES)
1045 {
1046 // Now set the already existing elements to have the default size
1047 // if COL_EMPTY_NEW_ENTRIES, we don't create the new elements, just inflate the
1048 // entries to allows new elements to be added later
1049 for (unsigned int i=0; i<entriesNbr; i++)
1050 InitElementsSize(i, defaultElementsNbr, (mode & COL_EMPTY_NEW_ENTRIES) ? 0 : COL_CREATE_ELEMENTS);
1051 }
1052 }
1053 else
1054 {
1055 // elements <= entriesNbr. Array is growing, do not delete already entered elements
1056 // This is useful when caller first set SetEntriesSize(100); (100 is an estimation)
1057 // Then it calls SetEntriesSize with different value in a loop, without knowing the final number of elements... This avoid memory reallocation
1058 // then user should call SetSize with the right number of element (and without COL_GROWING_ENTRIES) then calls FreeExtra to adjust the size
1059 // an example of such use is done in CSkpReader::ConvertFaces (SketchupConverter.cpp)
1060 if (mode & COL_GROWING_ENTRIES)
1061 return; // Keep predefined entriesNbr
1062
1063 // Destroy unuseful elements
1064 DestroyEntries(elements, entriesNbr-elements);
1065 offsetArray.SetSize(elements);
1066
1067 if (mode & COL_SHRINK_ENTRIES)
1068 {
1069 XASSERT(!(mode & COL_EMPTY_NEW_ENTRIES));
1070
1071 // Now set each elements to have the default size
1072 for (unsigned int i=0; i<elements; i++)
1073 InitElementsSize(i, defaultElementsNbr, (mode & COL_EMPTY_NEW_ENTRIES) ? 0 : COL_CREATE_ELEMENTS);
1074 }
1075 }
1076
1077 entriesNbr = elements;
1078
1079 if (mode & COL_GROWING_ENTRIES)
1080 return; // Keep PreAllocated memory (when using PreAllocate, element number is 0 and grow progressively
1081
1082 // Then clean the array, but let's some extra space for further operation
1083 FreeExtra(!(mode & COL_EXACTSIZE_ENTRIES));
1084 }
1085
1086 #ifdef COLLECTION_STATS
1088 #endif
1089 }
1090
1091 template<class TYPE, class SIZETYPE>
1092 void CSimpleCollection<TYPE, SIZETYPE>::RemoveEntry(unsigned int index, unsigned int nCount)
1093 {
1094 if (index < entriesNbr)
1095 {
1096 // Destroy the element
1097 while (nCount)
1098 {
1099 SIZET offset = offsetArray[index];
1100 CElementHeader *header = COL_HEADER_PTR(data, offset);
1101 DestroyElement(COL_TYPE_PTR(data, offset), header->size);
1102 offsetArray.RemoveAt(index);
1103 entriesNbr--;
1104 nCount--;
1105
1106 if (nCount > 0 && index == entriesNbr)
1107 {
1108 XASSERT(0);
1109 break;
1110 }
1111 }
1112
1113 #ifdef COLLECTION_STATS
1115 #endif
1116
1117 return;
1118 }
1119
1120 XASSERT(0);
1121 }
1122
1123 template<class TYPE, class SIZETYPE>
1125 {
1126 return entriesNbr;
1127 }
1128
1129 template<class TYPE, class SIZETYPE>
1130 unsigned int *CSimpleCollection<TYPE, SIZETYPE>::GetSizes(unsigned int& size) const
1131 {
1132 size = entriesNbr;
1133 unsigned int *sizes = xAllocateArray(unsigned int, size);
1134
1135 CElementHeader *header;
1136 for (int i=0; i<size; i++)
1137 {
1138 header = COL_HEADER_PTR(data, offsetArray[i]);
1139 sizes[i] = header->size;
1140 }
1141
1142 return sizes;
1143 }
1144
1145 template<class TYPE, class SIZETYPE>
1147 {
1148 if (index < entriesNbr)
1149 {
1150 int size = element.GetSize();
1151 TYPE *newElement = SetEntrySize(index, size);
1152
1153 const TYPE *elementData = element.elementData;
1154 XASSERT(element.elementCollection);
1155 if (element.elementCollection == this)
1156 {
1157 // Do not use the element.elementData pointer.
1158 // The elementData pointer might changed if SetEntrySize grows the array and if element.elementCollection == this
1159 // This might occurs when copying items from a collection to itself such in CFace::Clean method
1160 elementData = element.elementCollection->GetEntry(element.entryIndex, size);
1161 XASSERT(size == element.GetSize());
1162 }
1163
1164 CopyEntry(newElement, elementData, size);
1165
1166 return newElement;
1167 }
1168
1169 XASSERT(0);
1170 return NULL;
1171 }
1172
1173 template<class TYPE, class SIZETYPE>
1175 {
1176 if (dstindex < entriesNbr)
1177 {
1178 // Note: the data can't belong to the collection itself
1179 // SetEntrySize(index, size); might do reallocation and in such case data will become invalid
1180 XASSERT(((void *)entrydata < (void *)data) || ((void *)entrydata > (void *)(data+dataSize)));
1181 TYPE *newElement = SetEntrySize(dstindex, entrysize);
1182 CopyEntry(newElement, entrydata, entrysize);
1183
1184 return newElement;
1185 }
1186
1187 XASSERT(0);
1188 return NULL;
1189 }
1190
1191 template<class TYPE, class SIZETYPE>
1192 inline TYPE *CSimpleCollection<TYPE, SIZETYPE>::SetEntry(unsigned int dstindex, unsigned int srcindex)
1193 {
1194 if (dstindex < entriesNbr && srcindex < entriesNbr)
1195 {
1196 int size;
1197 GetEntry(srcindex, size);
1198
1199 TYPE *newElement = SetEntrySize(dstindex, size);
1200
1201 // Get elementData pointer now (the elementData pointer might changed if SetEntrySize grows the array)
1202 TYPE *elementData = GetEntry(srcindex, size);
1203 CopyEntry(newElement, elementData, size);
1204
1205 return elementData;
1206 }
1207
1208 XASSERT(0);
1209 return NULL;
1210 }
1211
1212 template<class TYPE, class SIZETYPE>
1214 {
1215 if (index < entriesNbr)
1216 {
1217 SIZET offset = offsetArray[index];
1218 type.Init(this, index, COL_HEADER_PTR(data, offset)->size, COL_TYPE_PTR(data, offset));
1219 return;
1220 }
1221
1222 type.Init(this, index, 0, NULL);
1223 XASSERT(0);
1224 }
1225
1226 template<class TYPE, class SIZETYPE>
1227 inline void CSimpleCollection<TYPE, SIZETYPE>::GetEntry(unsigned int index, const CCollectionElement<TYPE, SIZETYPE>& type) const
1228 {
1229 if (index < entriesNbr)
1230 {
1231 SIZET offset = offsetArray[index];
1232 const_cast<CCollectionElement<TYPE, SIZETYPE>&>(type).Init(const_cast<CSimpleCollection<TYPE, SIZETYPE> *>(this), index, COL_HEADER_PTR(data, offset)->size, COL_TYPE_PTR(data, offset));
1233
1234 return;
1235 }
1236
1237 XASSERT(0);
1238 }
1239
1240 template<class TYPE, class SIZETYPE>
1241 inline TYPE *CSimpleCollection<TYPE, SIZETYPE>::GetEntry(unsigned int index, int& size) const
1242 {
1243 if (index < entriesNbr)
1244 {
1245 SIZET offset = offsetArray[index];
1246 size = COL_HEADER_PTR(data, offset)->size;
1247 if (!size)
1248 return NULL;
1249
1250 return COL_TYPE_PTR(data, offset);
1251 }
1252
1253 XASSERT(0);
1254 size = 0;
1255 return NULL;
1256 }
1257
1258 template<class TYPE, class SIZETYPE>
1259 TYPE *CSimpleCollection<TYPE, SIZETYPE>::InitElementsSize(unsigned int index, unsigned int size, unsigned int creationMode)
1260 {
1261 XASSERT(size <= 0xFFFF);
1262 if (index < entriesNbr)
1263 {
1264 SIZET offset = offsetArray[index];
1265
1266 CElementHeader *header = COL_HEADER_PTR(data, offset);
1267 unsigned int cursize = header->size;
1268
1269 if (size == cursize)
1270 return COL_TYPE_PTR(data, offset);
1271 else if (size < cursize)
1272 {
1273 // Destroy the not needed elements
1274 header->size = (SIZETYPE)size;
1275
1276 TYPE *element = COL_TYPE_PTR(data, offset); // first element
1277 element += size; // first element to destroy
1278 DestroyElement(element, cursize-size);
1279
1280 return COL_TYPE_PTR(data, offset);
1281 }
1282 else if (size <= header->maxsize) // header->size < size <= maxsize
1283 {
1284 // if !createElements, nothing to do...
1285 if ((creationMode & COL_CREATE_ELEMENTS))
1286 {
1287 // Create the new elements
1288 header->size = (SIZETYPE)size;
1289
1290 TYPE *element = COL_TYPE_PTR(data, offset); // first element
1291 element += cursize; // first element to create
1292 CreateElement(element, size-cursize);
1293 }
1294
1295 return COL_TYPE_PTR(data, offset);
1296 }
1297
1298 // size > header->maxsize
1299
1300 // 12/19
1301 // Last entry case : extend the entry. Last entry index than the last index (if this index has been growed previously below)
1302 // This allows to perform PreAllocate / AddEntry / AddElementInEntry sequence and enter element one by one, without knowing the size of each element (cf. WFPolygon)
1303 if (offset + COL_DATA_SIZE(header->maxsize) == dataOffset)
1304 {
1305 Grow(offset + COL_DATA_SIZE(size)); // The entry will have size element including from it's current offset
1306
1307 header = COL_HEADER_PTR(data, offset); // data might changed
1308 header->size = (SIZETYPE)((creationMode & COL_CREATE_ELEMENTS) ? size : cursize);
1309 header->maxsize = (SIZETYPE)size;
1310
1311 // And creates new ones
1312 if ((creationMode & COL_CREATE_ELEMENTS))
1313 {
1314 TYPE* element = COL_TYPE_PTR(data, offset); // first element
1315 element += cursize; // first element to create
1316 CreateElement(element, size - cursize);
1317 }
1318
1319 dataOffset = offset + COL_DATA_SIZE(size);
1320
1321 return COL_TYPE_PTR(data, offset);
1322 }
1323
1324 // Compress if requires then grow if needed
1325 if ((creationMode & COL_COMPRESS) && ((dataOffset+COL_DATA_SIZE(size)) > dataSize))
1326 Compress();
1327
1328 // other entry case : we copy the previous information at the end of memory
1329 Grow(dataOffset+COL_DATA_SIZE(size));
1330
1331 offsetArray.SetAt(index, dataOffset);
1332 header = COL_HEADER_PTR(data, dataOffset);
1333 header->size = (SIZETYPE)((creationMode & COL_CREATE_ELEMENTS) ? size : cursize);
1334 header->maxsize = (SIZETYPE)size;
1335
1336 // copy old elements...
1337 dataOffset += sizeof(CElementHeader);
1338 xmemcpy_s(data+dataOffset, dataSize-dataOffset, COL_TYPE_PTR(data, offset), cursize*sizeof(TYPE));
1339 dataOffset += cursize*sizeof(TYPE);
1340
1341 // And creates new ones
1342 if ((creationMode & COL_CREATE_ELEMENTS))
1343 CreateElement((TYPE *)(data+dataOffset), size-cursize);
1344
1345 #ifdef COLLECTION_STATS
1346 readjustedEntries += size-cursize;
1348 #endif
1349
1350 dataOffset += (size-cursize)*sizeof(TYPE);
1351
1352 return COL_TYPE_PTR(data, offsetArray[index]);
1353 }
1354
1355 XASSERT(0);
1356 return NULL;
1357 }
1358
1359 template<class TYPE, class SIZETYPE>
1360 inline TYPE *CSimpleCollection<TYPE, SIZETYPE>::SetEntrySize(unsigned int index, unsigned int size, bool createElements)
1361 {
1362 return InitElementsSize(index, size, createElements ? COL_CREATE_ELEMENTS : 0);
1363 }
1364
1365 template<class TYPE, class SIZETYPE>
1366 inline TYPE *CSimpleCollection<TYPE, SIZETYPE>::SetEntrySizeCompressed(unsigned int index, unsigned int size, bool createElements)
1367 {
1368 return InitElementsSize(index, size, createElements ? COL_CREATE_ELEMENTS|COL_COMPRESS : COL_COMPRESS);
1369 }
1370
1371 template<class TYPE, class SIZETYPE>
1373 {
1374 unsigned int entryIndex = AddEntry(true, element.GetSize());
1375 SetEntry(entryIndex, element);
1376 return entryIndex;
1377 }
1378
1379 // Add an entry to the collection and returns its index
1380 template<class TYPE, class SIZETYPE>
1382 {
1383 if (elementsNbr == -1)
1384 elementsNbr = defaultElementsNbr;
1385
1386 // The new element has been preallocated...
1387 if (entriesNbr < (unsigned int)offsetArray.GetSize())
1388 {
1389 entriesNbr++;
1390 InitElementsSize(entriesNbr-1, elementsNbr, createElements ? COL_CREATE_ELEMENTS : 0);
1391 }
1392 else
1393 {
1394 Grow(dataOffset+COL_DATA_SIZE(elementsNbr));
1395 offsetArray.SetAtGrow(entriesNbr++, dataOffset);
1396
1397 CElementHeader *header = COL_HEADER_PTR(data, dataOffset);
1399 header->maxsize = (SIZETYPE)elementsNbr;
1400
1401 dataOffset += sizeof(CElementHeader);
1402
1403 if (createElements)
1404 CreateElement((TYPE *)(data+dataOffset), elementsNbr);
1405
1406 dataOffset += elementsNbr*sizeof(TYPE);
1407 }
1408
1409 return entriesNbr-1;
1410 }
1411
1412 template<class TYPE, class SIZETYPE>
1414 {
1415 if (index < entriesNbr)
1416 {
1417 SIZET offset = offsetArray[index];
1418 CElementHeader *header = COL_HEADER_PTR(data, offset);
1419 if (header->size < header->maxsize)
1420 {
1421 TYPE *element = COL_TYPE_PTR(data, offset); // first element
1422 element += header->size++; // Get element, create it, and copy it
1423 CreateElement(element, 1);
1425
1426 return header->size;
1427 }
1428
1429 // We have header->size = header->maxsize;
1430
1433
1434 unsigned int newElementOffset = header->size;
1435 TYPE *element = InitElementsSize(index, newElementOffset+newCreatedElementNumber, createExtraElements ? COL_CREATE_ELEMENTS : 0); // Header becomes invalid
1437
1438 if (!createExtraElements) // Create at least the element to add now, if not created above
1439 {
1440 CreateElement(element, 1);
1441
1442 SIZET indexOffset = offsetArray[index];
1443 header = COL_HEADER_PTR(data, indexOffset);
1444 XASSERT(header->size == newElementOffset); // The elements where not create and the size remains the same
1445 header->size++;
1446 }
1447
1449 return newElementOffset;
1450 }
1451
1452 XASSERT(0);
1453 return 0;
1454 }
1455
1456 template<class TYPE, class SIZETYPE>
1457 unsigned int CSimpleCollection<TYPE, SIZETYPE>::RemoveElementInEntry(unsigned int index, unsigned elementIndex)
1458 {
1459 if (index < entriesNbr)
1460 {
1461 SIZET offset = offsetArray[index];
1462 CElementHeader *header = COL_HEADER_PTR(data, offset);
1464 {
1465 TYPE *element = COL_TYPE_PTR(data, offset); // first element
1467 DestroyElement(element, 1);
1468
1469 // Move the others elements
1470 if (elementIndex+1 < header->size)
1471 xmemcpy_s(element, (header->size-elementIndex)*sizeof(TYPE), element+1, (header->size-(elementIndex+1))*sizeof(TYPE));
1472
1473 header->size--;
1474 return header->size;
1475 }
1476
1477 XASSERT(0);
1478 return 0;
1479 }
1480
1481 XASSERT(0);
1482 return 0;
1483 }
1484
1485 /////////////////////////////////////////////////////
1486 // CObjectCollection
1487 //
1488 // This class handles an array of entries
1489 // each entries contains a given number of object elements
1490 // object constructor and destructors are called
1491 // All is stored in a raw array
1492 //
1493
1494 template<class TYPE, class SIZETYPE>
1495 class CObjectCollection : public CSimpleCollection<TYPE, SIZETYPE>
1496 {
1497 private:
1498
1499 virtual void DestroyElement(TYPE *element, unsigned int number);
1500 virtual void CreateElement(TYPE *element, unsigned int number);
1501
1502 virtual void DestroyEntries(unsigned int first, unsigned int number);
1503 virtual void CreateEntries(unsigned int first, unsigned int number);
1504
1505 virtual void CopyEntry(TYPE *dst, const TYPE *src, int elementNbr);
1506 virtual void CopyEntries(const CSimpleCollection<TYPE, SIZETYPE>& collection, unsigned int dstindex = 0);
1507
1508 public:
1509 void Serialize(CXArchive& archive);
1510 virtual ~CObjectCollection();
1511 };
1512
1513
1514 template<class TYPE, class SIZETYPE>
1516 {
1517 CSimpleCollection<TYPE, SIZETYPE>::Free(); // Virtual function DestroyEntries not called by CSimpleCollection destructor
1518 }
1519
1520 template<class TYPE, class SIZETYPE>
1522 {
1523 XASSERT(0);
1524 }
1525
1526 // Destroy a particular element
1527 template<class TYPE, class SIZETYPE>
1529 {
1530 #ifdef COLLECTION_STATS
1532 #endif
1533
1534 for (unsigned int i=0; i<number; i++)
1535 {
1536 element->~TYPE();
1537 element++;
1538 }
1539 }
1540
1541 // Destroy collection elements
1542 template<class TYPE, class SIZETYPE>
1543 void CObjectCollection<TYPE, SIZETYPE>::DestroyEntries(unsigned int first, unsigned int number)
1544 {
1545 SIZET offset;
1547
1548 number += first;
1549 for (unsigned int i=first; i<number; i++)
1550 {
1551 offset = this->offsetArray[i];
1552 header = COL_HEADER_PTR(this->data, offset);
1553
1554 DestroyElement(COL_TYPE_PTR(this->data, offset), header->size);
1555 }
1556 }
1557
1558 // Create a particular elements
1559 template<class TYPE, class SIZETYPE>
1561 {
1562 #ifdef COLLECTION_STATS
1564 UpdateStatistics(); // update maxElements / maxEntries
1565 #endif
1566
1567 for (unsigned i=0; i<number; i++)
1568 {
1569 #pragma push_macro("new")
1570 #undef new
1571 xConstruct(TYPE, element);
1572 #pragma pop_macro("new")
1573 element++;
1574 }
1575 }
1576
1577 // Create collection elements
1578 template<class TYPE, class SIZETYPE>
1579 void CObjectCollection<TYPE, SIZETYPE>::CreateEntries(unsigned int first, unsigned int number)
1580 {
1581 SIZET offset;
1583
1584 number += first;
1585 for (unsigned int i=first; i<number; i++)
1586 {
1587 offset = this->offsetArray[i];
1588 header = COL_HEADER_PTR(this->data, offset);
1589
1590 CreateElement(COL_TYPE_PTR(this->data, offset), header->size);
1591 }
1592 }
1593
1594 template<class TYPE, class SIZETYPE>
1596 {
1597 for (int i=0; i<elementNbr; i++)
1598 {
1599 *dst = src[i];
1600 dst++;
1601 }
1602 }
1603
1604 template<class TYPE, class SIZETYPE>
1606 {
1607 XASSERT(dstindex+collection.entriesNbr <= this->entriesNbr); // Elements must have been created and preallocated
1608
1609 unsigned int i, j;
1611 SIZET srcoffset, dstoffset;
1612 TYPE *srctype, *dsttype;
1613
1614 CreateEntries(dstindex, collection.entriesNbr);
1615 for (i = 0; i<collection.entriesNbr; i++)
1616 {
1617 srcoffset = collection.offsetArray[i];
1618 dstoffset = this->offsetArray[dstindex+i];
1619
1620 srcheader = COL_HEADER_PTR(collection.data, srcoffset);
1621 srctype = COL_TYPE_PTR(collection.data, srcoffset);
1622 dsttype = COL_TYPE_PTR(this->data, dstoffset);
1623
1624 for (j=0; j<srcheader->size; j++)
1625 {
1626 *dsttype = *srctype;
1627 srctype++;
1628 dsttype++;
1629 }
1630 }
1631 }
1632
1633END_MOOTOOLS_NAMESPACE
1634
1635#endif // CCOLLECTION_CLASS_H
The class defines an x, y, z 3D point which can use int, float or double.
Definition 3DPoint.h:27
Definition Collection.h:30
Definition Collection.h:1496
Definition Collection.h:247
Definition XArchive.h:17