Move source code into Source folder and add a single header generator"
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
#define DN_ASYNC_CPP
|
||||
|
||||
#include "../dn_base_inc.h"
|
||||
#include "../dn_os_inc.h"
|
||||
#include "dn_async.h"
|
||||
|
||||
static DN_I32 DN_ASYNC_ThreadEntryPoint_(DN_OSThread *thread)
|
||||
{
|
||||
DN_OS_ThreadSetName(DN_FStr8_ToStr8(&thread->name));
|
||||
DN_ASYNCCore *async = DN_CAST(DN_ASYNCCore *) thread->user_context;
|
||||
DN_Ring *ring = &async->ring;
|
||||
for (;;) {
|
||||
DN_OS_SemaphoreWait(&async->worker_sem, UINT32_MAX);
|
||||
if (async->join_threads)
|
||||
break;
|
||||
|
||||
DN_ASYNCJob job = {};
|
||||
for (DN_OS_MutexScope(&async->ring_mutex)) {
|
||||
if (DN_Ring_HasData(ring, sizeof(job))) {
|
||||
DN_Ring_Read(ring, &job, sizeof(job));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (job.work.func) {
|
||||
DN_OS_ConditionVariableBroadcast(&async->ring_write_cv); // Resume any blocked ring write(s)
|
||||
|
||||
DN_Atomic_AddU32(&async->busy_threads, 1);
|
||||
job.work.func(job.work.input);
|
||||
DN_Atomic_SubU32(&async->busy_threads, 1);
|
||||
|
||||
if (job.completion_sem.handle != 0)
|
||||
DN_OS_SemaphoreIncrement(&job.completion_sem, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DN_API void DN_ASYNC_Init(DN_ASYNCCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size)
|
||||
{
|
||||
DN_Assert(async);
|
||||
async->ring.size = base_size;
|
||||
async->ring.base = base;
|
||||
async->ring_mutex = DN_OS_MutexInit();
|
||||
async->ring_write_cv = DN_OS_ConditionVariableInit();
|
||||
async->worker_sem = DN_OS_SemaphoreInit(0);
|
||||
async->thread_count = threads_size;
|
||||
async->threads = threads;
|
||||
for (DN_ForIndexU(index, async->thread_count)) {
|
||||
DN_OSThread *thread = async->threads + index;
|
||||
thread->name = DN_FStr8_InitF<64>("ASYNC W%zu", index);
|
||||
DN_OS_ThreadInit(thread, DN_ASYNC_ThreadEntryPoint_, async);
|
||||
}
|
||||
}
|
||||
|
||||
DN_API void DN_ASYNC_Deinit(DN_ASYNCCore *async)
|
||||
{
|
||||
DN_Assert(async);
|
||||
DN_Atomic_SetValue32(&async->join_threads, true);
|
||||
DN_OS_SemaphoreIncrement(&async->worker_sem, async->thread_count);
|
||||
for (DN_ForItSize(it, DN_OSThread, async->threads, async->thread_count))
|
||||
DN_OS_ThreadDeinit(it.data);
|
||||
}
|
||||
|
||||
|
||||
static bool DN_ASYNC_QueueJob_(DN_ASYNCCore *async, DN_ASYNCJob const *job, DN_U64 wait_time_ms) {
|
||||
DN_U64 end_time_ms = DN_OS_DateUnixTimeMs() + wait_time_ms;
|
||||
bool result = false;
|
||||
for (DN_OS_MutexScope(&async->ring_mutex)) {
|
||||
for (;;) {
|
||||
if (DN_Ring_HasSpace(&async->ring, sizeof(*job))) {
|
||||
DN_Ring_WriteStruct(&async->ring, job);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
DN_OS_ConditionVariableWaitUntil(&async->ring_write_cv, &async->ring_mutex, end_time_ms);
|
||||
if (DN_OS_DateUnixTimeMs() >= end_time_ms)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
DN_OS_SemaphoreIncrement(&async->worker_sem, 1); // Flag that a job is available
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API bool DN_ASYNC_QueueWork(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms)
|
||||
{
|
||||
DN_ASYNCJob job = {};
|
||||
job.work.func = func;
|
||||
job.work.input = input;
|
||||
bool result = DN_ASYNC_QueueJob_(async, &job, wait_time_ms);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API DN_OSSemaphore DN_ASYNC_QueueTask(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms)
|
||||
{
|
||||
DN_OSSemaphore result = DN_OS_SemaphoreInit(0);
|
||||
DN_ASYNCJob job = {};
|
||||
job.work.func = func;
|
||||
job.work.input = input;
|
||||
job.completion_sem = result;
|
||||
DN_ASYNC_QueueJob_(async, &job, wait_time_ms);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API void DN_ASYNC_WaitTask(DN_OSSemaphore *sem, DN_U32 timeout_ms)
|
||||
{
|
||||
DN_OS_SemaphoreWait(sem, timeout_ms);
|
||||
DN_OS_SemaphoreDeinit(sem);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#if !defined(DN_ASYNC_H)
|
||||
#define DN_ASYNC_H
|
||||
|
||||
#include "../dn_base_inc.h"
|
||||
#include "../dn_os_inc.h"
|
||||
|
||||
enum DN_ASYNCPriority
|
||||
{
|
||||
DN_ASYNCPriority_Low,
|
||||
DN_ASYNCPriority_High,
|
||||
DN_ASYNCPriority_Count,
|
||||
};
|
||||
|
||||
struct DN_ASYNCCore
|
||||
{
|
||||
DN_OSMutex ring_mutex;
|
||||
DN_OSConditionVariable ring_write_cv;
|
||||
DN_OSSemaphore worker_sem;
|
||||
DN_Ring ring;
|
||||
DN_OSThread *threads;
|
||||
DN_U32 thread_count;
|
||||
DN_U32 busy_threads;
|
||||
DN_U32 join_threads;
|
||||
};
|
||||
|
||||
typedef void(DN_ASYNCWorkFunc)(void *input);
|
||||
|
||||
struct DN_ASYNCWork
|
||||
{
|
||||
DN_ASYNCWorkFunc *func;
|
||||
void *input;
|
||||
void *output;
|
||||
};
|
||||
|
||||
struct DN_ASYNCJob
|
||||
{
|
||||
DN_ASYNCWork work;
|
||||
DN_OSSemaphore completion_sem;
|
||||
};
|
||||
|
||||
struct DN_ASYNCTask
|
||||
{
|
||||
DN_ASYNCWork work;
|
||||
};
|
||||
|
||||
DN_API void DN_ASYNC_Init (DN_ASYNCCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size);
|
||||
DN_API void DN_ASYNC_Deinit (DN_ASYNCCore *async);
|
||||
DN_API bool DN_ASYNC_QueueWork(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms);
|
||||
DN_API DN_OSSemaphore DN_ASYNC_QueueTask(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms);
|
||||
DN_API void DN_ASYNC_WaitTask (DN_OSSemaphore *sem, DN_U32 timeout_ms);
|
||||
|
||||
#endif // DN_ASYNC_H
|
||||
@@ -0,0 +1,170 @@
|
||||
DN_API void DN_BinPack_U64(DN_BinPack *pack, DN_BinPackMode mode, DN_U64 *item)
|
||||
{
|
||||
DN_U64 const VALUE_MASK = 0b0111'1111;
|
||||
DN_U8 const CONTINUE_BIT = 0b1000'0000;
|
||||
|
||||
if (mode == DN_BinPackMode_Serialise) {
|
||||
DN_U64 it = *item;
|
||||
do {
|
||||
DN_U8 write_value = DN_CAST(DN_U8)(it & VALUE_MASK);
|
||||
it >>= 7;
|
||||
if (it)
|
||||
write_value |= CONTINUE_BIT;
|
||||
DN_Str8Builder_AppendBytesCopy(&pack->writer, &write_value, sizeof(write_value));
|
||||
} while (it);
|
||||
} else {
|
||||
*item = 0;
|
||||
DN_USize bits_read = 0;
|
||||
for (DN_U8 src = CONTINUE_BIT; (src & CONTINUE_BIT) && bits_read < 64; bits_read += 7) {
|
||||
src = pack->read.data[pack->read_index++];
|
||||
DN_U8 masked_src = src & VALUE_MASK;
|
||||
*item |= (DN_CAST(DN_U64) masked_src << bits_read);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_VarInt_(DN_BinPack *pack, DN_BinPackMode mode, void *item, DN_USize size)
|
||||
{
|
||||
DN_U64 value = 0;
|
||||
DN_AssertF(size <= sizeof(value),
|
||||
"An item larger than 64 bits (%zu) is trying to be packed as a variable integer which is not supported",
|
||||
size * 8);
|
||||
|
||||
if (mode == DN_BinPackMode_Serialise) // Read `item` into U64 `value`
|
||||
DN_Memcpy(&value, item, size);
|
||||
|
||||
DN_BinPack_U64(pack, mode, &value);
|
||||
|
||||
if (mode == DN_BinPackMode_Deserialise) // Write U64 `value` into `item`
|
||||
DN_Memcpy(item, &value, size);
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_U32(DN_BinPack *pack, DN_BinPackMode mode, DN_U32 *item)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_U16(DN_BinPack *pack, DN_BinPackMode mode, DN_U16 *item)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_U8(DN_BinPack *pack, DN_BinPackMode mode, DN_U8 *item)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_I64(DN_BinPack *pack, DN_BinPackMode mode, DN_I64 *item)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_I32(DN_BinPack *pack, DN_BinPackMode mode, DN_I32 *item)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_I16(DN_BinPack *pack, DN_BinPackMode mode, DN_I16 *item)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_I8(DN_BinPack *pack, DN_BinPackMode mode, DN_I8 *item)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_F64(DN_BinPack *pack, DN_BinPackMode mode, DN_F64 *item)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_F32(DN_BinPack *pack, DN_BinPackMode mode, DN_F32 *item)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
#if defined(DN_MATH_H)
|
||||
DN_API void DN_BinPack_V2(DN_BinPack *pack, DN_BinPackMode mode, DN_V2F32 *item)
|
||||
{
|
||||
DN_BinPack_F32(pack, mode, &item->x);
|
||||
DN_BinPack_F32(pack, mode, &item->y);
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_V4(DN_BinPack *pack, DN_BinPackMode mode, DN_V4F32 *item)
|
||||
{
|
||||
DN_BinPack_F32(pack, mode, &item->x);
|
||||
DN_BinPack_F32(pack, mode, &item->y);
|
||||
DN_BinPack_F32(pack, mode, &item->z);
|
||||
DN_BinPack_F32(pack, mode, &item->w);
|
||||
}
|
||||
#endif
|
||||
|
||||
DN_API void DN_BinPack_Bool(DN_BinPack *pack, DN_BinPackMode mode, bool *item)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_Str8(DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, DN_Str8 *string)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, &string->size, sizeof(string->size));
|
||||
if (mode == DN_BinPackMode_Serialise) {
|
||||
DN_Str8Builder_AppendBytesCopy(&pack->writer, string->data, string->size);
|
||||
} else {
|
||||
DN_Str8 src = DN_Str8_Slice(pack->read, pack->read_index, string->size);
|
||||
*string = DN_Str8_Copy(arena, src);
|
||||
pack->read_index += src.size;
|
||||
}
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_Str8Pool(DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, DN_Str8 *string)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, &string->size, sizeof(string->size));
|
||||
if (mode == DN_BinPackMode_Serialise) {
|
||||
DN_Str8Builder_AppendBytesCopy(&pack->writer, string->data, string->size);
|
||||
} else {
|
||||
DN_Str8 src = DN_Str8_Slice(pack->read, pack->read_index, string->size);
|
||||
*string = DN_Pool_AllocStr8Copy(pool, src);
|
||||
pack->read_index += src.size;
|
||||
}
|
||||
}
|
||||
|
||||
template <DN_USize N>
|
||||
DN_API void DN_BinPack_FStr8(DN_BinPack *pack, DN_BinPackMode mode, DN_FStr8<N> *string)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, &string->size, sizeof(string->size));
|
||||
if (mode == DN_BinPackMode_Serialise) {
|
||||
DN_Str8Builder_AppendBytesCopy(&pack->writer, string->data, string->size);
|
||||
} else {
|
||||
DN_Str8 src = DN_Str8_Slice(pack->read, pack->read_index, string->size);
|
||||
*string = DN_FStr8_InitF<N>("%.*s", DN_STR_FMT(src));
|
||||
pack->read_index += src.size;
|
||||
}
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_Bytes(DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, void **ptr, DN_USize *size)
|
||||
{
|
||||
DN_Str8 string = DN_Str8_Init(*ptr, *size);
|
||||
DN_BinPack_Str8(pack, arena, mode, &string);
|
||||
*ptr = string.data;
|
||||
*size = string.size;
|
||||
}
|
||||
|
||||
DN_API void DN_BinPack_CArray(DN_BinPack *pack, DN_BinPackMode mode, void *ptr, DN_USize size)
|
||||
{
|
||||
DN_BinPack_VarInt_(pack, mode, &size, sizeof(size));
|
||||
if (mode == DN_BinPackMode_Serialise) {
|
||||
DN_Str8Builder_AppendBytesCopy(&pack->writer, ptr, size);
|
||||
} else {
|
||||
DN_Str8 src = DN_Str8_Slice(pack->read, pack->read_index, size);
|
||||
DN_Assert(src.size == size);
|
||||
DN_Memcpy(ptr, src.data, DN_Min(src.size, size));
|
||||
pack->read_index += src.size;
|
||||
}
|
||||
}
|
||||
|
||||
DN_API DN_Str8 DN_BinPack_Build(DN_BinPack const *pack, DN_Arena *arena)
|
||||
{
|
||||
DN_Str8 result = DN_Str8Builder_Build(&pack->writer, arena);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#if !defined(DN_BIN_PACK_H)
|
||||
#define DN_BIN_PACK_H
|
||||
|
||||
#if !defined(DN_BASE_INC_H)
|
||||
#error dn_base_inc.h must be included before this
|
||||
#endif
|
||||
|
||||
enum DN_BinPackMode
|
||||
{
|
||||
DN_BinPackMode_Serialise,
|
||||
DN_BinPackMode_Deserialise,
|
||||
};
|
||||
|
||||
struct DN_BinPack
|
||||
{
|
||||
DN_Str8Builder writer;
|
||||
DN_Str8 read;
|
||||
DN_USize read_index;
|
||||
};
|
||||
|
||||
DN_API void DN_BinPack_U64 (DN_BinPack *pack, DN_BinPackMode mode, DN_U64 *item);
|
||||
DN_API void DN_BinPack_U32 (DN_BinPack *pack, DN_BinPackMode mode, DN_U32 *item);
|
||||
DN_API void DN_BinPack_U16 (DN_BinPack *pack, DN_BinPackMode mode, DN_U16 *item);
|
||||
DN_API void DN_BinPack_U8 (DN_BinPack *pack, DN_BinPackMode mode, DN_U8 *item);
|
||||
DN_API void DN_BinPack_I64 (DN_BinPack *pack, DN_BinPackMode mode, DN_I64 *item);
|
||||
DN_API void DN_BinPack_I32 (DN_BinPack *pack, DN_BinPackMode mode, DN_I32 *item);
|
||||
DN_API void DN_BinPack_I16 (DN_BinPack *pack, DN_BinPackMode mode, DN_I16 *item);
|
||||
DN_API void DN_BinPack_I8 (DN_BinPack *pack, DN_BinPackMode mode, DN_I8 *item);
|
||||
DN_API void DN_BinPack_F64 (DN_BinPack *pack, DN_BinPackMode mode, DN_F64 *item);
|
||||
DN_API void DN_BinPack_F32 (DN_BinPack *pack, DN_BinPackMode mode, DN_F32 *item);
|
||||
#if defined(DN_MATH_H)
|
||||
DN_API void DN_BinPack_V2 (DN_BinPack *pack, DN_BinPackMode mode, DN_V2F32 *item);
|
||||
DN_API void DN_BinPack_V4 (DN_BinPack *pack, DN_BinPackMode mode, DN_V4F32 *item);
|
||||
#endif
|
||||
DN_API void DN_BinPack_Bool (DN_BinPack *pack, DN_BinPackMode mode, bool *item);
|
||||
DN_API void DN_BinPack_Str8 (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, DN_Str8 *string);
|
||||
DN_API void DN_BinPack_Str8Pool(DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, DN_Str8 *string);
|
||||
template <DN_USize N> DN_API void DN_BinPack_FStr8 (DN_BinPack *pack, DN_BinPackMode mode, DN_FStr8<N> *string);
|
||||
DN_API void DN_BinPack_Bytes (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, void **ptr, DN_USize *size);
|
||||
DN_API void DN_BinPack_CArray (DN_BinPack *pack, DN_BinPackMode mode, void *ptr, DN_USize size);
|
||||
DN_API DN_Str8 DN_BinPack_Build (DN_BinPack const *pack, DN_Arena *arena);
|
||||
|
||||
#endif // !defined(DN_BIN_PACK_H)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,200 @@
|
||||
#if !defined(DN_CGEN_H)
|
||||
#define DN_CGEN_H
|
||||
|
||||
#if !defined(DN_NO_METADESK)
|
||||
#if !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define DN_UNDO_CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
// NOTE: Metadesk does not have the header for 'size_t'
|
||||
#if defined(DN_COMPILER_GCC)
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#define MD_DEFAULT_SPRINTF 0
|
||||
#define MD_IMPL_Vsnprintf DN_VSNPrintF
|
||||
#include "../External/metadesk/md.h"
|
||||
#if defined(DN_UNDO_CRT_SECURE_NO_WARNINGS)
|
||||
#undef _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(DN_CPP_FILE_H)
|
||||
#error dn_cpp_file.h must be included before this
|
||||
#endif
|
||||
|
||||
#if defined(DN_PLATFORM_WINDOWS) && !defined(DN_NO_WINDOWS_H_REPLACEMENT_HEADER)
|
||||
#error DN <Windows.h> replacement header must be disabled with DN_NO_WINDOWS_H_REPLACEMENT_HEADER since Metadesk includes <Windows.h>
|
||||
#endif
|
||||
|
||||
#if !defined(MD_H)
|
||||
#error Metadesk 'md.h' must be included before 'dn_cgen.h'
|
||||
#endif
|
||||
|
||||
#if !defined(DN_BASE_INC_H)
|
||||
#error dn_base_inc.h must be included before this
|
||||
#endif
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$$$$$\ $$$$$$\ $$$$$$$$\ $$\ $$\
|
||||
// $$ __$$\ $$ __$$\ $$ _____|$$$\ $$ |
|
||||
// $$ / \__|$$ / \__|$$ | $$$$\ $$ |
|
||||
// $$ | $$ |$$$$\ $$$$$\ $$ $$\$$ |
|
||||
// $$ | $$ |\_$$ |$$ __| $$ \$$$$ |
|
||||
// $$ | $$\ $$ | $$ |$$ | $$ |\$$$ |
|
||||
// \$$$$$$ |\$$$$$$ |$$$$$$$$\ $$ | \$$ |
|
||||
// \______/ \______/ \________|\__| \__|
|
||||
//
|
||||
// dn_cgen.h -- C/C++ code generation from table data in Metadesk files
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
enum DN_CGenTableKeyType
|
||||
{
|
||||
DN_CGenTableKeyType_Nil,
|
||||
DN_CGenTableKeyType_Name,
|
||||
DN_CGenTableKeyType_Type,
|
||||
};
|
||||
|
||||
enum DN_CGenTableType
|
||||
{
|
||||
DN_CGenTableType_Nil,
|
||||
DN_CGenTableType_Data,
|
||||
DN_CGenTableType_CodeGenBuiltinTypes,
|
||||
DN_CGenTableType_CodeGenStruct,
|
||||
DN_CGenTableType_CodeGenEnum,
|
||||
DN_CGenTableType_Count,
|
||||
};
|
||||
|
||||
enum DN_CGenTableRowTagType
|
||||
{
|
||||
DN_CGenTableRowTagType_Nil,
|
||||
DN_CGenTableRowTagType_CommentDivider,
|
||||
DN_CGenTableRowTagType_EmptyLine,
|
||||
};
|
||||
|
||||
enum DN_CGenTableRowTagCommentDivider
|
||||
{
|
||||
DN_CGenTableRowTagCommentDivider_Nil,
|
||||
DN_CGenTableRowTagCommentDivider_Label,
|
||||
};
|
||||
|
||||
enum DN_CGenTableHeaderType
|
||||
{
|
||||
DN_CGenTableHeaderType_Name,
|
||||
DN_CGenTableHeaderType_Table,
|
||||
DN_CGenTableHeaderType_CppType,
|
||||
DN_CGenTableHeaderType_CppName,
|
||||
DN_CGenTableHeaderType_CppValue,
|
||||
DN_CGenTableHeaderType_CppIsPtr,
|
||||
DN_CGenTableHeaderType_CppOpEquals,
|
||||
DN_CGenTableHeaderType_CppArraySize,
|
||||
DN_CGenTableHeaderType_CppArraySizeField,
|
||||
DN_CGenTableHeaderType_CppLabel,
|
||||
DN_CGenTableHeaderType_GenTypeInfo,
|
||||
DN_CGenTableHeaderType_GenEnumCount,
|
||||
DN_CGenTableHeaderType_Count,
|
||||
};
|
||||
|
||||
struct DN_CGenTableHeader
|
||||
{
|
||||
MD_String8 name;
|
||||
int longest_string;
|
||||
};
|
||||
|
||||
struct DN_CGenTableRowTag
|
||||
{
|
||||
DN_CGenTableRowTagType type;
|
||||
MD_String8 comment;
|
||||
DN_CGenTableRowTag *next;
|
||||
};
|
||||
|
||||
struct DN_CGenTableColumn
|
||||
{
|
||||
MD_Node *node;
|
||||
DN_Str8 string;
|
||||
};
|
||||
|
||||
struct DN_CGenTableRow
|
||||
{
|
||||
DN_CGenTableRowTag *first_tag;
|
||||
DN_CGenTableRowTag *last_tag;
|
||||
DN_CGenTableColumn *columns;
|
||||
};
|
||||
|
||||
struct DN_CGenTable
|
||||
{
|
||||
DN_CGenTableType type;
|
||||
DN_Str8 name;
|
||||
MD_Map headers_map;
|
||||
DN_CGenTableHeader *headers;
|
||||
DN_CGenTableRow *rows;
|
||||
size_t column_count;
|
||||
size_t row_count;
|
||||
|
||||
MD_Node *node;
|
||||
MD_Node *headers_node;
|
||||
DN_USize column_indexes[DN_CGenTableHeaderType_Count];
|
||||
DN_CGenTable *next;
|
||||
};
|
||||
|
||||
struct DN_CGen
|
||||
{
|
||||
MD_Arena *arena;
|
||||
MD_Node *file_list;
|
||||
MD_Map table_map;
|
||||
DN_CGenTable *first_table;
|
||||
DN_CGenTable *last_table;
|
||||
DN_USize table_counts[DN_CGenTableType_Count];
|
||||
};
|
||||
|
||||
struct DN_CGenMapNodeToEnum
|
||||
{
|
||||
uint32_t enum_val;
|
||||
DN_Str8 node_string;
|
||||
};
|
||||
|
||||
struct DN_CGenLookupTableIterator
|
||||
{
|
||||
DN_CGenTable *cgen_table;
|
||||
DN_CGenTableRow *cgen_table_row;
|
||||
DN_CGenTableColumn cgen_table_column[DN_CGenTableHeaderType_Count];
|
||||
DN_CGenTable *table;
|
||||
DN_USize row_index;
|
||||
};
|
||||
|
||||
struct DN_CGenLookupColumnAtHeader
|
||||
{
|
||||
DN_USize index;
|
||||
DN_CGenTableHeader header;
|
||||
DN_CGenTableColumn column;
|
||||
};
|
||||
|
||||
enum DN_CGenEmit
|
||||
{
|
||||
DN_CGenEmit_Prototypes = 1 << 0,
|
||||
DN_CGenEmit_Implementation = 1 << 1,
|
||||
};
|
||||
|
||||
#define DN_CGen_MDToDNStr8(str8) DN_Str8_Init((str8).str, (str8).size)
|
||||
#define DN_CGen_DNToMDStr8(str8) \
|
||||
{ \
|
||||
DN_CAST(MD_u8 *) \
|
||||
(str8).data, \
|
||||
(str8).size \
|
||||
}
|
||||
|
||||
DN_API DN_CGen DN_CGen_InitFilesArgV(int argc, char const **argv, DN_OSErrSink *err);
|
||||
DN_API DN_Str8 DN_CGen_TableHeaderTypeToDeclStr8(DN_CGenTableHeaderType type);
|
||||
DN_API DN_CGenMapNodeToEnum DN_CGen_MapNodeToEnumOrExit(MD_Node const *node, DN_CGenMapNodeToEnum const *valid_keys, DN_USize valid_keys_size, char const *fmt, ...);
|
||||
DN_API DN_USize DN_CGen_NodeChildrenCount(MD_Node const *node);
|
||||
DN_API void DN_CGen_LogF(MD_MessageKind kind, MD_Node *node, DN_OSErrSink *err, char const *fmt, ...);
|
||||
DN_API bool DN_CGen_TableHasHeaders(DN_CGenTable const *table, DN_Str8 const *headers, DN_USize header_count, DN_OSErrSink *err);
|
||||
DN_API DN_CGenLookupColumnAtHeader DN_CGen_LookupColumnAtHeader(DN_CGenTable *table, DN_Str8 header, DN_CGenTableRow const *row);
|
||||
DN_API bool DN_CGen_LookupNextTableInCodeGenTable(DN_CGen *cgen, DN_CGenTable *cgen_table, DN_CGenLookupTableIterator *it);
|
||||
DN_API void DN_CGen_EmitCodeForTables(DN_CGen *cgen, DN_CGenEmit emit, DN_CppFile *cpp, DN_Str8 emit_prefix);
|
||||
#endif // DN_CGEN_H
|
||||
@@ -0,0 +1,288 @@
|
||||
#include "dn_csv.h"
|
||||
|
||||
static DN_CSVTokeniser DN_CSV_TokeniserInit(DN_Str8 string, char delimiter)
|
||||
{
|
||||
DN_CSVTokeniser result = {};
|
||||
result.string = string;
|
||||
result.delimiter = delimiter;
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool DN_CSV_TokeniserValid(DN_CSVTokeniser *tokeniser)
|
||||
{
|
||||
bool result = tokeniser && !tokeniser->bad;
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool DN_CSV_TokeniserNextRow(DN_CSVTokeniser *tokeniser)
|
||||
{
|
||||
bool result = false;
|
||||
if (DN_CSV_TokeniserValid(tokeniser) && DN_Str8_HasData(tokeniser->string)) {
|
||||
// NOTE: First time querying row iterator is nil, let tokeniser advance
|
||||
if (tokeniser->it) {
|
||||
// NOTE: Only advance the tokeniser if we're at the end of the line and
|
||||
// there's more to tokenise.
|
||||
char const *end = tokeniser->string.data + tokeniser->string.size;
|
||||
if (tokeniser->it != end && tokeniser->end_of_line) {
|
||||
tokeniser->end_of_line = false;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser)
|
||||
{
|
||||
DN_Str8 result = {};
|
||||
if (!DN_CSV_TokeniserValid(tokeniser))
|
||||
return result;
|
||||
|
||||
if (!DN_Str8_HasData(tokeniser->string)) {
|
||||
tokeniser->bad = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: First time tokeniser is invoked with a string, set up initial state.
|
||||
char const *string_end = tokeniser->string.data + tokeniser->string.size;
|
||||
if (!tokeniser->it) {
|
||||
tokeniser->it = tokeniser->string.data;
|
||||
// NOTE: Skip any leading new lines
|
||||
while (tokeniser->it[0] == '\n' || tokeniser->it[0] == '\r')
|
||||
if (++tokeniser->it == string_end)
|
||||
break;
|
||||
}
|
||||
|
||||
// NOTE: Tokeniser pointing at end, no more valid data to parse.
|
||||
if (tokeniser->it == string_end)
|
||||
return result;
|
||||
|
||||
// NOTE: Scan forward until the next control character.
|
||||
// 1. '"' Double quoted field, extract everything between the quotes.
|
||||
// 2. tokeniser->delimiter End of the field, extract everything leading up to the delimiter.
|
||||
// 3. '\n' Last field in record, extract everything leading up the the new line.
|
||||
char const *begin = tokeniser->it;
|
||||
while (tokeniser->it != string_end && (tokeniser->it[0] != '"' &&
|
||||
tokeniser->it[0] != tokeniser->delimiter &&
|
||||
tokeniser->it[0] != '\n'))
|
||||
tokeniser->it++;
|
||||
|
||||
bool quoted_field = (tokeniser->it != string_end) && tokeniser->it[0] == '"';
|
||||
if (quoted_field) {
|
||||
begin = ++tokeniser->it; // Begin after the quote
|
||||
|
||||
// NOTE: Scan forward until the next '"' which marks the end
|
||||
// of the field unless it is escaped by another '"'.
|
||||
find_next_quote:
|
||||
while (tokeniser->it != string_end && tokeniser->it[0] != '"')
|
||||
tokeniser->it++;
|
||||
|
||||
// NOTE: If we encounter a '"' right after, the quotes were escaped
|
||||
// and we need to skip to the next instance of a '"'.
|
||||
if (tokeniser->it != string_end && tokeniser->it + 1 != string_end && tokeniser->it[1] == '"') {
|
||||
tokeniser->it += 2;
|
||||
goto find_next_quote;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Mark the end of the field
|
||||
char const *end = tokeniser->it;
|
||||
tokeniser->end_of_line = tokeniser->it == string_end || end[0] == '\n';
|
||||
|
||||
// NOTE: In files with \r\n style new lines ensure that we don't include
|
||||
// the \r byte in the CSV field we produce.
|
||||
if (end != string_end && end[0] == '\n') {
|
||||
DN_Assert((uintptr_t)(end - 1) > (uintptr_t)tokeniser->string.data &&
|
||||
"Internal error: The string iterator is pointing behind the start of the string we're reading");
|
||||
if (end[-1] == '\r')
|
||||
end = end - 1;
|
||||
}
|
||||
|
||||
// NOTE: Quoted fields may have whitespace after the closing quote, we skip
|
||||
// until we reach the field terminator.
|
||||
if (quoted_field)
|
||||
while (tokeniser->it != string_end && (tokeniser->it[0] != tokeniser->delimiter &&
|
||||
tokeniser->it[0] != '\n'))
|
||||
tokeniser->it++;
|
||||
|
||||
// NOTE: Advance the tokeniser past the field terminator.
|
||||
if (tokeniser->it != string_end)
|
||||
tokeniser->it++;
|
||||
|
||||
// NOTE: Generate the record
|
||||
result.data = DN_CAST(char *) begin;
|
||||
result.size = DN_CAST(int)(end - begin);
|
||||
return result;
|
||||
}
|
||||
|
||||
static DN_Str8 DN_CSV_TokeniserNextColumn(DN_CSVTokeniser *tokeniser)
|
||||
{
|
||||
DN_Str8 result = {};
|
||||
if (!DN_CSV_TokeniserValid(tokeniser))
|
||||
return result;
|
||||
|
||||
// NOTE: End of line, the user must explicitly advance to the next row
|
||||
if (tokeniser->end_of_line)
|
||||
return result;
|
||||
|
||||
// NOTE: Advance tokeniser to the next field in the row
|
||||
result = DN_CSV_TokeniserNextField(tokeniser);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void DN_CSV_TokeniserSkipLine(DN_CSVTokeniser *tokeniser)
|
||||
{
|
||||
while (DN_CSV_TokeniserValid(tokeniser) && !tokeniser->end_of_line)
|
||||
DN_CSV_TokeniserNextColumn(tokeniser);
|
||||
DN_CSV_TokeniserNextRow(tokeniser);
|
||||
}
|
||||
|
||||
static int DN_CSV_TokeniserNextN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator)
|
||||
{
|
||||
if (!DN_CSV_TokeniserValid(tokeniser) || !fields || fields_size <= 0)
|
||||
return 0;
|
||||
|
||||
int result = 0;
|
||||
for (; result < fields_size; result++) {
|
||||
fields[result] = column_iterator ? DN_CSV_TokeniserNextColumn(tokeniser) : DN_CSV_TokeniserNextField(tokeniser);
|
||||
if (!DN_CSV_TokeniserValid(tokeniser) || !DN_Str8_HasData(fields[result]))
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_MSVC_WARNING_PUSH
|
||||
DN_MSVC_WARNING_DISABLE(4505) // 'x': unreferenced function with internal linkage has been removed
|
||||
static int DN_CSV_TokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size)
|
||||
{
|
||||
int result = DN_CSV_TokeniserNextN(tokeniser, fields, fields_size, true /*column_iterator*/);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int DN_CSV_TokeniserNextFieldN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size)
|
||||
{
|
||||
int result = DN_CSV_TokeniserNextN(tokeniser, fields, fields_size, false /*column_iterator*/);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void DN_CSV_TokeniserSkipLineN(DN_CSVTokeniser *tokeniser, int count)
|
||||
{
|
||||
for (int i = 0; i < count && DN_CSV_TokeniserValid(tokeniser); i++)
|
||||
DN_CSV_TokeniserSkipLine(tokeniser);
|
||||
}
|
||||
|
||||
static void DN_CSV_PackU64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value)
|
||||
{
|
||||
if (serialise == DN_CSVSerialise_Read) {
|
||||
DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser);
|
||||
DN_Str8ToU64Result to_u64 = DN_Str8_ToU64(csv_value, 0);
|
||||
DN_Assert(to_u64.success);
|
||||
*value = to_u64.value;
|
||||
} else {
|
||||
DN_Str8Builder_AppendF(&pack->write_builder, "%s%" PRIu64, pack->write_column++ ? "," : "", *value);
|
||||
}
|
||||
}
|
||||
|
||||
static void DN_CSV_PackI64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value)
|
||||
{
|
||||
if (serialise == DN_CSVSerialise_Read) {
|
||||
DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser);
|
||||
DN_Str8ToI64Result to_i64 = DN_Str8_ToI64(csv_value, 0);
|
||||
DN_Assert(to_i64.success);
|
||||
*value = to_i64.value;
|
||||
} else {
|
||||
DN_Str8Builder_AppendF(&pack->write_builder, "%s%" PRIu64, pack->write_column++ ? "," : "", *value);
|
||||
}
|
||||
}
|
||||
|
||||
static void DN_CSV_PackI32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value)
|
||||
{
|
||||
DN_I64 u64 = *value;
|
||||
DN_CSV_PackI64(pack, serialise, &u64);
|
||||
if (serialise == DN_CSVSerialise_Read)
|
||||
*value = DN_SaturateCastI64ToI32(u64);
|
||||
}
|
||||
|
||||
static void DN_CSV_PackI16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value)
|
||||
{
|
||||
DN_I64 u64 = *value;
|
||||
DN_CSV_PackI64(pack, serialise, &u64);
|
||||
if (serialise == DN_CSVSerialise_Read)
|
||||
*value = DN_SaturateCastI64ToI16(u64);
|
||||
}
|
||||
|
||||
static void DN_CSV_PackI8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value)
|
||||
{
|
||||
DN_I64 u64 = *value;
|
||||
DN_CSV_PackI64(pack, serialise, &u64);
|
||||
if (serialise == DN_CSVSerialise_Read)
|
||||
*value = DN_SaturateCastI64ToI8(u64);
|
||||
}
|
||||
|
||||
|
||||
static void DN_CSV_PackU32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value)
|
||||
{
|
||||
DN_U64 u64 = *value;
|
||||
DN_CSV_PackU64(pack, serialise, &u64);
|
||||
if (serialise == DN_CSVSerialise_Read)
|
||||
*value = DN_SaturateCastU64ToU32(u64);
|
||||
}
|
||||
|
||||
static void DN_CSV_PackU16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value)
|
||||
{
|
||||
DN_U64 u64 = *value;
|
||||
DN_CSV_PackU64(pack, serialise, &u64);
|
||||
if (serialise == DN_CSVSerialise_Read)
|
||||
*value = DN_SaturateCastU64ToU16(u64);
|
||||
}
|
||||
|
||||
static void DN_CSV_PackBoolAsU64(DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value)
|
||||
{
|
||||
DN_U64 u64 = *value;
|
||||
DN_CSV_PackU64(pack, serialise, &u64);
|
||||
if (serialise == DN_CSVSerialise_Read)
|
||||
*value = u64 ? 1 : 0;
|
||||
}
|
||||
|
||||
static void DN_CSV_PackStr8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena)
|
||||
{
|
||||
if (serialise == DN_CSVSerialise_Read) {
|
||||
DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser);
|
||||
*str8 = DN_Str8_Copy(arena, csv_value);
|
||||
} else {
|
||||
DN_Str8Builder_AppendF(&pack->write_builder, "%s%.*s", pack->write_column++ ? "," : "", DN_STR_FMT(*str8));
|
||||
}
|
||||
}
|
||||
|
||||
static void DN_CSV_PackBuffer(DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size)
|
||||
{
|
||||
if (serialise == DN_CSVSerialise_Read) {
|
||||
DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser);
|
||||
*size = DN_Min(*size, csv_value.size);
|
||||
DN_Memcpy(dest, csv_value.data, *size);
|
||||
} else {
|
||||
DN_Str8Builder_AppendF(&pack->write_builder, "%s%.*s", pack->write_column++ ? "," : "", DN_CAST(int)(*size), dest);
|
||||
}
|
||||
}
|
||||
|
||||
static void DN_CSV_PackBufferWithMax(DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max)
|
||||
{
|
||||
if (serialise == DN_CSVSerialise_Read)
|
||||
*size = max;
|
||||
DN_CSV_PackBuffer(pack, serialise, dest, size);
|
||||
}
|
||||
|
||||
static bool DN_CSV_PackNewLine(DN_CSVPack *pack, DN_CSVSerialise serialise)
|
||||
{
|
||||
bool result = true;
|
||||
if (serialise == DN_CSVSerialise_Read) {
|
||||
result = DN_CSV_TokeniserNextRow(&pack->read_tokeniser);
|
||||
} else {
|
||||
pack->write_column = 0;
|
||||
result = DN_Str8Builder_AppendRef(&pack->write_builder, DN_STR8("\n"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
DN_MSVC_WARNING_POP
|
||||
@@ -0,0 +1,26 @@
|
||||
#if !defined(DN_CSV_H)
|
||||
#define DN_CSV_H
|
||||
|
||||
enum DN_CSVSerialise
|
||||
{
|
||||
DN_CSVSerialise_Read,
|
||||
DN_CSVSerialise_Write,
|
||||
};
|
||||
|
||||
struct DN_CSVTokeniser
|
||||
{
|
||||
bool bad;
|
||||
DN_Str8 string;
|
||||
char delimiter;
|
||||
char const *it;
|
||||
bool end_of_line;
|
||||
};
|
||||
|
||||
struct DN_CSVPack
|
||||
{
|
||||
DN_Str8Builder write_builder;
|
||||
DN_USize write_column;
|
||||
DN_CSVTokeniser read_tokeniser;
|
||||
};
|
||||
|
||||
#endif // !defined(DN_CSV_H)
|
||||
@@ -0,0 +1,265 @@
|
||||
#define DN_HASH_CPP
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\
|
||||
// $$ | $$ |$$ __$$\ $$ __$$\ $$ | $$ |
|
||||
// $$ | $$ |$$ / $$ |$$ / \__|$$ | $$ |
|
||||
// $$$$$$$$ |$$$$$$$$ |\$$$$$$\ $$$$$$$$ |
|
||||
// $$ __$$ |$$ __$$ | \____$$\ $$ __$$ |
|
||||
// $$ | $$ |$$ | $$ |$$\ $$ |$$ | $$ |
|
||||
// $$ | $$ |$$ | $$ |\$$$$$$ |$$ | $$ |
|
||||
// \__| \__|\__| \__| \______/ \__| \__|
|
||||
//
|
||||
// dn_hash.cpp
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
// NOTE: DN_FNV1A //////////////////////////////////////////////////////////////////////////////////
|
||||
// Default values recommended by: http://isthe.com/chongo/tech/comp/fnv/
|
||||
DN_API uint32_t DN_FNV1A32_Iterate(void const *bytes, DN_USize size, uint32_t hash)
|
||||
{
|
||||
auto buffer = DN_CAST(uint8_t const *)bytes;
|
||||
for (DN_USize i = 0; i < size; i++)
|
||||
hash = (buffer[i] ^ hash) * 16777619 /*FNV Prime*/;
|
||||
return hash;
|
||||
}
|
||||
|
||||
DN_API uint32_t DN_FNV1A32_Hash(void const *bytes, DN_USize size)
|
||||
{
|
||||
uint32_t result = DN_FNV1A32_Iterate(bytes, size, DN_FNV1A32_SEED);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API uint64_t DN_FNV1A64_Iterate(void const *bytes, DN_USize size, uint64_t hash)
|
||||
{
|
||||
auto buffer = DN_CAST(uint8_t const *)bytes;
|
||||
for (DN_USize i = 0; i < size; i++)
|
||||
hash = (buffer[i] ^ hash) * 1099511628211 /*FNV Prime*/;
|
||||
return hash;
|
||||
}
|
||||
|
||||
DN_API uint64_t DN_FNV1A64_Hash(void const *bytes, DN_USize size)
|
||||
{
|
||||
uint64_t result = DN_FNV1A64_Iterate(bytes, size, DN_FNV1A64_SEED);
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: DN_MurmurHash3 ////////////////////////////////////////////////////////////////////////////
|
||||
#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL)
|
||||
#define DN_MMH3_ROTL32(x, y) _rotl(x, y)
|
||||
#define DN_MMH3_ROTL64(x, y) _rotl64(x, y)
|
||||
#else
|
||||
#define DN_MMH3_ROTL32(x, y) ((x) << (y)) | ((x) >> (32 - (y)))
|
||||
#define DN_MMH3_ROTL64(x, y) ((x) << (y)) | ((x) >> (64 - (y)))
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Block read - if your platform needs to do endian-swapping or can only
|
||||
// handle aligned reads, do the conversion here
|
||||
|
||||
DN_FORCE_INLINE uint32_t DN_MurmurHash3_GetBlock32(uint32_t const *p, int i)
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
DN_FORCE_INLINE uint64_t DN_MurmurHash3_GetBlock64(uint64_t const *p, int i)
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finalization mix - force all bits of a hash block to avalanche
|
||||
|
||||
DN_FORCE_INLINE uint32_t DN_MurmurHash3_FMix32(uint32_t h)
|
||||
{
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ^= h >> 16;
|
||||
return h;
|
||||
}
|
||||
|
||||
DN_FORCE_INLINE uint64_t DN_MurmurHash3_FMix64(uint64_t k)
|
||||
{
|
||||
k ^= k >> 33;
|
||||
k *= 0xff51afd7ed558ccd;
|
||||
k ^= k >> 33;
|
||||
k *= 0xc4ceb9fe1a85ec53;
|
||||
k ^= k >> 33;
|
||||
return k;
|
||||
}
|
||||
|
||||
DN_API uint32_t DN_MurmurHash3_x86U32(void const *key, int len, uint32_t seed)
|
||||
{
|
||||
const uint8_t *data = (const uint8_t *)key;
|
||||
const int nblocks = len / 4;
|
||||
|
||||
uint32_t h1 = seed;
|
||||
|
||||
const uint32_t c1 = 0xcc9e2d51;
|
||||
const uint32_t c2 = 0x1b873593;
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
|
||||
|
||||
for (int i = -nblocks; i; i++)
|
||||
{
|
||||
uint32_t k1 = DN_MurmurHash3_GetBlock32(blocks, i);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = DN_MMH3_ROTL32(k1, 15);
|
||||
k1 *= c2;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = DN_MMH3_ROTL32(h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
|
||||
|
||||
uint32_t k1 = 0;
|
||||
|
||||
switch (len & 3)
|
||||
{
|
||||
case 3:
|
||||
k1 ^= tail[2] << 16;
|
||||
case 2:
|
||||
k1 ^= tail[1] << 8;
|
||||
case 1:
|
||||
k1 ^= tail[0];
|
||||
k1 *= c1;
|
||||
k1 = DN_MMH3_ROTL32(k1, 15);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len;
|
||||
|
||||
h1 = DN_MurmurHash3_FMix32(h1);
|
||||
|
||||
return h1;
|
||||
}
|
||||
|
||||
DN_API DN_MurmurHash3 DN_MurmurHash3_x64U128(void const *key, int len, uint32_t seed)
|
||||
{
|
||||
const uint8_t *data = (const uint8_t *)key;
|
||||
const int nblocks = len / 16;
|
||||
|
||||
uint64_t h1 = seed;
|
||||
uint64_t h2 = seed;
|
||||
|
||||
const uint64_t c1 = 0x87c37b91114253d5;
|
||||
const uint64_t c2 = 0x4cf5ad432745937f;
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const uint64_t *blocks = (const uint64_t *)(data);
|
||||
|
||||
for (int i = 0; i < nblocks; i++)
|
||||
{
|
||||
uint64_t k1 = DN_MurmurHash3_GetBlock64(blocks, i * 2 + 0);
|
||||
uint64_t k2 = DN_MurmurHash3_GetBlock64(blocks, i * 2 + 1);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = DN_MMH3_ROTL64(k1, 31);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
|
||||
h1 = DN_MMH3_ROTL64(h1, 27);
|
||||
h1 += h2;
|
||||
h1 = h1 * 5 + 0x52dce729;
|
||||
|
||||
k2 *= c2;
|
||||
k2 = DN_MMH3_ROTL64(k2, 33);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
|
||||
h2 = DN_MMH3_ROTL64(h2, 31);
|
||||
h2 += h1;
|
||||
h2 = h2 * 5 + 0x38495ab5;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8_t *tail = (const uint8_t *)(data + nblocks * 16);
|
||||
|
||||
uint64_t k1 = 0;
|
||||
uint64_t k2 = 0;
|
||||
|
||||
switch (len & 15)
|
||||
{
|
||||
case 15:
|
||||
k2 ^= ((uint64_t)tail[14]) << 48;
|
||||
case 14:
|
||||
k2 ^= ((uint64_t)tail[13]) << 40;
|
||||
case 13:
|
||||
k2 ^= ((uint64_t)tail[12]) << 32;
|
||||
case 12:
|
||||
k2 ^= ((uint64_t)tail[11]) << 24;
|
||||
case 11:
|
||||
k2 ^= ((uint64_t)tail[10]) << 16;
|
||||
case 10:
|
||||
k2 ^= ((uint64_t)tail[9]) << 8;
|
||||
case 9:
|
||||
k2 ^= ((uint64_t)tail[8]) << 0;
|
||||
k2 *= c2;
|
||||
k2 = DN_MMH3_ROTL64(k2, 33);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
|
||||
case 8:
|
||||
k1 ^= ((uint64_t)tail[7]) << 56;
|
||||
case 7:
|
||||
k1 ^= ((uint64_t)tail[6]) << 48;
|
||||
case 6:
|
||||
k1 ^= ((uint64_t)tail[5]) << 40;
|
||||
case 5:
|
||||
k1 ^= ((uint64_t)tail[4]) << 32;
|
||||
case 4:
|
||||
k1 ^= ((uint64_t)tail[3]) << 24;
|
||||
case 3:
|
||||
k1 ^= ((uint64_t)tail[2]) << 16;
|
||||
case 2:
|
||||
k1 ^= ((uint64_t)tail[1]) << 8;
|
||||
case 1:
|
||||
k1 ^= ((uint64_t)tail[0]) << 0;
|
||||
k1 *= c1;
|
||||
k1 = DN_MMH3_ROTL64(k1, 31);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len;
|
||||
h2 ^= len;
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
h1 = DN_MurmurHash3_FMix64(h1);
|
||||
h2 = DN_MurmurHash3_FMix64(h2);
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
DN_MurmurHash3 result = {};
|
||||
result.e[0] = h1;
|
||||
result.e[1] = h2;
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#if !defined(DN_HASH_H)
|
||||
#define DN_HASH_H
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\
|
||||
// $$ | $$ |$$ __$$\ $$ __$$\ $$ | $$ |
|
||||
// $$ | $$ |$$ / $$ |$$ / \__|$$ | $$ |
|
||||
// $$$$$$$$ |$$$$$$$$ |\$$$$$$\ $$$$$$$$ |
|
||||
// $$ __$$ |$$ __$$ | \____$$\ $$ __$$ |
|
||||
// $$ | $$ |$$ | $$ |$$\ $$ |$$ | $$ |
|
||||
// $$ | $$ |$$ | $$ |\$$$$$$ |$$ | $$ |
|
||||
// \__| \__|\__| \__| \______/ \__| \__|
|
||||
//
|
||||
// dn_hash.h -- Hashing functions
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
// NOTE: DN_FNV1A //////////////////////////////////////////////////////////////////////////////////
|
||||
#if !defined(DN_FNV1A32_SEED)
|
||||
#define DN_FNV1A32_SEED 2166136261U
|
||||
#endif
|
||||
|
||||
#if !defined(DN_FNV1A64_SEED)
|
||||
#define DN_FNV1A64_SEED 14695981039346656037ULL
|
||||
#endif
|
||||
|
||||
// NOTE: DN_MurmurHash3 ////////////////////////////////////////////////////////////////////////////
|
||||
struct DN_MurmurHash3 { uint64_t e[2]; };
|
||||
|
||||
// NOTE: DN_FNV1A //////////////////////////////////////////////////////////////////////////////////
|
||||
DN_API uint32_t DN_FNV1A32_Hash (void const *bytes, DN_USize size);
|
||||
DN_API uint64_t DN_FNV1A64_Hash (void const *bytes, DN_USize size);
|
||||
DN_API uint32_t DN_FNV1A32_Iterate (void const *bytes, DN_USize size, uint32_t hash);
|
||||
DN_API uint64_t DN_FNV1A64_Iterate (void const *bytes, DN_USize size, uint64_t hash);
|
||||
|
||||
// NOTE: DN_MurmurHash3 ////////////////////////////////////////////////////////////////////////////
|
||||
DN_API uint32_t DN_MurmurHash3_x86U32 (void const *key, int len, uint32_t seed);
|
||||
DN_API DN_MurmurHash3 DN_MurmurHash3_x64U128 (void const *key, int len, uint32_t seed);
|
||||
#define DN_MurmurHash3_x64U128AsU64(key, len, seed) (DN_MurmurHash3_x64U128(key, len, seed).e[0])
|
||||
#define DN_MurmurHash3_x64U128AsU32(key, len, seed) (DN_CAST(uint32_t)DN_MurmurHash3_x64U128(key, len, seed).e[0])
|
||||
|
||||
#endif // !defined(DN_HASH_H)
|
||||
@@ -0,0 +1,374 @@
|
||||
#define DN_HELPERS_CPP
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\
|
||||
// $$ | $$ |$$ _____|$$ | $$ __$$\ $$ _____|$$ __$$\ $$ __$$\
|
||||
// $$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ | $$ |$$ / \__|
|
||||
// $$$$$$$$ |$$$$$\ $$ | $$$$$$$ |$$$$$\ $$$$$$$ |\$$$$$$\
|
||||
// $$ __$$ |$$ __| $$ | $$ ____/ $$ __| $$ __$$< \____$$\
|
||||
// $$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |$$\ $$ |
|
||||
// $$ | $$ |$$$$$$$$\ $$$$$$$$\ $$ | $$$$$$$$\ $$ | $$ |\$$$$$$ |
|
||||
// \__| \__|\________|\________|\__| \________|\__| \__| \______/
|
||||
//
|
||||
// dn_helpers.cpp
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
// NOTE: DN_PCG32 //////////////////////////////////////////////////////////////////////////////////
|
||||
#define DN_PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL
|
||||
#define DN_PCG_DEFAULT_INCREMENT_64 1442695040888963407ULL
|
||||
|
||||
DN_API DN_PCG32 DN_PCG32_Init(uint64_t seed)
|
||||
{
|
||||
DN_PCG32 result = {};
|
||||
DN_PCG32_Next(&result);
|
||||
result.state += seed;
|
||||
DN_PCG32_Next(&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API uint32_t DN_PCG32_Next(DN_PCG32 *rng)
|
||||
{
|
||||
uint64_t state = rng->state;
|
||||
rng->state = state * DN_PCG_DEFAULT_MULTIPLIER_64 + DN_PCG_DEFAULT_INCREMENT_64;
|
||||
|
||||
// XSH-RR
|
||||
uint32_t value = (uint32_t)((state ^ (state >> 18)) >> 27);
|
||||
int rot = state >> 59;
|
||||
return rot ? (value >> rot) | (value << (32 - rot)) : value;
|
||||
}
|
||||
|
||||
DN_API uint64_t DN_PCG32_Next64(DN_PCG32 *rng)
|
||||
{
|
||||
uint64_t value = DN_PCG32_Next(rng);
|
||||
value <<= 32;
|
||||
value |= DN_PCG32_Next(rng);
|
||||
return value;
|
||||
}
|
||||
|
||||
DN_API uint32_t DN_PCG32_Range(DN_PCG32 *rng, uint32_t low, uint32_t high)
|
||||
{
|
||||
uint32_t bound = high - low;
|
||||
uint32_t threshold = -(int32_t)bound % bound;
|
||||
|
||||
for (;;) {
|
||||
uint32_t r = DN_PCG32_Next(rng);
|
||||
if (r >= threshold)
|
||||
return low + (r % bound);
|
||||
}
|
||||
}
|
||||
|
||||
DN_API float DN_PCG32_NextF32(DN_PCG32 *rng)
|
||||
{
|
||||
uint32_t x = DN_PCG32_Next(rng);
|
||||
return (float)(int32_t)(x >> 8) * 0x1.0p-24f;
|
||||
}
|
||||
|
||||
DN_API double DN_PCG32_NextF64(DN_PCG32 *rng)
|
||||
{
|
||||
uint64_t x = DN_PCG32_Next64(rng);
|
||||
return (double)(int64_t)(x >> 11) * 0x1.0p-53;
|
||||
}
|
||||
|
||||
DN_API void DN_PCG32_Advance(DN_PCG32 *rng, uint64_t delta)
|
||||
{
|
||||
uint64_t cur_mult = DN_PCG_DEFAULT_MULTIPLIER_64;
|
||||
uint64_t cur_plus = DN_PCG_DEFAULT_INCREMENT_64;
|
||||
|
||||
uint64_t acc_mult = 1;
|
||||
uint64_t acc_plus = 0;
|
||||
|
||||
while (delta != 0) {
|
||||
if (delta & 1) {
|
||||
acc_mult *= cur_mult;
|
||||
acc_plus = acc_plus * cur_mult + cur_plus;
|
||||
}
|
||||
cur_plus = (cur_mult + 1) * cur_plus;
|
||||
cur_mult *= cur_mult;
|
||||
delta >>= 1;
|
||||
}
|
||||
|
||||
rng->state = acc_mult * rng->state + acc_plus;
|
||||
}
|
||||
|
||||
#if !defined(DN_NO_JSON_BUILDER)
|
||||
// NOTE: DN_JSONBuilder ////////////////////////////////////////////////////////////////////////////
|
||||
DN_API DN_JSONBuilder DN_JSONBuilder_Init(DN_Arena *arena, int spaces_per_indent)
|
||||
{
|
||||
DN_JSONBuilder result = {};
|
||||
result.spaces_per_indent = spaces_per_indent;
|
||||
result.string_builder.arena = arena;
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API DN_Str8 DN_JSONBuilder_Build(DN_JSONBuilder const *builder, DN_Arena *arena)
|
||||
{
|
||||
DN_Str8 result = DN_Str8Builder_Build(&builder->string_builder, arena);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_KeyValue(DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value)
|
||||
{
|
||||
if (key.size == 0 && value.size == 0)
|
||||
return;
|
||||
|
||||
DN_JSONBuilderItem item = DN_JSONBuilderItem_KeyValue;
|
||||
if (value.size >= 1) {
|
||||
if (value.data[0] == '{' || value.data[0] == '[')
|
||||
item = DN_JSONBuilderItem_OpenContainer;
|
||||
else if (value.data[0] == '}' || value.data[0] == ']')
|
||||
item = DN_JSONBuilderItem_CloseContainer;
|
||||
}
|
||||
|
||||
bool adding_to_container_with_items =
|
||||
item != DN_JSONBuilderItem_CloseContainer && (builder->last_item == DN_JSONBuilderItem_KeyValue ||
|
||||
builder->last_item == DN_JSONBuilderItem_CloseContainer);
|
||||
|
||||
uint8_t prefix_size = 0;
|
||||
char prefix[2] = {0};
|
||||
if (adding_to_container_with_items)
|
||||
prefix[prefix_size++] = ',';
|
||||
|
||||
if (builder->last_item != DN_JSONBuilderItem_Empty)
|
||||
prefix[prefix_size++] = '\n';
|
||||
|
||||
if (item == DN_JSONBuilderItem_CloseContainer)
|
||||
builder->indent_level--;
|
||||
|
||||
int spaces_per_indent = builder->spaces_per_indent ? builder->spaces_per_indent : 2;
|
||||
int spaces = builder->indent_level * spaces_per_indent;
|
||||
|
||||
if (key.size)
|
||||
DN_Str8Builder_AppendF(&builder->string_builder,
|
||||
"%.*s%*c\"%.*s\": %.*s",
|
||||
prefix_size,
|
||||
prefix,
|
||||
spaces,
|
||||
' ',
|
||||
DN_STR_FMT(key),
|
||||
DN_STR_FMT(value));
|
||||
else if (spaces == 0)
|
||||
DN_Str8Builder_AppendF(&builder->string_builder, "%.*s%.*s", prefix_size, prefix, DN_STR_FMT(value));
|
||||
else
|
||||
DN_Str8Builder_AppendF(&builder->string_builder, "%.*s%*c%.*s", prefix_size, prefix, spaces, ' ', DN_STR_FMT(value));
|
||||
|
||||
if (item == DN_JSONBuilderItem_OpenContainer)
|
||||
builder->indent_level++;
|
||||
|
||||
builder->last_item = item;
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_KeyValueFV(DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, va_list args)
|
||||
{
|
||||
DN_OSTLSTMem tmem = DN_OS_TLSTMem(builder->string_builder.arena);
|
||||
DN_Str8 value = DN_Str8_InitFV(tmem.arena, value_fmt, args);
|
||||
DN_JSONBuilder_KeyValue(builder, key, value);
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_KeyValueF(DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, value_fmt);
|
||||
DN_JSONBuilder_KeyValueFV(builder, key, value_fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_ObjectBeginNamed(DN_JSONBuilder *builder, DN_Str8 name)
|
||||
{
|
||||
DN_JSONBuilder_KeyValue(builder, name, DN_STR8("{"));
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_ObjectEnd(DN_JSONBuilder *builder)
|
||||
{
|
||||
DN_JSONBuilder_KeyValue(builder, DN_STR8(""), DN_STR8("}"));
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_ArrayBeginNamed(DN_JSONBuilder *builder, DN_Str8 name)
|
||||
{
|
||||
DN_JSONBuilder_KeyValue(builder, name, DN_STR8("["));
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_ArrayEnd(DN_JSONBuilder *builder)
|
||||
{
|
||||
DN_JSONBuilder_KeyValue(builder, DN_STR8(""), DN_STR8("]"));
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_Str8Named(DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value)
|
||||
{
|
||||
DN_JSONBuilder_KeyValueF(builder, key, "\"%.*s\"", value.size, value.data);
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_LiteralNamed(DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value)
|
||||
{
|
||||
DN_JSONBuilder_KeyValueF(builder, key, "%.*s", value.size, value.data);
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_U64Named(DN_JSONBuilder *builder, DN_Str8 key, uint64_t value)
|
||||
{
|
||||
DN_JSONBuilder_KeyValueF(builder, key, "%I64u", value);
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_I64Named(DN_JSONBuilder *builder, DN_Str8 key, int64_t value)
|
||||
{
|
||||
DN_JSONBuilder_KeyValueF(builder, key, "%I64d", value);
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_F64Named(DN_JSONBuilder *builder, DN_Str8 key, double value, int decimal_places)
|
||||
{
|
||||
if (!builder)
|
||||
return;
|
||||
|
||||
if (decimal_places >= 16)
|
||||
decimal_places = 16;
|
||||
|
||||
// NOTE: Generate the format string for the float, depending on how many
|
||||
// decimals places it wants.
|
||||
char float_fmt[16];
|
||||
if (decimal_places > 0) {
|
||||
// NOTE: Emit the format string "%.<decimal_places>f" i.e. %.1f
|
||||
DN_SNPrintF(float_fmt, sizeof(float_fmt), "%%.%df", decimal_places);
|
||||
} else {
|
||||
// NOTE: Emit the format string "%f"
|
||||
DN_SNPrintF(float_fmt, sizeof(float_fmt), "%%f");
|
||||
}
|
||||
DN_JSONBuilder_KeyValueF(builder, key, float_fmt, value);
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_BoolNamed(DN_JSONBuilder *builder, DN_Str8 key, bool value)
|
||||
{
|
||||
DN_Str8 value_string = value ? DN_STR8("true") : DN_STR8("false");
|
||||
DN_JSONBuilder_KeyValueF(builder, key, "%.*s", value_string.size, value_string.data);
|
||||
}
|
||||
#endif // !defined(DN_NO_JSON_BUILDER)
|
||||
|
||||
// NOTE: DN_JobQueue ///////////////////////////////////////////////////////////////////////////////
|
||||
DN_API DN_JobQueueSPMC DN_OS_JobQueueSPMCInit()
|
||||
{
|
||||
DN_JobQueueSPMC result = {};
|
||||
result.thread_wait_for_job_semaphore = DN_OS_SemaphoreInit(0 /*initial_count*/);
|
||||
result.wait_for_completion_semaphore = DN_OS_SemaphoreInit(0 /*initial_count*/);
|
||||
result.complete_queue_write_semaphore = DN_OS_SemaphoreInit(DN_ArrayCountU(result.complete_queue));
|
||||
result.mutex = DN_OS_MutexInit();
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API bool DN_OS_JobQueueSPMCCanAdd(DN_JobQueueSPMC const *queue, uint32_t count)
|
||||
{
|
||||
uint32_t read_index = queue->read_index;
|
||||
uint32_t write_index = queue->write_index;
|
||||
uint32_t size = write_index - read_index;
|
||||
bool result = (size + count) <= DN_ArrayCountU(queue->jobs);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API bool DN_OS_JobQueueSPMCAddArray(DN_JobQueueSPMC *queue, DN_Job *jobs, uint32_t count)
|
||||
{
|
||||
if (!queue)
|
||||
return false;
|
||||
|
||||
uint32_t const pot_mask = DN_ArrayCountU(queue->jobs) - 1;
|
||||
uint32_t read_index = queue->read_index;
|
||||
uint32_t write_index = queue->write_index;
|
||||
uint32_t size = write_index - read_index;
|
||||
|
||||
if ((size + count) > DN_ArrayCountU(queue->jobs))
|
||||
return false;
|
||||
|
||||
for (size_t offset = 0; offset < count; offset++) {
|
||||
uint32_t wrapped_write_index = (write_index + offset) & pot_mask;
|
||||
queue->jobs[wrapped_write_index] = jobs[offset];
|
||||
}
|
||||
|
||||
DN_OS_MutexLock(&queue->mutex);
|
||||
queue->write_index += count;
|
||||
DN_OS_SemaphoreIncrement(&queue->thread_wait_for_job_semaphore, count);
|
||||
DN_OS_MutexUnlock(&queue->mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
DN_API bool DN_OS_JobQueueSPMCAdd(DN_JobQueueSPMC *queue, DN_Job job)
|
||||
{
|
||||
bool result = DN_OS_JobQueueSPMCAddArray(queue, &job, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API int32_t DN_OS_JobQueueSPMCThread(DN_OSThread *thread)
|
||||
{
|
||||
DN_JobQueueSPMC *queue = DN_CAST(DN_JobQueueSPMC *) thread->user_context;
|
||||
uint32_t const pot_mask = DN_ArrayCountU(queue->jobs) - 1;
|
||||
static_assert(DN_ArrayCountU(queue->jobs) == DN_ArrayCountU(queue->complete_queue), "PoT mask is used to mask access to both arrays");
|
||||
|
||||
for (;;) {
|
||||
DN_OS_SemaphoreWait(&queue->thread_wait_for_job_semaphore, DN_OS_SEMAPHORE_INFINITE_TIMEOUT);
|
||||
if (queue->quit)
|
||||
break;
|
||||
|
||||
DN_Assert(queue->read_index != queue->write_index);
|
||||
|
||||
DN_OS_MutexLock(&queue->mutex);
|
||||
uint32_t wrapped_read_index = queue->read_index & pot_mask;
|
||||
DN_Job job = queue->jobs[wrapped_read_index];
|
||||
queue->read_index += 1;
|
||||
DN_OS_MutexUnlock(&queue->mutex);
|
||||
|
||||
job.elapsed_tsc -= DN_CPU_TSC();
|
||||
job.func(thread, job.user_context);
|
||||
job.elapsed_tsc += DN_CPU_TSC();
|
||||
|
||||
if (job.add_to_completion_queue) {
|
||||
DN_OS_SemaphoreWait(&queue->complete_queue_write_semaphore, DN_OS_SEMAPHORE_INFINITE_TIMEOUT);
|
||||
DN_OS_MutexLock(&queue->mutex);
|
||||
queue->complete_queue[(queue->complete_write_index++ & pot_mask)] = job;
|
||||
DN_OS_MutexUnlock(&queue->mutex);
|
||||
DN_OS_SemaphoreIncrement(&queue->complete_queue_write_semaphore, 1);
|
||||
}
|
||||
|
||||
// NOTE: Update finish counter
|
||||
DN_OS_MutexLock(&queue->mutex);
|
||||
queue->finish_index += 1;
|
||||
|
||||
// NOTE: If all jobs are finished and we have another thread who is
|
||||
// blocked via `WaitForCompletion` for this job queue, we will go
|
||||
// release the semaphore to wake them all up.
|
||||
bool all_jobs_finished = queue->finish_index == queue->write_index;
|
||||
if (all_jobs_finished && queue->threads_waiting_for_completion) {
|
||||
DN_OS_SemaphoreIncrement(&queue->wait_for_completion_semaphore,
|
||||
queue->threads_waiting_for_completion);
|
||||
queue->threads_waiting_for_completion = 0;
|
||||
}
|
||||
DN_OS_MutexUnlock(&queue->mutex);
|
||||
}
|
||||
|
||||
return queue->quit_exit_code;
|
||||
}
|
||||
|
||||
DN_API void DN_OS_JobQueueSPMCWaitForCompletion(DN_JobQueueSPMC *queue)
|
||||
{
|
||||
DN_OS_MutexLock(&queue->mutex);
|
||||
if (queue->finish_index == queue->write_index) {
|
||||
DN_OS_MutexUnlock(&queue->mutex);
|
||||
return;
|
||||
}
|
||||
queue->threads_waiting_for_completion++;
|
||||
DN_OS_MutexUnlock(&queue->mutex);
|
||||
|
||||
DN_OS_SemaphoreWait(&queue->wait_for_completion_semaphore, DN_OS_SEMAPHORE_INFINITE_TIMEOUT);
|
||||
}
|
||||
|
||||
DN_API DN_USize DN_OS_JobQueueSPMCGetFinishedJobs(DN_JobQueueSPMC *queue, DN_Job *jobs, DN_USize jobs_size)
|
||||
{
|
||||
DN_USize result = 0;
|
||||
if (!queue || !jobs || jobs_size <= 0)
|
||||
return result;
|
||||
|
||||
uint32_t const pot_mask = DN_ArrayCountU(queue->jobs) - 1;
|
||||
DN_OS_MutexLock(&queue->mutex);
|
||||
while (queue->complete_read_index < queue->complete_write_index && result < jobs_size)
|
||||
jobs[result++] = queue->complete_queue[(queue->complete_read_index++ & pot_mask)];
|
||||
DN_OS_MutexUnlock(&queue->mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
#if !defined(DN_HELPERS_H)
|
||||
#define DN_HELPERS_H
|
||||
|
||||
#if !defined(DN_BASE_H)
|
||||
#error dn_base_inc.h must be included before this
|
||||
#endif
|
||||
|
||||
#if !defined(DN_MATH_H)
|
||||
#error dn_math.h must be included before this
|
||||
#endif
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\
|
||||
// $$ | $$ |$$ _____|$$ | $$ __$$\ $$ _____|$$ __$$\ $$ __$$\
|
||||
// $$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ | $$ |$$ / \__|
|
||||
// $$$$$$$$ |$$$$$\ $$ | $$$$$$$ |$$$$$\ $$$$$$$ |\$$$$$$\
|
||||
// $$ __$$ |$$ __| $$ | $$ ____/ $$ __| $$ __$$< \____$$\
|
||||
// $$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |$$\ $$ |
|
||||
// $$ | $$ |$$$$$$$$\ $$$$$$$$\ $$ | $$$$$$$$\ $$ | $$ |\$$$$$$ |
|
||||
// \__| \__|\________|\________|\__| \________|\__| \__| \______/
|
||||
//
|
||||
// dn_helpers.h -- Helper functions/data structures
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
// NOTE: DN_PCG32 //////////////////////////////////////////////////////////////////////////////////
|
||||
struct DN_PCG32 { uint64_t state; };
|
||||
|
||||
#if !defined(DN_NO_JSON_BUILDER)
|
||||
// NOTE: DN_JSONBuilder ////////////////////////////////////////////////////////////////////////////
|
||||
enum DN_JSONBuilderItem
|
||||
{
|
||||
DN_JSONBuilderItem_Empty,
|
||||
DN_JSONBuilderItem_OpenContainer,
|
||||
DN_JSONBuilderItem_CloseContainer,
|
||||
DN_JSONBuilderItem_KeyValue,
|
||||
};
|
||||
|
||||
struct DN_JSONBuilder
|
||||
{
|
||||
bool use_stdout; // When set, ignore the string builder and dump immediately to stdout
|
||||
DN_Str8Builder string_builder; // (Internal)
|
||||
int indent_level; // (Internal)
|
||||
int spaces_per_indent; // The number of spaces per indent level
|
||||
DN_JSONBuilderItem last_item;
|
||||
};
|
||||
#endif // !defined(DN_NO_JSON_BUIDLER)
|
||||
|
||||
// NOTE: DN_BinarySearch ///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs);
|
||||
|
||||
template <typename T>
|
||||
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
|
||||
|
||||
enum DN_BinarySearchType
|
||||
{
|
||||
// Index of the match. If no match is found, found is set to false and the
|
||||
// index is set to the index where the match should be inserted/exist, if
|
||||
// it were in the array
|
||||
DN_BinarySearchType_Match,
|
||||
|
||||
// Index of the first element in the array that is `element >= find`. If no such
|
||||
// item is found or the array is empty, then, the index is set to the array
|
||||
// size and found is set to `false`.
|
||||
//
|
||||
// For example:
|
||||
// int array[] = {0, 1, 2, 3, 4, 5};
|
||||
// DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_LowerBound);
|
||||
// printf("%zu\n", result.index); // Prints index '4'
|
||||
|
||||
DN_BinarySearchType_LowerBound,
|
||||
|
||||
// Index of the first element in the array that is `element > find`. If no such
|
||||
// item is found or the array is empty, then, the index is set to the array
|
||||
// size and found is set to `false`.
|
||||
//
|
||||
// For example:
|
||||
// int array[] = {0, 1, 2, 3, 4, 5};
|
||||
// DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_UpperBound);
|
||||
// printf("%zu\n", result.index); // Prints index '5'
|
||||
|
||||
DN_BinarySearchType_UpperBound,
|
||||
};
|
||||
|
||||
struct DN_BinarySearchResult
|
||||
{
|
||||
bool found;
|
||||
DN_USize index;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using DN_QSortLessThanProc = bool(T const &a, T const &b, void *user_context);
|
||||
|
||||
// NOTE: Misc //////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: DN_JobQueue ///////////////////////////////////////////////////////////////////////////////
|
||||
typedef void(DN_JobQueueFunc)(DN_OSThread *thread, void *user_context);
|
||||
struct DN_Job
|
||||
{
|
||||
DN_JobQueueFunc *func; // The function to invoke for the job
|
||||
void *user_context; // Pointer user can set to use in their `job_func`
|
||||
uint64_t elapsed_tsc;
|
||||
uint16_t user_tag; // Arbitrary value the user can set to identiy the type of `user_context` this job has
|
||||
bool add_to_completion_queue; // When true, on job completion, job must be dequeued from the completion queue via `GetFinishedJobs`
|
||||
};
|
||||
|
||||
#if !defined(DN_JOB_QUEUE_SPMC_SIZE)
|
||||
#define DN_JOB_QUEUE_SPMC_SIZE 128
|
||||
#endif
|
||||
|
||||
struct DN_JobQueueSPMC
|
||||
{
|
||||
DN_OSMutex mutex;
|
||||
DN_OSSemaphore thread_wait_for_job_semaphore;
|
||||
DN_OSSemaphore wait_for_completion_semaphore;
|
||||
DN_U32 threads_waiting_for_completion;
|
||||
|
||||
DN_Job jobs[DN_JOB_QUEUE_SPMC_SIZE];
|
||||
DN_B32 quit;
|
||||
DN_U32 quit_exit_code;
|
||||
DN_U32 volatile read_index;
|
||||
DN_U32 volatile finish_index;
|
||||
DN_U32 volatile write_index;
|
||||
|
||||
DN_OSSemaphore complete_queue_write_semaphore;
|
||||
DN_Job complete_queue[DN_JOB_QUEUE_SPMC_SIZE];
|
||||
DN_U32 volatile complete_read_index;
|
||||
DN_U32 volatile complete_write_index;
|
||||
};
|
||||
|
||||
// NOTE: DN_PCG32 //////////////////////////////////////////////////////////////////////////////////
|
||||
DN_API DN_PCG32 DN_PCG32_Init (uint64_t seed);
|
||||
DN_API uint32_t DN_PCG32_Next (DN_PCG32 *rng);
|
||||
DN_API uint64_t DN_PCG32_Next64 (DN_PCG32 *rng);
|
||||
DN_API uint32_t DN_PCG32_Range (DN_PCG32 *rng, uint32_t low, uint32_t high);
|
||||
DN_API DN_F32 DN_PCG32_NextF32 (DN_PCG32 *rng);
|
||||
DN_API DN_F64 DN_PCG32_NextF64 (DN_PCG32 *rng);
|
||||
DN_API void DN_PCG32_Advance (DN_PCG32 *rng, uint64_t delta);
|
||||
|
||||
#if !defined(DN_NO_JSON_BUILDER)
|
||||
// NOTE: DN_JSONBuilder ////////////////////////////////////////////////////////////////////////////
|
||||
#define DN_JSONBuilder_Object(builder) \
|
||||
DN_DeferLoop(DN_JSONBuilder_ObjectBegin(builder), \
|
||||
DN_JSONBuilder_ObjectEnd(builder))
|
||||
|
||||
#define DN_JSONBuilder_ObjectNamed(builder, name) \
|
||||
DN_DeferLoop(DN_JSONBuilder_ObjectBeginNamed(builder, name), \
|
||||
DN_JSONBuilder_ObjectEnd(builder))
|
||||
|
||||
#define DN_JSONBuilder_Array(builder) \
|
||||
DN_DeferLoop(DN_JSONBuilder_ArrayBegin(builder), \
|
||||
DN_JSONBuilder_ArrayEnd(builder))
|
||||
|
||||
#define DN_JSONBuilder_ArrayNamed(builder, name) \
|
||||
DN_DeferLoop(DN_JSONBuilder_ArrayBeginNamed(builder, name), \
|
||||
DN_JSONBuilder_ArrayEnd(builder))
|
||||
|
||||
DN_API DN_JSONBuilder DN_JSONBuilder_Init (DN_Arena *arena, int spaces_per_indent);
|
||||
DN_API DN_Str8 DN_JSONBuilder_Build (DN_JSONBuilder const *builder, DN_Arena *arena);
|
||||
DN_API void DN_JSONBuilder_KeyValue (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value);
|
||||
DN_API void DN_JSONBuilder_KeyValueF (DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, ...);
|
||||
DN_API void DN_JSONBuilder_ObjectBeginNamed (DN_JSONBuilder *builder, DN_Str8 name);
|
||||
DN_API void DN_JSONBuilder_ObjectEnd (DN_JSONBuilder *builder);
|
||||
DN_API void DN_JSONBuilder_ArrayBeginNamed (DN_JSONBuilder *builder, DN_Str8 name);
|
||||
DN_API void DN_JSONBuilder_ArrayEnd (DN_JSONBuilder *builder);
|
||||
DN_API void DN_JSONBuilder_Str8Named (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value);
|
||||
DN_API void DN_JSONBuilder_LiteralNamed (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value);
|
||||
DN_API void DN_JSONBuilder_U64Named (DN_JSONBuilder *builder, DN_Str8 key, uint64_t value);
|
||||
DN_API void DN_JSONBuilder_I64Named (DN_JSONBuilder *builder, DN_Str8 key, int64_t value);
|
||||
DN_API void DN_JSONBuilder_F64Named (DN_JSONBuilder *builder, DN_Str8 key, double value, int decimal_places);
|
||||
DN_API void DN_JSONBuilder_BoolNamed (DN_JSONBuilder *builder, DN_Str8 key, bool value);
|
||||
|
||||
#define DN_JSONBuilder_ObjectBegin(builder) DN_JSONBuilder_ObjectBeginNamed(builder, DN_STR8(""))
|
||||
#define DN_JSONBuilder_ArrayBegin(builder) DN_JSONBuilder_ArrayBeginNamed(builder, DN_STR8(""))
|
||||
#define DN_JSONBuilder_Str8(builder, value) DN_JSONBuilder_Str8Named(builder, DN_STR8(""), value)
|
||||
#define DN_JSONBuilder_Literal(builder, value) DN_JSONBuilder_LiteralNamed(builder, DN_STR8(""), value)
|
||||
#define DN_JSONBuilder_U64(builder, value) DN_JSONBuilder_U64Named(builder, DN_STR8(""), value)
|
||||
#define DN_JSONBuilder_I64(builder, value) DN_JSONBuilder_I64Named(builder, DN_STR8(""), value)
|
||||
#define DN_JSONBuilder_F64(builder, value) DN_JSONBuilder_F64Named(builder, DN_STR8(""), value)
|
||||
#define DN_JSONBuilder_Bool(builder, value) DN_JSONBuilder_BoolNamed(builder, DN_STR8(""), value)
|
||||
#endif // !defined(DN_NO_JSON_BUILDER)
|
||||
|
||||
// NOTE: DN_BinarySearch ///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T> bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
|
||||
template <typename T> DN_BinarySearchResult DN_BinarySearch (T const *array,
|
||||
DN_USize array_size,
|
||||
T const &find,
|
||||
DN_BinarySearchType type = DN_BinarySearchType_Match,
|
||||
DN_BinarySearchLessThanProc<T> less_than = DN_BinarySearch_DefaultLessThan);
|
||||
|
||||
// NOTE: DN_QSort //////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T> bool DN_QSort_DefaultLessThan(T const &lhs, T const &rhs);
|
||||
template <typename T> void DN_QSort (T *array,
|
||||
DN_USize array_size,
|
||||
void *user_context,
|
||||
DN_QSortLessThanProc<T> less_than = DN_QSort_DefaultLessThan);
|
||||
|
||||
// NOTE: DN_JobQueue ///////////////////////////////////////////////////////////////////////////////
|
||||
DN_API DN_JobQueueSPMC DN_OS_JobQueueSPMCInit ();
|
||||
DN_API bool DN_OS_JobQueueSPMCCanAdd (DN_JobQueueSPMC const *queue, uint32_t count);
|
||||
DN_API bool DN_OS_JobQueueSPMCAddArray (DN_JobQueueSPMC *queue, DN_Job *jobs, uint32_t count);
|
||||
DN_API bool DN_OS_JobQueueSPMCAdd (DN_JobQueueSPMC *queue, DN_Job job);
|
||||
DN_API void DN_OS_JobQueueSPMCWaitForCompletion (DN_JobQueueSPMC *queue);
|
||||
DN_API int32_t DN_OS_JobQueueSPMCThread (DN_OSThread *thread);
|
||||
DN_API DN_USize DN_OS_JobQueueSPMCGetFinishedJobs (DN_JobQueueSPMC *queue, DN_Job *jobs, DN_USize jobs_size);
|
||||
|
||||
// NOTE: DN_BinarySearch ///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs)
|
||||
{
|
||||
bool result = lhs < rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DN_BinarySearchResult DN_BinarySearch(T const *array,
|
||||
DN_USize array_size,
|
||||
T const &find,
|
||||
DN_BinarySearchType type,
|
||||
DN_BinarySearchLessThanProc<T> less_than)
|
||||
{
|
||||
DN_BinarySearchResult result = {};
|
||||
if (!array || array_size <= 0 || !less_than)
|
||||
return result;
|
||||
|
||||
T const *end = array + array_size;
|
||||
T const *first = array;
|
||||
T const *last = end;
|
||||
while (first != last) {
|
||||
DN_USize count = last - first;
|
||||
T const *it = first + (count / 2);
|
||||
|
||||
bool advance_first = false;
|
||||
if (type == DN_BinarySearchType_UpperBound)
|
||||
advance_first = !less_than(find, it[0]);
|
||||
else
|
||||
advance_first = less_than(it[0], find);
|
||||
|
||||
if (advance_first)
|
||||
first = it + 1;
|
||||
else
|
||||
last = it;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case DN_BinarySearchType_Match: {
|
||||
result.found = first != end && !less_than(find, *first);
|
||||
} break;
|
||||
|
||||
case DN_BinarySearchType_LowerBound: /*FALLTHRU*/
|
||||
case DN_BinarySearchType_UpperBound: {
|
||||
result.found = first != end;
|
||||
} break;
|
||||
}
|
||||
|
||||
result.index = first - array;
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: DN_QSort //////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
bool DN_QSort_DefaultLessThan(T const &lhs, T const &rhs, void *user_context)
|
||||
{
|
||||
(void)user_context;
|
||||
bool result = lhs < rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void DN_QSort(T *array, DN_USize array_size, void *user_context, DN_QSortLessThanProc<T> less_than)
|
||||
{
|
||||
if (!array || array_size <= 1 || !less_than)
|
||||
return;
|
||||
|
||||
// NOTE: Insertion Sort, under 24->32 is an optimal amount /////////////////////////////////////
|
||||
const DN_USize QSORT_THRESHOLD = 24;
|
||||
if (array_size < QSORT_THRESHOLD) {
|
||||
for (DN_USize item_to_insert_index = 1; item_to_insert_index < array_size; item_to_insert_index++) {
|
||||
for (DN_USize index = 0; index < item_to_insert_index; index++) {
|
||||
if (!less_than(array[index], array[item_to_insert_index], user_context)) {
|
||||
T item_to_insert = array[item_to_insert_index];
|
||||
for (DN_USize i = item_to_insert_index; i > index; i--)
|
||||
array[i] = array[i - 1];
|
||||
|
||||
array[index] = item_to_insert;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: Quick sort, under 24->32 is an optimal amount /////////////////////////////////////////
|
||||
DN_USize last_index = array_size - 1;
|
||||
DN_USize pivot_index = array_size / 2;
|
||||
DN_USize partition_index = 0;
|
||||
DN_USize start_index = 0;
|
||||
|
||||
// Swap pivot with last index, so pivot is always at the end of the array.
|
||||
// This makes logic much simpler.
|
||||
DN_Swap(array[last_index], array[pivot_index]);
|
||||
pivot_index = last_index;
|
||||
|
||||
// 4^, 8, 7, 5, 2, 3, 6
|
||||
if (less_than(array[start_index], array[pivot_index], user_context))
|
||||
partition_index++;
|
||||
start_index++;
|
||||
|
||||
// 4, |8, 7, 5^, 2, 3, 6*
|
||||
// 4, 5, |7, 8, 2^, 3, 6*
|
||||
// 4, 5, 2, |8, 7, ^3, 6*
|
||||
// 4, 5, 2, 3, |7, 8, ^6*
|
||||
for (DN_USize index = start_index; index < last_index; index++) {
|
||||
if (less_than(array[index], array[pivot_index], user_context)) {
|
||||
DN_Swap(array[partition_index], array[index]);
|
||||
partition_index++;
|
||||
}
|
||||
}
|
||||
|
||||
// Move pivot to right of partition
|
||||
// 4, 5, 2, 3, |6, 8, ^7*
|
||||
DN_Swap(array[partition_index], array[pivot_index]);
|
||||
DN_QSort(array, partition_index, user_context, less_than);
|
||||
|
||||
// Skip the value at partion index since that is guaranteed to be sorted.
|
||||
// 4, 5, 2, 3, (x), 8, 7
|
||||
DN_USize one_after_partition_index = partition_index + 1;
|
||||
DN_QSort(array + one_after_partition_index, (array_size - one_after_partition_index), user_context, less_than);
|
||||
}
|
||||
|
||||
#endif // !defined(DN_HELPERS_H)
|
||||
@@ -0,0 +1,428 @@
|
||||
#define DN_JSON_CPP
|
||||
|
||||
// NOTE: DN_JSON //////////////////////////////////////////////////////////////////////////////////
|
||||
void *DN_JSON_ArenaAllocFunc(void *user_data, size_t count)
|
||||
{
|
||||
void *result = NULL;
|
||||
if (!user_data)
|
||||
return result;
|
||||
|
||||
DN_Arena *arena = DN_CAST(DN_Arena*)user_data;
|
||||
result = DN_Arena_Alloc(arena, count, alignof(json_value_s), DN_ZeroMem_No);
|
||||
return result;
|
||||
}
|
||||
|
||||
char const *DN_JSON_TypeEnumCString(json_type_e type, size_t *size)
|
||||
{
|
||||
switch (type) {
|
||||
case json_type_string: { if (size) { *size = sizeof("string") - 1; } return "string"; }
|
||||
case json_type_number: { if (size) { *size = sizeof("number") - 1; } return "number"; }
|
||||
case json_type_object: { if (size) { *size = sizeof("object") - 1; } return "object"; }
|
||||
case json_type_array: { if (size) { *size = sizeof("array") - 1; } return "array"; }
|
||||
case json_type_true: { if (size) { *size = sizeof("true (boolean)") - 1; } return "true (boolean)"; }
|
||||
case json_type_false: { if (size) { *size = sizeof("false (boolean)") - 1; } return "false (boolean)"; }
|
||||
|
||||
default: /*FALLTHRU*/
|
||||
case json_type_null: { if (size) { *size = sizeof("(null)") - 1; } return "(null)"; }
|
||||
}
|
||||
}
|
||||
|
||||
bool DN_JSON_String8Cmp(json_string_s const *lhs, DN_Str8 key)
|
||||
{
|
||||
bool result = false;
|
||||
if (lhs && DN_Str8_HasData(key)) {
|
||||
DN_Str8 lhs_string = DN_Str8_Init(lhs->string, lhs->string_size);
|
||||
result = DN_Str8_Eq(lhs_string, key);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: DN_JSON_It ///////////////////////////////////////////////////////////////////////////////
|
||||
DN_JSONIt DN_JSON_LoadFileToIt(DN_Arena *arena, DN_Str8 json)
|
||||
{
|
||||
json_parse_result_s parse_result = {};
|
||||
json_value_ex_s *ex_value =
|
||||
DN_CAST(json_value_ex_s *) json_parse_ex(json.data,
|
||||
json.size,
|
||||
json_parse_flags_allow_location_information,
|
||||
DN_JSON_ArenaAllocFunc,
|
||||
arena,
|
||||
&parse_result);
|
||||
|
||||
DN_JSONIt result = {};
|
||||
DN_JSON_ItPushValue(&result, &ex_value->value);
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: DN_JSON_ItPush/Pop ///////////////////////////////////////////////////////////////////////
|
||||
bool DN_JSON_ItPushObjElement(DN_JSONIt *it, json_object_element_s *element)
|
||||
{
|
||||
if (!it || !element)
|
||||
return false;
|
||||
DN_Assert(it->stack_count < DN_ArrayCountI(it->stack));
|
||||
it->stack[it->stack_count++] = {DN_JSON_ItEntryTypeObjElement, element};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DN_JSON_ItPushObj(DN_JSONIt *it, json_object_s *obj)
|
||||
{
|
||||
if (!it || !obj)
|
||||
return false;
|
||||
DN_Assert(it->stack_count < DN_ArrayCountI(it->stack));
|
||||
it->stack[it->stack_count++] = {DN_JSON_ItEntryTypeObj, obj};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DN_JSON_ItPushArrayElement(DN_JSONIt *it, json_array_element_s *element)
|
||||
{
|
||||
if (!it || !element)
|
||||
return false;
|
||||
DN_Assert(it->stack_count < DN_ArrayCountI(it->stack));
|
||||
it->stack[it->stack_count++] = {DN_JSON_ItEntryTypeArrayElement, element};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DN_JSON_ItPushArray(DN_JSONIt *it, json_value_s *value)
|
||||
{
|
||||
if (!it || !value || json_value_as_array(value) == nullptr)
|
||||
return false;
|
||||
DN_Assert(it->stack_count < DN_ArrayCountI(it->stack));
|
||||
it->stack[it->stack_count++] = {DN_JSON_ItEntryTypeArray, value};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DN_JSON_ItPushValue(DN_JSONIt *it, json_value_s *value)
|
||||
{
|
||||
bool result = false;
|
||||
if (!it || !value)
|
||||
return result;
|
||||
|
||||
if (value->type == json_type_object) {
|
||||
result = DN_JSON_ItPushObj(it, json_value_as_object(value));
|
||||
} else if (value->type == json_type_array) {
|
||||
result = DN_JSON_ItPushArray(it, value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DN_JSON_ItPop(DN_JSONIt *it)
|
||||
{
|
||||
if (!it)
|
||||
return;
|
||||
DN_Assert(it->stack_count > 0);
|
||||
if (it->stack_count > 0)
|
||||
it->stack_count--;
|
||||
}
|
||||
|
||||
// NOTE: DN_JSON_It JSON tree navigation //////////////////////////////////////////////////////////
|
||||
json_value_s *DN_JSON_ItPushCurrValue(DN_JSONIt *it)
|
||||
{
|
||||
json_value_s *result = nullptr;
|
||||
DN_JSONItEntry *curr = DN_JSON_ItCurr(it);
|
||||
if (!curr)
|
||||
return result;
|
||||
|
||||
if (curr->type == DN_JSON_ItEntryTypeObjElement) {
|
||||
json_object_element_s *element = DN_CAST(json_object_element_s *) curr->value;
|
||||
result = element->value;
|
||||
} else if (curr->type == DN_JSON_ItEntryTypeArrayElement) {
|
||||
json_array_element_s *element = DN_CAST(json_array_element_s *) curr->value;
|
||||
result = element->value;
|
||||
} else {
|
||||
result = DN_CAST(json_value_s *) curr->value;
|
||||
}
|
||||
|
||||
if (result->type == json_type_array) {
|
||||
json_array_s *array = json_value_as_array(result);
|
||||
DN_Assert(array);
|
||||
DN_JSON_ItPushArray(it, result);
|
||||
} else if (result->type == json_type_object) {
|
||||
json_object_s *obj = json_value_as_object(result);
|
||||
DN_Assert(obj);
|
||||
DN_JSON_ItPushObj(it, obj);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DN_JSON_ItNext(DN_JSONIt *it)
|
||||
{
|
||||
DN_JSONItEntry *curr = DN_JSON_ItCurr(it);
|
||||
if (!curr)
|
||||
return false;
|
||||
|
||||
json_object_element_s *obj_element = nullptr;
|
||||
json_array_element_s *array_element = nullptr;
|
||||
if (curr->type == DN_JSON_ItEntryTypeObj) {
|
||||
auto *obj = DN_CAST(json_object_s *) curr->value;
|
||||
obj_element = obj->start;
|
||||
} else if (curr->type == DN_JSON_ItEntryTypeObjElement) {
|
||||
auto *element = DN_CAST(json_object_element_s *) curr->value;
|
||||
obj_element = element->next;
|
||||
DN_JSON_ItPop(it);
|
||||
} else if (curr->type == DN_JSON_ItEntryTypeArray) {
|
||||
auto *value = DN_CAST(json_value_s *) curr->value;
|
||||
auto *array = json_value_as_array(value);
|
||||
array_element = array->start;
|
||||
} else if (curr->type == DN_JSON_ItEntryTypeArrayElement) {
|
||||
auto *element = DN_CAST(json_array_element_s *) curr->value;
|
||||
array_element = element->next;
|
||||
DN_JSON_ItPop(it);
|
||||
} else {
|
||||
DN_JSON_ItPop(it);
|
||||
}
|
||||
|
||||
if (obj_element)
|
||||
DN_JSON_ItPushObjElement(it, obj_element);
|
||||
else if (array_element)
|
||||
DN_JSON_ItPushArrayElement(it, array_element);
|
||||
|
||||
bool result = obj_element || array_element;
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: DN_JSON_ItCurr ///////////////////////////////////////////////////////////////////////////
|
||||
DN_JSONItEntry *DN_JSON_ItCurr(DN_JSONIt *it)
|
||||
{
|
||||
DN_JSONItEntry *result = nullptr;
|
||||
if (!it || it->stack_count <= 0)
|
||||
return result;
|
||||
|
||||
result = &it->stack[it->stack_count - 1];
|
||||
return result;
|
||||
}
|
||||
|
||||
json_value_s *DN_JSON_ItCurrValue(DN_JSONIt *it)
|
||||
{
|
||||
json_value_s *result = nullptr;
|
||||
DN_JSONItEntry *curr = DN_JSON_ItCurr(it);
|
||||
if (!curr)
|
||||
return result;
|
||||
|
||||
if (curr->type == DN_JSON_ItEntryTypeObjElement) {
|
||||
auto *element = DN_CAST(json_object_element_s *)curr->value;
|
||||
result = element->value;
|
||||
} else if (curr->type == DN_JSON_ItEntryTypeArrayElement) {
|
||||
auto *element = DN_CAST(json_array_element_s *)curr->value;
|
||||
result = element->value;
|
||||
} else if (curr->type == DN_JSON_ItEntryTypeString ||
|
||||
curr->type == DN_JSON_ItEntryTypeNumber ||
|
||||
curr->type == DN_JSON_ItEntryTypeObj ||
|
||||
curr->type == DN_JSON_ItEntryTypeArray)
|
||||
{
|
||||
result = DN_CAST(json_value_s *)curr->value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
json_object_element_s *DN_JSON_ItCurrObjElement(DN_JSONIt *it)
|
||||
{
|
||||
DN_JSONItEntry *curr = DN_JSON_ItCurr(it);
|
||||
auto *result = (curr && curr->type == DN_JSON_ItEntryTypeObjElement)
|
||||
? DN_CAST(json_object_element_s *) curr->value
|
||||
: nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: DN_JSON_ItValueIs ////////////////////////////////////////////////////////////////////////
|
||||
json_value_s *DN_JSON_ItValueIs(DN_JSONIt *it, json_type_e type)
|
||||
{
|
||||
json_value_s *curr = DN_JSON_ItCurrValue(it);
|
||||
json_value_s *result = (curr && type == curr->type) ? curr : nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
json_object_s *DN_JSON_ItValueIsObj(DN_JSONIt *it)
|
||||
{
|
||||
json_value_s *curr = DN_JSON_ItCurrValue(it);
|
||||
json_object_s *result = curr ? json_value_as_object(curr) : nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
json_array_s *DN_JSON_ItValueIsArray(DN_JSONIt *it)
|
||||
{
|
||||
json_value_s *curr = DN_JSON_ItCurrValue(it);
|
||||
json_array_s *result = curr ? json_value_as_array(curr) : nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
json_string_s *DN_JSON_ItValueIsString(DN_JSONIt *it)
|
||||
{
|
||||
json_value_s *curr = DN_JSON_ItCurrValue(it);
|
||||
json_string_s *result = curr ? json_value_as_string(curr) : nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
json_number_s *DN_JSON_ItValueIsNumber(DN_JSONIt *it)
|
||||
{
|
||||
json_value_s *curr = DN_JSON_ItCurrValue(it);
|
||||
json_number_s *result = curr ? json_value_as_number(curr) : nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
json_value_s *DN_JSON_ItValueIsBool(DN_JSONIt *it)
|
||||
{
|
||||
json_value_s *curr = DN_JSON_ItCurrValue(it);
|
||||
json_value_s *result = (curr && (curr->type == json_type_true || curr->type == json_type_false)) ? curr : nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
json_value_s *DN_JSON_ItValueIsNull(DN_JSONIt *it)
|
||||
{
|
||||
json_value_s *curr = DN_JSON_ItCurrValue(it);
|
||||
json_value_s *result = (curr && (curr->type == json_type_null)) ? curr : nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t DN_JSON_ItValueArraySize(DN_JSONIt *it)
|
||||
{
|
||||
size_t result = 0;
|
||||
if (json_array_s *curr = DN_JSON_ItValueIsArray(it))
|
||||
result = curr->length;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// NOTE: DN_JSON_ItKeyValueIs /////////////////////////////////////////////////////////////////////
|
||||
DN_Str8 DN_JSON_ItKey(DN_JSONIt *it)
|
||||
{
|
||||
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
|
||||
DN_Str8 result = {};
|
||||
if (curr) {
|
||||
result.data = DN_CAST(char *)curr->name->string;
|
||||
result.size = curr->name->string_size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DN_JSON_ItKeyIs(DN_JSONIt *it, DN_Str8 key)
|
||||
{
|
||||
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
|
||||
bool result = DN_JSON_String8Cmp(curr->name, key);
|
||||
return result;
|
||||
}
|
||||
|
||||
json_object_s *DN_JSON_ItKeyValueIsObj(DN_JSONIt *it, DN_Str8 key)
|
||||
{
|
||||
json_object_s *result = nullptr;
|
||||
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
|
||||
if (curr && DN_JSON_String8Cmp(curr->name, key))
|
||||
result = json_value_as_object(curr->value);
|
||||
return result;
|
||||
}
|
||||
|
||||
json_array_s *DN_JSON_ItKeyValueIsArray(DN_JSONIt *it, DN_Str8 key)
|
||||
{
|
||||
json_array_s *result = nullptr;
|
||||
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
|
||||
if (curr && DN_JSON_String8Cmp(curr->name, key))
|
||||
result = json_value_as_array(curr->value);
|
||||
return result;
|
||||
}
|
||||
|
||||
json_string_s *DN_JSON_ItKeyValueIsString(DN_JSONIt *it, DN_Str8 key)
|
||||
{
|
||||
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
|
||||
json_string_s *result = nullptr;
|
||||
if (curr && DN_JSON_String8Cmp(curr->name, key))
|
||||
result = json_value_as_string(curr->value);
|
||||
return result;
|
||||
}
|
||||
|
||||
json_number_s *DN_JSON_ItKeyValueIsNumber(DN_JSONIt *it, DN_Str8 key)
|
||||
{
|
||||
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
|
||||
json_number_s *result = nullptr;
|
||||
if (curr && DN_JSON_String8Cmp(curr->name, key))
|
||||
result = json_value_as_number(curr->value);
|
||||
return result;
|
||||
}
|
||||
|
||||
json_value_s *DN_JSON_ItKeyValueIsBool(DN_JSONIt *it, DN_Str8 key)
|
||||
{
|
||||
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
|
||||
json_value_s *result = nullptr;
|
||||
if (curr && DN_JSON_String8Cmp(curr->name, key))
|
||||
result = curr->value->type == json_type_true || curr->value->type == json_type_false ? curr->value : nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
json_value_s *DN_JSON_ItKeyValueIsNull(DN_JSONIt *it, DN_Str8 key)
|
||||
{
|
||||
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
|
||||
json_value_s *result = nullptr;
|
||||
if (curr && DN_JSON_String8Cmp(curr->name, key))
|
||||
result = curr->value->type == json_type_null ? curr->value : nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// NOTE: DN_JSON_ItValueTo ////////////////////////////////////////////////////////////////////////
|
||||
DN_Str8 DN_JSON_ItValueToString(DN_JSONIt *it)
|
||||
{
|
||||
DN_Str8 result = {};
|
||||
if (json_string_s *curr = DN_JSON_ItValueIsString(it))
|
||||
result = DN_Str8_Init(curr->string, curr->string_size);
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t DN_JSON_ItValueToI64(DN_JSONIt *it)
|
||||
{
|
||||
int64_t result = {};
|
||||
if (json_number_s *curr = DN_JSON_ItValueIsNumber(it))
|
||||
result = DN_Str8_ToI64(DN_Str8_Init(curr->number, curr->number_size), 0 /*separator*/).value;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t DN_JSON_ItValueToU64(DN_JSONIt *it)
|
||||
{
|
||||
uint64_t result = {};
|
||||
if (json_number_s *curr = DN_JSON_ItValueIsNumber(it))
|
||||
result = DN_Str8_ToU64(DN_Str8_Init(curr->number, curr->number_size), 0 /*separator*/).value;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DN_JSON_ItValueToBool(DN_JSONIt *it)
|
||||
{
|
||||
bool result = {};
|
||||
if (json_value_s *curr = DN_JSON_ItValueIsBool(it))
|
||||
result = curr->type == json_type_true;
|
||||
return result;
|
||||
}
|
||||
|
||||
void DN_JSON_ItErrorUnknownKeyValue_(DN_JSONIt *it, DN_CallSite call_site)
|
||||
{
|
||||
if (!it)
|
||||
return;
|
||||
|
||||
json_object_element_s const *curr = DN_JSON_ItCurrObjElement(it);
|
||||
if (!curr)
|
||||
return;
|
||||
|
||||
size_t value_type_size = 0;
|
||||
char const *value_type = DN_JSON_TypeEnumCString(DN_CAST(json_type_e)curr->value->type, &value_type_size);
|
||||
|
||||
json_string_s const *key = curr->name;
|
||||
if (it->flags & json_parse_flags_allow_location_information) {
|
||||
json_string_ex_s const *info = DN_CAST(json_string_ex_s const *)key;
|
||||
DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Warning),
|
||||
call_site,
|
||||
"Unknown key-value pair in object [loc=%zu:%zu, key=%.*s, value=%.*s]",
|
||||
info->line_no,
|
||||
info->row_no,
|
||||
DN_CAST(int) key->string_size,
|
||||
key->string,
|
||||
DN_CAST(int) value_type_size,
|
||||
value_type);
|
||||
} else {
|
||||
DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Warning),
|
||||
call_site,
|
||||
"Unknown key-value pair in object [key=%.*s, value=%.*s]",
|
||||
DN_CAST(int) key->string_size,
|
||||
key->string,
|
||||
DN_CAST(int) value_type_size,
|
||||
value_type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
#if !defined(DN_JSON_H)
|
||||
#define DN_JSON_H
|
||||
|
||||
#if !defined(SHEREDOM_JSON_H_INCLUDED)
|
||||
#error Sheredom json.h (github.com/sheredom/json.h) must be included before this file
|
||||
#endif
|
||||
|
||||
// NOTE: DN_JSON //////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void *DN_JSON_ArenaAllocFunc (void *user_data, size_t count);
|
||||
char const *DN_JSON_TypeEnumCString(json_type_e type, size_t *size);
|
||||
bool DN_JSON_String8Cmp (json_string_s const *lhs, DN_Str8 rhs);
|
||||
|
||||
// NOTE: DN_JSON_It /////////////////////////////////////////////////////////////////////////
|
||||
enum DN_JSONItEntryType
|
||||
{
|
||||
DN_JSON_ItEntryTypeObjElement,
|
||||
DN_JSON_ItEntryTypeObj,
|
||||
DN_JSON_ItEntryTypeArrayElement,
|
||||
DN_JSON_ItEntryTypeArray,
|
||||
DN_JSON_ItEntryTypeString,
|
||||
DN_JSON_ItEntryTypeNumber,
|
||||
};
|
||||
|
||||
struct DN_JSONItEntry
|
||||
{
|
||||
DN_JSONItEntryType type;
|
||||
void *value;
|
||||
};
|
||||
|
||||
struct DN_JSONIt
|
||||
{
|
||||
DN_JSONItEntry stack[128];
|
||||
int stack_count;
|
||||
size_t flags;
|
||||
};
|
||||
|
||||
DN_JSONIt DN_JSON_LoadFileToIt(DN_Arena *arena, DN_Str8 json);
|
||||
|
||||
// NOTE: DN_JSON_ItPush/Pop /////////////////////////////////////////////////////////////////
|
||||
bool DN_JSON_ItPushObjElement (DN_JSONIt *it, json_object_element_s *element);
|
||||
bool DN_JSON_ItPushObj (DN_JSONIt *it, json_object_s *obj);
|
||||
bool DN_JSON_ItPushArrayElement(DN_JSONIt *it, json_array_element_s *element);
|
||||
bool DN_JSON_ItPushArray (DN_JSONIt *it, json_value_s *value);
|
||||
bool DN_JSON_ItPushValue (DN_JSONIt *it, json_value_s *value);
|
||||
void DN_JSON_ItPop (DN_JSONIt *it);
|
||||
|
||||
// NOTE: DN_JSON_It tree navigation /////////////////////////////////////////////////////////
|
||||
json_value_s *DN_JSON_ItPushCurrValue(DN_JSONIt *it);
|
||||
bool DN_JSON_ItNext(DN_JSONIt *it);
|
||||
|
||||
#define DN_JSON_ItPushCurrValueIterateThenPop(it) \
|
||||
for(void *DN_UniqueName(ptr) = DN_JSON_ItPushCurrValue(it); DN_UniqueName(ptr); DN_JSON_ItPop(it), DN_UniqueName(ptr) = nullptr) \
|
||||
while (DN_JSON_ItNext(it))
|
||||
|
||||
// NOTE: DN_JSON_ItCurr /////////////////////////////////////////////////////////////////////
|
||||
DN_JSONItEntry *DN_JSON_ItCurr(DN_JSONIt *it);
|
||||
json_value_s *DN_JSON_ItCurrValue(DN_JSONIt *it);
|
||||
json_object_element_s *DN_JSON_ItCurrObjElement(DN_JSONIt *it);
|
||||
|
||||
// NOTE: DN_JSON_ItValueIs //////////////////////////////////////////////////////////////////
|
||||
json_value_s *DN_JSON_ItValueIs(DN_JSONIt *it, json_type_e type);
|
||||
json_object_s *DN_JSON_ItValueIsObj(DN_JSONIt *it);
|
||||
json_array_s *DN_JSON_ItValueIsArray(DN_JSONIt *it);
|
||||
json_string_s *DN_JSON_ItValueIsString(DN_JSONIt *it);
|
||||
json_number_s *DN_JSON_ItValueIsNumber(DN_JSONIt *it);
|
||||
json_value_s *DN_JSON_ItValueIsBool(DN_JSONIt *it);
|
||||
json_value_s *DN_JSON_ItValueIsNull(DN_JSONIt *it);
|
||||
|
||||
size_t DN_JSON_ItValueArraySize(DN_JSONIt *it);
|
||||
|
||||
// NOTE: DN_JSON_ItKeyValueIs ///////////////////////////////////////////////////////////////
|
||||
DN_Str8 DN_JSON_ItKey(DN_JSONIt *it);
|
||||
bool DN_JSON_ItKeyIs(DN_JSONIt *it, DN_Str8 key);
|
||||
json_object_s *DN_JSON_ItKeyValueIsObj(DN_JSONIt *it, DN_Str8 key);
|
||||
json_array_s *DN_JSON_ItKeyValueIsArray(DN_JSONIt *it, DN_Str8 key);
|
||||
json_string_s *DN_JSON_ItKeyValueIsString(DN_JSONIt *it, DN_Str8 key);
|
||||
json_number_s *DN_JSON_ItKeyValueIsNumber(DN_JSONIt *it, DN_Str8 key);
|
||||
json_value_s *DN_JSON_ItKeyValueIsBool(DN_JSONIt *it, DN_Str8 key);
|
||||
json_value_s *DN_JSON_ItKeyValueIsNull(DN_JSONIt *it, DN_Str8 key);
|
||||
|
||||
// NOTE: DN_JSON_ItValueTo //////////////////////////////////////////////////////////////////
|
||||
DN_Str8 DN_JSON_ItValueToString(DN_JSONIt *it);
|
||||
int64_t DN_JSON_ItValueToI64(DN_JSONIt *it);
|
||||
uint64_t DN_JSON_ItValueToU64(DN_JSONIt *it);
|
||||
bool DN_JSON_ItValueToBool(DN_JSONIt *it);
|
||||
|
||||
#define DN_JSON_ItErrorUnknownKeyValue(it) DN_JSON_ItErrorUnknownKeyValue_(it, DN_CALL_SITE)
|
||||
void DN_JSON_ItErrorUnknownKeyValue_(DN_JSONIt *it, DN_CallSite call_site);
|
||||
|
||||
#endif // !defined(DN_JSON_H)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,386 @@
|
||||
#if !defined(DN_MATH_H)
|
||||
#define DN_MATH_H
|
||||
|
||||
DN_MSVC_WARNING_PUSH
|
||||
DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union
|
||||
#if !defined(DN_NO_V2)
|
||||
// NOTE: DN_V2 /////////////////////////////////////////////////////////////////////////////////////
|
||||
union DN_V2I32
|
||||
{
|
||||
struct { int32_t x, y; };
|
||||
struct { int32_t w, h; };
|
||||
int32_t data[2];
|
||||
};
|
||||
|
||||
union DN_V2U16
|
||||
{
|
||||
struct { uint16_t x, y; };
|
||||
struct { uint16_t w, h; };
|
||||
uint16_t data[2];
|
||||
};
|
||||
|
||||
union DN_V2F32
|
||||
{
|
||||
struct { DN_F32 x, y; };
|
||||
struct { DN_F32 w, h; };
|
||||
DN_F32 data[2];
|
||||
};
|
||||
#endif // !defined(DN_NO_V2)
|
||||
|
||||
#if !defined(DN_NO_V3)
|
||||
// NOTE: DN_V3 /////////////////////////////////////////////////////////////////////////////////////
|
||||
union DN_V3F32
|
||||
{
|
||||
struct { DN_F32 x, y, z; };
|
||||
struct { DN_F32 r, g, b; };
|
||||
DN_F32 data[3];
|
||||
};
|
||||
|
||||
#endif // !defined(DN_NO_V3)
|
||||
|
||||
#if !defined(DN_NO_V4)
|
||||
// NOTE: DN_V4 /////////////////////////////////////////////////////////////////////////////////////
|
||||
union DN_V4F32
|
||||
{
|
||||
struct { DN_F32 x, y, z, w; };
|
||||
struct { DN_F32 r, g, b, a; };
|
||||
#if !defined(DN_NO_V3)
|
||||
DN_V3F32 rgb;
|
||||
DN_V3F32 xyz;
|
||||
#endif
|
||||
DN_F32 data[4];
|
||||
};
|
||||
#endif // !defined(DN_NO_V4)
|
||||
DN_MSVC_WARNING_POP
|
||||
|
||||
#if !defined(DN_NO_M4)
|
||||
// NOTE: DN_M4 /////////////////////////////////////////////////////////////////////////////////////
|
||||
struct DN_M4
|
||||
{
|
||||
DN_F32 columns[4][4]; // Column major matrix
|
||||
};
|
||||
#endif // !defined(DN_M4)
|
||||
|
||||
// NOTE: DN_M2x3 ///////////////////////////////////////////////////////////////////////////////////
|
||||
union DN_M2x3
|
||||
{
|
||||
DN_F32 e[6];
|
||||
DN_F32 row[2][3];
|
||||
};
|
||||
|
||||
// NOTE: DN_Rect ///////////////////////////////////////////////////////////////////////////////////
|
||||
#if !defined(DN_NO_RECT)
|
||||
#if defined(DN_NO_V2)
|
||||
#error "Rectangles requires V2, DN_NO_V2 must not be defined"
|
||||
#endif
|
||||
struct DN_Rect
|
||||
{
|
||||
DN_V2F32 pos, size;
|
||||
};
|
||||
|
||||
struct DN_RectMinMax
|
||||
{
|
||||
DN_V2F32 min, max;
|
||||
};
|
||||
|
||||
enum DN_RectCutClip
|
||||
{
|
||||
DN_RectCutClip_No,
|
||||
DN_RectCutClip_Yes,
|
||||
};
|
||||
|
||||
enum DN_RectCutSide
|
||||
{
|
||||
DN_RectCutSide_Left,
|
||||
DN_RectCutSide_Right,
|
||||
DN_RectCutSide_Top,
|
||||
DN_RectCutSide_Bottom,
|
||||
};
|
||||
|
||||
struct DN_RectCut
|
||||
{
|
||||
DN_Rect* rect;
|
||||
DN_RectCutSide side;
|
||||
};
|
||||
#endif // !defined(DN_NO_RECT)
|
||||
|
||||
// NOTE: Other /////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: API
|
||||
struct DN_RaycastLineIntersectV2Result
|
||||
{
|
||||
bool hit; // True if there was an intersection, false if the lines are parallel
|
||||
DN_F32 t_a; // Distance along `dir_a` that the intersection occurred, e.g. `origin_a + (dir_a * t_a)`
|
||||
DN_F32 t_b; // Distance along `dir_b` that the intersection occurred, e.g. `origin_b + (dir_b * t_b)`
|
||||
};
|
||||
|
||||
#if !defined(DN_NO_V2)
|
||||
// NOTE: DN_V2 /////////////////////////////////////////////////////////////////////////////////////
|
||||
#define DN_V2I32_Zero DN_LITERAL(DN_V2I32){{(int32_t)(0), (int32_t)(0)}}
|
||||
#define DN_V2I32_One DN_LITERAL(DN_V2I32){{(int32_t)(1), (int32_t)(1)}}
|
||||
#define DN_V2I32_Init1N(x) DN_LITERAL(DN_V2I32){{(int32_t)(x), (int32_t)(x)}}
|
||||
#define DN_V2I32_Init2N(x, y) DN_LITERAL(DN_V2I32){{(int32_t)(x), (int32_t)(y)}}
|
||||
#define DN_V2I32_InitV2(xy) DN_LITERAL(DN_V2I32){{(int32_t)(xy).x, (int32_t)(xy).y}}
|
||||
|
||||
DN_API bool operator!= (DN_V2I32 lhs, DN_V2I32 rhs);
|
||||
DN_API bool operator== (DN_V2I32 lhs, DN_V2I32 rhs);
|
||||
DN_API bool operator>= (DN_V2I32 lhs, DN_V2I32 rhs);
|
||||
DN_API bool operator<= (DN_V2I32 lhs, DN_V2I32 rhs);
|
||||
DN_API bool operator< (DN_V2I32 lhs, DN_V2I32 rhs);
|
||||
DN_API bool operator> (DN_V2I32 lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2I32 operator- (DN_V2I32 lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2I32 operator- (DN_V2I32 lhs);
|
||||
DN_API DN_V2I32 operator+ (DN_V2I32 lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_F32 rhs);
|
||||
DN_API DN_V2I32 operator* (DN_V2I32 lhs, int32_t rhs);
|
||||
DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_F32 rhs);
|
||||
DN_API DN_V2I32 operator/ (DN_V2I32 lhs, int32_t rhs);
|
||||
DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, DN_F32 rhs);
|
||||
DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, int32_t rhs);
|
||||
DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, DN_F32 rhs);
|
||||
DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, int32_t rhs);
|
||||
DN_API DN_V2I32 & operator-= (DN_V2I32& lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2I32 & operator+= (DN_V2I32& lhs, DN_V2I32 rhs);
|
||||
|
||||
DN_API DN_V2I32 DN_V2I32_Min (DN_V2I32 a, DN_V2I32 b);
|
||||
DN_API DN_V2I32 DN_V2I32_Max (DN_V2I32 a, DN_V2I32 b);
|
||||
DN_API DN_V2I32 DN_V2I32_Abs (DN_V2I32 a);
|
||||
|
||||
#define DN_V2U16_Zero DN_LITERAL(DN_V2U16){{(uint16_t)(0), (uint16_t)(0)}}
|
||||
#define DN_V2U16_One DN_LITERAL(DN_V2U16){{(uint16_t)(1), (uint16_t)(1)}}
|
||||
#define DN_V2U16_Init1N(x) DN_LITERAL(DN_V2U16){{(uint16_t)(x), (uint16_t)(x)}}
|
||||
#define DN_V2U16_Init2N(x, y) DN_LITERAL(DN_V2U16){{(uint16_t)(x), (uint16_t)(y)}}
|
||||
|
||||
DN_API bool operator!= (DN_V2U16 lhs, DN_V2U16 rhs);
|
||||
DN_API bool operator== (DN_V2U16 lhs, DN_V2U16 rhs);
|
||||
DN_API bool operator>= (DN_V2U16 lhs, DN_V2U16 rhs);
|
||||
DN_API bool operator<= (DN_V2U16 lhs, DN_V2U16 rhs);
|
||||
DN_API bool operator< (DN_V2U16 lhs, DN_V2U16 rhs);
|
||||
DN_API bool operator> (DN_V2U16 lhs, DN_V2U16 rhs);
|
||||
DN_API DN_V2U16 operator- (DN_V2U16 lhs, DN_V2U16 rhs);
|
||||
DN_API DN_V2U16 operator+ (DN_V2U16 lhs, DN_V2U16 rhs);
|
||||
DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_V2U16 rhs);
|
||||
DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_F32 rhs);
|
||||
DN_API DN_V2U16 operator* (DN_V2U16 lhs, int32_t rhs);
|
||||
DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_V2U16 rhs);
|
||||
DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_F32 rhs);
|
||||
DN_API DN_V2U16 operator/ (DN_V2U16 lhs, int32_t rhs);
|
||||
DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, DN_V2U16 rhs);
|
||||
DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, DN_F32 rhs);
|
||||
DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, int32_t rhs);
|
||||
DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, DN_V2U16 rhs);
|
||||
DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, DN_F32 rhs);
|
||||
DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, int32_t rhs);
|
||||
DN_API DN_V2U16 & operator-= (DN_V2U16& lhs, DN_V2U16 rhs);
|
||||
DN_API DN_V2U16 & operator+= (DN_V2U16& lhs, DN_V2U16 rhs);
|
||||
|
||||
#define DN_V2F32_Zero DN_LITERAL(DN_V2F32){{(DN_F32)(0), (DN_F32)(0)}}
|
||||
#define DN_V2F32_One DN_LITERAL(DN_V2F32){{(DN_F32)(1), (DN_F32)(1)}}
|
||||
#define DN_V2F32_Init1N(x) DN_LITERAL(DN_V2F32){{(DN_F32)(x), (DN_F32)(x)}}
|
||||
#define DN_V2F32_Init2N(x, y) DN_LITERAL(DN_V2F32){{(DN_F32)(x), (DN_F32)(y)}}
|
||||
#define DN_V2F32_InitV2I32(xy) DN_LITERAL(DN_V2F32){{(DN_F32)(xy).x, (DN_F32)(xy).y}}
|
||||
|
||||
DN_API bool operator!= (DN_V2F32 lhs, DN_V2F32 rhs);
|
||||
DN_API bool operator== (DN_V2F32 lhs, DN_V2F32 rhs);
|
||||
DN_API bool operator>= (DN_V2F32 lhs, DN_V2F32 rhs);
|
||||
DN_API bool operator<= (DN_V2F32 lhs, DN_V2F32 rhs);
|
||||
DN_API bool operator< (DN_V2F32 lhs, DN_V2F32 rhs);
|
||||
DN_API bool operator> (DN_V2F32 lhs, DN_V2F32 rhs);
|
||||
|
||||
DN_API DN_V2F32 operator- (DN_V2F32 lhs);
|
||||
DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2F32 rhs);
|
||||
DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_F32 rhs);
|
||||
DN_API DN_V2F32 operator- (DN_V2F32 lhs, int32_t rhs);
|
||||
|
||||
DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2F32 rhs);
|
||||
DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_F32 rhs);
|
||||
DN_API DN_V2F32 operator+ (DN_V2F32 lhs, int32_t rhs);
|
||||
|
||||
DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2F32 rhs);
|
||||
DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_F32 rhs);
|
||||
DN_API DN_V2F32 operator* (DN_V2F32 lhs, int32_t rhs);
|
||||
|
||||
DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2F32 rhs);
|
||||
DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_F32 rhs);
|
||||
DN_API DN_V2F32 operator/ (DN_V2F32 lhs, int32_t rhs);
|
||||
|
||||
DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_V2F32 rhs);
|
||||
DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_F32 rhs);
|
||||
DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, int32_t rhs);
|
||||
|
||||
DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_V2F32 rhs);
|
||||
DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_F32 rhs);
|
||||
DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, int32_t rhs);
|
||||
|
||||
DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_V2F32 rhs);
|
||||
DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_F32 rhs);
|
||||
DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, int32_t rhs);
|
||||
|
||||
DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_V2F32 rhs);
|
||||
DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_V2I32 rhs);
|
||||
DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_F32 rhs);
|
||||
DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, int32_t rhs);
|
||||
|
||||
DN_API DN_V2F32 DN_V2F32_Min (DN_V2F32 a, DN_V2F32 b);
|
||||
DN_API DN_V2F32 DN_V2F32_Max (DN_V2F32 a, DN_V2F32 b);
|
||||
DN_API DN_V2F32 DN_V2F32_Abs (DN_V2F32 a);
|
||||
DN_API DN_F32 DN_V2F32_Dot (DN_V2F32 a, DN_V2F32 b);
|
||||
DN_API DN_F32 DN_V2F32_LengthSq_V2x2 (DN_V2F32 lhs, DN_V2F32 rhs);
|
||||
DN_API DN_F32 DN_V2F32_Length_V2x2 (DN_V2F32 lhs, DN_V2F32 rhs);
|
||||
DN_API DN_F32 DN_V2F32_LengthSq (DN_V2F32 lhs);
|
||||
DN_API DN_F32 DN_V2F32_Length (DN_V2F32 lhs);
|
||||
DN_API DN_V2F32 DN_V2F32_Normalise (DN_V2F32 a);
|
||||
DN_API DN_V2F32 DN_V2F32_Perpendicular (DN_V2F32 a);
|
||||
DN_API DN_V2F32 DN_V2F32_Reflect (DN_V2F32 in, DN_V2F32 surface);
|
||||
DN_API DN_F32 DN_V2F32_Area (DN_V2F32 a);
|
||||
#endif // !defined(DN_NO_V2)
|
||||
#if !defined(DN_NO_V3)
|
||||
// NOTE: DN_V3 /////////////////////////////////////////////////////////////////////////////////////
|
||||
#define DN_V3F32_Init1N(x) DN_LITERAL(DN_V3F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}}
|
||||
#define DN_V3F32_Init3F32(x, y, z) DN_LITERAL(DN_V3F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z)}}
|
||||
#define DN_V3F32_InitV2F32_1F32(xy, z) DN_LITERAL(DN_V3F32){{(DN_F32)(xy.x), (DN_F32)(xy.y), (DN_F32)(z)}}
|
||||
|
||||
DN_API bool operator== (DN_V3F32 lhs, DN_V3F32 rhs);
|
||||
DN_API bool operator!= (DN_V3F32 lhs, DN_V3F32 rhs);
|
||||
DN_API bool operator>= (DN_V3F32 lhs, DN_V3F32 rhs);
|
||||
DN_API bool operator<= (DN_V3F32 lhs, DN_V3F32 rhs);
|
||||
DN_API bool operator< (DN_V3F32 lhs, DN_V3F32 rhs);
|
||||
DN_API bool operator> (DN_V3F32 lhs, DN_V3F32 rhs);
|
||||
DN_API DN_V3F32 operator- (DN_V3F32 lhs, DN_V3F32 rhs);
|
||||
DN_API DN_V3F32 operator- (DN_V3F32 lhs);
|
||||
DN_API DN_V3F32 operator+ (DN_V3F32 lhs, DN_V3F32 rhs);
|
||||
DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_V3F32 rhs);
|
||||
DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_F32 rhs);
|
||||
DN_API DN_V3F32 operator* (DN_V3F32 lhs, int32_t rhs);
|
||||
DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_V3F32 rhs);
|
||||
DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_F32 rhs);
|
||||
DN_API DN_V3F32 operator/ (DN_V3F32 lhs, int32_t rhs);
|
||||
DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, DN_V3F32 rhs);
|
||||
DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, DN_F32 rhs);
|
||||
DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, int32_t rhs);
|
||||
DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, DN_V3F32 rhs);
|
||||
DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, DN_F32 rhs);
|
||||
DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, int32_t rhs);
|
||||
DN_API DN_V3F32 & operator-= (DN_V3F32 &lhs, DN_V3F32 rhs);
|
||||
DN_API DN_V3F32 & operator+= (DN_V3F32 &lhs, DN_V3F32 rhs);
|
||||
DN_API DN_F32 DN_V3F32_LengthSq (DN_V3F32 a);
|
||||
DN_API DN_F32 DN_V3F32_Length (DN_V3F32 a);
|
||||
DN_API DN_V3F32 DN_V3F32_Normalise (DN_V3F32 a);
|
||||
#endif // !defined(DN_NO_V3)
|
||||
#if !defined(DN_NO_V4)
|
||||
// NOTE: DN_V4 /////////////////////////////////////////////////////////////////////////////////////
|
||||
#define DN_V4F32_Init1N(x) DN_LITERAL(DN_V4F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}}
|
||||
#define DN_V4F32_Init4N(x, y, z, w) DN_LITERAL(DN_V4F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z), (DN_F32)(w)}}
|
||||
#define DN_V4F32_InitV3_1N(xyz, w) DN_LITERAL(DN_V4F32){{xyz.x, xyz.y, xyz.z, w}}
|
||||
DN_API bool operator== (DN_V4F32 lhs, DN_V4F32 rhs);
|
||||
DN_API bool operator!= (DN_V4F32 lhs, DN_V4F32 rhs);
|
||||
DN_API bool operator<= (DN_V4F32 lhs, DN_V4F32 rhs);
|
||||
DN_API bool operator< (DN_V4F32 lhs, DN_V4F32 rhs);
|
||||
DN_API bool operator> (DN_V4F32 lhs, DN_V4F32 rhs);
|
||||
DN_API DN_V4F32 operator- (DN_V4F32 lhs, DN_V4F32 rhs);
|
||||
DN_API DN_V4F32 operator- (DN_V4F32 lhs);
|
||||
DN_API DN_V4F32 operator+ (DN_V4F32 lhs, DN_V4F32 rhs);
|
||||
DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_V4F32 rhs);
|
||||
DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_F32 rhs);
|
||||
DN_API DN_V4F32 operator* (DN_V4F32 lhs, int32_t rhs);
|
||||
DN_API DN_V4F32 operator/ (DN_V4F32 lhs, DN_F32 rhs);
|
||||
DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, DN_V4F32 rhs);
|
||||
DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, DN_F32 rhs);
|
||||
DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, int32_t rhs);
|
||||
DN_API DN_V4F32 & operator-= (DN_V4F32 &lhs, DN_V4F32 rhs);
|
||||
DN_API DN_V4F32 & operator+= (DN_V4F32 &lhs, DN_V4F32 rhs);
|
||||
#endif // !defined(DN_NO_V4)
|
||||
#if !defined(DN_NO_M4)
|
||||
// NOTE: DN_M4 /////////////////////////////////////////////////////////////////////////////////////
|
||||
DN_API DN_F32 DN_V4F32Dot (DN_V4F32 a, DN_V4F32 b);
|
||||
DN_API DN_M4 DN_M4_Identity ();
|
||||
DN_API DN_M4 DN_M4_ScaleF (DN_F32 x, DN_F32 y, DN_F32 z);
|
||||
DN_API DN_M4 DN_M4_Scale (DN_V3F32 xyz);
|
||||
DN_API DN_M4 DN_M4_TranslateF (DN_F32 x, DN_F32 y, DN_F32 z);
|
||||
DN_API DN_M4 DN_M4_Translate (DN_V3F32 xyz);
|
||||
DN_API DN_M4 DN_M4_Transpose (DN_M4 mat);
|
||||
DN_API DN_M4 DN_M4_Rotate (DN_V3F32 axis, DN_F32 radians);
|
||||
DN_API DN_M4 DN_M4_Orthographic (DN_F32 left, DN_F32 right, DN_F32 bottom, DN_F32 top, DN_F32 z_near, DN_F32 z_far);
|
||||
DN_API DN_M4 DN_M4_Perspective (DN_F32 fov /*radians*/, DN_F32 aspect, DN_F32 z_near, DN_F32 z_far);
|
||||
DN_API DN_M4 DN_M4_Add (DN_M4 lhs, DN_M4 rhs);
|
||||
DN_API DN_M4 DN_M4_Sub (DN_M4 lhs, DN_M4 rhs);
|
||||
DN_API DN_M4 DN_M4_Mul (DN_M4 lhs, DN_M4 rhs);
|
||||
DN_API DN_M4 DN_M4_Div (DN_M4 lhs, DN_M4 rhs);
|
||||
DN_API DN_M4 DN_M4_AddF (DN_M4 lhs, DN_F32 rhs);
|
||||
DN_API DN_M4 DN_M4_SubF (DN_M4 lhs, DN_F32 rhs);
|
||||
DN_API DN_M4 DN_M4_MulF (DN_M4 lhs, DN_F32 rhs);
|
||||
DN_API DN_M4 DN_M4_DivF (DN_M4 lhs, DN_F32 rhs);
|
||||
#if !defined(DN_NO_FSTR8)
|
||||
DN_API DN_FStr8<256> DN_M4_ColumnMajorString (DN_M4 mat);
|
||||
#endif
|
||||
#endif // !defined(DN_NO_M4)
|
||||
// NOTE: DN_M2x3 ///////////////////////////////////////////////////////////////////////////////////
|
||||
DN_API bool operator== (DN_M2x3 const &lhs, DN_M2x3 const &rhs);
|
||||
DN_API bool operator!= (DN_M2x3 const &lhs, DN_M2x3 const &rhs);
|
||||
DN_API DN_M2x3 DN_M2x3_Identity ();
|
||||
DN_API DN_M2x3 DN_M2x3_Translate (DN_V2F32 offset);
|
||||
DN_API DN_M2x3 DN_M2x3_Scale (DN_V2F32 scale);
|
||||
DN_API DN_M2x3 DN_M2x3_Rotate (DN_F32 radians);
|
||||
DN_API DN_M2x3 DN_M2x3_Mul (DN_M2x3 m1, DN_M2x3 m2);
|
||||
DN_API DN_V2F32 DN_M2x3_Mul2F32 (DN_M2x3 m1, DN_F32 x, DN_F32 y);
|
||||
DN_API DN_V2F32 DN_M2x3_MulV2 (DN_M2x3 m1, DN_V2F32 v2);
|
||||
#if !defined(DN_NO_RECT)
|
||||
// NOTE: DN_Rect ///////////////////////////////////////////////////////////////////////////////////
|
||||
#define DN_Rect_Init2V2(pos, size) DN_LITERAL(DN_Rect){(pos), (size)}
|
||||
#define DN_Rect_Init4N(x, y, w, h) DN_LITERAL(DN_Rect){DN_LITERAL(DN_V2F32){{x, y}}, DN_LITERAL(DN_V2F32){{w, h}}}
|
||||
|
||||
DN_API bool operator== (const DN_Rect& lhs, const DN_Rect& rhs);
|
||||
DN_API DN_V2F32 DN_Rect_Center (DN_Rect rect);
|
||||
DN_API bool DN_Rect_ContainsPoint (DN_Rect rect, DN_V2F32 p);
|
||||
DN_API bool DN_Rect_ContainsRect (DN_Rect a, DN_Rect b);
|
||||
DN_API DN_Rect DN_Rect_Expand (DN_Rect a, DN_F32 amount);
|
||||
DN_API DN_Rect DN_Rect_ExpandV2 (DN_Rect a, DN_V2F32 amount);
|
||||
DN_API bool DN_Rect_Intersects (DN_Rect a, DN_Rect b);
|
||||
DN_API DN_Rect DN_Rect_Intersection (DN_Rect a, DN_Rect b);
|
||||
DN_API DN_Rect DN_Rect_Union (DN_Rect a, DN_Rect b);
|
||||
DN_API DN_RectMinMax DN_Rect_MinMax (DN_Rect a);
|
||||
DN_API DN_F32 DN_Rect_Area (DN_Rect a);
|
||||
DN_API DN_V2F32 DN_Rect_InterpolatedPoint (DN_Rect rect, DN_V2F32 t01);
|
||||
DN_API DN_V2F32 DN_Rect_TopLeft (DN_Rect rect);
|
||||
DN_API DN_V2F32 DN_Rect_TopRight (DN_Rect rect);
|
||||
DN_API DN_V2F32 DN_Rect_BottomLeft (DN_Rect rect);
|
||||
DN_API DN_V2F32 DN_Rect_BottomRight (DN_Rect rect);
|
||||
|
||||
DN_API DN_Rect DN_Rect_CutLeftClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip);
|
||||
DN_API DN_Rect DN_Rect_CutRightClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip);
|
||||
DN_API DN_Rect DN_Rect_CutTopClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip);
|
||||
DN_API DN_Rect DN_Rect_CutBottomClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip);
|
||||
|
||||
#define DN_Rect_CutLeft(rect, amount) DN_Rect_CutLeftClip(rect, amount, DN_RectCutClip_Yes)
|
||||
#define DN_Rect_CutRight(rect, amount) DN_Rect_CutRightClip(rect, amount, DN_RectCutClip_Yes)
|
||||
#define DN_Rect_CutTop(rect, amount) DN_Rect_CutTopClip(rect, amount, DN_RectCutClip_Yes)
|
||||
#define DN_Rect_CutBottom(rect, amount) DN_Rect_CutBottomClip(rect, amount, DN_RectCutClip_Yes)
|
||||
|
||||
#define DN_Rect_CutLeftNoClip(rect, amount) DN_Rect_CutLeftClip(rect, amount, DN_RectCutClip_No)
|
||||
#define DN_Rect_CutRightNoClip(rect, amount) DN_Rect_CutRightClip(rect, amount, DN_RectCutClip_No)
|
||||
#define DN_Rect_CutTopNoClip(rect, amount) DN_Rect_CutTopClip(rect, amount, DN_RectCutClip_No)
|
||||
#define DN_Rect_CutBottomNoClip(rect, amount) DN_Rect_CutBottomClip(rect, amount, DN_RectCutClip_No)
|
||||
|
||||
DN_API DN_Rect DN_RectCut_Cut (DN_RectCut rect_cut, DN_V2F32 size, DN_RectCutClip clip);
|
||||
#define DN_RectCut_Init(rect, side) DN_LITERAL(DN_RectCut){rect, side}
|
||||
#define DN_RectCut_Left(rect) DN_LITERAL(DN_RectCut){rect, DN_RectCutSide_Left}
|
||||
#define DN_RectCut_Right(rect) DN_LITERAL(DN_RectCut){rect, DN_RectCutSide_Right}
|
||||
#define DN_RectCut_Top(rect) DN_LITERAL(DN_RectCut){rect, DN_RectCutSide_Top}
|
||||
#define DN_RectCut_Bottom(rect) DN_LITERAL(DN_RectCut){rect, DN_RectCutSide_Bottom}
|
||||
#endif // !defined(DN_NO_RECT)
|
||||
// NOTE: Other /////////////////////////////////////////////////////////////////////////////////////
|
||||
DN_API DN_RaycastLineIntersectV2Result DN_Raycast_LineIntersectV2(DN_V2F32 origin_a, DN_V2F32 dir_a, DN_V2F32 origin_b, DN_V2F32 dir_b);
|
||||
DN_API DN_V2F32 DN_Lerp_V2F32 (DN_V2F32 a, DN_F32 t, DN_V2F32 b);
|
||||
DN_API DN_F32 DN_Lerp_F32 (DN_F32 a, DN_F32 t, DN_F32 b);
|
||||
|
||||
#endif // !defined(DN_MATH_H)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
#include "../dn_base_inc.h"
|
||||
#include "../dn_os_inc.h"
|
||||
#include "../dn_core_inc.h"
|
||||
|
||||
#include "../dn_base_inc.cpp"
|
||||
#include "../dn_os_inc.cpp"
|
||||
#include "../dn_core_inc.cpp"
|
||||
|
||||
#include "../Extra/dn_math.h"
|
||||
#include "../Extra/dn_helpers.h"
|
||||
|
||||
#include "../Extra/dn_math.cpp"
|
||||
#include "../Extra/dn_helpers.cpp"
|
||||
|
||||
#define DN_UT_IMPLEMENTATION
|
||||
#include "../Standalone/dn_utest.h"
|
||||
#include "../Extra/dn_tests.cpp"
|
||||
|
||||
DN_MSVC_WARNING_PUSH
|
||||
DN_MSVC_WARNING_DISABLE(6262) // Function uses '29804' bytes of stack. Consider moving some data to heap.
|
||||
int main(int, char**)
|
||||
{
|
||||
DN_Core core = {};
|
||||
DN_OSCore os = {};
|
||||
|
||||
DN_OS_Init(&os, nullptr);
|
||||
DN_Core_Init(&core, DN_CoreOnInit_LogAllFeatures);
|
||||
DN_Tests_RunSuite(DN_TestsPrint_Yes);
|
||||
return 0;
|
||||
}
|
||||
DN_MSVC_WARNING_POP
|
||||
@@ -0,0 +1,33 @@
|
||||
#define DN_TYPE_INFO_CPP
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\
|
||||
// \__$$ __|\$$\ $$ |$$ __$$\ $$ _____| \_$$ _|$$$\ $$ |$$ _____|$$ __$$\
|
||||
// $$ | \$$\ $$ / $$ | $$ |$$ | $$ | $$$$\ $$ |$$ | $$ / $$ |
|
||||
// $$ | \$$$$ / $$$$$$$ |$$$$$\ $$ | $$ $$\$$ |$$$$$\ $$ | $$ |
|
||||
// $$ | \$$ / $$ ____/ $$ __| $$ | $$ \$$$$ |$$ __| $$ | $$ |
|
||||
// $$ | $$ | $$ | $$ | $$ | $$ |\$$$ |$$ | $$ | $$ |
|
||||
// $$ | $$ | $$ | $$$$$$$$\ $$$$$$\ $$ | \$$ |$$ | $$$$$$ |
|
||||
// \__| \__| \__| \________| \______|\__| \__|\__| \______/
|
||||
//
|
||||
// dn_type_info.cpp
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
DN_TypeGetField DN_Type_GetField(DN_TypeInfo const *type_info, DN_Str8 name)
|
||||
{
|
||||
DN_TypeGetField result = {};
|
||||
for (DN_USize index = 0; index < type_info->fields_count; index++) {
|
||||
DN_TypeField const *type_field = type_info->fields + index;
|
||||
if (type_field->name == name) {
|
||||
result.success = true;
|
||||
result.index = index;
|
||||
result.field = DN_CAST(DN_TypeField *)type_field;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#if !defined(DN_TYPE_INFO_H)
|
||||
#define DN_TYPE_INFO_H
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\
|
||||
// \__$$ __|\$$\ $$ |$$ __$$\ $$ _____| \_$$ _|$$$\ $$ |$$ _____|$$ __$$\
|
||||
// $$ | \$$\ $$ / $$ | $$ |$$ | $$ | $$$$\ $$ |$$ | $$ / $$ |
|
||||
// $$ | \$$$$ / $$$$$$$ |$$$$$\ $$ | $$ $$\$$ |$$$$$\ $$ | $$ |
|
||||
// $$ | \$$ / $$ ____/ $$ __| $$ | $$ \$$$$ |$$ __| $$ | $$ |
|
||||
// $$ | $$ | $$ | $$ | $$ | $$ |\$$$ |$$ | $$ | $$ |
|
||||
// $$ | $$ | $$ | $$$$$$$$\ $$$$$$\ $$ | \$$ |$$ | $$$$$$ |
|
||||
// \__| \__| \__| \________| \______|\__| \__|\__| \______/
|
||||
//
|
||||
// dn_type_info.h -- C++ type introspection
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
enum DN_TypeKind
|
||||
{
|
||||
DN_TypeKind_Nil,
|
||||
DN_TypeKind_Basic,
|
||||
DN_TypeKind_Enum,
|
||||
DN_TypeKind_Struct,
|
||||
};
|
||||
|
||||
struct DN_TypeField
|
||||
{
|
||||
uint16_t index;
|
||||
DN_Str8 name;
|
||||
DN_Str8 label;
|
||||
DN_ISize value;
|
||||
DN_USize offset_of;
|
||||
DN_USize size_of;
|
||||
DN_USize align_of;
|
||||
DN_Str8 type_decl;
|
||||
uint32_t type_enum;
|
||||
bool is_pointer;
|
||||
uint16_t array_size;
|
||||
DN_TypeField const *array_size_field;
|
||||
};
|
||||
|
||||
struct DN_TypeInfo
|
||||
{
|
||||
DN_Str8 name;
|
||||
DN_TypeKind kind;
|
||||
DN_USize size_of;
|
||||
DN_TypeField const *fields;
|
||||
uint16_t fields_count;
|
||||
};
|
||||
|
||||
struct DN_TypeGetField
|
||||
{
|
||||
bool success;
|
||||
DN_USize index;
|
||||
DN_TypeField *field;
|
||||
};
|
||||
|
||||
DN_TypeGetField DN_Type_GetField(DN_TypeInfo const *type_info, DN_Str8 name);
|
||||
|
||||
#endif // !defined(DN_TYPE_INFO_H)
|
||||
|
||||
Reference in New Issue
Block a user