BsFrameAlloc.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #pragma once
  4. #include "BsPrerequisitesUtil.h"
  5. namespace BansheeEngine
  6. {
  7. /** @cond INTERNAL */
  8. /** @addtogroup Memory
  9. * @{
  10. */
  11. /**
  12. * Frame allocator. Performs very fast allocations but can only free all of its memory at once. Perfect for allocations
  13. * that last just a single frame.
  14. *
  15. * @note Not thread safe with an exception. alloc() and clear() methods need to be called from the same thread.
  16. * dealloc() is thread safe and can be called from any thread.
  17. */
  18. class BS_UTILITY_EXPORT FrameAlloc
  19. {
  20. private:
  21. /** A single block of memory within a frame allocator. */
  22. class MemBlock
  23. {
  24. public:
  25. MemBlock(UINT32 size);
  26. ~MemBlock();
  27. /** Allocates a piece of memory within the block. Caller must ensure the block has enough empty space. */
  28. UINT8* alloc(UINT32 amount);
  29. /** Releases all allocations within a block but doesn't actually free the memory. */
  30. void clear();
  31. UINT8* mData;
  32. UINT32 mFreePtr;
  33. UINT32 mSize;
  34. };
  35. public:
  36. FrameAlloc(UINT32 blockSize = 1024 * 1024);
  37. ~FrameAlloc();
  38. /**
  39. * Allocates a new block of memory of the specified size.
  40. *
  41. * @param[in] amount Amount of memory to allocate, in bytes.
  42. *
  43. * @note Not thread safe.
  44. */
  45. UINT8* alloc(UINT32 amount);
  46. /**
  47. * Allocates and constructs a new object.
  48. *
  49. * @note Not thread safe.
  50. */
  51. template<class T, class... Args>
  52. T* alloc(Args &&...args)
  53. {
  54. return new ((T*)alloc(sizeof(T))) T(std::forward<Args>(args)...);
  55. }
  56. /**
  57. * Deallocates a previously allocated block of memory.
  58. *
  59. * @note
  60. * No deallocation is actually done here. This method is only used for debug purposes so it is easier to track
  61. * down memory leaks and corruption.
  62. * @note
  63. * Thread safe.
  64. */
  65. void dealloc(UINT8* data);
  66. /**
  67. * Deallocates and destructs a previously allocated object.
  68. *
  69. * @note
  70. * No deallocation is actually done here. This method is only used to call the destructor and for debug purposes
  71. * so it is easier to track down memory leaks and corruption.
  72. * @note
  73. * Thread safe.
  74. */
  75. template<class T>
  76. void dealloc(T* obj)
  77. {
  78. if (obj != nullptr)
  79. obj->~T();
  80. dealloc((UINT8*)obj);
  81. }
  82. /** Starts a new frame. Next call to ::clear will only clear memory allocated past this point. */
  83. void markFrame();
  84. /**
  85. * Deallocates all allocated memory since the last call to markFrame() (or all the memory if there was no call
  86. * to markFrame()).
  87. *
  88. * @note Not thread safe.
  89. */
  90. void clear();
  91. /**
  92. * Changes the frame allocator owner thread. After the owner thread has changed only allocations from that thread
  93. * can be made.
  94. */
  95. void setOwnerThread(BS_THREAD_ID_TYPE thread);
  96. private:
  97. UINT32 mBlockSize;
  98. Vector<MemBlock*> mBlocks;
  99. MemBlock* mFreeBlock;
  100. UINT32 mNextBlockIdx;
  101. std::atomic<UINT32> mTotalAllocBytes;
  102. void* mLastFrame;
  103. #if BS_DEBUG_MODE
  104. BS_THREAD_ID_TYPE mOwnerThread;
  105. #endif
  106. /**
  107. * Allocates a dynamic block of memory of the wanted size. The exact allocation size might be slightly higher in
  108. * order to store block meta data.
  109. */
  110. MemBlock* allocBlock(UINT32 wantedSize);
  111. /** Frees a memory block. */
  112. void deallocBlock(MemBlock* block);
  113. };
  114. /** Allocator for the standard library that internally uses a frame allocator. */
  115. template <class T>
  116. class StdFrameAlloc
  117. {
  118. public:
  119. typedef T value_type;
  120. StdFrameAlloc() noexcept
  121. :mFrameAlloc(nullptr)
  122. { }
  123. StdFrameAlloc(FrameAlloc* alloc) noexcept
  124. :mFrameAlloc(alloc)
  125. { }
  126. template<class T> StdFrameAlloc(const StdFrameAlloc<T>& alloc) noexcept
  127. :mFrameAlloc(alloc.mFrameAlloc)
  128. { }
  129. template<class T> bool operator==(const StdFrameAlloc<T>&) const noexcept { return true; }
  130. template<class T> bool operator!=(const StdFrameAlloc<T>&) const noexcept { return false; }
  131. /** Allocate but don't initialize number elements of type T.*/
  132. T* allocate(const size_t num) const
  133. {
  134. if (num == 0)
  135. return nullptr;
  136. if (num > static_cast<size_t>(-1) / sizeof(T))
  137. throw std::bad_array_new_length();
  138. void* const pv = mFrameAlloc->alloc((UINT32)(num * sizeof(T)));
  139. if (!pv)
  140. throw std::bad_alloc();
  141. return static_cast<T*>(pv);
  142. }
  143. /** Deallocate storage p of deleted elements. */
  144. void deallocate(T* p, size_t num) const noexcept
  145. {
  146. mFrameAlloc->dealloc((UINT8*)p);
  147. }
  148. FrameAlloc* mFrameAlloc;
  149. };
  150. /** Return that all specializations of this allocator are interchangeable. */
  151. template <class T1, class T2>
  152. bool operator== (const StdFrameAlloc<T1>&,
  153. const StdFrameAlloc<T2>&) throw() {
  154. return true;
  155. }
  156. /** Return that all specializations of this allocator are interchangeable. */
  157. template <class T1, class T2>
  158. bool operator!= (const StdFrameAlloc<T1>&,
  159. const StdFrameAlloc<T2>&) throw() {
  160. return false;
  161. }
  162. /** @} */
  163. /** @endcond */
  164. }