Restore win32 prototypes, add virtual mem allocation and array, add fixed pool

This commit is contained in:
Doyle T 2018-07-10 00:53:54 +10:00
parent 39d75ae5bf
commit 7785e35f91

604
dqn.h
View File

@ -47,6 +47,7 @@
// #DqnHashTable Hash Tables using Templates // #DqnHashTable Hash Tables using Templates
// #XPlatform (Win32 & Unix) // #XPlatform (Win32 & Unix)
// #DqnVArray Array backed by virtual memory
// #DqnFile File I/O (Read, Write, Delete) // #DqnFile File I/O (Read, Write, Delete)
// #DqnTimer High Resolution Timer // #DqnTimer High Resolution Timer
// #DqnLock Mutex Synchronisation // #DqnLock Mutex Synchronisation
@ -74,9 +75,9 @@
// This needs to be above the portable layer so that, if the user requests a platform // This needs to be above the portable layer so that, if the user requests a platform
// implementation, platform specific implementations in the portable layer will get activated. // implementation, platform specific implementations in the portable layer will get activated.
#if (defined(_WIN32) || defined(_WIN64)) #if (defined(_WIN32) || defined(_WIN64))
#define DQN__IS_WIN32 1 #define DQN_IS_WIN32 1
#else #else
#define DQN__IS_UNIX 1 #define DQN_IS_UNIX 1
#endif #endif
#if defined(DQN_PLATFORM_IMPLEMENTATION) #if defined(DQN_PLATFORM_IMPLEMENTATION)
@ -187,6 +188,348 @@ FILE_SCOPE const bool IS_DEBUG = true;
// #External Code // #External Code
// ================================================================================================= // =================================================================================================
#if defined(DQN_PLATFORM_HEADER) && defined(DQN_IS_WIN32) && !defined(_WINDOWS_)
using WORD = unsigned short;
using DWORD = unsigned long;
using BOOL = int;
using LONG = long;
using LONGLONG = long long;
using HANDLE = void *;
using HMODULE = HANDLE;
using HWND = HANDLE;
using UINT = unsigned int;
using ULONG = unsigned long;
using ULONGLONG = unsigned long long;
using DWORD64 = unsigned long long;
using BYTE = unsigned char;
u32 const MB_OK = 0x00000000L;
HANDLE const INVALID_HANDLE_VALUE = ((HANDLE)(LONG *)-1);
u32 const MAX_PATH = 260;
u32 const INFINITE = 0xFFFFFFFF;
u32 const CP_UTF8 = 65001;
u32 const FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
u32 const FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
u32 const MEM_COMMIT = 0x00001000;
u32 const MEM_RESERVE = 0x00002000;
u32 const PAGE_READWRITE = 0x04;
u32 const MEM_DECOMMIT = 0x4000;
u32 const MEM_RELEASE = 0x8000;
struct RECT
{
LONG left;
LONG top;
LONG right;
LONG bottom;
};
union LARGE_INTEGER
{
struct { DWORD LowPart; LONG HighPart; };
struct { DWORD LowPart; LONG HighPart; } u;
LONGLONG QuadPart;
};
union ULARGE_INTEGER
{
struct { DWORD LowPart; DWORD HighPart; };
struct { DWORD LowPart; DWORD HighPart; } u;
ULONGLONG QuadPart;
};
struct SECURITY_ATTRIBUTES
{
DWORD length;
void *securityDescriptor;
BOOL inheritHandle;
};
struct PROCESS_INFORMATION
{
void *hProcess;
void *hThread;
DWORD dwProcessId;
DWORD dwThreadId;
};
struct FILETIME
{
DWORD dwLowDateTime;
DWORD dwHighDateTime;
};
struct WIN32_FILE_ATTRIBUTE_DATA
{
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
};
enum GET_FILEEX_INFO_LEVELS
{
GetFileExInfoStandard,
GetFileExMaxInfoLevel
};
struct WIN32_FIND_DATAW
{
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
wchar_t cFileName[MAX_PATH];
wchar_t cAlternateFileName[14];
};
struct LIST_ENTRY {
struct LIST_ENTRY *Flink;
struct LIST_ENTRY *Blink;
};
struct RTL_CRITICAL_SECTION_DEBUG
{
WORD Type;
WORD CreatorBackTraceIndex;
struct CRITICAL_SECTION *CriticalSection;
LIST_ENTRY ProcessLocksList;
DWORD EntryCount;
DWORD ContentionCount;
DWORD Flags;
WORD CreatorBackTraceIndexHigh;
WORD SpareWORD;
};
struct CRITICAL_SECTION
{
RTL_CRITICAL_SECTION_DEBUG *DebugInfo;
LONG LockCount;
LONG RecursionCount;
HANDLE OwningThread;
HANDLE LockSemaphore;
ULONG *SpinCount;
};
struct OVERLAPPED {
ULONG *Internal;
ULONG *InternalHigh;
union {
struct {
DWORD Offset;
DWORD OffsetHigh;
};
void *Pointer;
};
HANDLE hEvent;
};
struct SYSTEM_INFO {
union
{
DWORD dwOemId;
struct
{
WORD wProcessorArchitecture;
WORD wReserved;
};
};
DWORD dwPageSize;
void *lpMinimumApplicationAddress;
void *lpMaximumApplicationAddress;
DWORD *dwActiveProcessorMask;
DWORD dwNumberOfProcessors;
DWORD dwProcessorType;
DWORD dwAllocationGranularity;
WORD wProcessorLevel;
WORD wProcessorRevision;
};
enum LOGICAL_PROCESSOR_RELATIONSHIP
{
RelationProcessorCore,
RelationNumaNode,
RelationCache,
RelationProcessorPackage,
RelationGroup,
RelationAll = 0xffff
};
typedef unsigned long *KAFFINITY;
struct GROUP_AFFINITY {
KAFFINITY Mask;
WORD Group;
WORD Reserved[3];
};
struct PROCESSOR_RELATIONSHIP
{
BYTE Flags;
BYTE EfficiencyClass;
BYTE Reserved[20];
WORD GroupCount;
GROUP_AFFINITY GroupMask[1];
};
struct NUMA_NODE_RELATIONSHIP {
DWORD NodeNumber;
BYTE Reserved[20];
GROUP_AFFINITY GroupMask;
};
enum PROCESSOR_CACHE_TYPE
{
CacheUnified,
CacheInstruction,
CacheData,
CacheTrace
};
struct CACHE_RELATIONSHIP
{
BYTE Level;
BYTE Associativity;
WORD LineSize;
DWORD CacheSize;
PROCESSOR_CACHE_TYPE Type;
BYTE Reserved[20];
GROUP_AFFINITY GroupMask;
};
struct PROCESSOR_GROUP_INFO
{
BYTE MaximumProcessorCount;
BYTE ActiveProcessorCount;
BYTE Reserved[38];
KAFFINITY ActiveProcessorMask;
};
struct GROUP_RELATIONSHIP
{
WORD MaximumGroupCount;
WORD ActiveGroupCount;
BYTE Reserved[20];
PROCESSOR_GROUP_INFO GroupInfo[1];
};
struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
{
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
DWORD Size;
union
{
PROCESSOR_RELATIONSHIP Processor;
NUMA_NODE_RELATIONSHIP NumaNode;
CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group;
};
};
typedef DWORD (*LPTHREAD_START_ROUTINE)(void *lpThreadParameter);
DWORD64 __rdtsc();
void DeleteCriticalSection (CRITICAL_SECTION *lpCriticalSection);
BOOL DeleteFileA (char const *lpFileName); // TODO(doyle): Wide versions only
BOOL DeleteFileW (wchar_t const *lpFileName);
BOOL CloseHandle (HANDLE hObject);
BOOL CopyFileA (char const *lpExistingFileName, char const *lpNewFileName, BOOL bFailIfExists);
BOOL CopyFileW (wchar_t const *lpExistingFileName, wchar_t const *lpNewFileName, BOOL bFailIfExists);
BOOL CloseHandle (HANDLE *hObject);
HANDLE CreateFileW (wchar_t const *lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
SECURITY_ATTRIBUTES *lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);
HANDLE CreateSemaphoreA (SECURITY_ATTRIBUTES *lpSemaphoreAttributes,
long lInitialCount,
long lMaximumCount,
char const *lpName);
HANDLE CreateThread (SECURITY_ATTRIBUTES *lpThreadAttributes,
size_t dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
void *lpParameter,
DWORD dwCreationFlags,
DWORD *lpThreadId);
void EnterCriticalSection (CRITICAL_SECTION *lpCriticalSection);
BOOL FindClose (HANDLE hFindFile);
HANDLE FindFirstFileW (wchar_t const *lpFileName, WIN32_FIND_DATAW *lpFindFileData);
BOOL FindNextFileW (HANDLE hFindFile, WIN32_FIND_DATAW *lpFindFileData);
DWORD FormatMessageA (DWORD dwFlags,
void const *lpSource,
DWORD dwMessageId,
DWORD dwLanguageId,
char *lpBuffer,
DWORD nSize,
va_list *Arguments);
BOOL GetClientRect (HWND hWnd, RECT *lpRect);
BOOL GetExitCodeProcess (HANDLE *hProcess, DWORD *lpExitCode);
BOOL GetFileSizeEx (HANDLE hFile, LARGE_INTEGER *lpFileSize);
BOOL GetFileAttributesExW (wchar_t const *lpFileName,
GET_FILEEX_INFO_LEVELS fInfoLevelId,
void *lpFileInformation);
DWORD GetLastError (void);
DWORD GetModuleFileNameA (HMODULE hModule, char *lpFilename, DWORD nSize);
void GetNativeSystemInfo (SYSTEM_INFO *lpSystemInfo);
BOOL GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *Buffer,
DWORD *ReturnedLength);
BOOL InitializeCriticalSectionEx (CRITICAL_SECTION *lpCriticalSection,
DWORD dwSpinCount,
DWORD Flags);
long InterlockedAdd (long volatile *Addend, long Value);
long InterlockedCompareExchange (long volatile *Destination, long Exchange, long Comparand);
void LeaveCriticalSection (CRITICAL_SECTION *lpCriticalSection);
int MessageBoxA (HWND hWnd, char const *lpText, char const *lpCaption, UINT uType);
int MultiByteToWideChar (unsigned int CodePage,
DWORD dwFlags,
char const *lpMultiByteStr,
int cbMultiByte,
wchar_t *lpWideCharStr,
int cchWideChar);
void OutputDebugStringA (char const *lpOutputString);
BOOL ReadFile (HANDLE hFile,
void *lpBuffer,
DWORD nNumberOfBytesToRead,
DWORD *lpNumberOfBytesRead,
OVERLAPPED *lpOverlapped);
BOOL ReleaseSemaphore (HANDLE hSemaphore, long lReleaseCount, long *lpPreviousCount);
BOOL QueryPerformanceFrequency (LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter (LARGE_INTEGER *lpPerformanceCount);
DWORD WaitForSingleObject (HANDLE *hHandle, DWORD dwMilliseconds);
DWORD WaitForSingleObjectEx (HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable);
int WideCharToMultiByte (unsigned int CodePage,
DWORD dwFlags,
wchar_t const *lpWideCharStr,
int cchWideChar,
char *lpMultiByteStr,
int cbMultiByte,
char const *lpDefaultChar,
BOOL *lpUsedDefaultChar);
void Sleep (DWORD dwMilliseconds);
BOOL WriteFile (HANDLE hFile,
void *const lpBuffer,
DWORD nNumberOfBytesToWrite,
DWORD *lpNumberOfBytesWritten,
OVERLAPPED *lpOverlapped);
void *VirtualAlloc (void *lpAddress,
size_t dwSize,
DWORD flAllocationType,
DWORD flProtect);
BOOL VirtualFree (void *lpAddress,
size_t dwSize,
DWORD dwFreeType);
#endif // defined(DQN_PLATFORM_HEADER) && defined(DQN_IS_WIN32) && !defined(_WINDOWS_)
#ifndef STB_SPRINTF_H_INCLUDE #ifndef STB_SPRINTF_H_INCLUDE
#define STB_SPRINTF_H_INCLUDE #define STB_SPRINTF_H_INCLUDE
#define STB_SPRINTF_DECORATE(name) Dqn_##name #define STB_SPRINTF_DECORATE(name) Dqn_##name
@ -857,7 +1200,7 @@ public:
// #DqnPool API // #DqnPool API
// ================================================================================================= // =================================================================================================
template <typename T, i16 SIZE> template <typename T, i16 SIZE>
struct DqnPool struct DqnFixedPool
{ {
struct Entry : public T struct Entry : public T
{ {
@ -870,7 +1213,7 @@ struct DqnPool
i16 freeIndex; i16 freeIndex;
i16 numFree; i16 numFree;
DqnPool() : freeIndex(0) , numFree(SIZE) DqnFixedPool() : freeIndex(0) , numFree(SIZE)
{ {
DQN_FOR_EACH(i, SIZE - 1) DQN_FOR_EACH(i, SIZE - 1)
{ {
@ -899,6 +1242,54 @@ struct DqnPool
} }
}; };
// #DqnPool API
// =================================================================================================
template <typename T>
struct DqnPool
{
struct Entry : public T
{
u16 nextIndex;
};
Entry *pool;
i16 freeIndex;
i16 numFree;
i32 size;
void UseMemory(Entry *pool_, isize size)
{
pool = pool_;
freeIndex = 0;
numFree = size;
DQN_FOR_EACH(i, size - 1)
{
Entry *entry = pool + i;
entry->nextIndex = i + 1;
}
Entry *last = pool + (size - 1);
last->nextIndex = size;
}
T *GetNext()
{
if (freeIndex == size) return nullptr;
Entry *result = pool + freeIndex;
freeIndex = result->nextIndex;
numFree--;
return result;
}
void Return(T *item)
{
auto *entry = reinterpret_cast<Entry *>(item);
entry->nextIndex = freeIndex;
freeIndex = entry - pool;
numFree++;
}
};
FILE_SCOPE DqnMemAPI DQN_DEFAULT_HEAP_ALLOCATOR_ = DqnMemAPI::HeapAllocator(); FILE_SCOPE DqnMemAPI DQN_DEFAULT_HEAP_ALLOCATOR_ = DqnMemAPI::HeapAllocator();
FILE_SCOPE DqnMemAPI *DQN_DEFAULT_HEAP_ALLOCATOR = &DQN_DEFAULT_HEAP_ALLOCATOR_; FILE_SCOPE DqnMemAPI *DQN_DEFAULT_HEAP_ALLOCATOR = &DQN_DEFAULT_HEAP_ALLOCATOR_;
@ -924,6 +1315,7 @@ struct DqnArray
void Resize (isize newCount) { if (newCount > max) Reserve(GrowCapacity_(newCount)); count = newCount; } void Resize (isize newCount) { if (newCount > max) Reserve(GrowCapacity_(newCount)); count = newCount; }
void Resize (isize newCount, T const *v) { if (newCount > max) Reserve(GrowCapacity_(newCount)); if (newCount > count) for (isize n = count; n < newCount; n++) data[n] = *v; count = newCount; } void Resize (isize newCount, T const *v) { if (newCount > max) Reserve(GrowCapacity_(newCount)); if (newCount > count) for (isize n = count; n < newCount; n++) data[n] = *v; count = newCount; }
void Reserve (isize newMax); void Reserve (isize newMax);
T *Make (isize num = 1) { count += num; if (count > max) Reserve(GrowCapacity_(count)); return &data[count - num]; }
T *Push (T const &v) { return Insert(count, &v, 1); } T *Push (T const &v) { return Insert(count, &v, 1); }
T *Push (T const *v, isize numItems = 1) { return Insert(count, v, numItems); } T *Push (T const *v, isize numItems = 1) { return Insert(count, v, numItems); }
void Pop () { if (count > 0) count--; } void Pop () { if (count > 0) count--; }
@ -2462,11 +2854,78 @@ DQN_FILE_SCOPE DqnJson DqnJson_GetNextArrayItem(DqnJson *iterator);
#ifndef DQN_PLATFORM_H #ifndef DQN_PLATFORM_H
#define DQN_PLATFORM_H #define DQN_PLATFORM_H
#if defined(DQN__IS_UNIX) #if defined(DQN_IS_UNIX)
#include <pthread.h> #include <pthread.h>
#include <semaphore.h> #include <semaphore.h>
#endif #endif
// XPlatform > #DqnOS API
// =================================================================================================
DQN_FILE_SCOPE void *DqnOS_VAlloc(isize size, void *baseAddress = nullptr);
DQN_FILE_SCOPE void DqnOS_VFree (void *address, isize size);
// Uses a single call to DqnMem_Calloc() and DqnMem_Free(). Not completely platform "independent" for Unix.
// numCores: numThreadsPerCore: Can be nullptr, the function will just skip it.
DQN_FILE_SCOPE void DqnOS_GetThreadsAndCores(u32 *const numCores, u32 *const numThreadsPerCore);
// #XPlatform > #DqnVArray Array backed by virtual memory
// =================================================================================================
template<typename T>
struct DqnVArray
{
isize count; // Read
isize max; // Read
T *data; // Read
DqnVArray () { count = 0; max = DQN_MEGABYTE(1) / sizeof(T); data = (T *)DqnOS_VAlloc(max * sizeof(T)); DQN_ASSERT(data); }
~DqnVArray () { if (data) DqnOS_VFree(data, sizeof(T) * max); }
void Clear (Dqn::ZeroClear clear = Dqn::ZeroClear::Yes) { if (data) { count = 0; if (clear == Dqn::ZeroClear::Yes) DqnMem_Clear(data, 0, sizeof(T) * max); } }
void Free () { if (data) { DqnOS_VFree(data, sizeof(T) * max); } *this = {}; }
T *Front () { DQN_ASSERT(count > 0); return data + 0; }
T *Back () { DQN_ASSERT(count > 0); return data + (count - 1); }
T *Make (isize num = 1) { count += num; DQN_ASSERT(count < max); return &data[count - num]; }
T *Push (T const &v) { return Insert(count, &v, 1); }
T *Push (T const *v, isize numItems = 1) { return Insert(count, v, numItems); }
void Pop () { if (count > 0) count--; }
void Erase (isize index) { DQN_ASSERT(index >= 0 && index < count); data[index] = data[--count]; }
void EraseStable(isize index);
T *Insert (isize index, T const *v) { return Insert(index, v, 1); }
T *Insert (isize index, T const &v) { return Insert(index, &v, 1); }
T *Insert (isize index, T const *v, isize numItems);
bool Contains (T const *v) const { T const *ptr = data; T const *end = data + count; while (ptr < end) if (*ptr++ == *v) return true; return false; }
T &operator[] (isize i) const { DQN_ASSERT(i < count && i > 0); return this->data[i]; }
T *begin () { return data; }
T *end () { return data + count; }
};
template<typename T> T *DqnVArray<T>::Insert(isize index, T const *v, isize numItems)
{
index = DQN_MIN(DQN_MAX(index, 0), count);
isize const newCount = count + numItems;
DQN_ASSERT(newCount < max);
T *src = data + index;
T *dest = src + numItems;
if (src < dest)
memmove(dest, src, ((data + count) - src) * sizeof(T));
count = newCount;
for (isize i = 0; i < numItems; i++)
src[i] = v[i];
return src;
}
template <typename T> void DqnVArray<T>::EraseStable(isize index)
{
DQN_ASSERT(index >= 0 && index < count);
isize const off = (data + index) - data;
memmove(data + off, data + off + 1, ((usize)count - (usize)off - 1) * sizeof(T));
count--;
}
// XPlatform > #DqnFile API // XPlatform > #DqnFile API
// ================================================================================================= // =================================================================================================
struct DqnFile struct DqnFile
@ -2573,7 +3032,7 @@ DQN_FILE_SCOPE f64 DqnTimer_NowInS ();
// ================================================================================================= // =================================================================================================
typedef struct DqnLock typedef struct DqnLock
{ {
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
CRITICAL_SECTION win32Handle; CRITICAL_SECTION win32Handle;
#else #else
pthread_mutex_t unixHandle; pthread_mutex_t unixHandle;
@ -2647,7 +3106,7 @@ struct DqnJobQueue
i32 volatile jobToExecuteIndex; i32 volatile jobToExecuteIndex;
i32 volatile numJobsToComplete; i32 volatile numJobsToComplete;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
void *semaphore; void *semaphore;
#else #else
sem_t semaphore; sem_t semaphore;
@ -2705,18 +3164,12 @@ DQN_FILE_SCOPE i32 DqnAtomic_CompareSwap32(i32 volatile *const dest, const i32 s
// return: The new value at src // return: The new value at src
DQN_FILE_SCOPE i32 DqnAtomic_Add32(i32 volatile *const src, const i32 value); DQN_FILE_SCOPE i32 DqnAtomic_Add32(i32 volatile *const src, const i32 value);
// XPlatform > #DqnOS API
// =================================================================================================
// Uses a single call to DqnMem_Calloc() and DqnMem_Free(). Not completely platform "independent" for Unix.
// numCores: numThreadsPerCore: Can be nullptr, the function will just skip it.
DQN_FILE_SCOPE void DqnOS_GetThreadsAndCores(u32 *const numCores, u32 *const numThreadsPerCore);
// #Platform Specific API // #Platform Specific API
// ================================================================================================= // =================================================================================================
// Functions here are only available for the #defined sections (i.e. all functions in // Functions here are only available for the #defined sections (i.e. all functions in
// DQN__IS_WIN32 only have a valid implementation in Win32. // DQN_IS_WIN32 only have a valid implementation in Win32.
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
// Platform > #DqnWin32 API // Platform > #DqnWin32 API
// ================================================================================================= // =================================================================================================
#define DQN__WIN32_ERROR_BOX(text, title) MessageBoxA(nullptr, text, title, MB_OK); #define DQN__WIN32_ERROR_BOX(text, title) MessageBoxA(nullptr, text, title, MB_OK);
@ -2750,7 +3203,7 @@ DQN_FILE_SCOPE void DqnWin32_OutputDebugString(const char *const formatStr, ...)
// return: The offset to the last backslash. -1 if bufLen was not large enough or buf is null. (i.e. // return: The offset to the last backslash. -1 if bufLen was not large enough or buf is null. (i.e.
// buf + offsetToLastSlash + 1, gives C:/Path/) // buf + offsetToLastSlash + 1, gives C:/Path/)
DQN_FILE_SCOPE i32 DqnWin32_GetEXEDirectory(char *const buf, const u32 bufLen); DQN_FILE_SCOPE i32 DqnWin32_GetEXEDirectory(char *const buf, const u32 bufLen);
#endif // DQN__IS_WIN32 #endif // DQN_IS_WIN32
#endif // DQN_PLATFORM_H #endif // DQN_PLATFORM_H
#endif // DQN_PLATFORM_HEADER #endif // DQN_PLATFORM_HEADER
@ -2802,7 +3255,7 @@ DQN_FILE_SCOPE void DqnLog(char const *file, char const *functionName, i32 lineN
char const *const formatStr = "%s:%s,%d: DqnLog: %s\n"; char const *const formatStr = "%s:%s,%d: DqnLog: %s\n";
fprintf(stderr, formatStr, file, functionName, lineNum, userMsg); fprintf(stderr, formatStr, file, functionName, lineNum, userMsg);
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
DqnWin32_OutputDebugString(formatStr, file, functionName, lineNum, userMsg); DqnWin32_OutputDebugString(formatStr, file, functionName, lineNum, userMsg);
#endif #endif
} }
@ -2837,7 +3290,7 @@ DQN_FILE_SCOPE void DqnLogExpr(char const *file, char const *functionName, i32 l
char const *const formatStr = ":%s:%s,%d(%s): DqnLog: %s\n"; char const *const formatStr = ":%s:%s,%d(%s): DqnLog: %s\n";
fprintf(stderr, formatStr, file, functionName, lineNum, expr, userMsg); fprintf(stderr, formatStr, file, functionName, lineNum, expr, userMsg);
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
DqnWin32_OutputDebugString(formatStr, file, functionName, lineNum, expr, userMsg); DqnWin32_OutputDebugString(formatStr, file, functionName, lineNum, expr, userMsg);
#endif #endif
} }
@ -5733,13 +6186,13 @@ FILE_SCOPE u64 DqnRnd__Murmur3Avalanche64(u64 h)
return h; return h;
} }
#if defined(DQN__IS_UNIX) #if defined(DQN_IS_UNIX)
#include <x86intrin.h> // __rdtsc #include <x86intrin.h> // __rdtsc
#endif #endif
FILE_SCOPE u32 DqnRnd__MakeSeed() FILE_SCOPE u32 DqnRnd__MakeSeed()
{ {
#if defined(DQN_PLATFORM_IMPLEMENTATION) && (defined(DQN__IS_WIN32) || defined(DQN__IS_UNIX)) #if defined(DQN_PLATFORM_IMPLEMENTATION) && (defined(DQN_IS_WIN32) || defined(DQN_IS_UNIX))
i64 numClockCycles = __rdtsc(); i64 numClockCycles = __rdtsc();
return (u32)numClockCycles; return (u32)numClockCycles;
#else #else
@ -5946,7 +6399,7 @@ bool DqnString::InitLiteral(wchar_t const *cstr, DqnMemStack *stack)
bool DqnString::InitLiteral(wchar_t const *cstr, DqnMemAPI *api) bool DqnString::InitLiteral(wchar_t const *cstr, DqnMemAPI *api)
{ {
#if defined(DQN__IS_WIN32) && defined(DQN_PLATFORM_IMPLEMENTATION) #if defined(DQN_IS_WIN32) && defined(DQN_PLATFORM_IMPLEMENTATION)
i32 reqLenInclNullTerminator = DqnWin32_WCharToUTF8(cstr, nullptr, 0); i32 reqLenInclNullTerminator = DqnWin32_WCharToUTF8(cstr, nullptr, 0);
if (!this->InitSize(reqLenInclNullTerminator - 1, api)) if (!this->InitSize(reqLenInclNullTerminator - 1, api))
{ {
@ -6175,7 +6628,7 @@ void DqnString::Free()
i32 DqnString::ToWChar(wchar_t *buf, i32 bufSize) const i32 DqnString::ToWChar(wchar_t *buf, i32 bufSize) const
{ {
#if defined(DQN__IS_WIN32) && defined(DQN_PLATFORM_IMPLEMENTATION) #if defined(DQN_IS_WIN32) && defined(DQN_PLATFORM_IMPLEMENTATION)
i32 result = DqnWin32_UTF8ToWChar(this->str, buf, bufSize); i32 result = DqnWin32_UTF8ToWChar(this->str, buf, bufSize);
return result; return result;
@ -6191,7 +6644,7 @@ wchar_t *DqnString::ToWChar(DqnMemAPI *api) const
// TODO(doyle): Should the "in" string allow specifyign len? probably // TODO(doyle): Should the "in" string allow specifyign len? probably
// Otherwise a c-string and a literal initiated string might have different lengths // Otherwise a c-string and a literal initiated string might have different lengths
// to wchar will produce an unintuitive output // to wchar will produce an unintuitive output
#if defined(DQN__IS_WIN32) && defined(DQN_PLATFORM_IMPLEMENTATION) #if defined(DQN_IS_WIN32) && defined(DQN_PLATFORM_IMPLEMENTATION)
i32 requiredLenInclNull = DqnWin32_UTF8ToWChar(this->str, nullptr, 0); i32 requiredLenInclNull = DqnWin32_UTF8ToWChar(this->str, nullptr, 0);
i32 allocSize = sizeof(wchar_t) * requiredLenInclNull; i32 allocSize = sizeof(wchar_t) * requiredLenInclNull;
@ -8133,7 +8586,7 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c
// Functions in the Cross Platform are guaranteed to be supported in both Unix // Functions in the Cross Platform are guaranteed to be supported in both Unix
// and Win32 // and Win32
#ifdef DQN__IS_UNIX #ifdef DQN_IS_UNIX
#include <stdio.h> // Basic File I/O // TODO(doyle): Syscall versions #include <stdio.h> // Basic File I/O // TODO(doyle): Syscall versions
#include <dirent.h> // readdir()/opendir()/closedir() #include <dirent.h> // readdir()/opendir()/closedir()
@ -8147,7 +8600,7 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c
// XPlatform > #DqnFile // XPlatform > #DqnFile
// ================================================================================================= // =================================================================================================
#ifdef DQN__IS_WIN32 #ifdef DQN_IS_WIN32
FILE_SCOPE bool FILE_SCOPE bool
DqnFile__Win32Open(wchar_t const *path, DqnFile *file, u32 flags, DqnFile::Action action) DqnFile__Win32Open(wchar_t const *path, DqnFile *file, u32 flags, DqnFile::Action action)
@ -8307,9 +8760,9 @@ DQN_FILE__LIST_DIR(DqnFile__PlatformListDir)
return list; return list;
} }
} }
#endif // DQN__IS_WIN32 #endif // DQN_IS_WIN32
#ifdef DQN__IS_UNIX #ifdef DQN_IS_UNIX
FILE_SCOPE bool DqnFile__UnixGetFileSize(char const *path, usize *size) FILE_SCOPE bool DqnFile__UnixGetFileSize(char const *path, usize *size)
{ {
struct stat fileStat = {}; struct stat fileStat = {};
@ -8464,13 +8917,13 @@ DQN_FILE__LIST_DIR(DqnFile__PlatformListDir)
return list; return list;
} }
} }
#endif // DQN__IS_UNIX #endif // DQN_IS_UNIX
bool DqnFile::Open(char const *path, u32 flags_, Action action) bool DqnFile::Open(char const *path, u32 flags_, Action action)
{ {
if (!path) return false; if (!path) return false;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
// TODO(doyle): MAX PATH is baad // TODO(doyle): MAX PATH is baad
wchar_t widePath[MAX_PATH] = {}; wchar_t widePath[MAX_PATH] = {};
DqnWin32_UTF8ToWChar(path, widePath, DQN_ARRAY_COUNT(widePath)); DqnWin32_UTF8ToWChar(path, widePath, DQN_ARRAY_COUNT(widePath));
@ -8484,7 +8937,7 @@ bool DqnFile::Open(wchar_t const *path, u32 flags_, Action action)
{ {
if (!path) return false; if (!path) return false;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
return DqnFile__Win32Open(path, this, flags_, action); return DqnFile__Win32Open(path, this, flags_, action);
#else #else
@ -8499,7 +8952,7 @@ usize DqnFile::Write(u8 const *buf, usize numBytesToWrite, usize fileOffset)
DQN_ASSERTM(fileOffset == 0, "File writing into offset is not implemented."); DQN_ASSERTM(fileOffset == 0, "File writing into offset is not implemented.");
usize numBytesWritten = 0; usize numBytesWritten = 0;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
DWORD bytesToWrite = (DWORD)numBytesToWrite; DWORD bytesToWrite = (DWORD)numBytesToWrite;
DWORD bytesWritten; DWORD bytesWritten;
BOOL result = WriteFile(this->handle, (void *)buf, bytesToWrite, &bytesWritten, nullptr); BOOL result = WriteFile(this->handle, (void *)buf, bytesToWrite, &bytesWritten, nullptr);
@ -8528,7 +8981,7 @@ usize DqnFile::Read(u8 *buf, usize numBytesToRead)
usize numBytesRead = 0; usize numBytesRead = 0;
if (this->handle) if (this->handle)
{ {
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
DWORD bytesToRead = (DWORD)numBytesToRead; DWORD bytesToRead = (DWORD)numBytesToRead;
DWORD bytesRead = 0; DWORD bytesRead = 0;
HANDLE win32Handle = this->handle; HANDLE win32Handle = this->handle;
@ -8666,7 +9119,7 @@ void DqnFile::Close()
{ {
if (this->handle) if (this->handle)
{ {
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
CloseHandle(this->handle); CloseHandle(this->handle);
#else #else
fclose((FILE *)this->handle); fclose((FILE *)this->handle);
@ -8678,7 +9131,7 @@ void DqnFile::Close()
this->flags = 0; this->flags = 0;
} }
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
DQN_COMPILE_ASSERT(sizeof(DWORD) == sizeof(u32)); DQN_COMPILE_ASSERT(sizeof(DWORD) == sizeof(u32));
#endif #endif
bool DqnFile::GetFileSize(wchar_t const *path, usize *size) bool DqnFile::GetFileSize(wchar_t const *path, usize *size)
@ -8700,7 +9153,7 @@ bool DqnFile::GetFileSize(char const *path, usize *size)
if (!path || !size) return false; if (!path || !size) return false;
// TODO(doyle): Logging // TODO(doyle): Logging
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
// TODO(doyle): MAX PATH is baad // TODO(doyle): MAX PATH is baad
wchar_t widePath[MAX_PATH] = {0}; wchar_t widePath[MAX_PATH] = {0};
DqnWin32_UTF8ToWChar(path, widePath, DQN_ARRAY_COUNT(widePath)); DqnWin32_UTF8ToWChar(path, widePath, DQN_ARRAY_COUNT(widePath));
@ -8717,7 +9170,7 @@ bool DqnFile::GetInfo(wchar_t const *path, Info *info)
{ {
if (!path || !info) return false; if (!path || !info) return false;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
auto FileTimeToSeconds = [](FILETIME const *time) -> i64 { auto FileTimeToSeconds = [](FILETIME const *time) -> i64 {
ULARGE_INTEGER timeLargeInt = {}; ULARGE_INTEGER timeLargeInt = {};
timeLargeInt.LowPart = time->dwLowDateTime; timeLargeInt.LowPart = time->dwLowDateTime;
@ -8760,7 +9213,7 @@ bool DqnFile::GetInfo(char const *path, Info *info)
return false; return false;
} }
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
// TODO(doyle): MAX PATH is baad // TODO(doyle): MAX PATH is baad
wchar_t widePath[MAX_PATH] = {}; wchar_t widePath[MAX_PATH] = {};
DqnWin32_UTF8ToWChar(path, widePath, DQN_ARRAY_COUNT(widePath)); DqnWin32_UTF8ToWChar(path, widePath, DQN_ARRAY_COUNT(widePath));
@ -8788,7 +9241,7 @@ bool DqnFile::Delete(char const *path)
if (!path) return false; if (!path) return false;
// TODO(doyle): Logging // TODO(doyle): Logging
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
return DeleteFileA(path); return DeleteFileA(path);
#else #else
@ -8805,7 +9258,7 @@ bool DqnFile::Delete(wchar_t const *path)
if (!path) return false; if (!path) return false;
// TODO(doyle): Logging // TODO(doyle): Logging
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
return DeleteFileW(path); return DeleteFileW(path);
#else #else
@ -8820,7 +9273,7 @@ bool DqnFile::Copy(char const *src, char const *dest)
if (!src || !dest) return false; if (!src || !dest) return false;
// TODO(doyle): Logging // TODO(doyle): Logging
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
BOOL result = (CopyFileA(src, dest, /*FailIfExist*/false) != 0); BOOL result = (CopyFileA(src, dest, /*FailIfExist*/false) != 0);
if (result == 0) if (result == 0)
{ {
@ -8840,7 +9293,7 @@ bool DqnFile::Copy(wchar_t const *src, wchar_t const *dest)
if (!src || !dest) return false; if (!src || !dest) return false;
// TODO(doyle): Logging // TODO(doyle): Logging
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
return (CopyFileW(src, dest, /*FailIfExist*/false) != 0); return (CopyFileW(src, dest, /*FailIfExist*/false) != 0);
#else #else
@ -8872,7 +9325,7 @@ void DqnFile::ListDirFree(char **fileList, i32 numFiles, DqnMemAPI *api)
// XPlatform > #DqnTimer // XPlatform > #DqnTimer
// ================================================================================================= // =================================================================================================
#if defined (DQN__IS_WIN32) #if defined (DQN_IS_WIN32)
FILE_SCOPE f64 DqnTimerInternal_Win32QueryPerfCounterTimeInMs() FILE_SCOPE f64 DqnTimerInternal_Win32QueryPerfCounterTimeInMs()
{ {
LOCAL_PERSIST LARGE_INTEGER queryPerformanceFrequency = {0}; LOCAL_PERSIST LARGE_INTEGER queryPerformanceFrequency = {0};
@ -8896,7 +9349,7 @@ FILE_SCOPE f64 DqnTimerInternal_Win32QueryPerfCounterTimeInMs()
DQN_FILE_SCOPE f64 DqnTimer_NowInMs() DQN_FILE_SCOPE f64 DqnTimer_NowInMs()
{ {
f64 result = 0; f64 result = 0;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
result = DQN_MAX(DqnTimerInternal_Win32QueryPerfCounterTimeInMs(), 0); result = DQN_MAX(DqnTimerInternal_Win32QueryPerfCounterTimeInMs(), 0);
#else #else
@ -8923,7 +9376,7 @@ bool DqnLock_Init(DqnLock *lock)
{ {
if (!lock) return false; if (!lock) return false;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
if (InitializeCriticalSectionEx(&lock->win32Handle, lock->win32SpinCount, 0)) if (InitializeCriticalSectionEx(&lock->win32Handle, lock->win32SpinCount, 0))
return true; return true;
#else #else
@ -8941,7 +9394,7 @@ void DqnLock_Acquire(DqnLock *lock)
{ {
if (!lock) return; if (!lock) return;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
EnterCriticalSection(&lock->win32Handle); EnterCriticalSection(&lock->win32Handle);
#else #else
@ -8955,7 +9408,7 @@ void DqnLock_Release(DqnLock *lock)
{ {
if (!lock) return; if (!lock) return;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
LeaveCriticalSection(&lock->win32Handle); LeaveCriticalSection(&lock->win32Handle);
#else #else
@ -8969,7 +9422,7 @@ void DqnLock_Delete(DqnLock *lock)
{ {
if (!lock) return; if (!lock) return;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
DeleteCriticalSection(&lock->win32Handle); DeleteCriticalSection(&lock->win32Handle);
#else #else
i32 error = pthread_mutex_destroy(&lock->unixHandle); i32 error = pthread_mutex_destroy(&lock->unixHandle);
@ -9017,7 +9470,7 @@ FILE_SCOPE u32 DqnJobQueueInternal_ThreadCreate(usize stackSize,
{ {
u32 numThreadsCreated = 0; u32 numThreadsCreated = 0;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
DQN_ASSERT(stackSize == 0 || !threadCallback); DQN_ASSERT(stackSize == 0 || !threadCallback);
for (u32 i = 0; i < numThreads; i++) for (u32 i = 0; i < numThreads; i++)
{ {
@ -9058,7 +9511,7 @@ FILE_SCOPE void *DqnJobQueueInternal_ThreadCallback(void *threadParam)
{ {
if (!DqnJobQueue_TryExecuteNextJob(queue)) if (!DqnJobQueue_TryExecuteNextJob(queue))
{ {
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
WaitForSingleObjectEx(queue->semaphore, INFINITE, false); WaitForSingleObjectEx(queue->semaphore, INFINITE, false);
#else #else
sem_wait(&queue->semaphore); sem_wait(&queue->semaphore);
@ -9071,7 +9524,7 @@ FILE_SCOPE bool DqnJobQueueInternal_CreateSemaphore(DqnJobQueue *queue, u32 init
{ {
if (!queue) return false; if (!queue) return false;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
queue->semaphore = (void *)CreateSemaphoreA(nullptr, initSignalCount, maxSignalCount, nullptr); queue->semaphore = (void *)CreateSemaphoreA(nullptr, initSignalCount, maxSignalCount, nullptr);
DQN_ASSERT(queue->semaphore); DQN_ASSERT(queue->semaphore);
@ -9093,7 +9546,7 @@ FILE_SCOPE bool DqnJobQueueInternal_ReleaseSemaphore(DqnJobQueue *queue)
{ {
DQN_ASSERT(queue); DQN_ASSERT(queue);
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
DQN_ASSERT(queue->semaphore); DQN_ASSERT(queue->semaphore);
ReleaseSemaphore(queue->semaphore, 1, nullptr); ReleaseSemaphore(queue->semaphore, 1, nullptr);
@ -9192,14 +9645,14 @@ bool DqnJobQueue::AllJobsComplete () { return DqnJobQueue_AllJo
// XPlatform > #DqnAtomic // XPlatform > #DqnAtomic
// ================================================================================================= // =================================================================================================
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
DQN_COMPILE_ASSERT(sizeof(LONG) == sizeof(i32)); DQN_COMPILE_ASSERT(sizeof(LONG) == sizeof(i32));
#endif #endif
DQN_FILE_SCOPE i32 DqnAtomic_CompareSwap32(i32 volatile *dest, i32 swapVal, i32 compareVal) DQN_FILE_SCOPE i32 DqnAtomic_CompareSwap32(i32 volatile *dest, i32 swapVal, i32 compareVal)
{ {
i32 result = 0; i32 result = 0;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
result = (i32)InterlockedCompareExchange((LONG volatile *)dest, (LONG)swapVal, (LONG)compareVal); result = (i32)InterlockedCompareExchange((LONG volatile *)dest, (LONG)swapVal, (LONG)compareVal);
#else #else
@ -9211,7 +9664,7 @@ DQN_FILE_SCOPE i32 DqnAtomic_CompareSwap32(i32 volatile *dest, i32 swapVal, i32
DQN_FILE_SCOPE i32 DqnAtomic_Add32(i32 volatile *src, i32 value) DQN_FILE_SCOPE i32 DqnAtomic_Add32(i32 volatile *src, i32 value)
{ {
i32 result = 0; i32 result = 0;
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
result = (i32)InterlockedAdd((LONG volatile *)src, value); result = (i32)InterlockedAdd((LONG volatile *)src, value);
#else #else
@ -9223,10 +9676,41 @@ DQN_FILE_SCOPE i32 DqnAtomic_Add32(i32 volatile *src, i32 value)
// XPlatform > #DqnOS // XPlatform > #DqnOS
// ================================================================================================= // =================================================================================================
#if defined(DQN_IS_UNIX)
include <sys/mman.h>
#endif
void *DqnOS_VAlloc(isize size, void *baseAddress)
{
void *result = nullptr;
#if defined (DQN_IS_WIN32)
result = VirtualAlloc(baseAddress, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
DQN_ASSERT(result);
#else
result = mmap(
baseAddress, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1 /*fd*/, 0 /*offset into fd*/);
DQN_ASSERT(result != MAP_FAILED);
#endif
return result;
}
void DqnOS_VFree(void *address, isize size)
{
#if defined (DQN_IS_WIN32)
BOOL result = VirtualFree(address, 0 /*size*/, MEM_RELEASE);
(void)size;
DQN_ASSERT(result);
#else
int result = munmap(address, size);
DQN_ASSERT(result != 0);
#endif
}
#define DQN_OS_GET_THREADS_AND_CORES(name) \ #define DQN_OS_GET_THREADS_AND_CORES(name) \
DQN_FILE_SCOPE void name(u32 *const numCores, u32 *const numThreadsPerCore) DQN_FILE_SCOPE void name(u32 *const numCores, u32 *const numThreadsPerCore)
#if defined(DQN__IS_UNIX) #if defined(DQN_IS_UNIX)
DQN_OS_GET_THREADS_AND_CORES(DqnOS_GetThreadsAndCores) DQN_OS_GET_THREADS_AND_CORES(DqnOS_GetThreadsAndCores)
{ {
if (!numThreadsPerCore && !numCores) return; if (!numThreadsPerCore && !numCores) return;
@ -9289,9 +9773,9 @@ DQN_OS_GET_THREADS_AND_CORES(DqnOS_GetThreadsAndCores)
DQN_ASSERT(DQN_INVALID_CODE_PATH); DQN_ASSERT(DQN_INVALID_CODE_PATH);
} }
} }
#endif // DQN__IS_UNIX #endif // DQN_IS_UNIX
#if defined(DQN__IS_WIN32) #if defined(DQN_IS_WIN32)
DQN_OS_GET_THREADS_AND_CORES(DqnOS_GetThreadsAndCores) DQN_OS_GET_THREADS_AND_CORES(DqnOS_GetThreadsAndCores)
{ {
if (numThreadsPerCore) if (numThreadsPerCore)
@ -9348,9 +9832,9 @@ DQN_OS_GET_THREADS_AND_CORES(DqnOS_GetThreadsAndCores)
DqnMem_Free(rawProcInfoArray); DqnMem_Free(rawProcInfoArray);
} }
} }
#endif // DQN__IS_WIN32 #endif // DQN_IS_WIN32
#ifdef DQN__IS_WIN32 #ifdef DQN_IS_WIN32
// #DqnWin32 // #DqnWin32
// ================================================================================================= // =================================================================================================
DQN_FILE_SCOPE i32 DqnWin32_UTF8ToWChar(char const *in, wchar_t *out, i32 outLen) DQN_FILE_SCOPE i32 DqnWin32_UTF8ToWChar(char const *in, wchar_t *out, i32 outLen)
@ -9460,5 +9944,5 @@ DQN_FILE_SCOPE i32 DqnWin32_GetEXEDirectory(char *buf, u32 bufLen)
return lastSlashIndex; return lastSlashIndex;
} }
#endif // DQN__IS_WIN32 #endif // DQN_IS_WIN32
#endif // DQN__XPLATFORM_LAYER #endif // DQN__XPLATFORM_LAYER