Add opt. RAII-isms for destruction, fix thread bug
Thread Bug: Incorrectly using && operator for while (DqnJobQueue_TryExecuteNextJob(queue) && !DqnJobQueue_AllJobsComplete(queue)) causing it to prematurely exit if the main thread has completed its work before other threads have completed the remainder. Should be using an || operator, so instead creating a helper function which encapsulates this functionality.
This commit is contained in:
parent
886425eaa3
commit
19c427d756
208
dqn.h
208
dqn.h
@ -178,7 +178,7 @@ DQN_FILE_SCOPE bool DqnAssertInternal(const bool result, const char *const file,
|
|||||||
DQN_FILE_SCOPE void *DqnMem_Alloc (const size_t size);
|
DQN_FILE_SCOPE void *DqnMem_Alloc (const size_t size);
|
||||||
DQN_FILE_SCOPE void *DqnMem_Calloc (const size_t size);
|
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 *const 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);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -245,7 +245,7 @@ typedef struct DqnMemStack
|
|||||||
void TempRegionEnd (DqnMemStackTempRegion region);
|
void TempRegionEnd (DqnMemStackTempRegion region);
|
||||||
|
|
||||||
// Scoped Temporary Regions API
|
// Scoped Temporary Regions API
|
||||||
struct DqnMemStackTempRegionScoped TempRegionScoped();
|
struct DqnMemStackTempRegionGuard TempRegionGuard();
|
||||||
|
|
||||||
// Advanced API
|
// Advanced API
|
||||||
DqnMemStackBlock *AllocateCompatibleBlock(size_t size);
|
DqnMemStackBlock *AllocateCompatibleBlock(size_t size);
|
||||||
@ -322,16 +322,19 @@ typedef struct DqnMemStackTempRegion
|
|||||||
|
|
||||||
// region: Takes pointer to a zero-cleared DqnMemStackTempRegion struct.
|
// region: Takes pointer to a zero-cleared DqnMemStackTempRegion struct.
|
||||||
// return: FALSE if arguments are invalid.
|
// return: FALSE if arguments are invalid.
|
||||||
DQN_FILE_SCOPE bool DqnMemStackTempRegion_Begin(DqnMemStackTempRegion *region, DqnMemStack *const stack);
|
DQN_FILE_SCOPE bool DqnMemStackTempRegion_Begin(DqnMemStackTempRegion *const region, DqnMemStack *const stack);
|
||||||
DQN_FILE_SCOPE void DqnMemStackTempRegion_End (DqnMemStackTempRegion region);
|
DQN_FILE_SCOPE void DqnMemStackTempRegion_End (DqnMemStackTempRegion region);
|
||||||
|
|
||||||
// In cplusplus this allows automatic Begin/End pairs upon constructor of DqnMemStackTempRegionScoped.
|
|
||||||
// isInit: Constructor was successful
|
|
||||||
#ifdef DQN_CPP_MODE
|
#ifdef DQN_CPP_MODE
|
||||||
struct DqnMemStackTempRegionScoped
|
// Region guard automatically starts a region on construction and ends a region
|
||||||
|
// on destruction.
|
||||||
|
struct DqnMemStackTempRegionGuard
|
||||||
{
|
{
|
||||||
DqnMemStackTempRegionScoped(DqnMemStack *const stack, bool *const succeeded);
|
// lock: Takes a pointer to a pre-existing and already initialised stack
|
||||||
~DqnMemStackTempRegionScoped();
|
// bool: Pass in (optionally) a pointer to a bool which returns whether construction was successful.
|
||||||
|
// It can be FALSE if stack is NULL.
|
||||||
|
DqnMemStackTempRegionGuard(DqnMemStack *const stack, bool *const succeeded);
|
||||||
|
~DqnMemStackTempRegionGuard();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DqnMemStackTempRegion tempMemStack;
|
DqnMemStackTempRegion tempMemStack;
|
||||||
@ -648,7 +651,7 @@ template <typename T> void DqnArray<T>::Pop ()
|
|||||||
template <typename T> T* DqnArray<T>::Get (const u64 index) { return DqnArray_Get(this, index); }
|
template <typename T> T* DqnArray<T>::Get (const u64 index) { return DqnArray_Get(this, index); }
|
||||||
template <typename T> bool DqnArray<T>::Clear() { return DqnArray_Clear (this); }
|
template <typename T> bool DqnArray<T>::Clear() { return DqnArray_Clear (this); }
|
||||||
template <typename T> bool DqnArray<T>::Remove (const u64 index) { return DqnArray_Remove(this, index); }
|
template <typename T> bool DqnArray<T>::Remove (const u64 index) { return DqnArray_Remove(this, index); }
|
||||||
template <typename T> bool DqnArray<T>::RemoveStable(const u64 index) { return DqnArray_RemoveStable(this, u64 index); }
|
template <typename T> bool DqnArray<T>::RemoveStable(const u64 index) { return DqnArray_RemoveStable(this, index); }
|
||||||
|
|
||||||
#endif // DQN_CPP_MODE
|
#endif // DQN_CPP_MODE
|
||||||
|
|
||||||
@ -898,18 +901,18 @@ DQN_FILE_SCOPE bool DqnChar_IsAlphanum(char c);
|
|||||||
// #DqnStr Public API - Str Operations
|
// #DqnStr Public API - Str Operations
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// return: 0 if equal. 0 < if a is before b, > 0 if a is after b
|
// return: 0 if equal. 0 < if a is before b, > 0 if a is after b
|
||||||
DQN_FILE_SCOPE i32 DqnStr_Cmp(const char *a, const char *b);
|
DQN_FILE_SCOPE i32 DqnStr_Cmp(const char *const a, const char *const b);
|
||||||
|
|
||||||
// return: String length not including the NULL terminator. 0 if invalid args.
|
// return: String length not including the NULL terminator. 0 if invalid args.
|
||||||
DQN_FILE_SCOPE i32 DqnStr_Len (const char *a);
|
DQN_FILE_SCOPE i32 DqnStr_Len (const char *const a);
|
||||||
|
|
||||||
// Get the String length starting from a, up to and not including the first delimiter character.
|
// Get the String length starting from a, up to and not including the first delimiter character.
|
||||||
DQN_FILE_SCOPE i32 DqnStr_LenDelimitWith(const char *a, const char delimiter);
|
DQN_FILE_SCOPE i32 DqnStr_LenDelimitWith(char *const a, const char delimiter);
|
||||||
|
|
||||||
// return: The dest argument, NULL if args invalid (i.e. NULL pointers or numChars < 0)
|
// return: The dest argument, NULL if args invalid (i.e. NULL pointers or numChars < 0)
|
||||||
DQN_FILE_SCOPE char *DqnStr_Copy(char *dest, const char *src, i32 numChars);
|
DQN_FILE_SCOPE char *DqnStr_Copy(char *const dest, const char *const src, const i32 numChars);
|
||||||
|
|
||||||
DQN_FILE_SCOPE bool DqnStr_Reverse (char *buf, const i32 bufSize);
|
DQN_FILE_SCOPE bool DqnStr_Reverse (char *const buf, const i32 bufSize);
|
||||||
DQN_FILE_SCOPE i32 DqnStr_FindFirstOccurence(const char *const src, const i32 srcLen, const char *const find, const i32 findLen);
|
DQN_FILE_SCOPE i32 DqnStr_FindFirstOccurence(const char *const src, const i32 srcLen, const char *const find, const i32 findLen);
|
||||||
DQN_FILE_SCOPE bool DqnStr_HasSubstring (const char *const src, const i32 srcLen, const char *const find, const i32 findLen);
|
DQN_FILE_SCOPE bool DqnStr_HasSubstring (const char *const src, const i32 srcLen, const char *const find, const i32 findLen);
|
||||||
|
|
||||||
@ -917,14 +920,14 @@ DQN_FILE_SCOPE bool DqnStr_HasSubstring (const char *const src, const i32 s
|
|||||||
#define DQN_64BIT_NUM_MAX_STR_SIZE 21
|
#define DQN_64BIT_NUM_MAX_STR_SIZE 21
|
||||||
// Return the len of the derived string. If buf is NULL and or bufSize is 0 the
|
// Return the len of the derived string. If buf is NULL and or bufSize is 0 the
|
||||||
// function returns the required string length for the integer.
|
// function returns the required string length for the integer.
|
||||||
DQN_FILE_SCOPE i32 Dqn_I64ToStr(i64 value, char *const buf, const i32 bufSize);
|
DQN_FILE_SCOPE i32 Dqn_I64ToStr(const i64 value, char *const buf, const i32 bufSize);
|
||||||
DQN_FILE_SCOPE i64 Dqn_StrToI64(const char *const buf, const i32 bufSize);
|
DQN_FILE_SCOPE i64 Dqn_StrToI64(const char *const buf, const i32 bufSize);
|
||||||
// WARNING: Not robust, precision errors and whatnot but good enough!
|
// WARNING: Not robust, precision errors and whatnot but good enough!
|
||||||
DQN_FILE_SCOPE f32 Dqn_StrToF32(const char *const buf, const i32 bufSize);
|
DQN_FILE_SCOPE f32 Dqn_StrToF32(const char *const buf, const i32 bufSize);
|
||||||
|
|
||||||
// Both return the number of bytes read, return 0 if invalid codepoint or UTF8
|
// Both return the number of bytes read, return 0 if invalid codepoint or UTF8
|
||||||
DQN_FILE_SCOPE u32 Dqn_UCSToUTF8(u32 *dest, u32 character);
|
DQN_FILE_SCOPE u32 Dqn_UCSToUTF8(u32 *const dest, const u32 character);
|
||||||
DQN_FILE_SCOPE u32 Dqn_UTF8ToUCS(u32 *dest, u32 character);
|
DQN_FILE_SCOPE u32 Dqn_UTF8ToUCS(u32 *const dest, const u32 character);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// #DqnWChar Public API - WChar Operations
|
// #DqnWChar Public API - WChar Operations
|
||||||
@ -932,8 +935,8 @@ DQN_FILE_SCOPE u32 Dqn_UTF8ToUCS(u32 *dest, u32 character);
|
|||||||
DQN_FILE_SCOPE bool DqnWChar_IsDigit(const wchar_t c);
|
DQN_FILE_SCOPE bool DqnWChar_IsDigit(const wchar_t c);
|
||||||
DQN_FILE_SCOPE wchar_t DqnWChar_ToLower(const wchar_t c);
|
DQN_FILE_SCOPE wchar_t DqnWChar_ToLower(const wchar_t c);
|
||||||
|
|
||||||
DQN_FILE_SCOPE i32 DqnWStr_Len(const wchar_t *a);
|
DQN_FILE_SCOPE i32 DqnWStr_Len(const wchar_t *const a);
|
||||||
DQN_FILE_SCOPE i32 DqnWStr_Cmp(const wchar_t *a, const wchar_t *b);
|
DQN_FILE_SCOPE i32 DqnWStr_Cmp(const wchar_t *const a, const wchar_t *const b);
|
||||||
|
|
||||||
DQN_FILE_SCOPE bool Dqn_WStrReverse(wchar_t *buf, const i32 bufSize);
|
DQN_FILE_SCOPE bool Dqn_WStrReverse(wchar_t *buf, const i32 bufSize);
|
||||||
DQN_FILE_SCOPE i32 Dqn_WStrToI32(const wchar_t *const buf, const i32 bufSize);
|
DQN_FILE_SCOPE i32 Dqn_WStrToI32(const wchar_t *const buf, const i32 bufSize);
|
||||||
@ -1000,11 +1003,17 @@ typedef struct DqnFile
|
|||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
#if defined(DQN_CPP_MODE)
|
#if defined(DQN_CPP_MODE)
|
||||||
bool Open (char const *const path, const u32 permissionFlags_, const enum DqnFileAction action);
|
// If true, RAII cleanup in the destructor on scope exit. Can be changed at any point by user.
|
||||||
bool OpenW(wchar_t const *const path, const u32 permissionFlags_, const enum DqnFileAction action);
|
bool raiiCleanup;
|
||||||
|
DqnFile (const bool raiiCleanup = false);
|
||||||
|
~DqnFile();
|
||||||
|
|
||||||
|
bool Open (const char *const path, const u32 permissionFlags_, const enum DqnFileAction action);
|
||||||
|
bool OpenW(const wchar_t *const path, const u32 permissionFlags_, const enum DqnFileAction action);
|
||||||
size_t Write(u8 *const buffer, const size_t numBytesToWrite, const size_t fileOffset);
|
size_t Write(u8 *const buffer, const size_t numBytesToWrite, const size_t fileOffset);
|
||||||
size_t Read (u8 *const buffer, const size_t numBytesToRead);
|
size_t Read (u8 *const buffer, const size_t numBytesToRead);
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
} DqnFile;
|
} DqnFile;
|
||||||
|
|
||||||
@ -1021,7 +1030,7 @@ DQN_FILE_SCOPE bool DqnFile_OpenW(const wchar_t *const path, DqnFile *const file
|
|||||||
DQN_FILE_SCOPE size_t DqnFile_Write(const DqnFile *const file, u8 *const buffer, const size_t numBytesToWrite, const size_t fileOffset);
|
DQN_FILE_SCOPE size_t DqnFile_Write(const DqnFile *const file, u8 *const buffer, const size_t numBytesToWrite, const size_t fileOffset);
|
||||||
|
|
||||||
// return: The number of bytes read. 0 if invalid args or it failed to read.
|
// return: The number of bytes read. 0 if invalid args or it failed to read.
|
||||||
DQN_FILE_SCOPE size_t DqnFile_Read (const DqnFile file, u8 *const buffer, const size_t numBytesToRead);
|
DQN_FILE_SCOPE size_t DqnFile_Read (const DqnFile *const file, u8 *const buffer, const size_t numBytesToRead);
|
||||||
DQN_FILE_SCOPE void DqnFile_Close(DqnFile *const file);
|
DQN_FILE_SCOPE void DqnFile_Close(DqnFile *const file);
|
||||||
|
|
||||||
// NOTE: You can't delete a file unless the handle has been closed to it on Win32.
|
// NOTE: You can't delete a file unless the handle has been closed to it on Win32.
|
||||||
@ -1072,6 +1081,22 @@ typedef struct DqnLock
|
|||||||
#endif
|
#endif
|
||||||
} DqnLock;
|
} DqnLock;
|
||||||
|
|
||||||
|
#if defined(DQN_CPP_MODE)
|
||||||
|
// Lock guard automatically acquires a lock on construction and releases a lock
|
||||||
|
// on destruction.
|
||||||
|
struct DqnLockGuard
|
||||||
|
{
|
||||||
|
// lock: Takes a pointer to a pre-existing and already initialised lock
|
||||||
|
// bool: Pass in (optionally) a pointer to a bool which returns whether a lock was successful.
|
||||||
|
// FALSE if lock is NULL.
|
||||||
|
DqnLockGuard(DqnLock *const lock_, bool *const succeeded);
|
||||||
|
~DqnLockGuard();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DqnLock *lock;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
DQN_FILE_SCOPE bool DqnLock_Init (DqnLock *const lock, const u32 spinCount = 16000);
|
DQN_FILE_SCOPE bool DqnLock_Init (DqnLock *const lock, const u32 spinCount = 16000);
|
||||||
DQN_FILE_SCOPE void DqnLock_Acquire(DqnLock *const lock);
|
DQN_FILE_SCOPE void DqnLock_Acquire(DqnLock *const lock);
|
||||||
DQN_FILE_SCOPE void DqnLock_Release(DqnLock *const lock);
|
DQN_FILE_SCOPE void DqnLock_Release(DqnLock *const lock);
|
||||||
@ -1125,30 +1150,39 @@ typedef struct DqnJobQueue
|
|||||||
u32 volatile jobInsertIndex;
|
u32 volatile jobInsertIndex;
|
||||||
|
|
||||||
#if defined(DQN_CPP_MODE)
|
#if defined(DQN_CPP_MODE)
|
||||||
bool Init (DqnJob const *const jobList_, const u32 jobListSize, const u32 numThreads);
|
bool Init (const DqnJob *const jobList_, const u32 jobListSize, const u32 numThreads);
|
||||||
bool AddJob (const DqnJob job);
|
bool AddJob (const DqnJob job);
|
||||||
|
|
||||||
|
void BlockAndCompleteAllJobs();
|
||||||
bool TryExecuteNextJob();
|
bool TryExecuteNextJob();
|
||||||
bool AllJobsComplete ();
|
bool AllJobsComplete ();
|
||||||
#endif
|
#endif
|
||||||
} DqnJobQueue;
|
} DqnJobQueue;
|
||||||
|
|
||||||
|
// TODO(doyle): Queue delete, thread delete
|
||||||
|
|
||||||
// queue: Pass a pointer to a zero cleared DqnJobQueue struct
|
// queue: Pass a pointer to a zero cleared DqnJobQueue struct
|
||||||
// jobList: Pass in a pointer to an array of DqnJob's
|
// jobList: Pass in a pointer to an array of DqnJob's
|
||||||
// jobListSize: The number of elements in the jobList array
|
// jobListSize: The number of elements in the jobList array
|
||||||
// numThreads: The number of threads the queue should request from the OS for working on the queue
|
// numThreads: The number of threads the queue should request from the OS for working on the queue
|
||||||
// return: FALSE if invalid args.
|
// return: FALSE if invalid args i.e. NULL ptrs or jobListSize & numThreads == 0
|
||||||
DQN_FILE_SCOPE bool DqnJobQueue_Init(DqnJobQueue *const queue, DqnJob const *const jobList,
|
DQN_FILE_SCOPE bool DqnJobQueue_Init(DqnJobQueue *const queue, const DqnJob *const jobList,
|
||||||
const u32 jobListSize, const u32 numThreads);
|
const u32 jobListSize, const u32 numThreads);
|
||||||
|
|
||||||
// return: FALSE if the job is not able to be added, this occurs if the queue is full.
|
// return: FALSE if the job is not able to be added, this occurs if the queue is full.
|
||||||
DQN_FILE_SCOPE bool DqnJobQueue_AddJob(DqnJobQueue *const queue, const DqnJob job);
|
DQN_FILE_SCOPE bool DqnJobQueue_AddJob(DqnJobQueue *const queue, const DqnJob job);
|
||||||
|
|
||||||
|
// Helper function that combines TryExecuteNextJob() and AllJobsComplete(), i.e.
|
||||||
|
// complete all work before moving on. Does nothing if queue is NULL.
|
||||||
|
DQN_FILE_SCOPE void DqnJobQueue_BlockAndCompleteAllJobs(DqnJobQueue *const queue);
|
||||||
|
|
||||||
// return: TRUE if there was a job to execute (the calling thread executes it). FALSE if it could
|
// return: TRUE if there was a job to execute (the calling thread executes it). FALSE if it could
|
||||||
// not get a job. It may return FALSE whilst there are still jobs, this means that another thread
|
// not get a job. It may return FALSE whilst there are still jobs, this means that another thread
|
||||||
// has taken the job before the calling thread could and should NOT be used to determine if there
|
// has taken the job before the calling thread could and should NOT be used to determine if there
|
||||||
// are any remaining jobs left. That can only be definitively known using
|
// are any remaining jobs left. That can only be definitively known using
|
||||||
// DqnJobQueue_AllJobsComplete(). This is typically combined like so ..
|
// DqnJobQueue_AllJobsComplete(). This is typically combined like so ..
|
||||||
// while (DqnJobQueue_TryExecuteNextJob(queue) && !DqnJobQueue_AllJobsComplete(queue));
|
// while (DqnJobQueue_TryExecuteNextJob(queue) || !DqnJobQueue_AllJobsComplete(queue));
|
||||||
|
// Return FALSE also if queue is a NULL pointer.
|
||||||
DQN_FILE_SCOPE bool DqnJobQueue_TryExecuteNextJob(DqnJobQueue *const queue);
|
DQN_FILE_SCOPE bool DqnJobQueue_TryExecuteNextJob(DqnJobQueue *const queue);
|
||||||
DQN_FILE_SCOPE bool DqnJobQueue_AllJobsComplete (DqnJobQueue *const queue);
|
DQN_FILE_SCOPE bool DqnJobQueue_AllJobsComplete (DqnJobQueue *const queue);
|
||||||
|
|
||||||
@ -1757,7 +1791,7 @@ DQN_FILE_SCOPE void DqnMem_Clear(void *const memory, const u8 clearValue, const
|
|||||||
if (memory) memset(memory, clearValue, size);
|
if (memory) memset(memory, clearValue, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE void *DqnMem_Realloc(void *const memory, const size_t newSize)
|
DQN_FILE_SCOPE void *DqnMem_Realloc(void *memory, const size_t newSize)
|
||||||
{
|
{
|
||||||
void *result = realloc(memory, newSize);
|
void *result = realloc(memory, newSize);
|
||||||
return result;
|
return result;
|
||||||
@ -1817,7 +1851,7 @@ DqnMemStackTempRegion DqnMemStack::TempRegionBegin()
|
|||||||
void DqnMemStack::TempRegionEnd(DqnMemStackTempRegion region) { DqnMemStackTempRegion_End(region); }
|
void DqnMemStack::TempRegionEnd(DqnMemStackTempRegion region) { DqnMemStackTempRegion_End(region); }
|
||||||
|
|
||||||
// NOTE: Guaranteed to always succeed. Fails when arguments are invalid, like a NULL ptr which is impossible here.
|
// NOTE: Guaranteed to always succeed. Fails when arguments are invalid, like a NULL ptr which is impossible here.
|
||||||
DqnMemStackTempRegionScoped DqnMemStack::TempRegionScoped() { return DqnMemStackTempRegionScoped(this, NULL); }
|
DqnMemStackTempRegionGuard DqnMemStack::TempRegionGuard() { return DqnMemStackTempRegionGuard(this, NULL); }
|
||||||
|
|
||||||
DqnMemStackBlock *DqnMemStack::AllocateCompatibleBlock(size_t size) { return DqnMemStack_AllocateCompatibleBlock(this, size); }
|
DqnMemStackBlock *DqnMemStack::AllocateCompatibleBlock(size_t size) { return DqnMemStack_AllocateCompatibleBlock(this, size); }
|
||||||
bool DqnMemStack::AttachBlock (DqnMemStackBlock *const newBlock) { return DqnMemStack_AttachBlock (this, newBlock); }
|
bool DqnMemStack::AttachBlock (DqnMemStackBlock *const newBlock) { return DqnMemStack_AttachBlock (this, newBlock); }
|
||||||
@ -2027,7 +2061,7 @@ DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock(DqnMemStack *const stack, const b
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// #DqnMemStackTempRegion Implementation
|
// #DqnMemStackTempRegion Implementation
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
DQN_FILE_SCOPE bool DqnMemStackTempRegion_Begin(DqnMemStackTempRegion *region,
|
DQN_FILE_SCOPE bool DqnMemStackTempRegion_Begin(DqnMemStackTempRegion *const region,
|
||||||
DqnMemStack *const stack)
|
DqnMemStack *const stack)
|
||||||
{
|
{
|
||||||
if (!region || !stack) return false;
|
if (!region || !stack) return false;
|
||||||
@ -2057,13 +2091,20 @@ DQN_FILE_SCOPE void DqnMemStackTempRegion_End(DqnMemStackTempRegion region)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DQN_CPP_MODE
|
#ifdef DQN_CPP_MODE
|
||||||
DqnMemStackTempRegionScoped::DqnMemStackTempRegionScoped(DqnMemStack *const stack, bool *const succeeded)
|
DqnMemStackTempRegionGuard::DqnMemStackTempRegionGuard(DqnMemStack *const stack, bool *const succeeded)
|
||||||
{
|
{
|
||||||
bool result = DqnMemStackTempRegion_Begin(&this->tempMemStack, stack);
|
if (stack)
|
||||||
if (succeeded) *succeeded = result;
|
{
|
||||||
|
DQN_ASSERT_HARD(DqnMemStackTempRegion_Begin(&this->tempMemStack, stack));
|
||||||
|
if (succeeded) *succeeded = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (succeeded) *succeeded = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DqnMemStackTempRegionScoped::~DqnMemStackTempRegionScoped()
|
DqnMemStackTempRegionGuard::~DqnMemStackTempRegionGuard()
|
||||||
{
|
{
|
||||||
DqnMemStackTempRegion_End(this->tempMemStack);
|
DqnMemStackTempRegion_End(this->tempMemStack);
|
||||||
}
|
}
|
||||||
@ -3106,23 +3147,26 @@ DQN_FILE_SCOPE bool DqnChar_IsAlphaNum(char c)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// #DqnStr Implementation
|
// #DqnStr Implementation
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
DQN_FILE_SCOPE i32 DqnStr_Cmp(const char *a, const char *b)
|
DQN_FILE_SCOPE i32 DqnStr_Cmp(const char *const a, const char *const b)
|
||||||
{
|
{
|
||||||
if (!a && !b) return -1;
|
if (!a && !b) return -1;
|
||||||
if (!a) return -1;
|
if (!a) return -1;
|
||||||
if (!b) return -1;
|
if (!b) return -1;
|
||||||
|
|
||||||
while ((*a) == (*b))
|
char const *aPtr = a;
|
||||||
|
char const *bPtr = b;
|
||||||
|
|
||||||
|
while ((*aPtr) == (*bPtr))
|
||||||
{
|
{
|
||||||
if (!(*a)) return 0;
|
if (!(*aPtr)) return 0;
|
||||||
a++;
|
aPtr++;
|
||||||
b++;
|
bPtr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (((*a) < (*b)) ? -1 : 1);
|
return (((*aPtr) < (*bPtr)) ? -1 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE i32 DqnStr_Len(const char *a)
|
DQN_FILE_SCOPE i32 DqnStr_Len(const char *const a)
|
||||||
{
|
{
|
||||||
i32 result = 0;
|
i32 result = 0;
|
||||||
while (a && a[result]) result++;
|
while (a && a[result]) result++;
|
||||||
@ -3137,7 +3181,7 @@ DQN_FILE_SCOPE i32 DqnStr_LenDelimitWith(const char *a, const char delimiter)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE char *DqnStr_Copy(char *dest, const char *src, i32 numChars)
|
DQN_FILE_SCOPE char *DqnStr_Copy(char *const dest, const char *const src, const i32 numChars)
|
||||||
{
|
{
|
||||||
if (!dest) return NULL;
|
if (!dest) return NULL;
|
||||||
if (!src) return NULL;
|
if (!src) return NULL;
|
||||||
@ -3149,7 +3193,7 @@ DQN_FILE_SCOPE char *DqnStr_Copy(char *dest, const char *src, i32 numChars)
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE bool DqnStr_Reverse(char *buf, const i32 bufSize)
|
DQN_FILE_SCOPE bool DqnStr_Reverse(char *const buf, const i32 bufSize)
|
||||||
{
|
{
|
||||||
if (!buf) return false;
|
if (!buf) return false;
|
||||||
i32 mid = bufSize / 2;
|
i32 mid = bufSize / 2;
|
||||||
@ -3213,7 +3257,7 @@ DQN_FILE_SCOPE bool DqnStr_HasSubstring(const char *const src, const i32 srcLen,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE i32 Dqn_I64ToStr(i64 value, char *const buf, const i32 bufSize)
|
DQN_FILE_SCOPE i32 Dqn_I64ToStr(const i64 value, char *const buf, const i32 bufSize)
|
||||||
{
|
{
|
||||||
bool validBuffer = true;
|
bool validBuffer = true;
|
||||||
if (!buf || bufSize == 0) validBuffer = false;
|
if (!buf || bufSize == 0) validBuffer = false;
|
||||||
@ -3433,7 +3477,7 @@ DQN_FILE_SCOPE f32 Dqn_StrToF32(const char *const buf, const i32 bufSize)
|
|||||||
The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well as 0xfffe and
|
The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well as 0xfffe and
|
||||||
0xffff (UCS noncharacters) should not appear in conforming UTF-8 streams.
|
0xffff (UCS noncharacters) should not appear in conforming UTF-8 streams.
|
||||||
*/
|
*/
|
||||||
DQN_FILE_SCOPE u32 Dqn_UCSToUTF8(u32 *dest, u32 character)
|
DQN_FILE_SCOPE u32 Dqn_UCSToUTF8(u32 *const dest, const u32 character)
|
||||||
{
|
{
|
||||||
if (!dest) return 0;
|
if (!dest) return 0;
|
||||||
|
|
||||||
@ -3502,7 +3546,7 @@ DQN_FILE_SCOPE u32 Dqn_UCSToUTF8(u32 *dest, u32 character)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE u32 Dqn_UTF8ToUCS(u32 *dest, u32 character)
|
DQN_FILE_SCOPE u32 Dqn_UTF8ToUCS(u32 *const dest, const u32 character)
|
||||||
{
|
{
|
||||||
if (!dest) return 0;
|
if (!dest) return 0;
|
||||||
|
|
||||||
@ -3598,27 +3642,30 @@ DQN_FILE_SCOPE wchar_t DqnWChar_ToLower(const wchar_t c)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// #DqnWStr Implementation
|
// #DqnWStr Implementation
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
DQN_FILE_SCOPE i32 DqnWStr_Len(const wchar_t *a)
|
DQN_FILE_SCOPE i32 DqnWStr_Len(const wchar_t *const a)
|
||||||
{
|
{
|
||||||
i32 result = 0;
|
i32 result = 0;
|
||||||
while (a && a[result]) result++;
|
while (a && a[result]) result++;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE i32 DqnWStr_Cmp(const wchar_t *a, const wchar_t *b)
|
DQN_FILE_SCOPE i32 DqnWStr_Cmp(const wchar_t *const a, const wchar_t *const b)
|
||||||
{
|
{
|
||||||
if (!a && !b) return -1;
|
if (!a && !b) return -1;
|
||||||
if (!a) return -1;
|
if (!a) return -1;
|
||||||
if (!b) return -1;
|
if (!b) return -1;
|
||||||
|
|
||||||
while ((*a) == (*b))
|
const wchar_t *aPtr = a;
|
||||||
|
const wchar_t *bPtr = b;
|
||||||
|
|
||||||
|
while ((*aPtr) == (*bPtr))
|
||||||
{
|
{
|
||||||
if (!(*a)) return 0;
|
if (!(*aPtr)) return 0;
|
||||||
a++;
|
aPtr++;
|
||||||
b++;
|
bPtr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (((*a) < (*b)) ? -1 : 1);
|
return (((*aPtr) < (*bPtr)) ? -1 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE bool Dqn_WStrReverse(wchar_t *buf, const i32 bufSize)
|
DQN_FILE_SCOPE bool Dqn_WStrReverse(wchar_t *buf, const i32 bufSize)
|
||||||
@ -5506,15 +5553,18 @@ void DqnIni_PropertyValueSet(DqnIni *ini, int section, int property,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// XPlatform > #DqnFileInternal CPP Implementation
|
// XPlatform > #DqnFile CPP Implementation
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool DqnFile::Open(char const *const path, const u32 permissionFlags_,
|
DqnFile::DqnFile (const bool raiiCleanup) { this->raiiCleanup = raiiCleanup; }
|
||||||
|
DqnFile::~DqnFile() { if (this->raiiCleanup) this->Close(); }
|
||||||
|
|
||||||
|
bool DqnFile::Open(const char *const path, const u32 permissionFlags_,
|
||||||
const enum DqnFileAction action)
|
const enum DqnFileAction action)
|
||||||
{
|
{
|
||||||
return DqnFile_Open(path, this, permissionFlags, action);
|
return DqnFile_Open(path, this, permissionFlags, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DqnFile::OpenW(wchar_t const *const path, const u32 permissionFlags_,
|
bool DqnFile::OpenW(const wchar_t *const path, const u32 permissionFlags_,
|
||||||
const enum DqnFileAction action)
|
const enum DqnFileAction action)
|
||||||
{
|
{
|
||||||
return DqnFile_OpenW(path, this, permissionFlags, action);
|
return DqnFile_OpenW(path, this, permissionFlags, action);
|
||||||
@ -5527,7 +5577,7 @@ size_t DqnFile::Write(u8 *const buffer, const size_t numBytesToWrite, const size
|
|||||||
|
|
||||||
size_t DqnFile::Read(u8 *const buffer, const size_t numBytesToRead)
|
size_t DqnFile::Read(u8 *const buffer, const size_t numBytesToRead)
|
||||||
{
|
{
|
||||||
return DqnFile_Read(*this, buffer, numBytesToRead);
|
return DqnFile_Read(this, buffer, numBytesToRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DqnFile::Close() { DqnFile_Close(this); }
|
void DqnFile::Close() { DqnFile_Close(this); }
|
||||||
@ -5895,16 +5945,16 @@ DQN_FILE_SCOPE size_t DqnFile_Write(const DqnFile *const file,
|
|||||||
return numBytesWritten;
|
return numBytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE size_t DqnFile_Read(DqnFile file, u8 *const buffer,
|
DQN_FILE_SCOPE size_t DqnFile_Read(const DqnFile *const file, u8 *const buffer,
|
||||||
const size_t numBytesToRead)
|
const size_t numBytesToRead)
|
||||||
{
|
{
|
||||||
size_t numBytesRead = 0;
|
size_t numBytesRead = 0;
|
||||||
if (file.handle && buffer)
|
if (file && file->handle && buffer)
|
||||||
{
|
{
|
||||||
#if defined(DQN_WIN32_PLATFORM)
|
#if defined(DQN_WIN32_PLATFORM)
|
||||||
DWORD bytesToRead = (DWORD)numBytesToRead;
|
DWORD bytesToRead = (DWORD)numBytesToRead;
|
||||||
DWORD bytesRead = 0;
|
DWORD bytesRead = 0;
|
||||||
HANDLE win32Handle = file.handle;
|
HANDLE win32Handle = file->handle;
|
||||||
|
|
||||||
BOOL result = ReadFile(win32Handle, (void *)buffer, bytesToRead,
|
BOOL result = ReadFile(win32Handle, (void *)buffer, bytesToRead,
|
||||||
&bytesRead, NULL);
|
&bytesRead, NULL);
|
||||||
@ -5919,10 +5969,10 @@ DQN_FILE_SCOPE size_t DqnFile_Read(DqnFile file, u8 *const buffer,
|
|||||||
#elif defined(DQN_UNIX_PLATFORM)
|
#elif defined(DQN_UNIX_PLATFORM)
|
||||||
// TODO(doyle): Syscall version
|
// TODO(doyle): Syscall version
|
||||||
const size_t ITEMS_TO_READ = 1;
|
const size_t ITEMS_TO_READ = 1;
|
||||||
if (fread(buffer, numBytesToRead, ITEMS_TO_READ, (FILE *)file.handle) ==
|
if (fread(buffer, numBytesToRead, ITEMS_TO_READ, (FILE *)file->handle) ==
|
||||||
ITEMS_TO_READ)
|
ITEMS_TO_READ)
|
||||||
{
|
{
|
||||||
rewind((FILE *)file.handle);
|
rewind((FILE *)file->handle);
|
||||||
numBytesRead = ITEMS_TO_READ * numBytesToRead;
|
numBytesRead = ITEMS_TO_READ * numBytesToRead;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -6100,11 +6150,32 @@ void DqnLock_Delete(DqnLock *const lock)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Win32Platform > #DqnLock CPP Implementation
|
// Win32Platform > #DqnLock CPP Implementation
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool DqnLock::Init(const u32 spinCount) { return DqnLock_Init(this, spinCount); }
|
|
||||||
void DqnLock::Acquire() { DqnLock_Acquire(this); }
|
void DqnLock::Acquire() { DqnLock_Acquire(this); }
|
||||||
void DqnLock::Release() { DqnLock_Release(this); }
|
void DqnLock::Release() { DqnLock_Release(this); }
|
||||||
void DqnLock::Delete() { DqnLock_Delete (this); }
|
void DqnLock::Delete() { DqnLock_Delete (this); }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Win32Platform > #DqnLockGuard CPP Implementation
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
DqnLockGuard::DqnLockGuard(DqnLock *const lock_, bool *const succeeded)
|
||||||
|
{
|
||||||
|
if (lock_)
|
||||||
|
{
|
||||||
|
this->lock = lock_;
|
||||||
|
this->lock->Acquire();
|
||||||
|
if (succeeded) *succeeded = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (succeeded) *succeeded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DqnLockGuard::~DqnLockGuard()
|
||||||
|
{
|
||||||
|
if (this->lock) this->lock->Release();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Win32Platform > #DqnAtomic Implementation
|
// Win32Platform > #DqnAtomic Implementation
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -6234,8 +6305,16 @@ DQN_FILE_SCOPE bool DqnJobQueue_AddJob(DqnJobQueue *const queue, const DqnJob jo
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DQN_FILE_SCOPE void DqnJobQueue_BlockAndCompleteAllJobs(DqnJobQueue *const queue)
|
||||||
|
{
|
||||||
|
while (DqnJobQueue_TryExecuteNextJob(queue) || !DqnJobQueue_AllJobsComplete(queue))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE bool DqnJobQueue_TryExecuteNextJob(DqnJobQueue *const queue)
|
DQN_FILE_SCOPE bool DqnJobQueue_TryExecuteNextJob(DqnJobQueue *const queue)
|
||||||
{
|
{
|
||||||
|
if (!queue) return false;
|
||||||
|
|
||||||
u32 originalJobToExecute = queue->jobToExecuteIndex;
|
u32 originalJobToExecute = queue->jobToExecuteIndex;
|
||||||
if (originalJobToExecute != queue->jobInsertIndex)
|
if (originalJobToExecute != queue->jobInsertIndex)
|
||||||
{
|
{
|
||||||
@ -6262,6 +6341,8 @@ DQN_FILE_SCOPE bool DqnJobQueue_TryExecuteNextJob(DqnJobQueue *const queue)
|
|||||||
|
|
||||||
DQN_FILE_SCOPE bool DqnJobQueue_AllJobsComplete(DqnJobQueue *const queue)
|
DQN_FILE_SCOPE bool DqnJobQueue_AllJobsComplete(DqnJobQueue *const queue)
|
||||||
{
|
{
|
||||||
|
if (!queue) return false;
|
||||||
|
|
||||||
bool result = (queue->numJobsToComplete == 0);
|
bool result = (queue->numJobsToComplete == 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -6269,13 +6350,14 @@ DQN_FILE_SCOPE bool DqnJobQueue_AllJobsComplete(DqnJobQueue *const queue)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Win32Platform > #DqnJobQueue CPP Implementation
|
// Win32Platform > #DqnJobQueue CPP Implementation
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool DqnJobQueue::Init(DqnJob const *const jobList_, const u32 jobListSize, const u32 numThreads)
|
bool DqnJobQueue::Init(const DqnJob *const jobList_, const u32 jobListSize, const u32 numThreads)
|
||||||
{
|
{
|
||||||
bool result = DqnJobQueue_Init(this, jobList, jobListSize, numThreads);
|
bool result = DqnJobQueue_Init(this, jobList, jobListSize, numThreads);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DqnJobQueue::AddJob (const DqnJob job) { return DqnJobQueue_AddJob(this, job); }
|
bool DqnJobQueue::AddJob (const DqnJob job) { return DqnJobQueue_AddJob(this, job); }
|
||||||
|
void DqnJobQueue::BlockAndCompleteAllJobs() { DqnJobQueue_BlockAndCompleteAllJobs(this); }
|
||||||
bool DqnJobQueue::TryExecuteNextJob() { return DqnJobQueue_TryExecuteNextJob(this); }
|
bool DqnJobQueue::TryExecuteNextJob() { return DqnJobQueue_TryExecuteNextJob(this); }
|
||||||
bool DqnJobQueue::AllJobsComplete () { return DqnJobQueue_AllJobsComplete(this); }
|
bool DqnJobQueue::AllJobsComplete () { return DqnJobQueue_AllJobsComplete(this); }
|
||||||
|
|
||||||
|
@ -1576,11 +1576,23 @@ void FileTest()
|
|||||||
expectedSize);
|
expectedSize);
|
||||||
|
|
||||||
u8 *buffer = (u8 *)calloc(1, (size_t)file.size * sizeof(u8));
|
u8 *buffer = (u8 *)calloc(1, (size_t)file.size * sizeof(u8));
|
||||||
DQN_ASSERT(DqnFile_Read(file, buffer, (u32)file.size) == file.size);
|
DQN_ASSERT(DqnFile_Read(&file, buffer, (u32)file.size) == file.size);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
|
||||||
DqnFile_Close(&file);
|
DqnFile_Close(&file);
|
||||||
DQN_ASSERT(!file.handle && file.size == 0 && file.permissionFlags == 0);
|
DQN_ASSERT(!file.handle && file.size == 0 && file.permissionFlags == 0);
|
||||||
|
|
||||||
|
if (1)
|
||||||
|
{
|
||||||
|
DqnFile raiiFile = DqnFile(true);
|
||||||
|
if (raiiFile.Open(FILE_TO_OPEN,
|
||||||
|
DqnFilePermissionFlag_Write | DqnFilePermissionFlag_Read,
|
||||||
|
DqnFileAction_OpenOnly))
|
||||||
|
{
|
||||||
|
i32 breakHereToTestRaii = 0;
|
||||||
|
(void)breakHereToTestRaii;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test invalid file
|
// Test invalid file
|
||||||
@ -1637,7 +1649,7 @@ void FileTest()
|
|||||||
u8 *buffer = (u8 *)DqnMemStack_Push(&memStack, file->size);
|
u8 *buffer = (u8 *)DqnMemStack_Push(&memStack, file->size);
|
||||||
DQN_ASSERT(buffer);
|
DQN_ASSERT(buffer);
|
||||||
|
|
||||||
size_t bytesRead = DqnFile_Read(files[i], buffer, file->size);
|
size_t bytesRead = DqnFile_Read(&files[i], buffer, file->size);
|
||||||
DQN_ASSERT(bytesRead == file->size);
|
DQN_ASSERT(bytesRead == file->size);
|
||||||
|
|
||||||
// Verify the data is the same as we wrote out
|
// Verify the data is the same as we wrote out
|
||||||
@ -1687,24 +1699,29 @@ void FileTest()
|
|||||||
|
|
||||||
#ifdef DQN_WIN32_IMPLEMENTATION
|
#ifdef DQN_WIN32_IMPLEMENTATION
|
||||||
FILE_SCOPE u32 volatile globalDebugCounter;
|
FILE_SCOPE u32 volatile globalDebugCounter;
|
||||||
FILE_SCOPE bool volatile globalDebugCounterMemoize[2048];
|
|
||||||
FILE_SCOPE DqnLock globalJobQueueLock;
|
FILE_SCOPE DqnLock globalJobQueueLock;
|
||||||
|
const u32 QUEUE_SIZE = 256;
|
||||||
FILE_SCOPE void JobQueueDebugCallbackIncrementCounter(DqnJobQueue *const queue,
|
FILE_SCOPE void JobQueueDebugCallbackIncrementCounter(DqnJobQueue *const queue,
|
||||||
void *const userData)
|
void *const userData)
|
||||||
{
|
{
|
||||||
DqnLock_Acquire(&globalJobQueueLock);
|
DQN_ASSERT(queue->size == QUEUE_SIZE);
|
||||||
DQN_ASSERT(!globalDebugCounterMemoize[globalDebugCounter]);
|
{
|
||||||
globalDebugCounterMemoize[globalDebugCounter] = true;
|
bool succeeded;
|
||||||
|
DqnLockGuard guard = DqnLockGuard(&globalJobQueueLock, &succeeded);
|
||||||
|
DQN_ASSERT(succeeded);
|
||||||
|
|
||||||
globalDebugCounter++;
|
globalDebugCounter++;
|
||||||
u32 number = globalDebugCounter;
|
u32 number = globalDebugCounter;
|
||||||
DqnLock_Release(&globalJobQueueLock);
|
|
||||||
|
|
||||||
printf("JobQueueDebugCallbackIncrementCounter(): Thread %d: Incrementing Number: %d\n",
|
printf("JobQueueDebugCallbackIncrementCounter(): Thread %d: Incrementing Number: %d\n",
|
||||||
GetCurrentThreadId(), number);
|
GetCurrentThreadId(), number);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE_SCOPE void JobQueueTest()
|
FILE_SCOPE void JobQueueTest()
|
||||||
{
|
{
|
||||||
|
globalDebugCounter = 0;
|
||||||
|
|
||||||
DqnMemStack memStack = {};
|
DqnMemStack memStack = {};
|
||||||
DQN_ASSERT_HARD(memStack.Init(DQN_MEGABYTE(1), true));
|
DQN_ASSERT_HARD(memStack.Init(DQN_MEGABYTE(1), true));
|
||||||
|
|
||||||
@ -1713,13 +1730,13 @@ FILE_SCOPE void JobQueueTest()
|
|||||||
DQN_ASSERT(numThreads > 0 && numCores > 0);
|
DQN_ASSERT(numThreads > 0 && numCores > 0);
|
||||||
i32 totalThreads = (numCores - 1) * numThreads;
|
i32 totalThreads = (numCores - 1) * numThreads;
|
||||||
|
|
||||||
const i32 QUEUE_SIZE = 256;
|
|
||||||
DqnJobQueue jobQueue = {};
|
DqnJobQueue jobQueue = {};
|
||||||
DqnJob *jobList = (DqnJob *)memStack.Push(sizeof(*jobQueue.jobList) * QUEUE_SIZE);
|
DqnJob *jobList = (DqnJob *)memStack.Push(sizeof(*jobQueue.jobList) * QUEUE_SIZE);
|
||||||
DQN_ASSERT(DqnJobQueue_Init(&jobQueue, jobList, QUEUE_SIZE, totalThreads));
|
DQN_ASSERT(DqnJobQueue_Init(&jobQueue, jobList, QUEUE_SIZE, totalThreads));
|
||||||
|
|
||||||
|
const u32 WORK_ENTRIES = 2048;
|
||||||
DQN_ASSERT(DqnLock_Init(&globalJobQueueLock));
|
DQN_ASSERT(DqnLock_Init(&globalJobQueueLock));
|
||||||
for (i32 i = 0; i < DQN_ARRAY_COUNT(globalDebugCounterMemoize); i++)
|
for (i32 i = 0; i < WORK_ENTRIES; i++)
|
||||||
{
|
{
|
||||||
DqnJob job = {};
|
DqnJob job = {};
|
||||||
job.callback = JobQueueDebugCallbackIncrementCounter;
|
job.callback = JobQueueDebugCallbackIncrementCounter;
|
||||||
@ -1729,22 +1746,17 @@ FILE_SCOPE void JobQueueTest()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (DqnJobQueue_TryExecuteNextJob(&jobQueue))
|
DqnJobQueue_BlockAndCompleteAllJobs(&jobQueue);
|
||||||
;
|
|
||||||
|
|
||||||
for (i32 i = 0; i < DQN_ARRAY_COUNT(globalDebugCounterMemoize); i++)
|
|
||||||
DQN_ASSERT(globalDebugCounterMemoize[i]);
|
|
||||||
|
|
||||||
while (DqnJobQueue_TryExecuteNextJob(&jobQueue) && !DqnJobQueue_AllJobsComplete(&jobQueue))
|
|
||||||
;
|
|
||||||
|
|
||||||
printf("\nJobQueueTest(): Final incremented value: %d\n", globalDebugCounter);
|
printf("\nJobQueueTest(): Final incremented value: %d\n", globalDebugCounter);
|
||||||
DQN_ASSERT(globalDebugCounter == DQN_ARRAY_COUNT(globalDebugCounterMemoize));
|
DQN_ASSERT(globalDebugCounter == WORK_ENTRIES);
|
||||||
|
DqnLock_Delete(&globalJobQueueLock);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
#if 1
|
||||||
StringsTest();
|
StringsTest();
|
||||||
RandomTest();
|
RandomTest();
|
||||||
MathTest();
|
MathTest();
|
||||||
@ -1752,6 +1764,7 @@ int main(void)
|
|||||||
VecTest();
|
VecTest();
|
||||||
ArrayTest();
|
ArrayTest();
|
||||||
MemStackTest();
|
MemStackTest();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DQN_XPLATFORM_LAYER
|
#ifdef DQN_XPLATFORM_LAYER
|
||||||
FileTest();
|
FileTest();
|
||||||
|
2
makefile
2
makefile
@ -1,3 +1,3 @@
|
|||||||
all: dqn_unit_test.cpp
|
all: dqn_unit_test.cpp
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
gcc -o bin/dqn_unit_test dqn_unit_test.cpp -lm -Wall -Werror
|
g++ -o bin/dqn_unit_test dqn_unit_test.cpp -lm -Wall -Werror
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user