Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

CascadeNewArray.h

Go to the documentation of this file.
00001 //
00002 // CascadeNewArray.h - header file for class CascadeNewArray
00003 //
00004 // Copyright (c) 2002, Roku, LLC.  All rights reserved.
00005 //
00008 
00009 #ifndef _ROKU_INCLUDE_CASCADE_UTIL_CASCADENEWARRAY_H
00010 #define _ROKU_INCLUDE_CASCADE_UTIL_CASCADENEWARRAY_H
00011 
00012 #include <cascade/CascadeObject.h>
00013 
00026 // template class CascadeNewArray<TYPE>
00027 //
00028 // good general purpose true array for fast random access of elements
00029 // (for sorting/searching).
00030 // provides automatic expansion of array elements -
00031 // it's expensive when expansion happens - new array memory allocation,
00032 // old element memcpy with each new array element getting its constructor
00033 // invoked.  Inserting or removing elements in the middle of the array
00034 // is also costly as it involves a shift of memory.  Use a CascadeListArray for
00035 // an array with good insert/remove performance.
00036 #undef CASSERT  /* temporary */
00037 #define CASSERT(x) do {} while (false) /* temporary */
00038 
00039 #if defined(new)
00040 #error "new cannot be #defined when including this file"
00041 #endif
00042 
00044 // class CascadeNewArray placement new helper implementation
00045 namespace CascadePrivate { class ArrayPlacementHelper { }; }
00046 inline void * operator new(MemoryWord nSize, void * pMem, CascadePrivate::ArrayPlacementHelper *)
00047 {
00048     return pMem;
00049 }
00050 
00052 // class CascadeNewArray quicksort helper
00053 namespace CascadePrivate { void CascadeNewArray_QuickSortHelper(void * base, u32 num, int width, void * pFunc); }
00054 
00056 // class CascadeNewArray
00057 template <class TYPE>
00058 class CascadeNewArray : public CascadeObject
00059 {
00060 public:
00061     CascadeNewArray(u32 nInitialMemSize = kDefaultInitialMemSize);
00062     CascadeNewArray(const CascadeNewArray & that);
00063     virtual ~CascadeNewArray();
00064 public:
00065     CascadeNewArray & operator = (const CascadeNewArray & that);
00066 public:
00067     void   SetAt(u32 nIndex, const TYPE & data);
00068     TYPE & GetAt(u32 nIndex) const;
00069     TYPE & operator[](u32 nIndex) const;
00070     void InsertAt(u32 nIndex, const TYPE & data);
00071     void RemoveAt(u32 nIndex);
00072     void Append(const TYPE & pData);
00073     u32  GetSize() const;
00074     void SetSize(u32 nSize);
00075     bool IsEmpty() const;
00076 
00077     typedef int (CompareFunction)(const TYPE * pElement1, const TYPE * pElement2);
00078         // CompareFunctions are used for QuickSort.  See QuickSort.
00079 
00080     void QuickSort(CompareFunction * pCompareFunction);
00081         // QuickSort performs a quicksort on the array, given a compare function
00082         // WARNING: QuickSort will only work if it can memmove the elements of the
00083         // array around without regard to their type (i.e. it uses memmove on the sizeof an
00084         // element, not a copy constructor or = operator).  As a result, QuickSort is good for sorting
00085         // arrays of pointers, not so good at sorting structures or classes unless they
00086         // can be memmoved.
00087 
00088 protected:
00089     enum { kDefaultInitialMemSize = 8 };
00090 
00091 protected:
00092     TYPE * m_pData;
00093     u32 m_nSize;
00094     u32 m_nMemSize;
00095 
00096 protected:
00097     inline static void PlacementNewConstruct(TYPE * pObjects, u32 nNumObjects)
00098     {
00099         u8 * pBytes = (u8 *)pObjects;
00100             u32 nBytes = nNumObjects * sizeof(TYPE);
00101         while (nBytes--) *pBytes++ = 0;
00102             for (; nNumObjects--; pObjects++) ::new((void *)pObjects, (CascadePrivate::ArrayPlacementHelper *)NULL) TYPE;
00103     }
00104     inline static void ManualDestruct(TYPE * pObjects, u32 nNumObjects)
00105     {
00106         for (; nNumObjects--; pObjects++) pObjects->~TYPE();
00107     }
00108     inline static void arraymemmove(void * pDest, const void * pSource, u32 nCount)
00109     {
00110         if ((u32)pDest > (u32)pSource)
00111         {
00112             // moving up, start at end of pSource, move to end of pDest
00113             u8 * pDEST = (u8 *)pDest + nCount - 1;
00114             u8 * pSOURCE = (u8 *)pSource + nCount - 1;
00115             for (; nCount--;) *pDEST-- = *pSOURCE--;
00116         }
00117         else
00118         {
00119             // moving down, start at beginning of pSource and pDest
00120             u8 * pDEST = (u8 *)pDest;
00121             u8 * pSOURCE = (u8 *)pSource;
00122             for (; nCount--;) *pDEST++ = *pSOURCE++;
00123         }
00124     }
00125     inline static void arraymemcpy(void * pDest, const void * pSource, u32 nCount)
00126     {
00127         u8 * pDEST = (u8 *)pDest;
00128         u8 * pSOURCE = (u8 *)pSource;
00129         for (; nCount--;) *pDEST++ = *pSOURCE++;
00130     }
00131 };
00132 
00134 // template class CascadeNewArray<TYPE> implementation
00135 template <class TYPE>
00136 CascadeNewArray<TYPE>::CascadeNewArray(u32 nInitialMemSize)
00137 {
00138         m_nSize = m_nMemSize = 0;
00139         m_pData = NULL;
00140     SetSize(nInitialMemSize);
00141     SetSize(0);
00142 }
00143 
00144 template <class TYPE>
00145 CascadeNewArray<TYPE>::CascadeNewArray(const CascadeNewArray<TYPE> & that)
00146 {
00147         m_nSize = m_nMemSize = 0;
00148         m_pData = NULL;
00149         
00150         u32 nThatSize = that.GetSize();
00151         if (0 == nThatSize)
00152         {
00153         SetSize(that.m_nMemSize);
00154         SetSize(0);
00155         }
00156         else
00157         {
00158            SetSize(nThatSize);
00159            for (u32 i = 0; i < nThatSize; i++) m_pData[i] = that.m_pData[i];
00160         }
00161 }
00162 
00163 template <class TYPE>
00164 CascadeNewArray<TYPE>::~CascadeNewArray()
00165 {
00166         if (m_pData)
00167         {
00168         ManualDestruct(m_pData, m_nMemSize);
00169                 delete [] (u8 *)m_pData;
00170         }
00171 }
00172 
00173 template <class TYPE>
00174 CascadeNewArray<TYPE> &
00175 CascadeNewArray<TYPE>::operator = (const CascadeNewArray<TYPE> & that)
00176 {
00177     SetSize(that.m_nSize);
00178     for (u32 i = 0; i < that.m_nSize; i++) m_pData[i] = that.m_pData[i];
00179     return *this;
00180 }
00181 
00182 template <class TYPE>
00183 inline void
00184 CascadeNewArray<TYPE>::SetAt(u32 nIndex, const TYPE & data)
00185 {
00186         CASSERT(nIndex < m_nSize);
00187     m_pData[nIndex] = data;
00188 }
00189 
00190 template <class TYPE>
00191 inline TYPE &
00192 CascadeNewArray<TYPE>::GetAt(u32 nIndex) const
00193 {
00194         CASSERT(nIndex < m_nSize);
00195     return m_pData[nIndex];
00196 }
00197 
00198 template <class TYPE>
00199 void
00200 CascadeNewArray<TYPE>::InsertAt(u32 nIndex, const TYPE & data)
00201 {
00202     if (nIndex >= m_nSize)
00203     {
00204         // inserting after the end of the array, make room
00205         SetSize(nIndex + 1);
00206     }
00207     else
00208     {
00209         // inserting into the middle, make room and shift up
00210         SetSize(m_nSize + 1);
00211                 // destruct the top slot that SetSize constructed since we're gonna memmove into it
00212         ManualDestruct(&m_pData[m_nSize-1], 1);
00213         // memmove everything up one
00214         //memmove(&m_pData[nIndex+1], &m_pData[nIndex], ((m_nSize-1) - nIndex) * sizeof(TYPE));
00215         arraymemmove(&m_pData[nIndex+1], &m_pData[nIndex], ((m_nSize-1) - nIndex) * sizeof(TYPE));
00216                 // re-construct the slot we're inserting into before copying into it
00217         PlacementNewConstruct(&m_pData[nIndex], 1);
00218     }
00219     
00220         CASSERT(nIndex < m_nSize);
00221     m_pData[nIndex] = data;
00222 }
00223 
00224 template <class TYPE>
00225 void
00226 CascadeNewArray<TYPE>::RemoveAt(u32 nIndex)
00227 {       
00228         CASSERT(nIndex < m_nSize);
00229 
00230     // destruct what we're removing
00231     ManualDestruct(&m_pData[nIndex], 1);
00232 
00233     // shift elements down if required
00234         //if (nIndex < (m_nSize - 1)) memmove(&m_pData[nIndex], &m_pData[nIndex + 1], (m_nSize - (nIndex + 1)) * sizeof(TYPE));
00235         if (nIndex < (m_nSize - 1)) arraymemmove(&m_pData[nIndex], &m_pData[nIndex + 1], (m_nSize - (nIndex + 1)) * sizeof(TYPE));
00236         // re-construct the slot we just exposed
00237     PlacementNewConstruct(&m_pData[m_nSize - 1], 1);
00238 
00239     // decrement the size of the array
00240     m_nSize--;
00241 }
00242 
00243 template <class TYPE>
00244 inline void
00245 CascadeNewArray<TYPE>::Append(const TYPE & data)
00246 {
00247     InsertAt(m_nSize, data);
00248 }
00249 
00250 template <class TYPE>
00251 inline u32
00252 CascadeNewArray<TYPE>::GetSize() const
00253 {
00254         return m_nSize;
00255 }
00256 
00257 template <class TYPE>
00258 void
00259 CascadeNewArray<TYPE>::SetSize(u32 nSize)
00260 {
00261         if (nSize > m_nMemSize)
00262         {
00263         u32 nNewMemSize;
00264         if (m_nMemSize)
00265         {
00266             u32 nDouble = 2 * m_nMemSize;
00267             nNewMemSize = nDouble * ((nSize / nDouble) + 1);
00268         }
00269         else nNewMemSize = nSize;
00270 
00271         // just alloc the nSize normalized up to the nearest grow size
00272                 u32 nBytesToAlloc = sizeof(TYPE) * nNewMemSize;
00273                 TYPE * pNewData = (TYPE *) new u8[nBytesToAlloc];
00274 
00275         // memcpy the old memory into the new
00276         //if (m_nMemSize) memcpy(pNewData, m_pData, m_nMemSize * sizeof(TYPE));
00277         if (m_nMemSize) arraymemcpy(pNewData, m_pData, m_nMemSize * sizeof(TYPE));
00278 
00279         // construct the new entries (m_nSize to nNewMemSize -1).
00280         PlacementNewConstruct(&pNewData[m_nSize], nNewMemSize - m_nSize);
00281 
00282         // free the old data, and remember the new data
00283                 if (m_pData) delete [] (u8 *)m_pData;
00284                 m_pData = pNewData;
00285                 m_nMemSize = nNewMemSize;
00286         }
00287 
00288     m_nSize = nSize;
00289 }
00290 
00291 template <class TYPE>
00292 inline bool
00293 CascadeNewArray<TYPE>::IsEmpty() const
00294 {
00295         return (m_nSize == 0);
00296 }
00297 
00298 template <class TYPE>
00299 inline TYPE &
00300 CascadeNewArray<TYPE>::operator[](u32 nIndex) const
00301 {
00302         CASSERT(nIndex < m_nSize);
00303     return m_pData[nIndex];
00304 }
00305 
00306 template <class TYPE>
00307 void
00308 CascadeNewArray<TYPE>::QuickSort(CompareFunction * pCompareFunction)
00309 {
00310     CascadePrivate::CascadeNewArray_QuickSortHelper((void *)m_pData, m_nSize, sizeof(TYPE), (void *)pCompareFunction);
00311 }
00312 
00313 #endif // #ifndef _ROKU_INCLUDE_CASCADE_UTIL_CASCADENEWARRAY_H
00314 
00316 //  LOG
00318 //  07-Feb-04   dwoodward       created
00319 //  19-Feb-04   dwoodward       streamlined
00320 //  29-Mar-04   dwoodward   disabled ManualDestruct on VDK
00321 //  14-Apr-04   dwoodward   added copy constructor and = operator
00322 //  01-Dec-04   dsletten    construct exposed slot in RemoveAt()
00323 //  12-May-05   dwoodward   added QuickSort
00324 //  07-Jun-05   dsletten    remove VDK workaround
00325 

Generated on Sun Jul 24 14:27:17 2005 for Cascade Library by  doxygen 1.4.1