3#include <OsoMemoryProfiler/OsoMemoryProfiler.h>
23 elementSize(elementSize),
28 assert(elementSize >=
sizeof(PoolHeader) &&
"Element size must be at least enough to store a pointer.");
29 assert(pageSize <= std::numeric_limits<ElementOffset>::max() &&
"Page size must be smaller or equal to max element offset.");
36 assert(desiredCapacity >= capacity &&
"Pool does not support shrinkage.");
38 const size_t numPages = (desiredCapacity / pageSize) + ((desiredCapacity % pageSize) ? 1 : 0);
40 assert(numPages <= std::numeric_limits<ElementOffset>::max() &&
"Page count must be smaller or equal to max element offset.");
43 while (numPages > pages.size()) {
47 capacity = pages.size() * pageSize;
53 pages.emplace_back(pageSize * elementSize, allocator, memType);
56 auto data =
static_cast<uint8_t *
>(pages.back().data());
59 for (
size_t i = 0; i < pageSize; ++i) {
60 PoolHeader * block =
reinterpret_cast<PoolHeader *
>(data + i * elementSize);
62 block->next =
reinterpret_cast<PoolHeader *
>(data + (i + 1) * elementSize);
66 reinterpret_cast<PoolHeader *
>(data + (pageSize - 1) * elementSize)->next =
nullptr;
75 PoolHeader * last =
static_cast<PoolHeader *
>(freeHead);
78 last =
static_cast<PoolHeader *
>(last->next);
88 if (!freeHead) resize(capacity + pageSize);
91 auto element =
static_cast<PoolHeader *
>(freeHead);
95 freeHead = element->next;
100 uint8_t* mem =
static_cast<uint8_t*
>(std::malloc(
sizeof(
void*) + elementSize));
101 *
reinterpret_cast<PoolHeader**
>(mem) = element;
102 element->next = mem +
sizeof(
void*);
103 return element->next;
111#ifdef COGS_HEAP_DEBUG
112 void * foo =
static_cast<char*
>(element) -
sizeof(
void*);
113 element = *
static_cast<PoolHeader**
>(foo);
117 assert(numAllocated &&
"No available elements to free.");
121 static_cast<PoolHeader *
>(element)->next = freeHead;
127#ifdef COGS_HEAP_DEBUG
128 element = *
reinterpret_cast<PoolHeader**
>(
static_cast<char*
>(element) -
sizeof(
void*));
131 for (
size_t i = 0; i < pages.size(); ++i) {
132 auto & page = pages[i];
133 auto data =
static_cast<const uint8_t *
>(page.data());
135 const auto pageBegin = data;
136 const auto pageEnd = data + pageSize * elementSize;
138 if (element >= pageBegin && element < pageEnd) {
139 const size_t offsetInBytes =
static_cast<uint8_t *
>(element) - pageBegin;
148 assert(
false &&
"Element not part of any allocated pages.");
155 const auto pageIndex = getPageIndex(handle);
157 assert(pageIndex < pages.size() &&
"Page index out of range.");
159 const auto elementIndex = getElementOffset(handle);
161 assert(elementIndex < pageSize &&
"Element index out of range.");
163 auto elementPtr =
reinterpret_cast<uint8_t *
>(pages[pageIndex].data()) + elementIndex * elementSize;
165#ifdef COGS_HEAP_DEBUG
166 return reinterpret_cast<PoolHeader *
>(elementPtr)->next;
174 if (!isValid(handle))
return false;
175 const auto pageIndex = getPageIndex(handle);
176 const auto elementIndex = getElementOffset(handle);
177 const void* elementPtr =
static_cast<const void*
>(
reinterpret_cast<const uint8_t*
>(pages[pageIndex].data()) + elementIndex * elementSize);
179 PoolHeader* last =
static_cast<PoolHeader*
>(freeHead);
182 if (last == elementPtr)
184 last =
static_cast<PoolHeader*
>(last->next);
Base allocator implementation.
uint16_t ElementOffset
Offset type used to index elements in resource pools.
uint32_t ElementHandle
Handle type for elements.
void addPage(size_t pageSize)
Adds a new page to the pool, with the given size in number of elements.
void * allocate()
Allocate storage for a single new element, returning the pointer to the uninitialized storage.
ElementHandle getHandle(void *element) const
Get a handle to the given element.
void resize(size_t capacity)
Resize the pool to have storage for the given capacity number of elements.
bool isAllocated(ElementHandle handle) const
Checks if the given handle is a valid handle to an allocated element.
void deallocate(void *element)
Deallocate the given element, returning the memory to be managed by the pool.
PoolBase(size_t elementSize, size_t initialCapacity, size_t pageSize, Memory::Allocator *allocator=Memory::Allocator::defaultAllocator(), MemBlockType memType=MemBlockType::Bucket)
Construct a pool base with the given parameters.
void * getElement(ElementHandle handle)
Get a pointer to the element indexed by the given handle.