Heap.h 31 KB

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