Rename membuffer to memstack

This commit is contained in:
Doyle Thai 2017-05-22 18:34:10 +10:00
parent 8ce4221ad2
commit 2c745d3571
5 changed files with 187 additions and 188 deletions

View File

@ -79,15 +79,15 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read)) if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read))
return false; // TODO(doyle): Logging return false; // TODO(doyle): Logging
DqnTempBuffer tmpMemRegion = DqnMemBuffer_BeginTempRegion(&memory->transientBuffer); DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack);
u8 *rawBytes = (u8 *)DqnMemBuffer_Allocate(&memory->transientBuffer, file.size); u8 *rawBytes = (u8 *)DqnMemStack_Allocate(&memory->transMemStack, file.size);
size_t bytesRead = api.FileRead(&file, rawBytes, file.size); size_t bytesRead = api.FileRead(&file, rawBytes, file.size);
size_t fileSize = file.size; size_t fileSize = file.size;
api.FileClose(&file); api.FileClose(&file);
if (bytesRead != file.size) if (bytesRead != file.size)
{ {
// TODO(doyle): Logging // TODO(doyle): Logging
DqnMemBuffer_EndTempRegion(tmpMemRegion); DqnMemStack_EndTempRegion(tmpMemRegion);
return false; return false;
} }
@ -101,7 +101,7 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
WavefrontObj obj = {}; WavefrontObj obj = {};
if (!ObjWaveFrontInit(&obj)) if (!ObjWaveFrontInit(&obj))
{ {
DqnMemBuffer_EndTempRegion(tmpMemRegion); DqnMemStack_EndTempRegion(tmpMemRegion);
return false; return false;
} }
@ -310,8 +310,8 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
DQN_ASSERT(obj.model.groupNameIndex + 1 < DQN_ARRAY_COUNT(obj.model.groupName)); DQN_ASSERT(obj.model.groupNameIndex + 1 < DQN_ARRAY_COUNT(obj.model.groupName));
DQN_ASSERT(!obj.model.groupName[obj.model.groupNameIndex]); DQN_ASSERT(!obj.model.groupName[obj.model.groupNameIndex]);
obj.model.groupName[obj.model.groupNameIndex++] = (char *)DqnMemBuffer_Allocate( obj.model.groupName[obj.model.groupNameIndex++] = (char *)DqnMemStack_Allocate(
&memory->permanentBuffer, (nameLen + 1) * sizeof(char)); &memory->permMemStack, (nameLen + 1) * sizeof(char));
for (i32 i = 0; i < nameLen; i++) for (i32 i = 0; i < nameLen; i++)
obj.model.groupName[obj.model.groupNameIndex - 1][i] = namePtr[i]; obj.model.groupName[obj.model.groupNameIndex - 1][i] = namePtr[i];
@ -370,7 +370,7 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
} }
} }
DqnMemBuffer_EndTempRegion(tmpMemRegion); DqnMemStack_EndTempRegion(tmpMemRegion);
return true; return true;
} }
@ -396,14 +396,14 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read)) if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read))
return false; // TODO(doyle): Logging return false; // TODO(doyle): Logging
DqnTempBuffer tmpMemRegion = DqnMemBuffer_BeginTempRegion(&memory->transientBuffer); DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack);
u8 *fontBuf = (u8 *)DqnMemBuffer_Allocate(&memory->transientBuffer, file.size); u8 *fontBuf = (u8 *)DqnMemStack_Allocate(&memory->transMemStack, file.size);
size_t bytesRead = api.FileRead(&file, fontBuf, file.size); size_t bytesRead = api.FileRead(&file, fontBuf, file.size);
api.FileClose(&file); api.FileClose(&file);
if (bytesRead != file.size) if (bytesRead != file.size)
{ {
// TODO(doyle): Logging // TODO(doyle): Logging
DqnMemBuffer_EndTempRegion(tmpMemRegion); DqnMemStack_EndTempRegion(tmpMemRegion);
return false; return false;
} }
@ -418,8 +418,8 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Pack font data to bitmap // Pack font data to bitmap
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
loadedFont.bitmap = (u8 *)DqnMemBuffer_Allocate( loadedFont.bitmap = (u8 *)DqnMemStack_Allocate(
&memory->permanentBuffer, &memory->permMemStack,
(size_t)(loadedFont.bitmapDim.w * loadedFont.bitmapDim.h)); (size_t)(loadedFont.bitmapDim.w * loadedFont.bitmapDim.h));
stbtt_pack_context fontPackContext = {}; stbtt_pack_context fontPackContext = {};
@ -431,18 +431,18 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
i32 numCodepoints = i32 numCodepoints =
(i32)((codepointRange.max + 1) - codepointRange.min); (i32)((codepointRange.max + 1) - codepointRange.min);
loadedFont.atlas = (stbtt_packedchar *)DqnMemBuffer_Allocate( loadedFont.atlas = (stbtt_packedchar *)DqnMemStack_Allocate(
&memory->permanentBuffer, numCodepoints * sizeof(stbtt_packedchar)); &memory->permMemStack, numCodepoints * sizeof(stbtt_packedchar));
stbtt_PackFontRange(&fontPackContext, fontBuf, 0, stbtt_PackFontRange(&fontPackContext, fontBuf, 0,
STBTT_POINT_SIZE(sizeInPt), (i32)codepointRange.min, STBTT_POINT_SIZE(sizeInPt), (i32)codepointRange.min,
numCodepoints, loadedFont.atlas); numCodepoints, loadedFont.atlas);
stbtt_PackEnd(&fontPackContext); stbtt_PackEnd(&fontPackContext);
DqnMemBuffer_EndTempRegion(tmpMemRegion); DqnMemStack_EndTempRegion(tmpMemRegion);
} }
else else
{ {
DQN_ASSERT(DQN_INVALID_CODE_PATH); DQN_ASSERT(DQN_INVALID_CODE_PATH);
DqnMemBuffer_EndTempRegion(tmpMemRegion); DqnMemStack_EndTempRegion(tmpMemRegion);
return false; return false;
} }
@ -478,7 +478,7 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap, FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap,
const char *const path, const char *const path,
DqnMemBuffer *const transientBuffer) DqnMemStack *const transMemStack)
{ {
if (!bitmap) return false; if (!bitmap) return false;
@ -486,23 +486,23 @@ FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap,
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read)) if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read))
return false; return false;
DqnTempBuffer tempBuffer = DqnMemBuffer_BeginTempRegion(transientBuffer); DqnTempMemStack tempBuffer = DqnMemStack_BeginTempRegion(transMemStack);
{ {
u8 *const rawData = u8 *const rawData =
(u8 *)DqnMemBuffer_Allocate(transientBuffer, file.size); (u8 *)DqnMemStack_Allocate(transMemStack, file.size);
size_t bytesRead = api.FileRead(&file, rawData, file.size); size_t bytesRead = api.FileRead(&file, rawData, file.size);
api.FileClose(&file); api.FileClose(&file);
if (bytesRead != file.size) if (bytesRead != file.size)
{ {
DqnMemBuffer_EndTempRegion(tempBuffer); DqnMemStack_EndTempRegion(tempBuffer);
return false; return false;
} }
bitmap->memory = stbi_load_from_memory(rawData, (i32)file.size, &bitmap->dim.w, bitmap->memory = stbi_load_from_memory(rawData, (i32)file.size, &bitmap->dim.w,
&bitmap->dim.h, &bitmap->bytesPerPixel, 4); &bitmap->dim.h, &bitmap->bytesPerPixel, 4);
} }
DqnMemBuffer_EndTempRegion(tempBuffer); DqnMemStack_EndTempRegion(tempBuffer);
if (!bitmap->memory) return false; if (!bitmap->memory) return false;
const i32 pitch = bitmap->dim.w * bitmap->bytesPerPixel; const i32 pitch = bitmap->dim.w * bitmap->bytesPerPixel;
@ -1489,21 +1489,21 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
memory->isInit = true; memory->isInit = true;
memory->context = memory->context =
DqnMemBuffer_Allocate(&memory->permanentBuffer, sizeof(DTRState)); DqnMemStack_Allocate(&memory->permMemStack, sizeof(DTRState));
DQN_ASSERT(memory->context); DQN_ASSERT(memory->context);
state = (DTRState *)memory->context; state = (DTRState *)memory->context;
BitmapFontCreate(input->api, memory, &state->font, "Roboto-bold.ttf", BitmapFontCreate(input->api, memory, &state->font, "Roboto-bold.ttf",
DqnV2i_2i(256, 256), DqnV2i_2i(' ', '~'), 12); DqnV2i_2i(256, 256), DqnV2i_2i(' ', '~'), 12);
BitmapLoad(input->api, &state->bitmap, "tree00.bmp", BitmapLoad(input->api, &state->bitmap, "tree00.bmp",
&memory->transientBuffer); &memory->transMemStack);
DTRBitmap test = {}; DTRBitmap test = {};
DqnTempBuffer tmp = DqnMemBuffer_BeginTempRegion(&memory->permanentBuffer); DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->permMemStack);
BitmapLoad(input->api, &test, "byte_read_check.bmp", BitmapLoad(input->api, &test, "byte_read_check.bmp",
&memory->transientBuffer); &memory->transMemStack);
int x = 5; int x = 5;
DqnMemBuffer_EndTempRegion(tmp); DqnMemStack_EndTempRegion(tmp);
ObjWavefrontLoad(input->api, memory, "african_head.obj"); ObjWavefrontLoad(input->api, memory, "african_head.obj");
} }

View File

@ -28,19 +28,19 @@ void DTRDebug_PushText(const char *const formatStr, ...)
} }
} }
FILE_SCOPE void PushMemBufferText(const char *const name, FILE_SCOPE void PushMemStackText(const char *const name,
const DqnMemBuffer *const buffer) const DqnMemStack *const stack)
{ {
if (DTR_DEBUG) if (DTR_DEBUG)
{ {
if (!buffer) return; if (!stack) return;
size_t totalUsed = 0; size_t totalUsed = 0;
size_t totalSize = 0; size_t totalSize = 0;
size_t totalWasted = 0; size_t totalWasted = 0;
i32 numBlocks = 0; i32 numBlocks = 0;
DqnMemBufferBlock *blockPtr = buffer->block; DqnMemStackBlock *blockPtr = stack->block;
while (blockPtr) while (blockPtr)
{ {
totalUsed += blockPtr->used; totalUsed += blockPtr->used;
@ -88,8 +88,8 @@ void DTRDebug_Update(DTRState *const state,
// memory // memory
{ {
PushMemBufferText("PermBuffer", &memory->permanentBuffer); PushMemStackText("PermBuffer", &memory->permMemStack);
PushMemBufferText("TransBuffer", &memory->transientBuffer); PushMemStackText("TransBuffer", &memory->transMemStack);
} }
DTRDebug_PushText("SSE2Support: %s", (input->canUseSSE2) ? "true" : "false"); DTRDebug_PushText("SSE2Support: %s", (input->canUseSSE2) ? "true" : "false");

View File

@ -110,8 +110,8 @@ typedef struct PlatformInput
typedef struct PlatformMemory typedef struct PlatformMemory
{ {
DqnMemBuffer permanentBuffer; DqnMemStack permMemStack;
DqnMemBuffer transientBuffer; DqnMemStack transMemStack;
bool isInit; bool isInit;
void *context; void *context;
} PlatformMemory; } PlatformMemory;

View File

@ -257,21 +257,21 @@ FILE_SCOPE void Win32HandleMenuMessages(HWND window, MSG msg,
case Win32Menu_FileFlushMemory: case Win32Menu_FileFlushMemory:
{ {
DqnMemBuffer permBuffer = globalPlatformMemory.permanentBuffer; DqnMemStack permMemStack = globalPlatformMemory.permMemStack;
DqnMemBuffer transBuffer = globalPlatformMemory.transientBuffer; DqnMemStack transMemStack = globalPlatformMemory.transMemStack;
while (permBuffer.block->prevBlock) while (permMemStack.block->prevBlock)
DqnMemBuffer_FreeLastBlock(&permBuffer); DqnMemStack_FreeLastBlock(&permMemStack);
while (transBuffer.block->prevBlock) while (transMemStack.block->prevBlock)
DqnMemBuffer_FreeLastBlock(&transBuffer); DqnMemStack_FreeLastBlock(&transMemStack);
DqnMemBuffer_ClearCurrBlock(&transBuffer, true); DqnMemStack_ClearCurrBlock(&transMemStack, true);
DqnMemBuffer_ClearCurrBlock(&permBuffer, true); DqnMemStack_ClearCurrBlock(&permMemStack, true);
PlatformMemory empty = {}; PlatformMemory empty = {};
globalPlatformMemory = empty; globalPlatformMemory = empty;
globalPlatformMemory.permanentBuffer = permBuffer; globalPlatformMemory.permMemStack = permMemStack;
globalPlatformMemory.transientBuffer = transBuffer; globalPlatformMemory.transMemStack = transMemStack;
} }
break; break;
@ -502,8 +502,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Platform Data Pre-amble // Platform Data Pre-amble
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
DQN_ASSERT(DqnMemBuffer_Init(&globalPlatformMemory.permanentBuffer, DQN_MEGABYTE(1), true, 4) && DQN_ASSERT(DqnMemStack_Init(&globalPlatformMemory.permMemStack, DQN_MEGABYTE(1), true, 4) &&
DqnMemBuffer_Init(&globalPlatformMemory.transientBuffer, DQN_MEGABYTE(1), true, 4)); DqnMemStack_Init(&globalPlatformMemory.transMemStack, DQN_MEGABYTE(1), true, 4));
PlatformAPI platformAPI = {}; PlatformAPI platformAPI = {};
platformAPI.FileOpen = Platform_FileOpen; platformAPI.FileOpen = Platform_FileOpen;

279
src/dqn.h
View File

@ -67,92 +67,92 @@ DQN_FILE_SCOPE void *DqnMem_Realloc(void *memory, size_t newSize);
DQN_FILE_SCOPE void DqnMem_Free (void *memory); DQN_FILE_SCOPE void DqnMem_Free (void *memory);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// DqnMemBuffer - Memory Buffer, For push buffer/ptr memory style management // DqnMemStack - Memory Stack, For push stack/ptr memory style management
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// DqnMemBuffer is a data structure to dynamically allocate memory in a stack // DqnMemStack is a data structure to dynamically allocate memory in a stack
// like style. It pre-allocates a block of memory in init and sub-allocates from // like style. It pre-allocates a block of memory in init and sub-allocates from
// this block to take advantage of memory locality. // this block to take advantage of memory locality.
// When an allocation requires a larger amount of memory than available in the // When an allocation requires a larger amount of memory than available in the
// block then the MemBuffer will allocate a new block of sufficient size for // block then the MemStack will allocate a new block of sufficient size for
// you in DqnMemBuffer_Allocate(..). This _DOES_ mean that there will be wasted // you in DqnMemStack_Allocate(..). This _DOES_ mean that there will be wasted
// space at the end of each block and is a tradeoff for memory locality against // space at the end of each block and is a tradeoff for memory locality against
// optimal space usage. // optimal space usage.
// How To Use: // How To Use:
// 1. Create a DqnMemBuffer struct and pass it into an initialisation function // 1. Create a DqnMemStack struct and pass it into an initialisation function
// - InitWithFixedMem() allows you to pass in your own memory which is // - InitWithFixedMem() allows you to pass in your own memory which is
// converted to a memory block. This disables dynamic allocation. // converted to a memory block. This disables dynamic allocation.
// NOTE: Space is reserved in the given memory for MemBufferBlock metadata. // NOTE: Space is reserved in the given memory for MemStackBlock metadata.
// - InitWithFixedSize() allows you to to disable dynamic allocations and // - InitWithFixedSize() allows you to to disable dynamic allocations and
// sub-allocate from the initial MemBuffer allocation size only. // sub-allocate from the initial MemStack allocation size only.
// 2. Use DqnMemBuffer_Allocate(..) to allocate memory for use. // 2. Use DqnMemStack_Allocate(..) to allocate memory for use.
// - "Freeing" memory is dealt by creating temporary MemBuffers or using the // - "Freeing" memory is dealt by creating temporary MemStacks or using the
// BeginTempRegion and EndTempRegion functions. Specifically freeing // BeginTempRegion and EndTempRegion functions. Specifically freeing
// individual items is typically not generalisable in this scheme. // individual items is typically not generalisable in this scheme.
typedef struct DqnMemBufferBlock typedef struct DqnMemStackBlock
{ {
u8 *memory; u8 *memory;
size_t used; size_t used;
size_t size; size_t size;
DqnMemBufferBlock *prevBlock; DqnMemStackBlock *prevBlock;
} DqnMemBufferBlock; } DqnMemStackBlock;
enum DqnMemBufferFlag enum DqnMemStackFlag
{ {
DqnMemBufferFlag_IsNotExpandable = (1 << 0), DqnMemStackFlag_IsNotExpandable = (1 << 0),
DqnMemBufferFlag_IsFixedMemoryFromUser = (1 << 1), // NOTE(doyle): Required to indicate we CAN'T free this memory when free is called. DqnMemStackFlag_IsFixedMemoryFromUser = (1 << 1), // NOTE(doyle): Required to indicate we CAN'T free this memory when free is called.
}; };
typedef struct DqnMemBuffer typedef struct DqnMemStack
{ {
DqnMemBufferBlock *block; DqnMemStackBlock *block;
u32 flags; u32 flags;
i32 tempBufferCount; i32 tempStackCount;
u32 byteAlign; u32 byteAlign;
} DqnMemBuffer; } DqnMemStack;
typedef struct DqnTempBuffer typedef struct DqnTempMemStack
{ {
DqnMemBuffer *buffer; DqnMemStack *stack;
DqnMemBufferBlock *startingBlock; DqnMemStackBlock *startingBlock;
size_t used; size_t used;
} DqnTempBuffer; } DqnTempMemStack;
DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedMem (DqnMemBuffer *const buffer, u8 *const mem, const size_t memSize, const u32 byteAlign = 4); // Use preallocated memory, no further allocations, returns NULL on allocate if out of space DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem (DqnMemStack *const stack, u8 *const mem, const size_t memSize, const u32 byteAlign = 4); // Use preallocated memory, no further allocations, returns NULL on allocate if out of space
DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedSize(DqnMemBuffer *const buffer, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Single allocation from platform, no further allocations, returns NULL of allocate if out of space DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Single allocation from platform, no further allocations, returns NULL of allocate if out of space
DQN_FILE_SCOPE bool DqnMemBuffer_Init (DqnMemBuffer *const buffer, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Allocates from platform dynamically as space runs out DQN_FILE_SCOPE bool DqnMemStack_Init (DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Allocates from platform dynamically as space runs out
DQN_FILE_SCOPE void *DqnMemBuffer_Allocate (DqnMemBuffer *const buffer, size_t size); // Returns NULL if out of space and buffer is using fixed memory/size, or platform allocation fails DQN_FILE_SCOPE void *DqnMemStack_Allocate (DqnMemStack *const stack, size_t size); // Returns NULL if out of space and stack is using fixed memory/size, or platform allocation fails
DQN_FILE_SCOPE void DqnMemBuffer_Free (DqnMemBuffer *const buffer); // Frees all blocks belonging to this buffer DQN_FILE_SCOPE void DqnMemStack_Free (DqnMemStack *const stack); // Frees all blocks belonging to this stack
DQN_FILE_SCOPE bool DqnMemBuffer_FreeBufferBlock(DqnMemBuffer *const buffer, DqnMemBufferBlock *block); // Frees the specified block, returns false if block doesn't belong DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock (DqnMemStack *const stack, DqnMemStackBlock *block); // Frees the specified block, returns false if block doesn't belong
DQN_FILE_SCOPE bool DqnMemBuffer_FreeLastBlock (DqnMemBuffer *const buffer); // Frees the last-most memory block. If last block, free that block, next allocate will attach a block. DQN_FILE_SCOPE bool DqnMemStack_FreeLastBlock (DqnMemStack *const stack); // Frees the last-most memory block. If last block, free that block, next allocate will attach a block.
DQN_FILE_SCOPE void DqnMemBuffer_ClearCurrBlock (DqnMemBuffer *const buffer, const bool zeroClear); // Reset the current memory block usage to 0 DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock (DqnMemStack *const stack, const bool zeroClear); // Reset the current memory block usage to 0
// TempBuffer is only required for the function. Once BeginTempRegion() is called, subsequent allocation calls can be made using the original buffer. // TempMemStack is only required for the function. Once BeginTempRegion() is called, subsequent allocation calls can be made using the original stack.
// Upon EndTempRegion() the original buffer will free any additional blocks it allocated during the temp region and revert to the original // Upon EndTempRegion() the original stack will free any additional blocks it allocated during the temp region and revert to the original
// state before BeginTempRegion() was called. // state before BeginTempRegion() was called.
// WARNING: Any calls to Free/Clear functions in a TempRegion will invalidate and trash the buffer structure. // WARNING: Any calls to Free/Clear functions in a TempRegion will invalidate and trash the stack structure.
// TODO(doyle): Look into a way of disallowing calls to free/clear in temp regions // TODO(doyle): Look into a way of disallowing calls to free/clear in temp regions
DQN_FILE_SCOPE DqnTempBuffer DqnMemBuffer_BeginTempRegion(DqnMemBuffer *const buffer); DQN_FILE_SCOPE DqnTempMemStack DqnMemStack_BeginTempRegion(DqnMemStack *const stack);
DQN_FILE_SCOPE void DqnMemBuffer_EndTempRegion (DqnTempBuffer tempBuffer); DQN_FILE_SCOPE void DqnMemStack_EndTempRegion (DqnTempMemStack tempstack);
// (OPTIONAL) DqnMemBuffer Advanced API // (OPTIONAL) DqnMemStack Advanced API
// This is useful for forcing a new block to be used. AllocateCompatibleBlock // This is useful for forcing a new block to be used. AllocateCompatibleBlock
// will fail if the supplied buffer has flags set such that the buffer is not // will fail if the supplied stack has flags set such that the stack is not
// allowed to have new blocks. // allowed to have new blocks.
DQN_FILE_SCOPE DqnMemBufferBlock *DqnMemBuffer_AllocateCompatibleBlock(const DqnMemBuffer *const buffer, size_t size); DQN_FILE_SCOPE DqnMemStackBlock *DqnMemStack_AllocateCompatibleBlock(const DqnMemStack *const stack, size_t size);
DQN_FILE_SCOPE bool DqnMemBuffer_AttachBlock (DqnMemBuffer *const buffer, DqnMemBufferBlock *const newBlock); DQN_FILE_SCOPE bool DqnMemStack_AttachBlock (DqnMemStack *const stack, DqnMemStackBlock *const newBlock);
// (IMPORTANT) Should only be used to free blocks that haven't been attached! // (IMPORTANT) Should only be used to free blocks that haven't been attached!
// Attached blocks should be freed using FreeBufferBlock(). // Attached blocks should be freed using FreeStackBlock().
DQN_FILE_SCOPE void DqnMemBuffer_FreeBlock(DqnMemBufferBlock *block); DQN_FILE_SCOPE void DqnMemStack_FreeBlock(DqnMemStackBlock *block);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// DqnMemAPI - Memory API, For using custom allocators // DqnMemAPI - Memory API, For using custom allocators
@ -1339,17 +1339,17 @@ DQN_FILE_SCOPE void DqnMem_Free(void *memory)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// DqnMemBuffer - Memory API, For using custom allocators // DqnMemStack - Memory API, For using custom allocators
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
DQN_FILE_SCOPE DqnMemBufferBlock * DQN_FILE_SCOPE DqnMemStackBlock *
DqnMemBuffer_AllocateBlockInternal(u32 byteAlign, size_t size) DqnMemStack_AllocateBlockInternal(u32 byteAlign, size_t size)
{ {
size_t alignedSize = DQN_ALIGN_POW_N(size, byteAlign); size_t alignedSize = DQN_ALIGN_POW_N(size, byteAlign);
size_t totalSize = alignedSize + sizeof(DqnMemBufferBlock) + (byteAlign -1); size_t totalSize = alignedSize + sizeof(DqnMemStackBlock) + (byteAlign -1);
// NOTE(doyle): Total size includes another (byteAlign-1) since we also want // NOTE(doyle): Total size includes another (byteAlign-1) since we also want
// to align the base pointer to memory that we receive. // to align the base pointer to memory that we receive.
DqnMemBufferBlock *result = (DqnMemBufferBlock *)DqnMem_Calloc(totalSize); DqnMemStackBlock *result = (DqnMemStackBlock *)DqnMem_Calloc(totalSize);
if (!result) return NULL; if (!result) return NULL;
result->memory = (u8 *)DQN_ALIGN_POW_N((u8 *)result + sizeof(*result), byteAlign); result->memory = (u8 *)DQN_ALIGN_POW_N((u8 *)result + sizeof(*result), byteAlign);
@ -1358,110 +1358,110 @@ DqnMemBuffer_AllocateBlockInternal(u32 byteAlign, size_t size)
return result; return result;
} }
DQN_FILE_SCOPE DqnMemBufferBlock * DQN_FILE_SCOPE DqnMemStackBlock *
DqnMemBuffer_AllocateCompatibleBlock(const DqnMemBuffer *const buffer, size_t size) DqnMemStack_AllocateCompatibleBlock(const DqnMemStack *const stack, size_t size)
{ {
if (!buffer) return NULL; if (!stack) return NULL;
if (buffer->flags & DqnMemBufferFlag_IsFixedMemoryFromUser) return NULL; if (stack->flags & DqnMemStackFlag_IsFixedMemoryFromUser) return NULL;
if (buffer->flags & DqnMemBufferFlag_IsNotExpandable) return NULL; if (stack->flags & DqnMemStackFlag_IsNotExpandable) return NULL;
DqnMemBufferBlock *block = DqnMemStackBlock *block =
DqnMemBuffer_AllocateBlockInternal(buffer->byteAlign, size); DqnMemStack_AllocateBlockInternal(stack->byteAlign, size);
return block; return block;
} }
DQN_FILE_SCOPE bool DqnMemBuffer_AttachBlock(DqnMemBuffer *const buffer, DQN_FILE_SCOPE bool DqnMemStack_AttachBlock(DqnMemStack *const stack,
DqnMemBufferBlock *const newBlock) DqnMemStackBlock *const newBlock)
{ {
if (!buffer || !newBlock) return false; if (!stack || !newBlock) return false;
if (buffer->flags & DqnMemBufferFlag_IsFixedMemoryFromUser) return false; if (stack->flags & DqnMemStackFlag_IsFixedMemoryFromUser) return false;
if (buffer->flags & DqnMemBufferFlag_IsNotExpandable) return false; if (stack->flags & DqnMemStackFlag_IsNotExpandable) return false;
newBlock->prevBlock = buffer->block; newBlock->prevBlock = stack->block;
buffer->block = newBlock; stack->block = newBlock;
return true; return true;
} }
DQN_FILE_SCOPE void DqnMemBuffer_FreeBlock(DqnMemBufferBlock *block) DQN_FILE_SCOPE void DqnMemStack_FreeBlock(DqnMemStackBlock *block)
{ {
if (!block) return; if (!block) return;
DqnMem_Free(block); DqnMem_Free(block);
} }
DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedMem(DqnMemBuffer *const buffer, DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem(DqnMemStack *const stack,
u8 *const mem, u8 *const mem,
const size_t memSize, const size_t memSize,
const u32 byteAlign) const u32 byteAlign)
{ {
if (!buffer || !mem) return false; if (!stack || !mem) return false;
DQN_ASSERT(!buffer->block); DQN_ASSERT(!stack->block);
// TODO(doyle): Better logging // TODO(doyle): Better logging
if (memSize < sizeof(DqnMemBufferBlock)) if (memSize < sizeof(DqnMemStackBlock))
DQN_ASSERT(DQN_INVALID_CODE_PATH); DQN_ASSERT(DQN_INVALID_CODE_PATH);
buffer->block = (DqnMemBufferBlock *)mem; stack->block = (DqnMemStackBlock *)mem;
buffer->block->memory = mem + sizeof(DqnMemBufferBlock); stack->block->memory = mem + sizeof(DqnMemStackBlock);
buffer->block->used = 0; stack->block->used = 0;
buffer->block->size = memSize - sizeof(DqnMemBufferBlock); stack->block->size = memSize - sizeof(DqnMemStackBlock);
buffer->flags = (DqnMemBufferFlag_IsFixedMemoryFromUser | DqnMemBufferFlag_IsNotExpandable); stack->flags = (DqnMemStackFlag_IsFixedMemoryFromUser | DqnMemStackFlag_IsNotExpandable);
const u32 DEFAULT_ALIGNMENT = 4; const u32 DEFAULT_ALIGNMENT = 4;
buffer->tempBufferCount = 0; stack->tempStackCount = 0;
buffer->byteAlign = (byteAlign == 0) ? DEFAULT_ALIGNMENT : byteAlign; stack->byteAlign = (byteAlign == 0) ? DEFAULT_ALIGNMENT : byteAlign;
return true; return true;
} }
DQN_FILE_SCOPE bool DqnMemBuffer_Init(DqnMemBuffer *const buffer, size_t size, DQN_FILE_SCOPE bool DqnMemStack_Init(DqnMemStack *const stack, size_t size,
const bool zeroClear, const bool zeroClear,
const u32 byteAlign) const u32 byteAlign)
{ {
if (!buffer || size <= 0) return false; if (!stack || size <= 0) return false;
DQN_ASSERT(!buffer->block); DQN_ASSERT(!stack->block);
buffer->block = DqnMemBuffer_AllocateBlockInternal(byteAlign, size); stack->block = DqnMemStack_AllocateBlockInternal(byteAlign, size);
if (!buffer->block) return false; if (!stack->block) return false;
buffer->tempBufferCount = 0; stack->tempStackCount = 0;
buffer->byteAlign = byteAlign; stack->byteAlign = byteAlign;
buffer->flags = 0; stack->flags = 0;
return true; return true;
} }
DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedSize(DqnMemBuffer *const buffer, DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack,
size_t size, size_t size,
const bool zeroClear, const bool zeroClear,
const u32 byteAlign) const u32 byteAlign)
{ {
bool result = DqnMemBuffer_Init(buffer, size, byteAlign); bool result = DqnMemStack_Init(stack, size, byteAlign);
if (result) if (result)
{ {
buffer->flags |= DqnMemBufferFlag_IsNotExpandable; stack->flags |= DqnMemStackFlag_IsNotExpandable;
return true; return true;
} }
return false; return false;
} }
DQN_FILE_SCOPE void *DqnMemBuffer_Allocate(DqnMemBuffer *const buffer, size_t size) DQN_FILE_SCOPE void *DqnMemStack_Allocate(DqnMemStack *const stack, size_t size)
{ {
if (!buffer || size == 0) return NULL; if (!stack || size == 0) return NULL;
size_t alignedSize = DQN_ALIGN_POW_N(size, buffer->byteAlign); size_t alignedSize = DQN_ALIGN_POW_N(size, stack->byteAlign);
if (!buffer->block || if (!stack->block ||
(buffer->block->used + alignedSize) > buffer->block->size) (stack->block->used + alignedSize) > stack->block->size)
{ {
size_t newBlockSize; size_t newBlockSize;
// TODO(doyle): Allocate block size based on the aligned size or // TODO(doyle): Allocate block size based on the aligned size or
// a minimum block size? Not allocate based on the current block // a minimum block size? Not allocate based on the current block
// size // size
if (buffer->block) newBlockSize = DQN_MAX(alignedSize, buffer->block->size); if (stack->block) newBlockSize = DQN_MAX(alignedSize, stack->block->size);
else newBlockSize = alignedSize; else newBlockSize = alignedSize;
DqnMemBufferBlock *newBlock = DqnMemBuffer_AllocateCompatibleBlock(buffer, newBlockSize); DqnMemStackBlock *newBlock = DqnMemStack_AllocateCompatibleBlock(stack, newBlockSize);
if (newBlock) if (newBlock)
{ {
if (!DqnMemBuffer_AttachBlock(buffer, newBlock)) if (!DqnMemStack_AttachBlock(stack, newBlock))
{ {
// IMPORTANT(doyle): This should be impossible, considering that // IMPORTANT(doyle): This should be impossible, considering that
// AllocateCompatibleBlock checks the preconditions that the new // AllocateCompatibleBlock checks the preconditions that the new
@ -1475,48 +1475,48 @@ DQN_FILE_SCOPE void *DqnMemBuffer_Allocate(DqnMemBuffer *const buffer, size_t si
} }
else else
{ {
// TODO: Better notifying to user, out of space in buffer OR buffer // TODO: Better notifying to user, out of space in stack OR stack
// is configured such that new blocks are not allowed. // is configured such that new blocks are not allowed.
return NULL; return NULL;
} }
} }
u8 *currPointer = buffer->block->memory + buffer->block->used; u8 *currPointer = stack->block->memory + stack->block->used;
u8 *alignedResult = (u8 *)DQN_ALIGN_POW_N(currPointer, buffer->byteAlign); u8 *alignedResult = (u8 *)DQN_ALIGN_POW_N(currPointer, stack->byteAlign);
size_t alignmentOffset = (size_t)(alignedResult - currPointer); size_t alignmentOffset = (size_t)(alignedResult - currPointer);
// NOTE(doyle): Since all buffers can't change alignment once they've been // NOTE(doyle): Since all stack can't change alignment once they've been
// initialised and that the base memory ptr is already aligned, then all // initialised and that the base memory ptr is already aligned, then all
// subsequent allocations should also be aligned automatically. // subsequent allocations should also be aligned automatically.
// TODO(doyle): In the future, do we want to allow arbitrary alignment PER // TODO(doyle): In the future, do we want to allow arbitrary alignment PER
// allocation, not per MemBuffer? // allocation, not per MemStack?
DQN_ASSERT(alignmentOffset == 0); DQN_ASSERT(alignmentOffset == 0);
void *result = alignedResult; void *result = alignedResult;
buffer->block->used += (alignedSize + alignmentOffset); stack->block->used += (alignedSize + alignmentOffset);
DQN_ASSERT(buffer->block->used <= buffer->block->size); DQN_ASSERT(stack->block->used <= stack->block->size);
return result; return result;
} }
DQN_FILE_SCOPE bool DqnMemBuffer_FreeBufferBlock(DqnMemBuffer *const buffer, DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock(DqnMemStack *const stack,
DqnMemBufferBlock *block) DqnMemStackBlock *block)
{ {
if (!buffer || !block || !buffer->block) return false; if (!stack || !block || !stack->block) return false;
if (buffer->flags & DqnMemBufferFlag_IsFixedMemoryFromUser) return false; if (stack->flags & DqnMemStackFlag_IsFixedMemoryFromUser) return false;
DqnMemBufferBlock **blockPtr = &buffer->block; DqnMemStackBlock **blockPtr = &stack->block;
while (*blockPtr && (*blockPtr) != block) while (*blockPtr && (*blockPtr) != block)
blockPtr = &((*blockPtr)->prevBlock); blockPtr = &((*blockPtr)->prevBlock);
if (*blockPtr) if (*blockPtr)
{ {
DqnMemBufferBlock *blockToFree = *blockPtr; DqnMemStackBlock *blockToFree = *blockPtr;
(*blockPtr) = blockToFree->prevBlock; (*blockPtr) = blockToFree->prevBlock;
DqnMem_Free(blockToFree); DqnMem_Free(blockToFree);
// No more blocks, then last block has been freed // No more blocks, then last block has been freed
if (!buffer->block) DQN_ASSERT(buffer->tempBufferCount == 0); if (!stack->block) DQN_ASSERT(stack->tempStackCount == 0);
return true; return true;
} }
@ -1524,73 +1524,72 @@ DQN_FILE_SCOPE bool DqnMemBuffer_FreeBufferBlock(DqnMemBuffer *const buffer,
} }
DQN_FILE_SCOPE bool DQN_FILE_SCOPE bool
DqnMemBuffer_FreeLastBlock(DqnMemBuffer *const buffer) DqnMemStack_FreeLastBlock(DqnMemStack *const stack)
{ {
bool result = DqnMemBuffer_FreeBufferBlock(buffer, buffer->block); bool result = DqnMemStack_FreeStackBlock(stack, stack->block);
return result; return result;
} }
DQN_FILE_SCOPE void DqnMemBuffer_Free(DqnMemBuffer *buffer) DQN_FILE_SCOPE void DqnMemStack_Free(DqnMemStack *stack)
{ {
if (!buffer) return; if (!stack) return;
// NOTE(doyle): User is in charge of freeing this memory, so all we need to // NOTE(doyle): User is in charge of freeing this memory, so all we need to
// do is clear the block. // do is clear the block.
if (buffer->flags & DqnMemBufferFlag_IsFixedMemoryFromUser) if (stack->flags & DqnMemStackFlag_IsFixedMemoryFromUser)
{ {
DQN_ASSERT(!buffer->block->prevBlock); DQN_ASSERT(!stack->block->prevBlock);
DqnMemBuffer_ClearCurrBlock(buffer, false); DqnMemStack_ClearCurrBlock(stack, false);
return; return;
} }
while (buffer->block) while (stack->block)
DqnMemBuffer_FreeLastBlock(buffer); DqnMemStack_FreeLastBlock(stack);
// After a buffer is free, we reset the not expandable flag so that if we // After a stack is free, we reset the not expandable flag so that if we
// allocate on an empty buffer it still works. // allocate on an empty stack it still works.
buffer->flags &= ~DqnMemBufferFlag_IsNotExpandable; stack->flags &= ~DqnMemStackFlag_IsNotExpandable;
} }
DQN_FILE_SCOPE void DqnMemBuffer_ClearCurrBlock(DqnMemBuffer *const buffer, DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock(DqnMemStack *const stack,
const bool zeroClear) const bool zeroClear)
{ {
if (!buffer) return; if (!stack) return;
if (buffer->block) if (stack->block)
{ {
buffer->block->used = 0; stack->block->used = 0;
if (zeroClear) if (zeroClear)
{ {
DqnMem_Clear(buffer->block->memory, 0, DqnMem_Clear(stack->block->memory, 0, stack->block->size);
buffer->block->size);
} }
} }
} }
DQN_FILE_SCOPE DqnTempBuffer DQN_FILE_SCOPE DqnTempMemStack
DqnMemBuffer_BeginTempRegion(DqnMemBuffer *const buffer) DqnMemStack_BeginTempRegion(DqnMemStack *const stack)
{ {
DqnTempBuffer result = {}; DqnTempMemStack result = {};
result.buffer = buffer; result.stack = stack;
result.startingBlock = buffer->block; result.startingBlock = stack->block;
result.used = buffer->block->used; result.used = stack->block->used;
buffer->tempBufferCount++; stack->tempStackCount++;
return result; return result;
} }
DQN_FILE_SCOPE void DqnMemBuffer_EndTempRegion(DqnTempBuffer tempBuffer) DQN_FILE_SCOPE void DqnMemStack_EndTempRegion(DqnTempMemStack tempStack)
{ {
DqnMemBuffer *buffer = tempBuffer.buffer; DqnMemStack *stack = tempStack.stack;
while (buffer->block != tempBuffer.startingBlock) while (stack->block != tempStack.startingBlock)
DqnMemBuffer_FreeLastBlock(buffer); DqnMemStack_FreeLastBlock(stack);
if (buffer->block) if (stack->block)
{ {
DQN_ASSERT(buffer->block->used >= tempBuffer.used); DQN_ASSERT(stack->block->used >= tempStack.used);
buffer->block->used = tempBuffer.used; stack->block->used = tempStack.used;
DQN_ASSERT(buffer->tempBufferCount >= 0); DQN_ASSERT(stack->tempStackCount >= 0);
} }
buffer->tempBufferCount--; stack->tempStackCount--;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////