fbxsdk/core/base/fbxdynamicarray.h Source File
 
 
 
fbxsdk/core/base/fbxdynamicarray.h
Go to the documentation of this file.
00001 /****************************************************************************************
00002  
00003    Copyright (C) 2013 Autodesk, Inc.
00004    All rights reserved.
00005  
00006    Use of this software is subject to the terms of the Autodesk license agreement
00007    provided at the time of installation or download, or which otherwise accompanies
00008    this software in either electronic or hard copy form.
00009  
00010 ****************************************************************************************/
00011 
00013 #ifndef _FBXSDK_CORE_BASE_DYNAMICARRAY_H_
00014 #define _FBXSDK_CORE_BASE_DYNAMICARRAY_H_
00015 
00016 #include <fbxsdk/fbxsdk_def.h>
00017 
00018 #include <fbxsdk/core/base/fbxcontainerallocators.h>
00019 
00020 #include <fbxsdk/fbxsdk_nsbegin.h>
00021 
00026 template <typename VALUE_TYPE, typename ALLOCATOR = FbxBaseAllocator> class FbxDynamicArray
00027 {
00028 public:
00030     typedef VALUE_TYPE ValueType;
00032     typedef ALLOCATOR AllocatorType;
00033 
00035     FbxDynamicArray()
00036         : mArray(NULL)
00037         , mArrayCapacity(0)
00038         , mValueCount(0)
00039         , mAllocator(sizeof(ValueType))
00040     {
00041     }
00042 
00046     FbxDynamicArray(const size_t pInitialSize)
00047         : mArray(NULL)
00048         , mArrayCapacity(0)
00049         , mValueCount(0)
00050         , mAllocator(sizeof(ValueType))
00051     {
00052         Reserve(pInitialSize);
00053     }
00054 
00060     FbxDynamicArray(const FbxDynamicArray& pArray)
00061         : mArray(NULL)
00062         , mArrayCapacity(0)
00063         , mValueCount(0)
00064         , mAllocator(sizeof(ValueType))
00065     {
00066         Reserve(pArray.mArrayCapacity);
00067         CopyArray(mArray, pArray.mArray, pArray.mValueCount);
00068         mValueCount = pArray.mValueCount;
00069     }
00070 
00072     ~FbxDynamicArray()
00073     {        
00074         for (size_t i = 0; i < mValueCount; i++)
00075         {
00076             mArray[i].~VALUE_TYPE();
00077         }
00078 
00079         mAllocator.FreeMemory(mArray);
00080     }
00081 
00083     size_t GetCapacity() const
00084     {
00085         return mArrayCapacity;
00086     }
00087 
00089     size_t GetSize() const
00090     {
00091         return mValueCount;
00092     }
00093 
00098     void Reserve(const size_t pCount)
00099     {
00100         if (pCount > mArrayCapacity)
00101         {
00102             // We don't use mAllocator.PreAllocate, because we want our array
00103             // to be continuous in memory.
00104             void* lBuffer = mAllocator.AllocateRecords(pCount);
00105             ValueType* lNewArray = reinterpret_cast<ValueType*>(lBuffer);
00106 
00107             MoveArray(lNewArray, mArray, mValueCount);
00108 
00109             mAllocator.FreeMemory(mArray);
00110             mArray = lNewArray;
00111             mArrayCapacity = pCount;
00112         }
00113     }
00114 
00119     void PushBack(const ValueType& pValue, const size_t pNCopies = 1)
00120     {
00121         if (mValueCount + pNCopies > mArrayCapacity)
00122         {
00123             // grow by 50%
00124             size_t lNewSize = mArrayCapacity + mArrayCapacity / 2;
00125 
00126             if (mValueCount + pNCopies > lNewSize)
00127             {
00128                 lNewSize = mValueCount + pNCopies;
00129             }
00130 
00131             Reserve(lNewSize);
00132         }
00133 
00134         FBX_ASSERT(mValueCount + pNCopies <= mArrayCapacity);
00135 
00136         Fill(mArray + mValueCount, pValue, pNCopies);
00137 
00138         mValueCount += pNCopies;
00139     }
00140 
00146     void Insert(const size_t pIndex, const ValueType& pValue, const size_t pNCopies = 1)
00147     {
00148         FBX_ASSERT(pIndex >= 0);
00149         FBX_ASSERT(pIndex <= mValueCount);
00150 
00151         ValueType lValue = pValue; // in case pValue is in array
00152 
00153         if (pNCopies == 0)
00154         {
00155         }
00156         else if (pIndex >= mValueCount)
00157         {
00158             PushBack(pValue, pNCopies);
00159         }
00160         else if (mValueCount + pNCopies > mArrayCapacity)
00161         {
00162             // not enough room
00163             // grow by 50%
00164             size_t lNewSize = mArrayCapacity + mArrayCapacity / 2;
00165 
00166             if (mValueCount + pNCopies > lNewSize)
00167             {
00168                 lNewSize = mValueCount + pNCopies;
00169             }
00170 
00171             void* lBuffer = mAllocator.AllocateRecords(lNewSize);
00172             ValueType* lNewArray = reinterpret_cast<ValueType*>(lBuffer);
00173 
00174             MoveArray(lNewArray, mArray, pIndex); // copy prefix
00175             Fill(lNewArray + pIndex, pValue, pNCopies); // copy values
00176             MoveArray(lNewArray + pIndex + pNCopies, mArray + pIndex, mValueCount - pIndex); // copy suffix
00177 
00178             mAllocator.FreeMemory(mArray);
00179             mArray = lNewArray;
00180             mValueCount += pNCopies;
00181             mArrayCapacity = lNewSize;
00182         }
00183         else
00184         {
00185             // copy suffix backwards
00186             MoveArrayBackwards(mArray + pIndex + pNCopies, mArray + pIndex, mValueCount - pIndex);
00187             Fill(mArray + pIndex, pValue, pNCopies); // copy values
00188             mValueCount += pNCopies;
00189         }
00190     }
00191 
00195     void PopBack(size_t pNElements = 1)
00196     {
00197         FBX_ASSERT(pNElements <= mValueCount);
00198          
00199         for (size_t i = mValueCount - pNElements; i < mValueCount; i++)
00200         {
00201             mArray[i].~VALUE_TYPE();
00202         }
00203 
00204         mValueCount -= pNElements;
00205     }
00206 
00211     void Remove(const size_t pIndex, size_t pNElements = 1)
00212     {
00213         FBX_ASSERT(pIndex >= 0);
00214         FBX_ASSERT(pIndex <= mValueCount);
00215         FBX_ASSERT(pIndex + pNElements <= mValueCount);
00216 
00217         if (pIndex + pNElements >= mValueCount)
00218         {
00219             PopBack(pNElements);
00220         }
00221         else
00222         {            
00223             for (size_t i = pIndex; i < pIndex + pNElements; i++)
00224             {
00225                 mArray[i].~VALUE_TYPE();
00226             }
00227 
00228             MoveOverlappingArray(mArray + pIndex, mArray + pIndex + pNElements, mValueCount - pNElements);
00229 
00230             mValueCount -= pNElements;
00231         }
00232     }
00233 
00237     ValueType& operator[](const size_t pIndex)
00238     {
00239         return *(mArray + pIndex);
00240     }
00241 
00245     ValueType const& operator[](const size_t pIndex) const
00246     {
00247         return *(mArray + pIndex);
00248     }
00249 
00255     FbxDynamicArray& operator=(const FbxDynamicArray& pArray)
00256     {
00257         Reserve(pArray.mArrayCapacity);
00258         CopyArray(mArray, pArray.mArray, pArray.mValueCount);
00259         mValueCount = pArray.mValueCount;
00260 
00261         return *this;
00262     }
00263 
00264 /*****************************************************************************************************************************
00265 ** WARNING! Anything beyond these lines is for internal use, may not be documented and is subject to change without notice! **
00266 *****************************************************************************************************************************/
00267 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00268 private:
00269     static void CopyArray(ValueType* pDest, const ValueType* pSrc, size_t pCount)
00270     {
00271         for( int i = 0; i < int(pCount); i++ )
00272         {
00273                         new(&(pDest[i])) ValueType(pSrc[i]);    //in-place new won't allocate memory, so it is safe
00274         }
00275     }
00276 
00277     static void MoveArray(ValueType* pDest, const ValueType* pSrc, size_t pCount)
00278     {
00279         for( int i = 0; i < int(pCount); i++ )
00280         {
00281                         new(&(pDest[i])) ValueType(pSrc[i]);    //in-place new won't allocate memory, so it is safe
00282         }
00283 
00284         for( int i = 0; i < int(pCount); i++ )
00285         {
00286             pSrc[i].~VALUE_TYPE();
00287         }
00288     }
00289 
00290     static void MoveOverlappingArray(ValueType* pDest, const ValueType* pSrc, size_t pCount)
00291     {
00292                 for( int i = 0; i < int(pCount); i++ )
00293                 {
00294                         new(&(pDest[i])) ValueType(pSrc[i]);    //in-place new won't allocate memory, so it is safe
00295                         pSrc[i].~VALUE_TYPE();
00296                 }
00297     }
00298 
00299     static void MoveArrayBackwards(ValueType* pDest, const ValueType* pSrc, size_t pCount)
00300     {
00301                 for( int i = 0; i < int(pCount); ++i )
00302                 {
00303                         new(&(pDest[pCount-1-i])) ValueType(pSrc[pCount-1-i]);  //in-place new won't allocate memory, so it is safe
00304                         pSrc[pCount-1-i].~VALUE_TYPE();
00305                 }
00306     }
00307 
00308     static void Fill(ValueType* pDest, const ValueType& pValue, size_t pCount)
00309     {
00310                 for( int i = 0; i < int(pCount); i++ )
00311                 {
00312                         new(&(pDest[i])) ValueType(pValue);     //in-place new won't allocate memory, so it is safe
00313                 }
00314     }
00315 
00316     ValueType*          mArray;
00317     size_t                      mArrayCapacity;
00318     size_t                      mValueCount;
00319     AllocatorType       mAllocator;
00320 #endif /* !DOXYGEN_SHOULD_SKIP_THIS *****************************************************************************************/
00321 };
00322 
00323 #include <fbxsdk/fbxsdk_nsend.h>
00324 
00325 #endif /* _FBXSDK_CORE_BASE_DYNAMICARRAY_H_ */