Add comments, make alignment function to macro

Alignment function becomes macro so that we can pass around alignment as a u32
instead of size_t.
This commit is contained in:
Doyle Thai 2017-05-01 21:03:27 +10:00
parent fef763aaff
commit 2203e9b4f2
2 changed files with 70 additions and 67 deletions

111
dqn.h
View File

@ -50,6 +50,9 @@ typedef float f32;
#define DQN_MEGABYTE(val) (DQN_KILOBYTE(val) * 1024LL) #define DQN_MEGABYTE(val) (DQN_KILOBYTE(val) * 1024LL)
#define DQN_KILOBYTE(val) ((val) * 1024LL) #define DQN_KILOBYTE(val) ((val) * 1024LL)
#define DQN_ALIGN_POW_N(val, align) ((((size_t)val) + ((size_t)align-1)) & (~(size_t)(align-1)))
#define DQN_ALIGN_POW_4(val) DQN_ALIGN_POW_N(val, 4)
#define DQN_INVALID_CODE_PATH 0 #define DQN_INVALID_CODE_PATH 0
#define DQN_ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) #define DQN_ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
#define DQN_ASSERT(expr) if (!(expr)) { (*((i32 *)0)) = 0; } #define DQN_ASSERT(expr) if (!(expr)) { (*((i32 *)0)) = 0; }
@ -588,7 +591,7 @@ typedef struct DqnMemBuffer
u32 flags; u32 flags;
i32 tempBufferCount; i32 tempBufferCount;
size_t alignment; u32 byteAlign;
} DqnMemBuffer; } DqnMemBuffer;
typedef struct DqnTempBuffer typedef struct DqnTempBuffer
@ -599,18 +602,21 @@ typedef struct DqnTempBuffer
} DqnTempBuffer; } DqnTempBuffer;
// NOTE: InitWithFixedMem() is for giving the MemBuffer a pre-allocated block AND the buffer WILL NOT allocate new blocks. 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
// Memory from user given memory is required for MemBufferBlock metadata which is equal to sizeof(DqnMemBufferBlock) DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedSize(DqnMemBuffer *const buffer, size_t size, const bool clearToZero, const u32 byteAlign = 4); // Single allocation from platform, no further allocations, returns NULL of allocate if out of space
// InitWithFixedSize() will incur one allocation from the platform and WILL NOT allocate any more blocks after that DQN_FILE_SCOPE bool DqnMemBuffer_Init (DqnMemBuffer *const buffer, size_t size, const bool clearToZero, const u32 byteAlign = 4); // Allocates from platform dynamically as space runs out
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 void *DqnMemBuffer_Allocate (DqnMemBuffer *const buffer, size_t size); DQN_FILE_SCOPE void *DqnMemBuffer_Allocate (DqnMemBuffer *const buffer, size_t size); // Returns NULL if out of space, or platform allocation fails, or buffer is using fixed memory/size
DQN_FILE_SCOPE void DqnMemBuffer_FreeLastBuffer(DqnMemBuffer *const buffer); DQN_FILE_SCOPE void DqnMemBuffer_FreeLastBuffer(DqnMemBuffer *const buffer); // Frees the last-most block to the buffer, if it's the only block, the buffer will free that block then, next allocate with attach a block.
DQN_FILE_SCOPE void DqnMemBuffer_Free (DqnMemBuffer *const buffer); DQN_FILE_SCOPE void DqnMemBuffer_Free (DqnMemBuffer *const buffer); // Frees all blocks belonging to this buffer
DQN_FILE_SCOPE void DqnMemBuffer_ClearCurrBlock(DqnMemBuffer *const buffer, const bool clearToZero); DQN_FILE_SCOPE void DqnMemBuffer_ClearCurrBlock(DqnMemBuffer *const buffer, const bool clearToZero); // Reset the current blocks usage ptr to 0
// TempBuffer is only required for the function. Once BeginTempRegion() is called, subsequent allocation calls can be made using the original buffer.
// Upon EndTempRegion() the original buffer will free any additional blocks it allocated during the temp region and revert to the original
// state before BeginTempRegion() was called.
// WARNING: Any calls to Free/Clear functions in a TempRegion will invalidate and trash the buffer structure.
// 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 DqnTempBuffer DqnMemBuffer_BeginTempRegion(DqnMemBuffer *const buffer);
DQN_FILE_SCOPE void DqnMemBuffer_EndTempRegion (DqnTempBuffer tempBuffer); DQN_FILE_SCOPE void DqnMemBuffer_EndTempRegion (DqnTempBuffer tempBuffer);
@ -2785,16 +2791,10 @@ DQN_FILE_SCOPE i32 DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// DqnMemBuffer Header // DqnMemBuffer Header
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
FILE_SCOPE size_t Dqn_SizeAlignmentInternal(size_t alignment, size_t size)
{
size_t result = ((size + (alignment-1)) & (size_t)(~(alignment-1)));
return result;
}
FILE_SCOPE DqnMemBufferBlock * FILE_SCOPE DqnMemBufferBlock *
DqnMemBuffer_AllocBlockInternal(size_t alignment, size_t size) DqnMemBuffer_AllocBlockInternal(u32 byteAlign, size_t size)
{ {
size_t alignedSize = Dqn_SizeAlignmentInternal(alignment, size); size_t alignedSize = DQN_ALIGN_POW_N(size, byteAlign);
size_t totalSize = alignedSize + sizeof(DqnMemBufferBlock); size_t totalSize = alignedSize + sizeof(DqnMemBufferBlock);
DqnMemBufferBlock *result = (DqnMemBufferBlock *)Dqn_MemAllocInternal(totalSize, true); DqnMemBufferBlock *result = (DqnMemBufferBlock *)Dqn_MemAllocInternal(totalSize, true);
@ -2806,38 +2806,10 @@ DqnMemBuffer_AllocBlockInternal(size_t alignment, size_t size)
return result; return result;
} }
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 = DqnMemBuffer_AllocBlockInternal(alignment, size);
if (!buffer->block) return false;
buffer->tempBufferCount = 0;
buffer->alignment = alignment;
buffer->flags = DqnMemBufferFlag_IsExpandable;
return true;
}
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, DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedMem(DqnMemBuffer *const buffer,
u8 *mem, size_t memSize, u8 *const mem,
const size_t alignment) const size_t memSize,
const u32 byteAlign)
{ {
if (!buffer || !mem) return false; if (!buffer || !mem) return false;
DQN_ASSERT(!buffer->block); DQN_ASSERT(!buffer->block);
@ -2854,15 +2826,46 @@ DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedMem(DqnMemBuffer *const buffer,
const u32 DEFAULT_ALIGNMENT = 4; const u32 DEFAULT_ALIGNMENT = 4;
buffer->tempBufferCount = 0; buffer->tempBufferCount = 0;
buffer->alignment = (alignment == 0) ? DEFAULT_ALIGNMENT : alignment; buffer->byteAlign = (byteAlign == 0) ? DEFAULT_ALIGNMENT : byteAlign;
return true; return true;
} }
DQN_FILE_SCOPE bool DqnMemBuffer_Init(DqnMemBuffer *const buffer, size_t size,
const bool clearToZero,
const u32 byteAlign)
{
if (!buffer || size <= 0) return false;
DQN_ASSERT(!buffer->block);
buffer->block = DqnMemBuffer_AllocBlockInternal(byteAlign, size);
if (!buffer->block) return false;
buffer->tempBufferCount = 0;
buffer->byteAlign = byteAlign;
buffer->flags = DqnMemBufferFlag_IsExpandable;
return true;
}
DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedSize(DqnMemBuffer *const buffer,
size_t size,
const bool clearToZero,
const u32 byteAlign)
{
bool result = DqnMemBuffer_Init(buffer, size, byteAlign);
if (result)
{
buffer->flags = 0;
return true;
}
return false;
}
DQN_FILE_SCOPE void *DqnMemBuffer_Allocate(DqnMemBuffer *const buffer, size_t size) DQN_FILE_SCOPE void *DqnMemBuffer_Allocate(DqnMemBuffer *const buffer, size_t size)
{ {
if (!buffer || size == 0) return NULL; if (!buffer || size == 0) return NULL;
size_t alignedSize = Dqn_SizeAlignmentInternal(buffer->alignment, size); size_t alignedSize = DQN_ALIGN_POW_N(size, buffer->byteAlign);
if (!buffer->block || if (!buffer->block ||
(buffer->block->used + alignedSize) > buffer->block->size) (buffer->block->used + alignedSize) > buffer->block->size)
{ {
@ -2873,7 +2876,7 @@ DQN_FILE_SCOPE void *DqnMemBuffer_Allocate(DqnMemBuffer *const buffer, size_t si
{ {
size_t newBlockSize = DQN_MAX(alignedSize, buffer->block->size); size_t newBlockSize = DQN_MAX(alignedSize, buffer->block->size);
DqnMemBufferBlock *newBlock = DqnMemBuffer_AllocBlockInternal( DqnMemBufferBlock *newBlock = DqnMemBuffer_AllocBlockInternal(
buffer->alignment, newBlockSize); buffer->byteAlign, newBlockSize);
if (!newBlock) return NULL; if (!newBlock) return NULL;
newBlock->prevBlock = buffer->block; newBlock->prevBlock = buffer->block;
@ -2886,7 +2889,7 @@ DQN_FILE_SCOPE void *DqnMemBuffer_Allocate(DqnMemBuffer *const buffer, size_t si
} }
u8 *currPointer = buffer->block->memory + buffer->block->used; u8 *currPointer = buffer->block->memory + buffer->block->used;
u8 *alignedResult = (u8 *)Dqn_SizeAlignmentInternal(buffer->alignment, (size_t)currPointer); u8 *alignedResult = (u8 *)DQN_ALIGN_POW_N(currPointer, buffer->byteAlign);
size_t alignmentOffset = (size_t)(alignedResult - currPointer); size_t alignmentOffset = (size_t)(alignedResult - currPointer);
void *result = alignedResult; void *result = alignedResult;

View File

@ -904,7 +904,7 @@ void MemBufferTest()
DQN_ASSERT(buffer.block && buffer.block->memory); DQN_ASSERT(buffer.block && buffer.block->memory);
DQN_ASSERT(buffer.block->size == allocSize); DQN_ASSERT(buffer.block->size == allocSize);
DQN_ASSERT(buffer.block->used == 0); DQN_ASSERT(buffer.block->used == 0);
DQN_ASSERT(buffer.alignment == ALIGNMENT); DQN_ASSERT(buffer.byteAlign == ALIGNMENT);
// Alocate A // Alocate A
size_t sizeA = (size_t)(allocSize * 0.5f); size_t sizeA = (size_t)(allocSize * 0.5f);
@ -915,7 +915,7 @@ void MemBufferTest()
DQN_ASSERT(buffer.block->size == allocSize); DQN_ASSERT(buffer.block->size == allocSize);
DQN_ASSERT(buffer.block->used >= sizeA + 0 && DQN_ASSERT(buffer.block->used >= sizeA + 0 &&
buffer.block->used <= sizeA + 3); buffer.block->used <= sizeA + 3);
DQN_ASSERT(buffer.alignment == ALIGNMENT); DQN_ASSERT(buffer.byteAlign == ALIGNMENT);
DQN_ASSERT(resultA); DQN_ASSERT(resultA);
u8 *ptrA = (u8 *)resultA; u8 *ptrA = (u8 *)resultA;
for (u32 i = 0; i < sizeA; i++) for (u32 i = 0; i < sizeA; i++)
@ -945,7 +945,7 @@ void MemBufferTest()
// Check that a new block was created since there wasn't enough space // Check that a new block was created since there wasn't enough space
DQN_ASSERT(buffer.block->prevBlock == blockA); DQN_ASSERT(buffer.block->prevBlock == blockA);
DQN_ASSERT(buffer.block != blockA); DQN_ASSERT(buffer.block != blockA);
DQN_ASSERT(buffer.alignment == ALIGNMENT); DQN_ASSERT(buffer.byteAlign == ALIGNMENT);
DQN_ASSERT(blockA->used == sizeA); DQN_ASSERT(blockA->used == sizeA);
DqnMemBufferBlock *blockB = buffer.block; DqnMemBufferBlock *blockB = buffer.block;
@ -959,7 +959,7 @@ void MemBufferTest()
DQN_ASSERT(buffer.block->used >= sizeC + 0 && DQN_ASSERT(buffer.block->used >= sizeC + 0 &&
buffer.block->used <= sizeC + 3); buffer.block->used <= sizeC + 3);
DQN_ASSERT(buffer.tempBufferCount == 1); DQN_ASSERT(buffer.tempBufferCount == 1);
DQN_ASSERT(buffer.alignment == ALIGNMENT); DQN_ASSERT(buffer.byteAlign == ALIGNMENT);
// NOTE: Allocation should be aligned to 4 byte boundary // NOTE: Allocation should be aligned to 4 byte boundary
DQN_ASSERT(tempBuffer.buffer->block->size == 2048); DQN_ASSERT(tempBuffer.buffer->block->size == 2048);
@ -970,7 +970,7 @@ void MemBufferTest()
// Check that a new block was created since there wasn't enough space // Check that a new block was created since there wasn't enough space
DQN_ASSERT(buffer.block->prevBlock == blockB); DQN_ASSERT(buffer.block->prevBlock == blockB);
DQN_ASSERT(buffer.block != blockB); DQN_ASSERT(buffer.block != blockB);
DQN_ASSERT(buffer.alignment == ALIGNMENT); DQN_ASSERT(buffer.byteAlign == ALIGNMENT);
for (u32 i = 0; i < sizeA; i++) for (u32 i = 0; i < sizeA; i++)
DQN_ASSERT(ptrA[i] == 1); DQN_ASSERT(ptrA[i] == 1);
@ -991,7 +991,7 @@ void MemBufferTest()
DQN_ASSERT(buffer.block->prevBlock == blockA); DQN_ASSERT(buffer.block->prevBlock == blockA);
DQN_ASSERT(buffer.block != blockA); DQN_ASSERT(buffer.block != blockA);
DQN_ASSERT(blockA->used == sizeA); DQN_ASSERT(blockA->used == sizeA);
DQN_ASSERT(buffer.alignment == ALIGNMENT); DQN_ASSERT(buffer.byteAlign == ALIGNMENT);
// Release the last linked buffer from the push buffer // Release the last linked buffer from the push buffer
DqnMemBuffer_FreeLastBuffer(&buffer); DqnMemBuffer_FreeLastBuffer(&buffer);
@ -1001,12 +1001,12 @@ void MemBufferTest()
DQN_ASSERT(buffer.block->memory); DQN_ASSERT(buffer.block->memory);
DQN_ASSERT(buffer.block->size == allocSize); DQN_ASSERT(buffer.block->size == allocSize);
DQN_ASSERT(buffer.block->used == sizeA); DQN_ASSERT(buffer.block->used == sizeA);
DQN_ASSERT(buffer.alignment == ALIGNMENT); DQN_ASSERT(buffer.byteAlign == ALIGNMENT);
// Free once more to release buffer A memory // Free once more to release buffer A memory
DqnMemBuffer_FreeLastBuffer(&buffer); DqnMemBuffer_FreeLastBuffer(&buffer);
DQN_ASSERT(!buffer.block); DQN_ASSERT(!buffer.block);
DQN_ASSERT(buffer.alignment == ALIGNMENT); DQN_ASSERT(buffer.byteAlign == ALIGNMENT);
DQN_ASSERT(buffer.tempBufferCount == 0); DQN_ASSERT(buffer.tempBufferCount == 0);
} }
@ -1021,7 +1021,7 @@ void MemBufferTest()
DQN_ASSERT(buffer.block->size == DQN_ASSERT(buffer.block->size ==
DQN_ARRAY_COUNT(memory) - sizeof(DqnMemBufferBlock)); DQN_ARRAY_COUNT(memory) - sizeof(DqnMemBufferBlock));
DQN_ASSERT(buffer.block->used == 0); DQN_ASSERT(buffer.block->used == 0);
DQN_ASSERT(buffer.alignment == ALIGNMENT); DQN_ASSERT(buffer.byteAlign == ALIGNMENT);
// Allocation larger than stack mem size should fail // Allocation larger than stack mem size should fail
DQN_ASSERT(!DqnMemBuffer_Allocate(&buffer, DQN_ARRAY_COUNT(memory) * 2)); DQN_ASSERT(!DqnMemBuffer_Allocate(&buffer, DQN_ARRAY_COUNT(memory) * 2));
@ -1033,7 +1033,7 @@ void MemBufferTest()
DQN_ASSERT(buffer.block->size == DQN_ASSERT(buffer.block->size ==
DQN_ARRAY_COUNT(memory) - sizeof(DqnMemBufferBlock)); DQN_ARRAY_COUNT(memory) - sizeof(DqnMemBufferBlock));
DQN_ASSERT(buffer.block->used == 0); DQN_ASSERT(buffer.block->used == 0);
DQN_ASSERT(buffer.alignment == ALIGNMENT); DQN_ASSERT(buffer.byteAlign == ALIGNMENT);
} }
// Test buffer with fixed size, allocates once from platform but does not // Test buffer with fixed size, allocates once from platform but does not
@ -1046,7 +1046,7 @@ void MemBufferTest()
DQN_ASSERT(buffer.block && buffer.block->memory); DQN_ASSERT(buffer.block && buffer.block->memory);
DQN_ASSERT(buffer.block->size == allocSize); DQN_ASSERT(buffer.block->size == allocSize);
DQN_ASSERT(buffer.block->used == 0); DQN_ASSERT(buffer.block->used == 0);
DQN_ASSERT(buffer.alignment == ALIGNMENT); DQN_ASSERT(buffer.byteAlign == ALIGNMENT);
void *result = DqnMemBuffer_Allocate(&buffer, (size_t)(0.5f * allocSize)); void *result = DqnMemBuffer_Allocate(&buffer, (size_t)(0.5f * allocSize));
DQN_ASSERT(result); DQN_ASSERT(result);