Heap.h 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 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. This is a replacement for the compiler heap code (i.e. "C" malloc() and
  26. free() calls). On average 2.5-3.0 times faster than MSVC malloc()/free().
  27. Worst case performance is 1.65 times faster and best case > 70 times.
  28. ===============================================================================
  29. */
  30. typedef struct {
  31. int num;
  32. int minSize;
  33. int maxSize;
  34. int totalSize;
  35. } memoryStats_t;
  36. void Mem_Init( void );
  37. void Mem_Shutdown( void );
  38. void Mem_EnableLeakTest( const char *name );
  39. void Mem_ClearFrameStats( void );
  40. void Mem_GetFrameStats( memoryStats_t &allocs, memoryStats_t &frees );
  41. void Mem_GetStats( memoryStats_t &stats );
  42. void Mem_Dump_f( const class idCmdArgs &args );
  43. void Mem_DumpCompressed_f( const class idCmdArgs &args );
  44. void Mem_AllocDefragBlock( void );
  45. #ifndef ID_DEBUG_MEMORY
  46. void * Mem_Alloc( const int size );
  47. void * Mem_ClearedAlloc( const int size );
  48. void Mem_Free( void *ptr );
  49. char * Mem_CopyString( const char *in );
  50. void * Mem_Alloc16( const int size );
  51. void Mem_Free16( void *ptr );
  52. #ifdef ID_REDIRECT_NEWDELETE
  53. __inline void *operator new( size_t s ) {
  54. return Mem_Alloc( s );
  55. }
  56. __inline void operator delete( void *p ) {
  57. Mem_Free( p );
  58. }
  59. __inline void *operator new[]( size_t s ) {
  60. return Mem_Alloc( s );
  61. }
  62. __inline void operator delete[]( void *p ) {
  63. Mem_Free( p );
  64. }
  65. #endif
  66. #else /* ID_DEBUG_MEMORY */
  67. void * Mem_Alloc( const int size, const char *fileName, const int lineNumber );
  68. void * Mem_ClearedAlloc( const int size, const char *fileName, const int lineNumber );
  69. void Mem_Free( void *ptr, const char *fileName, const int lineNumber );
  70. char * Mem_CopyString( const char *in, const char *fileName, const int lineNumber );
  71. void * Mem_Alloc16( const int size, const char *fileName, const int lineNumber );
  72. void Mem_Free16( void *ptr, const char *fileName, const int lineNumber );
  73. #ifdef ID_REDIRECT_NEWDELETE
  74. __inline void *operator new( size_t s, int t1, int t2, char *fileName, int lineNumber ) {
  75. return Mem_Alloc( s, fileName, lineNumber );
  76. }
  77. __inline void operator delete( void *p, int t1, int t2, char *fileName, int lineNumber ) {
  78. Mem_Free( p, fileName, lineNumber );
  79. }
  80. __inline void *operator new[]( size_t s, int t1, int t2, char *fileName, int lineNumber ) {
  81. return Mem_Alloc( s, fileName, lineNumber );
  82. }
  83. __inline void operator delete[]( void *p, int t1, int t2, char *fileName, int lineNumber ) {
  84. Mem_Free( p, fileName, lineNumber );
  85. }
  86. __inline void *operator new( size_t s ) {
  87. return Mem_Alloc( s, "", 0 );
  88. }
  89. __inline void operator delete( void *p ) {
  90. Mem_Free( p, "", 0 );
  91. }
  92. __inline void *operator new[]( size_t s ) {
  93. return Mem_Alloc( s, "", 0 );
  94. }
  95. __inline void operator delete[]( void *p ) {
  96. Mem_Free( p, "", 0 );
  97. }
  98. #define ID_DEBUG_NEW new( 0, 0, __FILE__, __LINE__ )
  99. #undef new
  100. #define new ID_DEBUG_NEW
  101. #endif
  102. #define Mem_Alloc( size ) Mem_Alloc( size, __FILE__, __LINE__ )
  103. #define Mem_ClearedAlloc( size ) Mem_ClearedAlloc( size, __FILE__, __LINE__ )
  104. #define Mem_Free( ptr ) Mem_Free( ptr, __FILE__, __LINE__ )
  105. #define Mem_CopyString( s ) Mem_CopyString( s, __FILE__, __LINE__ )
  106. #define Mem_Alloc16( size ) Mem_Alloc16( size, __FILE__, __LINE__ )
  107. #define Mem_Free16( ptr ) Mem_Free16( ptr, __FILE__, __LINE__ )
  108. #endif /* ID_DEBUG_MEMORY */
  109. /*
  110. ===============================================================================
  111. Block based allocator for fixed size objects.
  112. All objects of the 'type' are properly constructed.
  113. However, the constructor is not called for re-used objects.
  114. ===============================================================================
  115. */
  116. template<class type, int blockSize>
  117. class idBlockAlloc {
  118. public:
  119. idBlockAlloc( void );
  120. ~idBlockAlloc( void );
  121. void Shutdown( void );
  122. type * Alloc( void );
  123. void Free( type *element );
  124. int GetTotalCount( void ) const { return total; }
  125. int GetAllocCount( void ) const { return active; }
  126. int GetFreeCount( void ) const { return total - active; }
  127. private:
  128. typedef struct element_s {
  129. struct element_s * next;
  130. type t;
  131. } element_t;
  132. typedef struct block_s {
  133. element_t elements[blockSize];
  134. struct block_s * next;
  135. } block_t;
  136. block_t * blocks;
  137. element_t * free;
  138. int total;
  139. int active;
  140. };
  141. template<class type, int blockSize>
  142. idBlockAlloc<type,blockSize>::idBlockAlloc( void ) {
  143. blocks = NULL;
  144. free = NULL;
  145. total = active = 0;
  146. }
  147. template<class type, int blockSize>
  148. idBlockAlloc<type,blockSize>::~idBlockAlloc( void ) {
  149. Shutdown();
  150. }
  151. template<class type, int blockSize>
  152. type *idBlockAlloc<type,blockSize>::Alloc( void ) {
  153. if ( !free ) {
  154. block_t *block = new block_t;
  155. block->next = blocks;
  156. blocks = block;
  157. for ( int i = 0; i < blockSize; i++ ) {
  158. block->elements[i].next = free;
  159. free = &block->elements[i];
  160. }
  161. total += blockSize;
  162. }
  163. active++;
  164. element_t *element = free;
  165. free = free->next;
  166. element->next = NULL;
  167. return &element->t;
  168. }
  169. template<class type, int blockSize>
  170. void idBlockAlloc<type,blockSize>::Free( type *t ) {
  171. element_t *element = (element_t *)( ( (unsigned char *) t ) - ( (int) &((element_t *)0)->t ) );
  172. element->next = free;
  173. free = element;
  174. active--;
  175. }
  176. template<class type, int blockSize>
  177. void idBlockAlloc<type,blockSize>::Shutdown( void ) {
  178. while( blocks ) {
  179. block_t *block = blocks;
  180. blocks = blocks->next;
  181. delete block;
  182. }
  183. blocks = NULL;
  184. free = NULL;
  185. total = active = 0;
  186. }
  187. /*
  188. ==============================================================================
  189. Dynamic allocator, simple wrapper for normal allocations which can
  190. be interchanged with idDynamicBlockAlloc.
  191. No constructor is called for the 'type'.
  192. Allocated blocks are always 16 byte aligned.
  193. ==============================================================================
  194. */
  195. template<class type, int baseBlockSize, int minBlockSize>
  196. class idDynamicAlloc {
  197. public:
  198. idDynamicAlloc( void );
  199. ~idDynamicAlloc( void );
  200. void Init( void );
  201. void Shutdown( void );
  202. void SetFixedBlocks( int numBlocks ) {}
  203. void SetLockMemory( bool lock ) {}
  204. void FreeEmptyBaseBlocks( void ) {}
  205. type * Alloc( const int num );
  206. type * Resize( type *ptr, const int num );
  207. void Free( type *ptr );
  208. const char * CheckMemory( const type *ptr ) const;
  209. int GetNumBaseBlocks( void ) const { return 0; }
  210. int GetBaseBlockMemory( void ) const { return 0; }
  211. int GetNumUsedBlocks( void ) const { return numUsedBlocks; }
  212. int GetUsedBlockMemory( void ) const { return usedBlockMemory; }
  213. int GetNumFreeBlocks( void ) const { return 0; }
  214. int GetFreeBlockMemory( void ) const { return 0; }
  215. int GetNumEmptyBaseBlocks( void ) const { return 0; }
  216. private:
  217. int numUsedBlocks; // number of used blocks
  218. int usedBlockMemory; // total memory in used blocks
  219. int numAllocs;
  220. int numResizes;
  221. int numFrees;
  222. void Clear( void );
  223. };
  224. template<class type, int baseBlockSize, int minBlockSize>
  225. idDynamicAlloc<type, baseBlockSize, minBlockSize>::idDynamicAlloc( void ) {
  226. Clear();
  227. }
  228. template<class type, int baseBlockSize, int minBlockSize>
  229. idDynamicAlloc<type, baseBlockSize, minBlockSize>::~idDynamicAlloc( void ) {
  230. Shutdown();
  231. }
  232. template<class type, int baseBlockSize, int minBlockSize>
  233. void idDynamicAlloc<type, baseBlockSize, minBlockSize>::Init( void ) {
  234. }
  235. template<class type, int baseBlockSize, int minBlockSize>
  236. void idDynamicAlloc<type, baseBlockSize, minBlockSize>::Shutdown( void ) {
  237. Clear();
  238. }
  239. template<class type, int baseBlockSize, int minBlockSize>
  240. type *idDynamicAlloc<type, baseBlockSize, minBlockSize>::Alloc( const int num ) {
  241. numAllocs++;
  242. if ( num <= 0 ) {
  243. return NULL;
  244. }
  245. numUsedBlocks++;
  246. usedBlockMemory += num * sizeof( type );
  247. return Mem_Alloc16( num * sizeof( type ) );
  248. }
  249. template<class type, int baseBlockSize, int minBlockSize>
  250. type *idDynamicAlloc<type, baseBlockSize, minBlockSize>::Resize( type *ptr, const int num ) {
  251. numResizes++;
  252. if ( ptr == NULL ) {
  253. return Alloc( num );
  254. }
  255. if ( num <= 0 ) {
  256. Free( ptr );
  257. return NULL;
  258. }
  259. assert( 0 );
  260. return ptr;
  261. }
  262. template<class type, int baseBlockSize, int minBlockSize>
  263. void idDynamicAlloc<type, baseBlockSize, minBlockSize>::Free( type *ptr ) {
  264. numFrees++;
  265. if ( ptr == NULL ) {
  266. return;
  267. }
  268. Mem_Free16( ptr );
  269. }
  270. template<class type, int baseBlockSize, int minBlockSize>
  271. const char *idDynamicAlloc<type, baseBlockSize, minBlockSize>::CheckMemory( const type *ptr ) const {
  272. return NULL;
  273. }
  274. template<class type, int baseBlockSize, int minBlockSize>
  275. void idDynamicAlloc<type, baseBlockSize, minBlockSize>::Clear( void ) {
  276. numUsedBlocks = 0;
  277. usedBlockMemory = 0;
  278. numAllocs = 0;
  279. numResizes = 0;
  280. numFrees = 0;
  281. }
  282. /*
  283. ==============================================================================
  284. Fast dynamic block allocator.
  285. No constructor is called for the 'type'.
  286. Allocated blocks are always 16 byte aligned.
  287. ==============================================================================
  288. */
  289. #include "containers/BTree.h"
  290. //#define DYNAMIC_BLOCK_ALLOC_CHECK
  291. template<class type>
  292. class idDynamicBlock {
  293. public:
  294. type * GetMemory( void ) const { return (type *)( ( (byte *) this ) + sizeof( idDynamicBlock<type> ) ); }
  295. int GetSize( void ) const { return abs( size ); }
  296. void SetSize( int s, bool isBaseBlock ) { size = isBaseBlock ? -s : s; }
  297. bool IsBaseBlock( void ) const { return ( size < 0 ); }
  298. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  299. int id[3];
  300. void * allocator;
  301. #endif
  302. int size; // size in bytes of the block
  303. idDynamicBlock<type> * prev; // previous memory block
  304. idDynamicBlock<type> * next; // next memory block
  305. idBTreeNode<idDynamicBlock<type>,int> *node; // node in the B-Tree with free blocks
  306. };
  307. template<class type, int baseBlockSize, int minBlockSize>
  308. class idDynamicBlockAlloc {
  309. public:
  310. idDynamicBlockAlloc( void );
  311. ~idDynamicBlockAlloc( void );
  312. void Init( void );
  313. void Shutdown( void );
  314. void SetFixedBlocks( int numBlocks );
  315. void SetLockMemory( bool lock );
  316. void FreeEmptyBaseBlocks( void );
  317. type * Alloc( const int num );
  318. type * Resize( type *ptr, const int num );
  319. void Free( type *ptr );
  320. const char * CheckMemory( const type *ptr ) const;
  321. int GetNumBaseBlocks( void ) const { return numBaseBlocks; }
  322. int GetBaseBlockMemory( void ) const { return baseBlockMemory; }
  323. int GetNumUsedBlocks( void ) const { return numUsedBlocks; }
  324. int GetUsedBlockMemory( void ) const { return usedBlockMemory; }
  325. int GetNumFreeBlocks( void ) const { return numFreeBlocks; }
  326. int GetFreeBlockMemory( void ) const { return freeBlockMemory; }
  327. int GetNumEmptyBaseBlocks( void ) const;
  328. private:
  329. idDynamicBlock<type> * firstBlock; // first block in list in order of increasing address
  330. idDynamicBlock<type> * lastBlock; // last block in list in order of increasing address
  331. idBTree<idDynamicBlock<type>,int,4>freeTree; // B-Tree with free memory blocks
  332. bool allowAllocs; // allow base block allocations
  333. bool lockMemory; // lock memory so it cannot get swapped out
  334. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  335. int blockId[3];
  336. #endif
  337. int numBaseBlocks; // number of base blocks
  338. int baseBlockMemory; // total memory in base blocks
  339. int numUsedBlocks; // number of used blocks
  340. int usedBlockMemory; // total memory in used blocks
  341. int numFreeBlocks; // number of free blocks
  342. int freeBlockMemory; // total memory in free blocks
  343. int numAllocs;
  344. int numResizes;
  345. int numFrees;
  346. void Clear( void );
  347. idDynamicBlock<type> * AllocInternal( const int num );
  348. idDynamicBlock<type> * ResizeInternal( idDynamicBlock<type> *block, const int num );
  349. void FreeInternal( idDynamicBlock<type> *block );
  350. void LinkFreeInternal( idDynamicBlock<type> *block );
  351. void UnlinkFreeInternal( idDynamicBlock<type> *block );
  352. void CheckMemory( void ) const;
  353. };
  354. template<class type, int baseBlockSize, int minBlockSize>
  355. idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::idDynamicBlockAlloc( void ) {
  356. Clear();
  357. }
  358. template<class type, int baseBlockSize, int minBlockSize>
  359. idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::~idDynamicBlockAlloc( void ) {
  360. Shutdown();
  361. }
  362. template<class type, int baseBlockSize, int minBlockSize>
  363. void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::Init( void ) {
  364. freeTree.Init();
  365. }
  366. template<class type, int baseBlockSize, int minBlockSize>
  367. void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::Shutdown( void ) {
  368. idDynamicBlock<type> *block;
  369. for ( block = firstBlock; block != NULL; block = block->next ) {
  370. if ( block->node == NULL ) {
  371. FreeInternal( block );
  372. }
  373. }
  374. for ( block = firstBlock; block != NULL; block = firstBlock ) {
  375. firstBlock = block->next;
  376. assert( block->IsBaseBlock() );
  377. if ( lockMemory ) {
  378. idLib::sys->UnlockMemory( block, block->GetSize() + (int)sizeof( idDynamicBlock<type> ) );
  379. }
  380. Mem_Free16( block );
  381. }
  382. freeTree.Shutdown();
  383. Clear();
  384. }
  385. template<class type, int baseBlockSize, int minBlockSize>
  386. void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::SetFixedBlocks( int numBlocks ) {
  387. idDynamicBlock<type> *block;
  388. for ( int i = numBaseBlocks; i < numBlocks; i++ ) {
  389. block = ( idDynamicBlock<type> * ) Mem_Alloc16( baseBlockSize );
  390. if ( lockMemory ) {
  391. idLib::sys->LockMemory( block, baseBlockSize );
  392. }
  393. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  394. memcpy( block->id, blockId, sizeof( block->id ) );
  395. block->allocator = (void*)this;
  396. #endif
  397. block->SetSize( baseBlockSize - (int)sizeof( idDynamicBlock<type> ), true );
  398. block->next = NULL;
  399. block->prev = lastBlock;
  400. if ( lastBlock ) {
  401. lastBlock->next = block;
  402. } else {
  403. firstBlock = block;
  404. }
  405. lastBlock = block;
  406. block->node = NULL;
  407. FreeInternal( block );
  408. numBaseBlocks++;
  409. baseBlockMemory += baseBlockSize;
  410. }
  411. allowAllocs = false;
  412. }
  413. template<class type, int baseBlockSize, int minBlockSize>
  414. void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::SetLockMemory( bool lock ) {
  415. lockMemory = lock;
  416. }
  417. template<class type, int baseBlockSize, int minBlockSize>
  418. void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::FreeEmptyBaseBlocks( void ) {
  419. idDynamicBlock<type> *block, *next;
  420. for ( block = firstBlock; block != NULL; block = next ) {
  421. next = block->next;
  422. if ( block->IsBaseBlock() && block->node != NULL && ( next == NULL || next->IsBaseBlock() ) ) {
  423. UnlinkFreeInternal( block );
  424. if ( block->prev ) {
  425. block->prev->next = block->next;
  426. } else {
  427. firstBlock = block->next;
  428. }
  429. if ( block->next ) {
  430. block->next->prev = block->prev;
  431. } else {
  432. lastBlock = block->prev;
  433. }
  434. if ( lockMemory ) {
  435. idLib::sys->UnlockMemory( block, block->GetSize() + (int)sizeof( idDynamicBlock<type> ) );
  436. }
  437. numBaseBlocks--;
  438. baseBlockMemory -= block->GetSize() + (int)sizeof( idDynamicBlock<type> );
  439. Mem_Free16( block );
  440. }
  441. }
  442. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  443. CheckMemory();
  444. #endif
  445. }
  446. template<class type, int baseBlockSize, int minBlockSize>
  447. int idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::GetNumEmptyBaseBlocks( void ) const {
  448. int numEmptyBaseBlocks;
  449. idDynamicBlock<type> *block;
  450. numEmptyBaseBlocks = 0;
  451. for ( block = firstBlock; block != NULL; block = block->next ) {
  452. if ( block->IsBaseBlock() && block->node != NULL && ( block->next == NULL || block->next->IsBaseBlock() ) ) {
  453. numEmptyBaseBlocks++;
  454. }
  455. }
  456. return numEmptyBaseBlocks;
  457. }
  458. template<class type, int baseBlockSize, int minBlockSize>
  459. type *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::Alloc( const int num ) {
  460. idDynamicBlock<type> *block;
  461. numAllocs++;
  462. if ( num <= 0 ) {
  463. return NULL;
  464. }
  465. block = AllocInternal( num );
  466. if ( block == NULL ) {
  467. return NULL;
  468. }
  469. block = ResizeInternal( block, num );
  470. if ( block == NULL ) {
  471. return NULL;
  472. }
  473. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  474. CheckMemory();
  475. #endif
  476. numUsedBlocks++;
  477. usedBlockMemory += block->GetSize();
  478. return block->GetMemory();
  479. }
  480. template<class type, int baseBlockSize, int minBlockSize>
  481. type *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::Resize( type *ptr, const int num ) {
  482. numResizes++;
  483. if ( ptr == NULL ) {
  484. return Alloc( num );
  485. }
  486. if ( num <= 0 ) {
  487. Free( ptr );
  488. return NULL;
  489. }
  490. idDynamicBlock<type> *block = ( idDynamicBlock<type> * ) ( ( (byte *) ptr ) - (int)sizeof( idDynamicBlock<type> ) );
  491. usedBlockMemory -= block->GetSize();
  492. block = ResizeInternal( block, num );
  493. if ( block == NULL ) {
  494. return NULL;
  495. }
  496. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  497. CheckMemory();
  498. #endif
  499. usedBlockMemory += block->GetSize();
  500. return block->GetMemory();
  501. }
  502. template<class type, int baseBlockSize, int minBlockSize>
  503. void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::Free( type *ptr ) {
  504. numFrees++;
  505. if ( ptr == NULL ) {
  506. return;
  507. }
  508. idDynamicBlock<type> *block = ( idDynamicBlock<type> * ) ( ( (byte *) ptr ) - (int)sizeof( idDynamicBlock<type> ) );
  509. numUsedBlocks--;
  510. usedBlockMemory -= block->GetSize();
  511. FreeInternal( block );
  512. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  513. CheckMemory();
  514. #endif
  515. }
  516. template<class type, int baseBlockSize, int minBlockSize>
  517. const char *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::CheckMemory( const type *ptr ) const {
  518. idDynamicBlock<type> *block;
  519. if ( ptr == NULL ) {
  520. return NULL;
  521. }
  522. block = ( idDynamicBlock<type> * ) ( ( (byte *) ptr ) - (int)sizeof( idDynamicBlock<type> ) );
  523. if ( block->node != NULL ) {
  524. return "memory has been freed";
  525. }
  526. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  527. if ( block->id[0] != 0x11111111 || block->id[1] != 0x22222222 || block->id[2] != 0x33333333 ) {
  528. return "memory has invalid id";
  529. }
  530. if ( block->allocator != (void*)this ) {
  531. return "memory was allocated with different allocator";
  532. }
  533. #endif
  534. /* base blocks can be larger than baseBlockSize which can cause this code to fail
  535. idDynamicBlock<type> *base;
  536. for ( base = firstBlock; base != NULL; base = base->next ) {
  537. if ( base->IsBaseBlock() ) {
  538. if ( ((int)block) >= ((int)base) && ((int)block) < ((int)base) + baseBlockSize ) {
  539. break;
  540. }
  541. }
  542. }
  543. if ( base == NULL ) {
  544. return "no base block found for memory";
  545. }
  546. */
  547. return NULL;
  548. }
  549. template<class type, int baseBlockSize, int minBlockSize>
  550. void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::Clear( void ) {
  551. firstBlock = lastBlock = NULL;
  552. allowAllocs = true;
  553. lockMemory = false;
  554. numBaseBlocks = 0;
  555. baseBlockMemory = 0;
  556. numUsedBlocks = 0;
  557. usedBlockMemory = 0;
  558. numFreeBlocks = 0;
  559. freeBlockMemory = 0;
  560. numAllocs = 0;
  561. numResizes = 0;
  562. numFrees = 0;
  563. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  564. blockId[0] = 0x11111111;
  565. blockId[1] = 0x22222222;
  566. blockId[2] = 0x33333333;
  567. #endif
  568. }
  569. template<class type, int baseBlockSize, int minBlockSize>
  570. idDynamicBlock<type> *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::AllocInternal( const int num ) {
  571. idDynamicBlock<type> *block;
  572. int alignedBytes = ( num * sizeof( type ) + 15 ) & ~15;
  573. block = freeTree.FindSmallestLargerEqual( alignedBytes );
  574. if ( block != NULL ) {
  575. UnlinkFreeInternal( block );
  576. } else if ( allowAllocs ) {
  577. int allocSize = Max( baseBlockSize, alignedBytes + (int)sizeof( idDynamicBlock<type> ) );
  578. block = ( idDynamicBlock<type> * ) Mem_Alloc16( allocSize );
  579. if ( lockMemory ) {
  580. idLib::sys->LockMemory( block, baseBlockSize );
  581. }
  582. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  583. memcpy( block->id, blockId, sizeof( block->id ) );
  584. block->allocator = (void*)this;
  585. #endif
  586. block->SetSize( allocSize - (int)sizeof( idDynamicBlock<type> ), true );
  587. block->next = NULL;
  588. block->prev = lastBlock;
  589. if ( lastBlock ) {
  590. lastBlock->next = block;
  591. } else {
  592. firstBlock = block;
  593. }
  594. lastBlock = block;
  595. block->node = NULL;
  596. numBaseBlocks++;
  597. baseBlockMemory += allocSize;
  598. }
  599. return block;
  600. }
  601. template<class type, int baseBlockSize, int minBlockSize>
  602. idDynamicBlock<type> *idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::ResizeInternal( idDynamicBlock<type> *block, const int num ) {
  603. int alignedBytes = ( num * sizeof( type ) + 15 ) & ~15;
  604. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  605. assert( block->id[0] == 0x11111111 && block->id[1] == 0x22222222 && block->id[2] == 0x33333333 && block->allocator == (void*)this );
  606. #endif
  607. // if the new size is larger
  608. if ( alignedBytes > block->GetSize() ) {
  609. idDynamicBlock<type> *nextBlock = block->next;
  610. // try to annexate the next block if it's free
  611. if ( nextBlock && !nextBlock->IsBaseBlock() && nextBlock->node != NULL &&
  612. block->GetSize() + (int)sizeof( idDynamicBlock<type> ) + nextBlock->GetSize() >= alignedBytes ) {
  613. UnlinkFreeInternal( nextBlock );
  614. block->SetSize( block->GetSize() + (int)sizeof( idDynamicBlock<type> ) + nextBlock->GetSize(), block->IsBaseBlock() );
  615. block->next = nextBlock->next;
  616. if ( nextBlock->next ) {
  617. nextBlock->next->prev = block;
  618. } else {
  619. lastBlock = block;
  620. }
  621. } else {
  622. // allocate a new block and copy
  623. idDynamicBlock<type> *oldBlock = block;
  624. block = AllocInternal( num );
  625. if ( block == NULL ) {
  626. return NULL;
  627. }
  628. memcpy( block->GetMemory(), oldBlock->GetMemory(), oldBlock->GetSize() );
  629. FreeInternal( oldBlock );
  630. }
  631. }
  632. // if the unused space at the end of this block is large enough to hold a block with at least one element
  633. if ( block->GetSize() - alignedBytes - (int)sizeof( idDynamicBlock<type> ) < Max( minBlockSize, (int)sizeof( type ) ) ) {
  634. return block;
  635. }
  636. idDynamicBlock<type> *newBlock;
  637. newBlock = ( idDynamicBlock<type> * ) ( ( (byte *) block ) + (int)sizeof( idDynamicBlock<type> ) + alignedBytes );
  638. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  639. memcpy( newBlock->id, blockId, sizeof( newBlock->id ) );
  640. newBlock->allocator = (void*)this;
  641. #endif
  642. newBlock->SetSize( block->GetSize() - alignedBytes - (int)sizeof( idDynamicBlock<type> ), false );
  643. newBlock->next = block->next;
  644. newBlock->prev = block;
  645. if ( newBlock->next ) {
  646. newBlock->next->prev = newBlock;
  647. } else {
  648. lastBlock = newBlock;
  649. }
  650. newBlock->node = NULL;
  651. block->next = newBlock;
  652. block->SetSize( alignedBytes, block->IsBaseBlock() );
  653. FreeInternal( newBlock );
  654. return block;
  655. }
  656. template<class type, int baseBlockSize, int minBlockSize>
  657. void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::FreeInternal( idDynamicBlock<type> *block ) {
  658. assert( block->node == NULL );
  659. #ifdef DYNAMIC_BLOCK_ALLOC_CHECK
  660. assert( block->id[0] == 0x11111111 && block->id[1] == 0x22222222 && block->id[2] == 0x33333333 && block->allocator == (void*)this );
  661. #endif
  662. // try to merge with a next free block
  663. idDynamicBlock<type> *nextBlock = block->next;
  664. if ( nextBlock && !nextBlock->IsBaseBlock() && nextBlock->node != NULL ) {
  665. UnlinkFreeInternal( nextBlock );
  666. block->SetSize( block->GetSize() + (int)sizeof( idDynamicBlock<type> ) + nextBlock->GetSize(), block->IsBaseBlock() );
  667. block->next = nextBlock->next;
  668. if ( nextBlock->next ) {
  669. nextBlock->next->prev = block;
  670. } else {
  671. lastBlock = block;
  672. }
  673. }
  674. // try to merge with a previous free block
  675. idDynamicBlock<type> *prevBlock = block->prev;
  676. if ( prevBlock && !block->IsBaseBlock() && prevBlock->node != NULL ) {
  677. UnlinkFreeInternal( prevBlock );
  678. prevBlock->SetSize( prevBlock->GetSize() + (int)sizeof( idDynamicBlock<type> ) + block->GetSize(), prevBlock->IsBaseBlock() );
  679. prevBlock->next = block->next;
  680. if ( block->next ) {
  681. block->next->prev = prevBlock;
  682. } else {
  683. lastBlock = prevBlock;
  684. }
  685. LinkFreeInternal( prevBlock );
  686. } else {
  687. LinkFreeInternal( block );
  688. }
  689. }
  690. template<class type, int baseBlockSize, int minBlockSize>
  691. ID_INLINE void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::LinkFreeInternal( idDynamicBlock<type> *block ) {
  692. block->node = freeTree.Add( block, block->GetSize() );
  693. numFreeBlocks++;
  694. freeBlockMemory += block->GetSize();
  695. }
  696. template<class type, int baseBlockSize, int minBlockSize>
  697. ID_INLINE void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::UnlinkFreeInternal( idDynamicBlock<type> *block ) {
  698. freeTree.Remove( block->node );
  699. block->node = NULL;
  700. numFreeBlocks--;
  701. freeBlockMemory -= block->GetSize();
  702. }
  703. template<class type, int baseBlockSize, int minBlockSize>
  704. void idDynamicBlockAlloc<type, baseBlockSize, minBlockSize>::CheckMemory( void ) const {
  705. idDynamicBlock<type> *block;
  706. for ( block = firstBlock; block != NULL; block = block->next ) {
  707. // make sure the block is properly linked
  708. if ( block->prev == NULL ) {
  709. assert( firstBlock == block );
  710. } else {
  711. assert( block->prev->next == block );
  712. }
  713. if ( block->next == NULL ) {
  714. assert( lastBlock == block );
  715. } else {
  716. assert( block->next->prev == block );
  717. }
  718. }
  719. }
  720. #endif /* !__HEAP_H__ */