Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1090 lines
31 KiB

  1. //===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. // A growable memory class.
  8. //===========================================================================//
  9. #ifndef UTLMEMORY_H
  10. #define UTLMEMORY_H
  11. #ifdef _WIN32
  12. #pragma once
  13. #endif
  14. #include "tier0/dbg.h"
  15. #include <string.h>
  16. #include "tier0/platform.h"
  17. #include "tier0/memalloc.h"
  18. #include "mathlib/mathlib.h"
  19. #include "tier0/memdbgon.h"
  20. #pragma warning (disable:4100)
  21. #pragma warning (disable:4514)
  22. //-----------------------------------------------------------------------------
  23. #ifdef UTLMEMORY_TRACK
  24. #define UTLMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "||Sum of all UtlMemory||", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 )
  25. #define UTLMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "||Sum of all UtlMemory||", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 )
  26. #else
  27. #define UTLMEMORY_TRACK_ALLOC() ((void)0)
  28. #define UTLMEMORY_TRACK_FREE() ((void)0)
  29. #endif
  30. //-----------------------------------------------------------------------------
  31. // The CUtlMemory class:
  32. // A growable memory class which doubles in size by default.
  33. //-----------------------------------------------------------------------------
  34. template< class T, class I = int >
  35. class CUtlMemory
  36. {
  37. public:
  38. // constructor, destructor
  39. CUtlMemory( int nGrowSize = 0, int nInitSize = 0 );
  40. CUtlMemory( T* pMemory, int numElements );
  41. CUtlMemory( const T* pMemory, int numElements );
  42. ~CUtlMemory();
  43. // Set the size by which the memory grows
  44. void Init( int nGrowSize = 0, int nInitSize = 0 );
  45. class Iterator_t
  46. {
  47. public:
  48. Iterator_t( I i ) : index( i ) {}
  49. I index;
  50. bool operator==( const Iterator_t it ) const { return index == it.index; }
  51. bool operator!=( const Iterator_t it ) const { return index != it.index; }
  52. };
  53. Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); }
  54. Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); }
  55. I GetIndex( const Iterator_t &it ) const { return it.index; }
  56. bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; }
  57. bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); }
  58. Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); }
  59. // element access
  60. T& operator[]( I i );
  61. const T& operator[]( I i ) const;
  62. T& Element( I i );
  63. const T& Element( I i ) const;
  64. // Can we use this index?
  65. bool IsIdxValid( I i ) const;
  66. // Specify the invalid ('null') index that we'll only return on failure
  67. static const I INVALID_INDEX = ( I )-1; // For use with COMPILE_TIME_ASSERT
  68. static I InvalidIndex() { return INVALID_INDEX; }
  69. // Gets the base address (can change when adding elements!)
  70. T* Base();
  71. const T* Base() const;
  72. // Attaches the buffer to external memory....
  73. void SetExternalBuffer( T* pMemory, int numElements );
  74. void SetExternalBuffer( const T* pMemory, int numElements );
  75. void AssumeMemory( T *pMemory, int nSize );
  76. T* Detach();
  77. void *DetachMemory();
  78. // Fast swap
  79. void Swap( CUtlMemory< T, I > &mem );
  80. // Switches the buffer from an external memory buffer to a reallocatable buffer
  81. // Will copy the current contents of the external buffer to the reallocatable buffer
  82. void ConvertToGrowableMemory( int nGrowSize );
  83. // Size
  84. int NumAllocated() const;
  85. int Count() const;
  86. // Grows the memory, so that at least allocated + num elements are allocated
  87. void Grow( int num = 1 );
  88. // Makes sure we've got at least this much memory
  89. void EnsureCapacity( int num );
  90. // Memory deallocation
  91. void Purge();
  92. // Purge all but the given number of elements
  93. void Purge( int numElements );
  94. // is the memory externally allocated?
  95. bool IsExternallyAllocated() const;
  96. // is the memory read only?
  97. bool IsReadOnly() const;
  98. // Set the size by which the memory grows
  99. void SetGrowSize( int size );
  100. protected:
  101. void ValidateGrowSize()
  102. {
  103. #ifdef _X360
  104. if ( m_nGrowSize && m_nGrowSize != EXTERNAL_BUFFER_MARKER )
  105. {
  106. // Max grow size at 128 bytes on XBOX
  107. const int MAX_GROW = 128;
  108. if ( m_nGrowSize * sizeof(T) > MAX_GROW )
  109. {
  110. m_nGrowSize = max( 1, MAX_GROW / sizeof(T) );
  111. }
  112. }
  113. #endif
  114. }
  115. enum
  116. {
  117. EXTERNAL_BUFFER_MARKER = -1,
  118. EXTERNAL_CONST_BUFFER_MARKER = -2,
  119. };
  120. T* m_pMemory;
  121. int m_nAllocationCount;
  122. int m_nGrowSize;
  123. };
  124. //-----------------------------------------------------------------------------
  125. // The CUtlMemory class:
  126. // A growable memory class which doubles in size by default.
  127. //-----------------------------------------------------------------------------
  128. template< class T, size_t SIZE, class I = int >
  129. class CUtlMemoryFixedGrowable : public CUtlMemory< T, I >
  130. {
  131. typedef CUtlMemory< T, I > BaseClass;
  132. public:
  133. CUtlMemoryFixedGrowable( int nGrowSize = 0, int nInitSize = SIZE ) : BaseClass( m_pFixedMemory, SIZE )
  134. {
  135. Assert( nInitSize == 0 || nInitSize == SIZE );
  136. m_nMallocGrowSize = nGrowSize;
  137. }
  138. void Grow( int nCount = 1 )
  139. {
  140. if ( this->IsExternallyAllocated() )
  141. {
  142. this->ConvertToGrowableMemory( m_nMallocGrowSize );
  143. }
  144. BaseClass::Grow( nCount );
  145. }
  146. void EnsureCapacity( int num )
  147. {
  148. if ( CUtlMemory<T>::m_nAllocationCount >= num )
  149. return;
  150. if ( this->IsExternallyAllocated() )
  151. {
  152. // Can't grow a buffer whose memory was externally allocated
  153. this->ConvertToGrowableMemory( m_nMallocGrowSize );
  154. }
  155. BaseClass::EnsureCapacity( num );
  156. }
  157. private:
  158. int m_nMallocGrowSize;
  159. T m_pFixedMemory[ SIZE ];
  160. };
  161. //-----------------------------------------------------------------------------
  162. // The CUtlMemoryFixed class:
  163. // A fixed memory class
  164. //-----------------------------------------------------------------------------
  165. template< typename T, size_t SIZE, int nAlignment = 0 >
  166. class CUtlMemoryFixed
  167. {
  168. public:
  169. // constructor, destructor
  170. CUtlMemoryFixed( int nGrowSize = 0, int nInitSize = 0 ) { Assert( nInitSize == 0 || nInitSize == SIZE ); }
  171. CUtlMemoryFixed( T* pMemory, int numElements ) { Assert( 0 ); }
  172. // Can we use this index?
  173. bool IsIdxValid( int i ) const { return (i >= 0) && (i < SIZE); }
  174. // Specify the invalid ('null') index that we'll only return on failure
  175. static const int INVALID_INDEX = -1; // For use with COMPILE_TIME_ASSERT
  176. static int InvalidIndex() { return INVALID_INDEX; }
  177. // Gets the base address
  178. T* Base() { if ( nAlignment == 0 ) return (T*)(&m_Memory[0]); else return (T*)AlignValue( &m_Memory[0], nAlignment ); }
  179. const T* Base() const { if ( nAlignment == 0 ) return (T*)(&m_Memory[0]); else return (T*)AlignValue( &m_Memory[0], nAlignment ); }
  180. // element access
  181. T& operator[]( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
  182. const T& operator[]( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
  183. T& Element( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
  184. const T& Element( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
  185. // Attaches the buffer to external memory....
  186. void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); }
  187. // Size
  188. int NumAllocated() const { return SIZE; }
  189. int Count() const { return SIZE; }
  190. // Grows the memory, so that at least allocated + num elements are allocated
  191. void Grow( int num = 1 ) { Assert( 0 ); }
  192. // Makes sure we've got at least this much memory
  193. void EnsureCapacity( int num ) { Assert( num <= SIZE ); }
  194. // Memory deallocation
  195. void Purge() {}
  196. // Purge all but the given number of elements (NOT IMPLEMENTED IN CUtlMemoryFixed)
  197. void Purge( int numElements ) { Assert( 0 ); }
  198. // is the memory externally allocated?
  199. bool IsExternallyAllocated() const { return false; }
  200. // Set the size by which the memory grows
  201. void SetGrowSize( int size ) {}
  202. class Iterator_t
  203. {
  204. public:
  205. Iterator_t( int i ) : index( i ) {}
  206. int index;
  207. bool operator==( const Iterator_t it ) const { return index == it.index; }
  208. bool operator!=( const Iterator_t it ) const { return index != it.index; }
  209. };
  210. Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); }
  211. Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); }
  212. int GetIndex( const Iterator_t &it ) const { return it.index; }
  213. bool IsIdxAfter( int i, const Iterator_t &it ) const { return i > it.index; }
  214. bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); }
  215. Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); }
  216. private:
  217. char m_Memory[ SIZE*sizeof(T) + nAlignment ];
  218. };
  219. #ifdef _LINUX
  220. #define REMEMBER_ALLOC_SIZE_FOR_VALGRIND 1
  221. #endif
  222. //-----------------------------------------------------------------------------
  223. // The CUtlMemoryConservative class:
  224. // A dynamic memory class that tries to minimize overhead (itself small, no custom grow factor)
  225. //-----------------------------------------------------------------------------
  226. template< typename T >
  227. class CUtlMemoryConservative
  228. {
  229. public:
  230. // constructor, destructor
  231. CUtlMemoryConservative( int nGrowSize = 0, int nInitSize = 0 ) : m_pMemory( NULL )
  232. {
  233. #ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND
  234. m_nCurAllocSize = 0;
  235. #endif
  236. }
  237. CUtlMemoryConservative( T* pMemory, int numElements ) { Assert( 0 ); }
  238. ~CUtlMemoryConservative() { if ( m_pMemory ) free( m_pMemory ); }
  239. // Can we use this index?
  240. bool IsIdxValid( int i ) const { return ( IsDebug() ) ? ( i >= 0 && i < NumAllocated() ) : ( i >= 0 ); }
  241. static int InvalidIndex() { return -1; }
  242. // Gets the base address
  243. T* Base() { return m_pMemory; }
  244. const T* Base() const { return m_pMemory; }
  245. // element access
  246. T& operator[]( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
  247. const T& operator[]( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
  248. T& Element( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
  249. const T& Element( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
  250. // Attaches the buffer to external memory....
  251. void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); }
  252. // Size
  253. FORCEINLINE void RememberAllocSize( size_t sz )
  254. {
  255. #ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND
  256. m_nCurAllocSize = sz;
  257. #endif
  258. }
  259. size_t AllocSize( void ) const
  260. {
  261. #ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND
  262. return m_nCurAllocSize;
  263. #else
  264. return ( m_pMemory ) ? g_pMemAlloc->GetSize( m_pMemory ) : 0;
  265. #endif
  266. }
  267. int NumAllocated() const
  268. {
  269. return AllocSize() / sizeof( T );
  270. }
  271. int Count() const
  272. {
  273. return NumAllocated();
  274. }
  275. FORCEINLINE void ReAlloc( size_t sz )
  276. {
  277. m_pMemory = (T*)realloc( m_pMemory, sz );
  278. RememberAllocSize( sz );
  279. }
  280. // Grows the memory, so that at least allocated + num elements are allocated
  281. void Grow( int num = 1 )
  282. {
  283. int nCurN = NumAllocated();
  284. ReAlloc( ( nCurN + num ) * sizeof( T ) );
  285. }
  286. // Makes sure we've got at least this much memory
  287. void EnsureCapacity( int num )
  288. {
  289. size_t nSize = sizeof( T ) * MAX( num, Count() );
  290. ReAlloc( nSize );
  291. }
  292. // Memory deallocation
  293. void Purge()
  294. {
  295. free( m_pMemory );
  296. RememberAllocSize( 0 );
  297. m_pMemory = NULL;
  298. }
  299. // Purge all but the given number of elements
  300. void Purge( int numElements ) { ReAlloc( numElements * sizeof(T) ); }
  301. // is the memory externally allocated?
  302. bool IsExternallyAllocated() const { return false; }
  303. // Set the size by which the memory grows
  304. void SetGrowSize( int size ) {}
  305. class Iterator_t
  306. {
  307. public:
  308. Iterator_t( int i, int _limit ) : index( i ), limit( _limit ) {}
  309. int index;
  310. int limit;
  311. bool operator==( const Iterator_t it ) const { return index == it.index; }
  312. bool operator!=( const Iterator_t it ) const { return index != it.index; }
  313. };
  314. Iterator_t First() const { int limit = NumAllocated(); return Iterator_t( limit ? 0 : InvalidIndex(), limit ); }
  315. Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( ( it.index + 1 < it.limit ) ? it.index + 1 : InvalidIndex(), it.limit ); }
  316. int GetIndex( const Iterator_t &it ) const { return it.index; }
  317. bool IsIdxAfter( int i, const Iterator_t &it ) const { return i > it.index; }
  318. bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ) && ( it.index < it.limit ); }
  319. Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex(), 0 ); }
  320. private:
  321. T *m_pMemory;
  322. #ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND
  323. size_t m_nCurAllocSize;
  324. #endif
  325. };
  326. //-----------------------------------------------------------------------------
  327. // constructor, destructor
  328. //-----------------------------------------------------------------------------
  329. template< class T, class I >
  330. CUtlMemory<T,I>::CUtlMemory( int nGrowSize, int nInitAllocationCount ) : m_pMemory(0),
  331. m_nAllocationCount( nInitAllocationCount ), m_nGrowSize( nGrowSize )
  332. {
  333. ValidateGrowSize();
  334. Assert( nGrowSize >= 0 );
  335. if (m_nAllocationCount)
  336. {
  337. UTLMEMORY_TRACK_ALLOC();
  338. MEM_ALLOC_CREDIT_CLASS();
  339. m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) );
  340. }
  341. }
  342. template< class T, class I >
  343. CUtlMemory<T,I>::CUtlMemory( T* pMemory, int numElements ) : m_pMemory(pMemory),
  344. m_nAllocationCount( numElements )
  345. {
  346. // Special marker indicating externally supplied modifyable memory
  347. m_nGrowSize = EXTERNAL_BUFFER_MARKER;
  348. }
  349. template< class T, class I >
  350. CUtlMemory<T,I>::CUtlMemory( const T* pMemory, int numElements ) : m_pMemory( (T*)pMemory ),
  351. m_nAllocationCount( numElements )
  352. {
  353. // Special marker indicating externally supplied modifyable memory
  354. m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER;
  355. }
  356. template< class T, class I >
  357. CUtlMemory<T,I>::~CUtlMemory()
  358. {
  359. Purge();
  360. #ifdef _DEBUG
  361. m_pMemory = reinterpret_cast< T* >( 0xFEFEBAAD );
  362. m_nAllocationCount = 0x7BADF00D;
  363. #endif
  364. }
  365. template< class T, class I >
  366. void CUtlMemory<T,I>::Init( int nGrowSize /*= 0*/, int nInitSize /*= 0*/ )
  367. {
  368. Purge();
  369. m_nGrowSize = nGrowSize;
  370. m_nAllocationCount = nInitSize;
  371. ValidateGrowSize();
  372. Assert( nGrowSize >= 0 );
  373. if (m_nAllocationCount)
  374. {
  375. UTLMEMORY_TRACK_ALLOC();
  376. MEM_ALLOC_CREDIT_CLASS();
  377. m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) );
  378. }
  379. }
  380. //-----------------------------------------------------------------------------
  381. // Fast swap
  382. //-----------------------------------------------------------------------------
  383. template< class T, class I >
  384. void CUtlMemory<T,I>::Swap( CUtlMemory<T,I> &mem )
  385. {
  386. V_swap( m_nGrowSize, mem.m_nGrowSize );
  387. V_swap( m_pMemory, mem.m_pMemory );
  388. V_swap( m_nAllocationCount, mem.m_nAllocationCount );
  389. }
  390. //-----------------------------------------------------------------------------
  391. // Switches the buffer from an external memory buffer to a reallocatable buffer
  392. //-----------------------------------------------------------------------------
  393. template< class T, class I >
  394. void CUtlMemory<T,I>::ConvertToGrowableMemory( int nGrowSize )
  395. {
  396. if ( !IsExternallyAllocated() )
  397. return;
  398. m_nGrowSize = nGrowSize;
  399. if (m_nAllocationCount)
  400. {
  401. UTLMEMORY_TRACK_ALLOC();
  402. MEM_ALLOC_CREDIT_CLASS();
  403. int nNumBytes = m_nAllocationCount * sizeof(T);
  404. T *pMemory = (T*)malloc( nNumBytes );
  405. memcpy( pMemory, m_pMemory, nNumBytes );
  406. m_pMemory = pMemory;
  407. }
  408. else
  409. {
  410. m_pMemory = NULL;
  411. }
  412. }
  413. //-----------------------------------------------------------------------------
  414. // Attaches the buffer to external memory....
  415. //-----------------------------------------------------------------------------
  416. template< class T, class I >
  417. void CUtlMemory<T,I>::SetExternalBuffer( T* pMemory, int numElements )
  418. {
  419. // Blow away any existing allocated memory
  420. Purge();
  421. m_pMemory = pMemory;
  422. m_nAllocationCount = numElements;
  423. // Indicate that we don't own the memory
  424. m_nGrowSize = EXTERNAL_BUFFER_MARKER;
  425. }
  426. template< class T, class I >
  427. void CUtlMemory<T,I>::SetExternalBuffer( const T* pMemory, int numElements )
  428. {
  429. // Blow away any existing allocated memory
  430. Purge();
  431. m_pMemory = const_cast<T*>( pMemory );
  432. m_nAllocationCount = numElements;
  433. // Indicate that we don't own the memory
  434. m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER;
  435. }
  436. template< class T, class I >
  437. void CUtlMemory<T,I>::AssumeMemory( T* pMemory, int numElements )
  438. {
  439. // Blow away any existing allocated memory
  440. Purge();
  441. // Simply take the pointer but don't mark us as external
  442. m_pMemory = pMemory;
  443. m_nAllocationCount = numElements;
  444. }
  445. template< class T, class I >
  446. void *CUtlMemory<T,I>::DetachMemory()
  447. {
  448. if ( IsExternallyAllocated() )
  449. return NULL;
  450. void *pMemory = m_pMemory;
  451. m_pMemory = 0;
  452. m_nAllocationCount = 0;
  453. return pMemory;
  454. }
  455. template< class T, class I >
  456. inline T* CUtlMemory<T,I>::Detach()
  457. {
  458. return (T*)DetachMemory();
  459. }
  460. //-----------------------------------------------------------------------------
  461. // element access
  462. //-----------------------------------------------------------------------------
  463. template< class T, class I >
  464. inline T& CUtlMemory<T,I>::operator[]( I i )
  465. {
  466. Assert( !IsReadOnly() );
  467. Assert( IsIdxValid(i) );
  468. return m_pMemory[i];
  469. }
  470. template< class T, class I >
  471. inline const T& CUtlMemory<T,I>::operator[]( I i ) const
  472. {
  473. Assert( IsIdxValid(i) );
  474. return m_pMemory[i];
  475. }
  476. template< class T, class I >
  477. inline T& CUtlMemory<T,I>::Element( I i )
  478. {
  479. Assert( !IsReadOnly() );
  480. Assert( IsIdxValid(i) );
  481. return m_pMemory[i];
  482. }
  483. template< class T, class I >
  484. inline const T& CUtlMemory<T,I>::Element( I i ) const
  485. {
  486. Assert( IsIdxValid(i) );
  487. return m_pMemory[i];
  488. }
  489. //-----------------------------------------------------------------------------
  490. // is the memory externally allocated?
  491. //-----------------------------------------------------------------------------
  492. template< class T, class I >
  493. bool CUtlMemory<T,I>::IsExternallyAllocated() const
  494. {
  495. return (m_nGrowSize < 0);
  496. }
  497. //-----------------------------------------------------------------------------
  498. // is the memory read only?
  499. //-----------------------------------------------------------------------------
  500. template< class T, class I >
  501. bool CUtlMemory<T,I>::IsReadOnly() const
  502. {
  503. return (m_nGrowSize == EXTERNAL_CONST_BUFFER_MARKER);
  504. }
  505. template< class T, class I >
  506. void CUtlMemory<T,I>::SetGrowSize( int nSize )
  507. {
  508. Assert( !IsExternallyAllocated() );
  509. Assert( nSize >= 0 );
  510. m_nGrowSize = nSize;
  511. ValidateGrowSize();
  512. }
  513. //-----------------------------------------------------------------------------
  514. // Gets the base address (can change when adding elements!)
  515. //-----------------------------------------------------------------------------
  516. template< class T, class I >
  517. inline T* CUtlMemory<T,I>::Base()
  518. {
  519. Assert( !IsReadOnly() );
  520. return m_pMemory;
  521. }
  522. template< class T, class I >
  523. inline const T *CUtlMemory<T,I>::Base() const
  524. {
  525. return m_pMemory;
  526. }
  527. //-----------------------------------------------------------------------------
  528. // Size
  529. //-----------------------------------------------------------------------------
  530. template< class T, class I >
  531. inline int CUtlMemory<T,I>::NumAllocated() const
  532. {
  533. return m_nAllocationCount;
  534. }
  535. template< class T, class I >
  536. inline int CUtlMemory<T,I>::Count() const
  537. {
  538. return m_nAllocationCount;
  539. }
  540. //-----------------------------------------------------------------------------
  541. // Is element index valid?
  542. //-----------------------------------------------------------------------------
  543. template< class T, class I >
  544. inline bool CUtlMemory<T,I>::IsIdxValid( I i ) const
  545. {
  546. // GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0).
  547. // We get the warning even if we cast inside the expression. It only goes away if we assign to another variable.
  548. long x = i;
  549. return ( x >= 0 ) && ( x < m_nAllocationCount );
  550. }
  551. //-----------------------------------------------------------------------------
  552. // Grows the memory
  553. //-----------------------------------------------------------------------------
  554. inline int UtlMemory_CalcNewAllocationCount( int nAllocationCount, int nGrowSize, int nNewSize, int nBytesItem )
  555. {
  556. if ( nGrowSize )
  557. {
  558. nAllocationCount = ((1 + ((nNewSize - 1) / nGrowSize)) * nGrowSize);
  559. }
  560. else
  561. {
  562. if ( !nAllocationCount )
  563. {
  564. // Compute an allocation which is at least as big as a cache line...
  565. nAllocationCount = (31 + nBytesItem) / nBytesItem;
  566. }
  567. while (nAllocationCount < nNewSize)
  568. {
  569. #ifndef _X360
  570. nAllocationCount *= 2;
  571. #else
  572. int nNewAllocationCount = ( nAllocationCount * 9) / 8; // 12.5 %
  573. if ( nNewAllocationCount > nAllocationCount )
  574. nAllocationCount = nNewAllocationCount;
  575. else
  576. nAllocationCount *= 2;
  577. #endif
  578. }
  579. }
  580. return nAllocationCount;
  581. }
  582. template< class T, class I >
  583. void CUtlMemory<T,I>::Grow( int num )
  584. {
  585. Assert( num > 0 );
  586. if ( IsExternallyAllocated() )
  587. {
  588. // Can't grow a buffer whose memory was externally allocated
  589. Assert(0);
  590. return;
  591. }
  592. // Make sure we have at least numallocated + num allocations.
  593. // Use the grow rules specified for this memory (in m_nGrowSize)
  594. int nAllocationRequested = m_nAllocationCount + num;
  595. UTLMEMORY_TRACK_FREE();
  596. int nNewAllocationCount = UtlMemory_CalcNewAllocationCount( m_nAllocationCount, m_nGrowSize, nAllocationRequested, sizeof(T) );
  597. // if m_nAllocationRequested wraps index type I, recalculate
  598. if ( ( int )( I )nNewAllocationCount < nAllocationRequested )
  599. {
  600. if ( ( int )( I )nNewAllocationCount == 0 && ( int )( I )( nNewAllocationCount - 1 ) >= nAllocationRequested )
  601. {
  602. --nNewAllocationCount; // deal w/ the common case of m_nAllocationCount == MAX_USHORT + 1
  603. }
  604. else
  605. {
  606. if ( ( int )( I )nAllocationRequested != nAllocationRequested )
  607. {
  608. // we've been asked to grow memory to a size s.t. the index type can't address the requested amount of memory
  609. Assert( 0 );
  610. return;
  611. }
  612. while ( ( int )( I )nNewAllocationCount < nAllocationRequested )
  613. {
  614. nNewAllocationCount = ( nNewAllocationCount + nAllocationRequested ) / 2;
  615. }
  616. }
  617. }
  618. m_nAllocationCount = nNewAllocationCount;
  619. UTLMEMORY_TRACK_ALLOC();
  620. if (m_pMemory)
  621. {
  622. MEM_ALLOC_CREDIT_CLASS();
  623. m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) );
  624. Assert( m_pMemory );
  625. }
  626. else
  627. {
  628. MEM_ALLOC_CREDIT_CLASS();
  629. m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) );
  630. Assert( m_pMemory );
  631. }
  632. }
  633. //-----------------------------------------------------------------------------
  634. // Makes sure we've got at least this much memory
  635. //-----------------------------------------------------------------------------
  636. template< class T, class I >
  637. inline void CUtlMemory<T,I>::EnsureCapacity( int num )
  638. {
  639. if (m_nAllocationCount >= num)
  640. return;
  641. if ( IsExternallyAllocated() )
  642. {
  643. // Can't grow a buffer whose memory was externally allocated
  644. Assert(0);
  645. return;
  646. }
  647. UTLMEMORY_TRACK_FREE();
  648. m_nAllocationCount = num;
  649. UTLMEMORY_TRACK_ALLOC();
  650. if (m_pMemory)
  651. {
  652. MEM_ALLOC_CREDIT_CLASS();
  653. m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) );
  654. }
  655. else
  656. {
  657. MEM_ALLOC_CREDIT_CLASS();
  658. m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) );
  659. }
  660. }
  661. //-----------------------------------------------------------------------------
  662. // Memory deallocation
  663. //-----------------------------------------------------------------------------
  664. template< class T, class I >
  665. void CUtlMemory<T,I>::Purge()
  666. {
  667. if ( !IsExternallyAllocated() )
  668. {
  669. if (m_pMemory)
  670. {
  671. UTLMEMORY_TRACK_FREE();
  672. free( (void*)m_pMemory );
  673. m_pMemory = 0;
  674. }
  675. m_nAllocationCount = 0;
  676. }
  677. }
  678. template< class T, class I >
  679. void CUtlMemory<T,I>::Purge( int numElements )
  680. {
  681. Assert( numElements >= 0 );
  682. if( numElements > m_nAllocationCount )
  683. {
  684. // Ensure this isn't a grow request in disguise.
  685. Assert( numElements <= m_nAllocationCount );
  686. return;
  687. }
  688. // If we have zero elements, simply do a purge:
  689. if( numElements == 0 )
  690. {
  691. Purge();
  692. return;
  693. }
  694. if ( IsExternallyAllocated() )
  695. {
  696. // Can't shrink a buffer whose memory was externally allocated, fail silently like purge
  697. return;
  698. }
  699. // If the number of elements is the same as the allocation count, we are done.
  700. if( numElements == m_nAllocationCount )
  701. {
  702. return;
  703. }
  704. if( !m_pMemory )
  705. {
  706. // Allocation count is non zero, but memory is null.
  707. Assert( m_pMemory );
  708. return;
  709. }
  710. UTLMEMORY_TRACK_FREE();
  711. m_nAllocationCount = numElements;
  712. UTLMEMORY_TRACK_ALLOC();
  713. // Allocation count > 0, shrink it down.
  714. MEM_ALLOC_CREDIT_CLASS();
  715. m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) );
  716. }
  717. //-----------------------------------------------------------------------------
  718. // The CUtlMemory class:
  719. // A growable memory class which doubles in size by default.
  720. //-----------------------------------------------------------------------------
  721. template< class T, int nAlignment >
  722. class CUtlMemoryAligned : public CUtlMemory<T>
  723. {
  724. public:
  725. // constructor, destructor
  726. CUtlMemoryAligned( int nGrowSize = 0, int nInitSize = 0 );
  727. CUtlMemoryAligned( T* pMemory, int numElements );
  728. CUtlMemoryAligned( const T* pMemory, int numElements );
  729. ~CUtlMemoryAligned();
  730. // Attaches the buffer to external memory....
  731. void SetExternalBuffer( T* pMemory, int numElements );
  732. void SetExternalBuffer( const T* pMemory, int numElements );
  733. // Grows the memory, so that at least allocated + num elements are allocated
  734. void Grow( int num = 1 );
  735. // Makes sure we've got at least this much memory
  736. void EnsureCapacity( int num );
  737. // Memory deallocation
  738. void Purge();
  739. // Purge all but the given number of elements (NOT IMPLEMENTED IN CUtlMemoryAligned)
  740. void Purge( int numElements ) { Assert( 0 ); }
  741. private:
  742. void *Align( const void *pAddr );
  743. };
  744. //-----------------------------------------------------------------------------
  745. // Aligns a pointer
  746. //-----------------------------------------------------------------------------
  747. template< class T, int nAlignment >
  748. void *CUtlMemoryAligned<T, nAlignment>::Align( const void *pAddr )
  749. {
  750. size_t nAlignmentMask = nAlignment - 1;
  751. return (void*)( ((size_t)pAddr + nAlignmentMask) & (~nAlignmentMask) );
  752. }
  753. //-----------------------------------------------------------------------------
  754. // constructor, destructor
  755. //-----------------------------------------------------------------------------
  756. template< class T, int nAlignment >
  757. CUtlMemoryAligned<T, nAlignment>::CUtlMemoryAligned( int nGrowSize, int nInitAllocationCount )
  758. {
  759. CUtlMemory<T>::m_pMemory = 0;
  760. CUtlMemory<T>::m_nAllocationCount = nInitAllocationCount;
  761. CUtlMemory<T>::m_nGrowSize = nGrowSize;
  762. this->ValidateGrowSize();
  763. // Alignment must be a power of two
  764. COMPILE_TIME_ASSERT( (nAlignment & (nAlignment-1)) == 0 );
  765. Assert( (nGrowSize >= 0) && (nGrowSize != CUtlMemory<T>::EXTERNAL_BUFFER_MARKER) );
  766. if ( CUtlMemory<T>::m_nAllocationCount )
  767. {
  768. UTLMEMORY_TRACK_ALLOC();
  769. MEM_ALLOC_CREDIT_CLASS();
  770. CUtlMemory<T>::m_pMemory = (T*)_aligned_malloc( nInitAllocationCount * sizeof(T), nAlignment );
  771. }
  772. }
  773. template< class T, int nAlignment >
  774. CUtlMemoryAligned<T, nAlignment>::CUtlMemoryAligned( T* pMemory, int numElements )
  775. {
  776. // Special marker indicating externally supplied memory
  777. CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_BUFFER_MARKER;
  778. CUtlMemory<T>::m_pMemory = (T*)Align( pMemory );
  779. CUtlMemory<T>::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory ) / sizeof(T);
  780. }
  781. template< class T, int nAlignment >
  782. CUtlMemoryAligned<T, nAlignment>::CUtlMemoryAligned( const T* pMemory, int numElements )
  783. {
  784. // Special marker indicating externally supplied memory
  785. CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_CONST_BUFFER_MARKER;
  786. CUtlMemory<T>::m_pMemory = (T*)Align( pMemory );
  787. CUtlMemory<T>::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory ) / sizeof(T);
  788. }
  789. template< class T, int nAlignment >
  790. CUtlMemoryAligned<T, nAlignment>::~CUtlMemoryAligned()
  791. {
  792. Purge();
  793. }
  794. //-----------------------------------------------------------------------------
  795. // Attaches the buffer to external memory....
  796. //-----------------------------------------------------------------------------
  797. template< class T, int nAlignment >
  798. void CUtlMemoryAligned<T, nAlignment>::SetExternalBuffer( T* pMemory, int numElements )
  799. {
  800. // Blow away any existing allocated memory
  801. Purge();
  802. CUtlMemory<T>::m_pMemory = (T*)Align( pMemory );
  803. CUtlMemory<T>::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory ) / sizeof(T);
  804. // Indicate that we don't own the memory
  805. CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_BUFFER_MARKER;
  806. }
  807. template< class T, int nAlignment >
  808. void CUtlMemoryAligned<T, nAlignment>::SetExternalBuffer( const T* pMemory, int numElements )
  809. {
  810. // Blow away any existing allocated memory
  811. Purge();
  812. CUtlMemory<T>::m_pMemory = (T*)Align( pMemory );
  813. CUtlMemory<T>::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory ) / sizeof(T);
  814. // Indicate that we don't own the memory
  815. CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_CONST_BUFFER_MARKER;
  816. }
  817. //-----------------------------------------------------------------------------
  818. // Grows the memory
  819. //-----------------------------------------------------------------------------
  820. template< class T, int nAlignment >
  821. void CUtlMemoryAligned<T, nAlignment>::Grow( int num )
  822. {
  823. Assert( num > 0 );
  824. if ( this->IsExternallyAllocated() )
  825. {
  826. // Can't grow a buffer whose memory was externally allocated
  827. Assert(0);
  828. return;
  829. }
  830. UTLMEMORY_TRACK_FREE();
  831. // Make sure we have at least numallocated + num allocations.
  832. // Use the grow rules specified for this memory (in m_nGrowSize)
  833. int nAllocationRequested = CUtlMemory<T>::m_nAllocationCount + num;
  834. CUtlMemory<T>::m_nAllocationCount = UtlMemory_CalcNewAllocationCount( CUtlMemory<T>::m_nAllocationCount, CUtlMemory<T>::m_nGrowSize, nAllocationRequested, sizeof(T) );
  835. UTLMEMORY_TRACK_ALLOC();
  836. if ( CUtlMemory<T>::m_pMemory )
  837. {
  838. MEM_ALLOC_CREDIT_CLASS();
  839. CUtlMemory<T>::m_pMemory = (T*)MemAlloc_ReallocAligned( CUtlMemory<T>::m_pMemory, CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment );
  840. Assert( CUtlMemory<T>::m_pMemory );
  841. }
  842. else
  843. {
  844. MEM_ALLOC_CREDIT_CLASS();
  845. CUtlMemory<T>::m_pMemory = (T*)MemAlloc_AllocAligned( CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment );
  846. Assert( CUtlMemory<T>::m_pMemory );
  847. }
  848. }
  849. //-----------------------------------------------------------------------------
  850. // Makes sure we've got at least this much memory
  851. //-----------------------------------------------------------------------------
  852. template< class T, int nAlignment >
  853. inline void CUtlMemoryAligned<T, nAlignment>::EnsureCapacity( int num )
  854. {
  855. if ( CUtlMemory<T>::m_nAllocationCount >= num )
  856. return;
  857. if ( this->IsExternallyAllocated() )
  858. {
  859. // Can't grow a buffer whose memory was externally allocated
  860. Assert(0);
  861. return;
  862. }
  863. UTLMEMORY_TRACK_FREE();
  864. CUtlMemory<T>::m_nAllocationCount = num;
  865. UTLMEMORY_TRACK_ALLOC();
  866. if ( CUtlMemory<T>::m_pMemory )
  867. {
  868. MEM_ALLOC_CREDIT_CLASS();
  869. CUtlMemory<T>::m_pMemory = (T*)MemAlloc_ReallocAligned( CUtlMemory<T>::m_pMemory, CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment );
  870. }
  871. else
  872. {
  873. MEM_ALLOC_CREDIT_CLASS();
  874. CUtlMemory<T>::m_pMemory = (T*)MemAlloc_AllocAligned( CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment );
  875. }
  876. }
  877. //-----------------------------------------------------------------------------
  878. // Memory deallocation
  879. //-----------------------------------------------------------------------------
  880. template< class T, int nAlignment >
  881. void CUtlMemoryAligned<T, nAlignment>::Purge()
  882. {
  883. if ( !this->IsExternallyAllocated() )
  884. {
  885. if ( CUtlMemory<T>::m_pMemory )
  886. {
  887. UTLMEMORY_TRACK_FREE();
  888. MemAlloc_FreeAligned( CUtlMemory<T>::m_pMemory );
  889. CUtlMemory<T>::m_pMemory = 0;
  890. }
  891. CUtlMemory<T>::m_nAllocationCount = 0;
  892. }
  893. }
  894. #include "tier0/memdbgoff.h"
  895. #endif // UTLMEMORY_H