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.

354 lines
9.5 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 UTLFIXEDMEMORY_H
  10. #define UTLFIXEDMEMORY_H
  11. #ifdef _WIN32
  12. #pragma once
  13. #endif
  14. #include "tier0/dbg.h"
  15. #include "tier0/platform.h"
  16. #include "tier0/memalloc.h"
  17. #include "tier0/memdbgon.h"
  18. #pragma warning (disable:4100)
  19. #pragma warning (disable:4514)
  20. //-----------------------------------------------------------------------------
  21. #ifdef UTLFIXEDMEMORY_TRACK
  22. #define UTLFIXEDMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
  23. #define UTLFIXEDMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
  24. #else
  25. #define UTLFIXEDMEMORY_TRACK_ALLOC() ((void)0)
  26. #define UTLFIXEDMEMORY_TRACK_FREE() ((void)0)
  27. #endif
  28. //-----------------------------------------------------------------------------
  29. // The CUtlFixedMemory class:
  30. // A growable memory class that allocates non-sequential blocks, but is indexed sequentially
  31. //-----------------------------------------------------------------------------
  32. template< class T >
  33. class CUtlFixedMemory
  34. {
  35. public:
  36. // constructor, destructor
  37. CUtlFixedMemory( int nGrowSize = 0, int nInitSize = 0 );
  38. ~CUtlFixedMemory();
  39. // Set the size by which the memory grows
  40. void Init( int nGrowSize = 0, int nInitSize = 0 );
  41. // here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL
  42. T* Base() { return NULL; }
  43. const T* Base() const { return NULL; }
  44. protected:
  45. struct BlockHeader_t;
  46. public:
  47. class Iterator_t
  48. {
  49. public:
  50. Iterator_t( BlockHeader_t *p, int i ) : m_pBlockHeader( p ), m_nIndex( i ) {}
  51. BlockHeader_t *m_pBlockHeader;
  52. intp m_nIndex;
  53. bool operator==( const Iterator_t it ) const { return m_pBlockHeader == it.m_pBlockHeader && m_nIndex == it.m_nIndex; }
  54. bool operator!=( const Iterator_t it ) const { return m_pBlockHeader != it.m_pBlockHeader || m_nIndex != it.m_nIndex; }
  55. };
  56. Iterator_t First() const { return m_pBlocks ? Iterator_t( m_pBlocks, 0 ) : InvalidIterator(); }
  57. Iterator_t Next( const Iterator_t &it ) const
  58. {
  59. Assert( IsValidIterator( it ) );
  60. if ( !IsValidIterator( it ) )
  61. return InvalidIterator();
  62. BlockHeader_t * RESTRICT pHeader = it.m_pBlockHeader;
  63. if ( it.m_nIndex + 1 < pHeader->m_nBlockSize )
  64. return Iterator_t( pHeader, it.m_nIndex + 1 );
  65. return pHeader->m_pNext ? Iterator_t( pHeader->m_pNext, 0 ) : InvalidIterator();
  66. }
  67. intp GetIndex( const Iterator_t &it ) const
  68. {
  69. Assert( IsValidIterator( it ) );
  70. if ( !IsValidIterator( it ) )
  71. return InvalidIndex();
  72. return ( intp )( HeaderToBlock( it.m_pBlockHeader ) + it.m_nIndex );
  73. }
  74. bool IsIdxAfter( intp i, const Iterator_t &it ) const
  75. {
  76. Assert( IsValidIterator( it ) );
  77. if ( !IsValidIterator( it ) )
  78. return false;
  79. if ( IsInBlock( i, it.m_pBlockHeader ) )
  80. return i > GetIndex( it );
  81. for ( BlockHeader_t * RESTRICT pbh = it.m_pBlockHeader->m_pNext; pbh; pbh = pbh->m_pNext )
  82. {
  83. if ( IsInBlock( i, pbh ) )
  84. return true;
  85. }
  86. return false;
  87. }
  88. bool IsValidIterator( const Iterator_t &it ) const { return it.m_pBlockHeader && it.m_nIndex >= 0 && it.m_nIndex < it.m_pBlockHeader->m_nBlockSize; }
  89. Iterator_t InvalidIterator() const { return Iterator_t( NULL, INVALID_INDEX ); }
  90. // element access
  91. T& operator[]( intp i );
  92. const T& operator[]( intp i ) const;
  93. T& Element( intp i );
  94. const T& Element( intp i ) const;
  95. // Can we use this index?
  96. bool IsIdxValid( intp i ) const;
  97. // Specify the invalid ('null') index that we'll only return on failure
  98. static const intp INVALID_INDEX = 0; // For use with COMPILE_TIME_ASSERT
  99. static intp InvalidIndex() { return INVALID_INDEX; }
  100. // Size
  101. int NumAllocated() const;
  102. int Count() const { return NumAllocated(); }
  103. // Grows memory by max(num,growsize), and returns the allocation index/ptr
  104. void Grow( int num = 1 );
  105. // Makes sure we've got at least this much memory
  106. void EnsureCapacity( int num );
  107. // Memory deallocation
  108. void Purge();
  109. protected:
  110. // Fast swap - WARNING: Swap invalidates all ptr-based indices!!!
  111. void Swap( CUtlFixedMemory< T > &mem );
  112. bool IsInBlock( intp i, BlockHeader_t *pBlockHeader ) const
  113. {
  114. T *p = ( T* )i;
  115. const T *p0 = HeaderToBlock( pBlockHeader );
  116. return p >= p0 && p < p0 + pBlockHeader->m_nBlockSize;
  117. }
  118. struct BlockHeader_t
  119. {
  120. BlockHeader_t *m_pNext;
  121. intp m_nBlockSize;
  122. };
  123. const T *HeaderToBlock( const BlockHeader_t *pHeader ) const { return ( T* )( pHeader + 1 ); }
  124. const BlockHeader_t *BlockToHeader( const T *pBlock ) const { return ( BlockHeader_t* )( pBlock ) - 1; }
  125. BlockHeader_t* m_pBlocks;
  126. int m_nAllocationCount;
  127. int m_nGrowSize;
  128. };
  129. //-----------------------------------------------------------------------------
  130. // constructor, destructor
  131. //-----------------------------------------------------------------------------
  132. template< class T >
  133. CUtlFixedMemory<T>::CUtlFixedMemory( int nGrowSize, int nInitAllocationCount )
  134. : m_pBlocks( 0 ), m_nAllocationCount( 0 ), m_nGrowSize( 0 )
  135. {
  136. Init( nGrowSize, nInitAllocationCount );
  137. }
  138. template< class T >
  139. CUtlFixedMemory<T>::~CUtlFixedMemory()
  140. {
  141. Purge();
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Fast swap - WARNING: Swap invalidates all ptr-based indices!!!
  145. //-----------------------------------------------------------------------------
  146. template< class T >
  147. void CUtlFixedMemory<T>::Swap( CUtlFixedMemory< T > &mem )
  148. {
  149. V_swap( m_pBlocks, mem.m_pBlocks );
  150. V_swap( m_nAllocationCount, mem.m_nAllocationCount );
  151. V_swap( m_nGrowSize, mem.m_nGrowSize );
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Set the size by which the memory grows - round up to the next power of 2
  155. //-----------------------------------------------------------------------------
  156. template< class T >
  157. void CUtlFixedMemory<T>::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ )
  158. {
  159. Purge();
  160. m_nGrowSize = nGrowSize;
  161. Grow( nInitSize );
  162. }
  163. //-----------------------------------------------------------------------------
  164. // element access
  165. //-----------------------------------------------------------------------------
  166. template< class T >
  167. inline T& CUtlFixedMemory<T>::operator[]( intp i )
  168. {
  169. Assert( IsIdxValid(i) );
  170. return *( T* )i;
  171. }
  172. template< class T >
  173. inline const T& CUtlFixedMemory<T>::operator[]( intp i ) const
  174. {
  175. Assert( IsIdxValid(i) );
  176. return *( T* )i;
  177. }
  178. template< class T >
  179. inline T& CUtlFixedMemory<T>::Element( intp i )
  180. {
  181. Assert( IsIdxValid(i) );
  182. return *( T* )i;
  183. }
  184. template< class T >
  185. inline const T& CUtlFixedMemory<T>::Element( intp i ) const
  186. {
  187. Assert( IsIdxValid(i) );
  188. return *( T* )i;
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Size
  192. //-----------------------------------------------------------------------------
  193. template< class T >
  194. inline int CUtlFixedMemory<T>::NumAllocated() const
  195. {
  196. return m_nAllocationCount;
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Is element index valid?
  200. //-----------------------------------------------------------------------------
  201. template< class T >
  202. inline bool CUtlFixedMemory<T>::IsIdxValid( intp i ) const
  203. {
  204. #ifdef _DEBUG
  205. for ( BlockHeader_t *pbh = m_pBlocks; pbh; pbh = pbh->m_pNext )
  206. {
  207. if ( IsInBlock( i, pbh ) )
  208. return true;
  209. }
  210. return false;
  211. #else
  212. return i != InvalidIndex();
  213. #endif
  214. }
  215. template< class T >
  216. void CUtlFixedMemory<T>::Grow( int num )
  217. {
  218. if ( num <= 0 )
  219. return;
  220. int nBlockSize = m_nGrowSize;
  221. if ( nBlockSize == 0 )
  222. {
  223. if ( m_nAllocationCount )
  224. {
  225. nBlockSize = m_nAllocationCount;
  226. }
  227. else
  228. {
  229. // Compute an allocation which is at least as big as a cache line...
  230. nBlockSize = ( 31 + sizeof( T ) ) / sizeof( T );
  231. Assert( nBlockSize );
  232. }
  233. }
  234. if ( nBlockSize < num )
  235. {
  236. int n = ( num + nBlockSize -1 ) / nBlockSize;
  237. Assert( n * nBlockSize >= num );
  238. Assert( ( n - 1 ) * nBlockSize < num );
  239. nBlockSize *= n;
  240. }
  241. m_nAllocationCount += nBlockSize;
  242. MEM_ALLOC_CREDIT_CLASS();
  243. BlockHeader_t * RESTRICT pBlockHeader = ( BlockHeader_t* )malloc( sizeof( BlockHeader_t ) + nBlockSize * sizeof( T ) );
  244. if ( !pBlockHeader )
  245. {
  246. Error( "CUtlFixedMemory overflow!\n" );
  247. }
  248. pBlockHeader->m_pNext = NULL;
  249. pBlockHeader->m_nBlockSize = nBlockSize;
  250. if ( !m_pBlocks )
  251. {
  252. m_pBlocks = pBlockHeader;
  253. }
  254. else
  255. {
  256. #if 1 // IsIdxAfter assumes that newly allocated blocks are at the end
  257. BlockHeader_t * RESTRICT pbh = m_pBlocks;
  258. while ( pbh->m_pNext )
  259. {
  260. pbh = pbh->m_pNext;
  261. }
  262. pbh->m_pNext = pBlockHeader;
  263. #else
  264. pBlockHeader = m_pBlocks;
  265. pBlockHeader->m_pNext = m_pBlocks;
  266. #endif
  267. }
  268. }
  269. //-----------------------------------------------------------------------------
  270. // Makes sure we've got at least this much memory
  271. //-----------------------------------------------------------------------------
  272. template< class T >
  273. inline void CUtlFixedMemory<T>::EnsureCapacity( int num )
  274. {
  275. Grow( num - NumAllocated() );
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Memory deallocation
  279. //-----------------------------------------------------------------------------
  280. template< class T >
  281. void CUtlFixedMemory<T>::Purge()
  282. {
  283. if ( !m_pBlocks )
  284. return;
  285. for ( BlockHeader_t *pbh = m_pBlocks; pbh; )
  286. {
  287. BlockHeader_t *pFree = pbh;
  288. pbh = pbh->m_pNext;
  289. free( pFree );
  290. }
  291. m_pBlocks = NULL;
  292. m_nAllocationCount = 0;
  293. }
  294. #include "tier0/memdbgoff.h"
  295. #endif // UTLFIXEDMEMORY_H