CmMemoryAllocator.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. #pragma once
  2. #undef min
  3. #undef max
  4. #include <boost/preprocessor.hpp>
  5. #include <atomic>
  6. namespace BansheeEngine
  7. {
  8. class MemoryAllocatorBase;
  9. /**
  10. * @brief Thread safe class used for storing total number of memory allocations and deallocations,
  11. * primarily for statistic purposes.
  12. */
  13. class MemoryCounter
  14. {
  15. public:
  16. static CM_UTILITY_EXPORT UINT64 getNumAllocs()
  17. {
  18. return Allocs;
  19. }
  20. static CM_UTILITY_EXPORT UINT64 getNumFrees()
  21. {
  22. return Frees;
  23. }
  24. private:
  25. friend class MemoryAllocatorBase;
  26. // Threadlocal data can't be exported, so some magic to make it accessible from MemoryAllocator
  27. static CM_UTILITY_EXPORT void incAllocCount() { Allocs++; }
  28. static CM_UTILITY_EXPORT void incFreeCount() { Frees++; }
  29. static CM_THREADLOCAL UINT64 Allocs;
  30. static CM_THREADLOCAL UINT64 Frees;
  31. };
  32. /**
  33. * @brief Base class all memory allocators need to inherit. Provides
  34. * allocation and free counting.
  35. */
  36. class MemoryAllocatorBase
  37. {
  38. protected:
  39. static void incAllocCount() { MemoryCounter::incAllocCount(); }
  40. static void incFreeCount() { MemoryCounter::incFreeCount(); }
  41. };
  42. /**
  43. * @brief Memory allocator providing a generic implementation.
  44. * Specialize for specific categories as needed.
  45. *
  46. * @note For example you might implement a pool allocator for specific types in order
  47. * to reduce allocation overhead. By default standard malloc/free are used.
  48. */
  49. template<class T>
  50. class MemoryAllocator : public MemoryAllocatorBase
  51. {
  52. public:
  53. static inline void* allocate(size_t bytes)
  54. {
  55. #if CM_PROFILING_ENABLED
  56. incAllocCount();
  57. #endif
  58. return malloc(bytes);
  59. }
  60. static inline void* allocateArray(size_t bytes, UINT32 count)
  61. {
  62. #if CM_PROFILING_ENABLED
  63. incAllocCount();
  64. #endif
  65. return malloc(bytes * count);
  66. }
  67. static inline void free(void* ptr)
  68. {
  69. #if CM_PROFILING_ENABLED
  70. incFreeCount();
  71. #endif
  72. ::free(ptr);
  73. }
  74. static inline void freeArray(void* ptr, UINT32 count)
  75. {
  76. #if CM_PROFILING_ENABLED
  77. incFreeCount();
  78. #endif
  79. ::free(ptr);
  80. }
  81. };
  82. /**
  83. * @brief General allocator provided by the OS. Use for persistent long term allocations,
  84. * and allocations that don't happen often.
  85. */
  86. class GenAlloc
  87. { };
  88. /**
  89. * @brief Allocator used for allocating small amounts of temporary memory that
  90. * used and then quickly released
  91. *
  92. * @note Currently not used.
  93. */
  94. class ScratchAlloc
  95. { };
  96. /**
  97. * @brief Pool allocator that is only suited for allocating one specific type of data. Most useful when you are
  98. * often allocating one certain data type, with no specific allocation or deallocation order.
  99. *
  100. * @note Currently not used.
  101. */
  102. class PoolAlloc
  103. { };
  104. /**
  105. * @brief Allocates the specified number of bytes.
  106. */
  107. template<class Alloc>
  108. inline void* cm_alloc(size_t count)
  109. {
  110. return MemoryAllocator<Alloc>::allocate(count);
  111. }
  112. /**
  113. * @brief Allocates enough bytes to hold the specified type, but doesn't construct it.
  114. */
  115. template<class T, class Alloc>
  116. inline T* cm_alloc()
  117. {
  118. return (T*)MemoryAllocator<Alloc>::allocate(sizeof(T));
  119. }
  120. /**
  121. * @brief Creates and constructs an array of "count" elements.
  122. */
  123. template<class T, class Alloc>
  124. inline T* cm_newN(UINT32 count)
  125. {
  126. T* ptr = (T*)MemoryAllocator<Alloc>::allocateArray(sizeof(T), count);
  127. for(unsigned int i = 0; i < count; i++)
  128. new ((void*)&ptr[i]) T;
  129. return ptr;
  130. }
  131. /**
  132. * @brief Create a new object with the specified allocator and the specified parameters.
  133. */
  134. #define MAKE_CM_NEW(z, n, unused) \
  135. template<class Type, class Alloc BOOST_PP_ENUM_TRAILING_PARAMS(n, class T)> \
  136. Type* cm_new(BOOST_PP_ENUM_BINARY_PARAMS(n, T, &&t) ) { \
  137. return new (cm_alloc<Alloc>(sizeof(Type))) Type(std::forward<T0>(t0) BOOST_PP_REPEAT_FROM_TO(1, n, FORWARD_T, ~)); \
  138. }
  139. #define FORWARD_T(z, i, unused) \
  140. , std::forward<BOOST_PP_CAT(T, i)>(BOOST_PP_CAT(t, i))
  141. BOOST_PP_REPEAT_FROM_TO(1, 15, MAKE_CM_NEW, ~)
  142. #undef FORWARD_T
  143. #undef MAKE_CM_NEW
  144. /**
  145. * @brief Create a new object with the specified allocator without any parameters
  146. *
  147. * @note Needs to be separate from parameter version so I don't unnecessarily zero-initialize POD types.
  148. */
  149. template<class Type, class Alloc>
  150. Type* cm_new()
  151. {
  152. return new (cm_alloc<Alloc>(sizeof(Type))) Type;
  153. }
  154. /**
  155. * @brief Frees all the bytes allocated at the specified location.
  156. */
  157. template<class Alloc>
  158. inline void cm_free(void* ptr)
  159. {
  160. MemoryAllocator<Alloc>::free(ptr);
  161. }
  162. /**
  163. * @brief Destructs and frees the specified object.
  164. */
  165. template<class Alloc, class T>
  166. inline void cm_delete(T* ptr)
  167. {
  168. (ptr)->~T();
  169. MemoryAllocator<Alloc>::free(ptr);
  170. }
  171. /**
  172. * @brief Destructs and frees the specified array of objects.
  173. */
  174. template<class Alloc, class T>
  175. inline void cm_deleteN(T* ptr, UINT32 count)
  176. {
  177. for(unsigned int i = 0; i < count; i++)
  178. ptr[i].~T();
  179. MemoryAllocator<Alloc>::freeArray(ptr, count);
  180. }
  181. /*****************************************************************************/
  182. /* Default versions of all alloc/free/new/delete methods which call GenAlloc */
  183. /*****************************************************************************/
  184. /**
  185. * @brief Allocates the specified number of bytes.
  186. */
  187. inline void* cm_alloc(size_t count)
  188. {
  189. return MemoryAllocator<GenAlloc>::allocate(count);
  190. }
  191. /**
  192. * @brief Allocates enough bytes to hold the specified type, but doesn't construct it.
  193. */
  194. template<class T>
  195. inline T* cm_alloc()
  196. {
  197. return (T*)MemoryAllocator<GenAlloc>::allocate(sizeof(T));
  198. }
  199. /**
  200. * @brief Creates and constructs an array of "count" elements.
  201. */
  202. template<class T>
  203. inline T* cm_newN(UINT32 count)
  204. {
  205. T* ptr = (T*)MemoryAllocator<GenAlloc>::allocateArray(sizeof(T), count);
  206. for(unsigned int i = 0; i < count; i++)
  207. new ((void*)&ptr[i]) T;
  208. return ptr;
  209. }
  210. /**
  211. * @brief Create a new object with the specified allocator and the specified parameters.
  212. */
  213. #define MAKE_CM_NEW(z, n, unused) \
  214. template<class Type BOOST_PP_ENUM_TRAILING_PARAMS(n, class T)> \
  215. Type* cm_new(BOOST_PP_ENUM_BINARY_PARAMS(n, T, &&t) ) { \
  216. return new (cm_alloc<GenAlloc>(sizeof(Type))) Type(std::forward<T0>(t0) BOOST_PP_REPEAT_FROM_TO(1, n, FORWARD_T, ~)); \
  217. }
  218. #define FORWARD_T(z, i, unused) \
  219. , std::forward<BOOST_PP_CAT(T, i)>(BOOST_PP_CAT(t, i))
  220. BOOST_PP_REPEAT_FROM_TO(1, 15, MAKE_CM_NEW, ~)
  221. #undef FORWARD_T
  222. #undef MAKE_CM_NEW
  223. /**
  224. * @brief Create a new object with the specified allocator without any parameters
  225. *
  226. * @note Needs to be separate from parameter version so I don't unnecessarily zero-initialize POD types.
  227. */
  228. template<class Type>
  229. Type* cm_new()
  230. {
  231. return new (cm_alloc<GenAlloc>(sizeof(Type))) Type;
  232. }
  233. /**
  234. * @brief Frees all the bytes allocated at the specified location.
  235. */
  236. inline void cm_free(void* ptr)
  237. {
  238. MemoryAllocator<GenAlloc>::free(ptr);
  239. }
  240. /**
  241. * @brief Destructs and frees the specified object.
  242. */
  243. template<class T>
  244. inline void cm_delete(T* ptr)
  245. {
  246. (ptr)->~T();
  247. MemoryAllocator<GenAlloc>::free(ptr);
  248. }
  249. /**
  250. * @brief Destructs and frees the specified array of objects.
  251. */
  252. template<class T>
  253. inline void cm_deleteN(T* ptr, UINT32 count)
  254. {
  255. for(unsigned int i = 0; i < count; i++)
  256. ptr[i].~T();
  257. MemoryAllocator<GenAlloc>::freeArray(ptr, count);
  258. }
  259. /************************************************************************/
  260. /* MACRO VERSIONS */
  261. /* You will almost always want to use the template versions but in some */
  262. /* cases (private destructor) it is not possible. In which case you may */
  263. /* use these instead. */
  264. /************************************************************************/
  265. #define CM_PVT_DELETE(T, ptr) \
  266. (ptr)->~T(); \
  267. MemoryAllocator<GenAlloc>::free(ptr);
  268. #define CM_PVT_DELETE_A(T, ptr, Alloc) \
  269. (ptr)->~T(); \
  270. MemoryAllocator<Alloc>::free(ptr);
  271. }
  272. namespace BansheeEngine
  273. {
  274. /**
  275. * @brief Allocator for the standard library that internally uses Banshee
  276. * memory allocator.
  277. */
  278. template <class T, class Alloc = GenAlloc>
  279. class StdAlloc
  280. {
  281. public:
  282. // Type definitions
  283. typedef T value_type;
  284. typedef T* pointer;
  285. typedef const T* const_pointer;
  286. typedef T& reference;
  287. typedef const T& const_reference;
  288. typedef std::size_t size_type;
  289. typedef std::ptrdiff_t difference_type;
  290. /**
  291. * @brief Rebind allocator to type U
  292. */
  293. template <class U>
  294. struct rebind
  295. {
  296. typedef StdAlloc<U, Alloc> other;
  297. };
  298. StdAlloc() throw()
  299. { }
  300. StdAlloc(const StdAlloc&) throw()
  301. { }
  302. template <class U>
  303. StdAlloc (const StdAlloc<U, Alloc>&) throw()
  304. { }
  305. ~StdAlloc() throw()
  306. { }
  307. /**
  308. * @brief Return address of value.
  309. */
  310. pointer address (reference value) const
  311. {
  312. return &value;
  313. }
  314. /**
  315. * @brief Return address of value.
  316. */
  317. const_pointer address (const_reference value) const
  318. {
  319. return &value;
  320. }
  321. /**
  322. * @brief Return maximum number of elements that can be allocated.
  323. */
  324. size_type max_size () const throw()
  325. {
  326. return std::numeric_limits<std::size_t>::max() / sizeof(T);
  327. }
  328. /**
  329. * @brief Allocate but don't initialize number elements of type T.
  330. */
  331. pointer allocate (size_type num, const void* = 0)
  332. {
  333. pointer ret = (pointer)(cm_alloc<Alloc>((size_t)num*sizeof(T)));
  334. return ret;
  335. }
  336. /**
  337. * @brief Initialize elements of allocated storage p with value "value".
  338. */
  339. void construct (pointer p, const T& value)
  340. {
  341. new((void*)p)T(value);
  342. }
  343. /**
  344. * @brief Destroy elements of initialized storage p.
  345. */
  346. void destroy (pointer p)
  347. {
  348. p->~T();
  349. }
  350. /**
  351. * @brief Deallocate storage p of deleted elements.
  352. */
  353. void deallocate (pointer p, size_type num)
  354. {
  355. cm_free<Alloc>((void*)p);
  356. }
  357. };
  358. /**
  359. * @brief Return that all specializations of this allocator are interchangeable.
  360. */
  361. template <class T1, class T2, class Alloc>
  362. bool operator== (const StdAlloc<T1, Alloc>&,
  363. const StdAlloc<T2, Alloc>&) throw() {
  364. return true;
  365. }
  366. /**
  367. * @brief Return that all specializations of this allocator are interchangeable.
  368. */
  369. template <class T1, class T2, class Alloc>
  370. bool operator!= (const StdAlloc<T1, Alloc>&,
  371. const StdAlloc<T2, Alloc>&) throw() {
  372. return false;
  373. }
  374. }
  375. #include "CmMemStack.h"
  376. #include "CmMemAllocProfiler.h"