00001
00004
00005
00006
00007
00008 #ifndef _cel_memory_h_
00009 #define _cel_memory_h_
00010
00011 #include "cel_types.h"
00012 #include "cel_datatraits.h"
00013 #include "cel_exception.h"
00014 #include <new>
00015 #include <cstring>
00016
00017 namespace Celartem
00018 {
00019
00023 template<size_t ALIGN, class Int> Int align(Int sz)
00024 {
00025 return (sz + ((Int)ALIGN - 1)) & ~((Int)ALIGN - 1);
00026 }
00027
00028
00037 class MemoryAllocator
00038 {
00039 public:
00040
00050 virtual CEL_RESTRICT_RETVAL void *allocate(size_t inBlockSize) = 0;
00051
00052
00061 virtual void free(void *inMemoryBlockPtr) = 0;
00062
00063
00070 static MemoryAllocator *getDefault();
00071
00072
00083 static void setDefault(MemoryAllocator *inAllocator);
00084
00085
00089 virtual ~MemoryAllocator() {}
00090 };
00091
00092
00096 template<typename T, CopyPolicy copyPolicy> struct MemoryCopy;
00097
00098
00102 template<typename T> struct MemoryCopy<T, byConstructor>
00103 {
00104
00114 void operator()(
00115 T * CEL_RESTRICT dest, const T * CEL_RESTRICT src, size_t count)
00116 {
00117 for(size_t i = 0; i < count; i++)
00118 *dest++ = *src++;
00119 }
00120 };
00121
00122
00126 template<typename T> struct MemoryCopy<T, byMemcpy>
00127 {
00137 void operator()(
00138 T * CEL_RESTRICT dest, const T * CEL_RESTRICT src, size_t count)
00139 {
00140 std::memcpy(dest, src, sizeof(T) * count);
00141 }
00142 };
00143
00144
00149 template<typename T> struct MemoryCopy<T, noCopy>
00150 {
00160 void operator()(
00161 T * CEL_RESTRICT dest, const T * CEL_RESTRICT src, size_t count)
00162 {
00163
00164 celThrow2(
00165 errNotPermitted,
00166 "The class does not allow duplication of instances.");
00167 }
00168 };
00169
00170
00174 template<typename T, CopyPolicy copyPolicy> struct MemoryMove;
00175
00176
00180 template<typename T> struct MemoryMove<T, byConstructor>
00181 {
00182
00192 void operator()(
00193 T * dest, const T * src, size_t count)
00194 {
00195 if(dest < src)
00196 {
00197 for(size_t i = 0; i < count; i++)
00198 *dest++ = *src++;
00199 }
00200 else
00201 {
00202 dest += count;
00203 src += count;
00204 for(size_t i = 0; i < count; i++)
00205 *(--dest) = *(--src);
00206 }
00207 }
00208 };
00209
00210
00214 template<typename T> struct MemoryMove<T, byMemcpy>
00215 {
00225 void operator()(
00226 T * dest, const T * src, size_t count)
00227 {
00228 std::memmove(dest, src, sizeof(T) * count);
00229 }
00230 };
00231
00232
00237 template<typename T> struct MemoryMove<T, noCopy>
00238 {
00248 void operator()(
00249 T * dest, const T * src, size_t count)
00250 {
00251
00252 celThrow2(
00253 errNotPermitted,
00254 "The class does not allow move of instances.");
00255 }
00256 };
00257
00258
00262 template<typename T> struct MemoryFill
00263 {
00272 void operator()(T *buffer, size_t count, const T& t)
00273 {
00274 for(size_t i = 0; i < count; i++)
00275 *buffer++ = t;
00276 }
00277 };
00278
00279
00283 template<> struct MemoryFill<int8_t>
00284 {
00293 void operator()(int8_t *buffer, size_t count, const int8_t& t)
00294 {
00295 std::memset(buffer, t, count);
00296 }
00297 };
00298
00299
00303 template<> struct MemoryFill<uint8_t>
00304 {
00313 void operator()(uint8_t *buffer, size_t count, const uint8_t& t)
00314 {
00315 std::memset(buffer, t, count);
00316 }
00317 };
00318
00319
00343 template<class T, CopyPolicy copyPolicy = DataTraits<T>::copyPolicy>
00344 class SimpleArray
00345 {
00346 public:
00347 static const size_t AUTO_SIZE = (size_t)0-1;
00348
00349
00372 SimpleArray(
00373 size_t inSize = 0, size_t inReserve = AUTO_SIZE,
00374 MemoryAllocator *inAllocator = NULL,
00375 size_t inAllocationUnit = 0)
00376 :
00377 m_array(NULL), m_size(0), m_realSize(0), m_strictCleanup(false),
00378 m_alloc(inAllocator ? inAllocator : MemoryAllocator::getDefault())
00379 {
00380 setAllocationUnit(inAllocationUnit);
00381 allocate(inSize, inReserve);
00382 }
00383
00384
00392 SimpleArray(const SimpleArray& inSa)
00393 : m_array(NULL), m_size(0), m_realSize(0)
00394 {
00395 duplicate(inSa);
00396 }
00397
00398
00402 ~SimpleArray()
00403 {
00404 free();
00405 }
00406
00407
00431 void init(size_t inSize = 0, size_t inReserve = 0,
00432 MemoryAllocator *inAllocator = NULL,
00433 size_t inAllocationUnit = 0)
00434 {
00435 free();
00436 m_alloc
00437 = inAllocator ? inAllocator : MemoryAllocator::getDefault();
00438 setAllocationUnit(inAllocationUnit);
00439 allocate(inSize, inReserve);
00440 }
00441
00442
00451 SimpleArray& operator=(const SimpleArray& inSa)
00452 {
00453 duplicate(inSa);
00454 return *this;
00455 }
00456
00457
00467 void strictCleanup(bool doIt = true)
00468 {
00469 m_strictCleanup = doIt;
00470 }
00471
00472
00485 void setAllocationUnit(size_t inAllocationUnit)
00486 {
00487 if(inAllocationUnit)
00488 m_allocationUnit = inAllocationUnit;
00489 else
00490 m_allocationUnit = 128;
00491 }
00492
00493
00500 size_t getAllocationUnit()
00501 {
00502 return m_allocationUnit;
00503 }
00504
00505
00511 T *getPtr()
00512 {
00513 if(_CEL_DEBUG_) healthCheck();
00514 return m_array;
00515 }
00516
00517
00523 const T *getPtr() const
00524 {
00525 if(_CEL_DEBUG_) healthCheck();
00526 return m_array;
00527 }
00528
00529
00535 size_t getSize() const {return m_size;}
00536
00537
00543 size_t getReservedSize() const {return m_realSize;}
00544
00545
00551 bool isValid() const
00552 {
00553 return m_array ? true : false;
00554 }
00555
00556
00564 T& operator[](size_t inPos)
00565 {
00566 if(_CEL_DEBUG_) boundCheck(inPos);
00567 return m_array[inPos];
00568 }
00569
00577 const T& operator[](size_t inPos) const
00578 {
00579 if(_CEL_DEBUG_) boundCheck(inPos);
00580 return m_array[inPos];
00581 }
00582
00583
00602 void allocate(size_t inSize, size_t inReserve = AUTO_SIZE)
00603 {
00604 free();
00605 if(inSize == 0 && inReserve == 0)
00606 return;
00607 if(inReserve == AUTO_SIZE)
00608 inReserve = calc_realsize(inSize);
00609 _reserve(inReserve, inSize);
00610 }
00611
00612
00624 void reserve(size_t inSize)
00625 {
00626 _reserve(inSize, m_size);
00627 }
00628
00629
00641 void reallocate(size_t inSize)
00642 {
00643 if(inSize <= m_realSize)
00644 {
00645 _destruct(inSize, m_size);
00646 _construct(m_array, m_size, inSize);
00647 m_size = inSize;
00648 }
00649 else
00650 {
00651 size_t rsize = calc_realsize(inSize);
00652 _reserve(rsize, inSize);
00653 }
00654 }
00655
00656
00666 inline void resize(size_t inSize) {reallocate(inSize);}
00667
00668
00676 void compact()
00677 {
00678 if(m_size == 0)
00679 {
00680 free();
00681 return;
00682 }
00683 _reserve_no_restriction(m_size, m_size);
00684 }
00685
00686
00699 void free()
00700 {
00701 if(m_array)
00702 {
00703 _destruct(0, m_size);
00704 m_alloc->free(m_array);
00705 m_array = NULL;
00706 m_size = m_realSize = 0;
00707 }
00708 }
00709
00710
00715 void clear()
00716 {
00717 free();
00718 }
00719
00720
00729 void remove(size_t inPos, size_t inCount)
00730 {
00731 size_t end = inPos + inCount;
00732 if(inPos > m_size || end > m_size)
00733 celThrow2(errInvalidParam,
00734 "The range to remove is out of the array!");
00735 const size_t elemsToMove = m_size - end;
00736 MemoryMove<T, copyPolicy>()(
00737 m_array + inPos, m_array + end, elemsToMove);
00738 _destruct(m_size - inCount, m_size);
00739 m_size -= inCount;
00740 }
00741
00742
00751 void insert(size_t inPos, size_t inCount)
00752 {
00753 if(inCount == 0)
00754 return;
00755
00756 if(inPos > m_size)
00757 celThrow2(errInvalidParam,
00758 "inPos out of the array!");
00759
00760 const size_t newSize = m_size + inCount;
00761 if(newSize < m_realSize)
00762 {
00763 const size_t elemsToMove = m_size - inPos;
00764 _construct(m_array, m_size, m_size + inCount);
00765 MemoryMove<T, copyPolicy>()(
00766 m_array + inPos + inCount, m_array + inPos, elemsToMove);
00767 _destruct(inPos, inPos + inCount);
00768 _construct(m_array, inPos, inPos + inCount);
00769 m_size += inCount;
00770 return;
00771 }
00772
00773 size_t rsize = calc_realsize(newSize);
00774 T *temp = _malloc(rsize);
00775 if(copyPolicy == byMemcpy)
00776 _construct(temp, inPos, inPos + inCount);
00777 else
00778 _construct(temp, 0, newSize);
00779
00780 MemoryCopy<T, copyPolicy>()(temp, m_array, inPos);
00781 MemoryCopy<T, copyPolicy>()(
00782 temp + inPos + inCount, m_array + inPos, m_size - inPos);
00783
00784 free();
00785 m_array = temp;
00786 m_size = newSize;
00787 m_realSize = rsize;
00788 }
00789
00790
00801 void insert(size_t inPos, size_t inCount, const T* inElements)
00802 {
00803 insert(inPos, inCount);
00804 for(size_t i = 0; i < inCount; i++)
00805 m_array[inPos + i] = inElements[i];
00806 }
00807
00808
00817 void insert(size_t inPos, const SimpleArray& inElements)
00818 {
00819 insert(inPos, inElements.getSize(), &inElements[0]);
00820 }
00821
00822
00830 void duplicate(const SimpleArray& inSa, bool inNeedCompaction = false)
00831 {
00832 free();
00833 m_alloc = inSa.m_alloc;
00834 m_allocationUnit = inSa.m_allocationUnit;
00835 allocate(
00836 inSa.m_size,
00837 inNeedCompaction ? inSa.m_size : inSa.m_realSize);
00838 MemoryCopy<T, copyPolicy>()(m_array, inSa.m_array, inSa.m_size);
00839 }
00840
00841
00849 void duplicate(const T *inBuffer, size_t inSize)
00850 {
00851 free();
00852 allocate(inSize);
00853 MemoryCopy<T, copyPolicy>()(m_array, inBuffer, inSize);
00854 }
00855
00856
00866 void duplicate(
00867 const T *inBuffer, size_t inSize, Endian inEndian)
00868 {
00869 free();
00870 allocate(inSize);
00871 if(inEndian == endianHost)
00872 MemoryCopy<T, copyPolicy>()(m_array, inBuffer, inSize);
00873 else
00874 {
00875 for(size_t i = 0; i < inSize; i++)
00876 m_array[i] = read<T>(&inBuffer[i], inEndian);
00877 }
00878 }
00879
00880
00888 void fill(const T& t)
00889 {
00890 MemoryFill<T>()(m_array, m_size, t);
00891 }
00892
00893
00901 template<typename U> void fill(const U& u)
00902 {
00903 MemoryFill<T>()(m_array, m_size, (const T)u);
00904 }
00905
00906
00913 void zeroClear()
00914 {
00915 std::memset(m_array, 0, sizeof(T) * m_size);
00916 }
00917
00918
00926 void swap(SimpleArray& inSa)
00927 {
00928 T *array = m_array;
00929 size_t size = m_size;
00930 size_t realSize = m_realSize;
00931 size_t resizeUnit = m_allocationUnit;
00932 bool strictCleanup = m_strictCleanup;
00933 MemoryAllocator *allocr = m_alloc;
00934
00935 m_array = inSa.m_array;
00936 m_size = inSa.m_size;
00937 m_realSize = inSa.m_realSize;
00938 m_allocationUnit = inSa.m_allocationUnit;
00939 m_strictCleanup = inSa.m_strictCleanup;
00940 m_alloc = inSa.m_alloc;
00941
00942 inSa.m_array = array;
00943 inSa.m_size = size;
00944 inSa.m_realSize = realSize;
00945 inSa.m_allocationUnit = resizeUnit;
00946 inSa.m_strictCleanup = strictCleanup;
00947 inSa.m_alloc = allocr;
00948 }
00949
00950
00956 inline void push_back(const T& t)
00957 {
00958 size_t size = getSize();
00959 resize(size + 1);
00960 m_array[size] = t;
00961 }
00962
00963
00969 template<typename U> void push_back(const U& t)
00970 {
00971 push_back((const T)t);
00972 }
00973
00974
00980 inline T pop_back()
00981 {
00982 size_t size = getSize() - 1;
00983 T t = m_array[size];
00984 resize(size);
00985 return t;
00986 }
00987
00988
00994 inline void push_front(const T& t)
00995 {
00996 insert(0, 1);
00997 m_array[0] = t;
00998 }
00999
01000
01006 template<typename U> void push_front(const U& t)
01007 {
01008 push_front((const T)t);
01009 }
01010
01011
01018 inline T pop_front()
01019 {
01020 T t = m_array[0];
01021 remove(0, 1);
01022 return t;
01023 }
01024
01025
01032 T *begin()
01033 {
01034 if(_CEL_DEBUG_) healthCheck();
01035 return m_array;
01036 }
01037
01038
01045 T *end()
01046 {
01047 if(_CEL_DEBUG_) healthCheck();
01048 return m_array + m_size;
01049 }
01050
01051
01058 T *last()
01059 {
01060 if(_CEL_DEBUG_) boundCheck(m_size - 1);
01061 return m_array + m_size - 1;
01062 }
01063
01064
01071 const T *begin() const
01072 {
01073 if(_CEL_DEBUG_) healthCheck();
01074 return m_array;
01075 }
01076
01077
01084 const T *end() const
01085 {
01086 if(_CEL_DEBUG_) healthCheck();
01087 return m_array + m_size;
01088 }
01089
01090
01097 const T *last() const
01098 {
01099 if(_CEL_DEBUG_) boundCheck(m_size - 1);
01100 return m_array + m_size - 1;
01101 }
01102
01103
01110 T& front()
01111 {
01112 return *begin();
01113 }
01114
01115
01122 const T& front() const
01123 {
01124 return *begin();
01125 }
01126
01127
01134 T& back()
01135 {
01136 return *last();
01137 }
01138
01139
01146 const T& back() const
01147 {
01148 return *last();
01149 }
01150
01151 private:
01152 T *m_array;
01153 size_t m_size;
01154 size_t m_realSize;
01155 size_t m_allocationUnit;
01156 bool m_strictCleanup;
01157 MemoryAllocator *m_alloc;
01158
01159
01160
01161 inline size_t calc_realsize(size_t inSize)
01162 {
01163 size_t res = inSize < m_allocationUnit ? m_allocationUnit : inSize;
01164 return inSize + res;
01165 }
01166
01167
01168 static void _construct(T* inArray, size_t inStart, size_t inEnd)
01169 {
01170
01171
01172 for(size_t i = inStart; i < inEnd; i++)
01173 new(&inArray[i]) T;
01174 }
01175
01176
01177 void _destruct(size_t inStart, size_t inEnd)
01178 {
01179
01180
01181 for(size_t i = inStart; i < inEnd; i++)
01182 m_array[i].~T();
01183
01184
01185 if(m_strictCleanup && inStart < inEnd)
01186 std::memset(
01187 &m_array[inStart], 0, (inEnd - inStart) * sizeof(T));
01188 }
01189
01190
01191 CEL_RESTRICT_RETVAL T *_malloc(size_t inSize)
01192 {
01193 if(inSize >= 0x80000000)
01194 celThrow2(
01195 errOperationFailed,
01196 "SimpleArray: "
01197 "The size of the memory block exceeds 2GB, "
01198 "we could not deal with the request!");
01199
01200 T *mem = (T *)m_alloc->allocate(sizeof(T) * inSize);
01201 if(!mem)
01202 celThrow2(
01203 errOutOfMemory,
01204 "SimpleArray: Out of memory!");
01205 return mem;
01206 }
01207
01208
01209
01210 void _reserve(size_t inSize, size_t inSizeToInit)
01211 {
01212 if(inSize < m_realSize)
01213 return;
01214
01215 _reserve_no_restriction(inSize, inSizeToInit);
01216 }
01217
01218
01219 void _reserve_no_restriction(size_t inSize, size_t inSizeToInit)
01220 {
01221 T *temp = _malloc(inSize);
01222 if(copyPolicy != byMemcpy)
01223 _construct(temp, 0, inSizeToInit);
01224
01225
01226 if(m_size)
01227 MemoryCopy<T, copyPolicy>()(
01228 temp, m_array, m_size);
01229
01230 free();
01231 m_array = temp;
01232 m_size = inSizeToInit;
01233 m_realSize = inSize;
01234 }
01235
01236
01237
01238
01239 void healthCheck() const
01240 {
01241 }
01242
01243
01244
01245 void boundCheck(size_t inPos) const
01246 {
01247 if(inPos == 0)
01248 return;
01249
01250 if(!m_array)
01251 celThrow2(errInternalError, "SimpleArray: m_array==NULL!");
01252
01253
01254
01255
01256
01257 if(inPos >= m_size)
01258 celThrow2(errInvalidParam,
01259 "SimpleArray: subscript out of range");
01260 }
01261 };
01262
01263 }
01264
01265 #endif // _cel_memory_h_