Simplify, simplify, simplify. Kill code that was unloved and unused
This commit is contained in:
@@ -1,124 +0,0 @@
|
||||
#define DN_ASYNC_CPP
|
||||
|
||||
#if defined(_CLANGD)
|
||||
#define DN_H_WITH_OS 1
|
||||
#include "../dn.h"
|
||||
#include "dn_async.h"
|
||||
#endif
|
||||
|
||||
static DN_I32 DN_ASYNC_ThreadEntryPoint_(DN_OSThread *thread)
|
||||
{
|
||||
DN_OS_ThreadSetNameFmt("%.*s", DN_Str8PrintFmt(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_ASYNCTask task = {};
|
||||
for (DN_OS_MutexScope(&async->ring_mutex)) {
|
||||
if (DN_RingHasData(ring, sizeof(task)))
|
||||
DN_RingRead(ring, &task, sizeof(task));
|
||||
}
|
||||
|
||||
if (task.work.func) {
|
||||
DN_OS_ConditionVariableBroadcast(&async->ring_write_cv); // Resume any blocked ring write(s)
|
||||
|
||||
DN_ASYNCWorkArgs args = {};
|
||||
args.input = task.work.input;
|
||||
args.thread = thread;
|
||||
|
||||
DN_AtomicAddU32(&async->busy_threads, 1);
|
||||
task.work.func(args);
|
||||
DN_AtomicSubU32(&async->busy_threads, 1);
|
||||
|
||||
if (task.completion_sem.handle != 0)
|
||||
DN_OS_SemaphoreIncrement(&task.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;
|
||||
DN_OS_ThreadInit(thread, DN_ASYNC_ThreadEntryPoint_, /*lane=*/ nullptr, DN_TCInitArgsDefault(), async);
|
||||
}
|
||||
}
|
||||
|
||||
DN_API void DN_ASYNC_Deinit(DN_ASYNCCore *async)
|
||||
{
|
||||
DN_Assert(async);
|
||||
DN_AtomicSetValue32(&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_ThreadJoin(it.data, DN_TCDeinitArenas_Yes);
|
||||
}
|
||||
|
||||
static bool DN_ASYNC_QueueTask_(DN_ASYNCCore *async, DN_ASYNCTask const *task, 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_RingHasSpace(&async->ring, sizeof(*task))) {
|
||||
DN_RingWriteStruct(&async->ring, task);
|
||||
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_ASYNCTask task = {};
|
||||
task.work.func = func;
|
||||
task.work.input = input;
|
||||
bool result = DN_ASYNC_QueueTask_(async, &task, wait_time_ms);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API DN_ASYNCTask DN_ASYNC_QueueTask(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms)
|
||||
{
|
||||
DN_ASYNCTask result = {};
|
||||
result.work.func = func;
|
||||
result.work.input = input;
|
||||
result.completion_sem = DN_OS_SemaphoreInit(0);
|
||||
result.queued = DN_ASYNC_QueueTask_(async, &result, wait_time_ms);
|
||||
if (!result.queued)
|
||||
DN_OS_SemaphoreDeinit(&result.completion_sem);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API bool DN_ASYNC_WaitTask(DN_ASYNCTask *task, DN_U32 timeout_ms)
|
||||
{
|
||||
bool result = true;
|
||||
if (!task->queued)
|
||||
return result;
|
||||
|
||||
DN_OSSemaphoreWaitResult wait = DN_OS_SemaphoreWait(&task->completion_sem, timeout_ms);
|
||||
result = wait == DN_OSSemaphoreWaitResult_Success;
|
||||
if (result)
|
||||
DN_OS_SemaphoreDeinit(&task->completion_sem);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
#if !defined(DN_ASYNC_H)
|
||||
#define DN_ASYNC_H
|
||||
|
||||
#if defined(_CLANGD)
|
||||
#define DN_H_WITH_OS 1
|
||||
#include "../dn.h"
|
||||
#endif
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct DN_ASYNCWorkArgs
|
||||
{
|
||||
DN_OSThread *thread;
|
||||
void *input;
|
||||
};
|
||||
|
||||
typedef void(DN_ASYNCWorkFunc)(DN_ASYNCWorkArgs work_args);
|
||||
|
||||
struct DN_ASYNCWork
|
||||
{
|
||||
DN_ASYNCWorkFunc *func;
|
||||
void *input;
|
||||
void *output;
|
||||
};
|
||||
|
||||
struct DN_ASYNCTask
|
||||
{
|
||||
bool queued;
|
||||
DN_ASYNCWork work;
|
||||
DN_OSSemaphore completion_sem;
|
||||
};
|
||||
|
||||
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_ASYNCTask 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
|
||||
@@ -1,206 +0,0 @@
|
||||
#define DN_BIN_PACK_CPP
|
||||
|
||||
#if defined(_CLANGD)
|
||||
#include "dn_bin_pack.h"
|
||||
#endif
|
||||
|
||||
DN_API void DN_BinPackU64(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_Str8BuilderAppendBytesCopy(&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_BinPackVarInt_(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_BinPackU64(pack, mode, &value);
|
||||
|
||||
if (mode == DN_BinPackMode_Deserialise) // Write U64 `value` into `item`
|
||||
DN_Memcpy(item, &value, size);
|
||||
}
|
||||
|
||||
DN_API bool DN_BinPackIsEndOfReadStream(DN_BinPack const *pack)
|
||||
{
|
||||
bool result = pack->read_index == pack->read.size;
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackUSize(DN_BinPack *pack, DN_BinPackMode mode, DN_USize *item)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackU32(DN_BinPack *pack, DN_BinPackMode mode, DN_U32 *item)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackU16(DN_BinPack *pack, DN_BinPackMode mode, DN_U16 *item)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackU8(DN_BinPack *pack, DN_BinPackMode mode, DN_U8 *item)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackI64(DN_BinPack *pack, DN_BinPackMode mode, DN_I64 *item)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackI32(DN_BinPack *pack, DN_BinPackMode mode, DN_I32 *item)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackI16(DN_BinPack *pack, DN_BinPackMode mode, DN_I16 *item)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackI8(DN_BinPack *pack, DN_BinPackMode mode, DN_I8 *item)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackF64(DN_BinPack *pack, DN_BinPackMode mode, DN_F64 *item)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackF32(DN_BinPack *pack, DN_BinPackMode mode, DN_F32 *item)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
#if defined(DN_MATH_H)
|
||||
DN_API void DN_BinPackV2(DN_BinPack *pack, DN_BinPackMode mode, DN_V2F32 *item)
|
||||
{
|
||||
DN_BinPackF32(pack, mode, &item->x);
|
||||
DN_BinPackF32(pack, mode, &item->y);
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackV4(DN_BinPack *pack, DN_BinPackMode mode, DN_V4F32 *item)
|
||||
{
|
||||
DN_BinPackF32(pack, mode, &item->x);
|
||||
DN_BinPackF32(pack, mode, &item->y);
|
||||
DN_BinPackF32(pack, mode, &item->z);
|
||||
DN_BinPackF32(pack, mode, &item->w);
|
||||
}
|
||||
#endif
|
||||
|
||||
DN_API void DN_BinPackBool(DN_BinPack *pack, DN_BinPackMode mode, bool *item)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackStr8FromArena(DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, DN_Str8 *string)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, &string->size, sizeof(string->size));
|
||||
if (mode == DN_BinPackMode_Serialise) {
|
||||
DN_Str8BuilderAppendBytesCopy(&pack->writer, string->data, string->size);
|
||||
} else {
|
||||
DN_Str8 src = DN_Str8Subset(pack->read, pack->read_index, string->size);
|
||||
*string = DN_Str8FromStr8Arena(src, arena);
|
||||
pack->read_index += src.size;
|
||||
}
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackStr8FromPool(DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, DN_Str8 *string)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, &string->size, sizeof(string->size));
|
||||
if (mode == DN_BinPackMode_Serialise) {
|
||||
DN_Str8BuilderAppendBytesCopy(&pack->writer, string->data, string->size);
|
||||
} else {
|
||||
DN_Str8 src = DN_Str8Subset(pack->read, pack->read_index, string->size);
|
||||
*string = DN_Str8FromStr8Pool(src, pool);
|
||||
pack->read_index += src.size;
|
||||
}
|
||||
}
|
||||
|
||||
DN_API DN_Str8 DN_BinPackStr8FromBuffer(DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max)
|
||||
{
|
||||
DN_BinPackCBuffer(pack, mode, ptr, size, max);
|
||||
DN_Str8 result = DN_Str8FromPtr(ptr, *size);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackBytesFromArena(DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, void **ptr, DN_USize *size)
|
||||
{
|
||||
DN_Str8 string = DN_Str8FromPtr(*ptr, *size);
|
||||
DN_BinPackStr8FromArena(pack, arena, mode, &string);
|
||||
*ptr = string.data;
|
||||
*size = string.size;
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackBytesFromPool(DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, void **ptr, DN_USize *size)
|
||||
{
|
||||
DN_Str8 string = DN_Str8FromPtr(*ptr, *size);
|
||||
DN_BinPackStr8FromPool(pack, pool, mode, &string);
|
||||
*ptr = string.data;
|
||||
*size = string.size;
|
||||
}
|
||||
|
||||
DN_API void DN_BinPackCArray(DN_BinPack *pack, DN_BinPackMode mode, void *ptr, DN_USize size)
|
||||
{
|
||||
DN_BinPackVarInt_(pack, mode, &size, sizeof(size));
|
||||
if (mode == DN_BinPackMode_Serialise) {
|
||||
DN_Str8BuilderAppendBytesCopy(&pack->writer, ptr, size);
|
||||
} else {
|
||||
DN_Str8 src = DN_Str8Subset(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 void DN_BinPackCBuffer(DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max)
|
||||
{
|
||||
if (mode == DN_BinPackMode_Serialise) {
|
||||
DN_BinPackUSize(pack, mode, size);
|
||||
DN_Str8BuilderAppendBytesCopy(&pack->writer, ptr, *size);
|
||||
} else {
|
||||
DN_U64 size_u64 = 0;
|
||||
DN_BinPackU64(pack, mode, &size_u64);
|
||||
DN_Assert(size_u64 < DN_USIZE_MAX);
|
||||
DN_Assert(size_u64 <= max);
|
||||
|
||||
*size = DN_Min(size_u64, max);
|
||||
DN_Memcpy(ptr, pack->read.data + pack->read_index, *size);
|
||||
pack->read_index += size_u64;
|
||||
}
|
||||
}
|
||||
|
||||
DN_API DN_Str8 DN_BinPackBuild(DN_BinPack const *pack, DN_Arena *arena)
|
||||
{
|
||||
DN_Str8 result = DN_Str8FromStr8BuilderArena(&pack->writer, arena);
|
||||
return result;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#if !defined(DN_BIN_PACK_H)
|
||||
#define DN_BIN_PACK_H
|
||||
|
||||
#if defined(_CLANGD)
|
||||
#include "../dn.h"
|
||||
#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 bool DN_BinPackIsEndOfReadStream(DN_BinPack const *pack);
|
||||
DN_API void DN_BinPackUSize (DN_BinPack *pack, DN_BinPackMode mode, DN_USize *item);
|
||||
DN_API void DN_BinPackU64 (DN_BinPack *pack, DN_BinPackMode mode, DN_U64 *item);
|
||||
DN_API void DN_BinPackU32 (DN_BinPack *pack, DN_BinPackMode mode, DN_U32 *item);
|
||||
DN_API void DN_BinPackU16 (DN_BinPack *pack, DN_BinPackMode mode, DN_U16 *item);
|
||||
DN_API void DN_BinPackU8 (DN_BinPack *pack, DN_BinPackMode mode, DN_U8 *item);
|
||||
DN_API void DN_BinPackI64 (DN_BinPack *pack, DN_BinPackMode mode, DN_I64 *item);
|
||||
DN_API void DN_BinPackI32 (DN_BinPack *pack, DN_BinPackMode mode, DN_I32 *item);
|
||||
DN_API void DN_BinPackI16 (DN_BinPack *pack, DN_BinPackMode mode, DN_I16 *item);
|
||||
DN_API void DN_BinPackI8 (DN_BinPack *pack, DN_BinPackMode mode, DN_I8 *item);
|
||||
DN_API void DN_BinPackF64 (DN_BinPack *pack, DN_BinPackMode mode, DN_F64 *item);
|
||||
DN_API void DN_BinPackF32 (DN_BinPack *pack, DN_BinPackMode mode, DN_F32 *item);
|
||||
#if defined (DN_MATH_H)
|
||||
DN_API void DN_BinPackV2 (DN_BinPack *pack, DN_BinPackMode mode, DN_V2F32 *item);
|
||||
DN_API void DN_BinPackV4 (DN_BinPack *pack, DN_BinPackMode mode, DN_V4F32 *item);
|
||||
#endif
|
||||
DN_API void DN_BinPackBool (DN_BinPack *pack, DN_BinPackMode mode, bool *item);
|
||||
DN_API void DN_BinPackStr8FromArena (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, DN_Str8 *string);
|
||||
DN_API void DN_BinPackStr8FromPool (DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, DN_Str8 *string);
|
||||
DN_API DN_Str8 DN_BinPackStr8FromBuffer (DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max);
|
||||
DN_API void DN_BinPackBytesFromArena (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, void **ptr, DN_USize *size);
|
||||
DN_API void DN_BinPackBytesFromPool (DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, void **ptr, DN_USize *size);
|
||||
DN_API void DN_BinPackCArray (DN_BinPack *pack, DN_BinPackMode mode, void *ptr, DN_USize size);
|
||||
DN_API void DN_BinPackCBuffer (DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max);
|
||||
DN_API DN_Str8 DN_BinPackBuild (DN_BinPack const *pack, DN_Arena *arena);
|
||||
|
||||
#endif // !defined(DN_BIN_PACK_H)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,185 +0,0 @@
|
||||
#if !defined(DN_CGEN_H)
|
||||
#define DN_CGEN_H
|
||||
|
||||
#if defined(_CLANGD)
|
||||
#define DN_H_WITH_OS 1
|
||||
#include "../dn.h"
|
||||
#include "../Standalone/dn_cpp_file.h"
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
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_Str8FromPtr((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_ErrSink *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_ErrSink *err, char const *fmt, ...);
|
||||
DN_API bool DN_CGen_TableHasHeaders(DN_CGenTable const *table, DN_Str8 const *headers, DN_USize header_count, DN_ErrSink *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
|
||||
@@ -1,290 +0,0 @@
|
||||
#define DN_CSV_CPP
|
||||
|
||||
#include "dn_csv.h"
|
||||
|
||||
DN_CSVTokeniser DN_CSV_TokeniserInit(DN_Str8 string, char delimiter)
|
||||
{
|
||||
DN_CSVTokeniser result = {};
|
||||
result.string = string;
|
||||
result.delimiter = delimiter;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DN_CSV_TokeniserValid(DN_CSVTokeniser *tokeniser)
|
||||
{
|
||||
bool result = tokeniser && !tokeniser->bad;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void DN_CSV_TokeniserEatNewLines_(DN_CSVTokeniser *tokeniser)
|
||||
{
|
||||
char const *end = tokeniser->string.data + tokeniser->string.size;
|
||||
while (tokeniser->it[0] == '\n' || tokeniser->it[0] == '\r')
|
||||
if (++tokeniser->it == end)
|
||||
break;
|
||||
}
|
||||
|
||||
bool DN_CSV_TokeniserNextRow(DN_CSVTokeniser *tokeniser)
|
||||
{
|
||||
bool result = false;
|
||||
if (DN_CSV_TokeniserValid(tokeniser) && tokeniser->string.size) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser)
|
||||
{
|
||||
DN_Str8 result = {};
|
||||
if (!DN_CSV_TokeniserValid(tokeniser))
|
||||
return result;
|
||||
|
||||
if (tokeniser->string.size == 0) {
|
||||
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;
|
||||
DN_CSV_TokeniserEatNewLines_(tokeniser); // NOTE: Skip any leading new lines
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void DN_CSV_TokeniserSkipLine(DN_CSVTokeniser *tokeniser)
|
||||
{
|
||||
while (DN_CSV_TokeniserValid(tokeniser) && !tokeniser->end_of_line)
|
||||
DN_CSV_TokeniserNextColumn(tokeniser);
|
||||
DN_CSV_TokeniserNextRow(tokeniser);
|
||||
}
|
||||
|
||||
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) || !fields[result].data)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void DN_CSV_TokeniserSkipLineN(DN_CSVTokeniser *tokeniser, int count)
|
||||
{
|
||||
for (int i = 0; i < count && DN_CSV_TokeniserValid(tokeniser); i++)
|
||||
DN_CSV_TokeniserSkipLine(tokeniser);
|
||||
}
|
||||
|
||||
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_U64FromResult to_u64 = DN_U64FromStr8(csv_value, 0);
|
||||
DN_Assert(to_u64.success);
|
||||
*value = to_u64.value;
|
||||
} else {
|
||||
DN_Str8BuilderAppendF(&pack->write_builder, "%s%" PRIu64, pack->write_column++ ? "," : "", *value);
|
||||
}
|
||||
}
|
||||
|
||||
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_I64FromResult to_i64 = DN_I64FromStr8(csv_value, 0);
|
||||
DN_Assert(to_i64.success);
|
||||
*value = to_i64.value;
|
||||
} else {
|
||||
DN_Str8BuilderAppendF(&pack->write_builder, "%s%" PRIu64, pack->write_column++ ? "," : "", *value);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_Str8FromStr8Arena(csv_value, arena);
|
||||
} else {
|
||||
DN_Str8BuilderAppendF(&pack->write_builder, "%s%.*s", pack->write_column++ ? "," : "", DN_Str8PrintFmt(*str8));
|
||||
}
|
||||
}
|
||||
|
||||
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_Str8BuilderAppendF(&pack->write_builder, "%s%.*s", pack->write_column++ ? "," : "", DN_Cast(int)(*size), dest);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_Str8BuilderAppendRef(&pack->write_builder, DN_Str8Lit("\n"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
#if !defined(DN_CSV_H)
|
||||
#define DN_CSV_H
|
||||
|
||||
// NOTE: Data structures to create and parse CSV files, supports Python style escaped quotes (e.g.
|
||||
// Using "" to escape quotes inside a quoted string).
|
||||
//
|
||||
// API
|
||||
// DN_CSV_TokeniserNextN: Reads the next N consecutive fields from the parser. If `column_iterator`
|
||||
// is `false` then the read of the N consecutive fields does not proceed past the end of the
|
||||
// current CSV row. If `true` then it reads the next N fields even if reading would progress onto
|
||||
// the next row.
|
||||
|
||||
#if defined(_CLANGD)
|
||||
#include "../dn.h"
|
||||
#endif
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
DN_CSVTokeniser DN_CSV_TokeniserInit (DN_Str8 string, char delimiter);
|
||||
bool DN_CSV_TokeniserValid (DN_CSVTokeniser *tokeniser);
|
||||
bool DN_CSV_TokeniserNextRow (DN_CSVTokeniser *tokeniser);
|
||||
DN_Str8 DN_CSV_TokeniserNextField (DN_CSVTokeniser *tokeniser);
|
||||
DN_Str8 DN_CSV_TokeniserNextColumn (DN_CSVTokeniser *tokeniser);
|
||||
void DN_CSV_TokeniserSkipLine (DN_CSVTokeniser *tokeniser);
|
||||
int DN_CSV_TokeniserNextN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator);
|
||||
int DN_CSV_TokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size);
|
||||
int DN_CSV_TokeniserNextFieldN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size);
|
||||
void DN_CSV_TokeniserSkipLineN (DN_CSVTokeniser *tokeniser, int count);
|
||||
void DN_CSV_PackU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value);
|
||||
void DN_CSV_PackI64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value);
|
||||
void DN_CSV_PackI32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value);
|
||||
void DN_CSV_PackI16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value);
|
||||
void DN_CSV_PackI8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value);
|
||||
void DN_CSV_PackU32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value);
|
||||
void DN_CSV_PackU16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value);
|
||||
void DN_CSV_PackBoolAsU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value);
|
||||
void DN_CSV_PackStr8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena);
|
||||
void DN_CSV_PackBuffer (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size);
|
||||
void DN_CSV_PackBufferWithMax (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max);
|
||||
bool DN_CSV_PackNewLine (DN_CSVPack *pack, DN_CSVSerialise serialise);
|
||||
|
||||
#endif // !defined(DN_CSV_H)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,153 +0,0 @@
|
||||
#define DN_HELPERS_CPP
|
||||
|
||||
#if defined(_CLANGD)
|
||||
#include "dn_helpers.h"
|
||||
#endif
|
||||
|
||||
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_Str8FromStr8BuilderArena(&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_Str8BuilderAppendF(&builder->string_builder,
|
||||
"%.*s%*c\"%.*s\": %.*s",
|
||||
prefix_size,
|
||||
prefix,
|
||||
spaces,
|
||||
' ',
|
||||
DN_Str8PrintFmt(key),
|
||||
DN_Str8PrintFmt(value));
|
||||
else if (spaces == 0)
|
||||
DN_Str8BuilderAppendF(&builder->string_builder, "%.*s%.*s", prefix_size, prefix, DN_Str8PrintFmt(value));
|
||||
else
|
||||
DN_Str8BuilderAppendF(&builder->string_builder, "%.*s%*c%.*s", prefix_size, prefix, spaces, ' ', DN_Str8PrintFmt(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_TCScratch scratch = DN_TCScratchBeginArena(&builder->string_builder.arena, 1);
|
||||
DN_Str8 value = DN_Str8FromFmtVArena(&scratch.arena, value_fmt, args);
|
||||
DN_JSONBuilder_KeyValue(builder, key, value);
|
||||
DN_TCScratchEnd(&scratch);
|
||||
}
|
||||
|
||||
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_Str8Lit("{"));
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_ObjectEnd(DN_JSONBuilder *builder)
|
||||
{
|
||||
DN_JSONBuilder_KeyValue(builder, DN_Str8Lit(""), DN_Str8Lit("}"));
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_ArrayBeginNamed(DN_JSONBuilder *builder, DN_Str8 name)
|
||||
{
|
||||
DN_JSONBuilder_KeyValue(builder, name, DN_Str8Lit("["));
|
||||
}
|
||||
|
||||
DN_API void DN_JSONBuilder_ArrayEnd(DN_JSONBuilder *builder)
|
||||
{
|
||||
DN_JSONBuilder_KeyValue(builder, DN_Str8Lit(""), DN_Str8Lit("]"));
|
||||
}
|
||||
|
||||
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_Str8Lit("true") : DN_Str8Lit("false");
|
||||
DN_JSONBuilder_KeyValueF(builder, key, "%.*s", value_string.size, value_string.data);
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
#if !defined(DN_HELPERS_H)
|
||||
#define DN_HELPERS_H
|
||||
|
||||
#if defined(_CLANGD)
|
||||
#include "../dn.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\
|
||||
// $$ | $$ |$$ _____|$$ | $$ __$$\ $$ _____|$$ __$$\ $$ __$$\
|
||||
// $$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ | $$ |$$ / \__|
|
||||
// $$$$$$$$ |$$$$$\ $$ | $$$$$$$ |$$$$$\ $$$$$$$ |\$$$$$$\
|
||||
// $$ __$$ |$$ __| $$ | $$ ____/ $$ __| $$ __$$< \____$$\
|
||||
// $$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |$$\ $$ |
|
||||
// $$ | $$ |$$$$$$$$\ $$$$$$$$\ $$ | $$$$$$$$\ $$ | $$ |\$$$$$$ |
|
||||
// \__| \__|\________|\________|\__| \________|\__| \__| \______/
|
||||
//
|
||||
// dn_helpers.h -- Helper functions/data structures
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
#if !defined(DN_NO_JSON_BUILDER)
|
||||
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)
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#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_Str8Lit(""))
|
||||
#define DN_JSONBuilder_ArrayBegin(builder) DN_JSONBuilder_ArrayBeginNamed(builder, DN_Str8Lit(""))
|
||||
#define DN_JSONBuilder_Str8(builder, value) DN_JSONBuilder_Str8Named(builder, DN_Str8Lit(""), value)
|
||||
#define DN_JSONBuilder_Literal(builder, value) DN_JSONBuilder_LiteralNamed(builder, DN_Str8Lit(""), value)
|
||||
#define DN_JSONBuilder_U64(builder, value) DN_JSONBuilder_U64Named(builder, DN_Str8Lit(""), value)
|
||||
#define DN_JSONBuilder_I64(builder, value) DN_JSONBuilder_I64Named(builder, DN_Str8Lit(""), value)
|
||||
#define DN_JSONBuilder_F64(builder, value) DN_JSONBuilder_F64Named(builder, DN_Str8Lit(""), value)
|
||||
#define DN_JSONBuilder_Bool(builder, value) DN_JSONBuilder_BoolNamed(builder, DN_Str8Lit(""), 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_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;
|
||||
}
|
||||
#endif // !defined(DN_HELPERS_H)
|
||||
@@ -1,428 +0,0 @@
|
||||
#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_ArenaAlloc(arena, count, alignof(json_value_s), DN_ZMem_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 && key.size) {
|
||||
DN_Str8 lhs_string = DN_Str8FromPtr(lhs->string, lhs->string_size);
|
||||
result = DN_Str8Eq(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_Str8FromPtr(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_I64FromStr8(DN_Str8FromPtr(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_U64FromStr8(DN_Str8FromPtr(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_LogEmitFromType(DN_LogMakeU32LogTypeParam(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_LogEmitFromType(DN_LogMakeU32LogTypeParam(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);
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
#if !defined(DN_JSON_H)
|
||||
#define DN_JSON_H
|
||||
|
||||
#if defined(_CLANGD)
|
||||
#include "../dn.h"
|
||||
#include "../External/json.h"
|
||||
#endif
|
||||
|
||||
#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)
|
||||
@@ -1342,90 +1342,6 @@ static DN_UTCore DN_TST_BaseArray()
|
||||
return result;
|
||||
}
|
||||
|
||||
static DN_UTCore DN_TST_BaseVArray()
|
||||
{
|
||||
DN_UTCore result = DN_UT_Init();
|
||||
DN_UT_LogF(&result, "DN_VArray\n");
|
||||
{
|
||||
{
|
||||
DN_VArray<DN_U32> array = DN_OS_VArrayInitByteSize<DN_U32>(DN_Kilobytes(64));
|
||||
DN_DEFER
|
||||
{
|
||||
DN_OS_VArrayDeinit(&array);
|
||||
};
|
||||
|
||||
for (DN_UT_Test(&result, "Test adding an array of items to the array")) {
|
||||
DN_U32 array_literal[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
DN_OS_VArrayAddArray<DN_U32>(&array, array_literal, DN_ArrayCountU(array_literal));
|
||||
DN_UT_Assert(&result, array.size == DN_ArrayCountU(array_literal));
|
||||
DN_UT_Assert(&result, DN_Memcmp(array.data, array_literal, DN_ArrayCountU(array_literal) * sizeof(array_literal[0])) == 0);
|
||||
}
|
||||
|
||||
for (DN_UT_Test(&result, "Test adding an array of items")) {
|
||||
DN_U32 array_literal[] = {0, 1, 2, 3};
|
||||
DN_OS_VArrayAddArray<DN_U32>(&array, array_literal, DN_ArrayCountU(array_literal));
|
||||
|
||||
DN_U32 expected_literal[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3};
|
||||
DN_UT_Assert(&result, array.size == DN_ArrayCountU(expected_literal));
|
||||
DN_UT_Assert(&result, DN_Memcmp(array.data, expected_literal, DN_ArrayCountU(expected_literal) * sizeof(expected_literal[0])) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (DN_UT_Test(&result, "Array of unaligned objects are contiguously laid out in memory")) {
|
||||
// NOTE: Since we allocate from a virtual memory block, each time
|
||||
// we request memory from the block we can demand some alignment
|
||||
// on the returned pointer from the memory block. If there's
|
||||
// additional alignment done in that function then we can no
|
||||
// longer access the items in the array contiguously leading to
|
||||
// confusing memory "corruption" errors.
|
||||
//
|
||||
// This result makes sure that the unaligned objects are allocated
|
||||
// from the memory block (and hence the array) contiguously
|
||||
// when the size of the object is not aligned with the required
|
||||
// alignment of the object.
|
||||
DN_MSVC_WARNING_PUSH
|
||||
DN_MSVC_WARNING_DISABLE(4324) // warning C4324: 'TestVArray::UnalignedObject': structure was padded due to alignment specifier
|
||||
|
||||
struct alignas(8) UnalignedObject
|
||||
{
|
||||
char data[511];
|
||||
};
|
||||
|
||||
DN_MSVC_WARNING_POP
|
||||
|
||||
DN_VArray<UnalignedObject> array = DN_OS_VArrayInitByteSize<UnalignedObject>(DN_Kilobytes(64));
|
||||
DN_DEFER
|
||||
{
|
||||
DN_OS_VArrayDeinit(&array);
|
||||
};
|
||||
|
||||
// NOTE: Verify that the items returned from the data array are
|
||||
// contiguous in memory.
|
||||
UnalignedObject *make_item_a = DN_OS_VArrayMakeArray(&array, 1, DN_ZMem_Yes);
|
||||
UnalignedObject *make_item_b = DN_OS_VArrayMakeArray(&array, 1, DN_ZMem_Yes);
|
||||
DN_Memset(make_item_a->data, 'a', sizeof(make_item_a->data));
|
||||
DN_Memset(make_item_b->data, 'b', sizeof(make_item_b->data));
|
||||
DN_UT_Assert(&result, (uintptr_t)make_item_b == (uintptr_t)(make_item_a + 1));
|
||||
|
||||
// NOTE: Verify that accessing the items from the data array yield
|
||||
// the same object.
|
||||
DN_UT_Assert(&result, array.size == 2);
|
||||
UnalignedObject *data_item_a = array.data + 0;
|
||||
UnalignedObject *data_item_b = array.data + 1;
|
||||
DN_UT_Assert(&result, (uintptr_t)data_item_b == (uintptr_t)(data_item_a + 1));
|
||||
DN_UT_Assert(&result, (uintptr_t)data_item_b == (uintptr_t)(make_item_a + 1));
|
||||
DN_UT_Assert(&result, (uintptr_t)data_item_b == (uintptr_t)make_item_b);
|
||||
|
||||
for (DN_USize i = 0; i < sizeof(data_item_a->data); i++)
|
||||
DN_UT_Assert(&result, data_item_a->data[i] == 'a');
|
||||
|
||||
for (DN_USize i = 0; i < sizeof(data_item_b->data); i++)
|
||||
DN_UT_Assert(&result, data_item_b->data[i] == 'b');
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(DN_UNIT_TESTS_WITH_KECCAK)
|
||||
DN_GCC_WARNING_PUSH
|
||||
DN_GCC_WARNING_DISABLE(-Wunused-parameter)
|
||||
@@ -2695,7 +2611,6 @@ DN_TSTResult DN_TST_RunSuite(DN_TSTPrint print)
|
||||
DN_TST_BaseDSMap(),
|
||||
DN_TST_BaseIArray(),
|
||||
DN_TST_BaseArray(),
|
||||
DN_TST_BaseVArray(),
|
||||
DN_TST_Keccak(),
|
||||
DN_TST_M4(),
|
||||
DN_TST_OS(),
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#define DN_TYPE_INFO_CPP
|
||||
|
||||
#if defined(_CLANGD)
|
||||
#include "dn_type_info.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\
|
||||
// \__$$ __|\$$\ $$ |$$ __$$\ $$ _____| \_$$ _|$$$\ $$ |$$ _____|$$ __$$\
|
||||
// $$ | \$$\ $$ / $$ | $$ |$$ | $$ | $$$$\ $$ |$$ | $$ / $$ |
|
||||
// $$ | \$$$$ / $$$$$$$ |$$$$$\ $$ | $$ $$\$$ |$$$$$\ $$ | $$ |
|
||||
// $$ | \$$ / $$ ____/ $$ __| $$ | $$ \$$$$ |$$ __| $$ | $$ |
|
||||
// $$ | $$ | $$ | $$ | $$ | $$ |\$$$ |$$ | $$ | $$ |
|
||||
// $$ | $$ | $$ | $$$$$$$$\ $$$$$$\ $$ | \$$ |$$ | $$$$$$ |
|
||||
// \__| \__| \__| \________| \______|\__| \__|\__| \______/
|
||||
//
|
||||
// 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 (DN_Str8Eq(type_field->name, name)) {
|
||||
result.success = true;
|
||||
result.index = index;
|
||||
result.field = DN_Cast(DN_TypeField *)type_field;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
#if !defined(DN_TYPE_INFO_H)
|
||||
#define DN_TYPE_INFO_H
|
||||
|
||||
#if defined(_CLANGD)
|
||||
#include "../dn.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\
|
||||
// \__$$ __|\$$\ $$ |$$ __$$\ $$ _____| \_$$ _|$$$\ $$ |$$ _____|$$ __$$\
|
||||
// $$ | \$$\ $$ / $$ | $$ |$$ | $$ | $$$$\ $$ |$$ | $$ / $$ |
|
||||
// $$ | \$$$$ / $$$$$$$ |$$$$$\ $$ | $$ $$\$$ |$$$$$\ $$ | $$ |
|
||||
// $$ | \$$ / $$ ____/ $$ __| $$ | $$ \$$$$ |$$ __| $$ | $$ |
|
||||
// $$ | $$ | $$ | $$ | $$ | $$ |\$$$ |$$ | $$ | $$ |
|
||||
// $$ | $$ | $$ | $$$$$$$$\ $$$$$$\ $$ | \$$ |$$ | $$$$$$ |
|
||||
// \__| \__| \__| \________| \______|\__| \__|\__| \______/
|
||||
//
|
||||
// dn_type_info.h -- C++ type introspection
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
enum DN_TypeKind
|
||||
{
|
||||
DN_TypeKind_Nil,
|
||||
DN_TypeKind_Basic,
|
||||
DN_TypeKind_Enum,
|
||||
DN_TypeKind_Struct,
|
||||
};
|
||||
|
||||
struct DN_TypeField
|
||||
{
|
||||
uint16_t index;
|
||||
DN_Str8 name;
|
||||
DN_Str8 label;
|
||||
DN_ISize value;
|
||||
DN_USize offset_of;
|
||||
DN_USize size_of;
|
||||
DN_USize align_of;
|
||||
DN_Str8 type_decl;
|
||||
uint32_t type_enum;
|
||||
bool is_pointer;
|
||||
uint16_t array_size;
|
||||
DN_TypeField const *array_size_field;
|
||||
};
|
||||
|
||||
struct DN_TypeInfo
|
||||
{
|
||||
DN_Str8 name;
|
||||
DN_TypeKind kind;
|
||||
DN_USize size_of;
|
||||
DN_TypeField const *fields;
|
||||
uint16_t fields_count;
|
||||
};
|
||||
|
||||
struct DN_TypeGetField
|
||||
{
|
||||
bool success;
|
||||
DN_USize index;
|
||||
DN_TypeField *field;
|
||||
};
|
||||
|
||||
DN_TypeGetField DN_Type_GetField(DN_TypeInfo const *type_info, DN_Str8 name);
|
||||
|
||||
#endif // !defined(DN_TYPE_INFO_H)
|
||||
|
||||
Reference in New Issue
Block a user