cel_memory.h

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00004 //
00005 // (C) 2003-2006 Celartem Technology Inc. All rights reserved.
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             // The class does not allow duplication of instances.
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             // The class does not allow duplication of instances.
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; // good enough?
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; // replace my memory allocator
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         // calc_realsize
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             // TODO: With some classes, we can implement more effecient
01171             // implementation such as std::memset.
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             // We wish the intelligent compilers can remove these
01180             // code on POD arrays.
01181             for(size_t i = inStart; i < inEnd; i++)
01182                 m_array[i].~T(); // call destructor explicitly
01183 
01184             // zeroclear trailing garbages for security reasons
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         // _reserve
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             // move the entries to new array
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         // We should implement some health checking code here, which will
01238         // be called by debug version of SimpleArray.
01239         void healthCheck() const
01240         {
01241         }
01242 
01243         //--------------------------------------------------------------------
01244         // This code do validation of the array subscript.
01245         void boundCheck(size_t inPos) const
01246         {
01247             if(inPos == 0)
01248                 return; // special case
01249 
01250             if(!m_array)
01251                 celThrow2(errInternalError, "SimpleArray: m_array==NULL!");
01252 
01253             // some of the code may use &buf[0] to get the pointer to the
01254             // array regardless of the validity of it since such process
01255             // firstly checks the length of buffer. So we should ignore cases
01256             // with inPos = 0.
01257             if(inPos >= m_size)
01258                 celThrow2(errInvalidParam,
01259                     "SimpleArray: subscript out of range");
01260         }
01261     };
01262 
01263 } // namespace Celartem
01264 
01265 #endif // _cel_memory_h_

This document is automatically generated using doxygen 1.5.4 at Fri Jun 27 18:21:54 2008.