BsMemoryAllocator.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #pragma once
  4. #undef min
  5. #undef max
  6. #include <atomic>
  7. /** @addtogroup Memory
  8. * @{
  9. */
  10. namespace BansheeEngine
  11. {
  12. class MemoryAllocatorBase;
  13. /** @cond INTERNAL */
  14. /**
  15. * Thread safe class used for storing total number of memory allocations and deallocations, primarily for statistic
  16. * purposes.
  17. */
  18. class MemoryCounter
  19. {
  20. public:
  21. static BS_UTILITY_EXPORT UINT64 getNumAllocs()
  22. {
  23. return Allocs;
  24. }
  25. static BS_UTILITY_EXPORT UINT64 getNumFrees()
  26. {
  27. return Frees;
  28. }
  29. private:
  30. friend class MemoryAllocatorBase;
  31. // Threadlocal data can't be exported, so some magic to make it accessible from MemoryAllocator
  32. static BS_UTILITY_EXPORT void incAllocCount() { Allocs++; }
  33. static BS_UTILITY_EXPORT void incFreeCount() { Frees++; }
  34. static BS_THREADLOCAL UINT64 Allocs;
  35. static BS_THREADLOCAL UINT64 Frees;
  36. };
  37. /** Base class all memory allocators need to inherit. Provides allocation and free counting. */
  38. class MemoryAllocatorBase
  39. {
  40. protected:
  41. static void incAllocCount() { MemoryCounter::incAllocCount(); }
  42. static void incFreeCount() { MemoryCounter::incFreeCount(); }
  43. };
  44. /**
  45. * Memory allocator providing a generic implementation. Specialize for specific categories as needed.
  46. *
  47. * @note For example you might implement a pool allocator for specific types in order
  48. * to reduce allocation overhead. By default standard malloc/free are used.
  49. */
  50. template<class T>
  51. class MemoryAllocator : public MemoryAllocatorBase
  52. {
  53. public:
  54. static void* allocate(size_t bytes)
  55. {
  56. #if BS_PROFILING_ENABLED
  57. incAllocCount();
  58. #endif
  59. return malloc(bytes);
  60. }
  61. static void* allocateArray(size_t bytes, UINT32 count)
  62. {
  63. #if BS_PROFILING_ENABLED
  64. incAllocCount();
  65. #endif
  66. return malloc(bytes * count);
  67. }
  68. static void free(void* ptr)
  69. {
  70. #if BS_PROFILING_ENABLED
  71. incFreeCount();
  72. #endif
  73. ::free(ptr);
  74. }
  75. static void freeArray(void* ptr, UINT32 count)
  76. {
  77. #if BS_PROFILING_ENABLED
  78. incFreeCount();
  79. #endif
  80. ::free(ptr);
  81. }
  82. };
  83. /**
  84. * General allocator provided by the OS. Use for persistent long term allocations, and allocations that don't
  85. * happen often.
  86. */
  87. class GenAlloc
  88. { };
  89. /** @endcond */
  90. /** Allocates the specified number of bytes. */
  91. template<class Alloc>
  92. inline void* bs_alloc(UINT32 count)
  93. {
  94. return MemoryAllocator<Alloc>::allocate(count);
  95. }
  96. /** Allocates enough bytes to hold the specified type, but doesn't construct it. */
  97. template<class T, class Alloc>
  98. inline T* bs_alloc()
  99. {
  100. return (T*)MemoryAllocator<Alloc>::allocate(sizeof(T));
  101. }
  102. /** Creates and constructs an array of @p count elements. */
  103. template<class T, class Alloc>
  104. inline T* bs_newN(UINT32 count)
  105. {
  106. T* ptr = (T*)MemoryAllocator<Alloc>::allocateArray(sizeof(T), count);
  107. for(unsigned int i = 0; i < count; i++)
  108. new ((void*)&ptr[i]) T;
  109. return ptr;
  110. }
  111. /** Create a new object with the specified allocator and the specified parameters. */
  112. template<class Type, class Alloc, class... Args>
  113. Type* bs_new(Args &&...args)
  114. {
  115. return new (bs_alloc<Alloc>(sizeof(Type))) Type(std::forward<Args>(args)...);
  116. }
  117. /** Frees all the bytes allocated at the specified location. */
  118. template<class Alloc>
  119. inline void bs_free(void* ptr)
  120. {
  121. MemoryAllocator<Alloc>::free(ptr);
  122. }
  123. /** Destructs and frees the specified object. */
  124. template<class T, class Alloc = GenAlloc>
  125. inline void bs_delete(T* ptr)
  126. {
  127. (ptr)->~T();
  128. MemoryAllocator<Alloc>::free(ptr);
  129. }
  130. /** Destructs and frees the specified array of objects. */
  131. template<class T, class Alloc = GenAlloc>
  132. inline void bs_deleteN(T* ptr, UINT32 count)
  133. {
  134. for(unsigned int i = 0; i < count; i++)
  135. ptr[i].~T();
  136. MemoryAllocator<Alloc>::freeArray(ptr, count);
  137. }
  138. /*****************************************************************************/
  139. /* Default versions of all alloc/free/new/delete methods which call GenAlloc */
  140. /*****************************************************************************/
  141. /** Allocates the specified number of bytes. */
  142. inline void* bs_alloc(UINT32 count)
  143. {
  144. return MemoryAllocator<GenAlloc>::allocate(count);
  145. }
  146. /** Allocates enough bytes to hold the specified type, but doesn't construct it. */
  147. template<class T>
  148. inline T* bs_alloc()
  149. {
  150. return (T*)MemoryAllocator<GenAlloc>::allocate(sizeof(T));
  151. }
  152. /** Allocates enough bytes to hold an array of @p count elements the specified type, but doesn't construct them. */
  153. template<class T>
  154. inline T* bs_allocN(UINT32 count)
  155. {
  156. return (T*)MemoryAllocator<GenAlloc>::allocate(count * sizeof(T));
  157. }
  158. /** Creates and constructs an array of @p count elements. */
  159. template<class T>
  160. inline T* bs_newN(UINT32 count)
  161. {
  162. T* ptr = (T*)MemoryAllocator<GenAlloc>::allocateArray(sizeof(T), count);
  163. for(unsigned int i = 0; i < count; i++)
  164. new ((void*)&ptr[i]) T;
  165. return ptr;
  166. }
  167. /** Create a new object with the specified allocator and the specified parameters. */
  168. template<class Type, class... Args>
  169. Type* bs_new(Args &&...args)
  170. {
  171. return new (bs_alloc<GenAlloc>(sizeof(Type))) Type(std::forward<Args>(args)...);
  172. }
  173. /** Frees all the bytes allocated at the specified location. */
  174. inline void bs_free(void* ptr)
  175. {
  176. MemoryAllocator<GenAlloc>::free(ptr);
  177. }
  178. /************************************************************************/
  179. /* MACRO VERSIONS */
  180. /* You will almost always want to use the template versions but in some */
  181. /* cases (private destructor) it is not possible. In which case you may */
  182. /* use these instead. */
  183. /************************************************************************/
  184. #define BS_PVT_DELETE(T, ptr) \
  185. (ptr)->~T(); \
  186. MemoryAllocator<GenAlloc>::free(ptr);
  187. #define BS_PVT_DELETE_A(T, ptr, Alloc) \
  188. (ptr)->~T(); \
  189. MemoryAllocator<Alloc>::free(ptr);
  190. }
  191. namespace BansheeEngine
  192. {
  193. /** @cond INTERNAL */
  194. /** Allocator for the standard library that internally uses Banshee memory allocator. */
  195. template <class T, class Alloc = GenAlloc>
  196. class StdAlloc
  197. {
  198. public:
  199. typedef T value_type;
  200. StdAlloc() noexcept {}
  201. template<class T, class Alloc> StdAlloc(const StdAlloc<T, Alloc>&) noexcept {}
  202. template<class T, class Alloc> bool operator==(const StdAlloc<T, Alloc>&) const noexcept { return true; }
  203. template<class T, class Alloc> bool operator!=(const StdAlloc<T, Alloc>&) const noexcept { return false; }
  204. /** Allocate but don't initialize number elements of type T. */
  205. T* allocate(const size_t num) const
  206. {
  207. if (num == 0)
  208. return nullptr;
  209. if (num > static_cast<size_t>(-1) / sizeof(T))
  210. throw std::bad_array_new_length();
  211. void* const pv = bs_alloc<Alloc>((UINT32)(num * sizeof(T)));
  212. if (!pv)
  213. throw std::bad_alloc();
  214. return static_cast<T*>(pv);
  215. }
  216. /** Deallocate storage p of deleted elements. */
  217. void deallocate(T* p, size_t num) const noexcept
  218. {
  219. bs_free<Alloc>((void*)p);
  220. }
  221. };
  222. /** @endcond */
  223. }
  224. /** @} */
  225. #include "BsMemStack.h"
  226. #include "BsGlobalFrameAlloc.h"
  227. #include "BsMemAllocProfiler.h"