Move source code into Source folder and add a single header generator"

This commit is contained in:
2025-06-26 22:14:18 +10:00
parent a41a9d550d
commit 7259cbf296
80 changed files with 18259 additions and 47 deletions
+114
View File
@@ -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);
}
+52
View File
@@ -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
+170
View File
@@ -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;
}
+43
View File
@@ -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
+200
View File
@@ -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
+288
View File
@@ -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
+26
View File
@@ -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)
+265
View File
@@ -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;
}
+45
View File
@@ -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)
+374
View File
@@ -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;
}
+334
View File
@@ -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)
+428
View File
@@ -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);
}
}
+91
View File
@@ -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
+386
View File
@@ -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
+31
View File
@@ -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
+33
View File
@@ -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;
}
+64
View File
@@ -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)