123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #ifndef __HEAP_H__
- #define __HEAP_H__
- /*
- ===============================================================================
- Memory Management
- ===============================================================================
- */
- // memory tag names are used to sort allocations for sys_dumpMemory and other reporting functions
- enum memTag_t {
- #define MEM_TAG( x ) TAG_##x,
- #include "sys/sys_alloc_tags.h"
- TAG_NUM_TAGS,
- };
- static const int MAX_TAGS = 256;
- void * Mem_Alloc16( const int size, const memTag_t tag );
- void Mem_Free16( void *ptr );
- ID_INLINE void * Mem_Alloc( const int size, const memTag_t tag ) { return Mem_Alloc16( size, tag ); }
- ID_INLINE void Mem_Free( void *ptr ) { Mem_Free16( ptr ); }
- void * Mem_ClearedAlloc( const int size, const memTag_t tag );
- char * Mem_CopyString( const char *in );
- ID_INLINE void *operator new( size_t s ) {
- return Mem_Alloc( s, TAG_NEW );
- }
- ID_INLINE void operator delete( void *p ) {
- Mem_Free( p );
- }
- ID_INLINE void *operator new[]( size_t s ) {
- return Mem_Alloc( s, TAG_NEW );
- }
- ID_INLINE void operator delete[]( void *p ) {
- Mem_Free( p );
- }
- ID_INLINE void *operator new( size_t s, memTag_t tag ) {
- return Mem_Alloc( s, tag );
- }
- ID_INLINE void operator delete( void *p, memTag_t tag ) {
- Mem_Free( p );
- }
- ID_INLINE void *operator new[]( size_t s, memTag_t tag ) {
- return Mem_Alloc( s, tag );
- }
- ID_INLINE void operator delete[]( void *p, memTag_t tag ) {
- Mem_Free( p );
- }
- // Define replacements for the PS3 library's aligned new operator.
- // Without these, allocations of objects with 32 byte or greater alignment
- // may not go through our memory system.
- /*
- ================================================
- idTempArray is an array that is automatically free'd when it goes out of scope.
- There is no "cast" operator because these are very unsafe.
- The template parameter MUST BE POD!
- Compile time asserting POD-ness of the template parameter is complicated due
- to our vector classes that need a default constructor but are otherwise
- considered POD.
- ================================================
- */
- template < class T >
- class idTempArray {
- public:
- idTempArray( idTempArray<T> & other );
- idTempArray( unsigned int num );
- ~idTempArray();
- T & operator []( unsigned int i ) { assert( i < num ); return buffer[i]; }
- const T & operator []( unsigned int i ) const { assert( i < num ); return buffer[i]; }
- T * Ptr() { return buffer; }
- const T* Ptr() const { return buffer; }
- size_t Size( ) const { return num * sizeof( T ); }
- unsigned int Num( ) const { return num; }
- void Zero() { memset( Ptr(), 0, Size() ); }
- private:
- T * buffer; // Ensure this buffer comes first, so this == &this->buffer
- unsigned int num;
- };
- /*
- ========================
- idTempArray::idTempArray
- ========================
- */
- template < class T >
- ID_INLINE idTempArray<T>::idTempArray( idTempArray<T> & other ) {
- this->num = other.num;
- this->buffer = other.buffer;
- other.num = 0;
- other.buffer = NULL;
- }
- /*
- ========================
- idTempArray::idTempArray
- ========================
- */
- template < class T >
- ID_INLINE idTempArray<T>::idTempArray( unsigned int num ) {
- this->num = num;
- buffer = (T*)Mem_Alloc( num * sizeof( T ), TAG_TEMP );
- }
- /*
- ========================
- idTempArray::~idTempArray
- ========================
- */
- template < class T >
- ID_INLINE idTempArray<T>::~idTempArray() {
- Mem_Free( buffer );
- }
- /*
- ===============================================================================
- Block based allocator for fixed size objects.
- All objects of the 'type' are properly constructed and destructed when reused.
- ===============================================================================
- */
- #define BLOCK_ALLOC_ALIGNMENT 16
- // Define this to force all block allocators to act like normal new/delete allocation
- // for tool checking.
- //#define FORCE_DISCRETE_BLOCK_ALLOCS
- /*
- ================================================
- idBlockAlloc is a block-based allocator for fixed-size objects.
- All objects are properly constructed and destructed.
- ================================================
- */
- template<class _type_, int _blockSize_, memTag_t memTag = TAG_BLOCKALLOC>
- class idBlockAlloc {
- public:
- ID_INLINE idBlockAlloc( bool clear = false );
- ID_INLINE ~idBlockAlloc();
- // returns total size of allocated memory
- size_t Allocated() const { return total * sizeof( _type_ ); }
- // returns total size of allocated memory including size of (*this)
- size_t Size() const { return sizeof( *this ) + Allocated(); }
- ID_INLINE void Shutdown();
- ID_INLINE void SetFixedBlocks( int numBlocks );
- ID_INLINE void FreeEmptyBlocks();
- ID_INLINE _type_ * Alloc();
- ID_INLINE void Free( _type_ *element );
- int GetTotalCount() const { return total; }
- int GetAllocCount() const { return active; }
- int GetFreeCount() const { return total - active; }
- private:
- union element_t {
- _type_ * data; // this is a hack to make sure the save game system marks _type_ as saveable
- element_t * next;
- byte buffer[( CONST_MAX( sizeof( _type_ ), sizeof( element_t * ) ) + ( BLOCK_ALLOC_ALIGNMENT - 1 ) ) & ~( BLOCK_ALLOC_ALIGNMENT - 1 )];
- };
- class idBlock {
- public:
- element_t elements[_blockSize_];
- idBlock * next;
- element_t * free; // list with free elements in this block (temp used only by FreeEmptyBlocks)
- int freeCount; // number of free elements in this block (temp used only by FreeEmptyBlocks)
- };
- idBlock * blocks;
- element_t * free;
- int total;
- int active;
- bool allowAllocs;
- bool clearAllocs;
- ID_INLINE void AllocNewBlock();
- };
- /*
- ========================
- idBlockAlloc<_type_,_blockSize_,align_t>::idBlockAlloc
- ========================
- */
- template<class _type_, int _blockSize_, memTag_t memTag>
- ID_INLINE idBlockAlloc<_type_,_blockSize_,memTag>::idBlockAlloc( bool clear ) :
- blocks( NULL ),
- free( NULL ),
- total( 0 ),
- active( 0 ),
- allowAllocs( true ),
- clearAllocs( clear )
- {
- }
- /*
- ========================
- idBlockAlloc<_type_,_blockSize__,align_t>::~idBlockAlloc
- ========================
- */
- template<class _type_, int _blockSize_, memTag_t memTag>
- ID_INLINE idBlockAlloc<_type_,_blockSize_,memTag>::~idBlockAlloc() {
- Shutdown();
- }
- /*
- ========================
- idBlockAlloc<_type_,_blockSize_,align_t>::Alloc
- ========================
- */
- template<class _type_, int _blockSize_, memTag_t memTag>
- ID_INLINE _type_ * idBlockAlloc<_type_,_blockSize_,memTag>::Alloc() {
- #ifdef FORCE_DISCRETE_BLOCK_ALLOCS
- // for debugging tools
- return new _type_;
- #else
- if ( free == NULL ) {
- if ( !allowAllocs ) {
- return NULL;
- }
- AllocNewBlock();
- }
- active++;
- element_t * element = free;
- free = free->next;
- element->next = NULL;
- _type_ * t = (_type_ *) element->buffer;
- if ( clearAllocs ) {
- memset( t, 0, sizeof( _type_ ) );
- }
- new ( t ) _type_;
- return t;
- #endif
- }
- /*
- ========================
- idBlockAlloc<_type_,_blockSize_,align_t>::Free
- ========================
- */
- template<class _type_, int _blockSize_, memTag_t memTag>
- ID_INLINE void idBlockAlloc<_type_,_blockSize_,memTag>::Free( _type_ * t ) {
- #ifdef FORCE_DISCRETE_BLOCK_ALLOCS
- // for debugging tools
- delete t;
- #else
- if ( t == NULL ) {
- return;
- }
- t->~_type_();
- element_t * element = (element_t *)( t );
- element->next = free;
- free = element;
- active--;
- #endif
- }
- /*
- ========================
- idBlockAlloc<_type_,_blockSize_,align_t>::Shutdown
- ========================
- */
- template<class _type_, int _blockSize_, memTag_t memTag>
- ID_INLINE void idBlockAlloc<_type_,_blockSize_,memTag>::Shutdown() {
- while( blocks != NULL ) {
- idBlock * block = blocks;
- blocks = blocks->next;
- Mem_Free( block );
- }
- blocks = NULL;
- free = NULL;
- total = active = 0;
- }
- /*
- ========================
- idBlockAlloc<_type_,_blockSize_,align_t>::SetFixedBlocks
- ========================
- */
- template<class _type_, int _blockSize_, memTag_t memTag>
- ID_INLINE void idBlockAlloc<_type_,_blockSize_,memTag>::SetFixedBlocks( int numBlocks ) {
- int currentNumBlocks = 0;
- for ( idBlock * block = blocks; block != NULL; block = block->next ) {
- currentNumBlocks++;
- }
- for ( int i = currentNumBlocks; i < numBlocks; i++ ) {
- AllocNewBlock();
- }
- allowAllocs = false;
- }
- /*
- ========================
- idBlockAlloc<_type_,_blockSize_,align_t>::AllocNewBlock
- ========================
- */
- template<class _type_, int _blockSize_, memTag_t memTag>
- ID_INLINE void idBlockAlloc<_type_,_blockSize_,memTag>::AllocNewBlock() {
- idBlock * block = (idBlock *)Mem_Alloc( sizeof( idBlock ), memTag );
- block->next = blocks;
- blocks = block;
- for ( int i = 0; i < _blockSize_; i++ ) {
- block->elements[i].next = free;
- free = &block->elements[i];
- assert( ( ( (UINT_PTR)free ) & ( BLOCK_ALLOC_ALIGNMENT - 1 ) ) == 0 );
- }
- total += _blockSize_;
- }
- /*
- ========================
- idBlockAlloc<_type_,_blockSize_,align_t>::FreeEmptyBlocks
- ========================
- */
- template<class _type_, int _blockSize_, memTag_t memTag>
- ID_INLINE void idBlockAlloc<_type_,_blockSize_,memTag>::FreeEmptyBlocks() {
- // first count how many free elements are in each block
- // and build up a free chain per block
- for ( idBlock * block = blocks; block != NULL; block = block->next ) {
- block->free = NULL;
- block->freeCount = 0;
- }
- for ( element_t * element = free; element != NULL; ) {
- element_t * next = element->next;
- for ( idBlock * block = blocks; block != NULL; block = block->next ) {
- if ( element >= block->elements && element < block->elements + _blockSize_ ) {
- element->next = block->free;
- block->free = element;
- block->freeCount++;
- break;
- }
- }
- // if this assert fires, we couldn't find the element in any block
- assert( element->next != next );
- element = next;
- }
- // now free all blocks whose free count == _blockSize_
- idBlock * prevBlock = NULL;
- for ( idBlock * block = blocks; block != NULL; ) {
- idBlock * next = block->next;
- if ( block->freeCount == _blockSize_ ) {
- if ( prevBlock == NULL ) {
- assert( blocks == block );
- blocks = block->next;
- } else {
- assert( prevBlock->next == block );
- prevBlock->next = block->next;
- }
- Mem_Free( block );
- total -= _blockSize_;
- } else {
- prevBlock = block;
- }
- block = next;
- }
- // now rebuild the free chain
- free = NULL;
- for ( idBlock * block = blocks; block != NULL; block = block->next ) {
- for ( element_t * element = block->free; element != NULL; ) {
- element_t * next = element->next;
- element->next = free;
- free = element;
- element = next;
- }
- }
- }
- /*
- ==============================================================================
- Dynamic allocator, simple wrapper for normal allocations which can
- be interchanged with idDynamicBlockAlloc.
- No constructor is called for the 'type'.
- Allocated blocks are always 16 byte aligned.
- ==============================================================================
- */
- template<class type, int baseBlockSize, int minBlockSize>
- class idDynamicAlloc {
- public:
- idDynamicAlloc();
- ~idDynamicAlloc();
- void Init();
- void Shutdown();
- void SetFixedBlocks( int numBlocks ) {}
- void SetLockMemory( bool lock ) {}
- void FreeEmptyBaseBlocks() {}
- type * Alloc( const int num );
- type * Resize( type *ptr, const int num );
- void Free( type *ptr );
- const char * CheckMemory( const type *ptr ) const;
- int GetNumBaseBlocks() const { return 0; }
- int GetBaseBlockMemory() const { return 0; }
- int GetNumUsedBlocks() const { return numUsedBlocks; }
- int GetUsedBlockMemory() const { return usedBlockMemory; }
- int GetNumFreeBlocks() const { return 0; }
- int GetFreeBlockMemory() const { return 0; }
- int GetNumEmptyBaseBlocks() const { return 0; }
- private:
- int numUsedBlocks; // number of used blocks
- int usedBlockMemory; // total memory in used blocks
- int numAllocs;
- int numResizes;
- int numFrees;
- void Clear();
- };
- template<class type, int baseBlockSize, int minBlockSize>
- idDynamicAlloc<type, baseBlockSize, minBlockSize>::idDynamicAlloc() {
- Clear();
- }
- template<class type, int baseBlockSize, int minBlockSize>
- idDynamicAlloc<type, baseBlockSize, minBlockSize>::~idDynamicAlloc() {
- Shutdown();
- }
- template<class type, int baseBlockSize, int minBlockSize>
- void idDynamicAlloc<type, baseBlockSize, minBlockSize>::Init() {
- }
- template<class type, int baseBlockSize, int minBlockSize>
- void idDynamicAlloc<type, baseBlockSize, minBlockSize>::Shutdown() {
- Clear();
- }
- template<class type, int baseBlockSize, int minBlockSize>
- type *idDynamicAlloc<type, baseBlockSize, minBlockSize>::Alloc( const int num ) {
- numAllocs++;
- if ( num <= 0 ) {
- return NULL;
- }
- numUsedBlocks++;
- usedBlockMemory += num * sizeof( type );
- return Mem_Alloc16( num * sizeof( type ), TAG_BLOCKALLOC );
- }
- template<class type, int baseBlockSize, int minBlockSize>
- type *idDynamicAlloc<type, baseBlockSize, minBlockSize>::Resize( type *ptr, const int num ) {
- numResizes++;
- if ( ptr == NULL ) {
- return Alloc( num );
- }
- if ( num <= 0 ) {
- Free( ptr );
- return NULL;
- }
- assert( 0 );
- return ptr;
- }
- template<class type, int baseBlockSize, int minBlockSize>
- void idDynamicAlloc<type, baseBlockSize, minBlockSize>::Free( type *ptr ) {
- numFrees++;
- if ( ptr == NULL ) {
- return;
- }
- Mem_Free16( ptr );
- }
- template<class type, int baseBlockSize, int minBlockSize>
- const char *idDynamicAlloc<type, baseBlockSize, minBlockSize>::CheckMemory( const type *ptr ) const {
- return NULL;
- }
- template<class type, int baseBlockSize, int minBlockSize>
- void idDynamicAlloc<type, baseBlockSize, minBlockSize>::Clear() {
- numUsedBlocks = 0;
- usedBlockMemory = 0;
- numAllocs = 0;
- numResizes = 0;
- numFrees = 0;
- }
- /*
- ==============================================================================
- Fast dynamic block allocator.
- No constructor is called for the 'type'.
- Allocated blocks are always 16 byte aligned.
- ==============================================================================
- */
- #include "containers/BTree.h"
- //#define DYNAMIC_BLOCK_ALLOC_CHECK
- template<class type>
- class idDynamicBlock {
- public:
- type * GetMemory() const { return (type *)( ( (byte *) this ) + sizeof( idDynamicBlock<type> ) ); }
- int GetSize() const { return abs( size ); }
- void SetSize( int s, bool isBaseBlock ) { size = isBaseBlock ? -s : s; }
- bool IsBaseBlock() const { return ( size < 0 ); }
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- int id[3];
- void * allocator;
- #endif
- int size; // size in bytes of the block
- idDynamicBlock<type> * prev; // previous memory block
- idDynamicBlock<type> * next; // next memory block
- idBTreeNode<idDynamicBlock<type>,int> *node; // node in the B-Tree with free blocks
- };
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_ = TAG_BLOCKALLOC>
- class idDynamicBlockAlloc {
- public:
- idDynamicBlockAlloc();
- ~idDynamicBlockAlloc();
- void Init();
- void Shutdown();
- void SetFixedBlocks( int numBlocks );
- void SetLockMemory( bool lock );
- void FreeEmptyBaseBlocks();
- type * Alloc( const int num );
- type * Resize( type *ptr, const int num );
- void Free( type *ptr );
- const char * CheckMemory( const type *ptr ) const;
- int GetNumBaseBlocks() const { return numBaseBlocks; }
- int GetBaseBlockMemory() const { return baseBlockMemory; }
- int GetNumUsedBlocks() const { return numUsedBlocks; }
- int GetUsedBlockMemory() const { return usedBlockMemory; }
- int GetNumFreeBlocks() const { return numFreeBlocks; }
- int GetFreeBlockMemory() const { return freeBlockMemory; }
- int GetNumEmptyBaseBlocks() const;
- private:
- idDynamicBlock<type> * firstBlock; // first block in list in order of increasing address
- idDynamicBlock<type> * lastBlock; // last block in list in order of increasing address
- idBTree<idDynamicBlock<type>,int,4>freeTree; // B-Tree with free memory blocks
- bool allowAllocs; // allow base block allocations
- bool lockMemory; // lock memory so it cannot get swapped out
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- int blockId[3];
- #endif
- int numBaseBlocks; // number of base blocks
- int baseBlockMemory; // total memory in base blocks
- int numUsedBlocks; // number of used blocks
- int usedBlockMemory; // total memory in used blocks
- int numFreeBlocks; // number of free blocks
- int freeBlockMemory; // total memory in free blocks
- int numAllocs;
- int numResizes;
- int numFrees;
-
- memTag_t tag;
- void Clear();
- idDynamicBlock<type> * AllocInternal( const int num );
- idDynamicBlock<type> * ResizeInternal( idDynamicBlock<type> *block, const int num );
- void FreeInternal( idDynamicBlock<type> *block );
- void LinkFreeInternal( idDynamicBlock<type> *block );
- void UnlinkFreeInternal( idDynamicBlock<type> *block );
- void CheckMemory() const;
- };
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::idDynamicBlockAlloc() {
- tag = _tag_;
- Clear();
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::~idDynamicBlockAlloc() {
- Shutdown();
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::Init() {
- freeTree.Init();
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::Shutdown() {
- idDynamicBlock<type> *block;
- for ( block = firstBlock; block != NULL; block = block->next ) {
- if ( block->node == NULL ) {
- FreeInternal( block );
- }
- }
- for ( block = firstBlock; block != NULL; block = firstBlock ) {
- firstBlock = block->next;
- assert( block->IsBaseBlock() );
- if ( lockMemory ) {
- //idLib::sys->UnlockMemory( block, block->GetSize() + (int)sizeof( idDynamicBlock<type> ) );
- }
- Mem_Free16( block );
- }
- freeTree.Shutdown();
- Clear();
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::SetFixedBlocks( int numBlocks ) {
- idDynamicBlock<type> *block;
- for ( int i = numBaseBlocks; i < numBlocks; i++ ) {
- block = ( idDynamicBlock<type> * ) Mem_Alloc16( baseBlockSize, _tag_ );
- if ( lockMemory ) {
- //idLib::sys->LockMemory( block, baseBlockSize );
- }
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- memcpy( block->id, blockId, sizeof( block->id ) );
- block->allocator = (void*)this;
- #endif
- block->SetSize( baseBlockSize - (int)sizeof( idDynamicBlock<type> ), true );
- block->next = NULL;
- block->prev = lastBlock;
- if ( lastBlock ) {
- lastBlock->next = block;
- } else {
- firstBlock = block;
- }
- lastBlock = block;
- block->node = NULL;
- FreeInternal( block );
- numBaseBlocks++;
- baseBlockMemory += baseBlockSize;
- }
- allowAllocs = false;
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::SetLockMemory( bool lock ) {
- lockMemory = lock;
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::FreeEmptyBaseBlocks() {
- idDynamicBlock<type> *block, *next;
- for ( block = firstBlock; block != NULL; block = next ) {
- next = block->next;
- if ( block->IsBaseBlock() && block->node != NULL && ( next == NULL || next->IsBaseBlock() ) ) {
- UnlinkFreeInternal( block );
- if ( block->prev ) {
- block->prev->next = block->next;
- } else {
- firstBlock = block->next;
- }
- if ( block->next ) {
- block->next->prev = block->prev;
- } else {
- lastBlock = block->prev;
- }
- if ( lockMemory ) {
- //idLib::sys->UnlockMemory( block, block->GetSize() + (int)sizeof( idDynamicBlock<type> ) );
- }
- numBaseBlocks--;
- baseBlockMemory -= block->GetSize() + (int)sizeof( idDynamicBlock<type> );
- Mem_Free16( block );
- }
- }
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- CheckMemory();
- #endif
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- int idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::GetNumEmptyBaseBlocks() const {
- int numEmptyBaseBlocks;
- idDynamicBlock<type> *block;
- numEmptyBaseBlocks = 0;
- for ( block = firstBlock; block != NULL; block = block->next ) {
- if ( block->IsBaseBlock() && block->node != NULL && ( block->next == NULL || block->next->IsBaseBlock() ) ) {
- numEmptyBaseBlocks++;
- }
- }
- return numEmptyBaseBlocks;
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- type *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::Alloc( const int num ) {
- idDynamicBlock<type> *block;
- numAllocs++;
- if ( num <= 0 ) {
- return NULL;
- }
- block = AllocInternal( num );
- if ( block == NULL ) {
- return NULL;
- }
- block = ResizeInternal( block, num );
- if ( block == NULL ) {
- return NULL;
- }
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- CheckMemory();
- #endif
- numUsedBlocks++;
- usedBlockMemory += block->GetSize();
- return block->GetMemory();
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- type *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::Resize( type *ptr, const int num ) {
- numResizes++;
- if ( ptr == NULL ) {
- return Alloc( num );
- }
- if ( num <= 0 ) {
- Free( ptr );
- return NULL;
- }
- idDynamicBlock<type> *block = ( idDynamicBlock<type> * ) ( ( (byte *) ptr ) - (int)sizeof( idDynamicBlock<type> ) );
- usedBlockMemory -= block->GetSize();
- block = ResizeInternal( block, num );
- if ( block == NULL ) {
- return NULL;
- }
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- CheckMemory();
- #endif
- usedBlockMemory += block->GetSize();
- return block->GetMemory();
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::Free( type *ptr ) {
- numFrees++;
- if ( ptr == NULL ) {
- return;
- }
- idDynamicBlock<type> *block = ( idDynamicBlock<type> * ) ( ( (byte *) ptr ) - (int)sizeof( idDynamicBlock<type> ) );
- numUsedBlocks--;
- usedBlockMemory -= block->GetSize();
- FreeInternal( block );
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- CheckMemory();
- #endif
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- const char *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::CheckMemory( const type *ptr ) const {
- idDynamicBlock<type> *block;
- if ( ptr == NULL ) {
- return NULL;
- }
- block = ( idDynamicBlock<type> * ) ( ( (byte *) ptr ) - (int)sizeof( idDynamicBlock<type> ) );
- if ( block->node != NULL ) {
- return "memory has been freed";
- }
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- if ( block->id[0] != 0x11111111 || block->id[1] != 0x22222222 || block->id[2] != 0x33333333 ) {
- return "memory has invalid id";
- }
- if ( block->allocator != (void*)this ) {
- return "memory was allocated with different allocator";
- }
- #endif
- /* base blocks can be larger than baseBlockSize which can cause this code to fail
- idDynamicBlock<type> *base;
- for ( base = firstBlock; base != NULL; base = base->next ) {
- if ( base->IsBaseBlock() ) {
- if ( ((int)block) >= ((int)base) && ((int)block) < ((int)base) + baseBlockSize ) {
- break;
- }
- }
- }
- if ( base == NULL ) {
- return "no base block found for memory";
- }
- */
- return NULL;
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::Clear() {
- firstBlock = lastBlock = NULL;
- allowAllocs = true;
- lockMemory = false;
- numBaseBlocks = 0;
- baseBlockMemory = 0;
- numUsedBlocks = 0;
- usedBlockMemory = 0;
- numFreeBlocks = 0;
- freeBlockMemory = 0;
- numAllocs = 0;
- numResizes = 0;
- numFrees = 0;
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- blockId[0] = 0x11111111;
- blockId[1] = 0x22222222;
- blockId[2] = 0x33333333;
- #endif
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- idDynamicBlock<type> *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::AllocInternal( const int num ) {
- idDynamicBlock<type> *block;
- int alignedBytes = ( num * sizeof( type ) + 15 ) & ~15;
- block = freeTree.FindSmallestLargerEqual( alignedBytes );
- if ( block != NULL ) {
- UnlinkFreeInternal( block );
- } else if ( allowAllocs ) {
- int allocSize = Max( baseBlockSize, alignedBytes + (int)sizeof( idDynamicBlock<type> ) );
- block = ( idDynamicBlock<type> * ) Mem_Alloc16( allocSize, _tag_ );
- if ( lockMemory ) {
- //idLib::sys->LockMemory( block, baseBlockSize );
- }
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- memcpy( block->id, blockId, sizeof( block->id ) );
- block->allocator = (void*)this;
- #endif
- block->SetSize( allocSize - (int)sizeof( idDynamicBlock<type> ), true );
- block->next = NULL;
- block->prev = lastBlock;
- if ( lastBlock ) {
- lastBlock->next = block;
- } else {
- firstBlock = block;
- }
- lastBlock = block;
- block->node = NULL;
- numBaseBlocks++;
- baseBlockMemory += allocSize;
- }
- return block;
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- idDynamicBlock<type> *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::ResizeInternal( idDynamicBlock<type> *block, const int num ) {
- int alignedBytes = ( num * sizeof( type ) + 15 ) & ~15;
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- assert( block->id[0] == 0x11111111 && block->id[1] == 0x22222222 && block->id[2] == 0x33333333 && block->allocator == (void*)this );
- #endif
- // if the new size is larger
- if ( alignedBytes > block->GetSize() ) {
- idDynamicBlock<type> *nextBlock = block->next;
- // try to annexate the next block if it's free
- if ( nextBlock && !nextBlock->IsBaseBlock() && nextBlock->node != NULL &&
- block->GetSize() + (int)sizeof( idDynamicBlock<type> ) + nextBlock->GetSize() >= alignedBytes ) {
- UnlinkFreeInternal( nextBlock );
- block->SetSize( block->GetSize() + (int)sizeof( idDynamicBlock<type> ) + nextBlock->GetSize(), block->IsBaseBlock() );
- block->next = nextBlock->next;
- if ( nextBlock->next ) {
- nextBlock->next->prev = block;
- } else {
- lastBlock = block;
- }
- } else {
- // allocate a new block and copy
- idDynamicBlock<type> *oldBlock = block;
- block = AllocInternal( num );
- if ( block == NULL ) {
- return NULL;
- }
- memcpy( block->GetMemory(), oldBlock->GetMemory(), oldBlock->GetSize() );
- FreeInternal( oldBlock );
- }
- }
- // if the unused space at the end of this block is large enough to hold a block with at least one element
- if ( block->GetSize() - alignedBytes - (int)sizeof( idDynamicBlock<type> ) < Max( minBlockSize, (int)sizeof( type ) ) ) {
- return block;
- }
- idDynamicBlock<type> *newBlock;
- newBlock = ( idDynamicBlock<type> * ) ( ( (byte *) block ) + (int)sizeof( idDynamicBlock<type> ) + alignedBytes );
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- memcpy( newBlock->id, blockId, sizeof( newBlock->id ) );
- newBlock->allocator = (void*)this;
- #endif
- newBlock->SetSize( block->GetSize() - alignedBytes - (int)sizeof( idDynamicBlock<type> ), false );
- newBlock->next = block->next;
- newBlock->prev = block;
- if ( newBlock->next ) {
- newBlock->next->prev = newBlock;
- } else {
- lastBlock = newBlock;
- }
- newBlock->node = NULL;
- block->next = newBlock;
- block->SetSize( alignedBytes, block->IsBaseBlock() );
- FreeInternal( newBlock );
- return block;
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::FreeInternal( idDynamicBlock<type> *block ) {
- assert( block->node == NULL );
- #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
- assert( block->id[0] == 0x11111111 && block->id[1] == 0x22222222 && block->id[2] == 0x33333333 && block->allocator == (void*)this );
- #endif
- // try to merge with a next free block
- idDynamicBlock<type> *nextBlock = block->next;
- if ( nextBlock && !nextBlock->IsBaseBlock() && nextBlock->node != NULL ) {
- UnlinkFreeInternal( nextBlock );
- block->SetSize( block->GetSize() + (int)sizeof( idDynamicBlock<type> ) + nextBlock->GetSize(), block->IsBaseBlock() );
- block->next = nextBlock->next;
- if ( nextBlock->next ) {
- nextBlock->next->prev = block;
- } else {
- lastBlock = block;
- }
- }
- // try to merge with a previous free block
- idDynamicBlock<type> *prevBlock = block->prev;
- if ( prevBlock && !block->IsBaseBlock() && prevBlock->node != NULL ) {
- UnlinkFreeInternal( prevBlock );
- prevBlock->SetSize( prevBlock->GetSize() + (int)sizeof( idDynamicBlock<type> ) + block->GetSize(), prevBlock->IsBaseBlock() );
- prevBlock->next = block->next;
- if ( block->next ) {
- block->next->prev = prevBlock;
- } else {
- lastBlock = prevBlock;
- }
- LinkFreeInternal( prevBlock );
- } else {
- LinkFreeInternal( block );
- }
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- ID_INLINE void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::LinkFreeInternal( idDynamicBlock<type> *block ) {
- block->node = freeTree.Add( block, block->GetSize() );
- numFreeBlocks++;
- freeBlockMemory += block->GetSize();
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- ID_INLINE void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::UnlinkFreeInternal( idDynamicBlock<type> *block ) {
- freeTree.Remove( block->node );
- block->node = NULL;
- numFreeBlocks--;
- freeBlockMemory -= block->GetSize();
- }
- template<class type, int baseBlockSize, int minBlockSize, memTag_t _tag_>
- void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize, _tag_>::CheckMemory() const {
- idDynamicBlock<type> *block;
- for ( block = firstBlock; block != NULL; block = block->next ) {
- // make sure the block is properly linked
- if ( block->prev == NULL ) {
- assert( firstBlock == block );
- } else {
- assert( block->prev->next == block );
- }
- if ( block->next == NULL ) {
- assert( lastBlock == block );
- } else {
- assert( block->next->prev == block );
- }
- }
- }
- #endif /* !__HEAP_H__ */
|