// Copyright (C) 2007 Id Software, Inc. // #ifndef __STATICLIST_H__ #define __STATICLIST_H__ /* =============================================================================== Static list template A non-growing, memset-able list using no memory allocation. =============================================================================== */ template class idStaticList { public: typedef int cmp_t( const type *, const type * ); typedef const type ConstType; typedef type Type; typedef Type* Iterator; typedef ConstType* ConstIterator; idStaticList(); idStaticList( const idStaticList &other ); ~idStaticList( void ); void Clear( void ); // marks the list as empty. does not deallocate or intialize data. int Num( void ) const; // returns number of elements in list int Max( void ) const; // returns the maximum number of elements in the list void SetNum( int newnum ); // set number of elements in list bool Empty( void ) const; // returns true if number elements in list is 0 size_t Allocated( void ) const; // returns total size of allocated memory size_t Size( void ) const; // returns total size of allocated memory including size of list type size_t MemoryUsed( void ) const; // returns size of the used elements in the list const type & operator[]( int index ) const; type & operator[]( int index ); type * Alloc( void ); // returns reference to a new data element at the end of the list. returns NULL when full. int Append( const type & obj ); // append element int Append( const idStaticList &other ); // append list int AddUnique( const type & obj ); // add unique element int Insert( const type & obj, int index ); // insert the element at the given index int FindIndex( const type & obj ) const; // find the index for the given element const type * FindElement( type const & obj ) const; // find pointer to the given element int FindNull( void ) const; // find the index for the first NULL pointer in the list bool RemoveIndex( int index ); // remove the element at the given index bool RemoveIndexFast( int index ); // remove the element at the given index and put the last element into its spot bool Remove( const type & obj ); // remove the element bool RemoveFast( const type & obj ); // remove the element, move the last element into its spot void Swap( idStaticList &other ); // swap the contents of the lists void DeleteContents( bool clear ); // delete the contents of the list void Sort( cmp_t *compare ); // members for compatibility with STL algorithms Iterator Begin( void ); // return list[ 0 ] Iterator End( void ); // return list[ num ] (one past end) ConstIterator Begin( void ) const; // return list[ 0 ] ConstIterator End( void ) const; // return list[ num ] (one past end) type& Front(); // return *list[ 0 ] const type& Front() const; // return *list[ 0 ] type& Back(); // return *list[ num - 1 ] const type& Back() const; // return *list[ num - 1 ] bool Remove( Iterator iter ); // Comparison functions // find an object that passes the predicate // IMPORTANT: unlike Find, this returns End() if the element is not found, NOT NULL template< class Cmp > Iterator FindIteratorIf( Cmp predicate ) { Iterator begin = Begin(); Iterator end = End(); while( begin != end ) { if( predicate( *begin ) ) { break; } ++begin; } return begin; } // find an object that passes the predicate // IMPORTANT: unlike Find, this returns End() if the element is not found, NOT NULL template< class Cmp > ConstIterator FindIteratorIf( Cmp predicate ) const { ConstIterator begin = Begin(); ConstIterator end = End(); while( begin != end ) { if( predicate( *begin ) ) { break; } ++begin; } return begin; } // Comparison functions // find an object that passes the predicate // IMPORTANT: unlike Find, this returns End() if the element is not found, NOT NULL template< class searchType, class Cmp > Iterator FindIteratorIf( const searchType& element, const Cmp predicate ) { Iterator begin = Begin(); Iterator end = End(); while( begin != end ) { if( predicate( element, *begin ) ) { break; } ++begin; } return begin; } // find an object that passes the predicate // IMPORTANT: unlike Find, this returns End() if the element is not found, NOT NULL template< class searchType, class Cmp > ConstIterator FindIteratorIf( const searchType& element, Cmp predicate ) const { ConstIterator begin = Begin(); ConstIterator end = End(); while( begin != end ) { if( predicate( element, *begin ) ) { break; } ++begin; } return begin; } Iterator FindIterator( type const & obj ) { Iterator begin = Begin(); Iterator end = End(); while( begin != end ) { if( *begin == obj ) { break; } ++begin; } return begin; } ConstIterator FindIterator( type const & obj ) const { ConstIterator begin = Begin(); ConstIterator end = End(); while( begin != end ) { if( *begin == obj ) { break; } ++begin; } return begin; } // Sorting functions template< class Cmp > void Sort( Cmp compare ) { sdQuickSort( Begin(), End(), compare ); } // Searching functions // IMPORTANT: unlike FindElement, this returns End() if the element is not found, NOT NULL template< class Cmp > Iterator FindIteratorBinary( const type& searchElement, Cmp compare ) { return sdBinarySearch( searchElement, Begin(), End(), compare ); } // IMPORTANT: unlike FindElement, this returns End() if the element is not found, NOT NULL template< class Cmp > ConstIterator FindIteratorBinary( const type& searchElement, Cmp compare ) const { return sdBinarySearch( searchElement, Begin(), End(), compare ); } template< class Iter > void CopyFromRange( Iter begin, Iter end ) { SetNum( end - begin ); for( int i = 0; i < num; i++, ++begin ) { list[ i ] = *begin; } } protected: int num; type list[ size ]; }; /* ================ idStaticList::idStaticList() ================ */ template ID_INLINE idStaticList::idStaticList() { num = 0; } /* ================ idStaticList::idStaticList( const idStaticList &other ) ================ */ template ID_INLINE idStaticList::idStaticList( const idStaticList &other ) { *this = other; } /* ================ idStaticList::~idStaticList ================ */ template ID_INLINE idStaticList::~idStaticList( void ) { } /* ================ idStaticList::Empty ================ */ template< class type, int size > ID_INLINE bool idStaticList::Empty() const { return num == 0; } /* ================ idStaticList::Clear Sets the number of elements in the list to 0. Assumes that type automatically handles freeing up memory. ================ */ template ID_INLINE void idStaticList::Clear( void ) { num = 0; } /* ================ idStaticList::DeleteContents Calls the destructor of all elements in the list. Conditionally frees up memory used by the list. Note that this only works on lists containing pointers to objects and will cause a compiler error if called with non-pointers. Since the list was not responsible for allocating the object, it has no information on whether the object still exists or not, so care must be taken to ensure that the pointers are still valid when this function is called. Function will set all pointers in the list to NULL. ================ */ template ID_INLINE void idStaticList::DeleteContents( bool clear ) { int i; for( i = 0; i < num; i++ ) { delete list[ i ]; list[ i ] = NULL; } if ( clear ) { Clear(); } else { memset( list, 0, sizeof( list ) ); } } /* ================ idStaticList::Num Returns the number of elements currently contained in the list. ================ */ template ID_INLINE int idStaticList::Num( void ) const { return num; } /* ================ idStaticList::Num Returns the maximum number of elements in the list. ================ */ template ID_INLINE int idStaticList::Max( void ) const { return size; } /* ================ idStaticList::Allocated ================ */ template ID_INLINE size_t idStaticList::Allocated( void ) const { return size * sizeof( type ); } /* ================ idStaticList::Size ================ */ template ID_INLINE size_t idStaticList::Size( void ) const { return sizeof( idStaticList ) + Allocated(); } /* ================ idStaticList::Num ================ */ template ID_INLINE size_t idStaticList::MemoryUsed( void ) const { return num * sizeof( list[ 0 ] ); } /* ================ idStaticList::SetNum Set number of elements in list. ================ */ template ID_INLINE void idStaticList::SetNum( int newnum ) { assert( newnum >= 0 ); assert( newnum <= size ); num = newnum; } /* ================ idStaticList::operator[] const Access operator. Index must be within range or an assert will be issued in debug builds. Release builds do no range checking. ================ */ template ID_INLINE const type &idStaticList::operator[]( int index ) const { assert( index >= 0 ); assert( index < num ); return list[ index ]; } /* ================ idStaticList::operator[] Access operator. Index must be within range or an assert will be issued in debug builds. Release builds do no range checking. ================ */ template ID_INLINE type &idStaticList::operator[]( int index ) { assert( index >= 0 ); assert( index < num ); return list[ index ]; } /* ================ idStaticList::Alloc Returns a pointer to a new data element at the end of the list. ================ */ template ID_INLINE type *idStaticList::Alloc( void ) { if ( num >= size ) { return NULL; } return &list[ num++ ]; } /* ================ idStaticList::Append Increases the size of the list by one element and copies the supplied data into it. Returns the index of the new element, or -1 when list is full. ================ */ template ID_INLINE int idStaticList::Append( type const & obj ) { assert( num < size ); if ( num < size ) { list[ num ] = obj; num++; return num - 1; } return -1; } /* ================ idStaticList::Insert Increases the size of the list by at leat one element if necessary and inserts the supplied data into it. Returns the index of the new element, or -1 when list is full. ================ */ template ID_INLINE int idStaticList::Insert( type const & obj, int index ) { int i; assert( num < size ); if ( num >= size ) { return -1; } assert( index >= 0 ); if ( index < 0 ) { index = 0; } else if ( index > num ) { index = num; } for( i = num; i > index; --i ) { list[i] = list[i-1]; } num++; list[index] = obj; return index; } /* ================ idStaticList::Append adds the other list to this one Returns the size of the new combined list ================ */ template ID_INLINE int idStaticList::Append( const idStaticList &other ) { int i; int n = other.Num(); if ( num + n > size ) { n = size - num; } for( i = 0; i < n; i++ ) { list[i + num] = other.list[i]; } num += n; return Num(); } /* ================ idStaticList::AddUnique Adds the data to the list if it doesn't already exist. Returns the index of the data in the list. ================ */ template ID_INLINE int idStaticList::AddUnique( type const & obj ) { int index; index = FindIndex( obj ); if ( index < 0 ) { index = Append( obj ); } return index; } /* ================ idStaticList::FindIndex Searches for the specified data in the list and returns it's index. Returns -1 if the data is not found. ================ */ template ID_INLINE int idStaticList::FindIndex( type const & obj ) const { int i; for( i = 0; i < num; i++ ) { if ( list[ i ] == obj ) { return i; } } // Not found return -1; } /* ================ idStaticList::Find Searches for the specified data in the list and returns it's address. Returns NULL if the data is not found. ================ */ template ID_INLINE const type *idStaticList::FindElement( type const & obj ) const { int i; i = FindIndex( obj ); if ( i >= 0 ) { return &list[ i ]; } return NULL; } /* ================ idStaticList::FindNull Searches for a NULL pointer in the list. Returns -1 if NULL is not found. NOTE: This function can only be called on lists containing pointers. Calling it on non-pointer lists will cause a compiler error. ================ */ template ID_INLINE int idStaticList::FindNull( void ) const { int i; for( i = 0; i < num; i++ ) { if ( list[ i ] == NULL ) { return i; } } // Not found return -1; } /* ================ idStaticList::RemoveIndex Removes the element at the specified index and moves all data following the element down to fill in the gap. The number of elements in the list is reduced by one. Returns false if the index is outside the bounds of the list. Note that the element is not destroyed, so any memory used by it may not be freed until the destruction of the list. ================ */ template ID_INLINE bool idStaticList::RemoveIndex( int index ) { int i; assert( index >= 0 ); assert( index < num ); if ( ( index < 0 ) || ( index >= num ) ) { return false; } num--; for( i = index; i < num; i++ ) { list[ i ] = list[ i + 1 ]; } return true; } /* =============== idStaticList::RemoveIndexFast Removes the element at the specified index and moves the last element into it's spot, rather than moving the whole array down by one. Of course, this doesn't maintain the order of elements! The number of elements in the list is reduced by one. Returns false if the index is outside the bounds of the list. Note that the element is not destroyed, so any memory used by it may not be freed until the destruction of the list. =============== */ template< class type, int size > ID_INLINE bool idStaticList< type, size >::RemoveIndexFast( int index ) { assert( index >= 0 ); assert( index < num ); if ( ( index < 0 ) || ( index >= num ) ) { return false; } num--; // nothing to do if( index == num ) { return true; } list[ index ] = list[ num ]; return true; } /* ================ idStaticList::Remove Removes the element if it is found within the list and moves all data following the element down to fill in the gap. The number of elements in the list is reduced by one. Returns false if the data is not found in the list. Note that the element is not destroyed, so any memory used by it may not be freed until the destruction of the list. ================ */ template ID_INLINE bool idStaticList::Remove( type const & obj ) { int index; index = FindIndex( obj ); if ( index >= 0 ) { return RemoveIndex( index ); } return false; } /* ================ idStaticList::RemoveFast Removes the element if it is found within the list and moves the last element into the gap. The number of elements in the list is reduced by one. Returns false if the data is not found in the list. Note that the element is not destroyed, so any memory used by it may not be freed until the destruction of the list. ================ */ template< class type, int size > ID_INLINE bool idStaticList::RemoveFast( type const & obj ) { int index; index = FindIndex( obj ); if ( index >= 0 ) { return RemoveIndexFast( index ); } return false; } /* ================ idStaticList::Swap Swaps the contents of two lists ================ */ template ID_INLINE void idStaticList::Swap( idStaticList &other ) { idStaticList temp = *this; *this = other; other = temp; } /* ================ idStaticList::Begin Returns the first element of the list ================ */ template< class type, int size > ID_INLINE typename idStaticList::Iterator idStaticList::Begin( void ) { if( num == 0 ) { return End(); } return list; } /* ================ idStaticList::End Returns one past the end of the list ================ */ template< class type, int size > ID_INLINE typename idStaticList::Iterator idStaticList::End( void ) { return list + num; } /* ================ idStaticList::Begin Returns the first element of the list ================ */ template< class type, int size > ID_INLINE typename idStaticList::ConstIterator idStaticList::Begin( void ) const { if( num == 0 ) { return End(); } return list; } /* ================ idStaticList::End Returns one past the end of the list ================ */ template< class type, int size > ID_INLINE typename idStaticList::ConstIterator idStaticList::End( void ) const { return list + num; } /* ================ idStaticList::Back returns the last element ================ */ template< class type, int size > ID_INLINE type& idStaticList::Back() { assert( num != 0 ); return list[ num - 1 ]; } /* ================ idStaticList::Back returns the last element ================ */ template< class type, int size > ID_INLINE const type& idStaticList::Back() const { assert( num != 0 ); return list[ num - 1 ]; } /* ================ idStaticList::Front returns the first element ================ */ template< class type, int size > ID_INLINE type& idStaticList::Front() { assert( num != 0 ); return list[ 0 ]; } /* ================ idStaticList::Front returns the first element ================ */ template< class type, int size > ID_INLINE const type& idStaticList::Front() const { assert( num != 0 ); return list[ 0 ]; } /* ================ idStaticList::Remove ================ */ template< class type, int size > ID_INLINE bool idStaticList::Remove( Iterator iter ) { int index = iter - list; return RemoveIndex( index ); } /* ================ idStaticList::Sort Performs a qsort on the list using the supplied comparison function. Note that the data is merely moved around the list, so any pointers to data within the list may no longer be valid. ================ */ template ID_INLINE void idStaticList::Sort( cmp_t *compare ) { if ( !list ) { return; } typedef int cmp_c(const void *, const void *); cmp_c *vCompare = (cmp_c *)compare; qsort( ( void * )list, ( size_t )num, sizeof( type ), vCompare ); } #endif /* !__STATICLIST_H__ */