CmMemoryAllocator.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. #pragma once
  2. #undef min
  3. #undef max
  4. #include <boost/preprocessor.hpp>
  5. namespace CamelotFramework
  6. {
  7. /**
  8. * @brief Memory allocator providing a generic implementation.
  9. * Specialize for specific categories as needed.
  10. */
  11. template<class T>
  12. class MemoryAllocator
  13. {
  14. public:
  15. static inline void* allocate(UINT32 bytes)
  16. {
  17. return malloc(bytes);
  18. }
  19. static inline void* allocateArray(UINT32 bytes, UINT32 count)
  20. {
  21. return malloc(bytes * count);
  22. }
  23. static inline void free(void* ptr)
  24. {
  25. ::free(ptr);
  26. }
  27. static inline void freeArray(void* ptr, UINT32 count)
  28. {
  29. ::free(ptr);
  30. }
  31. };
  32. /**
  33. * @brief General allocator provided by the OS. Use for persistent long term allocations,
  34. * and allocations that don't happen often.
  35. */
  36. class GenAlloc
  37. { };
  38. /**
  39. * @brief Allocator used for allocating small amounts of temporary memory that
  40. * used and then quickly released
  41. */
  42. class ScratchAlloc
  43. { };
  44. /**
  45. * @brief Pool allocator that is only suited for allocating one specific type of data. Most useful when you are
  46. * often allocating one certain data type, with no specific allocation or deallocation order.
  47. */
  48. class PoolAlloc
  49. { };
  50. /**
  51. * @brief Allocates the specified number of bytes.
  52. */
  53. template<class Alloc>
  54. inline void* cm_alloc(UINT32 count)
  55. {
  56. return MemoryAllocator<Alloc>::allocate(count);
  57. }
  58. /**
  59. * @brief Allocates enough bytes to hold the specified type, but doesn't construct it.
  60. */
  61. template<class T, class Alloc>
  62. inline T* cm_alloc()
  63. {
  64. return (T*)MemoryAllocator<Alloc>::allocate(sizeof(T));
  65. }
  66. /**
  67. * @brief Creates and constructs an array of "count" elements.
  68. */
  69. template<class T, class Alloc>
  70. inline T* cm_newN(UINT32 count)
  71. {
  72. T* ptr = (T*)MemoryAllocator<Alloc>::allocateArray(sizeof(T), count);
  73. for(unsigned int i = 0; i < count; i++)
  74. new ((void*)&ptr[i]) T;
  75. return ptr;
  76. }
  77. /**
  78. * @brief Create a new object with the specified allocator and the specified parameters.
  79. */
  80. #define MAKE_CM_NEW(z, n, unused) \
  81. template<class Type, class Alloc BOOST_PP_ENUM_TRAILING_PARAMS(n, class T)> \
  82. Type* cm_new(BOOST_PP_ENUM_BINARY_PARAMS(n, T, &&t) ) { \
  83. return new (cm_alloc<Alloc>(sizeof(Type))) Type(std::forward<T0>(t0) BOOST_PP_REPEAT_FROM_TO(1, n, FORWARD_T, ~)); \
  84. }
  85. #define FORWARD_T(z, i, unused) \
  86. , std::forward<BOOST_PP_CAT(T, i)>(BOOST_PP_CAT(t, i))
  87. BOOST_PP_REPEAT_FROM_TO(1, 15, MAKE_CM_NEW, ~)
  88. #undef FORWARD_T
  89. #undef MAKE_CM_NEW
  90. // Create a new object with the specified allocator without any parameters
  91. // (Needs to be separate from parameter version so I don't unnecessarily zero-initialize POD types)
  92. template<class Type, class Alloc>
  93. Type* cm_new()
  94. {
  95. return new (cm_alloc<Alloc>(sizeof(Type))) Type;
  96. }
  97. /**
  98. * @brief Frees all the bytes allocated at the specified location.
  99. */
  100. template<class Alloc>
  101. inline void cm_free(void* ptr)
  102. {
  103. MemoryAllocator<Alloc>::free(ptr);
  104. }
  105. /**
  106. * @brief Destructs and frees the specified object.
  107. */
  108. template<class Alloc, class T>
  109. inline void cm_delete(T* ptr)
  110. {
  111. (ptr)->~T();
  112. MemoryAllocator<Alloc>::free(ptr);
  113. }
  114. /**
  115. * @brief Destructs and frees the specified array of objects.
  116. */
  117. template<class Alloc, class T>
  118. inline void cm_deleteN(T* ptr, UINT32 count)
  119. {
  120. for(unsigned int i = 0; i < count; i++)
  121. ptr[i].~T();
  122. MemoryAllocator<Alloc>::freeArray(ptr, count);
  123. }
  124. /*****************************************************************************/
  125. /* Default versions of all alloc/free/new/delete methods which call GenAlloc */
  126. /*****************************************************************************/
  127. /**
  128. * @brief Allocates the specified number of bytes.
  129. */
  130. inline void* cm_alloc(UINT32 count)
  131. {
  132. return MemoryAllocator<GenAlloc>::allocate(count);
  133. }
  134. /**
  135. * @brief Allocates enough bytes to hold the specified type, but doesn't construct it.
  136. */
  137. template<class T>
  138. inline T* cm_alloc()
  139. {
  140. return (T*)MemoryAllocator<GenAlloc>::allocate(sizeof(T));
  141. }
  142. /**
  143. * @brief Creates and constructs an array of "count" elements.
  144. */
  145. template<class T>
  146. inline T* cm_newN(UINT32 count)
  147. {
  148. T* ptr = (T*)MemoryAllocator<GenAlloc>::allocateArray(sizeof(T), count);
  149. for(unsigned int i = 0; i < count; i++)
  150. new ((void*)&ptr[i]) T;
  151. return ptr;
  152. }
  153. // Create a new object with the general allocator and the specified parameters.
  154. #define MAKE_CM_NEW(z, n, unused) \
  155. template<class Type BOOST_PP_ENUM_TRAILING_PARAMS(n, class T)> \
  156. Type* cm_new(BOOST_PP_ENUM_BINARY_PARAMS(n, T, &&t) ) { \
  157. return new (cm_alloc<GenAlloc>(sizeof(Type))) Type(std::forward<T0>(t0) BOOST_PP_REPEAT_FROM_TO(1, n, FORWARD_T, ~)); \
  158. }
  159. #define FORWARD_T(z, i, unused) \
  160. , std::forward<BOOST_PP_CAT(T, i)>(BOOST_PP_CAT(t, i))
  161. BOOST_PP_REPEAT_FROM_TO(1, 15, MAKE_CM_NEW, ~)
  162. #undef FORWARD_T
  163. #undef MAKE_CM_NEW
  164. // Create a new object with the general allocator without any parameters
  165. // (Needs to be separate from parameter version so I don't unnecessarily zero-initialize POD types)
  166. template<class Type>
  167. Type* cm_new()
  168. {
  169. return new (cm_alloc<GenAlloc>(sizeof(Type))) Type;
  170. }
  171. /**
  172. * @brief Frees all the bytes allocated at the specified location.
  173. */
  174. inline void cm_free(void* ptr)
  175. {
  176. MemoryAllocator<GenAlloc>::free(ptr);
  177. }
  178. /**
  179. * @brief Destructs and frees the specified object.
  180. */
  181. template<class T>
  182. inline void cm_delete(T* ptr)
  183. {
  184. (ptr)->~T();
  185. MemoryAllocator<GenAlloc>::free(ptr);
  186. }
  187. /**
  188. * @brief Destructs and frees the specified array of objects.
  189. */
  190. template<class T>
  191. inline void cm_deleteN(T* ptr, UINT32 count)
  192. {
  193. for(unsigned int i = 0; i < count; i++)
  194. ptr[i].~T();
  195. MemoryAllocator<GenAlloc>::freeArray(ptr, count);
  196. }
  197. }
  198. namespace CamelotFramework
  199. {
  200. // Allocator we can use in the standard library
  201. template <class T, class Alloc = GenAlloc>
  202. class StdAlloc
  203. {
  204. public:
  205. // type definitions
  206. typedef T value_type;
  207. typedef T* pointer;
  208. typedef const T* const_pointer;
  209. typedef T& reference;
  210. typedef const T& const_reference;
  211. typedef std::size_t size_type;
  212. typedef std::ptrdiff_t difference_type;
  213. // rebind allocator to type U
  214. template <class U>
  215. struct rebind
  216. {
  217. typedef StdAlloc<U, Alloc> other;
  218. };
  219. // return address of values
  220. pointer address (reference value) const
  221. {
  222. return &value;
  223. }
  224. const_pointer address (const_reference value) const
  225. {
  226. return &value;
  227. }
  228. /* constructors and destructor
  229. * - nothing to do because the allocator has no state
  230. */
  231. StdAlloc() throw()
  232. { }
  233. StdAlloc(const StdAlloc&) throw()
  234. { }
  235. template <class U>
  236. StdAlloc (const StdAlloc<U, Alloc>&) throw()
  237. { }
  238. ~StdAlloc() throw()
  239. { }
  240. // return maximum number of elements that can be allocated
  241. size_type max_size () const throw()
  242. {
  243. return std::numeric_limits<std::size_t>::max() / sizeof(T);
  244. }
  245. // allocate but don't initialize num elements of type T
  246. pointer allocate (size_type num, const void* = 0)
  247. {
  248. pointer ret = (pointer)(cm_alloc<Alloc>((UINT32)num*sizeof(T)));
  249. return ret;
  250. }
  251. // initialize elements of allocated storage p with value value
  252. void construct (pointer p, const T& value)
  253. {
  254. // initialize memory with placement new
  255. new((void*)p)T(value);
  256. }
  257. // destroy elements of initialized storage p
  258. void destroy (pointer p)
  259. {
  260. // destroy objects by calling their destructor
  261. p->~T();
  262. }
  263. // deallocate storage p of deleted elements
  264. void deallocate (pointer p, size_type num)
  265. {
  266. // print message and deallocate memory with global delete
  267. cm_free<Alloc>((void*)p);
  268. }
  269. };
  270. // return that all specializations of this allocator are interchangeable
  271. template <class T1, class T2, class Alloc>
  272. bool operator== (const StdAlloc<T1, Alloc>&,
  273. const StdAlloc<T2, Alloc>&) throw() {
  274. return true;
  275. }
  276. template <class T1, class T2, class Alloc>
  277. bool operator!= (const StdAlloc<T1, Alloc>&,
  278. const StdAlloc<T2, Alloc>&) throw() {
  279. return false;
  280. }
  281. }
  282. #include "CmMemStack.h"