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__ */