Add CPP member functions to DqnMemStack

This commit is contained in:
Doyle Thai 2017-06-23 15:30:21 +10:00
parent 187fc14d02
commit 9bb8efcf9d
3 changed files with 120 additions and 35 deletions

107
dqn.h
View File

@ -53,7 +53,7 @@
// #DqnSprintf Cross-platform Sprintf Implementation (Public Domain lib stb_sprintf) // #DqnSprintf Cross-platform Sprintf Implementation (Public Domain lib stb_sprintf)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Platform Checks // Global Preprocessor Checks
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// This needs to be above the portable layer so that, if the user requests // This needs to be above the portable layer so that, if the user requests
// a platform implementation, platform specific implementations in the portable // a platform implementation, platform specific implementations in the portable
@ -66,6 +66,10 @@
#define DQN_UNIX_PLATFORM #define DQN_UNIX_PLATFORM
#endif #endif
#ifdef __cplusplus
#define DQN_CPP_MODE
#endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// #Portable Code // #Portable Code
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -77,10 +81,6 @@
#define DQN_FILE_SCOPE #define DQN_FILE_SCOPE
#endif #endif
#ifdef __cplusplus
#define DQN_CPP_MODE
#endif
#include <stdint.h> // For standard types #include <stdint.h> // For standard types
#include <stddef.h> // For standard types #include <stddef.h> // For standard types
#include <string.h> // memmove #include <string.h> // memmove
@ -210,10 +210,37 @@ enum DqnMemStackFlag
typedef struct DqnMemStack typedef struct DqnMemStack
{ {
struct DqnMemStackBlock *block; struct DqnMemStackBlock *block;
u32 flags; u32 flags;
i32 tempRegionCount; i32 tempRegionCount;
u32 byteAlign; u32 byteAlign;
#if defined(DQN_CPP_MODE)
// Initialisation API
bool InitWithFixedMem (u8 *const mem, const size_t memSize, const u32 byteAlignment = 4);
bool InitWithFixedSize(const size_t size, const bool zeroClear, const u32 byteAlignment = 4);
bool Init (const size_t size, const bool zeroClear, const u32 byteAlignment = 4);
// Memory API
void *Push(size_t size);
void Pop (void *const ptr, size_t size);
void Free();
bool FreeMemBlock (DqnMemStackBlock *memBlock);
bool FreeLastBlock ();
void ClearCurrBlock(const bool zeroClear);
// Temporary Regions API
struct DqnMemStackTempRegion TempRegionBegin();
void TempRegionEnd (DqnMemStackTempRegion region);
// Scoped Temporary Regions API
struct DqnMemStackTempRegionScoped TempRegionScoped(bool *const succeeded);
// Advanced API
DqnMemStackBlock *AllocateCompatibleBlock(size_t size);
bool AttachBlock (DqnMemStackBlock *const newBlock);
bool DetachBlock (DqnMemStackBlock *const detachBlock);
void FreeDetachedBlock (DqnMemStackBlock *memBlock);
#endif
} DqnMemStack; } DqnMemStack;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -241,6 +268,7 @@ DQN_FILE_SCOPE bool DqnMemStack_Init (DqnMemStack *const stack, size_t size, con
// DqnMemStack Memory Operations // DqnMemStack Memory Operations
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Allocate memory from the MemStack. // Allocate memory from the MemStack.
// size: "size" gets aligned to the byte alignment of the stack.
// return: NULL if out of space OR stack is using fixed memory/size OR stack full and platform malloc fails. // return: NULL if out of space OR stack is using fixed memory/size OR stack full and platform malloc fails.
DQN_FILE_SCOPE void *DqnMemStack_Push (DqnMemStack *const stack, size_t size); DQN_FILE_SCOPE void *DqnMemStack_Push (DqnMemStack *const stack, size_t size);
@ -252,7 +280,7 @@ DQN_FILE_SCOPE void DqnMemStack_Free (DqnMemStack *const stack);
// Frees the specified block belonging to the stack. // Frees the specified block belonging to the stack.
// return: FALSE if block doesn't belong this into calls DqnMem_Free() or invalid args. // return: FALSE if block doesn't belong this into calls DqnMem_Free() or invalid args.
DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock(DqnMemStack *const stack, DqnMemStackBlock *block); DQN_FILE_SCOPE bool DqnMemStack_FreeMemBlock(DqnMemStack *const stack, DqnMemStackBlock *memBlock);
// Frees the last-most memory block. If last block, free that block making the MemStack blockless. // Frees the last-most memory block. If last block, free that block making the MemStack blockless.
// Next allocate will attach a block. // Next allocate will attach a block.
@ -287,8 +315,7 @@ DQN_FILE_SCOPE void DqnMemStackTempRegion_End (DqnMemStackTempRegion region);
#ifdef DQN_CPP_MODE #ifdef DQN_CPP_MODE
struct DqnMemStackTempRegionScoped struct DqnMemStackTempRegionScoped
{ {
bool isInit; DqnMemStackTempRegionScoped(DqnMemStack *const stack, bool *const succeeded);
DqnMemStackTempRegionScoped(DqnMemStack *const stack);
~DqnMemStackTempRegionScoped(); ~DqnMemStackTempRegionScoped();
private: private:
@ -317,8 +344,8 @@ DQN_FILE_SCOPE bool DqnMemStack_AttachBlock (DqnMemStack
DQN_FILE_SCOPE bool DqnMemStack_DetachBlock (DqnMemStack *const stack, DqnMemStackBlock *const detachBlock); DQN_FILE_SCOPE bool DqnMemStack_DetachBlock (DqnMemStack *const stack, DqnMemStackBlock *const detachBlock);
// (IMPORTANT) Should only be used to free blocks that haven't been attached! Attached blocks should // (IMPORTANT) Should only be used to free blocks that haven't been attached! Attached blocks should
// be freed using DqnMemStack_FreeStackBlock(). // be freed using DqnMemStack_FreeMemBlock().
DQN_FILE_SCOPE void DqnMemStack_FreeBlock(DqnMemStackBlock *block); DQN_FILE_SCOPE void DqnMemStack_FreeDetachedBlock(DqnMemStackBlock *memBlock);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// #DqnMemAPI Public API - Custom memory API for Dqn Data Structures // #DqnMemAPI Public API - Custom memory API for Dqn Data Structures
@ -927,9 +954,10 @@ enum DqnFileAction
typedef struct DqnFile typedef struct DqnFile
{ {
u32 permissionFlags;
void *handle; void *handle;
size_t size; size_t size;
u32 permissionFlags;
} DqnFile; } DqnFile;
// NOTE: W(ide) versions of functions only work on Win32, since Unix is UTF-8 compatible. // NOTE: W(ide) versions of functions only work on Win32, since Unix is UTF-8 compatible.
@ -1682,12 +1710,45 @@ DqnMemStackInternal_AllocateBlock(u32 byteAlign, size_t size)
return result; return result;
} }
////////////////////////////////////////////////////////////////////////////////
// #DqnMemStack CPP Implementation
////////////////////////////////////////////////////////////////////////////////
#if defined(DQN_CPP_MODE)
bool DqnMemStack::InitWithFixedMem (u8 *const mem, const size_t memSize, const u32 byteAlignment) { return DqnMemStack_InitWithFixedMem (this, mem, memSize, byteAlign); }
bool DqnMemStack::InitWithFixedSize(const size_t size, const bool zeroClear, const u32 byteAlignment) { return DqnMemStack_InitWithFixedSize(this, size, zeroClear, byteAlign); }
bool DqnMemStack::Init (const size_t size, const bool zeroClear, const u32 byteAlignment) { return DqnMemStack_Init (this, size, zeroClear, byteAlign); }
void *DqnMemStack::Push(size_t size) { return DqnMemStack_Push(this, size); }
void DqnMemStack::Pop (void *const ptr, size_t size) { DqnMemStack_Pop (this, ptr, size); }
void DqnMemStack::Free() { DqnMemStack_Free(this); }
bool DqnMemStack::FreeMemBlock(DqnMemStackBlock *memBlock) { return DqnMemStack_FreeMemBlock(this, block); }
bool DqnMemStack::FreeLastBlock() { return DqnMemStack_FreeLastBlock(this); }
void DqnMemStack::ClearCurrBlock(const bool zeroClear) { DqnMemStack_ClearCurrBlock(this, zeroClear); }
DqnMemStackTempRegion DqnMemStack::TempRegionBegin()
{
// NOTE: Should always succeed since the stack is guaranteed to exist.
DqnMemStackTempRegion result = {};
bool succeeded = DqnMemStackTempRegion_Begin(&result, this);
DQN_ASSERT_HARD(succeeded);
return result;
}
void DqnMemStack::TempRegionEnd(DqnMemStackTempRegion region) { DqnMemStackTempRegion_End(region); }
DqnMemStackTempRegionScoped DqnMemStack::TempRegionScoped(bool *const succeeded) { return DqnMemStackTempRegionScoped(this, succeeded); }
DqnMemStackBlock *DqnMemStack::AllocateCompatibleBlock(size_t size) { return DqnMemStack_AllocateCompatibleBlock(this, size); }
bool DqnMemStack::AttachBlock (DqnMemStackBlock *const newBlock) { return DqnMemStack_AttachBlock (this, newBlock); }
bool DqnMemStack::DetachBlock (DqnMemStackBlock *const detachBlock) { return DqnMemStack_DetachBlock (this, detachBlock); }
void DqnMemStack::FreeDetachedBlock (DqnMemStackBlock *memBlock) { DqnMemStack_FreeDetachedBlock (memBlock); }
#endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// #DqnMemStack Initialisation Implementation // #DqnMemStack Initialisation Implementation
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem(DqnMemStack *const stack, u8 *const mem, DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem(DqnMemStack *const stack, u8 *const mem,
const size_t memSize, const u32 byteAlign) const size_t memSize, const u32 byteAlign)
{ {
// TODO(doyle): Logging
if (!stack || !mem) return false; if (!stack || !mem) return false;
if (!DQN_ASSERT_MSG( if (!DQN_ASSERT_MSG(
@ -1706,7 +1767,7 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem(DqnMemStack *const stack, u8 *c
stack->flags = (DqnMemStackFlag_IsFixedMemoryFromUser | DqnMemStackFlag_IsNotExpandable); stack->flags = (DqnMemStackFlag_IsFixedMemoryFromUser | DqnMemStackFlag_IsNotExpandable);
const u32 DEFAULT_ALIGNMENT = 4; const u32 DEFAULT_ALIGNMENT = 4;
stack->tempRegionCount = 0; stack->tempRegionCount = 0;
stack->byteAlign = (byteAlign == 0) ? DEFAULT_ALIGNMENT : byteAlign; stack->byteAlign = (byteAlign == 0) ? DEFAULT_ALIGNMENT : byteAlign;
return true; return true;
} }
@ -1837,14 +1898,14 @@ DQN_FILE_SCOPE void DqnMemStack_Free(DqnMemStack *stack)
stack->flags &= ~DqnMemStackFlag_IsNotExpandable; stack->flags &= ~DqnMemStackFlag_IsNotExpandable;
} }
DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock(DqnMemStack *const stack, DqnMemStackBlock *block) DQN_FILE_SCOPE bool DqnMemStack_FreeMemBlock(DqnMemStack *const stack, DqnMemStackBlock *memBlock)
{ {
if (!stack || !block || !stack->block) return false; if (!stack || !memBlock || !stack->block) return false;
if (stack->flags & DqnMemStackFlag_IsFixedMemoryFromUser) return false; if (stack->flags & DqnMemStackFlag_IsFixedMemoryFromUser) return false;
DqnMemStackBlock **blockPtr = &stack->block; DqnMemStackBlock **blockPtr = &stack->block;
while (*blockPtr && (*blockPtr) != block) while (*blockPtr && (*blockPtr) != memBlock)
blockPtr = &((*blockPtr)->prevBlock); blockPtr = &((*blockPtr)->prevBlock);
if (*blockPtr) if (*blockPtr)
@ -1863,7 +1924,7 @@ DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock(DqnMemStack *const stack, DqnMemS
DQN_FILE_SCOPE bool DqnMemStack_FreeLastBlock(DqnMemStack *const stack) DQN_FILE_SCOPE bool DqnMemStack_FreeLastBlock(DqnMemStack *const stack)
{ {
bool result = DqnMemStack_FreeStackBlock(stack, stack->block); bool result = DqnMemStack_FreeMemBlock(stack, stack->block);
return result; return result;
} }
@ -1913,10 +1974,10 @@ DQN_FILE_SCOPE void DqnMemStackTempRegion_End(DqnMemStackTempRegion region)
} }
#ifdef DQN_CPP_MODE #ifdef DQN_CPP_MODE
DqnMemStackTempRegionScoped::DqnMemStackTempRegionScoped(DqnMemStack *const stack) DqnMemStackTempRegionScoped::DqnMemStackTempRegionScoped(DqnMemStack *const stack, bool *const succeeded)
{ {
this->isInit = DqnMemStackTempRegion_Begin(&this->tempMemStack, stack); bool result = DqnMemStackTempRegion_Begin(&this->tempMemStack, stack);
DQN_ASSERT(this->isInit); if (succeeded) *succeeded = result;
} }
DqnMemStackTempRegionScoped::~DqnMemStackTempRegionScoped() DqnMemStackTempRegionScoped::~DqnMemStackTempRegionScoped()
@ -1976,10 +2037,10 @@ DQN_FILE_SCOPE bool DqnMemStack_DetachBlock(DqnMemStack *const stack,
return true; return true;
} }
DQN_FILE_SCOPE void DqnMemStack_FreeBlock(DqnMemStackBlock *block) DQN_FILE_SCOPE void DqnMemStack_FreeDetachedBlock(DqnMemStackBlock *memBlock)
{ {
if (!block) return; if (!memBlock) return;
DqnMem_Free(block); DqnMem_Free(memBlock);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -1399,7 +1399,7 @@ void MemStackTest()
fakeBlock.memory = fakeBlockMem; fakeBlock.memory = fakeBlockMem;
fakeBlock.size = DQN_ARRAY_COUNT(fakeBlockMem); fakeBlock.size = DQN_ARRAY_COUNT(fakeBlockMem);
fakeBlock.used = 0; fakeBlock.used = 0;
DQN_ASSERT(!DqnMemStack_FreeStackBlock(&stack, &fakeBlock)); DQN_ASSERT(!DqnMemStack_FreeMemBlock(&stack, &fakeBlock));
// Ensure that the actual blocks are still valid and freeing did nothing // Ensure that the actual blocks are still valid and freeing did nothing
DQN_ASSERT(firstBlock->size == firstBlockSize); DQN_ASSERT(firstBlock->size == firstBlockSize);
@ -1432,7 +1432,7 @@ void MemStackTest()
DQN_ASSERT(fourth[i] == 'f'); DQN_ASSERT(fourth[i] == 'f');
// Free the first block // Free the first block
DqnMemStack_FreeStackBlock(&stack, firstBlock); DqnMemStack_FreeMemBlock(&stack, firstBlock);
// Revalidate state // Revalidate state
DQN_ASSERT(secondBlock->size == secondBlockSize); DQN_ASSERT(secondBlock->size == secondBlockSize);
@ -1458,7 +1458,7 @@ void MemStackTest()
DQN_ASSERT(fourth[i] == 'f'); DQN_ASSERT(fourth[i] == 'f');
// Free the third block // Free the third block
DqnMemStack_FreeStackBlock(&stack, thirdBlock); DqnMemStack_FreeMemBlock(&stack, thirdBlock);
// Revalidate state // Revalidate state
DQN_ASSERT(secondBlock->size == secondBlockSize); DQN_ASSERT(secondBlock->size == secondBlockSize);
@ -1478,7 +1478,7 @@ void MemStackTest()
DQN_ASSERT(fourth[i] == 'f'); DQN_ASSERT(fourth[i] == 'f');
// Free the second block // Free the second block
DqnMemStack_FreeStackBlock(&stack, secondBlock); DqnMemStack_FreeMemBlock(&stack, secondBlock);
// Revalidate state // Revalidate state
DQN_ASSERT(fourthBlock->size == fourthBlockSize); DQN_ASSERT(fourthBlock->size == fourthBlockSize);
@ -1496,15 +1496,36 @@ void MemStackTest()
// Test pop // Test pop
if (1) if (1)
{ {
DqnMemStack stack = {}; // Test aligned pop
DqnMemStack_Init(&stack, DQN_KILOBYTE(1), true); if (1)
{
DqnMemStack stack = {};
DqnMemStack_Init(&stack, DQN_KILOBYTE(1), true);
size_t allocSize = 512; size_t allocSize = 512;
void *alloc = DqnMemStack_Push(&stack, allocSize); void *alloc = DqnMemStack_Push(&stack, allocSize);
DQN_ASSERT(stack.block->used == allocSize); DQN_ASSERT(stack.block->used == allocSize);
DQN_ASSERT(DqnMemStack_Pop(&stack, alloc, allocSize)); DQN_ASSERT(DqnMemStack_Pop(&stack, alloc, allocSize));
DQN_ASSERT(stack.block->used == 0); DQN_ASSERT(stack.block->used == 0);
DqnMemStack_Free(&stack);
}
// Test pop on a non-byte aligned allocation. This checks to see if
// Pop() doesn't naiively forget to re-byte align the passed in size.
if (1)
{
DqnMemStack stack = {};
DqnMemStack_Init(&stack, DQN_KILOBYTE(1), true);
size_t allocSize = 1;
void *alloc = DqnMemStack_Push(&stack, allocSize);
DQN_ASSERT(stack.block->used == DQN_ALIGN_POW_N(allocSize, stack.byteAlign));
DQN_ASSERT(DqnMemStack_Pop(&stack, alloc, allocSize));
DQN_ASSERT(stack.block->used == 0);
DqnMemStack_Free(&stack);
}
} }
} }
@ -1641,6 +1662,9 @@ void FileTest()
DqnMemStack_Free(&memStack); DqnMemStack_Free(&memStack);
} }
////////////////////////////////////////////////////////////////////////////
// Test directory listing
////////////////////////////////////////////////////////////////////////////
if (1) if (1)
{ {
u32 numFiles; u32 numFiles;

View File

@ -21,7 +21,7 @@ Global
Release|x86 = Release|x86 Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{87785192-6F49-4F85-AA0D-F0AFA5CCCDDA}.Release|x86.ActiveCfg = Release|x64 {87785192-6F49-4F85-AA0D-F0AFA5CCCDDA}.Release|x86.ActiveCfg = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE