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.

349 lines
9.7 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. // A growable memory class.
  8. //===========================================================================//
  9. #ifndef UTLBLOCKMEMORY_H
  10. #define UTLBLOCKMEMORY_H
  11. #ifdef _WIN32
  12. #pragma once
  13. #endif
  14. #include "tier0/dbg.h"
  15. #include "tier0/platform.h"
  16. #include "mathlib/mathlib.h"
  17. #include "tier0/memalloc.h"
  18. #include "tier0/memdbgon.h"
  19. #pragma warning (disable:4100)
  20. #pragma warning (disable:4514)
  21. //-----------------------------------------------------------------------------
  22. #ifdef UTBLOCKLMEMORY_TRACK
  23. #define UTLBLOCKMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "||Sum of all UtlBlockMemory||", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
  24. #define UTLBLOCKMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "||Sum of all UtlBlockMemory||", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
  25. #else
  26. #define UTLBLOCKMEMORY_TRACK_ALLOC() ((void)0)
  27. #define UTLBLOCKMEMORY_TRACK_FREE() ((void)0)
  28. #endif
  29. //-----------------------------------------------------------------------------
  30. // The CUtlBlockMemory class:
  31. // A growable memory class that allocates non-sequential blocks, but is indexed sequentially
  32. //-----------------------------------------------------------------------------
  33. template< class T, class I >
  34. class CUtlBlockMemory
  35. {
  36. public:
  37. // constructor, destructor
  38. CUtlBlockMemory( int nGrowSize = 0, int nInitSize = 0 );
  39. ~CUtlBlockMemory();
  40. // Set the size by which the memory grows - round up to the next power of 2
  41. void Init( int nGrowSize = 0, int nInitSize = 0 );
  42. // here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL
  43. T* Base() { return NULL; }
  44. const T* Base() const { return NULL; }
  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. static I InvalidIndex() { return ( I )-1; }
  67. void Swap( CUtlBlockMemory< T, I > &mem );
  68. // Size
  69. int NumAllocated() const;
  70. int Count() const { return NumAllocated(); }
  71. // Grows memory by max(num,growsize) rounded up to the next power of 2, and returns the allocation index/ptr
  72. void Grow( int num = 1 );
  73. // Makes sure we've got at least this much memory
  74. void EnsureCapacity( int num );
  75. // Memory deallocation
  76. void Purge();
  77. // Purge all but the given number of elements
  78. void Purge( int numElements );
  79. protected:
  80. int Index( int major, int minor ) const { return ( major << m_nIndexShift ) | minor; }
  81. int MajorIndex( int i ) const { return i >> m_nIndexShift; }
  82. int MinorIndex( int i ) const { return i & m_nIndexMask; }
  83. void ChangeSize( int nBlocks );
  84. int NumElementsInBlock() const { return m_nIndexMask + 1; }
  85. T** m_pMemory;
  86. int m_nBlocks;
  87. int m_nIndexMask : 27;
  88. int m_nIndexShift : 5;
  89. };
  90. //-----------------------------------------------------------------------------
  91. // constructor, destructor
  92. //-----------------------------------------------------------------------------
  93. template< class T, class I >
  94. CUtlBlockMemory<T,I>::CUtlBlockMemory( int nGrowSize, int nInitAllocationCount )
  95. : m_pMemory( 0 ), m_nBlocks( 0 ), m_nIndexMask( 0 ), m_nIndexShift( 0 )
  96. {
  97. Init( nGrowSize, nInitAllocationCount );
  98. }
  99. template< class T, class I >
  100. CUtlBlockMemory<T,I>::~CUtlBlockMemory()
  101. {
  102. Purge();
  103. }
  104. //-----------------------------------------------------------------------------
  105. // Fast swap
  106. //-----------------------------------------------------------------------------
  107. template< class T, class I >
  108. void CUtlBlockMemory<T,I>::Swap( CUtlBlockMemory< T, I > &mem )
  109. {
  110. V_swap( m_pMemory, mem.m_pMemory );
  111. V_swap( m_nBlocks, mem.m_nBlocks );
  112. V_swap( m_nIndexMask, mem.m_nIndexMask );
  113. V_swap( m_nIndexShift, mem.m_nIndexShift );
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Set the size by which the memory grows - round up to the next power of 2
  117. //-----------------------------------------------------------------------------
  118. template< class T, class I >
  119. void CUtlBlockMemory<T,I>::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ )
  120. {
  121. Purge();
  122. if ( nGrowSize == 0)
  123. {
  124. // default grow size is smallest size s.t. c++ allocation overhead is ~6% of block size
  125. nGrowSize = ( 127 + sizeof( T ) ) / sizeof( T );
  126. }
  127. nGrowSize = SmallestPowerOfTwoGreaterOrEqual( nGrowSize );
  128. m_nIndexMask = nGrowSize - 1;
  129. m_nIndexShift = 0;
  130. while ( nGrowSize > 1 )
  131. {
  132. nGrowSize >>= 1;
  133. ++m_nIndexShift;
  134. }
  135. Assert( m_nIndexMask + 1 == ( 1 << m_nIndexShift ) );
  136. Grow( nInitSize );
  137. }
  138. //-----------------------------------------------------------------------------
  139. // element access
  140. //-----------------------------------------------------------------------------
  141. template< class T, class I >
  142. inline T& CUtlBlockMemory<T,I>::operator[]( I i )
  143. {
  144. Assert( IsIdxValid(i) );
  145. T *pBlock = m_pMemory[ MajorIndex( i ) ];
  146. return pBlock[ MinorIndex( i ) ];
  147. }
  148. template< class T, class I >
  149. inline const T& CUtlBlockMemory<T,I>::operator[]( I i ) const
  150. {
  151. Assert( IsIdxValid(i) );
  152. const T *pBlock = m_pMemory[ MajorIndex( i ) ];
  153. return pBlock[ MinorIndex( i ) ];
  154. }
  155. template< class T, class I >
  156. inline T& CUtlBlockMemory<T,I>::Element( I i )
  157. {
  158. Assert( IsIdxValid(i) );
  159. T *pBlock = m_pMemory[ MajorIndex( i ) ];
  160. return pBlock[ MinorIndex( i ) ];
  161. }
  162. template< class T, class I >
  163. inline const T& CUtlBlockMemory<T,I>::Element( I i ) const
  164. {
  165. Assert( IsIdxValid(i) );
  166. const T *pBlock = m_pMemory[ MajorIndex( i ) ];
  167. return pBlock[ MinorIndex( i ) ];
  168. }
  169. //-----------------------------------------------------------------------------
  170. // Size
  171. //-----------------------------------------------------------------------------
  172. template< class T, class I >
  173. inline int CUtlBlockMemory<T,I>::NumAllocated() const
  174. {
  175. return m_nBlocks * NumElementsInBlock();
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Is element index valid?
  179. //-----------------------------------------------------------------------------
  180. template< class T, class I >
  181. inline bool CUtlBlockMemory<T,I>::IsIdxValid( I i ) const
  182. {
  183. return ( i >= 0 ) && ( MajorIndex( i ) < m_nBlocks );
  184. }
  185. template< class T, class I >
  186. void CUtlBlockMemory<T,I>::Grow( int num )
  187. {
  188. if ( num <= 0 )
  189. return;
  190. int nBlockSize = NumElementsInBlock();
  191. int nBlocks = ( num + nBlockSize - 1 ) / nBlockSize;
  192. ChangeSize( m_nBlocks + nBlocks );
  193. }
  194. template< class T, class I >
  195. void CUtlBlockMemory<T,I>::ChangeSize( int nBlocks )
  196. {
  197. UTLBLOCKMEMORY_TRACK_FREE(); // this must stay before the recalculation of m_nBlocks, since it implicitly uses the old value
  198. int nBlocksOld = m_nBlocks;
  199. m_nBlocks = nBlocks;
  200. UTLBLOCKMEMORY_TRACK_ALLOC(); // this must stay after the recalculation of m_nBlocks, since it implicitly uses the new value
  201. // free old blocks if shrinking
  202. for ( int i = m_nBlocks; i < nBlocksOld; ++i )
  203. {
  204. UTLBLOCKMEMORY_TRACK_FREE();
  205. free( (void*)m_pMemory[ i ] );
  206. }
  207. if ( m_pMemory )
  208. {
  209. MEM_ALLOC_CREDIT_CLASS();
  210. m_pMemory = (T**)realloc( m_pMemory, m_nBlocks * sizeof(T*) );
  211. Assert( m_pMemory );
  212. }
  213. else
  214. {
  215. MEM_ALLOC_CREDIT_CLASS();
  216. m_pMemory = (T**)malloc( m_nBlocks * sizeof(T*) );
  217. Assert( m_pMemory );
  218. }
  219. if ( !m_pMemory )
  220. {
  221. Error( "CUtlBlockMemory overflow!\n" );
  222. }
  223. // allocate new blocks if growing
  224. int nBlockSize = NumElementsInBlock();
  225. for ( int i = nBlocksOld; i < m_nBlocks; ++i )
  226. {
  227. MEM_ALLOC_CREDIT_CLASS();
  228. m_pMemory[ i ] = (T*)malloc( nBlockSize * sizeof( T ) );
  229. Assert( m_pMemory[ i ] );
  230. }
  231. }
  232. //-----------------------------------------------------------------------------
  233. // Makes sure we've got at least this much memory
  234. //-----------------------------------------------------------------------------
  235. template< class T, class I >
  236. inline void CUtlBlockMemory<T,I>::EnsureCapacity( int num )
  237. {
  238. Grow( num - NumAllocated() );
  239. }
  240. //-----------------------------------------------------------------------------
  241. // Memory deallocation
  242. //-----------------------------------------------------------------------------
  243. template< class T, class I >
  244. void CUtlBlockMemory<T,I>::Purge()
  245. {
  246. if ( !m_pMemory )
  247. return;
  248. for ( int i = 0; i < m_nBlocks; ++i )
  249. {
  250. UTLBLOCKMEMORY_TRACK_FREE();
  251. free( (void*)m_pMemory[ i ] );
  252. }
  253. m_nBlocks = 0;
  254. UTLBLOCKMEMORY_TRACK_FREE();
  255. free( (void*)m_pMemory );
  256. m_pMemory = 0;
  257. }
  258. template< class T, class I >
  259. void CUtlBlockMemory<T,I>::Purge( int numElements )
  260. {
  261. Assert( numElements >= 0 );
  262. int nAllocated = NumAllocated();
  263. if ( numElements > nAllocated )
  264. {
  265. // Ensure this isn't a grow request in disguise.
  266. Assert( numElements <= nAllocated );
  267. return;
  268. }
  269. if ( numElements <= 0 )
  270. {
  271. Purge();
  272. return;
  273. }
  274. int nBlockSize = NumElementsInBlock();
  275. int nBlocksOld = m_nBlocks;
  276. int nBlocks = ( numElements + nBlockSize - 1 ) / nBlockSize;
  277. // If the number of blocks is the same as the allocated number of blocks, we are done.
  278. if ( nBlocks == m_nBlocks )
  279. return;
  280. ChangeSize( nBlocks );
  281. }
  282. #include "tier0/memdbgoff.h"
  283. #endif // UTLBLOCKMEMORY_H