632 lines
20 KiB
C
632 lines
20 KiB
C
/*
|
|
pl_memory
|
|
* no dependencies
|
|
* simple
|
|
|
|
Do this:
|
|
#define PL_MEMORY_IMPLEMENTATION
|
|
before you include this file in *one* C or C++ file to create the implementation.
|
|
// i.e. it should look like this:
|
|
#include ...
|
|
#include ...
|
|
#include ...
|
|
#define PL_MEMORY_IMPLEMENTATION
|
|
#include "pl_memory.h"
|
|
Notes:
|
|
* allocations return NULL on failure
|
|
* general allocation uses malloc, free, & realloc by default
|
|
* override general allocators by defining PL_MEMORY_ALLOC(x), PL_MEMORY_FREE(x)
|
|
* override assert by defining PL_ASSERT(x)
|
|
*/
|
|
|
|
// library version
|
|
#define PL_MEMORY_VERSION "0.6.0"
|
|
#define PL_MEMORY_VERSION_NUM 00600
|
|
|
|
/*
|
|
Index of this file:
|
|
// [SECTION] header mess
|
|
// [SECTION] defines
|
|
// [SECTION] includes
|
|
// [SECTION] forward declarations & basic types
|
|
// [SECTION] public api
|
|
// [SECTION] structs
|
|
// [SECTION] c/c++ file start
|
|
*/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// [SECTION] header mess
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#ifndef PL_MEMORY_H
|
|
#define PL_MEMORY_H
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// [SECTION] defines
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#ifndef PL_MEMORY_TEMP_STACK_SIZE
|
|
#define PL_MEMORY_TEMP_STACK_SIZE 1024
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// [SECTION] includes
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <stddef.h> // size_t
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// [SECTION] forward declarations & basic types
|
|
//-----------------------------------------------------------------------------
|
|
|
|
typedef struct _plTempAllocator plTempAllocator;
|
|
typedef struct _plStackAllocator plStackAllocator;
|
|
typedef struct _plPoolAllocator plPoolAllocator;
|
|
typedef struct _plPoolAllocatorNode plPoolAllocatorNode;
|
|
|
|
typedef size_t plStackAllocatorMarker;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// [SECTION] public api
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~general purpose allocation~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void* pl_aligned_alloc(size_t szAlignment, size_t);
|
|
void pl_aligned_free (void*);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~temporary allocator~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void* pl_temp_allocator_alloc (plTempAllocator*, size_t);
|
|
void pl_temp_allocator_reset (plTempAllocator*);
|
|
void pl_temp_allocator_free (plTempAllocator*);
|
|
char* pl_temp_allocator_sprintf(plTempAllocator*, const char* cPFormat, ...);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~stack allocators~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
// common
|
|
void pl_stack_allocator_init(plStackAllocator*, size_t, void*);
|
|
|
|
// single stack
|
|
void* pl_stack_allocator_alloc (plStackAllocator*, size_t);
|
|
void* pl_stack_allocator_aligned_alloc (plStackAllocator*, size_t, size_t szAlignment);
|
|
plStackAllocatorMarker pl_stack_allocator_marker (plStackAllocator*);
|
|
void pl_stack_allocator_free_to_marker(plStackAllocator*, plStackAllocatorMarker);
|
|
void pl_stack_allocator_reset (plStackAllocator*);
|
|
|
|
// double sided stack
|
|
void* pl_stack_allocator_aligned_alloc_bottom (plStackAllocator*, size_t, size_t szAlignment);
|
|
plStackAllocatorMarker pl_stack_allocator_top_marker (plStackAllocator*);
|
|
plStackAllocatorMarker pl_stack_allocator_bottom_marker (plStackAllocator*);
|
|
void* pl_stack_allocator_alloc_bottom (plStackAllocator*, size_t);
|
|
void* pl_stack_allocator_alloc_top (plStackAllocator*, size_t);
|
|
void pl_stack_allocator_free_top_to_marker (plStackAllocator*, plStackAllocatorMarker);
|
|
void pl_stack_allocator_free_bottom_to_marker(plStackAllocator*, plStackAllocatorMarker);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pool allocator~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void pl_pool_allocator_init (plPoolAllocator*, size_t szItemCount, size_t szItemSize, size_t szItemAlignment, size_t* pszBufferSize, void*);
|
|
void* pl_pool_allocator_alloc(plPoolAllocator*);
|
|
void pl_pool_allocator_free (plPoolAllocator*, void* pItem);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// [SECTION] structs
|
|
//-----------------------------------------------------------------------------
|
|
|
|
typedef struct _plTempAllocator
|
|
{
|
|
size_t szSize;
|
|
size_t szOffset;
|
|
char* pcBuffer;
|
|
char acStackBuffer[PL_MEMORY_TEMP_STACK_SIZE];
|
|
char** ppcMemoryBlocks;
|
|
size_t szMemoryBlockCount;
|
|
size_t szMemoryBlockCapacity;
|
|
} plTempAllocator;
|
|
|
|
typedef struct _plStackAllocator
|
|
{
|
|
unsigned char* pucBuffer;
|
|
size_t szSize;
|
|
size_t szBottomOffset;
|
|
size_t szTopOffset;
|
|
} plStackAllocator;
|
|
|
|
typedef struct _plPoolAllocatorNode
|
|
{
|
|
plPoolAllocatorNode* ptNextNode;
|
|
} plPoolAllocatorNode;
|
|
|
|
typedef struct _plPoolAllocator
|
|
{
|
|
unsigned char* pucBuffer;
|
|
size_t szGivenSize;
|
|
size_t szUsableSize;
|
|
size_t szRequestedItemSize;
|
|
size_t szItemSize;
|
|
size_t szFreeItems;
|
|
plPoolAllocatorNode* pFreeList;
|
|
} plPoolAllocator;
|
|
|
|
#endif // PL_MEMORY_H
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// [SECTION] c/c++ file start
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/*
|
|
Index of this file:
|
|
// [SECTION] defines
|
|
// [SECTION] internal api
|
|
// [SECTION] public api implementation
|
|
// [SECTION] internal api implementation
|
|
*/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// [SECTION] defines
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#ifdef PL_MEMORY_IMPLEMENTATION
|
|
|
|
#if defined(PL_MEMORY_ALLOC) && defined(PL_MEMORY_FREE)
|
|
// ok
|
|
#elif !defined(PL_MEMORY_ALLOC) && !defined(PL_MEMORY_FREE)
|
|
// ok
|
|
#else
|
|
#error "Must define both or none of PL_MEMORY_ALLOC and PL_MEMORY_FREE"
|
|
#endif
|
|
|
|
#ifndef PL_MEMORY_ALLOC
|
|
#include <stdlib.h>
|
|
#define PL_MEMORY_ALLOC(x) malloc(x)
|
|
#define PL_MEMORY_FREE(x) free(x)
|
|
#endif
|
|
|
|
|
|
#ifndef PL_ASSERT
|
|
#include <assert.h>
|
|
#define PL_ASSERT(x) assert((x))
|
|
#endif
|
|
|
|
#ifndef PL_MEMORY_TEMP_STACK_BLOCK_SIZE
|
|
#define PL_MEMORY_TEMP_BLOCK_SIZE 4194304
|
|
#endif
|
|
|
|
#define PL__ALIGN_UP(num, align) (((num) + ((align)-1)) & ~((align)-1))
|
|
|
|
#ifndef pl_vnsprintf
|
|
#include <stdio.h>
|
|
#define pl_vnsprintf vnsprintf
|
|
#endif
|
|
|
|
#include <stdarg.h>
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// [SECTION] internal api
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static inline size_t
|
|
pl__get_next_power_of_2(size_t n)
|
|
{
|
|
size_t ulResult = 1;
|
|
if (n && !(n & (n - 1)))
|
|
ulResult = n;
|
|
while (ulResult < n)
|
|
ulResult <<= 1;
|
|
return ulResult;
|
|
}
|
|
|
|
static inline uintptr_t
|
|
pl__align_forward_uintptr(uintptr_t ptr, size_t szAlign)
|
|
{
|
|
PL_ASSERT((szAlign & (szAlign-1)) == 0 && "alignment must be power of 2");
|
|
uintptr_t a = (uintptr_t)szAlign;
|
|
uintptr_t p = ptr;
|
|
uintptr_t pModulo = p & (a - 1);
|
|
if (pModulo != 0){ p += a - pModulo;}
|
|
return p;
|
|
}
|
|
|
|
static inline size_t
|
|
pl__align_forward_size(size_t szPtr, size_t szAlign)
|
|
{
|
|
PL_ASSERT((szAlign & (szAlign-1)) == 0 && "alignment must be power of 2");
|
|
size_t a = szAlign;
|
|
size_t p = szPtr;
|
|
size_t szModulo = p & (a - 1);
|
|
if (szModulo != 0){ p += a - szModulo;}
|
|
return p;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// [SECTION] public api implementation
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void*
|
|
pl_aligned_alloc(size_t szAlignment, size_t szSize)
|
|
{
|
|
void* pBuffer = NULL;
|
|
|
|
// ensure power of 2
|
|
PL_ASSERT((szAlignment & (szAlignment -1)) == 0 && "alignment must be a power of 2");
|
|
|
|
if(szAlignment && szSize)
|
|
{
|
|
// allocate extra bytes for alignment
|
|
uint64_t ulHeaderSize = sizeof(uint64_t) + (szAlignment - 1);
|
|
void* pActualBuffer = PL_MEMORY_ALLOC(szSize + ulHeaderSize);
|
|
|
|
if(pActualBuffer)
|
|
{
|
|
// add offset size to pointer & align
|
|
pBuffer = (void*)PL__ALIGN_UP(((uintptr_t)pActualBuffer + sizeof(uint64_t)), szAlignment);
|
|
|
|
// calculate offset & store it behind aligned pointer
|
|
*((uint64_t*)pBuffer - 1) = (uint64_t)((uintptr_t)pBuffer - (uintptr_t)pActualBuffer);
|
|
}
|
|
}
|
|
return pBuffer;
|
|
}
|
|
|
|
void
|
|
pl_aligned_free(void* pBuffer)
|
|
{
|
|
PL_ASSERT(pBuffer);
|
|
|
|
// get stored offset
|
|
uint64_t ulOffset = *((uint64_t*)pBuffer - 1);
|
|
|
|
// get original buffer to free
|
|
void* pActualBuffer = ((uint8_t*)pBuffer - ulOffset);
|
|
PL_MEMORY_FREE(pActualBuffer);
|
|
}
|
|
|
|
void*
|
|
pl_temp_allocator_alloc(plTempAllocator* ptAllocator, size_t szSize)
|
|
{
|
|
|
|
if(ptAllocator->szSize == 0) // first usage ever
|
|
{
|
|
ptAllocator->ppcMemoryBlocks = NULL;
|
|
ptAllocator->szMemoryBlockCount = 0;
|
|
ptAllocator->szMemoryBlockCapacity = 0;
|
|
ptAllocator->szSize = PL_MEMORY_TEMP_STACK_SIZE;
|
|
ptAllocator->pcBuffer = ptAllocator->acStackBuffer;
|
|
ptAllocator->szOffset = 0;
|
|
memset(ptAllocator->acStackBuffer, 0, PL_MEMORY_TEMP_STACK_SIZE);
|
|
}
|
|
|
|
void* pRequestedMemory = NULL;
|
|
|
|
// not enough room is available
|
|
if(szSize > ptAllocator->szSize - ptAllocator->szOffset)
|
|
{
|
|
PL_ASSERT(szSize < PL_MEMORY_TEMP_BLOCK_SIZE);
|
|
if(ptAllocator->szMemoryBlockCapacity == 0) // first overflow
|
|
{
|
|
// allocate block array
|
|
ptAllocator->szMemoryBlockCapacity = 1;
|
|
ptAllocator->ppcMemoryBlocks = (char**)PL_MEMORY_ALLOC(sizeof(char*) * ptAllocator->szMemoryBlockCapacity);
|
|
memset(ptAllocator->ppcMemoryBlocks, 0, (sizeof(char*) * ptAllocator->szMemoryBlockCapacity));
|
|
|
|
// allocate first block
|
|
ptAllocator->ppcMemoryBlocks[0] = (char*)PL_MEMORY_ALLOC(PL_MEMORY_TEMP_BLOCK_SIZE);
|
|
ptAllocator->szSize = PL_MEMORY_TEMP_BLOCK_SIZE;
|
|
ptAllocator->szOffset = 0;
|
|
ptAllocator->pcBuffer = ptAllocator->ppcMemoryBlocks[0];
|
|
}
|
|
else if(ptAllocator->szMemoryBlockCount == ptAllocator->szMemoryBlockCapacity) // grow memory block storage
|
|
{
|
|
char** ppcOldBlocks = ptAllocator->ppcMemoryBlocks;
|
|
ptAllocator->ppcMemoryBlocks = (char**)PL_MEMORY_ALLOC(sizeof(char*) * (ptAllocator->szMemoryBlockCapacity + 1));
|
|
memset(ptAllocator->ppcMemoryBlocks, 0, (sizeof(char*) * (ptAllocator->szMemoryBlockCapacity + 1)));
|
|
memcpy(ptAllocator->ppcMemoryBlocks, ppcOldBlocks, sizeof(char*) * ptAllocator->szMemoryBlockCapacity);
|
|
ptAllocator->szMemoryBlockCapacity++;
|
|
ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount] = (char*)PL_MEMORY_ALLOC(PL_MEMORY_TEMP_BLOCK_SIZE);
|
|
ptAllocator->szSize = PL_MEMORY_TEMP_BLOCK_SIZE;
|
|
ptAllocator->pcBuffer = ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount];
|
|
ptAllocator->szOffset = 0;
|
|
}
|
|
else // block is available
|
|
{
|
|
ptAllocator->szSize = PL_MEMORY_TEMP_BLOCK_SIZE;
|
|
ptAllocator->szOffset = 0;
|
|
ptAllocator->pcBuffer = ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount];
|
|
}
|
|
|
|
ptAllocator->szMemoryBlockCount++;
|
|
}
|
|
|
|
pRequestedMemory = &ptAllocator->pcBuffer[ptAllocator->szOffset];
|
|
ptAllocator->szOffset += szSize;
|
|
return pRequestedMemory;
|
|
}
|
|
|
|
void
|
|
pl_temp_allocator_reset(plTempAllocator* ptAllocator)
|
|
{
|
|
ptAllocator->szSize = PL_MEMORY_TEMP_STACK_SIZE;
|
|
ptAllocator->szOffset = 0;
|
|
ptAllocator->szMemoryBlockCount = 0;
|
|
ptAllocator->pcBuffer = ptAllocator->acStackBuffer;
|
|
}
|
|
|
|
void
|
|
pl_temp_allocator_free(plTempAllocator* ptAllocator)
|
|
{
|
|
for(size_t i = 0; i < ptAllocator->szMemoryBlockCapacity; i++)
|
|
{
|
|
PL_MEMORY_FREE(ptAllocator->ppcMemoryBlocks[i]);
|
|
}
|
|
if(ptAllocator->ppcMemoryBlocks)
|
|
PL_MEMORY_FREE(ptAllocator->ppcMemoryBlocks);
|
|
ptAllocator->ppcMemoryBlocks = NULL;
|
|
ptAllocator->szMemoryBlockCapacity = 0;
|
|
ptAllocator->szMemoryBlockCount = 0;
|
|
ptAllocator->pcBuffer = NULL;
|
|
ptAllocator->szSize = 0;
|
|
ptAllocator->szOffset = 0;
|
|
}
|
|
|
|
inline static char*
|
|
pl__temp_allocator_sprintf_va(plTempAllocator* ptAllocator, const char* cPFormat, va_list args)
|
|
{
|
|
void* pRequestedMemory = NULL;
|
|
|
|
// sprint
|
|
va_list args2;
|
|
va_copy(args2, args);
|
|
int32_t n = pl_vnsprintf(NULL, 0, cPFormat, args2);
|
|
va_end(args2);
|
|
|
|
pRequestedMemory = pl_temp_allocator_alloc(ptAllocator, n + 1);
|
|
memset(pRequestedMemory, 0, n + 1);
|
|
pl_vnsprintf(pRequestedMemory, n + 1, cPFormat, args);
|
|
|
|
return pRequestedMemory;
|
|
}
|
|
|
|
char*
|
|
pl_temp_allocator_sprintf(plTempAllocator* ptAllocator, const char* cPFormat, ...)
|
|
{
|
|
void* pRequestedMemory = NULL;
|
|
|
|
va_list argptr;
|
|
va_start(argptr, cPFormat);
|
|
pRequestedMemory = pl__temp_allocator_sprintf_va(ptAllocator, cPFormat, argptr);
|
|
va_end(argptr);
|
|
|
|
return pRequestedMemory;
|
|
}
|
|
|
|
void
|
|
pl_stack_allocator_init(plStackAllocator* ptAllocator, size_t szSize, void* pBuffer)
|
|
{
|
|
PL_ASSERT(ptAllocator);
|
|
PL_ASSERT(szSize > 0);
|
|
PL_ASSERT(pBuffer);
|
|
|
|
ptAllocator->pucBuffer = (unsigned char*)pBuffer;
|
|
ptAllocator->szSize = szSize;
|
|
ptAllocator->szBottomOffset = 0;
|
|
ptAllocator->szTopOffset = szSize;
|
|
}
|
|
|
|
void*
|
|
pl_stack_allocator_alloc(plStackAllocator* ptAllocator, size_t szSize)
|
|
{
|
|
size_t szOffset = ptAllocator->szBottomOffset + szSize;
|
|
|
|
PL_ASSERT(szOffset < ptAllocator->szTopOffset && "stack allocator full");
|
|
|
|
// update offset
|
|
void* pBuffer = ptAllocator->pucBuffer + ptAllocator->szBottomOffset;
|
|
ptAllocator->szBottomOffset = szOffset;
|
|
|
|
return pBuffer;
|
|
}
|
|
|
|
void*
|
|
pl_stack_allocator_aligned_alloc(plStackAllocator* ptAllocator, size_t szSize, size_t szAlignment)
|
|
{
|
|
void* pBuffer = NULL;
|
|
|
|
szAlignment = pl__get_next_power_of_2(szAlignment);
|
|
uintptr_t pCurrentPointer = (uintptr_t)ptAllocator->pucBuffer + (uintptr_t)ptAllocator->szBottomOffset;
|
|
uintptr_t pOffset = pl__align_forward_uintptr(pCurrentPointer, szAlignment);
|
|
pOffset -= (uintptr_t)ptAllocator->pucBuffer;
|
|
|
|
PL_ASSERT(pOffset + szSize <= ptAllocator->szTopOffset && "linear allocator full");
|
|
|
|
// check if allocator has enough space left
|
|
if(pOffset + szSize <= ptAllocator->szSize)
|
|
{
|
|
pBuffer = &ptAllocator->pucBuffer[pOffset];
|
|
ptAllocator->szBottomOffset = pOffset + szSize;
|
|
|
|
// zero new memory
|
|
memset(pBuffer, 0, szSize);
|
|
}
|
|
return pBuffer;
|
|
}
|
|
|
|
void*
|
|
pl_stack_allocator_aligned_alloc_bottom(plStackAllocator* ptAllocator, size_t szSize, size_t szAlignment)
|
|
{
|
|
return pl_stack_allocator_aligned_alloc(ptAllocator, szSize, szAlignment);
|
|
}
|
|
|
|
void*
|
|
pl_stack_allocator_aligned_alloc_top(plStackAllocator* ptAllocator, size_t szSize, size_t szAlignment)
|
|
{
|
|
void* pBuffer = NULL;
|
|
|
|
szAlignment = pl__get_next_power_of_2(szAlignment);
|
|
uintptr_t pCurrentPointer = (uintptr_t)ptAllocator->pucBuffer + (uintptr_t)ptAllocator->szBottomOffset;
|
|
uintptr_t pOffset = pl__align_forward_uintptr(pCurrentPointer, szAlignment);
|
|
pOffset -= (uintptr_t)ptAllocator->pucBuffer;
|
|
|
|
PL_ASSERT(pOffset + szSize <= ptAllocator->szTopOffset && "linear allocator full");
|
|
|
|
// check if allocator has enough space left
|
|
if(pOffset + szSize <= ptAllocator->szSize)
|
|
{
|
|
pBuffer = &ptAllocator->pucBuffer[pOffset];
|
|
ptAllocator->szBottomOffset = pOffset + szSize;
|
|
|
|
// zero new memory
|
|
memset(pBuffer, 0, szSize);
|
|
}
|
|
return pBuffer;
|
|
}
|
|
|
|
void*
|
|
pl_stack_allocator_alloc_bottom(plStackAllocator* ptAllocator, size_t szSize)
|
|
{
|
|
return pl_stack_allocator_alloc(ptAllocator, szSize);
|
|
}
|
|
|
|
void*
|
|
pl_stack_allocator_alloc_top(plStackAllocator* ptAllocator, size_t szSize)
|
|
{
|
|
size_t szOffset = ptAllocator->szTopOffset - szSize;
|
|
|
|
PL_ASSERT(szOffset > ptAllocator->szBottomOffset && szOffset < ptAllocator->szTopOffset && "stack allocator full");
|
|
|
|
// update offset
|
|
void* pBuffer = ptAllocator->pucBuffer + szOffset;
|
|
ptAllocator->szTopOffset = szOffset;
|
|
|
|
return pBuffer;
|
|
}
|
|
|
|
plStackAllocatorMarker
|
|
pl_stack_allocator_marker(plStackAllocator* ptAllocator)
|
|
{
|
|
plStackAllocatorMarker tMarker = ptAllocator->szBottomOffset;
|
|
return tMarker;
|
|
}
|
|
|
|
plStackAllocatorMarker
|
|
pl_stack_allocator_bottom_marker(plStackAllocator* ptAllocator)
|
|
{
|
|
return pl_stack_allocator_marker(ptAllocator);
|
|
}
|
|
|
|
plStackAllocatorMarker
|
|
pl_stack_allocator_top_marker(plStackAllocator* ptAllocator)
|
|
{
|
|
plStackAllocatorMarker tMarker = ptAllocator->szTopOffset;
|
|
return tMarker;
|
|
}
|
|
|
|
void
|
|
pl_stack_allocator_free_to_marker(plStackAllocator* ptAllocator, plStackAllocatorMarker tMarker)
|
|
{
|
|
ptAllocator->szBottomOffset = tMarker;
|
|
|
|
#ifdef _DEBUG
|
|
memset(&ptAllocator->pucBuffer[ptAllocator->szBottomOffset], 0, ptAllocator->szTopOffset - ptAllocator->szBottomOffset);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
pl_stack_allocator_free_top_to_marker(plStackAllocator* ptAllocator, plStackAllocatorMarker tMarker)
|
|
{
|
|
ptAllocator->szTopOffset = tMarker;
|
|
|
|
#ifdef _DEBUG
|
|
memset(&ptAllocator->pucBuffer[ptAllocator->szBottomOffset], 0, ptAllocator->szTopOffset - ptAllocator->szBottomOffset);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
pl_stack_allocator_free_bottom_to_marker(plStackAllocator* ptAllocator, plStackAllocatorMarker tMarker)
|
|
{
|
|
ptAllocator->szBottomOffset = tMarker;
|
|
|
|
#ifdef _DEBUG
|
|
memset(&ptAllocator->pucBuffer[ptAllocator->szBottomOffset], 0, ptAllocator->szTopOffset - ptAllocator->szBottomOffset);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
pl_stack_allocator_reset(plStackAllocator* ptAllocator)
|
|
{
|
|
ptAllocator->szBottomOffset = 0;
|
|
ptAllocator->szTopOffset = ptAllocator->szSize;
|
|
|
|
#ifdef _DEBUG
|
|
memset(ptAllocator->pucBuffer, 0, ptAllocator->szSize);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
pl_pool_allocator_init(plPoolAllocator* ptAllocator, size_t szItemCount, size_t szItemSize, size_t szItemAlignment, size_t* pszBufferSize, void* pBuffer)
|
|
{
|
|
PL_ASSERT(ptAllocator);
|
|
PL_ASSERT(szItemCount > 0);
|
|
PL_ASSERT(szItemSize > 0);
|
|
PL_ASSERT(pszBufferSize);
|
|
|
|
if(szItemAlignment == 0)
|
|
{
|
|
szItemAlignment = pl__get_next_power_of_2(szItemSize);
|
|
}
|
|
|
|
if(pBuffer == NULL)
|
|
{
|
|
size_t szAlignedItemSize = pl__align_forward_size(szItemSize, szItemAlignment);
|
|
*pszBufferSize = szAlignedItemSize * szItemCount + szItemAlignment;
|
|
return;
|
|
}
|
|
|
|
ptAllocator->szFreeItems = szItemCount;
|
|
ptAllocator->szRequestedItemSize = szItemSize;
|
|
ptAllocator->szGivenSize = *pszBufferSize;
|
|
ptAllocator->szUsableSize = *pszBufferSize;
|
|
ptAllocator->pucBuffer = (unsigned char*)pBuffer;
|
|
ptAllocator->szItemSize = pl__align_forward_size(szItemSize, szItemAlignment);
|
|
|
|
uintptr_t pInitialStart = (uintptr_t)pBuffer;
|
|
uintptr_t pStart = pl__align_forward_uintptr(pInitialStart, (uintptr_t)szItemAlignment);
|
|
ptAllocator->szUsableSize -= (size_t)(pStart - pInitialStart);
|
|
|
|
PL_ASSERT(ptAllocator->szItemSize >= sizeof(plPoolAllocatorNode) && "pool allocator item size too small");
|
|
PL_ASSERT(ptAllocator->szUsableSize >= ptAllocator->szItemSize * szItemCount && "pool allocator buffer size too small");
|
|
|
|
unsigned char* pUsableBuffer = (unsigned char*)pStart;
|
|
for(size_t i = 0; i < szItemCount - 1; i++)
|
|
{
|
|
plPoolAllocatorNode* pNode0 = (plPoolAllocatorNode*)&pUsableBuffer[i * ptAllocator->szItemSize];
|
|
plPoolAllocatorNode* pNode1 = (plPoolAllocatorNode*)&pUsableBuffer[(i + 1) * ptAllocator->szItemSize];
|
|
pNode0->ptNextNode = pNode1;
|
|
}
|
|
ptAllocator->pFreeList = (plPoolAllocatorNode*)pUsableBuffer;
|
|
}
|
|
|
|
void*
|
|
pl_pool_allocator_alloc(plPoolAllocator* ptAllocator)
|
|
{
|
|
if(ptAllocator->szFreeItems == 0)
|
|
return NULL;
|
|
ptAllocator->szFreeItems--;
|
|
plPoolAllocatorNode* pFirstNode = ptAllocator->pFreeList;
|
|
plPoolAllocatorNode* ptNextNode = pFirstNode->ptNextNode;
|
|
ptAllocator->pFreeList = ptNextNode;
|
|
memset(pFirstNode, 0, ptAllocator->szItemSize);
|
|
return pFirstNode;
|
|
}
|
|
|
|
void
|
|
pl_pool_allocator_free(plPoolAllocator* ptAllocator, void* pItem)
|
|
{
|
|
ptAllocator->szFreeItems++;
|
|
plPoolAllocatorNode* pOldFreeNode = ptAllocator->pFreeList;
|
|
ptAllocator->pFreeList = (plPoolAllocatorNode*)pItem;
|
|
ptAllocator->pFreeList->ptNextNode = pOldFreeNode;
|
|
}
|
|
|
|
#endif
|