33 #include <unordered_map>
35 #include <unordered_set>
39 #include "../../Primitives/interface/Errors.hpp"
40 #include "../../Primitives/interface/MemoryAllocator.h"
49 memset(ptr, Pattern, NumBytes);
52 # define FillWithDebugPattern(...)
63 virtual void*
Allocate(
size_t Size,
const Char* dbgDescription,
const char* dbgFileName,
const Int32 dbgLineNumber)
override final;
66 virtual void Free(
void* Ptr)
override final;
83 static constexpr
Uint8 NewPageMemPattern = 0xAA;
84 static constexpr
Uint8 AllocatedBlockMemPattern = 0xAB;
85 static constexpr
Uint8 DeallocatedBlockMemPattern = 0xDE;
86 static constexpr
Uint8 InitializedBlockMemPattern = 0xCF;
90 m_NumFreeBlocks {OwnerAllocator.m_NumBlocksInPage},
91 m_NumInitializedBlocks{0},
92 m_pOwnerAllocator {&OwnerAllocator}
95 auto PageSize = OwnerAllocator.m_BlockSize * OwnerAllocator.m_NumBlocksInPage;
96 m_pPageStart =
reinterpret_cast<Uint8*
>(
97 OwnerAllocator.m_RawMemoryAllocator.
Allocate(PageSize,
"FixedBlockMemoryAllocator page", __FILE__, __LINE__));
98 m_pNextFreeBlock = m_pPageStart;
102 MemoryPage(MemoryPage&& Page) noexcept :
104 m_NumFreeBlocks {Page.m_NumFreeBlocks },
105 m_NumInitializedBlocks{Page.m_NumInitializedBlocks},
106 m_pPageStart {Page.m_pPageStart },
107 m_pNextFreeBlock {Page.m_pNextFreeBlock },
108 m_pOwnerAllocator {Page.m_pOwnerAllocator }
111 Page.m_NumFreeBlocks = 0;
112 Page.m_NumInitializedBlocks = 0;
113 Page.m_pPageStart =
nullptr;
114 Page.m_pNextFreeBlock =
nullptr;
115 Page.m_pOwnerAllocator =
nullptr;
120 if (m_pOwnerAllocator)
121 m_pOwnerAllocator->m_RawMemoryAllocator.Free(m_pPageStart);
124 void* GetBlockStartAddress(
Uint32 BlockIndex)
const
127 VERIFY(BlockIndex >= 0 && BlockIndex < m_pOwnerAllocator->m_NumBlocksInPage,
"Invalid block index");
128 return reinterpret_cast<Uint8*
>(m_pPageStart) + BlockIndex * m_pOwnerAllocator->m_BlockSize;
131 #ifdef DILIGENT_DEBUG
134 size_t Delta =
reinterpret_cast<const Uint8*
>(pBlockAddr) -
reinterpret_cast<Uint8*
>(m_pPageStart);
135 VERIFY(Delta % m_pOwnerAllocator->m_BlockSize == 0,
"Invalid address");
136 Uint32 BlockIndex =
static_cast<Uint32>(Delta / m_pOwnerAllocator->m_BlockSize);
137 VERIFY(BlockIndex >= 0 && BlockIndex < m_pOwnerAllocator->m_NumBlocksInPage,
"Invalid block index");
140 # define dbgVerifyAddress(...)
147 if (m_NumFreeBlocks == 0)
149 VERIFY_EXPR(m_NumInitializedBlocks == m_pOwnerAllocator->m_NumBlocksInPage);
154 if (m_NumInitializedBlocks < m_pOwnerAllocator->m_NumBlocksInPage)
172 auto* pUninitializedBlock = GetBlockStartAddress(m_NumInitializedBlocks);
173 FillWithDebugPattern(pUninitializedBlock, InitializedBlockMemPattern, m_pOwnerAllocator->m_BlockSize);
174 void** ppNextBlock =
reinterpret_cast<void**
>(pUninitializedBlock);
175 ++m_NumInitializedBlocks;
176 if (m_NumInitializedBlocks < m_pOwnerAllocator->m_NumBlocksInPage)
177 *ppNextBlock = GetBlockStartAddress(m_NumInitializedBlocks);
179 *ppNextBlock =
nullptr;
182 void* res = m_pNextFreeBlock;
185 m_pNextFreeBlock = *
reinterpret_cast<void**
>(m_pNextFreeBlock);
187 if (m_NumFreeBlocks != 0)
196 void DeAllocate(
void* p)
203 *
reinterpret_cast<void**
>(p) = m_pNextFreeBlock;
204 m_pNextFreeBlock = p;
208 bool HasSpace()
const {
return m_NumFreeBlocks > 0; }
209 bool HasAllocations()
const {
return m_NumFreeBlocks < m_NumInitializedBlocks; }
212 MemoryPage(
const MemoryPage&) =
delete;
213 MemoryPage& operator=(
const MemoryPage) =
delete;
214 MemoryPage& operator=(MemoryPage&&) =
delete;
216 Uint32 m_NumFreeBlocks = 0;
217 Uint32 m_NumInitializedBlocks = 0;
218 void* m_pPageStart =
nullptr;
219 void* m_pNextFreeBlock =
nullptr;
223 std::vector<MemoryPage, STDAllocatorRawMem<MemoryPage>> m_PagePool;
224 std::unordered_set<size_t, std::hash<size_t>, std::equal_to<size_t>, STDAllocatorRawMem<size_t>> m_AvailablePages;
226 using AddrToPageIdMapElem = std::pair<void* const, size_t>;
227 std::unordered_map<void*, size_t, std::hash<void*>, std::equal_to<void*>, STDAllocatorRawMem<AddrToPageIdMapElem>> m_AddrToPageId;
231 IMemoryAllocator& m_RawMemoryAllocator;
232 const size_t m_BlockSize;
233 const Uint32 m_NumBlocksInPage;
238 template <
typename ObjectType>
244 #ifdef DILIGENT_DEBUG
245 if (m_bPoolInitialized && m_pRawAllocator != &Allocator)
247 LOG_WARNING_MESSAGE(
"Setting pool raw allocator after the pool has been initialized has no effect");
250 m_pRawAllocator = &Allocator;
254 #ifdef DILIGENT_DEBUG
255 if (m_bPoolInitialized && m_NumAllocationsInPage != NumAllocationsInPage)
257 LOG_WARNING_MESSAGE(
"Setting pool page size after the pool has been initialized has no effect");
260 m_NumAllocationsInPage = NumAllocationsInPage;
265 #ifdef DILIGENT_DEBUG
266 m_bPoolInitialized =
true;
271 template <
typename... CtorArgTypes>
272 ObjectType*
NewObject(
const Char* dbgDescription,
const char* dbgFileName,
const Int32 dbgLineNumber, CtorArgTypes&&... CtorArgs)
274 void* pRawMem = m_FixedBlockAlloctor.
Allocate(
sizeof(ObjectType), dbgDescription, dbgFileName, dbgLineNumber);
277 return new (pRawMem) ObjectType(std::forward<CtorArgTypes>(CtorArgs)...);
281 m_FixedBlockAlloctor.
Free(pRawMem);
291 m_FixedBlockAlloctor.
Free(pObj);
296 static Uint32 m_NumAllocationsInPage;
300 m_FixedBlockAlloctor(m_pRawAllocator ? *m_pRawAllocator :
GetRawAllocator(), sizeof(ObjectType), m_NumAllocationsInPage)
302 #ifdef DILIGENT_DEBUG
303 static bool m_bPoolInitialized;
305 FixedBlockMemoryAllocator m_FixedBlockAlloctor;
307 template <
typename ObjectType>
308 Uint32 ObjectPool<ObjectType>::m_NumAllocationsInPage = 64;
310 template <
typename ObjectType>
311 IMemoryAllocator* ObjectPool<ObjectType>::m_pRawAllocator =
nullptr;
313 #ifdef DILIGENT_DEBUG
314 template <
typename ObjectType>
315 bool ObjectPool<ObjectType>::m_bPoolInitialized =
false;
318 #define SET_POOL_RAW_ALLOCATOR(ObjectType, Allocator) ObjectPool<ObjectType>::SetRawAllocator(Allocator)
319 #define SET_POOL_PAGE_SIZE(ObjectType, NumAllocationsInPage) ObjectPool<ObjectType>::SetPageSize(NumAllocationsInPage)
320 #define NEW_POOL_OBJECT(ObjectType, Desc, ...) ObjectPool<ObjectType>::GetPool().NewObject(Desc, __FILE__, __LINE__, ##__VA_ARGS__)
321 #define DESTROY_POOL_OBJECT(pObject) ObjectPool<std::remove_reference<decltype(*pObject)>::type>::GetPool().Destroy(pObject)