DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

List.h (27179B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #ifndef __LIST_H__
     30 #define __LIST_H__
     31 
     32 #include <new>
     33 
     34 /*
     35 ===============================================================================
     36 
     37 	List template
     38 	Does not allocate memory until the first item is added.
     39 
     40 ===============================================================================
     41 */
     42 
     43 /*
     44 ========================
     45 idListArrayNew
     46 ========================
     47 */
     48 template< typename _type_, memTag_t _tag_ >
     49 ID_INLINE void * idListArrayNew( int num, bool zeroBuffer ) {
     50 	_type_ * ptr = NULL;
     51 	if ( zeroBuffer ) {
     52 		ptr = (_type_ *)Mem_ClearedAlloc( sizeof(_type_) * num, _tag_ );
     53 	} else {
     54 		ptr = (_type_ *)Mem_Alloc( sizeof(_type_) * num, _tag_ );
     55 	}
     56 	for ( int i = 0; i < num; i++ ) {
     57 		new ( &ptr[i] ) _type_;
     58 	}
     59 	return ptr;
     60 }
     61 
     62 /*
     63 ========================
     64 idListArrayDelete
     65 ========================
     66 */
     67 template< typename _type_ >
     68 ID_INLINE void idListArrayDelete( void *ptr, int num ) {
     69 	// Call the destructors on all the elements
     70 	for ( int i = 0; i < num; i++ ) {
     71 		((_type_ *)ptr)[i].~_type_();
     72 	}
     73 	Mem_Free( ptr );
     74 }
     75 
     76 /*
     77 ========================
     78 idListArrayResize
     79 ========================
     80 */
     81 template< typename _type_, memTag_t _tag_ >
     82 ID_INLINE void * idListArrayResize( void * voldptr, int oldNum, int newNum, bool zeroBuffer ) {
     83 	_type_ * oldptr = (_type_ *)voldptr;
     84 	_type_ * newptr = NULL;
     85 	if ( newNum > 0 ) {
     86 		newptr = (_type_ *)idListArrayNew<_type_, _tag_>( newNum, zeroBuffer );
     87 		int overlap = Min( oldNum, newNum );
     88 		for ( int i = 0; i < overlap; i++ ) {
     89 			newptr[i] = oldptr[i];
     90 		}
     91 	}
     92 	idListArrayDelete<_type_>( voldptr, oldNum );
     93 	return newptr;
     94 }
     95 
     96 /*
     97 ================
     98 idListNewElement<type>
     99 ================
    100 */
    101 template< class type >
    102 ID_INLINE type *idListNewElement( void ) {
    103 	return new type;
    104 }
    105 
    106 template< typename _type_, memTag_t _tag_ = TAG_IDLIB_LIST >
    107 class idList {
    108 public:
    109 
    110 	typedef int		cmp_t( const _type_ *, const _type_ * );
    111 	typedef _type_	new_t();
    112 
    113 					idList( int newgranularity = 16 );
    114 					idList( const idList &other );
    115 					~idList();
    116 
    117 	void			Clear();											// clear the list
    118 	int				Num() const;										// returns number of elements in list
    119 	int				NumAllocated() const;								// returns number of elements allocated for
    120 	void			SetGranularity( int newgranularity );				// set new granularity
    121 	int				GetGranularity() const;								// get the current granularity
    122 
    123 	size_t			Allocated() const;									// returns total size of allocated memory
    124 	size_t			Size() const;										// returns total size of allocated memory including size of list _type_
    125 	size_t			MemoryUsed() const;									// returns size of the used elements in the list
    126 
    127 	idList<_type_,_tag_> &		operator=( const idList<_type_,_tag_> &other );
    128 	const _type_ &	operator[]( int index ) const;
    129 	_type_ &		operator[]( int index );
    130 
    131 	void			Condense();											// resizes list to exactly the number of elements it contains
    132 	void			Resize( int newsize );								// resizes list to the given number of elements
    133 	void			Resize( int newsize, int newgranularity	 );			// resizes list and sets new granularity
    134 	void			SetNum( int newnum );								// set number of elements in list and resize to exactly this number if needed
    135 	void			AssureSize( int newSize);							// assure list has given number of elements, but leave them uninitialized
    136 	void			AssureSize( int newSize, const _type_ &initValue );	// assure list has given number of elements and initialize any new elements
    137 	void			AssureSizeAlloc( int newSize, new_t *allocator );	// assure the pointer list has the given number of elements and allocate any new elements
    138 
    139 	_type_ *		Ptr();												// returns a pointer to the list
    140 	const _type_ *	Ptr() const;										// returns a pointer to the list
    141 	_type_ &		Alloc();											// returns reference to a new data element at the end of the list
    142 	int				Append( const _type_ & obj );						// append element
    143 	int				Append( const idList &other );						// append list
    144 	int				AddUnique( const _type_ & obj );					// add unique element
    145 	int				Insert( const _type_ & obj, int index = 0 );		// insert the element at the given index
    146 	int				FindIndex( const _type_ & obj ) const;				// find the index for the given element
    147 	_type_ *		Find( _type_ const & obj ) const;					// find pointer to the given element
    148 	int				FindNull() const;									// find the index for the first NULL pointer in the list
    149 	int				IndexOf( const _type_ *obj ) const;					// returns the index for the pointer to an element in the list
    150 	bool			RemoveIndex( int index );							// remove the element at the given index
    151 	// removes the element at the given index and places the last element into its spot - DOES NOT PRESERVE LIST ORDER
    152 	bool			RemoveIndexFast( int index );
    153 	bool			Remove( const _type_ & obj );						// remove the element
    154 //	void			Sort( cmp_t *compare = ( cmp_t * )&idListSortCompare<_type_, _tag_> );
    155 	void			SortWithTemplate( const idSort<_type_> & sort = idSort_QuickDefault<_type_>() );
    156 //	void			SortSubSection( int startIndex, int endIndex, cmp_t *compare = ( cmp_t * )&idListSortCompare<_type_> );
    157 	void			Swap( idList &other );								// swap the contents of the lists
    158 	void			DeleteContents( bool clear = true );				// delete the contents of the list
    159 
    160 	//------------------------
    161 	// auto-cast to other idList types with a different memory tag
    162 	//------------------------
    163 
    164 	template< memTag_t _t_ >
    165 	operator idList<_type_, _t_> & () { 
    166 		return *reinterpret_cast<idList<_type_, _t_> *>( this ); 
    167 	}
    168 
    169 	template< memTag_t _t_>
    170 	operator const idList<_type_, _t_> & () const { 
    171 		return *reinterpret_cast<const idList<_type_, _t_> *>( this ); 
    172 	}
    173 
    174 	//------------------------
    175 	// memTag
    176 	//
    177 	// Changing the memTag when the list has an allocated buffer will
    178 	// result in corruption of the memory statistics.
    179 	//------------------------
    180 	memTag_t		GetMemTag() const { return (memTag_t)memTag; };
    181 	void			SetMemTag( memTag_t tag_ ) { memTag = (byte)tag_; };
    182 
    183 private:
    184 	int				num;
    185 	int				size;
    186 	int				granularity;
    187 	_type_ *		list;
    188 	byte			memTag;
    189 };
    190 
    191 /*
    192 ================
    193 idList<_type_,_tag_>::idList( int )
    194 ================
    195 */
    196 template< typename _type_, memTag_t _tag_ >
    197 ID_INLINE idList<_type_,_tag_>::idList( int newgranularity ) {
    198 	assert( newgranularity > 0 );
    199 
    200 	list		= NULL;
    201 	granularity	= newgranularity;
    202 	memTag		= _tag_;
    203 	Clear();
    204 }
    205 
    206 /*
    207 ================
    208 idList<_type_,_tag_>::idList( const idList< _type_, _tag_ > &other )
    209 ================
    210 */
    211 template< typename _type_, memTag_t _tag_ >
    212 ID_INLINE idList<_type_,_tag_>::idList( const idList &other ) {
    213 	list = NULL;
    214 	*this = other;
    215 }
    216 
    217 /*
    218 ================
    219 idList<_type_,_tag_>::~idList< _type_, _tag_ >
    220 ================
    221 */
    222 template< typename _type_, memTag_t _tag_ >
    223 ID_INLINE idList<_type_,_tag_>::~idList() {
    224 	Clear();
    225 }
    226 
    227 /*
    228 ================
    229 idList<_type_,_tag_>::Clear
    230 
    231 Frees up the memory allocated by the list.  Assumes that _type_ automatically handles freeing up memory.
    232 ================
    233 */
    234 template< typename _type_, memTag_t _tag_ >
    235 ID_INLINE void idList<_type_,_tag_>::Clear() {
    236 	if ( list ) {
    237 		idListArrayDelete< _type_ >( list, size );
    238 	}
    239 
    240 	list	= NULL;
    241 	num		= 0;
    242 	size	= 0;
    243 }
    244 
    245 /*
    246 ================
    247 idList<_type_,_tag_>::DeleteContents
    248 
    249 Calls the destructor of all elements in the list.  Conditionally frees up memory used by the list.
    250 Note that this only works on lists containing pointers to objects and will cause a compiler error
    251 if called with non-pointers.  Since the list was not responsible for allocating the object, it has
    252 no information on whether the object still exists or not, so care must be taken to ensure that
    253 the pointers are still valid when this function is called.  Function will set all pointers in the
    254 list to NULL.
    255 ================
    256 */
    257 template< typename _type_, memTag_t _tag_ >
    258 ID_INLINE void idList<_type_,_tag_>::DeleteContents( bool clear ) {
    259 	int i;
    260 
    261 	for( i = 0; i < num; i++ ) {
    262 		delete list[ i ];
    263 		list[ i ] = NULL;
    264 	}
    265 
    266 	if ( clear ) {
    267 		Clear();
    268 	} else {
    269 		memset( list, 0, size * sizeof( _type_ ) );
    270 	}
    271 }
    272 
    273 /*
    274 ================
    275 idList<_type_,_tag_>::Allocated
    276 
    277 return total memory allocated for the list in bytes, but doesn't take into account additional memory allocated by _type_
    278 ================
    279 */
    280 template< typename _type_, memTag_t _tag_ >
    281 ID_INLINE size_t idList<_type_,_tag_>::Allocated() const {
    282 	return size * sizeof( _type_ );
    283 }
    284 
    285 /*
    286 ================
    287 idList<_type_,_tag_>::Size
    288 
    289 return total size of list in bytes, but doesn't take into account additional memory allocated by _type_
    290 ================
    291 */
    292 template< typename _type_, memTag_t _tag_ >
    293 ID_INLINE size_t idList<_type_,_tag_>::Size() const {
    294 	return sizeof( idList< _type_, _tag_ > ) + Allocated();
    295 }
    296 
    297 /*
    298 ================
    299 idList<_type_,_tag_>::MemoryUsed
    300 ================
    301 */
    302 template< typename _type_, memTag_t _tag_ >
    303 ID_INLINE size_t idList<_type_,_tag_>::MemoryUsed() const {
    304 	return num * sizeof( *list );
    305 }
    306 
    307 /*
    308 ================
    309 idList<_type_,_tag_>::Num
    310 
    311 Returns the number of elements currently contained in the list.
    312 Note that this is NOT an indication of the memory allocated.
    313 ================
    314 */
    315 template< typename _type_, memTag_t _tag_ >
    316 ID_INLINE int idList<_type_,_tag_>::Num() const {
    317 	return num;
    318 }
    319 
    320 /*
    321 ================
    322 idList<_type_,_tag_>::NumAllocated
    323 
    324 Returns the number of elements currently allocated for.
    325 ================
    326 */
    327 template< typename _type_, memTag_t _tag_ >
    328 ID_INLINE int idList<_type_,_tag_>::NumAllocated() const {
    329 	return size;
    330 }
    331 
    332 /*
    333 ================
    334 idList<_type_,_tag_>::SetNum
    335 ================
    336 */
    337 template< typename _type_, memTag_t _tag_ >
    338 ID_INLINE void idList<_type_,_tag_>::SetNum( int newnum ) {
    339 	assert( newnum >= 0 );
    340 	if ( newnum > size ) {
    341 		Resize( newnum );
    342 	}
    343 	num = newnum;
    344 }
    345 
    346 /*
    347 ================
    348 idList<_type_,_tag_>::SetGranularity
    349 
    350 Sets the base size of the array and resizes the array to match.
    351 ================
    352 */
    353 template< typename _type_, memTag_t _tag_ >
    354 ID_INLINE void idList<_type_,_tag_>::SetGranularity( int newgranularity ) {
    355 	int newsize;
    356 
    357 	assert( newgranularity > 0 );
    358 	granularity = newgranularity;
    359 
    360 	if ( list ) {
    361 		// resize it to the closest level of granularity
    362 		newsize = num + granularity - 1;
    363 		newsize -= newsize % granularity;
    364 		if ( newsize != size ) {
    365 			Resize( newsize );
    366 		}
    367 	}
    368 }
    369 
    370 /*
    371 ================
    372 idList<_type_,_tag_>::GetGranularity
    373 
    374 Get the current granularity.
    375 ================
    376 */
    377 template< typename _type_, memTag_t _tag_ >
    378 ID_INLINE int idList<_type_,_tag_>::GetGranularity() const {
    379 	return granularity;
    380 }
    381 
    382 /*
    383 ================
    384 idList<_type_,_tag_>::Condense
    385 
    386 Resizes the array to exactly the number of elements it contains or frees up memory if empty.
    387 ================
    388 */
    389 template< typename _type_, memTag_t _tag_ >
    390 ID_INLINE void idList<_type_,_tag_>::Condense() {
    391 	if ( list ) {
    392 		if ( num ) {
    393 			Resize( num );
    394 		} else {
    395 			Clear();
    396 		}
    397 	}
    398 }
    399 
    400 /*
    401 ================
    402 idList<_type_,_tag_>::Resize
    403 
    404 Allocates memory for the amount of elements requested while keeping the contents intact.
    405 Contents are copied using their = operator so that data is correnctly instantiated.
    406 ================
    407 */
    408 template< typename _type_, memTag_t _tag_ >
    409 ID_INLINE void idList<_type_,_tag_>::Resize( int newsize ) {
    410 	assert( newsize >= 0 );
    411 
    412 	// free up the list if no data is being reserved
    413 	if ( newsize <= 0 ) {
    414 		Clear();
    415 		return;
    416 	}
    417 
    418 	if ( newsize == size ) {
    419 		// not changing the size, so just exit
    420 		return;
    421 	}
    422 
    423 	list = (_type_ *)idListArrayResize< _type_, _tag_ >( list, size, newsize, false );
    424 	size = newsize;
    425 	if ( size < num ) {
    426 		num = size;
    427 	}
    428 }
    429 
    430 /*
    431 ================
    432 idList<_type_,_tag_>::Resize
    433 
    434 Allocates memory for the amount of elements requested while keeping the contents intact.
    435 Contents are copied using their = operator so that data is correnctly instantiated.
    436 ================
    437 */
    438 template< typename _type_, memTag_t _tag_ >
    439 ID_INLINE void idList<_type_,_tag_>::Resize( int newsize, int newgranularity ) {
    440 	assert( newsize >= 0 );
    441 
    442 	assert( newgranularity > 0 );
    443 	granularity = newgranularity;
    444 
    445 	// free up the list if no data is being reserved
    446 	if ( newsize <= 0 ) {
    447 		Clear();
    448 		return;
    449 	}
    450 
    451 	list = (_type_ *)idListArrayResize< _type_, _tag_ >( list, size, newsize, false );
    452 	size = newsize;
    453 	if ( size < num ) {
    454 		num = size;
    455 	}
    456 }
    457 
    458 /*
    459 ================
    460 idList<_type_,_tag_>::AssureSize
    461 
    462 Makes sure the list has at least the given number of elements.
    463 ================
    464 */
    465 template< typename _type_, memTag_t _tag_ >
    466 ID_INLINE void idList<_type_,_tag_>::AssureSize( int newSize ) {
    467 	int newNum = newSize;
    468 
    469 	if ( newSize > size ) {
    470 
    471 		if ( granularity == 0 ) {	// this is a hack to fix our memset classes
    472 			granularity = 16;
    473 		}
    474 
    475 		newSize += granularity - 1;
    476 		newSize -= newSize % granularity;
    477 		Resize( newSize );
    478 	}
    479 
    480 	num = newNum;
    481 }
    482 
    483 /*
    484 ================
    485 idList<_type_,_tag_>::AssureSize
    486 
    487 Makes sure the list has at least the given number of elements and initialize any elements not yet initialized.
    488 ================
    489 */
    490 template< typename _type_, memTag_t _tag_ >
    491 ID_INLINE void idList<_type_,_tag_>::AssureSize( int newSize, const _type_ &initValue ) {
    492 	int newNum = newSize;
    493 
    494 	if ( newSize > size ) {
    495 
    496 		if ( granularity == 0 ) {	// this is a hack to fix our memset classes
    497 			granularity = 16;
    498 		}
    499 
    500 		newSize += granularity - 1;
    501 		newSize -= newSize % granularity;
    502 		num = size;
    503 		Resize( newSize );
    504 
    505 		for ( int i = num; i < newSize; i++ ) {
    506 			list[i] = initValue;
    507 		}
    508 	}
    509 
    510 	num = newNum;
    511 }
    512 
    513 /*
    514 ================
    515 idList<_type_,_tag_>::AssureSizeAlloc
    516 
    517 Makes sure the list has at least the given number of elements and allocates any elements using the allocator.
    518 
    519 NOTE: This function can only be called on lists containing pointers. Calling it
    520 on non-pointer lists will cause a compiler error.
    521 ================
    522 */
    523 template< typename _type_, memTag_t _tag_ >
    524 ID_INLINE void idList<_type_,_tag_>::AssureSizeAlloc( int newSize, new_t *allocator ) {
    525 	int newNum = newSize;
    526 
    527 	if ( newSize > size ) {
    528 
    529 		if ( granularity == 0 ) {	// this is a hack to fix our memset classes
    530 			granularity = 16;
    531 		}
    532 
    533 		newSize += granularity - 1;
    534 		newSize -= newSize % granularity;
    535 		num = size;
    536 		Resize( newSize );
    537 
    538 		for ( int i = num; i < newSize; i++ ) {
    539 			list[i] = (*allocator)();
    540 		}
    541 	}
    542 
    543 	num = newNum;
    544 }
    545 
    546 /*
    547 ================
    548 idList<_type_,_tag_>::operator=
    549 
    550 Copies the contents and size attributes of another list.
    551 ================
    552 */
    553 template< typename _type_, memTag_t _tag_ >
    554 ID_INLINE idList<_type_,_tag_> & idList<_type_,_tag_>::operator=( const idList<_type_,_tag_> &other ) {
    555 	int	i;
    556 
    557 	Clear();
    558 
    559 	num			= other.num;
    560 	size		= other.size;
    561 	granularity	= other.granularity;
    562 	memTag		= other.memTag;
    563 
    564 	if ( size ) {
    565 		list = (_type_ *)idListArrayNew< _type_, _tag_ >( size, false );
    566 		for( i = 0; i < num; i++ ) {
    567 			list[ i ] = other.list[ i ];
    568 		}
    569 	}
    570 
    571 	return *this;
    572 }
    573 
    574 /*
    575 ================
    576 idList<_type_,_tag_>::operator[] const
    577 
    578 Access operator.  Index must be within range or an assert will be issued in debug builds.
    579 Release builds do no range checking.
    580 ================
    581 */
    582 template< typename _type_, memTag_t _tag_ >
    583 ID_INLINE const _type_ & idList<_type_,_tag_>::operator[]( int index ) const {
    584 	assert( index >= 0 );
    585 	assert( index < num );
    586 
    587 	return list[ index ];
    588 }
    589 
    590 /*
    591 ================
    592 idList<_type_,_tag_>::operator[]
    593 
    594 Access operator.  Index must be within range or an assert will be issued in debug builds.
    595 Release builds do no range checking.
    596 ================
    597 */
    598 template< typename _type_, memTag_t _tag_ >
    599 ID_INLINE _type_ & idList<_type_,_tag_>::operator[]( int index ) {
    600 	assert( index >= 0 );
    601 	assert( index < num );
    602 
    603 	return list[ index ];
    604 }
    605 
    606 /*
    607 ================
    608 idList<_type_,_tag_>::Ptr
    609 
    610 Returns a pointer to the begining of the array.  Useful for iterating through the list in loops.
    611 
    612 Note: may return NULL if the list is empty.
    613 
    614 FIXME: Create an iterator template for this kind of thing.
    615 ================
    616 */
    617 template< typename _type_, memTag_t _tag_ >
    618 ID_INLINE _type_ * idList<_type_,_tag_>::Ptr() {
    619 	return list;
    620 }
    621 
    622 /*
    623 ================
    624 idList<_type_,_tag_>::Ptr
    625 
    626 Returns a pointer to the begining of the array.  Useful for iterating through the list in loops.
    627 
    628 Note: may return NULL if the list is empty.
    629 
    630 FIXME: Create an iterator template for this kind of thing.
    631 ================
    632 */
    633 template< typename _type_, memTag_t _tag_ >
    634 const ID_INLINE _type_ * idList<_type_,_tag_>::Ptr() const {
    635 	return list;
    636 }
    637 
    638 /*
    639 ================
    640 idList<_type_,_tag_>::Alloc
    641 
    642 Returns a reference to a new data element at the end of the list.
    643 ================
    644 */
    645 template< typename _type_, memTag_t _tag_ >
    646 ID_INLINE _type_ & idList<_type_,_tag_>::Alloc() {
    647 	if ( !list ) {
    648 		Resize( granularity );
    649 	}
    650 
    651 	if ( num == size ) {
    652 		Resize( size + granularity );
    653 	}
    654 
    655 	return list[ num++ ];
    656 }
    657 
    658 /*
    659 ================
    660 idList<_type_,_tag_>::Append
    661 
    662 Increases the size of the list by one element and copies the supplied data into it.
    663 
    664 Returns the index of the new element.
    665 ================
    666 */
    667 template< typename _type_, memTag_t _tag_ >
    668 ID_INLINE int idList<_type_,_tag_>::Append( _type_ const & obj ) {
    669 	if ( !list ) {
    670 		Resize( granularity );
    671 	}
    672 
    673 	if ( num == size ) {
    674 		int newsize;
    675 
    676 		if ( granularity == 0 ) {	// this is a hack to fix our memset classes
    677 			granularity = 16;
    678 		}
    679 		newsize = size + granularity;
    680 		Resize( newsize - newsize % granularity );
    681 	}
    682 
    683 	list[ num ] = obj;
    684 	num++;
    685 
    686 	return num - 1;
    687 }
    688 
    689 
    690 /*
    691 ================
    692 idList<_type_,_tag_>::Insert
    693 
    694 Increases the size of the list by at leat one element if necessary 
    695 and inserts the supplied data into it.
    696 
    697 Returns the index of the new element.
    698 ================
    699 */
    700 template< typename _type_, memTag_t _tag_ >
    701 ID_INLINE int idList<_type_,_tag_>::Insert( _type_ const & obj, int index ) {
    702 	if ( !list ) {
    703 		Resize( granularity );
    704 	}
    705 
    706 	if ( num == size ) {
    707 		int newsize;
    708 
    709 		if ( granularity == 0 ) {	// this is a hack to fix our memset classes
    710 			granularity = 16;
    711 		}
    712 		newsize = size + granularity;
    713 		Resize( newsize - newsize % granularity );
    714 	}
    715 
    716 	if ( index < 0 ) {
    717 		index = 0;
    718 	}
    719 	else if ( index > num ) {
    720 		index = num;
    721 	}
    722 	for ( int i = num; i > index; --i ) {
    723 		list[i] = list[i-1];
    724 	}
    725 	num++;
    726 	list[index] = obj;
    727 	return index;
    728 }
    729 
    730 /*
    731 ================
    732 idList<_type_,_tag_>::Append
    733 
    734 adds the other list to this one
    735 
    736 Returns the size of the new combined list
    737 ================
    738 */
    739 template< typename _type_, memTag_t _tag_ >
    740 ID_INLINE int idList<_type_,_tag_>::Append( const idList< _type_, _tag_ > &other ) {
    741 	if ( !list ) {
    742 		if ( granularity == 0 ) {	// this is a hack to fix our memset classes
    743 			granularity = 16;
    744 		}
    745 		Resize( granularity );
    746 	}
    747 
    748 	int n = other.Num();
    749 	for (int i = 0; i < n; i++) {
    750 		Append(other[i]);
    751 	}
    752 
    753 	return Num();
    754 }
    755 
    756 /*
    757 ================
    758 idList<_type_,_tag_>::AddUnique
    759 
    760 Adds the data to the list if it doesn't already exist.  Returns the index of the data in the list.
    761 ================
    762 */
    763 template< typename _type_, memTag_t _tag_ >
    764 ID_INLINE int idList<_type_,_tag_>::AddUnique( _type_ const & obj ) {
    765 	int index;
    766 
    767 	index = FindIndex( obj );
    768 	if ( index < 0 ) {
    769 		index = Append( obj );
    770 	}
    771 
    772 	return index;
    773 }
    774 
    775 /*
    776 ================
    777 idList<_type_,_tag_>::FindIndex
    778 
    779 Searches for the specified data in the list and returns it's index.  Returns -1 if the data is not found.
    780 ================
    781 */
    782 template< typename _type_, memTag_t _tag_ >
    783 ID_INLINE int idList<_type_,_tag_>::FindIndex( _type_ const & obj ) const {
    784 	int i;
    785 
    786 	for( i = 0; i < num; i++ ) {
    787 		if ( list[ i ] == obj ) {
    788 			return i;
    789 		}
    790 	}
    791 
    792 	// Not found
    793 	return -1;
    794 }
    795 
    796 /*
    797 ================
    798 idList<_type_,_tag_>::Find
    799 
    800 Searches for the specified data in the list and returns it's address. Returns NULL if the data is not found.
    801 ================
    802 */
    803 template< typename _type_, memTag_t _tag_ >
    804 ID_INLINE _type_ *idList<_type_,_tag_>::Find( _type_ const & obj ) const {
    805 	int i;
    806 
    807 	i = FindIndex( obj );
    808 	if ( i >= 0 ) {
    809 		return &list[ i ];
    810 	}
    811 
    812 	return NULL;
    813 }
    814 
    815 /*
    816 ================
    817 idList<_type_,_tag_>::FindNull
    818 
    819 Searches for a NULL pointer in the list.  Returns -1 if NULL is not found.
    820 
    821 NOTE: This function can only be called on lists containing pointers. Calling it
    822 on non-pointer lists will cause a compiler error.
    823 ================
    824 */
    825 template< typename _type_, memTag_t _tag_ >
    826 ID_INLINE int idList<_type_,_tag_>::FindNull() const {
    827 	int i;
    828 
    829 	for( i = 0; i < num; i++ ) {
    830 		if ( list[ i ] == NULL ) {
    831 			return i;
    832 		}
    833 	}
    834 
    835 	// Not found
    836 	return -1;
    837 }
    838 
    839 /*
    840 ================
    841 idList<_type_,_tag_>::IndexOf
    842 
    843 Takes a pointer to an element in the list and returns the index of the element.
    844 This is NOT a guarantee that the object is really in the list. 
    845 Function will assert in debug builds if pointer is outside the bounds of the list,
    846 but remains silent in release builds.
    847 ================
    848 */
    849 template< typename _type_, memTag_t _tag_ >
    850 ID_INLINE int idList<_type_,_tag_>::IndexOf( _type_ const *objptr ) const {
    851 	int index;
    852 
    853 	index = objptr - list;
    854 
    855 	assert( index >= 0 );
    856 	assert( index < num );
    857 
    858 	return index;
    859 }
    860 
    861 /*
    862 ================
    863 idList<_type_,_tag_>::RemoveIndex
    864 
    865 Removes the element at the specified index and moves all data following the element down to fill in the gap.
    866 The number of elements in the list is reduced by one.  Returns false if the index is outside the bounds of the list.
    867 Note that the element is not destroyed, so any memory used by it may not be freed until the destruction of the list.
    868 ================
    869 */
    870 template< typename _type_, memTag_t _tag_ >
    871 ID_INLINE bool idList<_type_,_tag_>::RemoveIndex( int index ) {
    872 	int i;
    873 
    874 	assert( list != NULL );
    875 	assert( index >= 0 );
    876 	assert( index < num );
    877 
    878 	if ( ( index < 0 ) || ( index >= num ) ) {
    879 		return false;
    880 	}
    881 
    882 	num--;
    883 	for( i = index; i < num; i++ ) {
    884 		list[ i ] = list[ i + 1 ];
    885 	}
    886 
    887 	return true;
    888 }
    889 
    890 /*
    891 ========================
    892 idList<_type_,_tag_>::RemoveIndexFast
    893 
    894 Removes the element at the specified index and moves the last element into its spot, rather 
    895 than moving the whole array down by one. Of course, this doesn't maintain the order of 
    896 elements! The number of elements in the list is reduced by one.  
    897 
    898 return:	bool	- false if the data is not found in the list.  
    899 
    900 NOTE:	The element is not destroyed, so any memory used by it may not be freed until the 
    901 		destruction of the list.
    902 ========================
    903 */
    904 template< typename _type_, memTag_t _tag_ >
    905 ID_INLINE bool idList<_type_,_tag_>::RemoveIndexFast( int index ) {
    906 
    907 	if ( ( index < 0 ) || ( index >= num ) ) {
    908 		return false;
    909 	}
    910 
    911 	num--;
    912 	if ( index != num ) {
    913 		list[ index ] = list[ num ];
    914 	}
    915 
    916 	return true;
    917 }
    918 
    919 /*
    920 ================
    921 idList<_type_,_tag_>::Remove
    922 
    923 Removes the element if it is found within the list and moves all data following the element down to fill in the gap.
    924 The number of elements in the list is reduced by one.  Returns false if the data is not found in the list.  Note that
    925 the element is not destroyed, so any memory used by it may not be freed until the destruction of the list.
    926 ================
    927 */
    928 template< typename _type_, memTag_t _tag_ >
    929 ID_INLINE bool idList<_type_,_tag_>::Remove( _type_ const & obj ) {
    930 	int index;
    931 
    932 	index = FindIndex( obj );
    933 	if ( index >= 0 ) {
    934 		return RemoveIndex( index );
    935 	}
    936 	
    937 	return false;
    938 }
    939 //
    940 ///*
    941 //================
    942 //idList<_type_,_tag_>::Sort
    943 //
    944 //Performs a qsort on the list using the supplied comparison function.  Note that the data is merely moved around the
    945 //list, so any pointers to data within the list may no longer be valid.
    946 //================
    947 //*/
    948 //template< typename _type_, memTag_t _tag_ >
    949 //ID_INLINE void idList<_type_,_tag_>::Sort( cmp_t *compare ) {
    950 //	if ( !list ) {
    951 //		return;
    952 //	}
    953 //	typedef int cmp_c(const void *, const void *);
    954 //
    955 //	cmp_c *vCompare = (cmp_c *)compare;
    956 //	qsort( ( void * )list, ( size_t )num, sizeof( _type_ ), vCompare );
    957 //}
    958 
    959 /*
    960 ========================
    961 idList<_type_,_tag_>::SortWithTemplate
    962 
    963 Performs a QuickSort on the list using the supplied sort algorithm.  
    964 
    965 Note:	The data is merely moved around the list, so any pointers to data within the list may 
    966 		no longer be valid.
    967 ========================
    968 */
    969 template< typename _type_, memTag_t _tag_ >
    970 ID_INLINE void idList<_type_,_tag_>::SortWithTemplate( const idSort<_type_> & sort ) {
    971 	if ( list == NULL ) {
    972 		return;
    973 	}
    974 	sort.Sort( Ptr(), Num() );
    975 }
    976 //
    977 ///*
    978 //================
    979 //idList<_type_,_tag_>::SortSubSection
    980 //
    981 //Sorts a subsection of the list.
    982 //================
    983 //*/
    984 //template< typename _type_, memTag_t _tag_ >
    985 //ID_INLINE void idList<_type_,_tag_>::SortSubSection( int startIndex, int endIndex, cmp_t *compare ) {
    986 //	if ( !list ) {
    987 //		return;
    988 //	}
    989 //	if ( startIndex < 0 ) {
    990 //		startIndex = 0;
    991 //	}
    992 //	if ( endIndex >= num ) {
    993 //		endIndex = num - 1;
    994 //	}
    995 //	if ( startIndex >= endIndex ) {
    996 //		return;
    997 //	}
    998 //	typedef int cmp_c(const void *, const void *);
    999 //
   1000 //	cmp_c *vCompare = (cmp_c *)compare;
   1001 //	qsort( ( void * )( &list[startIndex] ), ( size_t )( endIndex - startIndex + 1 ), sizeof( _type_ ), vCompare );
   1002 //}
   1003 
   1004 /*
   1005 ========================
   1006 FindFromGeneric
   1007 
   1008 Finds an item in a list based on any another datatype.  Your _type_ must overload operator()== for the _type_.
   1009 If your _type_ is a ptr, use the FindFromGenericPtr function instead.
   1010 ========================
   1011 */
   1012 template< typename _type_, memTag_t _tag_, typename _compare_type_ >
   1013 _type_ * FindFromGeneric( idList<_type_, _tag_> & list, const _compare_type_ & other ) {
   1014 	for ( int i = 0; i < list.Num(); i++ ) {
   1015 		if ( list[ i ] == other ) {
   1016 			return &list[ i ];
   1017 		}
   1018 	}
   1019 	return NULL;
   1020 }
   1021 
   1022 /*
   1023 ========================
   1024 FindFromGenericPtr
   1025 ========================
   1026 */
   1027 template< typename _type_, memTag_t _tag_, typename _compare_type_ >
   1028 _type_ * FindFromGenericPtr( idList<_type_, _tag_> & list, const _compare_type_ & other ) {
   1029 	for ( int i = 0; i < list.Num(); i++ ) {
   1030 		if ( *list[ i ] == other ) {
   1031 			return &list[ i ];
   1032 		}
   1033 	}
   1034 	return NULL;
   1035 }
   1036 
   1037 #endif /* !__LIST_H__ */