Polygon Crucher SDK - Documentation
Documentation
Loading...
Searching...
No Matches
XTemplate.h
Go to the documentation of this file.
1//! @file XTemplate.h
2//! @brief a simple array class for handling data which does not require to be construct / destroy
3//!
4//////////////////////////////////////////////////////////////////////
5
6#if !defined(CXTEMPLATE_INCLUDE_H)
7#define CXTEMPLATE_INCLUDE_H
8
9#ifdef _MSC_VER
10#pragma once
11#endif // _MSC_VER
12
13#include "XObject.h"
14
15BEGIN_MOOTOOLS_NAMESPACE
16
17//////////////////////////////////////////
18// CXArray predefined typedef
19
20template <class TYPE, class ARG_TYPE> class CXArray;
27
28//! @class CXArray
29//! @brief CXArray is an array of simple data information which does not requires to call a constructor / destructor.
30//! @details If you intend to manage array of more complex data, please look at CElementArray.
31//! @param TYPE specified the data type stored in the array.
32template<class TYPE, class ARG_TYPE = const TYPE&>
33class CXArray : public CXObject
34{
35public:
36 //! @enum GrowMode
37 //! GrowMode control the way the array inflate while adding data.
38 typedef enum GrowMode
39 {
40 GROW_DEFAULT = 0, //!< A default grow mode which increase the array size by 1024 bytes each times its needed. using it with SetSize(0) will free the buffer
41 GROW_KEEP_MODE = -1, //!< Keep the default grow size (SetAtGrow, SetSize)
42 GROW_DOUBLE_SIZE = -2, //!< Double size the array for fast element growing (required when the final element number is not known, and is probably big)
43 } GrowMode;
44
45 // Construction
46 CXArray(bool enableMemcpy = true);
48
49 // Attributes
50 int GetSizeOfElement() const; // Size of the stored element
51 int GetSize() const;
52 void SetSize(int newCount, int newGrowCount = GROW_KEEP_MODE); //!< The buffer always grows unless FreeExtra / RemoveAll(false) is called
53 void PreAllocate(int size, int newGrowCount = GROW_KEEP_MODE); //!< Preallocate size elements. GetSize() return 0 after the call.
54
55 // Operations
56 // Clean up
57 void FreeExtra(); //!< Remove extra data allocated when adding data
58 void RemoveAll(bool keepBuffer = false); //!< Remove all data and set size to 0
59
60 // Access to the element data (may return NULL)
61 const TYPE* GetData() const; //!< Get raw array const data access
62 TYPE* GetData(); //!< Get raw array data access for modifying data directly.
63
64 // Potentially growing the array
65 void SetAtGrow(int index, ARG_TYPE newElement, int nGrowBy = GROW_KEEP_MODE);
67 int AddArray(const CXArray<TYPE, ARG_TYPE>& src); //!< Add an array to another array. There might be duplicated items.
68 void Copy(const CXArray<TYPE, ARG_TYPE>& src);
69 void Copy(const CXArray<TYPE, ARG_TYPE> *src);
70
71 const TYPE& operator[](int index) const;
72 TYPE& operator[](int index);
73
74 void InsertAt(int index, ARG_TYPE newElement, int insertCount = 1);
75 void RemoveAt(int index, int removedCount = 1);
76 bool Remove(ARG_TYPE newElement, bool firstonly = true); //!< Remove newElement and return true if found. If firstonly = true, the return return once the first newElement has been removed
77
78protected:
79 // Note this is safer to use int instead of unsigned int, even if index if always >=0
80 // One good reason is the for loop case, in case of unsigned int:
81 // unsigned int size = array.GetLength()
82 // for (i=size-1; i>=0; i--) // Loop never end
83 TYPE *buffer; // the array of data
84 int elementCount; // number of elements
85 int maxElementCount; // max allocated elements
86 int growElementCount; // number of element to grow the array
87 bool enableMemcpy; // The data can be copied with a simple memcpy, the operator = should always been called. This is mainly for using ie std::simple_string which requires deep copy, as object contains pointer to themself in debug mode.
88
89private:
90 const CXArray<TYPE, ARG_TYPE>& operator=(const CXArray<TYPE, ARG_TYPE>& Rhs) {return *this;}; // Use Copy instead, to avoid unvoluntary copy
91
92public:
93 virtual ~CXArray();
94
95#ifndef MOOTOOLS_NO_ARCHIVE_SUPPORT
96 void Serialize(CXArchive&);
97#endif
98
99#ifdef _DEBUG
100 void Dump() const;
101#endif
102};
103
104/////////////////////////////////////////////////////////////////////////////
105// CXArray<TYPE, ARG_TYPE> inline functions
106template<class TYPE, class ARG_TYPE>
108{
109 return sizeof(TYPE);
110}
111
112template<class TYPE, class ARG_TYPE>
113inline int CXArray<TYPE, ARG_TYPE>::GetSize() const
114{
115 return elementCount;
116}
117
118template<class TYPE, class ARG_TYPE>
120{
121 // keepBuffer = false deallocate the buffer. This is done using GROW_DEFAULT mode.
122 // SetSize changes growElementCount. Restore the previous value after the call in order to keep the way the caller want the array to grow
123 int prevGrowElementCount = growElementCount;
124 SetSize(0, keepBuffer ? GROW_KEEP_MODE : GROW_DEFAULT);
125 growElementCount = prevGrowElementCount;
126}
127
128template<class TYPE, class ARG_TYPE>
130{
131 return (const TYPE*)buffer;
132}
133
134template<class TYPE, class ARG_TYPE>
136{
137 return (TYPE*)buffer;
138}
139
140template<class TYPE, class ARG_TYPE>
142{
143 int index = elementCount;
144 SetAtGrow(index, newElement, nGrowBy);
145 return index;
146}
147
148template<class TYPE, class ARG_TYPE>
149inline const TYPE& CXArray<TYPE, ARG_TYPE>::operator[](int index) const
150{
151 XASSERT(index >= 0 && index < elementCount);
152 if(index >= 0 && index < elementCount)
153 return buffer[index];
154
155 XThrowException(CXInvalidArgException);
156}
157
158template<class TYPE, class ARG_TYPE>
160{
161 XASSERT(index >= 0 && index < elementCount);
162 if(index >= 0 && index < elementCount)
163 return buffer[index];
164
165 XThrowException(CXInvalidArgException);
166}
167
168/////////////////////////////////////////////////////////////////////////////
169// CXArray<TYPE, ARG_TYPE>
170
171template<class TYPE>
172inline void XArrayCopy(TYPE* pDst, const TYPE* pSrc, int elementCount)
173{
174 XENSURE(elementCount == 0 || (pDst != NULL && pSrc != NULL));
175
176 // default is element-copy using assignment
177 while (elementCount--)
178 *pDst++ = *pSrc++;
179}
180
181#ifdef _DEBUG
182template<class TYPE>
183void XArrayDump(const TYPE* pElements, int elementCount)
184{
185 XENSURE(elementCount == 0 || pElements != NULL);
186}
187#endif
188
189/////////////////////////////////////////////////////////////////////////////
190// CXArray<TYPE, ARG_TYPE> out-of-line functions
191
192template<class TYPE, class ARG_TYPE>
194{
195 buffer = NULL;
196 elementCount = maxElementCount = 0;
197 growElementCount = GROW_DEFAULT;
198 this->enableMemcpy = refenableMemcpy;
199}
200
201template<class TYPE, class ARG_TYPE>
203{
204 buffer = NULL;
205 elementCount = maxElementCount = 0;
206 growElementCount = copyFrom.growElementCount;
207 this->enableMemcpy = copyFrom.enableMemcpy;
208 this->Copy(copyFrom);
209}
210
211template<class TYPE, class ARG_TYPE>
213{
214 XASSERT(this);
215
216 if (buffer != NULL)
217 {
218#ifndef MOOTOOLS_FOR_UNREAL
219 try
220 {
221#endif
222 for (int i = 0; i < elementCount; i++ )
223 (buffer + i)->~TYPE();
224
225 xDeallocateArray((unsigned char *)buffer);
226#ifndef MOOTOOLS_FOR_UNREAL
227 }
228 catch(...)
229 {
230 XTRACE(_T("Array: exception in destructor occured.\n"));
231 }
232#endif
233 }
234}
235
236template<class TYPE, class ARG_TYPE>
238{
239 if (size == maxElementCount && elementCount == 0) // Already preallocated with the same size
240 return;
241
242 RemoveAll();
243 SetSize(size, newGrowCount);
244 maxElementCount = size;
245 elementCount = 0;
246}
247
248template<class TYPE, class ARG_TYPE>
250{
251 XASSERT(this);
252 XASSERT(newCount >= 0);
253
254 if(newCount < 0 )
255 XThrowException(CXInvalidArgException);
256
257 if (newGrowCount != GROW_KEEP_MODE)
258 growElementCount = newGrowCount; // set new size
259
260 if (newCount == 0)
261 {
262 // Destroy all
263 if (buffer != NULL)
264 {
265 for (int i = 0; i < elementCount; i++ )
266 (buffer + i)->~TYPE();
267
268 if (newGrowCount == GROW_DEFAULT)
269 {
270 xDeallocateArray((unsigned char *)buffer);
271 buffer = NULL;
272 }
273 }
274
275 elementCount = 0;
276 if (newGrowCount == GROW_DEFAULT)
277 maxElementCount = 0;
278 }
279 else if (buffer == NULL)
280 {
281 // Allocate elements using grow amount if needed
282#ifdef SIZE_T_MAX
283 XASSERT(newCount <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
284#endif
285 int allocCount = __max(newCount, growElementCount);
286 buffer = (TYPE*) xAllocateArray(unsigned char, (size_t)allocCount * sizeof(TYPE));
287 memset((void*)buffer, 0, (size_t)allocCount * sizeof(TYPE));
288
289 for (int i = 0; i < newCount; i++ )
290 xConstruct(TYPE, (void*)(buffer+i));
291
292 elementCount = newCount;
293 maxElementCount = allocCount;
294 }
295 else if (newCount <= maxElementCount)
296 {
297 // it fits
298 if (newCount > elementCount)
299 {
300 // construct new elements
301 memset((void*)(buffer + elementCount), 0, (size_t)(newCount-elementCount) * sizeof(TYPE));
302 for (int i = 0; i < newCount-elementCount; i++ )
303 xConstruct(TYPE, (void*)(buffer+elementCount+i));
304 }
305 else if (elementCount > newCount)
306 {
307 // destroy old elements
308 for (int i = 0; i < elementCount-newCount; i++ )
309 (buffer + newCount + i)->~TYPE();
310 }
311
312 elementCount = newCount;
313 }
314 else
315 {
316 // otherwise, grow array
317 newGrowCount = growElementCount;
318 if (newGrowCount == GROW_DOUBLE_SIZE)
319 newGrowCount = maxElementCount;
320 else if (newGrowCount == GROW_DEFAULT)
321 {
322 newGrowCount = elementCount / 8;
323 newGrowCount = (newGrowCount < 4) ? 4 : ((newGrowCount > 1024) ? 1024 : newGrowCount);
324 }
325 // else newGrowCount > 0
326
327 int newMaxCount;
328 if (newCount < maxElementCount + newGrowCount)
329 newMaxCount = maxElementCount + newGrowCount;
330 else
331 newMaxCount = newCount; // still ok
332
333 XASSERT(newMaxCount >= maxElementCount); // no wrap around
334
335 if(newMaxCount < maxElementCount)
336 XThrowException(CXInvalidArgException);
337
338#ifdef SIZE_T_MAX
339 XASSERT(newMaxCount <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
340#endif
341 TYPE* newBuffer = (TYPE*) xAllocateArray(unsigned char, (size_t)newMaxCount * sizeof(TYPE));
342
343 if (enableMemcpy)
344 {
345 // copy new data from old
346 xmemcpy_s(newBuffer, (size_t)newMaxCount * sizeof(TYPE), buffer, (size_t)elementCount * sizeof(TYPE));
347 }
348 else
349 {
350 // The data need to be construct and assigned using the = operator
351 int i;
352
353 for (i = 0; i < elementCount; i++)
354 xConstruct(TYPE, (void*)(newBuffer + i));
355
356 for (i = 0; i < elementCount; i++)
357 newBuffer[i] = buffer[i];
358
359 for (i = 0; i < elementCount; i++)
360 (buffer + i)->~TYPE();
361 }
362
363 // construct remaining elements
364 XASSERT(newCount > elementCount);
365 memset((void*)(newBuffer + elementCount), 0, (size_t)(newCount-elementCount) * sizeof(TYPE));
366
367 for (int i = 0; i < newCount-elementCount; i++ )
368 xConstruct(TYPE, (void*)(newBuffer+elementCount+i));
369
370 // destroy array (note: no destructors called)
371 xDeallocateArray((unsigned char *)buffer);
372
373 buffer = newBuffer;
374 elementCount = newCount;
375 maxElementCount = newMaxCount;
376 }
377}
378
379template<class TYPE, class ARG_TYPE>
381{
382 if (!src)
383 {
384 RemoveAll();
385 return;
386 }
387
388 this->Copy(*src);
389}
390
391template<class TYPE, class ARG_TYPE>
393{
394 XASSERT(this);
395
396 if (this != &src)
397 {
398 enableMemcpy = src.enableMemcpy;
399
400 SetSize(src.elementCount);
401 XArrayCopy<TYPE>(buffer, src.buffer, src.elementCount);
402 }
403}
404
405template<class TYPE, class ARG_TYPE>
407{
408 XASSERT(this);
409
410 int baseindex = GetSize();
411 int i, srcsize = src.GetSize();
412 SetSize(baseindex + srcsize);
413 for (i = 0; i < srcsize; i++)
414 buffer[baseindex+i] = src[i];
415
416 return baseindex + srcsize;
417}
418
419template<class TYPE, class ARG_TYPE>
421{
422 XASSERT(this);
423
424 if (elementCount != maxElementCount)
425 {
426 // shrink to desired size
427#ifdef SIZE_T_MAX
428 XASSERT(elementCount <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
429#endif
431 if (elementCount != 0)
432 {
433 newBuffer = (TYPE*) xAllocateArray(unsigned char, elementCount * sizeof(TYPE));
434
435 if (enableMemcpy)
436 {
437 // copy new data from old
438 xmemcpy_s(newBuffer, elementCount * sizeof(TYPE), buffer, elementCount * sizeof(TYPE));
439 }
440 else
441 {
442 // The data need to be construct and assigned using the = operator
443 int i;
444
445 for (i = 0; i < elementCount; i++)
446 xConstruct(TYPE, (void*)(newBuffer + i));
447
448 for (i = 0; i < elementCount; i++)
449 newBuffer[i] = buffer[i];
450
451 for (i = 0; i < elementCount; i++)
452 (buffer + i)->~TYPE();
453 }
454
455 // destroy array (note: no destructors called)
456 xDeallocateArray((unsigned char *)buffer);
457 }
458
459 buffer = newBuffer;
460 maxElementCount = elementCount;
461 }
462}
463
464template<class TYPE, class ARG_TYPE>
466{
467 XASSERT(this);
468 XASSERT(index >= 0);
469
470 if(index < 0)
471 XThrowException(CXInvalidArgException);
472
473 if (index >= elementCount)
474 SetSize(index+1, nGrowBy);
475 buffer[index] = newElement;
476}
477
478template<class TYPE, class ARG_TYPE>
480{
481 XASSERT(this);
482 XASSERT(index >= 0); // will expand to meet need
483 XASSERT(insertedCount > 0); // zero or negative size not allowed
484
485 if(index < 0 || insertedCount <= 0)
486 XThrowException(CXInvalidArgException);
487
488 if (index >= elementCount)
489 {
490 // adding after the end of the array
491 SetSize(index + insertedCount); // grow so index is valid
492 }
493 else
494 {
495 // inserting in the middle of the array
496 int prevBufCount = elementCount;
497 SetSize(elementCount + insertedCount); // grow it to new size
498
499 // shift old data up to fill gap
500 if (enableMemcpy)
501 {
502 // destroy the data that have been created in SetSize before copying over it
503 for (int i = 0; i < insertedCount; i++)
504 (buffer + prevBufCount + i)->~TYPE();
505
506 xmemmove_s(buffer + index + insertedCount, (prevBufCount - index) * sizeof(TYPE), buffer + index, (prevBufCount - index) * sizeof(TYPE));
507
508 // No init the new data
509 memset((void*)(buffer + index), 0, (size_t)insertedCount * sizeof(TYPE));
510 for (int i = 0; i < insertedCount; i++)
511 xConstruct(TYPE, (void*)(buffer + index + i));
512 }
513 else
514 {
515 // The data need to be assigned using the = operator
516 int copyCount = (prevBufCount - index);
517 while (copyCount > 0)
518 {
519 buffer[index+insertedCount+copyCount-1] = buffer[index+copyCount-1];
520 copyCount--;
521 }
522 }
523 }
524
525 // insert new value in the gap
526 XASSERT(index + insertedCount <= elementCount);
527 while (insertedCount--)
528 buffer[index++] = newElement;
529}
530
531template<class TYPE, class ARG_TYPE>
533{
534 XASSERT(this);
535 XASSERT(index >= 0);
536 XASSERT(removedCount >= 0);
537 int upperIndex = index + removedCount;
539
540 if (index < 0 || removedCount < 0 || (upperIndex > elementCount) || (upperIndex < index) || (upperIndex < removedCount))
541 XThrowException(CXInvalidArgException);
542
543 // just remove a range
544 int moveCount = elementCount - (upperIndex);
545 for (int i = 0; i < removedCount; i++ )
546 (buffer + index + i)->~TYPE();
547
548 if (moveCount)
549 {
550 if (enableMemcpy)
551 xmemmove_s(buffer + index, (size_t)moveCount * sizeof(TYPE), buffer + upperIndex, (size_t)moveCount * sizeof(TYPE));
552 else
553 {
554 // The data need to be assigned using the = operator
555 int i = 0;
556 while (moveCount-- > 0)
557 {
558 buffer[index+i] = buffer[upperIndex+i];
559 i++;
560 }
561 }
562 }
563
564 elementCount -= removedCount;
565}
566
567template<class TYPE, class ARG_TYPE>
569{
570 bool result = false;
571 int i, size = GetSize();
572 for (i = 0; i < size; i++)
573 {
574 if (buffer[i] == element)
575 {
576 RemoveAt(i);
577 if (firstonly)
578 return true;
579
580 i--; size--;
581 result = true;
582 }
583 }
584
585 return result;
586}
587
588////////////////////////////////////////////////////////////
589// Specialization : CXStringArray serialization
590
591#ifndef MOOTOOLS_NO_ARCHIVE_SUPPORT
592template<> DLL_TOOLSFUNCTION void CXStringArray::Serialize(CXArchive& ar);
593#endif
594
595#ifdef _DEBUG
596template<class TYPE, class ARG_TYPE>
598{
599 CXObject::Dump();
600
601 XTRACE(_T("with %d elements\n"));
602 XArrayDump<TYPE>(buffer, elementCount);
603}
604#endif //_DEBUG
605
606END_MOOTOOLS_NAMESPACE
607
608#endif // !defined(CXTEMPLATE_INCLUDE_H)
The class defines an x, y, z 3D point which can use int, float or double.
Definition 3DPoint.h:27
Definition XArchive.h:17
CXArray is an array of simple data information which does not requires to call a constructor / destru...
Definition XTemplate.h:34
GrowMode
Definition XTemplate.h:39
@ GROW_DEFAULT
A default grow mode which increase the array size by 1024 bytes each times its needed....
Definition XTemplate.h:40
@ GROW_DOUBLE_SIZE
Double size the array for fast element growing (required when the final element number is not known,...
Definition XTemplate.h:42
@ GROW_KEEP_MODE
Keep the default grow size (SetAtGrow, SetSize)
Definition XTemplate.h:41
void PreAllocate(int size, int newGrowCount=GROW_KEEP_MODE)
Preallocate size elements. GetSize() return 0 after the call.
Definition XTemplate.h:237
bool Remove(ARG_TYPE newElement, bool firstonly=true)
Remove newElement and return true if found. If firstonly = true, the return return once the first new...
Definition XTemplate.h:568
void SetSize(int newCount, int newGrowCount=GROW_KEEP_MODE)
The buffer always grows unless FreeExtra / RemoveAll(false) is called.
Definition XTemplate.h:249
const TYPE * GetData() const
Get raw array const data access.
Definition XTemplate.h:129
void RemoveAll(bool keepBuffer=false)
Remove all data and set size to 0.
Definition XTemplate.h:119
TYPE * GetData()
Get raw array data access for modifying data directly.
Definition XTemplate.h:135
int AddArray(const CXArray< TYPE, ARG_TYPE > &src)
Add an array to another array. There might be duplicated items.
Definition XTemplate.h:406
void FreeExtra()
Remove extra data allocated when adding data.
Definition XTemplate.h:420
CXStringArray implement an array of CXString.
Definition XStringArray.h:25