From 8209593f577c0a1245a4ff0a4cfd256b10e901fd Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Thu, 4 Jan 2018 16:07:18 +1100 Subject: [PATCH] Fix literals not working with strings in structs --- dqn.h | 174 ++++++++++++++++++++++++++++++++-------------- dqn_unit_test.cpp | 8 +-- 2 files changed, 125 insertions(+), 57 deletions(-) diff --git a/dqn.h b/dqn.h index 288cb3d..7190137 100644 --- a/dqn.h +++ b/dqn.h @@ -147,6 +147,7 @@ typedef float f32; #define DQN_ALIGN_POW_4(val) DQN_ALIGN_POW_N(val, 4) #define DQN_INVALID_CODE_PATH 0 +#define DQN_CHAR_COUNT(charArray) DQN_ARRAY_COUNT(charArray) - 1 #define DQN_ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) #define DQN_PI 3.14159265359f @@ -271,11 +272,13 @@ public: }; }; + typedef u8 *Allocator(DqnMemAPI::Request request); + static Request RequestRealloc(const DqnMemAPI memAPI, void *const oldMemPtr, const size_t oldSize, const size_t newSize); static Request RequestAlloc (const DqnMemAPI memAPI, const size_t size, const bool clearToZero); static Request RequestFree (const DqnMemAPI memAPI, void *const ptrToFree, const size_t sizeToFree); - typedef u8 *Allocator(DqnMemAPI::Request request); + bool IsValid() const { return (callback != nullptr); } Allocator *callback; void *userContext; @@ -438,30 +441,34 @@ private: // 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. +// 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"); -#define DQN_STRING_LITERAL(dqnstring, literal) \ - {}; \ - char dqnstring##_[] = literal; \ - dqnstring.InitLiteralNoAlloc(dqnstring##_, DQN_ARRAY_COUNT(dqnstring##_) - 1); +#define DQN_STRING_LITERAL(srcVariable, literal) \ + DQN_STRING_LITERAL_INTERNAL1(srcVariable, literal, DQN_TOKEN_COMBINE2(dqnstring_, __COUNTER__)) class DqnString { public: char *str; - i32 len; // Len of the string in bytes not including null-terminator - i32 max; // The maximum capacity not including space for 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. DqnMemAPI memAPI; - bool InitSize (const i32 size, DqnMemStack *const stack); - bool InitSize (const i32 size, const DqnMemAPI api = DqnMemAPI_HeapAllocator()); + bool InitSize(const i32 size, DqnMemStack *const stack); + bool InitSize(const i32 size, const DqnMemAPI api = DqnMemAPI_HeapAllocator()); bool InitFixedMem(char *const memory, const i32 sizeInBytes); - bool InitLiteral (char const *const cstr, DqnMemStack *const stack); - bool InitLiteral (char const *const cstr, DqnMemAPI const api = DqnMemAPI_HeapAllocator()); + bool InitLiteral(char const *const cstr, DqnMemStack *const stack); + bool InitLiteral(char const *const cstr, DqnMemAPI const api = DqnMemAPI_HeapAllocator()); - bool InitLiteral (char const *const cstr, i32 const lenInBytes, DqnMemStack *const stack); - bool InitLiteral (char const *const cstr, i32 const lenInBytes, DqnMemAPI const api = DqnMemAPI_HeapAllocator()); + bool InitLiteral(char const *const cstr, i32 const lenInBytes, DqnMemStack *const stack); + bool InitLiteral(char const *const cstr, i32 const lenInBytes, + DqnMemAPI const api = DqnMemAPI_HeapAllocator()); bool InitWLiteral(const wchar_t *const cstr, DqnMemStack *const stack); bool InitWLiteral(const wchar_t *const cstr, const DqnMemAPI api = DqnMemAPI_HeapAllocator()); @@ -470,24 +477,39 @@ public: bool Expand(const i32 newMax); - bool Sprintf (char const *fmt, ...); - bool AppendStr (const DqnString strToAppend, i32 bytesToCopy = -1); - bool AppendCStr(const char *const cstr, i32 bytesToCopy = -1); + bool Sprintf(char const *fmt, ...); + bool AppendStr(const DqnString strToAppend, i32 bytesToCopy = -1); + bool AppendCStr(const char *const cstr, i32 bytesToCopy = -1); void Clear(); bool Free(); // The function automatically null-terminates the output string. // bufSize: The size of the buffer in wchar_t characters. - // return: -1 if invalid, or if bufSize is 0 the required buffer length in wchar_t characters + // return: -1 if invalid, or if bufSize is 0 the required buffer length in wchar_t + // characters i32 ToWCharUseBuf(wchar_t *const buf, const i32 bufSize); // returns a malloc() string, needs to be freed using free(..); wchar_t *ToWChar(DqnMemAPI api = DqnMemAPI_HeapAllocator()); }; -DQN_FILE_SCOPE DqnString DqnString_(const DqnMemAPI api); +// returns: Initialised string, +DQN_FILE_SCOPE DqnString DqnString_(i32 const len, DqnMemAPI const api = DqnMemAPI_HeapAllocator()); +DQN_FILE_SCOPE DqnString DqnString_(i32 const len, DqnMemStack *const stack); + +DQN_FILE_SCOPE DqnString DqnString_(DqnMemAPI const api = DqnMemAPI_HeapAllocator()); DQN_FILE_SCOPE DqnString DqnString_(DqnMemStack *const stack); +// NOTE: First level of indirection needs to turn the combined dqnstring_(guid) into a name. Otherwise +// each use of literalVarName will increment __COUNTER__ +#define DQN_STRING_LITERAL_INTERNAL1(srcVariable, literal, literalVarName) \ + DQN_STRING_LITERAL_INTERNAL2(srcVariable, literal, literalVarName) + +#define DQN_STRING_LITERAL_INTERNAL2(srcVariable, literal, literalVarName) \ + {}; \ + char literalVarName[] = literal; \ + srcVariable.InitLiteralNoAlloc(literalVarName, DQN_CHAR_COUNT(literalVarName)) + //////////////////////////////////////////////////////////////////////////////// // #DqnArray Public API - CPP Dynamic Array with Templates //////////////////////////////////////////////////////////////////////////////// @@ -524,6 +546,37 @@ struct DqnArray void RemoveStable(i64 *indexList, const i64 numIndexes); }; +template +DQN_FILE_SCOPE DqnArray DqnArray_(i64 const size, + DqnMemAPI const api = DqnMemAPI_HeapAllocator()) +{ + DqnArray result; + bool init = result.Init(size, api); + DQN_ASSERT_HARD(init); + return result; +} + +template +DQN_FILE_SCOPE DqnArray DqnArray_(i64 const size, DqnMemStack *const stack) +{ + DqnArray result = DqnArray_(size, DqnMemAPI_StackAllocator(stack)); + return result; +} + +template +DQN_FILE_SCOPE DqnArray DqnArray_(DqnMemAPI const api = DqnMemAPI_HeapAllocator()) +{ + DqnArray result = DqnArray_(0, api); + return result; +} + +template +DQN_FILE_SCOPE DqnArray DqnArray_(DqnMemStack *const stack) +{ + DqnArray result = DqnArray_(0, stack); + return result; +} + template bool DqnArray::Init(const i64 size, DqnMemStack *const stack) { @@ -1947,10 +2000,10 @@ struct DqnFile // fileOffset: The byte offset to starting writing from. // return: The number of bytes written. 0 if invalid args or it failed to write. - size_t Write(u8 const &buf, size_t const numBytesToWrite, size_t const fileOffset); + size_t Write(u8 const *const buf, size_t const numBytesToWrite, size_t const fileOffset); // return: The number of bytes read. 0 if invalid args or it failed to read. - size_t Read (u8 &buf, size_t const numBytesToRead); + size_t Read (u8 *const buf, size_t const numBytesToRead); // File close invalidates the handle after it is called. void Close(); @@ -1962,8 +2015,8 @@ struct DqnFile // used. Will be valid only if function returns true. This is basically the return value // of Read() // return: FALSE if insufficient bufferSize OR file access failure OR invalid args (i.e nullptr) - static bool ReadEntireFile (char const *const path, u8 &buf, size_t const bufSize, size_t &bytesRead); - static bool ReadEntireFileW(wchar_t const *const path, u8 &buf, size_t const bufSize, size_t &bytesRead); + static bool ReadEntireFile (char const *const path, u8 *const buf, size_t const bufSize, size_t &bytesRead); + static bool ReadEntireFileW(wchar_t const *const path, u8 *const buf, size_t const bufSize, size_t &bytesRead); // bufSize: Pass in ref to a size_t to fill out with the size of the returned buffer. Holds invalid data // if the returned ptr is null. @@ -2737,12 +2790,7 @@ DQN_FILE_SCOPE bool DqnAssertInternal(const bool result, const char *const file, va_end(argList); } -#ifdef DQN_WIN32_PLATFORM - DqnWin32_OutputDebugString(formatStr, file, lineNum, expr, userMsg); -#else printf(formatStr, file, lineNum, expr, userMsg); -#endif - (*((i32 *)0)) = 0; } return result; @@ -5192,19 +5240,29 @@ DQN_FILE_SCOPE i32 Dqn_I32ToWstr(i32 value, wchar_t *buf, i32 bufSize) //////////////////////////////////////////////////////////////////////////////// // #DqnString Impleemntation //////////////////////////////////////////////////////////////////////////////// -DQN_FILE_SCOPE DqnString DqnString_(const DqnMemAPI api) +DQN_FILE_SCOPE DqnString DqnString_(i32 const len, DqnMemAPI const api) { DqnString result; - bool init = result.InitSize(0, api); + bool init = result.InitSize(len, api); DQN_ASSERT_HARD(init); return result; } +DQN_FILE_SCOPE DqnString DqnString_(i32 const len, DqnMemStack *const stack) +{ + DqnString result = DqnString_(len, DqnMemAPI_StackAllocator(stack)); + return result; +} + +DQN_FILE_SCOPE DqnString DqnString_(DqnMemAPI const api) +{ + DqnString result = DqnString_(0, api); + return result; +} + DQN_FILE_SCOPE DqnString DqnString_(DqnMemStack *const stack) { - DqnString result; - bool init = result.InitSize(0, stack); - DQN_ASSERT_HARD(init); + DqnString result = DqnString_(0, stack); return result; } @@ -5216,22 +5274,33 @@ bool DqnString::InitSize(const i32 size, DqnMemStack *const stack) bool DqnString::InitSize(const i32 size, const DqnMemAPI api) { - DQN_ASSERT_HARD(size >= 0); + DQN_ASSERT(size >= 0); + if (size < 0) + { + DqnString nullString = {}; + *this = nullString; + return false; + } + if (size > 0) { size_t allocSize = sizeof(*(this->str)) * (size + 1); DqnMemAPI::Request info = DqnMemAPI::RequestAlloc(api, allocSize); this->str = (char *)api.callback(info); - if (!this->str) return false; + + if (!this->str) + { + return false; + } } - else + else // size == 0 { this->str = nullptr; } - this->len = 0; - this->max = size; - this->memAPI = api; + this->max = size; + this->len = 0; + this->memAPI = api; return true; } @@ -5239,10 +5308,10 @@ bool DqnString::InitFixedMem(char *const memory, i32 const sizeInBytes) { if (!memory || sizeInBytes == 0) return false; - this->str = (char *)memory; - this->len = 0; - this->max = sizeInBytes - 1; - this->memAPI = {}; + this->str = (char *)memory; + this->len = 0; + this->max = sizeInBytes - 1; + this->memAPI = {}; return true; } @@ -5266,8 +5335,8 @@ bool DqnString::InitLiteral(char const *const cstr, i32 const lenInBytes, DqnMem this->str = (char *)api.callback(info); if (!this->str) return false; - this->max = this->len; this->len = lenInBytes; + this->max = lenInBytes; this->memAPI = api; for (i32 i = 0; i < this->len; i++) this->str[i] = cstr[i]; @@ -5295,7 +5364,6 @@ bool DqnString::InitWLiteral(wchar_t const *const cstr, DqnMemAPI const api) { #if defined(DQN_IS_WIN32) && defined(DQN_WIN32_IMPLEMENTATION) i32 requiredLen = DqnWin32_WCharToUTF8(cstr, nullptr, 0); - this->len = requiredLen - 1; size_t allocSize = sizeof(*(this->str)) * (this->len + 1); @@ -5350,7 +5418,7 @@ bool DqnString::Expand(const i32 newMax) if (this->str) { - info = DqnMemAPI::RequestRealloc(this->memAPI, this->str, this->len, allocSize); + info = DqnMemAPI::RequestRealloc(this->memAPI, this->str, this->max, allocSize); } else { @@ -7757,7 +7825,7 @@ bool DqnFile::OpenW(const wchar_t *const path, u32 const flags_, Action const ac #endif } -size_t DqnFile::Write(u8 const &buf, size_t const numBytesToWrite, size_t const fileOffset) +size_t DqnFile::Write(u8 const *const buf, size_t const numBytesToWrite, size_t const fileOffset) { // TODO(doyle): Implement when it's needed if (!DQN_ASSERT_MSG(fileOffset == 0, "'fileOffset' not implemented yet")) return 0; @@ -7765,7 +7833,7 @@ size_t DqnFile::Write(u8 const &buf, size_t const numBytesToWrite, size_t const #if defined(DQN_WIN32_PLATFORM) DWORD bytesToWrite = (DWORD)numBytesToWrite; DWORD bytesWritten; - BOOL result = WriteFile(this->handle, (void *)&buf, bytesToWrite, &bytesWritten, nullptr); + BOOL result = WriteFile(this->handle, (void *)buf, bytesToWrite, &bytesWritten, nullptr); size_t numBytesWritten = (size_t)bytesWritten; // TODO(doyle): Better logging system @@ -7787,7 +7855,7 @@ size_t DqnFile::Write(u8 const &buf, size_t const numBytesToWrite, size_t const return numBytesWritten; } -size_t DqnFile::Read(u8 &buf, size_t const numBytesToRead) +size_t DqnFile::Read(u8 *const buf, size_t const numBytesToRead) { size_t numBytesRead = 0; if (this->handle) @@ -7797,7 +7865,7 @@ size_t DqnFile::Read(u8 &buf, size_t const numBytesToRead) DWORD bytesRead = 0; HANDLE win32Handle = this->handle; - BOOL result = ReadFile(win32Handle, (void *)&buf, bytesToRead, &bytesRead, nullptr); + BOOL result = ReadFile(win32Handle, (void *)buf, bytesToRead, &bytesRead, nullptr); numBytesRead = (size_t)bytesRead; // TODO(doyle): 0 also means it is completing async, but still valid @@ -7837,7 +7905,7 @@ u8 *DqnFile::ReadEntireFileSimpleW(wchar_t const *const path, size_t &bufSize, D if (!buf) return nullptr; size_t bytesRead = 0; - if (DqnFile::ReadEntireFileW(path, *buf, requiredSize, bytesRead)) + if (DqnFile::ReadEntireFileW(path, buf, requiredSize, bytesRead)) { bufSize = requiredSize; DQN_ASSERT(bytesRead == requiredSize); @@ -7860,7 +7928,7 @@ u8 *DqnFile::ReadEntireFileSimple(char const *const path, size_t &bufSize, DqnMe if (!buf) return nullptr; size_t bytesRead = 0; - if (DqnFile::ReadEntireFile(path, *buf, requiredSize, bytesRead)) + if (DqnFile::ReadEntireFile(path, buf, requiredSize, bytesRead)) { bufSize = requiredSize; DQN_ASSERT(bytesRead == requiredSize); @@ -7871,7 +7939,7 @@ u8 *DqnFile::ReadEntireFileSimple(char const *const path, size_t &bufSize, DqnMe return nullptr; } -bool DqnFile::ReadEntireFileW(wchar_t const *const path, u8 &buf, size_t const bufSize, +bool DqnFile::ReadEntireFileW(wchar_t const *const path, u8 *const buf, size_t const bufSize, size_t &bytesRead) { if (!path) return false; @@ -7896,7 +7964,7 @@ cleanup: return result; } -bool DqnFile::ReadEntireFile(const char *const path, u8 &buf, size_t const bufSize, +bool DqnFile::ReadEntireFile(const char *const path, u8 *const buf, size_t const bufSize, size_t &bytesRead) { if (!path) return false; diff --git a/dqn_unit_test.cpp b/dqn_unit_test.cpp index 79b5502..75a13ca 100644 --- a/dqn_unit_test.cpp +++ b/dqn_unit_test.cpp @@ -1913,7 +1913,7 @@ void DqnFile_Test() expectedSize); u8 *buffer = (u8 *)calloc(1, (size_t)file.size * sizeof(u8)); - DQN_ASSERT(file.Read(*buffer, (u32)file.size) == file.size); + DQN_ASSERT(file.Read(buffer, (u32)file.size) == file.size); free(buffer); file.Close(); @@ -1971,7 +1971,7 @@ void DqnFile_Test() size_t bytesToWrite = DqnStr_Len(writeData[i]); u8 *dataToWrite = (u8 *)(writeData[i]); - size_t bytesWritten = file->Write(*dataToWrite, bytesToWrite, 0); + size_t bytesWritten = file->Write(dataToWrite, bytesToWrite, 0); DQN_ASSERT(bytesWritten == bytesToWrite); file->Close(); } @@ -1991,7 +1991,7 @@ void DqnFile_Test() u8 *buffer = (u8 *)memStack.Push(file->size); DQN_ASSERT(buffer); - size_t bytesRead = file->Read(*buffer, file->size); + size_t bytesRead = file->Read(buffer, file->size); DQN_ASSERT(bytesRead == file->size); // Verify the data is the same as we wrote out @@ -2011,7 +2011,7 @@ void DqnFile_Test() DQN_ASSERT(buffer); size_t bytesRead = 0; - DQN_ASSERT(DqnFile::ReadEntireFile(fileNames[i], *buffer, reqSize, bytesRead)); + DQN_ASSERT(DqnFile::ReadEntireFile(fileNames[i], buffer, reqSize, bytesRead)); DQN_ASSERT(bytesRead == reqSize); // Verify the data is the same as we wrote out