DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Heap.h (31672B)


      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 __HEAP_H__
     30 #define __HEAP_H__
     31 
     32 /*
     33 ===============================================================================
     34 
     35 	Memory Management
     36 
     37 ===============================================================================
     38 */
     39 
     40 // memory tag names are used to sort allocations for sys_dumpMemory and other reporting functions
     41 enum memTag_t {
     42 #define MEM_TAG( x )	TAG_##x,
     43 #include "sys/sys_alloc_tags.h"
     44 	TAG_NUM_TAGS,
     45 };
     46 
     47 static const int MAX_TAGS = 256;
     48 
     49 
     50 
     51 
     52 void *		Mem_Alloc16( const int size, const memTag_t tag );
     53 void		Mem_Free16( void *ptr );
     54 
     55 ID_INLINE void *	Mem_Alloc( const int size, const memTag_t tag ) { return Mem_Alloc16( size, tag ); }
     56 ID_INLINE void		Mem_Free( void *ptr ) { Mem_Free16( ptr ); }
     57 
     58 void *		Mem_ClearedAlloc( const int size, const memTag_t tag );
     59 char *		Mem_CopyString( const char *in );
     60 
     61 ID_INLINE void *operator new( size_t s ) {
     62 	return Mem_Alloc( s, TAG_NEW );
     63 }
     64 ID_INLINE void operator delete( void *p ) {
     65 	Mem_Free( p );
     66 }
     67 ID_INLINE void *operator new[]( size_t s ) {
     68 	return Mem_Alloc( s, TAG_NEW );
     69 }
     70 ID_INLINE void operator delete[]( void *p ) {
     71 	Mem_Free( p );
     72 }
     73 ID_INLINE void *operator new( size_t s, memTag_t tag ) {
     74 	return Mem_Alloc( s, tag );
     75 }
     76 ID_INLINE void operator delete( void *p, memTag_t tag ) {
     77 	Mem_Free( p );
     78 }
     79 ID_INLINE void *operator new[]( size_t s, memTag_t tag ) {
     80 	return Mem_Alloc( s, tag );
     81 }
     82 ID_INLINE void operator delete[]( void *p, memTag_t tag ) {
     83 	Mem_Free( p );
     84 }
     85 
     86 // Define replacements for the PS3 library's aligned new operator.
     87 // Without these, allocations of objects with 32 byte or greater alignment
     88 // may not go through our memory system.
     89 
     90 /*
     91 ================================================
     92 idTempArray is an array that is automatically free'd when it goes out of scope.
     93 There is no "cast" operator because these are very unsafe.
     94 
     95 The template parameter MUST BE POD!
     96 
     97 Compile time asserting POD-ness of the template parameter is complicated due
     98 to our vector classes that need a default constructor but are otherwise
     99 considered POD.
    100 ================================================
    101 */
    102 template < class T >
    103 class idTempArray {
    104 public:
    105 	idTempArray( idTempArray<T> & other );
    106 	idTempArray( unsigned int num );
    107 
    108 	~idTempArray();
    109 
    110 	T & operator []( unsigned int i ) { assert( i < num ); return buffer[i]; }
    111 	const T & operator []( unsigned int i ) const { assert( i < num ); return buffer[i]; }
    112 
    113 	T * Ptr() { return buffer; }
    114 	const T* Ptr() const { return buffer; }
    115 
    116 	size_t Size( ) const { return num * sizeof( T ); }
    117 	unsigned int Num( ) const { return num; }
    118 
    119 	void Zero() { memset( Ptr(), 0, Size() ); }
    120 
    121 private:
    122 	T *				buffer;		// Ensure this buffer comes first, so this == &this->buffer
    123 	unsigned int	num;
    124 };
    125 
    126 /*
    127 ========================
    128 idTempArray::idTempArray
    129 ========================
    130 */
    131 template < class T >
    132 ID_INLINE idTempArray<T>::idTempArray( idTempArray<T> & other ) {
    133 	this->num = other.num;
    134 	this->buffer = other.buffer;
    135 	other.num = 0;
    136 	other.buffer = NULL;
    137 }
    138 
    139 /*
    140 ========================
    141 idTempArray::idTempArray
    142 ========================
    143 */
    144 template < class T >
    145 ID_INLINE idTempArray<T>::idTempArray( unsigned int num ) {
    146 	this->num = num;
    147 	buffer = (T*)Mem_Alloc( num * sizeof( T ), TAG_TEMP );
    148 }
    149 
    150 /*
    151 ========================
    152 idTempArray::~idTempArray
    153 ========================
    154 */
    155 template < class T >
    156 ID_INLINE idTempArray<T>::~idTempArray() {
    157 	Mem_Free( buffer );
    158 }
    159 
    160 /*
    161 ===============================================================================
    162 
    163 	Block based allocator for fixed size objects.
    164 
    165 	All objects of the 'type' are properly constructed and destructed when reused.
    166 
    167 ===============================================================================
    168 */
    169 
    170 #define BLOCK_ALLOC_ALIGNMENT 16
    171 
    172 // Define this to force all block allocators to act like normal new/delete allocation
    173 // for tool checking.
    174 //#define	FORCE_DISCRETE_BLOCK_ALLOCS
    175 
    176 /*
    177 ================================================
    178 idBlockAlloc is a block-based allocator for fixed-size objects.
    179 
    180 All objects are properly constructed and destructed.
    181 ================================================
    182 */
    183 template<class _type_, int _blockSize_, memTag_t memTag = TAG_BLOCKALLOC>
    184 class idBlockAlloc {
    185 public:
    186 	ID_INLINE			idBlockAlloc( bool clear = false );
    187 	ID_INLINE			~idBlockAlloc();
    188 
    189 	// returns total size of allocated memory
    190 	size_t				Allocated() const { return total * sizeof( _type_ ); }
    191 
    192 	// returns total size of allocated memory including size of (*this)
    193 	size_t				Size() const { return sizeof( *this ) + Allocated(); }
    194 
    195 	ID_INLINE void		Shutdown();
    196 	ID_INLINE void		SetFixedBlocks( int numBlocks );
    197 	ID_INLINE void		FreeEmptyBlocks();
    198 
    199 	ID_INLINE _type_ *	Alloc();
    200 	ID_INLINE void		Free( _type_ *element );
    201 
    202 	int					GetTotalCount() const { return total; }
    203 	int					GetAllocCount() const { return active; }
    204 	int					GetFreeCount() const { return total - active; }
    205 
    206 private:
    207 	union element_t {
    208 		_type_ *		data;	// this is a hack to make sure the save game system marks _type_ as saveable
    209 		element_t *		next;
    210 		byte			buffer[( CONST_MAX( sizeof( _type_ ), sizeof( element_t * ) ) + ( BLOCK_ALLOC_ALIGNMENT - 1 ) ) & ~( BLOCK_ALLOC_ALIGNMENT - 1 )];
    211 	};
    212 
    213 	class idBlock {
    214 	public:
    215 		element_t		elements[_blockSize_];
    216 		idBlock *		next;
    217 		element_t *		free;		// list with free elements in this block (temp used only by FreeEmptyBlocks)
    218 		int				freeCount;	// number of free elements in this block (temp used only by FreeEmptyBlocks)
    219 	};
    220 
    221 	idBlock *			blocks;
    222 	element_t *			free;
    223 	int					total;
    224 	int					active;
    225 	bool				allowAllocs;
    226 	bool				clearAllocs;
    227 
    228 	ID_INLINE void		AllocNewBlock();
    229 };
    230 
    231 /*
    232 ========================
    233 idBlockAlloc<_type_,_blockSize_,align_t>::idBlockAlloc
    234 ========================
    235 */
    236 template<class _type_, int _blockSize_, memTag_t memTag>
    237 ID_INLINE idBlockAlloc<_type_,_blockSize_,memTag>::idBlockAlloc( bool clear ) :
    238 	blocks( NULL ),
    239 	free( NULL ),
    240 	total( 0 ),
    241 	active( 0 ),
    242 	allowAllocs( true ),
    243 	clearAllocs( clear )
    244 {
    245 }
    246 
    247 /*
    248 ========================
    249 idBlockAlloc<_type_,_blockSize__,align_t>::~idBlockAlloc
    250 ========================
    251 */
    252 template<class _type_, int _blockSize_, memTag_t memTag>
    253 ID_INLINE idBlockAlloc<_type_,_blockSize_,memTag>::~idBlockAlloc() {
    254 	Shutdown();
    255 }
    256 
    257 /*
    258 ========================
    259 idBlockAlloc<_type_,_blockSize_,align_t>::Alloc
    260 ========================
    261 */
    262 template<class _type_, int _blockSize_, memTag_t memTag>
    263 ID_INLINE _type_ * idBlockAlloc<_type_,_blockSize_,memTag>::Alloc() {
    264 #ifdef FORCE_DISCRETE_BLOCK_ALLOCS
    265 	// for debugging tools
    266 	return new _type_;
    267 #else
    268 	if ( free == NULL ) {
    269 		if ( !allowAllocs ) {
    270 			return NULL;
    271 		}
    272 		AllocNewBlock();
    273 	}
    274 
    275 	active++;
    276 	element_t * element = free;
    277 	free = free->next;
    278 	element->next = NULL;
    279 
    280 	_type_ * t = (_type_ *) element->buffer;
    281 	if ( clearAllocs ) {
    282 		memset( t, 0, sizeof( _type_ ) );
    283 	}
    284 	new ( t ) _type_;
    285 	return t;
    286 #endif
    287 }
    288 
    289 /*
    290 ========================
    291 idBlockAlloc<_type_,_blockSize_,align_t>::Free
    292 ========================
    293 */
    294 template<class _type_, int _blockSize_, memTag_t memTag>
    295 ID_INLINE void idBlockAlloc<_type_,_blockSize_,memTag>::Free( _type_ * t ) {
    296 #ifdef FORCE_DISCRETE_BLOCK_ALLOCS
    297 	// for debugging tools
    298 	delete t;
    299 #else
    300 	if ( t == NULL ) {
    301 		return;
    302 	}
    303 
    304 	t->~_type_();
    305 
    306 	element_t * element = (element_t *)( t );
    307 	element->next = free;
    308 	free = element;
    309 	active--;
    310 #endif
    311 }
    312 
    313 /*
    314 ========================
    315 idBlockAlloc<_type_,_blockSize_,align_t>::Shutdown
    316 ========================
    317 */
    318 template<class _type_, int _blockSize_, memTag_t memTag>
    319 ID_INLINE void idBlockAlloc<_type_,_blockSize_,memTag>::Shutdown() {
    320 	while( blocks != NULL ) {
    321 		idBlock * block = blocks;
    322 		blocks = blocks->next;
    323 		Mem_Free( block );
    324 	}
    325 	blocks = NULL;
    326 	free = NULL;
    327 	total = active = 0;
    328 }
    329 
    330 /*
    331 ========================
    332 idBlockAlloc<_type_,_blockSize_,align_t>::SetFixedBlocks
    333 ========================
    334 */
    335 template<class _type_, int _blockSize_, memTag_t memTag>
    336 ID_INLINE void idBlockAlloc<_type_,_blockSize_,memTag>::SetFixedBlocks( int numBlocks ) {
    337 	int currentNumBlocks = 0;
    338 	for ( idBlock * block = blocks; block != NULL; block = block->next ) {
    339 		currentNumBlocks++;
    340 	}
    341 	for ( int i = currentNumBlocks; i < numBlocks; i++ ) {
    342 		AllocNewBlock();
    343 	}
    344 	allowAllocs = false;
    345 }
    346 
    347 /*
    348 ========================
    349 idBlockAlloc<_type_,_blockSize_,align_t>::AllocNewBlock
    350 ========================
    351 */
    352 template<class _type_, int _blockSize_, memTag_t memTag>
    353 ID_INLINE void idBlockAlloc<_type_,_blockSize_,memTag>::AllocNewBlock() {
    354 	idBlock * block = (idBlock *)Mem_Alloc( sizeof( idBlock ), memTag );
    355 	block->next = blocks;
    356 	blocks = block;
    357 	for ( int i = 0; i < _blockSize_; i++ ) {
    358 		block->elements[i].next = free;
    359 		free = &block->elements[i];
    360 		assert( ( ( (UINT_PTR)free ) & ( BLOCK_ALLOC_ALIGNMENT - 1 ) ) == 0 );
    361 	}
    362 	total += _blockSize_;
    363 }
    364 
    365 /*
    366 ========================
    367 idBlockAlloc<_type_,_blockSize_,align_t>::FreeEmptyBlocks
    368 ========================
    369 */
    370 template<class _type_, int _blockSize_, memTag_t memTag>
    371 ID_INLINE void idBlockAlloc<_type_,_blockSize_,memTag>::FreeEmptyBlocks() {
    372 	// first count how many free elements are in each block
    373 	// and build up a free chain per block
    374 	for ( idBlock * block = blocks; block != NULL; block = block->next ) {
    375 		block->free = NULL;
    376 		block->freeCount = 0;
    377 	}
    378 	for ( element_t * element = free; element != NULL; ) {
    379 		element_t * next = element->next;
    380 		for ( idBlock * block = blocks; block != NULL; block = block->next ) {
    381 			if ( element >= block->elements && element < block->elements + _blockSize_ ) {
    382 				element->next = block->free;
    383 				block->free = element;
    384 				block->freeCount++;
    385 				break;
    386 			}
    387 		}
    388 		// if this assert fires, we couldn't find the element in any block
    389 		assert( element->next != next );
    390 		element = next;
    391 	}
    392 	// now free all blocks whose free count == _blockSize_
    393 	idBlock * prevBlock = NULL;
    394 	for ( idBlock * block = blocks; block != NULL; ) {
    395 		idBlock * next = block->next;
    396 		if ( block->freeCount == _blockSize_ ) {
    397 			if ( prevBlock == NULL ) {
    398 				assert( blocks == block );
    399 				blocks = block->next;
    400 			} else {
    401 				assert( prevBlock->next == block );
    402 				prevBlock->next = block->next;
    403 			}
    404 			Mem_Free( block );
    405 			total -= _blockSize_;
    406 		} else {
    407 			prevBlock = block;
    408 		}
    409 		block = next;
    410 	}
    411 	// now rebuild the free chain
    412 	free = NULL;
    413 	for ( idBlock * block = blocks; block != NULL; block = block->next ) {
    414 		for ( element_t * element = block->free; element != NULL; ) {
    415 			element_t * next = element->next;
    416 			element->next = free;
    417 			free = element;
    418 			element = next;
    419 		}
    420 	}
    421 }
    422 
    423 /*
    424 ==============================================================================
    425 
    426 	Dynamic allocator, simple wrapper for normal allocations which can
    427 	be interchanged with idDynamicBlockAlloc.
    428 
    429 	No constructor is called for the 'type'.
    430 	Allocated blocks are always 16 byte aligned.
    431 
    432 ==============================================================================
    433 */
    434 
    435 template<class type, int baseBlockSize, int minBlockSize>
    436 class idDynamicAlloc {
    437 public:
    438 									idDynamicAlloc();
    439 									~idDynamicAlloc();
    440 
    441 	void							Init();
    442 	void							Shutdown();
    443 	void							SetFixedBlocks( int numBlocks ) {}
    444 	void							SetLockMemory( bool lock ) {}
    445 	void							FreeEmptyBaseBlocks() {}
    446 
    447 	type *							Alloc( const int num );
    448 	type *							Resize( type *ptr, const int num );
    449 	void							Free( type *ptr );
    450 	const char *					CheckMemory( const type *ptr ) const;
    451 
    452 	int								GetNumBaseBlocks() const { return 0; }
    453 	int								GetBaseBlockMemory() const { return 0; }
    454 	int								GetNumUsedBlocks() const { return numUsedBlocks; }
    455 	int								GetUsedBlockMemory() const { return usedBlockMemory; }
    456 	int								GetNumFreeBlocks() const { return 0; }
    457 	int								GetFreeBlockMemory() const { return 0; }
    458 	int								GetNumEmptyBaseBlocks() const { return 0; }
    459 
    460 private:
    461 	int								numUsedBlocks;			// number of used blocks
    462 	int								usedBlockMemory;		// total memory in used blocks
    463 
    464 	int								numAllocs;
    465 	int								numResizes;
    466 	int								numFrees;
    467 
    468 	void							Clear();
    469 };
    470 
    471 template<class type, int baseBlockSize, int minBlockSize>
    472 idDynamicAlloc<type, baseBlockSize, minBlockSize>::idDynamicAlloc() {
    473 	Clear();
    474 }
    475 
    476 template<class type, int baseBlockSize, int minBlockSize>
    477 idDynamicAlloc<type, baseBlockSize, minBlockSize>::~idDynamicAlloc() {
    478 	Shutdown();
    479 }
    480 
    481 template<class type, int baseBlockSize, int minBlockSize>
    482 void idDynamicAlloc<type, baseBlockSize, minBlockSize>::Init() {
    483 }
    484 
    485 template<class type, int baseBlockSize, int minBlockSize>
    486 void idDynamicAlloc<type, baseBlockSize, minBlockSize>::Shutdown() {
    487 	Clear();
    488 }
    489 
    490 template<class type, int baseBlockSize, int minBlockSize>
    491 type *idDynamicAlloc<type, baseBlockSize, minBlockSize>::Alloc( const int num ) {
    492 	numAllocs++;
    493 	if ( num <= 0 ) {
    494 		return NULL;
    495 	}
    496 	numUsedBlocks++;
    497 	usedBlockMemory += num * sizeof( type );
    498 	return Mem_Alloc16( num * sizeof( type ), TAG_BLOCKALLOC );
    499 }
    500 
    501 template<class type, int baseBlockSize, int minBlockSize>
    502 type *idDynamicAlloc<type, baseBlockSize, minBlockSize>::Resize( type *ptr, const int num ) {
    503 
    504 	numResizes++;
    505 
    506 	if ( ptr == NULL ) {
    507 		return Alloc( num );
    508 	}
    509 
    510 	if ( num <= 0 ) {
    511 		Free( ptr );
    512 		return NULL;
    513 	}
    514 
    515 	assert( 0 );
    516 	return ptr;
    517 }
    518 
    519 template<class type, int baseBlockSize, int minBlockSize>
    520 void idDynamicAlloc<type, baseBlockSize, minBlockSize>::Free( type *ptr ) {
    521 	numFrees++;
    522 	if ( ptr == NULL ) {
    523 		return;
    524 	}
    525 	Mem_Free16( ptr );
    526 }
    527 
    528 template<class type, int baseBlockSize, int minBlockSize>
    529 const char *idDynamicAlloc<type, baseBlockSize, minBlockSize>::CheckMemory( const type *ptr ) const {
    530 	return NULL;
    531 }
    532 
    533 template<class type, int baseBlockSize, int minBlockSize>
    534 void idDynamicAlloc<type, baseBlockSize, minBlockSize>::Clear() {
    535 	numUsedBlocks = 0;
    536 	usedBlockMemory = 0;
    537 	numAllocs = 0;
    538 	numResizes = 0;
    539 	numFrees = 0;
    540 }
    541 
    542 
    543 /*
    544 ==============================================================================
    545 
    546 	Fast dynamic block allocator.
    547 
    548 	No constructor is called for the 'type'.
    549 	Allocated blocks are always 16 byte aligned.
    550 
    551 ==============================================================================
    552 */
    553 
    554 #include "containers/BTree.h"
    555 
    556 //#define DYNAMIC_BLOCK_ALLOC_CHECK
    557 
    558 template<class type>
    559 class idDynamicBlock {
    560 public:
    561 	type *							GetMemory() const { return (type *)( ( (byte *) this ) + sizeof( idDynamicBlock<type> ) ); }
    562 	int								GetSize() const { return abs( size ); }
    563 	void							SetSize( int s, bool isBaseBlock ) { size = isBaseBlock ? -s : s; }
    564 	bool							IsBaseBlock() const { return ( size < 0 ); }
    565 
    566 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
    567 	int								id[3];
    568 	void *							allocator;
    569 #endif
    570 
    571 	int								size;					// size in bytes of the block
    572 	idDynamicBlock<type> *			prev;					// previous memory block
    573 	idDynamicBlock<type> *			next;					// next memory block
    574 	idBTreeNode<idDynamicBlock<type>,int> *node;			// node in the B-Tree with free blocks
    575 };
    576 
    577 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_ = TAG_BLOCKALLOC>
    578 class idDynamicBlockAlloc {
    579 public:
    580 									idDynamicBlockAlloc();
    581 									~idDynamicBlockAlloc();
    582 
    583 	void							Init();
    584 	void							Shutdown();
    585 	void							SetFixedBlocks( int numBlocks );
    586 	void							SetLockMemory( bool lock );
    587 	void							FreeEmptyBaseBlocks();
    588 
    589 	type *							Alloc( const int num );
    590 	type *							Resize( type *ptr, const int num );
    591 	void							Free( type *ptr );
    592 	const char *					CheckMemory( const type *ptr ) const;
    593 
    594 	int								GetNumBaseBlocks() const { return numBaseBlocks; }
    595 	int								GetBaseBlockMemory() const { return baseBlockMemory; }
    596 	int								GetNumUsedBlocks() const { return numUsedBlocks; }
    597 	int								GetUsedBlockMemory() const { return usedBlockMemory; }
    598 	int								GetNumFreeBlocks() const { return numFreeBlocks; }
    599 	int								GetFreeBlockMemory() const { return freeBlockMemory; }
    600 	int								GetNumEmptyBaseBlocks() const;
    601 
    602 private:
    603 	idDynamicBlock<type> *			firstBlock;				// first block in list in order of increasing address
    604 	idDynamicBlock<type> *			lastBlock;				// last block in list in order of increasing address
    605 	idBTree<idDynamicBlock<type>,int,4>freeTree;			// B-Tree with free memory blocks
    606 	bool							allowAllocs;			// allow base block allocations
    607 	bool							lockMemory;				// lock memory so it cannot get swapped out
    608 
    609 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
    610 	int								blockId[3];
    611 #endif
    612 
    613 	int								numBaseBlocks;			// number of base blocks
    614 	int								baseBlockMemory;		// total memory in base blocks
    615 	int								numUsedBlocks;			// number of used blocks
    616 	int								usedBlockMemory;		// total memory in used blocks
    617 	int								numFreeBlocks;			// number of free blocks
    618 	int								freeBlockMemory;		// total memory in free blocks
    619 
    620 	int								numAllocs;
    621 	int								numResizes;
    622 	int								numFrees;
    623 	
    624 	memTag_t						tag;
    625 
    626 	void							Clear();
    627 	idDynamicBlock<type> *			AllocInternal( const int num );
    628 	idDynamicBlock<type> *			ResizeInternal( idDynamicBlock<type> *block, const int num );
    629 	void							FreeInternal( idDynamicBlock<type> *block );
    630 	void							LinkFreeInternal( idDynamicBlock<type> *block );
    631 	void							UnlinkFreeInternal( idDynamicBlock<type> *block );
    632 	void							CheckMemory() const;
    633 };
    634 
    635 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    636 idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::idDynamicBlockAlloc() {
    637 	tag = _tag_;
    638 	Clear();
    639 }
    640 
    641 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    642 idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::~idDynamicBlockAlloc() {
    643 	Shutdown();
    644 }
    645 
    646 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    647 void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::Init() {
    648 	freeTree.Init();
    649 }
    650 
    651 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    652 void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::Shutdown() {
    653 	idDynamicBlock<type> *block;
    654 
    655 	for ( block = firstBlock; block != NULL; block = block->next ) {
    656 		if ( block->node == NULL ) {
    657 			FreeInternal( block );
    658 		}
    659 	}
    660 
    661 	for ( block = firstBlock; block != NULL; block = firstBlock ) {
    662 		firstBlock = block->next;
    663 		assert( block->IsBaseBlock() );
    664 		if ( lockMemory ) {
    665 			//idLib::sys->UnlockMemory( block, block->GetSize() + (int)sizeof( idDynamicBlock<type> ) );
    666 		}
    667 		Mem_Free16( block );
    668 	}
    669 
    670 	freeTree.Shutdown();
    671 
    672 	Clear();
    673 }
    674 
    675 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    676 void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::SetFixedBlocks( int numBlocks ) {
    677 	idDynamicBlock<type> *block;
    678 
    679 	for ( int i = numBaseBlocks; i < numBlocks; i++ ) {
    680 		block = ( idDynamicBlock<type> * ) Mem_Alloc16( baseBlockSize, _tag_ );
    681 		if ( lockMemory ) {
    682 			//idLib::sys->LockMemory( block, baseBlockSize );
    683 		}
    684 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
    685 		memcpy( block->id, blockId, sizeof( block->id ) );
    686 		block->allocator = (void*)this;
    687 #endif
    688 		block->SetSize( baseBlockSize - (int)sizeof( idDynamicBlock<type> ), true );
    689 		block->next = NULL;
    690 		block->prev = lastBlock;
    691 		if ( lastBlock ) {
    692 			lastBlock->next = block;
    693 		} else {
    694 			firstBlock = block;
    695 		}
    696 		lastBlock = block;
    697 		block->node = NULL;
    698 
    699 		FreeInternal( block );
    700 
    701 		numBaseBlocks++;
    702 		baseBlockMemory += baseBlockSize;
    703 	}
    704 
    705 	allowAllocs = false;
    706 }
    707 
    708 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    709 void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::SetLockMemory( bool lock ) {
    710 	lockMemory = lock;
    711 }
    712 
    713 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    714 void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::FreeEmptyBaseBlocks() {
    715 	idDynamicBlock<type> *block, *next;
    716 
    717 	for ( block = firstBlock; block != NULL; block = next ) {
    718 		next = block->next;
    719 
    720 		if ( block->IsBaseBlock() && block->node != NULL && ( next == NULL || next->IsBaseBlock() ) ) {
    721 			UnlinkFreeInternal( block );
    722 			if ( block->prev ) {
    723 				block->prev->next = block->next;
    724 			} else {
    725 				firstBlock = block->next;
    726 			}
    727 			if ( block->next ) {
    728 				block->next->prev = block->prev;
    729 			} else {
    730 				lastBlock = block->prev;
    731 			}
    732 			if ( lockMemory ) {
    733 				//idLib::sys->UnlockMemory( block, block->GetSize() + (int)sizeof( idDynamicBlock<type> ) );
    734 			}
    735 			numBaseBlocks--;
    736 			baseBlockMemory -= block->GetSize() + (int)sizeof( idDynamicBlock<type> );
    737 			Mem_Free16( block );
    738 		}
    739 	}
    740 
    741 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
    742 	CheckMemory();
    743 #endif
    744 }
    745 
    746 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    747 int idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::GetNumEmptyBaseBlocks() const {
    748 	int numEmptyBaseBlocks;
    749 	idDynamicBlock<type> *block;
    750 
    751 	numEmptyBaseBlocks = 0;
    752 	for ( block = firstBlock; block != NULL; block = block->next ) {
    753 		if ( block->IsBaseBlock() && block->node != NULL && ( block->next == NULL || block->next->IsBaseBlock() ) ) {
    754 			numEmptyBaseBlocks++;
    755 		}
    756 	}
    757 	return numEmptyBaseBlocks;
    758 }
    759 
    760 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    761 type *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::Alloc( const int num ) {
    762 	idDynamicBlock<type> *block;
    763 
    764 	numAllocs++;
    765 
    766 	if ( num <= 0 ) {
    767 		return NULL;
    768 	}
    769 
    770 	block = AllocInternal( num );
    771 	if ( block == NULL ) {
    772 		return NULL;
    773 	}
    774 	block = ResizeInternal( block, num );
    775 	if ( block == NULL ) {
    776 		return NULL;
    777 	}
    778 
    779 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
    780 	CheckMemory();
    781 #endif
    782 
    783 	numUsedBlocks++;
    784 	usedBlockMemory += block->GetSize();
    785 
    786 	return block->GetMemory();
    787 }
    788 
    789 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    790 type *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::Resize( type *ptr, const int num ) {
    791 
    792 	numResizes++;
    793 
    794 	if ( ptr == NULL ) {
    795 		return Alloc( num );
    796 	}
    797 
    798 	if ( num <= 0 ) {
    799 		Free( ptr );
    800 		return NULL;
    801 	}
    802 
    803 	idDynamicBlock<type> *block = ( idDynamicBlock<type> * ) ( ( (byte *) ptr ) - (int)sizeof( idDynamicBlock<type> ) );
    804 
    805 	usedBlockMemory -= block->GetSize();
    806 
    807 	block = ResizeInternal( block, num );
    808 	if ( block == NULL ) {
    809 		return NULL;
    810 	}
    811 
    812 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
    813 	CheckMemory();
    814 #endif
    815 
    816 	usedBlockMemory += block->GetSize();
    817 
    818 	return block->GetMemory();
    819 }
    820 
    821 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    822 void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::Free( type *ptr ) {
    823 
    824 	numFrees++;
    825 
    826 	if ( ptr == NULL ) {
    827 		return;
    828 	}
    829 
    830 	idDynamicBlock<type> *block = ( idDynamicBlock<type> * ) ( ( (byte *) ptr ) - (int)sizeof( idDynamicBlock<type> ) );
    831 
    832 	numUsedBlocks--;
    833 	usedBlockMemory -= block->GetSize();
    834 
    835 	FreeInternal( block );
    836 
    837 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
    838 	CheckMemory();
    839 #endif
    840 }
    841 
    842 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    843 const char *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::CheckMemory( const type *ptr ) const {
    844 	idDynamicBlock<type> *block;
    845 
    846 	if ( ptr == NULL ) {
    847 		return NULL;
    848 	}
    849 
    850 	block = ( idDynamicBlock<type> * ) ( ( (byte *) ptr ) - (int)sizeof( idDynamicBlock<type> ) );
    851 
    852 	if ( block->node != NULL ) {
    853 		return "memory has been freed";
    854 	}
    855 
    856 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
    857 	if ( block->id[0] != 0x11111111 || block->id[1] != 0x22222222 || block->id[2] != 0x33333333 ) {
    858 		return "memory has invalid id";
    859 	}
    860 	if ( block->allocator != (void*)this ) {
    861 		return "memory was allocated with different allocator";
    862 	}
    863 #endif
    864 
    865 	/* base blocks can be larger than baseBlockSize which can cause this code to fail
    866 	idDynamicBlock<type> *base;
    867 	for ( base = firstBlock; base != NULL; base = base->next ) {
    868 		if ( base->IsBaseBlock() ) {
    869 			if ( ((int)block) >= ((int)base) && ((int)block) < ((int)base) + baseBlockSize ) {
    870 				break;
    871 			}
    872 		}
    873 	}
    874 	if ( base == NULL ) {
    875 		return "no base block found for memory";
    876 	}
    877 	*/
    878 
    879 	return NULL;
    880 }
    881 
    882 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    883 void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::Clear() {
    884 	firstBlock = lastBlock = NULL;
    885 	allowAllocs = true;
    886 	lockMemory = false;
    887 	numBaseBlocks = 0;
    888 	baseBlockMemory = 0;
    889 	numUsedBlocks = 0;
    890 	usedBlockMemory = 0;
    891 	numFreeBlocks = 0;
    892 	freeBlockMemory = 0;
    893 	numAllocs = 0;
    894 	numResizes = 0;
    895 	numFrees = 0;
    896 
    897 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
    898 	blockId[0] = 0x11111111;
    899 	blockId[1] = 0x22222222;
    900 	blockId[2] = 0x33333333;
    901 #endif
    902 }
    903 
    904 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    905 idDynamicBlock<type> *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::AllocInternal( const int num ) {
    906 	idDynamicBlock<type> *block;
    907 	int alignedBytes = ( num * sizeof( type ) + 15 ) & ~15;
    908 
    909 	block = freeTree.FindSmallestLargerEqual( alignedBytes );
    910 	if ( block != NULL ) {
    911 		UnlinkFreeInternal( block );
    912 	} else if ( allowAllocs ) {
    913 		int allocSize = Max( baseBlockSize, alignedBytes + (int)sizeof( idDynamicBlock<type> ) );
    914 		block = ( idDynamicBlock<type> * ) Mem_Alloc16( allocSize, _tag_ );
    915 		if ( lockMemory ) {
    916 			//idLib::sys->LockMemory( block, baseBlockSize );
    917 		}
    918 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
    919 		memcpy( block->id, blockId, sizeof( block->id ) );
    920 		block->allocator = (void*)this;
    921 #endif
    922 		block->SetSize( allocSize - (int)sizeof( idDynamicBlock<type> ), true );
    923 		block->next = NULL;
    924 		block->prev = lastBlock;
    925 		if ( lastBlock ) {
    926 			lastBlock->next = block;
    927 		} else {
    928 			firstBlock = block;
    929 		}
    930 		lastBlock = block;
    931 		block->node = NULL;
    932 
    933 		numBaseBlocks++;
    934 		baseBlockMemory += allocSize;
    935 	}
    936 
    937 	return block;
    938 }
    939 
    940 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
    941 idDynamicBlock<type> *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::ResizeInternal( idDynamicBlock<type> *block, const int num ) {
    942 	int alignedBytes = ( num * sizeof( type ) + 15 ) & ~15;
    943 
    944 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
    945 	assert( block->id[0] == 0x11111111 && block->id[1] == 0x22222222 && block->id[2] == 0x33333333 && block->allocator == (void*)this );
    946 #endif
    947 
    948 	// if the new size is larger
    949 	if ( alignedBytes > block->GetSize() ) {
    950 
    951 		idDynamicBlock<type> *nextBlock = block->next;
    952 
    953 		// try to annexate the next block if it's free
    954 		if ( nextBlock && !nextBlock->IsBaseBlock() && nextBlock->node != NULL &&
    955 				block->GetSize() + (int)sizeof( idDynamicBlock<type> ) + nextBlock->GetSize() >= alignedBytes ) {
    956 
    957 			UnlinkFreeInternal( nextBlock );
    958 			block->SetSize( block->GetSize() + (int)sizeof( idDynamicBlock<type> ) + nextBlock->GetSize(), block->IsBaseBlock() );
    959 			block->next = nextBlock->next;
    960 			if ( nextBlock->next ) {
    961 				nextBlock->next->prev = block;
    962 			} else {
    963 				lastBlock = block;
    964 			}
    965 		} else {
    966 			// allocate a new block and copy
    967 			idDynamicBlock<type> *oldBlock = block;
    968 			block = AllocInternal( num );
    969 			if ( block == NULL ) {
    970 				return NULL;
    971 			}
    972 			memcpy( block->GetMemory(), oldBlock->GetMemory(), oldBlock->GetSize() );
    973 			FreeInternal( oldBlock );
    974 		}
    975 	}
    976 
    977 	// if the unused space at the end of this block is large enough to hold a block with at least one element
    978 	if ( block->GetSize() - alignedBytes - (int)sizeof( idDynamicBlock<type> ) < Max( minBlockSize, (int)sizeof( type ) ) ) {
    979 		return block;
    980 	}
    981 
    982 	idDynamicBlock<type> *newBlock;
    983 
    984 	newBlock = ( idDynamicBlock<type> * ) ( ( (byte *) block ) + (int)sizeof( idDynamicBlock<type> ) + alignedBytes );
    985 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
    986 	memcpy( newBlock->id, blockId, sizeof( newBlock->id ) );
    987 	newBlock->allocator = (void*)this;
    988 #endif
    989 	newBlock->SetSize( block->GetSize() - alignedBytes - (int)sizeof( idDynamicBlock<type> ), false );
    990 	newBlock->next = block->next;
    991 	newBlock->prev = block;
    992 	if ( newBlock->next ) {
    993 		newBlock->next->prev = newBlock;
    994 	} else {
    995 		lastBlock = newBlock;
    996 	}
    997 	newBlock->node = NULL;
    998 	block->next = newBlock;
    999 	block->SetSize( alignedBytes, block->IsBaseBlock() );
   1000 
   1001 	FreeInternal( newBlock );
   1002 
   1003 	return block;
   1004 }
   1005 
   1006 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
   1007 void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::FreeInternal( idDynamicBlock<type> *block ) {
   1008 
   1009 	assert( block->node == NULL );
   1010 
   1011 #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
   1012 	assert( block->id[0] == 0x11111111 && block->id[1] == 0x22222222 && block->id[2] == 0x33333333 && block->allocator == (void*)this );
   1013 #endif
   1014 
   1015 	// try to merge with a next free block
   1016 	idDynamicBlock<type> *nextBlock = block->next;
   1017 	if ( nextBlock && !nextBlock->IsBaseBlock() && nextBlock->node != NULL ) {
   1018 		UnlinkFreeInternal( nextBlock );
   1019 		block->SetSize( block->GetSize() + (int)sizeof( idDynamicBlock<type> ) + nextBlock->GetSize(), block->IsBaseBlock() );
   1020 		block->next = nextBlock->next;
   1021 		if ( nextBlock->next ) {
   1022 			nextBlock->next->prev = block;
   1023 		} else {
   1024 			lastBlock = block;
   1025 		}
   1026 	}
   1027 
   1028 	// try to merge with a previous free block
   1029 	idDynamicBlock<type> *prevBlock = block->prev;
   1030 	if ( prevBlock && !block->IsBaseBlock() && prevBlock->node != NULL ) {
   1031 		UnlinkFreeInternal( prevBlock );
   1032 		prevBlock->SetSize( prevBlock->GetSize() + (int)sizeof( idDynamicBlock<type> ) + block->GetSize(), prevBlock->IsBaseBlock() );
   1033 		prevBlock->next = block->next;
   1034 		if ( block->next ) {
   1035 			block->next->prev = prevBlock;
   1036 		} else {
   1037 			lastBlock = prevBlock;
   1038 		}
   1039 		LinkFreeInternal( prevBlock );
   1040 	} else {
   1041 		LinkFreeInternal( block );
   1042 	}
   1043 }
   1044 
   1045 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
   1046 ID_INLINE void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::LinkFreeInternal( idDynamicBlock<type> *block ) {
   1047 	block->node = freeTree.Add( block, block->GetSize() );
   1048 	numFreeBlocks++;
   1049 	freeBlockMemory += block->GetSize();
   1050 }
   1051 
   1052 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
   1053 ID_INLINE void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::UnlinkFreeInternal( idDynamicBlock<type> *block ) {
   1054 	freeTree.Remove( block->node );
   1055 	block->node = NULL;
   1056 	numFreeBlocks--;
   1057 	freeBlockMemory -= block->GetSize();
   1058 }
   1059 
   1060 template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
   1061 void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::CheckMemory() const {
   1062 	idDynamicBlock<type> *block;
   1063 
   1064 	for ( block = firstBlock; block != NULL; block = block->next ) {
   1065 		// make sure the block is properly linked
   1066 		if ( block->prev == NULL ) {
   1067 			assert( firstBlock == block );
   1068 		} else {
   1069 			assert( block->prev->next == block );
   1070 		}
   1071 		if ( block->next == NULL ) {
   1072 			assert( lastBlock == block );
   1073 		} else {
   1074 			assert( block->next->prev == block );
   1075 		}
   1076 	}
   1077 }
   1078 
   1079 #endif /* !__HEAP_H__ */