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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user