Add SSO for strings, memStack quick initialiser
This commit is contained in:
parent
feeec0c610
commit
398ca0bc96
240
dqn.h
240
dqn.h
@ -152,6 +152,14 @@ typedef float f32;
|
|||||||
#define DQN_MIN(a, b) ((a) < (b) ? (a) : (b))
|
#define DQN_MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
#define DQN_SWAP(type, a, b) do { type tmp = a; a = b; b = tmp; } while(0)
|
#define DQN_SWAP(type, a, b) do { type tmp = a; a = b; b = tmp; } while(0)
|
||||||
|
|
||||||
|
// NOTE: Directives don't get replaced if there's a stringify or paste (# or ##) so TOKEN_COMBINE2 is needed
|
||||||
|
// to let directives get expanded (i.e. __COUNTER__), then we can combine.
|
||||||
|
#define DQN_TOKEN_COMBINE(x, y) x ## y
|
||||||
|
#define DQN_TOKEN_COMBINE2(x, y) DQN_TOKEN_COMBINE(x, y)
|
||||||
|
|
||||||
|
// Produce a unique name with prefix and counter. i.e. data => data1
|
||||||
|
#define DQN_UNIQUE_NAME(prefix) DQN_TOKEN_COMBINE2(prefix, __COUNTER__)
|
||||||
|
|
||||||
// #DqnAssert API
|
// #DqnAssert API
|
||||||
// =================================================================================================
|
// =================================================================================================
|
||||||
// DQN_ASSERT() & DQN_ASSERT_MSG() will hard break the program but it can be
|
// DQN_ASSERT() & DQN_ASSERT_MSG() will hard break the program but it can be
|
||||||
@ -188,9 +196,9 @@ DQN_FILE_SCOPE void *DqnMem_Calloc (const size_t size);
|
|||||||
DQN_FILE_SCOPE void DqnMem_Clear (void *const memory, const u8 clearValue, const size_t size);
|
DQN_FILE_SCOPE void DqnMem_Clear (void *const memory, const u8 clearValue, const size_t size);
|
||||||
DQN_FILE_SCOPE void *DqnMem_Realloc(void *memory, const size_t newSize);
|
DQN_FILE_SCOPE void *DqnMem_Realloc(void *memory, const size_t newSize);
|
||||||
DQN_FILE_SCOPE void DqnMem_Free (void *memory);
|
DQN_FILE_SCOPE void DqnMem_Free (void *memory);
|
||||||
DQN_FILE_SCOPE void DqnMem_Copy (void *const dest, void *const src, const i64 numBytesToCopy);
|
DQN_FILE_SCOPE void DqnMem_Copy (void *const dest, void const *const src, i64 const numBytesToCopy);
|
||||||
DQN_FILE_SCOPE void *DqnMem_Set (void *const dest, u8 value, const i64 numBytesToSet);
|
DQN_FILE_SCOPE void *DqnMem_Set (void *const dest, u8 const value, i64 const numBytesToSet);
|
||||||
DQN_FILE_SCOPE void *DqnMem_Set64 (void *const dest, u8 value, const i64 numBytesToSet);
|
DQN_FILE_SCOPE void *DqnMem_Set64 (void *const dest, u8 const value, i64 const numBytesToSet);
|
||||||
|
|
||||||
// #DqnMemAPI API
|
// #DqnMemAPI API
|
||||||
// =================================================================================================
|
// =================================================================================================
|
||||||
@ -288,8 +296,19 @@ public:
|
|||||||
// 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.
|
||||||
|
|
||||||
|
// Usage: DqnMemStack example = DQN_MEM_STACK_FIXED_MEM(example, DQN_KILOBYTES(512), 4);
|
||||||
|
#define DQN_MEM_STACK_FIXED_MEM(memStack, sizeInBytes, align) \
|
||||||
|
DQN_MEM_STACK_FIXED_MEM_INTERNAL(memStack, sizeInBytes, align, DQN_UNIQUE_NAME(memory_))
|
||||||
|
|
||||||
|
#define DQN_MEM_STACK_FIXED_MEM_INTERNAL(memStack, sizeInBytes, align, uniqueName) \
|
||||||
|
{}; \
|
||||||
|
u8 uniqueName[sizeInBytes]; \
|
||||||
|
memStack.InitWithFixedMem(uniqueName, sizeInBytes, align);
|
||||||
|
|
||||||
struct DqnMemStack
|
struct DqnMemStack
|
||||||
{
|
{
|
||||||
|
static const i32 MINIMUM_BLOCK_SIZE = DQN_KILOBYTE(32);
|
||||||
|
|
||||||
enum Flag
|
enum Flag
|
||||||
{
|
{
|
||||||
IsNotExpandable = (1 << 0),
|
IsNotExpandable = (1 << 0),
|
||||||
@ -410,28 +429,25 @@ struct DqnMemStack
|
|||||||
// String allocates +1 extra byte for the null-terminator to be completely compatible with
|
// String allocates +1 extra byte for the null-terminator to be completely compatible with
|
||||||
// C style strings, but this is not reflected in the capacity or len, and is hidden from the user.
|
// C style strings, but this is not reflected in the capacity or len, and is hidden from the user.
|
||||||
|
|
||||||
// NOTE: Pasting tokens doesn't do anything with preprocessor directives IF the preprocessor finds
|
|
||||||
// a stringify or paste operation (# or ##) so we need this level of indirection.
|
|
||||||
#define DQN_TOKEN_COMBINE(x, y) x ## y
|
|
||||||
#define DQN_TOKEN_COMBINE2(x, y) DQN_TOKEN_COMBINE(x, y)
|
|
||||||
|
|
||||||
// Usage: DqnString example = DQN_STRING_LITERAL(example, "hello world");
|
// Usage: DqnString example = DQN_STRING_LITERAL(example, "hello world");
|
||||||
#define DQN_STRING_LITERAL(srcVariable, literal) \
|
#define DQN_STRING_LITERAL(srcVariable, literal) \
|
||||||
DQN_STRING_LITERAL_INTERNAL1(srcVariable, literal, DQN_TOKEN_COMBINE2(dqnstring_, __COUNTER__))
|
DQN_STRING_LITERAL_INTERNAL(srcVariable, literal, DQN_UNIQUE_NAME(dqnstring_))
|
||||||
|
|
||||||
class DqnString
|
class DqnString
|
||||||
{
|
{
|
||||||
|
char sso[128];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
DqnMemAPI memAPI;
|
||||||
char *str;
|
char *str;
|
||||||
i32 len; // Len of the string in bytes not including null-terminator
|
i32 len; // Len of the string in bytes not including null-terminator
|
||||||
i32 max; // The maximum capacity not including space for null-terminator.
|
i32 max; // The maximum capacity not including space for null-terminator.
|
||||||
DqnMemAPI memAPI;
|
|
||||||
|
|
||||||
// Initialisation API
|
// Initialisation API
|
||||||
// =============================================================================================
|
// =============================================================================================
|
||||||
// return: False if (size < 0) or (memAPI allocation failed).
|
// return: False if (size < 0) or (memAPI allocation failed).
|
||||||
bool InitSize (const i32 size, DqnMemStack *const stack);
|
bool InitSize (i32 size, DqnMemStack *const stack);
|
||||||
bool InitSize (const i32 size, DqnMemAPI api = DqnMemAPI::HeapAllocator());
|
bool InitSize (i32 size, DqnMemAPI api = DqnMemAPI::HeapAllocator());
|
||||||
|
|
||||||
// return: False if arguments are invalid.
|
// return: False if arguments are invalid.
|
||||||
bool InitFixedMem (char *const memory, const i32 sizeInBytes);
|
bool InitFixedMem (char *const memory, const i32 sizeInBytes);
|
||||||
@ -465,6 +481,11 @@ public:
|
|||||||
wchar_t *ToWChar(DqnMemAPI api = DqnMemAPI::HeapAllocator());
|
wchar_t *ToWChar(DqnMemAPI api = DqnMemAPI::HeapAllocator());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DqnSmartString : public DqnString
|
||||||
|
{
|
||||||
|
~DqnSmartString() { this->Free(); }
|
||||||
|
};
|
||||||
|
|
||||||
// TODO(doyle): Remove this? I only want it to return the string if we can guarantee initialisation.
|
// TODO(doyle): Remove this? I only want it to return the string if we can guarantee initialisation.
|
||||||
// returns: Initialised string,
|
// returns: Initialised string,
|
||||||
DQN_FILE_SCOPE DqnString DqnString_(i32 const len, DqnMemAPI const api = DqnMemAPI::HeapAllocator());
|
DQN_FILE_SCOPE DqnString DqnString_(i32 const len, DqnMemAPI const api = DqnMemAPI::HeapAllocator());
|
||||||
@ -475,10 +496,7 @@ DQN_FILE_SCOPE DqnString DqnString_(DqnMemStack *const stack);
|
|||||||
|
|
||||||
// NOTE: First level of indirection needs to turn the combined dqnstring_(guid) into a name. Otherwise
|
// NOTE: First level of indirection needs to turn the combined dqnstring_(guid) into a name. Otherwise
|
||||||
// each use of literalVarName will increment __COUNTER__
|
// each use of literalVarName will increment __COUNTER__
|
||||||
#define DQN_STRING_LITERAL_INTERNAL1(srcVariable, literal, literalVarName) \
|
#define DQN_STRING_LITERAL_INTERNAL(srcVariable, literal, literalVarName) \
|
||||||
DQN_STRING_LITERAL_INTERNAL2(srcVariable, literal, literalVarName)
|
|
||||||
|
|
||||||
#define DQN_STRING_LITERAL_INTERNAL2(srcVariable, literal, literalVarName) \
|
|
||||||
{}; \
|
{}; \
|
||||||
char literalVarName[] = literal; \
|
char literalVarName[] = literal; \
|
||||||
srcVariable.InitLiteralNoAlloc(literalVarName, DQN_CHAR_COUNT(literalVarName))
|
srcVariable.InitLiteralNoAlloc(literalVarName, DQN_CHAR_COUNT(literalVarName))
|
||||||
@ -1661,9 +1679,27 @@ public:
|
|||||||
DQN_FILE_SCOPE DqnRndPCG DqnRndPCG_(); // Uses rdtsc to create a seed
|
DQN_FILE_SCOPE DqnRndPCG DqnRndPCG_(); // Uses rdtsc to create a seed
|
||||||
DQN_FILE_SCOPE DqnRndPCG DqnRndPCG_(u32 seed);
|
DQN_FILE_SCOPE DqnRndPCG DqnRndPCG_(u32 seed);
|
||||||
|
|
||||||
// #Dqn API
|
// #Dqn_ API
|
||||||
// =================================================================================================
|
// =================================================================================================
|
||||||
|
|
||||||
|
inline bool Dqn_BitIsSet(u32 const bits, u32 const flag)
|
||||||
|
{
|
||||||
|
bool result = ((bits & flag) == flag);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 Dqn_BitSet(u32 const bits, u32 const flag)
|
||||||
|
{
|
||||||
|
u32 result = (bits | flag);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 Dqn_BitUnset(u32 const bits, u32 const flag)
|
||||||
|
{
|
||||||
|
u32 result = (bits & ~flag);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using Dqn_QuickSortLessThanCallback = bool (*)(const T *const , const T *const);
|
using Dqn_QuickSortLessThanCallback = bool (*)(const T *const , const T *const);
|
||||||
|
|
||||||
@ -2780,7 +2816,7 @@ DQN_FILE_SCOPE void DqnMem_Free(void *memory)
|
|||||||
if (memory) free(memory);
|
if (memory) free(memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE void DqnMem_Copy(void *const dest, void *const src, const i64 numBytesToCopy)
|
DQN_FILE_SCOPE void DqnMem_Copy(void *const dest, void const *const src, i64 const numBytesToCopy)
|
||||||
{
|
{
|
||||||
auto *to = (u8 *)dest;
|
auto *to = (u8 *)dest;
|
||||||
auto *from = (u8 *)src;
|
auto *from = (u8 *)src;
|
||||||
@ -2788,7 +2824,7 @@ DQN_FILE_SCOPE void DqnMem_Copy(void *const dest, void *const src, const i64 num
|
|||||||
to[i] = from[i];
|
to[i] = from[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE void *DqnMem_Set(void *const dest, u8 value, const i64 numBytesToSet)
|
DQN_FILE_SCOPE void *DqnMem_Set(void *const dest, u8 const value, i64 const numBytesToSet)
|
||||||
{
|
{
|
||||||
auto *ptr = (u8 *)dest;
|
auto *ptr = (u8 *)dest;
|
||||||
for (auto i = 0; i < numBytesToSet; i++)
|
for (auto i = 0; i < numBytesToSet; i++)
|
||||||
@ -2797,7 +2833,7 @@ DQN_FILE_SCOPE void *DqnMem_Set(void *const dest, u8 value, const i64 numBytesTo
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE void *DqnMem_Set64(void *const dest, u8 value, const i64 numBytesToCopy)
|
DQN_FILE_SCOPE void *DqnMem_Set64(void *const dest, u8 const value, i64 const numBytesToCopy)
|
||||||
{
|
{
|
||||||
#if defined(DQN_WIN32_PLATFORM)
|
#if defined(DQN_WIN32_PLATFORM)
|
||||||
u64 valueU64 = value;
|
u64 valueU64 = value;
|
||||||
@ -3111,6 +3147,7 @@ bool DqnMemStack::InitWithFixedSize(size_t size, bool const zeroClear, u32 const
|
|||||||
bool DqnMemStack::Init(size_t size, bool const zeroClear, u32 const byteAlign_, DqnMemAPI memAPI_)
|
bool DqnMemStack::Init(size_t size, bool const zeroClear, u32 const byteAlign_, DqnMemAPI memAPI_)
|
||||||
{
|
{
|
||||||
if (!this || size < 0) return false;
|
if (!this || size < 0) return false;
|
||||||
|
|
||||||
if (!DQN_ASSERT_MSG(!this->block, "MemStack has pre-existing block already attached"))
|
if (!DQN_ASSERT_MSG(!this->block, "MemStack has pre-existing block already attached"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -3139,7 +3176,8 @@ void *DqnMemStack::Push(size_t size)
|
|||||||
if (size == 0) return nullptr;
|
if (size == 0) return nullptr;
|
||||||
|
|
||||||
size_t alignedSize = DQN_ALIGN_POW_N(size, this->byteAlign);
|
size_t alignedSize = DQN_ALIGN_POW_N(size, this->byteAlign);
|
||||||
if (!this->block || (this->block->used + alignedSize) > this->block->size)
|
size_t newUsage = this->block->used + alignedSize;
|
||||||
|
if (!this->block || newUsage > this->block->size)
|
||||||
{
|
{
|
||||||
size_t newBlockSize;
|
size_t newBlockSize;
|
||||||
|
|
||||||
@ -3147,9 +3185,17 @@ void *DqnMemStack::Push(size_t size)
|
|||||||
// 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 (this->block)
|
if (this->block)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
newBlockSize = DQN_MAX(alignedSize, this->block->size);
|
newBlockSize = DQN_MAX(alignedSize, this->block->size);
|
||||||
|
#else
|
||||||
|
newBlockSize = DQN_MAX(alignedSize, DqnMemStack::MINIMUM_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
newBlockSize = alignedSize;
|
newBlockSize = alignedSize;
|
||||||
|
}
|
||||||
|
|
||||||
DqnMemStack::Block *newBlock = this->AllocateCompatibleBlock(newBlockSize, true);
|
DqnMemStack::Block *newBlock = this->AllocateCompatibleBlock(newBlockSize, true);
|
||||||
if (newBlock)
|
if (newBlock)
|
||||||
@ -3188,29 +3234,47 @@ void *DqnMemStack::Push(size_t size)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FILE_SCOPE bool DqnMemStackInternal_TryPopPtrInBlock(DqnMemStack::Block *block, u32 const byteAlign,
|
||||||
|
void *const ptr, size_t size)
|
||||||
|
{
|
||||||
|
u8 *currPtr = block->memory + block->used;
|
||||||
|
if ((size_t)ptr >= (size_t)block->memory && (size_t)ptr < (size_t)currPtr)
|
||||||
|
{
|
||||||
|
auto calcSize = (size_t)currPtr - (size_t)ptr;
|
||||||
|
size_t sizeAligned = DQN_ALIGN_POW_N(size, byteAlign);
|
||||||
|
if (calcSize == sizeAligned)
|
||||||
|
{
|
||||||
|
block->used -= sizeAligned;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// printf("The ptr to free and its size aligned to byteAlign does not match.
|
||||||
|
// This
|
||||||
|
// ptr is not a valid address to free. We got: %d, expected: %d", calcSize,
|
||||||
|
// alignedSized);
|
||||||
|
DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool DqnMemStack::Pop(void *const ptr, size_t size)
|
bool DqnMemStack::Pop(void *const ptr, size_t size)
|
||||||
{
|
{
|
||||||
if (!this->block) return false;
|
if (!this->block) return false;
|
||||||
u8 *currPtr = block->memory + block->used;
|
|
||||||
if (DQN_ASSERT_MSG((u8 *)ptr >= block->memory && ptr < currPtr,
|
|
||||||
"'ptr' to pop does not belong to current memStack attached block"))
|
|
||||||
{
|
|
||||||
size_t calcSize = (size_t)currPtr - (size_t)ptr;
|
|
||||||
size_t sizeAligned = DQN_ALIGN_POW_N(size, this->byteAlign);
|
|
||||||
|
|
||||||
if (calcSize == sizeAligned)
|
if (DqnMemStackInternal_TryPopPtrInBlock(this->block, this->byteAlign, ptr, size))
|
||||||
{
|
{
|
||||||
this->block->used -= sizeAligned;
|
if (this->block->used == 0 && this->block->prevBlock)
|
||||||
if (this->block->used == 0 && block->prevBlock)
|
|
||||||
{
|
{
|
||||||
bool result = this->FreeLastBlock();
|
bool result = this->FreeLastBlock();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// printf("Ptr (%x) does not belong to the newest memory blocks", ptr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3247,7 +3311,7 @@ bool DqnMemStack::FreeMemBlock(DqnMemStack::Block *memBlock)
|
|||||||
{
|
{
|
||||||
DqnMemStack::Block *blockToFree = *blockPtr;
|
DqnMemStack::Block *blockToFree = *blockPtr;
|
||||||
(*blockPtr) = blockToFree->prevBlock;
|
(*blockPtr) = blockToFree->prevBlock;
|
||||||
DqnMem_Free(blockToFree);
|
this->memAPI.Free(blockToFree, blockToFree->size);
|
||||||
|
|
||||||
// No more blocks, then last block has been freed
|
// No more blocks, then last block has been freed
|
||||||
if (!this->block) DQN_ASSERT_HARD(this->tempRegionCount == 0);
|
if (!this->block) DQN_ASSERT_HARD(this->tempRegionCount == 0);
|
||||||
@ -5257,31 +5321,22 @@ bool DqnString::InitSize(const i32 size, DqnMemStack *const stack)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DqnString::InitSize(const i32 size, DqnMemAPI api)
|
bool DqnString::InitSize(i32 size, DqnMemAPI api)
|
||||||
{
|
{
|
||||||
|
// NOTE: CHAR_COUNT is (ARRAY_COUNT - 1) to leave the last spot as the implicit null-terminator.
|
||||||
DQN_ASSERT(size >= 0);
|
DQN_ASSERT(size >= 0);
|
||||||
if (size < 0)
|
if (size < DQN_CHAR_COUNT(this->sso))
|
||||||
{
|
{
|
||||||
DqnString nullString = {};
|
this->str = &(this->sso[0]);
|
||||||
*this = nullString;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (size > 0)
|
|
||||||
{
|
{
|
||||||
size_t allocSize = sizeof(*(this->str)) * (size + 1);
|
size_t allocSize = sizeof(*(this->str)) * (size + 1);
|
||||||
this->str = (char *)api.Alloc(allocSize, /*zeroClear*/false);
|
this->str = (char *)api.Alloc(allocSize, /*zeroClear*/false);
|
||||||
|
if (!this->str) return false;
|
||||||
if (!this->str)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // size == 0
|
|
||||||
{
|
|
||||||
this->str = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->str[0] = 0;
|
||||||
this->max = size;
|
this->max = size;
|
||||||
this->len = 0;
|
this->len = 0;
|
||||||
this->memAPI = api;
|
this->memAPI = api;
|
||||||
@ -5314,25 +5369,15 @@ bool DqnString::InitLiteral(char const *const cstr, i32 const lenInBytes, DqnMem
|
|||||||
|
|
||||||
bool DqnString::InitLiteral(char const *const cstr, i32 const lenInBytes, DqnMemAPI api)
|
bool DqnString::InitLiteral(char const *const cstr, i32 const lenInBytes, DqnMemAPI api)
|
||||||
{
|
{
|
||||||
if (lenInBytes < 0) return false;
|
if (!this->InitSize(lenInBytes, api))
|
||||||
|
|
||||||
if (lenInBytes > 0)
|
|
||||||
{
|
{
|
||||||
size_t allocSize = sizeof(*(this->str)) * (lenInBytes + 1);
|
return false;
|
||||||
this->str = (char *)api.Alloc(allocSize, /*zeroClear*/ false);
|
}
|
||||||
if (!this->str) return false;
|
|
||||||
|
|
||||||
this->str[lenInBytes] = 0;
|
this->str[lenInBytes] = 0;
|
||||||
}
|
|
||||||
|
|
||||||
this->len = lenInBytes;
|
this->len = lenInBytes;
|
||||||
this->max = lenInBytes;
|
this->max = this->len;
|
||||||
this->memAPI = api;
|
DqnMem_Copy(this->str, cstr, lenInBytes);
|
||||||
|
|
||||||
for (i32 i = 0; i < this->len; i++)
|
|
||||||
{
|
|
||||||
this->str[i] = cstr[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -5354,20 +5399,18 @@ bool DqnString::InitLiteral(wchar_t const *const cstr, DqnMemStack *const stack)
|
|||||||
bool DqnString::InitLiteral(wchar_t const *const cstr, DqnMemAPI api)
|
bool DqnString::InitLiteral(wchar_t const *const cstr, DqnMemAPI api)
|
||||||
{
|
{
|
||||||
#if defined(DQN_IS_WIN32) && defined(DQN_WIN32_IMPLEMENTATION)
|
#if defined(DQN_IS_WIN32) && defined(DQN_WIN32_IMPLEMENTATION)
|
||||||
i32 requiredLen = DqnWin32_WCharToUTF8(cstr, nullptr, 0);
|
i32 reqLenInclNullTerminator = DqnWin32_WCharToUTF8(cstr, nullptr, 0);
|
||||||
this->len = requiredLen - 1;
|
if (!this->InitSize(reqLenInclNullTerminator - 1, api))
|
||||||
|
{
|
||||||
size_t allocSize = sizeof(*(this->str)) * (this->len + 1);
|
return false;
|
||||||
this->str = (char *)api.Alloc(allocSize, /*zeroClear*/false);
|
}
|
||||||
if (!this->str) return false;
|
|
||||||
|
|
||||||
|
this->len = reqLenInclNullTerminator - 1;
|
||||||
this->max = this->len;
|
this->max = this->len;
|
||||||
this->memAPI = api;
|
|
||||||
|
|
||||||
i32 convertResult = DqnWin32_WCharToUTF8(cstr, this->str, this->len + 1);
|
i32 convertResult = DqnWin32_WCharToUTF8(cstr, this->str, this->len + 1);
|
||||||
DQN_ASSERT(convertResult != -1);
|
DQN_ASSERT(convertResult != -1);
|
||||||
|
|
||||||
this->str[this->len] = 0;
|
this->str[this->len] = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -5394,14 +5437,35 @@ bool DqnString::InitLiteralNoAlloc(char *const cstr, i32 cstrLen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->max = this->len;
|
this->max = this->len;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DqnString::Expand(const i32 newMax)
|
bool DqnString::Expand(const i32 newMax)
|
||||||
{
|
{
|
||||||
if (!this->memAPI.IsValid()) return false;
|
if (newMax < this->max)
|
||||||
if (newMax < this->max) return true;
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->memAPI.IsValid())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newMax < DQN_CHAR_COUNT(this->sso))
|
||||||
|
{
|
||||||
|
DQN_ASSERT(this->memAPI.IsValid());
|
||||||
|
DQN_ASSERT(this->sso == this->str);
|
||||||
|
this->max = newMax;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool usingSSO = (this->str == this->sso);
|
||||||
|
if (usingSSO)
|
||||||
|
{
|
||||||
|
DQN_ASSERT(newMax >= DQN_CHAR_COUNT(this->sso));
|
||||||
|
this->str = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
size_t allocSize = sizeof(*(this->str)) * (newMax + 1);
|
size_t allocSize = sizeof(*(this->str)) * (newMax + 1);
|
||||||
char *result = nullptr;
|
char *result = nullptr;
|
||||||
@ -5411,10 +5475,19 @@ bool DqnString::Expand(const i32 newMax)
|
|||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
|
if (usingSSO)
|
||||||
|
DqnMem_Copy(result, this->sso, this->max);
|
||||||
|
|
||||||
this->str = (char *)result;
|
this->str = (char *)result;
|
||||||
this->max = newMax;
|
this->max = newMax;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Restore the pointer to the SSO to return to the original state from before this call.
|
||||||
|
if (usingSSO)
|
||||||
|
this->str = this->sso;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -5435,8 +5508,8 @@ DQN_FILE_SCOPE bool DqnStringInternal_Append(DqnString *const str, char const *c
|
|||||||
if (!result) return false;
|
if (!result) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append
|
char *dest = str->str + str->len;
|
||||||
for (i32 i = 0; i < bytesToCopy; i++) str->str[str->len + i] = cstr[i];
|
DqnMem_Copy(dest, cstr, bytesToCopy);
|
||||||
|
|
||||||
str->len = totalLen;
|
str->len = totalLen;
|
||||||
str->str[totalLen] = 0;
|
str->str[totalLen] = 0;
|
||||||
@ -5512,10 +5585,19 @@ void DqnString::Clear()
|
|||||||
|
|
||||||
void DqnString::Free()
|
void DqnString::Free()
|
||||||
{
|
{
|
||||||
if (this->str && this->memAPI.IsValid())
|
if (this->str)
|
||||||
|
{
|
||||||
|
if (this->str == this->sso)
|
||||||
|
{
|
||||||
|
this->sso[0] = '\0';
|
||||||
|
this->str = nullptr;
|
||||||
|
}
|
||||||
|
else if (this->memAPI.IsValid())
|
||||||
{
|
{
|
||||||
this->memAPI.Free(this->str, this->len);
|
this->memAPI.Free(this->str, this->len);
|
||||||
this->str = nullptr;
|
this->str = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
this->len = 0;
|
this->len = 0;
|
||||||
this->max = 0;
|
this->max = 0;
|
||||||
}
|
}
|
||||||
|
@ -1573,11 +1573,10 @@ void DqnMemStack_Test()
|
|||||||
|
|
||||||
DqnMemStack::Block *blockA = stack.block;
|
DqnMemStack::Block *blockA = stack.block;
|
||||||
// Alocate B
|
// Alocate B
|
||||||
size_t sizeB = (size_t)(allocSize * 2.0f);
|
size_t sizeB = DqnMemStack::MINIMUM_BLOCK_SIZE;
|
||||||
void *resultB = stack.Push(sizeB);
|
void *resultB = stack.Push(sizeB);
|
||||||
DQN_ASSERT(((intptr_t)resultB % ALIGNMENT) == 0);
|
DQN_ASSERT(((intptr_t)resultB % ALIGNMENT) == 0);
|
||||||
DQN_ASSERT(stack.block && stack.block->memory);
|
DQN_ASSERT(stack.block && stack.block->memory);
|
||||||
DQN_ASSERT(stack.block->size == DQN_KILOBYTE(2));
|
|
||||||
|
|
||||||
// Since we alignment the pointers we return they can be within 0-3
|
// 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
|
// bytes of what we expect and since this is in a new block as well used
|
||||||
@ -1598,7 +1597,7 @@ void DqnMemStack_Test()
|
|||||||
// Check temp regions work
|
// Check temp regions work
|
||||||
DqnMemStack::TempRegion tempBuffer = stack.TempRegionBegin();
|
DqnMemStack::TempRegion tempBuffer = stack.TempRegionBegin();
|
||||||
|
|
||||||
size_t sizeC = 1024 + 1;
|
size_t sizeC = DQN_ALIGN_POW_N(DqnMemStack::MINIMUM_BLOCK_SIZE + 1, ALIGNMENT);
|
||||||
void *resultC = stack.Push(sizeC);
|
void *resultC = stack.Push(sizeC);
|
||||||
DQN_ASSERT(((intptr_t)resultC % ALIGNMENT) == 0);
|
DQN_ASSERT(((intptr_t)resultC % ALIGNMENT) == 0);
|
||||||
DQN_ASSERT(stack.block != blockB && stack.block != blockA);
|
DQN_ASSERT(stack.block != blockB && stack.block != blockA);
|
||||||
@ -1607,7 +1606,7 @@ void DqnMemStack_Test()
|
|||||||
DQN_ASSERT(stack.byteAlign == ALIGNMENT);
|
DQN_ASSERT(stack.byteAlign == ALIGNMENT);
|
||||||
|
|
||||||
// NOTE: Allocation should be aligned to 4 byte boundary
|
// NOTE: Allocation should be aligned to 4 byte boundary
|
||||||
DQN_ASSERT(tempBuffer.stack->block->size == 2048);
|
DQN_ASSERT(tempBuffer.stack->block->size == sizeC);
|
||||||
u8 *ptrC = (u8 *)resultC;
|
u8 *ptrC = (u8 *)resultC;
|
||||||
for (u32 i = 0; i < sizeC; i++)
|
for (u32 i = 0; i < sizeC; i++)
|
||||||
ptrC[i] = 3;
|
ptrC[i] = 3;
|
||||||
@ -1769,19 +1768,19 @@ void DqnMemStack_Test()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Force it to allocate three new blocks and write out data to each
|
// Force it to allocate three new blocks and write out data to each
|
||||||
size_t secondBlockSize = DQN_KILOBYTE(2);
|
size_t secondBlockSize = DQN_ALIGN_POW_N(DqnMemStack::MINIMUM_BLOCK_SIZE, stack.byteAlign);
|
||||||
u8 *second = (u8 *)stack.Push(secondBlockSize);
|
u8 *second = (u8 *)stack.Push(secondBlockSize);
|
||||||
DqnMemStack::Block *secondBlock = stack.block;
|
DqnMemStack::Block *secondBlock = stack.block;
|
||||||
for (u32 i = 0; i < secondBlockSize; i++)
|
for (u32 i = 0; i < secondBlockSize; i++)
|
||||||
second[i] = 'd';
|
second[i] = 'd';
|
||||||
|
|
||||||
size_t thirdBlockSize = DQN_KILOBYTE(3);
|
size_t thirdBlockSize = DQN_ALIGN_POW_N(DqnMemStack::MINIMUM_BLOCK_SIZE, stack.byteAlign);
|
||||||
u8 *third = (u8 *)stack.Push(thirdBlockSize);
|
u8 *third = (u8 *)stack.Push(thirdBlockSize);
|
||||||
DqnMemStack::Block *thirdBlock = stack.block;
|
DqnMemStack::Block *thirdBlock = stack.block;
|
||||||
for (u32 i = 0; i < thirdBlockSize; i++)
|
for (u32 i = 0; i < thirdBlockSize; i++)
|
||||||
third[i] = 'e';
|
third[i] = 'e';
|
||||||
|
|
||||||
size_t fourthBlockSize = DQN_KILOBYTE(4);
|
size_t fourthBlockSize = DQN_ALIGN_POW_N(DqnMemStack::MINIMUM_BLOCK_SIZE, stack.byteAlign);
|
||||||
u8 *fourth = (u8 *)stack.Push(fourthBlockSize);
|
u8 *fourth = (u8 *)stack.Push(fourthBlockSize);
|
||||||
DqnMemStack::Block *fourthBlock = stack.block;
|
DqnMemStack::Block *fourthBlock = stack.block;
|
||||||
for (u32 i = 0; i < fourthBlockSize; i++)
|
for (u32 i = 0; i < fourthBlockSize; i++)
|
||||||
|
Loading…
Reference in New Issue
Block a user