fbxdynamicarray.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /****************************************************************************************
  2. Copyright (C) 2015 Autodesk, Inc.
  3. All rights reserved.
  4. Use of this software is subject to the terms of the Autodesk license agreement
  5. provided at the time of installation or download, or which otherwise accompanies
  6. this software in either electronic or hard copy form.
  7. ****************************************************************************************/
  8. //! \file fbxdynamicarray.h
  9. #ifndef _FBXSDK_CORE_BASE_DYNAMICARRAY_H_
  10. #define _FBXSDK_CORE_BASE_DYNAMICARRAY_H_
  11. #include <fbxsdk/fbxsdk_def.h>
  12. #include <fbxsdk/core/base/fbxcontainerallocators.h>
  13. #include <fbxsdk/fbxsdk_nsbegin.h>
  14. /** Template class for dynamic array holding objects.
  15. * \nosubgrouping
  16. * \see FbxStaticArray
  17. */
  18. template <typename Type, typename Allocator=FbxBaseAllocator> class FbxDynamicArray
  19. {
  20. public:
  21. //! Default constructor.
  22. FbxDynamicArray() :
  23. mArray(NULL),
  24. mCapacity(0),
  25. mSize(0),
  26. mAllocator(sizeof(Type))
  27. {
  28. }
  29. /** Constructor.
  30. * \param pInitialSize initial capacity of this array */
  31. FbxDynamicArray(const size_t pInitialSize) :
  32. mArray(NULL),
  33. mCapacity(0),
  34. mSize(0),
  35. mAllocator(sizeof(Type))
  36. {
  37. Reserve(pInitialSize);
  38. }
  39. /** Copy constructor.
  40. * \remarks The copy constructor of \c Type will be
  41. * invoked in order to copy the value of elements to the
  42. * new array.
  43. */
  44. FbxDynamicArray(const FbxDynamicArray& pArray) :
  45. mArray(NULL),
  46. mCapacity(0),
  47. mSize(0),
  48. mAllocator(sizeof(Type))
  49. {
  50. Reserve(pArray.mCapacity);
  51. CopyArray(mArray, pArray.mArray, pArray.mSize);
  52. mSize = pArray.mSize;
  53. }
  54. //! Destructor.
  55. ~FbxDynamicArray()
  56. {
  57. for( size_t i = 0; i < mSize; ++i )
  58. {
  59. mArray[i].~Type();
  60. }
  61. mAllocator.FreeMemory(mArray);
  62. }
  63. //! Gets the current capacity of the array.
  64. size_t Capacity() const
  65. {
  66. return mCapacity;
  67. }
  68. //! Gets the size of the array.
  69. size_t Size() const
  70. {
  71. return mSize;
  72. }
  73. /** Assures that sufficient memory is allocated to hold n objects in the array, and increases the capacity if necessary.
  74. * \param pCount Number of objects to reserve */
  75. void Reserve(const size_t pCount)
  76. {
  77. if( pCount > mCapacity )
  78. {
  79. //We don't use mAllocator.PreAllocate, because we want our array to be continuous in memory.
  80. Type* lNewArray = (Type*)mAllocator.AllocateRecords(pCount);
  81. MoveArray(lNewArray, mArray, mSize);
  82. mAllocator.FreeMemory(mArray);
  83. mArray = lNewArray;
  84. mCapacity = pCount;
  85. }
  86. }
  87. /** Appends n objects at the end of the array.
  88. * \param pItem object to append
  89. * \param pNCopies number of copies to append */
  90. void PushBack(const Type& pItem, const size_t pNCopies = 1)
  91. {
  92. if( mSize + pNCopies > mCapacity )
  93. {
  94. size_t lNewSize = mCapacity + mCapacity / 2; //grow by 50%
  95. if( mSize + pNCopies > lNewSize )
  96. {
  97. lNewSize = mSize + pNCopies;
  98. }
  99. Reserve(lNewSize);
  100. }
  101. FBX_ASSERT(mSize + pNCopies <= mCapacity);
  102. Fill(mArray + mSize, pItem, pNCopies);
  103. mSize += pNCopies;
  104. }
  105. /** Inserts n objects at the specified position.
  106. * \param pIndex position index
  107. * \param pItem object to insert
  108. * \param pNCopies number of copies to append */
  109. void Insert(const size_t pIndex, const Type& pItem, const size_t pNCopies=1)
  110. {
  111. FBX_ASSERT(pIndex >= 0);
  112. FBX_ASSERT(pIndex <= mSize);
  113. Type lValue = pItem; // in case pItem is in array
  114. if( pNCopies == 0 )
  115. {
  116. }
  117. else if( pIndex >= mSize )
  118. {
  119. PushBack(pItem, pNCopies);
  120. }
  121. else if( mSize + pNCopies > mCapacity )
  122. {
  123. size_t lNewSize = mCapacity + mCapacity / 2; //not enough room, grow by 50%
  124. if( mSize + pNCopies > lNewSize )
  125. {
  126. lNewSize = mSize + pNCopies;
  127. }
  128. Type* lNewArray = (Type*)mAllocator.AllocateRecords(lNewSize);
  129. MoveArray(lNewArray, mArray, pIndex); // copy prefix
  130. Fill(lNewArray + pIndex, pItem, pNCopies); // copy values
  131. MoveArray(lNewArray + pIndex + pNCopies, mArray + pIndex, mSize - pIndex); // copy suffix
  132. mAllocator.FreeMemory(mArray);
  133. mArray = lNewArray;
  134. mSize += pNCopies;
  135. mCapacity = lNewSize;
  136. }
  137. else
  138. {
  139. // copy suffix backwards
  140. MoveArrayBackwards(mArray + pIndex + pNCopies, mArray + pIndex, mSize - pIndex);
  141. Fill(mArray + pIndex, pItem, pNCopies); // copy values
  142. mSize += pNCopies;
  143. }
  144. }
  145. /** Removes n objects at the end.
  146. * \param pNElements number of objects to remove */
  147. void PopBack(size_t pNElements=1)
  148. {
  149. FBX_ASSERT(pNElements <= mSize);
  150. for( size_t i = mSize - pNElements; i < mSize; ++i )
  151. {
  152. mArray[i].~Type();
  153. }
  154. mSize -= pNElements;
  155. }
  156. /** Removes n objects at the specified position.
  157. * \param pIndex position index
  158. * \param pNElements number of objects to remove */
  159. void Remove(const size_t pIndex, size_t pNElements=1)
  160. {
  161. FBX_ASSERT(pIndex >= 0);
  162. FBX_ASSERT(pIndex <= mSize);
  163. FBX_ASSERT(pIndex + pNElements <= mSize);
  164. if( pIndex + pNElements >= mSize )
  165. {
  166. PopBack(pNElements);
  167. }
  168. else
  169. {
  170. for( size_t i = pIndex; i < pIndex + pNElements; ++i )
  171. {
  172. mArray[i].~Type();
  173. }
  174. MoveOverlappingArray(&mArray[pIndex], &mArray[pIndex + pNElements], mSize - pIndex - pNElements);
  175. mSize -= pNElements;
  176. }
  177. }
  178. /** Gets nth object in the array.
  179. * \param pIndex position index */
  180. Type& operator[](const size_t pIndex)
  181. {
  182. return mArray[pIndex];
  183. }
  184. /** Gets nth object in the array.
  185. * \param pIndex position index */
  186. const Type& operator[](const size_t pIndex) const
  187. {
  188. return mArray[pIndex];
  189. }
  190. /** Retrieve the first item in the array.
  191. * \return The first item in the array. */
  192. Type& First()
  193. {
  194. return operator[](0);
  195. }
  196. /** Retrieve the first item in the array.
  197. * \return The first item in the array. */
  198. const Type& First() const
  199. {
  200. return operator[](0);
  201. }
  202. /** Retrieve the last item in the array.
  203. * \return The last item in the array. */
  204. Type& Last()
  205. {
  206. return operator[](mSize-1);
  207. }
  208. /** Retrieve the last item in the array.
  209. * \return The last item in the array. */
  210. const Type& Last() const
  211. {
  212. return operator[](mSize-1);
  213. }
  214. /** Find first matching element, from first to last.
  215. * \param pItem The item to try to find in the array.
  216. * \param pStartIndex The index to start searching from.
  217. * \return Index of the first matching item, otherwise returns -1 (equivalent of SIZE_MAX for size_t). */
  218. size_t Find(const Type& pItem, const size_t pStartIndex=0) const
  219. {
  220. for( size_t i = pStartIndex; i < mSize; ++i )
  221. {
  222. if( operator[](i) == pItem ) return i;
  223. }
  224. return -1;
  225. }
  226. /** Assignment operator.
  227. * \remarks The copy constructor of \c Type will be invoked in order to copy the value of elements to the new array. */
  228. FbxDynamicArray& operator=(const FbxDynamicArray& pArray)
  229. {
  230. Reserve(pArray.mCapacity);
  231. CopyArray(mArray, pArray.mArray, pArray.mSize);
  232. mSize = pArray.mSize;
  233. return *this;
  234. }
  235. /*****************************************************************************************************************************
  236. ** WARNING! Anything beyond these lines is for internal use, may not be documented and is subject to change without notice! **
  237. *****************************************************************************************************************************/
  238. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  239. private:
  240. static void CopyArray(Type* pDest, const Type* pSrc, size_t pCount)
  241. {
  242. for( int i = 0; i < int(pCount); i++ )
  243. {
  244. new(&(pDest[i])) Type(pSrc[i]); //in-place new won't allocate memory, so it is safe
  245. }
  246. }
  247. static void MoveArray(Type* pDest, const Type* pSrc, size_t pCount)
  248. {
  249. for( int i = 0; i < int(pCount); i++ )
  250. {
  251. new(&(pDest[i])) Type(pSrc[i]); //in-place new won't allocate memory, so it is safe
  252. }
  253. for( int i = 0; i < int(pCount); i++ )
  254. {
  255. pSrc[i].~Type();
  256. }
  257. }
  258. static void MoveOverlappingArray(Type* pDest, const Type* pSrc, size_t pCount)
  259. {
  260. for( int i = 0; i < int(pCount); i++ )
  261. {
  262. new(&(pDest[i])) Type(pSrc[i]); //in-place new won't allocate memory, so it is safe
  263. pSrc[i].~Type();
  264. }
  265. }
  266. static void MoveArrayBackwards(Type* pDest, const Type* pSrc, size_t pCount)
  267. {
  268. for( int i = 0; i < int(pCount); ++i )
  269. {
  270. new(&(pDest[pCount-1-i])) Type(pSrc[pCount-1-i]); //in-place new won't allocate memory, so it is safe
  271. pSrc[pCount-1-i].~Type();
  272. }
  273. }
  274. static void Fill(Type* pDest, const Type& pItem, size_t pCount)
  275. {
  276. for( int i = 0; i < int(pCount); i++ )
  277. {
  278. new(&(pDest[i])) Type(pItem); //in-place new won't allocate memory, so it is safe
  279. }
  280. }
  281. Type* mArray;
  282. size_t mCapacity;
  283. size_t mSize;
  284. Allocator mAllocator;
  285. #endif /* !DOXYGEN_SHOULD_SKIP_THIS *****************************************************************************************/
  286. };
  287. #include <fbxsdk/fbxsdk_nsend.h>
  288. #endif /* _FBXSDK_CORE_BASE_DYNAMICARRAY_H_ */