CmMemoryAllocator.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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(BOOST_PP_ENUM_PARAMS (n, t)); \
  84. }
  85. BOOST_PP_REPEAT_FROM_TO(1, 15, MAKE_CM_NEW, ~)
  86. #undef MAKE_CM_NEW
  87. // Create a new object with the specified allocator without any parameters
  88. // (Needs to be separate from parameter version so I don't unnecessarily zero-initialize POD types)
  89. template<class Type, class Alloc>
  90. Type* cm_new()
  91. {
  92. return new (cm_alloc<Alloc>(sizeof(Type))) Type;
  93. }
  94. /**
  95. * @brief Frees all the bytes allocated at the specified location.
  96. */
  97. template<class Alloc>
  98. inline void cm_free(void* ptr)
  99. {
  100. MemoryAllocator<Alloc>::free(ptr);
  101. }
  102. /**
  103. * @brief Destructs and frees the specified object.
  104. */
  105. template<class Alloc, class T>
  106. inline void cm_delete(T* ptr)
  107. {
  108. (ptr)->~T();
  109. MemoryAllocator<Alloc>::free(ptr);
  110. }
  111. /**
  112. * @brief Destructs and frees the specified array of objects.
  113. */
  114. template<class Alloc, class T>
  115. inline void cm_deleteN(T* ptr, UINT32 count)
  116. {
  117. for(unsigned int i = 0; i < count; i++)
  118. ptr[i].~T();
  119. MemoryAllocator<Alloc>::freeArray(ptr, count);
  120. }
  121. /*****************************************************************************/
  122. /* Default versions of all alloc/free/new/delete methods which call GenAlloc */
  123. /*****************************************************************************/
  124. /**
  125. * @brief Allocates the specified number of bytes.
  126. */
  127. inline void* cm_alloc(UINT32 count)
  128. {
  129. return MemoryAllocator<GenAlloc>::allocate(count);
  130. }
  131. /**
  132. * @brief Allocates enough bytes to hold the specified type, but doesn't construct it.
  133. */
  134. template<class T>
  135. inline T* cm_alloc()
  136. {
  137. return (T*)MemoryAllocator<GenAlloc>::allocate(sizeof(T));
  138. }
  139. /**
  140. * @brief Creates and constructs an array of "count" elements.
  141. */
  142. template<class T>
  143. inline T* cm_newN(UINT32 count)
  144. {
  145. T* ptr = (T*)MemoryAllocator<GenAlloc>::allocateArray(sizeof(T), count);
  146. for(unsigned int i = 0; i < count; i++)
  147. new ((void*)&ptr[i]) T;
  148. return ptr;
  149. }
  150. // Create a new object with the general allocator and the specified parameters.
  151. #define MAKE_CM_NEW(z, n, unused) \
  152. template<class Type BOOST_PP_ENUM_TRAILING_PARAMS(n, class T)> \
  153. Type* cm_new(BOOST_PP_ENUM_BINARY_PARAMS(n, T, t) ) { \
  154. return new (cm_alloc<GenAlloc>(sizeof(Type))) Type(BOOST_PP_ENUM_PARAMS (n, t)); \
  155. }
  156. BOOST_PP_REPEAT_FROM_TO(1, 15, MAKE_CM_NEW, ~)
  157. #undef MAKE_CM_NEW
  158. // Create a new object with the general allocator without any parameters
  159. // (Needs to be separate from parameter version so I don't unnecessarily zero-initialize POD types)
  160. template<class Type>
  161. Type* cm_new()
  162. {
  163. return new (cm_alloc<GenAlloc>(sizeof(Type))) Type;
  164. }
  165. /**
  166. * @brief Frees all the bytes allocated at the specified location.
  167. */
  168. inline void cm_free(void* ptr)
  169. {
  170. MemoryAllocator<GenAlloc>::free(ptr);
  171. }
  172. /**
  173. * @brief Destructs and frees the specified object.
  174. */
  175. template<class T>
  176. inline void cm_delete(T* ptr)
  177. {
  178. (ptr)->~T();
  179. MemoryAllocator<GenAlloc>::free(ptr);
  180. }
  181. /**
  182. * @brief Destructs and frees the specified array of objects.
  183. */
  184. template<class T>
  185. inline void cm_deleteN(T* ptr, UINT32 count)
  186. {
  187. for(unsigned int i = 0; i < count; i++)
  188. ptr[i].~T();
  189. MemoryAllocator<GenAlloc>::freeArray(ptr, count);
  190. }
  191. }
  192. namespace CamelotFramework
  193. {
  194. // Allocator we can use in the standard library
  195. template <class T, class Alloc = GenAlloc>
  196. class StdAlloc
  197. {
  198. public:
  199. // type definitions
  200. typedef T value_type;
  201. typedef T* pointer;
  202. typedef const T* const_pointer;
  203. typedef T& reference;
  204. typedef const T& const_reference;
  205. typedef std::size_t size_type;
  206. typedef std::ptrdiff_t difference_type;
  207. // rebind allocator to type U
  208. template <class U>
  209. struct rebind
  210. {
  211. typedef StdAlloc<U, Alloc> other;
  212. };
  213. // return address of values
  214. pointer address (reference value) const
  215. {
  216. return &value;
  217. }
  218. const_pointer address (const_reference value) const
  219. {
  220. return &value;
  221. }
  222. /* constructors and destructor
  223. * - nothing to do because the allocator has no state
  224. */
  225. StdAlloc() throw()
  226. { }
  227. StdAlloc(const StdAlloc&) throw()
  228. { }
  229. template <class U>
  230. StdAlloc (const StdAlloc<U, Alloc>&) throw()
  231. { }
  232. ~StdAlloc() throw()
  233. { }
  234. // return maximum number of elements that can be allocated
  235. size_type max_size () const throw()
  236. {
  237. return std::numeric_limits<std::size_t>::max() / sizeof(T);
  238. }
  239. // allocate but don't initialize num elements of type T
  240. pointer allocate (size_type num, const void* = 0)
  241. {
  242. pointer ret = (pointer)(cm_alloc<Alloc>((UINT32)num*sizeof(T)));
  243. return ret;
  244. }
  245. // initialize elements of allocated storage p with value value
  246. void construct (pointer p, const T& value)
  247. {
  248. // initialize memory with placement new
  249. new((void*)p)T(value);
  250. }
  251. // destroy elements of initialized storage p
  252. void destroy (pointer p)
  253. {
  254. // destroy objects by calling their destructor
  255. p->~T();
  256. }
  257. // deallocate storage p of deleted elements
  258. void deallocate (pointer p, size_type num)
  259. {
  260. // print message and deallocate memory with global delete
  261. cm_free<Alloc>((void*)p);
  262. }
  263. };
  264. // return that all specializations of this allocator are interchangeable
  265. template <class T1, class T2, class Alloc>
  266. bool operator== (const StdAlloc<T1, Alloc>&,
  267. const StdAlloc<T2, Alloc>&) throw() {
  268. return true;
  269. }
  270. template <class T1, class T2, class Alloc>
  271. bool operator!= (const StdAlloc<T1, Alloc>&,
  272. const StdAlloc<T2, Alloc>&) throw() {
  273. return false;
  274. }
  275. }
  276. #include "CmMemStack.h"