Counter Strike : Global Offensive Source Code
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.

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