//===========================================================================// // Purpose : Template version for a TCT_DynamicVector dynamic vector class. // This vector class dynamically expands and shrinks the total // memory usage requirements based on current vector length. // // Inline methods include: // - SetCapacity // - ResetCapacity // - GetCapacity // - GetLength // - Set // - Add // - Delete // - Clear // - IsValid // // Public methods include: // - TCT_DynamicVector_c, ~TCT_DynamicVector_c // - operator= // - operator==, operator!= // - operator[] // - Print // // Protected methods include: // - Init_ // - Set_ // - Add_ // - Delete_ // - Clear_ // - Expand_ // - Shrink_ // //===========================================================================// #ifndef TCT_DYNAMIC_VECTOR_H #define TCT_DYNAMIC_VECTOR_H #include #include "TIO_PrintHandler.h" #include "TCT_Generic.h" #include "TC_Typedefs.h" //===========================================================================// // Purpose : Class declaration // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > class TCT_DynamicVector_c { public: TCT_DynamicVector_c( size_t allocLen = 1, size_t reallocLen = 1 ); TCT_DynamicVector_c( const TCT_DynamicVector_c& dynamicVector ); ~TCT_DynamicVector_c( void ); TCT_DynamicVector_c< T >& operator=( const TCT_DynamicVector_c& dynamicVector ); bool operator==( const TCT_DynamicVector_c& dynamicVector ) const; bool operator!=( const TCT_DynamicVector_c& dynamicVector ) const; T* operator[]( size_t i ); T* operator[]( size_t i ) const; void Print( FILE* pfile = stdout, size_t spaceLen = 0 ) const; void SetCapacity( size_t capacity ); void SetCapacity( size_t allocLen, size_t reallocLen ); void ResetCapacity( size_t capacity ); void ResetCapacity( size_t allocLen, size_t reallocLen ); size_t GetCapacity( void ) const; size_t GetLength( void ) const; bool Set( size_t i, const T& data ); T* Add( const T& data ); void Delete( size_t i ); void Clear( void ); bool IsValid( void ) const; protected: bool Init_( size_t allocLen, size_t reallocLen ); bool Init_( const TCT_DynamicVector_c& dynamicVector ); bool Set_( size_t i, const T& data ); T* Add_( const T& data ); void Delete_( size_t i ); void Clear_( void ); bool Expand_( void ); bool Shrink_( void ); protected: T* padata_; // Ptr to a dynamic vector of data elements size_t curLen_; // Current dynamic vector size // (ie. defines count of elements currently in use) size_t maxLen_; // Max dynamic vector size (w/o memory reallocate) // (ie. assume curLen_ <= maxLen_) size_t allocLen_; // Initial allocate/deallocate size // (ie. used for dynamic memory expand/shrink) size_t reallocLen_; // Reallocate allocate/deallocate size // (ie. used for dynamic memory expand/shrink) size_t addCount_; // Track number of adds made to this dynamic vector size_t deleteCount_; // Track number of deletes made to this dynamic vector }; //===========================================================================// // Purpose : Class inline definition(s) // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > inline void TCT_DynamicVector_c< T >::SetCapacity( size_t capacity ) { this->Clear_( ); this->Init_( capacity, capacity ); } //===========================================================================// template< class T > inline void TCT_DynamicVector_c< T >::SetCapacity( size_t allocLen, size_t reallocLen ) { this->Clear_( ); this->Init_( allocLen, reallocLen ); } //===========================================================================// template< class T > inline void TCT_DynamicVector_c< T >::ResetCapacity( size_t capacity ) { this->maxLen_ = capacity; this->Init_( capacity, capacity ); } //===========================================================================// template< class T > inline void TCT_DynamicVector_c< T >::ResetCapacity( size_t allocLen, size_t reallocLen ) { this->maxLen_ = TCT_Max( allocLen, reallocLen ); this->Init_( allocLen, reallocLen ); } //===========================================================================// template< class T > inline size_t TCT_DynamicVector_c< T >::GetCapacity( void ) const { return( TCT_Max( this->allocLen_, this->reallocLen_ )); } //===========================================================================// template< class T > inline size_t TCT_DynamicVector_c< T >::GetLength( void ) const { return( this->curLen_ ); } //===========================================================================// template< class T > inline bool TCT_DynamicVector_c< T >::Set( size_t i, const T& data ) { return( this->Set_( i, data )); } //===========================================================================// template< class T > inline T* TCT_DynamicVector_c< T >::Add( const T& data ) { return( this->Add_( data )); } //===========================================================================// template< class T > inline void TCT_DynamicVector_c< T >::Delete( size_t i ) { this->Delete_( i ); } //===========================================================================// template< class T > inline void TCT_DynamicVector_c< T >::Clear( void ) { this->Clear_( ); } //===========================================================================// template< class T > inline bool TCT_DynamicVector_c< T >::IsValid( void ) const { return( this->GetLength( ) > 0 ? true : false ); } //===========================================================================// // Method : TCT_DynamicVector_c // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > TCT_DynamicVector_c< T >::TCT_DynamicVector_c( size_t allocLen, size_t reallocLen ) : padata_( 0 ), curLen_( 0 ), maxLen_( 0 ), allocLen_( 0 ), reallocLen_( 0 ), addCount_( 0 ), deleteCount_( 0 ) { this->Init_( allocLen, reallocLen ); } //===========================================================================// template< class T > TCT_DynamicVector_c< T >::TCT_DynamicVector_c( const TCT_DynamicVector_c& dynamicVector ) : padata_( 0 ), curLen_( 0 ), maxLen_( 0 ), allocLen_( 0 ), reallocLen_( 0 ), addCount_( 0 ), deleteCount_( 0 ) { this->Init_( dynamicVector ); } //===========================================================================// // Method : ~TCT_DynamicVector_c // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > TCT_DynamicVector_c< T >::~TCT_DynamicVector_c( void ) { this->curLen_ = 0; this->Shrink_( ); } //===========================================================================// // Method : operator= // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > TCT_DynamicVector_c< T >& TCT_DynamicVector_c< T >::operator=( const TCT_DynamicVector_c& dynamicVector ) { if ( &dynamicVector != this ) { this->Init_( dynamicVector ); } return( *this ); } //===========================================================================// // Method : operator== // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > bool TCT_DynamicVector_c< T >::operator==( const TCT_DynamicVector_c& dynamicVector ) const { bool isEqual = this->GetLength( ) == dynamicVector.GetLength( ) ? true : false; if ( isEqual ) { for ( size_t i = 0; i < this->GetLength( ); ++i ) { isEqual = *this->operator[]( i ) == *dynamicVector.operator[]( i ) ? true : false; if ( !isEqual ) break; } } return( isEqual ); } //===========================================================================// // Method : operator!= // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > bool TCT_DynamicVector_c< T >::operator!=( const TCT_DynamicVector_c& dynamicVector ) const { return( !this->operator==( dynamicVector ) ? true : false ); } //===========================================================================// // Method : operator[] // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > T* TCT_DynamicVector_c< T >::operator[]( size_t i ) { return( i < this->maxLen_ ? this->padata_ + i : 0 ); } //===========================================================================// template< class T > T* TCT_DynamicVector_c< T >::operator[]( size_t i ) const { return( i < this->maxLen_ ? this->padata_ + i : 0 ); } //===========================================================================// // Method : Print // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > void TCT_DynamicVector_c< T >::Print( FILE* pfile, size_t spaceLen ) const { TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( ); printHandler.Write( pfile, spaceLen, "// %u/%u [%u/%u] (+%u/-%u)", this->curLen_, this->maxLen_, this->allocLen_, this->reallocLen_, this->addCount_, this->deleteCount_ ); for ( size_t i = 0; i < this->GetLength( ); ++i ) { const T& data = *this->operator[]( i ); data.Print( pfile, spaceLen ); } } //===========================================================================// // Method : Init_ // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > bool TCT_DynamicVector_c< T >::Init_( size_t allocLen, size_t reallocLen ) { bool ok = true; // Init alloc and realloc lengths per given values this->allocLen_ = allocLen; this->reallocLen_ = reallocLen; // Force alloc and realloc lengths to minimum acceptable values this->allocLen_ = TCT_Max( this->allocLen_, static_cast< size_t >( 1 )); this->reallocLen_ = TCT_Max( this->allocLen_, this->reallocLen_ ); // And force alloc length to a multiple of realloc length // (for easier subsequent dynamic vector memory expand/shrink) this->allocLen_ = (( this->allocLen_ - 1 ) / this->reallocLen_ ) + 1; this->allocLen_ *= this->reallocLen_; return( ok ); } //===========================================================================// template< class T > bool TCT_DynamicVector_c< T >::Init_( const TCT_DynamicVector_c& dynamicVector ) { bool ok = true; this->Clear_( ); this->allocLen_ = dynamicVector.allocLen_; this->reallocLen_ = dynamicVector.reallocLen_; this->curLen_ = dynamicVector.curLen_; this->maxLen_ = dynamicVector.maxLen_; if ( this->maxLen_ > 0 ) { this->padata_ = new TC_NOTHROW T[ this->maxLen_ ]; TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( ); ok = printHandler.IsValidNew( this->padata_, sizeof( T ) * this->maxLen_, "TCT_DynamicVector_c< T >::Init_" ); if ( ok ) { for ( size_t i = 0; i < this->maxLen_; ++i ) { // Need to copy each element into the newly allocated list // (using 'deep' copy, instead of a faster 'shallow' memcpy) *( this->padata_ + i ) = *( dynamicVector.padata_ + i ); } } } return( ok ); } //===========================================================================// // Method : Set_ // Purpose : Sets a new data element in this dynamic vector. // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > bool TCT_DynamicVector_c< T >::Set_( size_t i, const T& data ) { bool ok = true; while ( i >= this->curLen_ ) { ok = this->Expand_( ); if ( !ok ) break; } if ( ok ) { *( this->padata_ + i ) = data; } return( ok ); } //===========================================================================// // Method : Add_ // Purpose : Adds a new data element to this dynamic vector. The // vector length is automatically expanded, if needed. // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > T* TCT_DynamicVector_c< T >::Add_( const T& data ) { T* pdata = 0; // Expand dynamic vector to accommodate new data element, if needed if ( this->Expand_( )) { // Add new data element to end of vector pdata = this->operator[]( this->curLen_ ); *pdata = data; // Update current length to reflect new vector size ++this->curLen_; // Track total number of add operations made to this vector too ++this->addCount_; } return( pdata ); } //===========================================================================// // Method : Delete_ // Purpose : Deletes an existing data element from this dynamic // vector. The vector length is automatically shrunk, if // needed. // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > void TCT_DynamicVector_c< T >::Delete_( size_t i ) { if ( i < this->curLen_ ) { // Delete existing data element by shifting subsequent data elements while ( i < this->curLen_ - 1 ) { // Need to copy each element into the newly allocated list // (using 'deep' copy, instead of a faster 'shallow' memcpy) *( this->padata_ + i ) = *( this->padata_ + i + 1 ); ++i; } // Update current length to reflect new vector size --this->curLen_; // Track total number of delete operations made to this vector too ++this->deleteCount_; // Shrink dynamic vector to account for deleted data element, if needed this->Shrink_( ); } } //===========================================================================// // Method : Clear_ // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > void TCT_DynamicVector_c< T >::Clear_( void ) { this->curLen_ = 0; this->Shrink_( ); this->padata_ = 0; this->addCount_ = 0; this->deleteCount_ = 0; } //===========================================================================// // Method : Expand_ // Purpose : Expands this dynamic vector whenever the current length // exceeds the maximum length. The new vector length is // adjusted based on the current alloc/realloc length. // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > bool TCT_DynamicVector_c< T >::Expand_( void ) { bool ok = true; // Test if current length requires expanding dynamic vector max length if ( this->curLen_ >= this->maxLen_ ) { // Increase max length based on either alloc or realloc length size_t incLen = ( this->maxLen_ == 0 ? this->allocLen_ : this->reallocLen_ ); this->maxLen_ += incLen; // Make local copy of current vector, then allocate and copy new vector T* padata = new TC_NOTHROW T[ this->maxLen_ ]; TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( ); ok = printHandler.IsValidNew( padata, sizeof( T ) * this->maxLen_, "TCT_DynamicVector_c< T >::Expand_" ); if ( ok ) { for ( size_t i = 0; i < this->curLen_; ++i ) { // Need to copy each element into the newly allocated list // (using 'deep' copy, instead of a faster 'shallow' memcpy) *( padata + i ) = *( this->padata_ + i ); } } else { this->curLen_ = this->maxLen_ = 0; } delete[] this->padata_; this->padata_ = padata; } return( ok ); } //===========================================================================// // Method : Shrink_ // Purpose : Shrink this dynamic vector length when the current length // has been reduced to the maximum length less the realloc // length. The new vector length is adjusted based on the // given realloc length. // Author : Jeff Rudolph //---------------------------------------------------------------------------// // Version history // 05/20/12 jeffr : Original //===========================================================================// template< class T > bool TCT_DynamicVector_c< T >::Shrink_( void ) { bool ok = true; // Test if dynamic vector length can be constracted based on current length if (( this->maxLen_ > 0 ) && ( this->curLen_ <= ( this->maxLen_ - this->reallocLen_ ))) { // Ready to deallocate a portion of dynamic vector this->maxLen_ = ( this->curLen_ / this->reallocLen_ ) + 1; this->maxLen_ = ( this->curLen_ ? this->maxLen_ : 0 ); this->maxLen_ *= this->reallocLen_; if ( this->maxLen_ != 0 ) { T* padata = new TC_NOTHROW T[ this->maxLen_ ]; TIO_PrintHandler_c& printHandler = TIO_PrintHandler_c::GetInstance( ); ok = printHandler.IsValidNew( padata, sizeof( T ) * this->maxLen_, "TCT_DynamicVector_c< T >::Shrink_" ); if ( ok ) { // Need to copy each element into the newly allocated list // (using 'deep' copy, instead of a faster 'shallow' memcpy) for ( size_t i = 0; i < this->maxLen_; ++i ) { *( padata + i ) = *( this->padata_ + i ); } } else { this->curLen_ = this->maxLen_ = 0; } delete[] this->padata_; this->padata_ = padata; } else { delete[] this->padata_; this->padata_ = 0; } } return( ok ); } #endif