//------------------------------------------------------------------ // // FILE : DynArray.h // // PURPOSE : Caching dynamic arrays used everywhere. // // CREATED : 5/1/96 // // COPYRIGHT : Microsoft 1996 All Rights Reserved // //------------------------------------------------------------------ #ifndef __MODYNARRAY_H__ #define __MODYNARRAY_H__ #include "Memory.h" // Defines.... #define CHECK_ARRAY_BOUNDS #define CACHE_DEFAULT_SIZE 5 // Predefined types of arrays. #define CMoPtrArray CMoArray #define CMoDWordArray CMoArray #define CMoWordArray CMoArray #define CMoByteArray CMoArray #define DYNA_TEMPLATE template // This can be used if you don't want the extra 4 bytes of caching info in the array. class NoCache { public: WORD GetCacheSize() const {return 0;} void SetCacheSize(WORD size) {} WORD GetWantedCache() const {return 0;} void SetWantedCache(WORD size) {} }; class DefaultCache { public: WORD GetCacheSize() const {return m_CacheSize;} void SetCacheSize(WORD val) {m_CacheSize = val;} WORD GetWantedCache() const {return m_WantedCache;} void SetWantedCache(WORD val){m_WantedCache = val;} private: WORD m_CacheSize; WORD m_WantedCache; }; template class CMoArray { public: // Constructors CMoArray(CMoArray ©From, const T &toAdd) { Clear(); Init(); CopyArray(copyFrom); Append(toAdd); } CMoArray() { Clear(); Init(); } CMoArray( WORD cacheSize ) { Clear(); Init(0, cacheSize); } // Destructor ~CMoArray() { Term(); } // Member functions BOOL Init(DWORD size = 0, WORD cacheSize = CACHE_DEFAULT_SIZE); void Term() { SetSize(0); } // Comparison BOOL Compare( const CMoArray &other ); // Assignment // You should use CopyArray whenever possible. CMoArray& operator=(const CMoArray &other); CMoArray operator+(const T &toAdd); BOOL CopyArray( const CMoArray &other ); BOOL AppendArray( const CMoArray &other ); DWORD FindElement( const T &x ); BOOL Append( const T &toAdd ) { return Insert(m_nElements, toAdd); } BOOL Insert( DWORD index, const T &toInsert ); void Remove( DWORD index ); // You can use it like a stack with these... BOOL Push( const T &toAdd ) { return Append(toAdd); } void Pop() { ASSERT(m_nElements>0); Remove( m_nElements-1 ); } // Accessors BOOL IsValid() { return TRUE; } // Helpers for if you want to wrap around... T& Last() const { ASSERT(m_nElements>0); return m_pArray[ m_nElements-1 ]; } DWORD LastI() const { ASSERT(m_nElements>0); return m_nElements-1; } T& Next( DWORD index ) const { return m_pArray[ NextI(index) ]; } T& Prev( DWORD index ) const { return m_pArray[ PrevI(index) ]; } DWORD NextI( DWORD i ) const { #ifdef CHECK_ARRAY_BOUNDS ASSERT( m_nElements > 0 ); #endif if( i < (m_nElements-1) ) return i+1; else return 0; } DWORD PrevI( DWORD i ) const { #ifdef CHECK_ARRAY_BOUNDS ASSERT( m_nElements > 0 ); #endif if( i == 0 ) return m_nElements - 1; else return i-1; } // Number of elements operator unsigned long() const { return (unsigned long)m_nElements; } // Array-like access. T& operator[]( const DWORD index ) const { return Get(index); } // Returns FALSE if there isn't enough memory. BOOL SetSize( DWORD newSize ); BOOL SetSizeInit( DWORD newSize, T &val ); BOOL SetSizeInit2( DWORD newSize, T val ); // Same as SetSize but preserves the old contents (ie: sizing from 8 to 4 preserves // the first 4 and sizing from 4 to 8 preserves the first 4). BOOL NiceSetSize(DWORD newSize) {return InternalNiceSetSize(newSize, FALSE);} BOOL Fast_NiceSetSize(DWORD newSize) {return InternalNiceSetSize(newSize, TRUE);} DWORD GetSize() const { return m_nElements; } // Sets the cache size void SetCacheSize( WORD size ) { m_Cache.SetWantedCache(size); } // Get and set T& Get( DWORD index ) const { #ifdef CHECK_ARRAY_BOUNDS ASSERT( index < m_nElements ); #endif return m_pArray[index]; } void Set( DWORD index, T &data ) { #ifdef CHECK_ARRAY_BOUNDS ASSERT( index < m_nElements ); #endif m_pArray[index] = data; } // Returns a pointer to the internal array.. T* GetArray() { return m_pArray; } // Accessors for MFC compatibility. public: T& GetAt( DWORD index ) const { return Get(index); } void SetAt( DWORD index, T data ) { Set(index, data); } void RemoveAll() { SetSize(0); } BOOL Add( const T &toAdd ) { return Insert(m_nElements, toAdd); } private: void _InitArray( WORD wantedCache ); void _DeleteAndDestroyArray(); T* _AllocateTArray( DWORD nElements ); BOOL InternalNiceSetSize( DWORD newSize, BOOL bFast ); private: void Clear() { m_pArray = 0; m_nElements = 0; m_Cache.SetCacheSize(0); m_Cache.SetWantedCache(0); } // Member variables T *m_pArray; DWORD m_nElements; C m_Cache; }; DYNA_TEMPLATE BOOL CMoArray::Init( DWORD size, WORD cacheSize ) { Term(); _InitArray(cacheSize); return SetSize(size); } DYNA_TEMPLATE BOOL CMoArray::Compare( const CMoArray &other ) { DWORD i; if( m_nElements != other.m_nElements ) return FALSE; for( i=0; i < m_nElements; i++ ) if( m_pArray[i] != other.m_pArray[i] ) return FALSE; return TRUE; } template CMoArray& CMoArray::operator=( const CMoArray &other ) { CopyArray(other); return *this; } DYNA_TEMPLATE CMoArray CMoArray::operator+(const T &toAdd) { return CMoArray(*this, toAdd); } DYNA_TEMPLATE BOOL CMoArray::CopyArray(const CMoArray &other) { DWORD i; if( m_pArray ) _DeleteAndDestroyArray(); m_nElements = other.m_nElements; m_Cache.SetCacheSize(other.m_Cache.GetCacheSize()); m_Cache.SetWantedCache(other.m_Cache.GetWantedCache()); if( m_nElements + m_Cache.GetCacheSize() > 0 ) { m_pArray = _AllocateTArray( m_nElements + m_Cache.GetCacheSize() ); } else { m_nElements = 0; m_Cache.SetCacheSize(0); m_pArray = NULL; return TRUE; } // Could it allocate the array? if( !m_pArray ) { m_nElements = 0; m_Cache.SetCacheSize(0); return FALSE; } for( i=0; i < m_nElements; i++ ) m_pArray[i] = other.m_pArray[i]; return TRUE; } DYNA_TEMPLATE BOOL CMoArray::AppendArray( const CMoArray &other ) { DWORD i; for( i=0; i < other; i++ ) if( !Append(other[i]) ) return FALSE; return TRUE; } DYNA_TEMPLATE DWORD CMoArray::FindElement( const T &x ) { DWORD i, ret = BAD_INDEX; for( i=0; i < m_nElements; i++ ) { if( m_pArray[i] == x ) { ret = i; break; } } return ret; } DYNA_TEMPLATE BOOL CMoArray::Insert( DWORD index, const T &toInsert ) { T *pNewArray; DWORD newSize, i; ASSERT( index <= m_nElements ); if(index > m_nElements) return FALSE; // Create a new array (possibly). newSize = m_nElements + 1; //if( newSize >= (m_nElements+m_CacheSize) || m_nElements == 0 ) if( m_Cache.GetCacheSize() == 0 ) { pNewArray = _AllocateTArray( newSize + m_Cache.GetWantedCache() ); if( !pNewArray ) return FALSE; // Copy the old array into the new one, start inserting at index. for( i=0; i < index; i++ ) pNewArray[i] = m_pArray[i]; for( i=index; i < m_nElements; i++ ) pNewArray[i+1] = m_pArray[i]; // Insert the new item into the array pNewArray[index] = toInsert; // Free the old array and set our pointer to the new one if( m_pArray ) _DeleteAndDestroyArray(); m_Cache.SetCacheSize(m_Cache.GetWantedCache()); m_pArray = pNewArray; } else { for( i=m_nElements; i > index; i-- ) m_pArray[i] = m_pArray[i-1]; m_Cache.SetCacheSize(m_Cache.GetCacheSize() - 1); m_pArray[index] = toInsert; } ++m_nElements; return TRUE; } DYNA_TEMPLATE void CMoArray::Remove( DWORD index ) { DWORD newSize; DWORD i; T *pNewArray; BOOL bSlideDown = FALSE; ASSERT( index < m_nElements && m_pArray ); if( m_Cache.GetCacheSize() >= (m_Cache.GetWantedCache()*2) ) { newSize = m_nElements - 1; pNewArray = _AllocateTArray( newSize + m_Cache.GetWantedCache() ); // Make sure it allocated the array .. if it didn't, just have // it slide all the elements down (this guarantees that Remove() // won't fail.) if( pNewArray ) { for( i=0; i < index; i++ ) pNewArray[i] = m_pArray[i]; for( i=index; i < m_nElements-1; i++ ) pNewArray[i] = m_pArray[i+1]; _DeleteAndDestroyArray(); m_pArray = pNewArray; m_Cache.SetCacheSize(m_Cache.GetWantedCache()); } else bSlideDown = TRUE; } else bSlideDown = TRUE; if( bSlideDown ) { // Slide them all down one. m_Cache.SetCacheSize(m_Cache.GetCacheSize() + 1); for( i=index; i < m_nElements-1; i++ ) m_pArray[i] = m_pArray[i+1]; } --m_nElements; } DYNA_TEMPLATE BOOL CMoArray::SetSize( DWORD newSize ) { if( m_pArray ) _DeleteAndDestroyArray(); m_nElements = newSize; if( newSize > 0 ) { m_pArray = _AllocateTArray( newSize + m_Cache.GetWantedCache() ); if( !m_pArray ) { m_nElements = 0; m_Cache.SetCacheSize(0); return FALSE; } m_Cache.SetCacheSize(m_Cache.GetWantedCache()); } return TRUE; } DYNA_TEMPLATE BOOL CMoArray::SetSizeInit( DWORD newSize, T &val ) { DWORD i; if(!SetSize(newSize)) return FALSE; for(i=0; i < GetSize(); i++) { m_pArray[i] = val; } return TRUE; } DYNA_TEMPLATE BOOL CMoArray::SetSizeInit2( DWORD newSize, T val ) { return SetSizeInit(newSize, val); } DYNA_TEMPLATE BOOL CMoArray::InternalNiceSetSize( DWORD newSize, BOOL bFast ) { T *pNewArray; DWORD i, nToCopy; // Trivial reject.. if(newSize < m_nElements && ((DWORD)m_Cache.GetCacheSize() + (m_nElements - newSize)) <= 0xFFFF) { m_Cache.SetCacheSize(m_Cache.GetCacheSize() + (WORD)(m_nElements - newSize)); m_nElements = newSize; return TRUE; } else if(newSize > m_nElements && (m_nElements + (DWORD)m_Cache.GetCacheSize()) >= newSize) { m_Cache.SetCacheSize(m_Cache.GetCacheSize() - (WORD)(newSize - m_nElements)); m_nElements = newSize; return TRUE; } pNewArray = _AllocateTArray(newSize + m_Cache.GetWantedCache()); if(!pNewArray) return FALSE; nToCopy = m_nElements; if(nToCopy > newSize) nToCopy = newSize; // Copy as many elements as we can. if(bFast) { memcpy(pNewArray, m_pArray, sizeof(T)*nToCopy); } else { for(i=0; i < nToCopy; i++) { pNewArray[i] = m_pArray[i]; } } // Get rid of the old array and point at the new one. _DeleteAndDestroyArray(); m_pArray = pNewArray; m_nElements = newSize; m_Cache.SetCacheSize(m_Cache.GetWantedCache()); return TRUE; } DYNA_TEMPLATE void CMoArray::_InitArray( WORD wantedCache ) { m_pArray = NULL; m_nElements = 0; m_Cache.SetWantedCache(wantedCache); m_Cache.SetCacheSize(0); } DYNA_TEMPLATE T *CMoArray::_AllocateTArray( DWORD nElements ) { T *tPtr = new T[nElements]; return tPtr; } DYNA_TEMPLATE void CMoArray::_DeleteAndDestroyArray() { if(m_pArray) { delete [] m_pArray; m_pArray = NULL; } m_Cache.SetCacheSize(0); } template BOOL AllocateArray(CMoArray &theArray, ToAlloc *pToAlloc) { DWORD i; for(i=0; i < theArray; i++) { theArray[i] = new ToAlloc; if(!theArray[i]) return FALSE; } return TRUE; } template void DeleteAndClearArray( T &theArray ) { DWORD i; for( i=0; i < theArray.GetSize(); i++ ) { if(theArray[i]) delete theArray[i]; } theArray.SetSize(0); } #endif