From fef763aaff50c484f1d498f7771428da2a20c171 Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Mon, 1 May 2017 18:29:45 +1000 Subject: [PATCH] Add MemBuffer with allocation from stack memory --- dqn.h | 148 +++++++++++++++++++-------- dqn_unit_test.cpp | 250 ++++++++++++++++++++++++++++------------------ 2 files changed, 258 insertions(+), 140 deletions(-) diff --git a/dqn.h b/dqn.h index 34fd6d5..cb3e2c0 100644 --- a/dqn.h +++ b/dqn.h @@ -117,7 +117,7 @@ bool DqnArray_Grow(DqnArray *array) if (!array || !array->data) return false; const f32 GROWTH_FACTOR = 1.2f; - size_t newCapacity = (size_t)(array->capacity * GROWTH_FACTOR); + size_t newCapacity = (size_t)(array->capacity * GROWTH_FACTOR); if (newCapacity == array->capacity) newCapacity++; T *newMem = (T *)Dqn_MemReallocInternal( @@ -567,39 +567,52 @@ DQN_FILE_SCOPE i32 DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max); //////////////////////////////////////////////////////////////////////////////// // PushBuffer Header //////////////////////////////////////////////////////////////////////////////// -typedef struct DqnPushBufferBlock +typedef struct DqnMemBufferBlock { u8 *memory; size_t used; size_t size; - DqnPushBufferBlock *prevBlock; -} DqnPushBufferBlock; + DqnMemBufferBlock *prevBlock; +} DqnMemBufferBlock; -typedef struct DqnPushBuffer +enum DqnMemBufferFlag { - DqnPushBufferBlock *block; + DqnMemBufferFlag_IsExpandable = (1 << 0), + DqnMemBufferFlag_IsFixedMemoryFromUser = (1 << 1), +}; +typedef struct DqnMemBuffer +{ + DqnMemBufferBlock *block; + + u32 flags; i32 tempBufferCount; size_t alignment; -} DqnPushBuffer; +} DqnMemBuffer; typedef struct DqnTempBuffer { - DqnPushBuffer *buffer; - DqnPushBufferBlock *startingBlock; + DqnMemBuffer *buffer; + DqnMemBufferBlock *startingBlock; size_t used; } DqnTempBuffer; -DQN_FILE_SCOPE bool DqnPushBuffer_Init (DqnPushBuffer *const buffer, size_t size, const size_t alignment); -DQN_FILE_SCOPE void *DqnPushBuffer_Allocate (DqnPushBuffer *const buffer, size_t size); -DQN_FILE_SCOPE void DqnPushBuffer_FreeLastBuffer(DqnPushBuffer *const buffer); -DQN_FILE_SCOPE void DqnPushBuffer_Free (DqnPushBuffer *const buffer); -DQN_FILE_SCOPE void DqnPushBuffer_ClearCurrBlock(DqnPushBuffer *const buffer, const bool clearToZero); +// NOTE: InitWithFixedMem() is for giving the MemBuffer a pre-allocated block AND the buffer WILL NOT allocate new blocks. +// Memory from user given memory is required for MemBufferBlock metadata which is equal to sizeof(DqnMemBufferBlock) +// InitWithFixedSize() will incur one allocation from the platform and WILL NOT allocate any more blocks after that +DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedMem (DqnMemBuffer *const buffer, u8* mem, size_t memSize, const size_t alignment = 4); +DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedSize(DqnMemBuffer *const buffer, size_t size, const size_t alignment = 4); +DQN_FILE_SCOPE bool DqnMemBuffer_Init (DqnMemBuffer *const buffer, size_t size, const size_t alignment = 4); -DQN_FILE_SCOPE DqnTempBuffer DqnPushBuffer_BeginTempRegion(DqnPushBuffer *const buffer); -DQN_FILE_SCOPE void DqnPushBuffer_EndTempRegion(DqnTempBuffer tempBuffer); +DQN_FILE_SCOPE void *DqnMemBuffer_Allocate (DqnMemBuffer *const buffer, size_t size); +DQN_FILE_SCOPE void DqnMemBuffer_FreeLastBuffer(DqnMemBuffer *const buffer); +DQN_FILE_SCOPE void DqnMemBuffer_Free (DqnMemBuffer *const buffer); +DQN_FILE_SCOPE void DqnMemBuffer_ClearCurrBlock(DqnMemBuffer *const buffer, const bool clearToZero); + +DQN_FILE_SCOPE DqnTempBuffer DqnMemBuffer_BeginTempRegion(DqnMemBuffer *const buffer); +DQN_FILE_SCOPE void DqnMemBuffer_EndTempRegion (DqnTempBuffer tempBuffer); #endif /* DQN_H */ @@ -2770,7 +2783,7 @@ DQN_FILE_SCOPE i32 DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max) } //////////////////////////////////////////////////////////////////////////////// -// DqnPushBuffer Header +// DqnMemBuffer Header //////////////////////////////////////////////////////////////////////////////// FILE_SCOPE size_t Dqn_SizeAlignmentInternal(size_t alignment, size_t size) { @@ -2778,13 +2791,13 @@ FILE_SCOPE size_t Dqn_SizeAlignmentInternal(size_t alignment, size_t size) return result; } -FILE_SCOPE DqnPushBufferBlock * -DqnPushBuffer_AllocBlockInternal(size_t alignment, size_t size) +FILE_SCOPE DqnMemBufferBlock * +DqnMemBuffer_AllocBlockInternal(size_t alignment, size_t size) { size_t alignedSize = Dqn_SizeAlignmentInternal(alignment, size); - size_t totalSize = alignedSize + sizeof(DqnPushBufferBlock); + size_t totalSize = alignedSize + sizeof(DqnMemBufferBlock); - DqnPushBufferBlock *result = (DqnPushBufferBlock *)Dqn_MemAllocInternal(totalSize, true); + DqnMemBufferBlock *result = (DqnMemBufferBlock *)Dqn_MemAllocInternal(totalSize, true); if (!result) return NULL; result->memory = (u8 *)result + sizeof(*result); @@ -2793,21 +2806,59 @@ DqnPushBuffer_AllocBlockInternal(size_t alignment, size_t size) return result; } -DQN_FILE_SCOPE bool DqnPushBuffer_Init(DqnPushBuffer *const buffer, - size_t size, const size_t alignment) +DQN_FILE_SCOPE bool DqnMemBuffer_Init(DqnMemBuffer *const buffer, size_t size, + const size_t alignment) { if (!buffer || size <= 0) return false; DQN_ASSERT(!buffer->block); - buffer->block = DqnPushBuffer_AllocBlockInternal(alignment, size); + buffer->block = DqnMemBuffer_AllocBlockInternal(alignment, size); if (!buffer->block) return false; buffer->tempBufferCount = 0; buffer->alignment = alignment; + buffer->flags = DqnMemBufferFlag_IsExpandable; return true; } -DQN_FILE_SCOPE void *DqnPushBuffer_Allocate(DqnPushBuffer *const buffer, size_t size) +DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedSize(DqnMemBuffer *const buffer, + size_t size, + const size_t alignment) +{ + bool result = DqnMemBuffer_Init(buffer, size, alignment); + if (result) + { + buffer->flags = 0; + return true; + } + + return false; +} + +DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedMem(DqnMemBuffer *const buffer, + u8 *mem, size_t memSize, + const size_t alignment) +{ + if (!buffer || !mem) return false; + DQN_ASSERT(!buffer->block); + + // TODO(doyle): Better logging + if (memSize < sizeof(DqnMemBufferBlock)) + DQN_ASSERT(DQN_INVALID_CODE_PATH); + + buffer->block = (DqnMemBufferBlock *)mem; + buffer->block->memory = mem + sizeof(DqnMemBufferBlock); + buffer->block->used = 0; + buffer->block->size = memSize - sizeof(DqnMemBufferBlock); + buffer->flags = DqnMemBufferFlag_IsFixedMemoryFromUser; + + const u32 DEFAULT_ALIGNMENT = 4; + buffer->tempBufferCount = 0; + buffer->alignment = (alignment == 0) ? DEFAULT_ALIGNMENT : alignment; + return true; +} + +DQN_FILE_SCOPE void *DqnMemBuffer_Allocate(DqnMemBuffer *const buffer, size_t size) { if (!buffer || size == 0) return NULL; @@ -2815,13 +2866,23 @@ DQN_FILE_SCOPE void *DqnPushBuffer_Allocate(DqnPushBuffer *const buffer, size_t if (!buffer->block || (buffer->block->used + alignedSize) > buffer->block->size) { - size_t newBlockSize = DQN_MAX(alignedSize, buffer->block->size); - DqnPushBufferBlock *newBlock = DqnPushBuffer_AllocBlockInternal( - buffer->alignment, newBlockSize); - if (!newBlock) return NULL; + if (buffer->flags & DqnMemBufferFlag_IsFixedMemoryFromUser) return NULL; - newBlock->prevBlock = buffer->block; - buffer->block = newBlock; + // TODO: Better notifying to user, out of space in buffer + if (buffer->flags & DqnMemBufferFlag_IsExpandable) + { + size_t newBlockSize = DQN_MAX(alignedSize, buffer->block->size); + DqnMemBufferBlock *newBlock = DqnMemBuffer_AllocBlockInternal( + buffer->alignment, newBlockSize); + if (!newBlock) return NULL; + + newBlock->prevBlock = buffer->block; + buffer->block = newBlock; + } + else + { + return NULL; + } } u8 *currPointer = buffer->block->memory + buffer->block->used; @@ -2835,9 +2896,11 @@ DQN_FILE_SCOPE void *DqnPushBuffer_Allocate(DqnPushBuffer *const buffer, size_t } DQN_FILE_SCOPE void -DqnPushBuffer_FreeLastBuffer(DqnPushBuffer *const buffer) +DqnMemBuffer_FreeLastBuffer(DqnMemBuffer *const buffer) { - DqnPushBufferBlock *prevBlock = buffer->block->prevBlock; + if (buffer->flags & DqnMemBufferFlag_IsFixedMemoryFromUser) return; + + DqnMemBufferBlock *prevBlock = buffer->block->prevBlock; Dqn_MemFreeInternal(buffer->block); buffer->block = prevBlock; @@ -2845,18 +2908,19 @@ DqnPushBuffer_FreeLastBuffer(DqnPushBuffer *const buffer) if (!buffer->block) DQN_ASSERT(buffer->tempBufferCount == 0); } -DQN_FILE_SCOPE void DqnPushBuffer_Free(DqnPushBuffer *buffer) +DQN_FILE_SCOPE void DqnMemBuffer_Free(DqnMemBuffer *buffer) { if (!buffer) return; + if (buffer->flags & DqnMemBufferFlag_IsFixedMemoryFromUser) return; + while (buffer->block) { - DqnPushBuffer_FreeLastBuffer(buffer); + DqnMemBuffer_FreeLastBuffer(buffer); } } -DQN_FILE_SCOPE void -DqnPushBuffer_ClearCurrBlock(DqnPushBuffer *const buffer, - const bool clearToZero) +DQN_FILE_SCOPE void DqnMemBuffer_ClearCurrBlock(DqnMemBuffer *const buffer, + const bool clearToZero) { if (!buffer) return; if (buffer->block) @@ -2871,7 +2935,7 @@ DqnPushBuffer_ClearCurrBlock(DqnPushBuffer *const buffer, } DQN_FILE_SCOPE DqnTempBuffer -DqnPushBuffer_BeginTempRegion(DqnPushBuffer *const buffer) +DqnMemBuffer_BeginTempRegion(DqnMemBuffer *const buffer) { DqnTempBuffer result = {}; result.buffer = buffer; @@ -2882,11 +2946,11 @@ DqnPushBuffer_BeginTempRegion(DqnPushBuffer *const buffer) return result; } -DQN_FILE_SCOPE void DqnPushBuffer_EndTempRegion(DqnTempBuffer tempBuffer) +DQN_FILE_SCOPE void DqnMemBuffer_EndTempRegion(DqnTempBuffer tempBuffer) { - DqnPushBuffer *buffer = tempBuffer.buffer; + DqnMemBuffer *buffer = tempBuffer.buffer; while (buffer->block != tempBuffer.startingBlock) - DqnPushBuffer_FreeLastBuffer(buffer); + DqnMemBuffer_FreeLastBuffer(buffer); if (buffer->block) { diff --git a/dqn_unit_test.cpp b/dqn_unit_test.cpp index eb547a8..e91bfdb 100644 --- a/dqn_unit_test.cpp +++ b/dqn_unit_test.cpp @@ -893,117 +893,171 @@ void FileTest() printf("FileTest(): Completed successfully\n"); } -void PushBufferTest() +void MemBufferTest() { - size_t allocSize = DQN_KILOBYTE(1); - DqnPushBuffer buffer = {}; - const u32 ALIGNMENT = 4; - DqnPushBuffer_Init(&buffer, allocSize, ALIGNMENT); - DQN_ASSERT(buffer.block && buffer.block->memory); - DQN_ASSERT(buffer.block->size == allocSize); - DQN_ASSERT(buffer.block->used == 0); - DQN_ASSERT(buffer.alignment == ALIGNMENT); + // Expandable memory buffer + { + size_t allocSize = DQN_KILOBYTE(1); + DqnMemBuffer buffer = {}; + const u32 ALIGNMENT = 4; + DqnMemBuffer_Init(&buffer, allocSize, ALIGNMENT); + DQN_ASSERT(buffer.block && buffer.block->memory); + DQN_ASSERT(buffer.block->size == allocSize); + DQN_ASSERT(buffer.block->used == 0); + DQN_ASSERT(buffer.alignment == ALIGNMENT); - // Alocate A - size_t sizeA = (size_t)(allocSize * 0.5f); - void *resultA = DqnPushBuffer_Allocate(&buffer, sizeA); - u64 resultAddrA = *((u64 *)resultA); - DQN_ASSERT(resultAddrA % ALIGNMENT == 0); - DQN_ASSERT(buffer.block && buffer.block->memory); - DQN_ASSERT(buffer.block->size == allocSize); - DQN_ASSERT(buffer.block->used >= sizeA + 0 && - buffer.block->used <= sizeA + 3); - DQN_ASSERT(buffer.alignment == ALIGNMENT); - DQN_ASSERT(resultA); - u8 *ptrA = (u8 *)resultA; - for (u32 i = 0; i < sizeA; i++) - ptrA[i] = 1; + // Alocate A + size_t sizeA = (size_t)(allocSize * 0.5f); + void *resultA = DqnMemBuffer_Allocate(&buffer, sizeA); + u64 resultAddrA = *((u64 *)resultA); + DQN_ASSERT(resultAddrA % ALIGNMENT == 0); + DQN_ASSERT(buffer.block && buffer.block->memory); + DQN_ASSERT(buffer.block->size == allocSize); + DQN_ASSERT(buffer.block->used >= sizeA + 0 && + buffer.block->used <= sizeA + 3); + DQN_ASSERT(buffer.alignment == ALIGNMENT); + DQN_ASSERT(resultA); + u8 *ptrA = (u8 *)resultA; + for (u32 i = 0; i < sizeA; i++) + ptrA[i] = 1; - DqnPushBufferBlock *blockA = buffer.block; - // Alocate B - size_t sizeB = (size_t)(allocSize * 2.0f); - void *resultB = DqnPushBuffer_Allocate(&buffer, sizeB); - u64 resultAddrB = *((u64 *)resultB); - DQN_ASSERT(resultAddrB % ALIGNMENT == 0); - DQN_ASSERT(buffer.block && buffer.block->memory); - DQN_ASSERT(buffer.block->size == DQN_KILOBYTE(2)); + DqnMemBufferBlock *blockA = buffer.block; + // Alocate B + size_t sizeB = (size_t)(allocSize * 2.0f); + void *resultB = DqnMemBuffer_Allocate(&buffer, sizeB); + u64 resultAddrB = *((u64 *)resultB); + DQN_ASSERT(resultAddrB % ALIGNMENT == 0); + DQN_ASSERT(buffer.block && buffer.block->memory); + DQN_ASSERT(buffer.block->size == DQN_KILOBYTE(2)); - // Since we alignment the pointers we return they can be within 0-3 bytes of - // what we expect and since this is in a new block as well used will reflect - // just this allocation. - DQN_ASSERT(buffer.block->used >= sizeB + 0 && - buffer.block->used <= sizeB + 3); - DQN_ASSERT(resultB); - u8 *ptrB = (u8 *)resultB; - for (u32 i = 0; i < sizeB; i++) - ptrB[i] = 2; + // Since we alignment the pointers we return they can be within 0-3 + // bytes of + // what we expect and since this is in a new block as well used will + // reflect + // just this allocation. + DQN_ASSERT(buffer.block->used >= sizeB + 0 && + buffer.block->used <= sizeB + 3); + DQN_ASSERT(resultB); + u8 *ptrB = (u8 *)resultB; + for (u32 i = 0; i < sizeB; i++) + ptrB[i] = 2; - // Check that a new block was created since there wasn't enough space - DQN_ASSERT(buffer.block->prevBlock == blockA); - DQN_ASSERT(buffer.block != blockA); - DQN_ASSERT(buffer.alignment == ALIGNMENT); - DQN_ASSERT(blockA->used == sizeA); - DqnPushBufferBlock *blockB = buffer.block; + // Check that a new block was created since there wasn't enough space + DQN_ASSERT(buffer.block->prevBlock == blockA); + DQN_ASSERT(buffer.block != blockA); + DQN_ASSERT(buffer.alignment == ALIGNMENT); + DQN_ASSERT(blockA->used == sizeA); + DqnMemBufferBlock *blockB = buffer.block; - // Check temp regions work - DqnTempBuffer tempBuffer = DqnPushBuffer_BeginTempRegion(&buffer); - size_t sizeC = 1024 + 1; - void *resultC = DqnPushBuffer_Allocate(tempBuffer.buffer, sizeC); - u64 resultAddrC = *((u64 *)resultC); - DQN_ASSERT(resultAddrC % ALIGNMENT == 0); - DQN_ASSERT(buffer.block != blockB && buffer.block != blockA); - DQN_ASSERT(buffer.block->used >= sizeC + 0 && - buffer.block->used <= sizeC + 3); - DQN_ASSERT(buffer.tempBufferCount == 1); - DQN_ASSERT(buffer.alignment == ALIGNMENT); + // Check temp regions work + DqnTempBuffer tempBuffer = DqnMemBuffer_BeginTempRegion(&buffer); + size_t sizeC = 1024 + 1; + void *resultC = DqnMemBuffer_Allocate(tempBuffer.buffer, sizeC); + u64 resultAddrC = *((u64 *)resultC); + DQN_ASSERT(resultAddrC % ALIGNMENT == 0); + DQN_ASSERT(buffer.block != blockB && buffer.block != blockA); + DQN_ASSERT(buffer.block->used >= sizeC + 0 && + buffer.block->used <= sizeC + 3); + DQN_ASSERT(buffer.tempBufferCount == 1); + DQN_ASSERT(buffer.alignment == ALIGNMENT); - // NOTE: Allocation should be aligned to 4 byte boundary - DQN_ASSERT(tempBuffer.buffer->block->size == 2048); - u8 *ptrC = (u8 *)resultC; - for (u32 i = 0; i < sizeC; i++) - ptrC[i] = 3; + // NOTE: Allocation should be aligned to 4 byte boundary + DQN_ASSERT(tempBuffer.buffer->block->size == 2048); + u8 *ptrC = (u8 *)resultC; + for (u32 i = 0; i < sizeC; i++) + ptrC[i] = 3; - // Check that a new block was created since there wasn't enough space - DQN_ASSERT(buffer.block->prevBlock == blockB); - DQN_ASSERT(buffer.block != blockB); - DQN_ASSERT(buffer.alignment == ALIGNMENT); + // Check that a new block was created since there wasn't enough space + DQN_ASSERT(buffer.block->prevBlock == blockB); + DQN_ASSERT(buffer.block != blockB); + DQN_ASSERT(buffer.alignment == ALIGNMENT); - for (u32 i = 0; i < sizeA; i++) - DQN_ASSERT(ptrA[i] == 1); - for (u32 i = 0; i < sizeB; i++) - DQN_ASSERT(ptrB[i] == 2); - for (u32 i = 0; i < sizeC; i++) - DQN_ASSERT(ptrC[i] == 3); + for (u32 i = 0; i < sizeA; i++) + DQN_ASSERT(ptrA[i] == 1); + for (u32 i = 0; i < sizeB; i++) + DQN_ASSERT(ptrB[i] == 2); + for (u32 i = 0; i < sizeC; i++) + DQN_ASSERT(ptrC[i] == 3); - // End temp region which should revert back to 2 linked buffers, A and B - DqnPushBuffer_EndTempRegion(tempBuffer); - DQN_ASSERT(buffer.block && buffer.block->memory); - DQN_ASSERT(buffer.block->size == sizeB); - DQN_ASSERT(buffer.block->used >= sizeB + 0 && - buffer.block->used <= sizeB + 3); - DQN_ASSERT(buffer.tempBufferCount == 0); - DQN_ASSERT(resultB); + // End temp region which should revert back to 2 linked buffers, A and B + DqnMemBuffer_EndTempRegion(tempBuffer); + DQN_ASSERT(buffer.block && buffer.block->memory); + DQN_ASSERT(buffer.block->size == sizeB); + DQN_ASSERT(buffer.block->used >= sizeB + 0 && + buffer.block->used <= sizeB + 3); + DQN_ASSERT(buffer.tempBufferCount == 0); + DQN_ASSERT(resultB); - DQN_ASSERT(buffer.block->prevBlock == blockA); - DQN_ASSERT(buffer.block != blockA); - DQN_ASSERT(blockA->used == sizeA); - DQN_ASSERT(buffer.alignment == ALIGNMENT); + DQN_ASSERT(buffer.block->prevBlock == blockA); + DQN_ASSERT(buffer.block != blockA); + DQN_ASSERT(blockA->used == sizeA); + DQN_ASSERT(buffer.alignment == ALIGNMENT); - // Release the last linked buffer from the push buffer - DqnPushBuffer_FreeLastBuffer(&buffer); + // Release the last linked buffer from the push buffer + DqnMemBuffer_FreeLastBuffer(&buffer); - // Which should return back to the 1st allocation - DQN_ASSERT(buffer.block == blockA); - DQN_ASSERT(buffer.block->memory); - DQN_ASSERT(buffer.block->size == allocSize); - DQN_ASSERT(buffer.block->used == sizeA); - DQN_ASSERT(buffer.alignment == ALIGNMENT); + // Which should return back to the 1st allocation + DQN_ASSERT(buffer.block == blockA); + DQN_ASSERT(buffer.block->memory); + DQN_ASSERT(buffer.block->size == allocSize); + DQN_ASSERT(buffer.block->used == sizeA); + DQN_ASSERT(buffer.alignment == ALIGNMENT); - // Free once more to release buffer A memory - DqnPushBuffer_FreeLastBuffer(&buffer); - DQN_ASSERT(!buffer.block); - DQN_ASSERT(buffer.alignment == ALIGNMENT); - DQN_ASSERT(buffer.tempBufferCount == 0); + // Free once more to release buffer A memory + DqnMemBuffer_FreeLastBuffer(&buffer); + DQN_ASSERT(!buffer.block); + DQN_ASSERT(buffer.alignment == ALIGNMENT); + DQN_ASSERT(buffer.tempBufferCount == 0); + } + + // Test buffer with fixed memory does not allocate more + { + u8 memory[DQN_KILOBYTE(1)] = {}; + DqnMemBuffer buffer = {}; + const u32 ALIGNMENT = 4; + DqnMemBuffer_InitWithFixedMem(&buffer, memory, DQN_ARRAY_COUNT(memory), + ALIGNMENT); + DQN_ASSERT(buffer.block && buffer.block->memory); + DQN_ASSERT(buffer.block->size == + DQN_ARRAY_COUNT(memory) - sizeof(DqnMemBufferBlock)); + DQN_ASSERT(buffer.block->used == 0); + DQN_ASSERT(buffer.alignment == ALIGNMENT); + + // Allocation larger than stack mem size should fail + DQN_ASSERT(!DqnMemBuffer_Allocate(&buffer, DQN_ARRAY_COUNT(memory) * 2)); + + // Check free does nothing + DqnMemBuffer_Free(&buffer); + DqnMemBuffer_FreeLastBuffer(&buffer); + DQN_ASSERT(buffer.block && buffer.block->memory); + DQN_ASSERT(buffer.block->size == + DQN_ARRAY_COUNT(memory) - sizeof(DqnMemBufferBlock)); + DQN_ASSERT(buffer.block->used == 0); + DQN_ASSERT(buffer.alignment == ALIGNMENT); + } + + // Test buffer with fixed size, allocates once from platform but does not + // grow further + { + size_t allocSize = DQN_KILOBYTE(1); + DqnMemBuffer buffer = {}; + const u32 ALIGNMENT = 4; + DqnMemBuffer_InitWithFixedSize(&buffer, allocSize, ALIGNMENT); + DQN_ASSERT(buffer.block && buffer.block->memory); + DQN_ASSERT(buffer.block->size == allocSize); + DQN_ASSERT(buffer.block->used == 0); + DQN_ASSERT(buffer.alignment == ALIGNMENT); + + void *result = DqnMemBuffer_Allocate(&buffer, (size_t)(0.5f * allocSize)); + DQN_ASSERT(result); + + // Allocating more should fail + DQN_ASSERT(!DqnMemBuffer_Allocate(&buffer, allocSize)); + + // Freeing should work + DqnMemBuffer_Free(&buffer); + DQN_ASSERT(!buffer.block); + } } int main(void) @@ -1015,7 +1069,7 @@ int main(void) OtherTest(); ArrayTest(); FileTest(); - PushBufferTest(); + MemBufferTest(); printf("\nPress 'Enter' Key to Exit\n"); getchar();