adjusting repo for removing extra features not part of the original library

This commit is contained in:
ed
2025-02-12 13:57:45 -05:00
parent ea67e889e0
commit d569b93bbd
59 changed files with 4 additions and 202 deletions
+215
View File
@@ -0,0 +1,215 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "arena.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Arena Functions
//- rjf: arena creation/destruction
Arena*
arena__alloc(ArenaParams* optional_params)
{
ArenaParams params = optional_params ? *optional_params : (ArenaParams){0};
SPTR const varena_header_size = align_pow2(size_of(VArena), MD_DEFAULT_MEMORY_ALIGNMENT);
SPTR const header_size = align_pow2(size_of(Arena), MD_DEFAULT_MEMORY_ALIGNMENT);
U64 const varena_reserve_size = VARENA_DEFAULT_RESERVE;
B32 is_virtual = allocator_type(params.backing) & AllocatorType_VArena;
params.flags |= ArenaFlag_Virtual * is_virtual;
if (params.backing.proc == nullptr) params.backing = default_allocator();
if (params.block_size == 0 ) params.block_size = ARENA_DEFAULT_BLOCK_SIZE;
SSIZE alloc_size = is_virtual ? header_size : params.block_size;
void* base = alloc(params.backing, alloc_size);
// rjf: extract arena header & fill
Arena* arena = (Arena*) base;
arena->prev = nullptr;
arena->current = arena;
arena->backing = params.backing;
arena->base_pos = 0;
arena->pos = header_size;
arena->block_size = params.block_size;
arena->flags = params.flags;
asan_unpoison_memory_region(base, sizeof(Arena));
return arena;
}
//- rjf: arena push/pop core functions
void*
arena_push(Arena* arena, SSIZE size, SSIZE align)
{
SPTR const header_size = align_pow2(size_of(Arena), MD_DEFAULT_MEMORY_ALIGNMENT);
Arena* current = arena->current;
SPTR curr_sptr = scast(SPTR, current);
SSIZE aligned_size = align_pow2(size, align);
SPTR pos_pre = current->pos;
SPTR pos_pst = pos_pre + aligned_size;
B32 is_virtual = arena->flags & ArenaFlag_Virtual;
// rjf: chain, if needed
if ( current->block_size < pos_pst && ! (arena->flags & ArenaFlag_NoChain) )
{
Arena* new_block = nullptr;
B32 vmem_chain = is_virtual && (arena->flags & ArenaFlag_NoChainVirtual);
if (vmem_chain) {
SPTR const varena_header_size = align_pow2(size_of(VArena), MD_DEFAULT_MEMORY_ALIGNMENT);
SPTR const arena_block_size = VARENA_DEFAULT_RESERVE - varena_header_size;
VArena* vcurrent = rcast(VArena*, arena->backing.data);
VArena* new_vm = varena_alloc(.reserve_size = vcurrent->reserve, .commit_size = vcurrent->commit_size);
new_block = arena_alloc(.backing = varena_allocator(new_vm), .block_size = arena_block_size);
}
else {
SPTR const arena_block_size = arena->block_size + header_size;
new_block = arena_alloc(.backing = arena->backing, .block_size = arena_block_size);
}
new_block->base_pos = current->base_pos + current->block_size;
sll_stack_push_n(arena->current, new_block, prev);
current = new_block;
pos_pre = current->pos;
pos_pst = pos_pre + aligned_size;
}
// rjf: push onto current block
void* result = 0;
{
result = scast(void*, curr_sptr + pos_pre);
current->pos = pos_pst;
asan_unpoison_memory_region(result, size);
}
if (is_virtual) {
// Sync virtual arena
void* vresult = alloc_align(arena->backing, size, align);
assert(vresult == result);
}
// rjf: panic on failure
#if OS_FEATURE_GRAPHICAL
if(unlikely(result == 0))
{
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
os_abort(1);
}
#endif
return result;
}
void
arena_pop_to(Arena *arena, SSIZE pos)
{
SPTR const header_size = align_pow2(size_of(Arena), MD_DEFAULT_MEMORY_ALIGNMENT);
Arena* current = arena->current;
AllocatorInfo backing = current->backing;
B32 is_virtual = allocator_type(backing) & AllocatorType_VArena;
SSIZE big_pos = clamp_bot(header_size, pos);
// If base position is larger than the position to pop to:
// We are in a previous arena and msut free the current
for(Arena* prev = 0; current->base_pos >= big_pos; current = prev)
{
prev = current->prev;
if (is_virtual) {
varena_release(rcast(VArena*, current->backing.data));
}
else if (allocator_query_support(backing) & AllocatorQuery_Free) {
alloc_free(current->backing, current);
}
}
arena->current = current;
SSIZE new_pos = big_pos - current->base_pos;
assert_always(new_pos <= current->pos);
asan_poison_memory_region((U8*)current + new_pos, (current->pos - new_pos));
current->pos = new_pos;
if (is_virtual) {
varena_rewind(rcast(VArena*, current->backing.data), current->pos);
}
}
void* arena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags)
{
Arena* arena = rcast(Arena*, allocator_data);
void* allocated_ptr = nullptr;
switch (mode)
{
case AllocatorMode_Alloc:
{
allocated_ptr = arena_push(arena, size, alignment);
}
break;
case AllocatorMode_Free:
{
}
break;
case AllocatorMode_FreeAll:
{
arena_release(arena);
}
break;
case AllocatorMode_Resize:
{
assert(old_memory != nullptr);
assert(old_size > 0);
assert_msg(old_size == size, "Requested resize when none needed");
size = align_pow2(size, alignment);
old_size = align_pow2(size, alignment);
SPTR old_memory_offset = scast(SPTR, old_memory) + old_size;
SPTR current_offset = arena->pos;
assert_msg(old_memory_offset == current_offset, "Cannot resize existing allocation in VArena unless it was the last allocated");
B32 requested_shrink = size >= old_size;
if (requested_shrink) {
arena->pos -= size;
allocated_ptr = old_memory;
break;
}
allocated_ptr = old_memory;
arena->pos += size;
}
break;
case AllocatorMode_QueryType:
{
return (void*) AllocatorType_Arena;
}
break;
case AllocatorMode_QuerySupport:
{
return (void*) (AllocatorQuery_Alloc | AllocatorQuery_Resize | AllocatorQuery_FreeAll);
}
break;
}
return allocated_ptr;
}
+175
View File
@@ -0,0 +1,175 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "macros.h"
# include "base_types.h"
# include "memory_substrate.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Types
typedef U32 ArenaFlags;
enum
{
// Don't chain this arena
ArenaFlag_NoChain = (1 << 0),
// Only relevant if backing is virtual memory, will prevent allocating a new backing VArena when the current block exhausts
// Will assume backing can chain multiple block_size arenas however. If there is an allocation failure it will assert.
ArenaFlag_NoChainVirtual = (1 << 1),
// Backing allocator identified as VArena during initialization
ArenaFlag_Virtual = (1 << 2),
};
typedef struct ArenaParams ArenaParams;
struct ArenaParams
{
AllocatorInfo backing;
ArenaFlags flags;
U64 block_size; // If chaining VArenas set this to the reserve size
};
#define ARENA_DEFAULT_BLOCK_SIZE VARENA_DEFAULT_RESERVE - align_pow2(size_of(VArena), MD_DEFAULT_MEMORY_ALIGNMENT)
/* NOTE(Ed): The original metadesk arena is a combination of several concepts into a single interface
* An OS virtual memory allocation scheme
* A arena 'block' of memory with segmented chaining of the blocks
* A push/pop stack allocation interface for the arena
The virtual memory has been abstracted into a backing allocator,
and chaining still supports reserving new virtual address regions .
(can be disabled with ArenaFlag_NoChainVirtual)
If large pages are desired, see VArena.
*/
typedef struct Arena Arena;
struct Arena
{
Arena* prev; // Previous arena in chain
Arena* current; // Current arena in chain
AllocatorInfo backing;
SSIZE base_pos; // Tracks how main arenas have been chained
SSIZE pos;
SSIZE block_size;
ArenaFlags flags;
};
// static_assert(size_of(Arena) <= ARENA_HEADER_SIZE, "sizeof(Arena) <= ARENA_HEADER_SIZE");
typedef struct TempArena TempArena;
struct TempArena
{
Arena* arena;
SSIZE pos;
};
////////////////////////////////
//~ rjf: Arena Functions
MD_API void* arena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags);
force_inline AllocatorInfo arena_allocator(Arena* arena) { AllocatorInfo info = { arena_allocator_proc, arena}; return info; }
// Useful for providing an arena to scratch_begin_alloc
force_inline Arena*
extract_arena(AllocatorInfo ainfo) {
if (allocator_type(ainfo) == AllocatorType_Arena) {
return (Arena*) ainfo.data;
}
return nullptr;
}
//- rjf: arena creation/destruction
MD_API Arena* arena__alloc(ArenaParams* params);
#define arena_alloc(...) arena__alloc( &(ArenaParams){ __VA_ARGS__ } )
void arena_release(Arena *arena);
//- rjf: arena push/pop/pos core functions
MD_API void* arena_push (Arena* arena, SSIZE size, SSIZE align);
U64 arena_pos (Arena* arena);
MD_API void arena_pop_to(Arena* arena, SSIZE pos);
//- rjf: arena push/pop helpers
void arena_clear(Arena* arena);
void arena_pop (Arena* arena, SSIZE amt);
//- rjf: temporary arena scopes
TempArena temp_arena_begin(Arena* arena);
void temp_arena_end(TempArena temp);
//- rjf: push helper macros
#ifndef push_array
#define push_array_no_zero_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T) * (c), (align))
#define push_array_aligned(a, T, c, align) (T *)memory_zero(push_array_no_zero_aligned(a, T, c, align), sizeof(T) * (c))
#define push_array_no_zero(a, T, c) push_array_no_zero_aligned(a, T, c, max(8, align_of(T)))
#define push_array(a, T, c) push_array_aligned (a, T, c, max(8, align_of(T)))
#endif
// Inlines
inline void
arena_release(Arena* arena) {
for (Arena* n = arena->current, *prev = 0; n != 0; n = prev) {
prev = n->prev;
alloc_free(arena->backing, n);
}
}
inline U64
arena_pos(Arena *arena) {
Arena* current = arena->current;
U64 pos = current->base_pos + current->pos;
return pos;
}
//- rjf: arena push/pop helpers
force_inline void arena_clear(Arena* arena) { arena_pop_to(arena, 0); }
inline void
arena_pop(Arena* arena, SSIZE amt) {
SSIZE pos_old = arena_pos(arena);
SSIZE pos_new = pos_old;
if (amt < pos_old)
{
pos_new = pos_old - amt;
}
arena_pop_to(arena, pos_new);
}
//- rjf: temporary arena scopes
inline TempArena
temp_begin(Arena* arena) {
U64 pos = arena_pos(arena);
TempArena temp = {arena, pos};
return temp;
}
force_inline void temp_end(TempArena temp) { arena_pop_to(temp.arena, temp.pos); }
// ======================================== DEFAULT_ALLOCATOR =====================================================
#ifndef MD_OVERRIDE_DEFAULT_ALLOCATOR
// The default allocator for this base module is the Arena allocator with a VArena backing
// NOTE(Ed): In order for this to work, either the os entry_point must have been utilized or os_init needs to be called.
inline AllocatorInfo
default_allocator()
{
local_persist thread_local Arena* arena = nullptr;
if (arena == nullptr) {
VArena* backing_vmem = varena_alloc(.flags = 0, .base_addr = 0x0, .reserve_size = VARENA_DEFAULT_RESERVE, .commit_size = VARENA_DEFAULT_COMMIT);
arena = arena_alloc(.backing = varena_allocator(backing_vmem), .block_size = VARENA_DEFAULT_RESERVE);
}
AllocatorInfo info = { arena_allocator_proc, arena };
return info;
}
#endif
+328
View File
@@ -0,0 +1,328 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "context_cracking.h"
# include "linkage.h"
# include "macros.h"
# include "generic_macros.h"
# include "platform.h"
#endif
#if defined( COMPILER_MSVC )
# if _MSC_VER < 1300
typedef unsigned char, U8;
typedef signed char, S8;
typedef unsigned short, U16;
typedef signed short, S16;
typedef unsigned int, U32;
typedef signed int, S32;
# else
typedef unsigned __int8 U8;
typedef signed __int8 S8;
typedef unsigned __int16 U16;
typedef signed __int16 S16;
typedef unsigned __int32 U32;
typedef signed __int32 S32;
# endif
typedef unsigned __int64 U64;
typedef signed __int64 S64;
#else
# include <stdint.h>
typedef uint8_t, U8;
typedef int8_t, S8;
typedef uint16_t, U16;
typedef int16_t, S16;
typedef uint32_t, U32;
typedef int32_t, S32;
typedef uint64_t, U64;
typedef int64_t, S64;
#endif
typedef struct U128 U128;
struct U128 {
U64 data[2];
};
static_assert( sizeof( U8 ) == sizeof( S8 ), "sizeof(U8) != sizeof(S8)" );
static_assert( sizeof( U16 ) == sizeof( S16 ), "sizeof(U16) != sizeof(sS6)" );
static_assert( sizeof( U32 ) == sizeof( S32 ), "sizeof(U32) != sizeof(sS2)" );
static_assert( sizeof( U64 ) == sizeof( S64 ), "sizeof(U64) != sizeof(sS4)" );
static_assert( sizeof( U8 ) == 1, "sizeof(U8) != 1" );
static_assert( sizeof( U16 ) == 2, "sizeof(U16) != 2" );
static_assert( sizeof( U32 ) == 4, "sizeof(U32) != 4" );
static_assert( sizeof( U64 ) == 8, "sizeof(U64) != 8" );
typedef size_t USIZE;
typedef ptrdiff_t SSIZE;
static_assert( sizeof( USIZE ) == sizeof( SSIZE ), "sizeof(USIZE) != sizeof(SSIZE)" );
#ifndef size_of
#define size_of( x ) ( SSIZE )( sizeof( x ) )
#endif
// NOTE: (u)zpl_intptr is only here for semantic reasons really as this library will only support 32/64 bit OSes.
#if defined( _WIN64 )
typedef signed __int64 SPTR;
typedef unsigned __int64 UPTR;
#elif defined( _WIN32 )
// NOTE; To mark types changing their size, e.g. zpl_intptr
# ifndef _W64
# if ! defined( __midl ) && ( defined( _X86_ ) || defined( _M_IX86 ) ) && _MSC_VER >= 1300
# define _W64 __w64
# else
# define _W64
# endif
# endif
typedef _W64 signed int SPTR;
typedef _W64 unsigned int UPTR;
#else
typedef uintptr_t UPTR;
typedef intptr_t SPTR;
#endif
static_assert( sizeof( UPTR ) == sizeof( SPTR ), "sizeof(UPTR) != sizeof(SPTR)" );
typedef float F32;
typedef double F64;
static_assert( sizeof( F32 ) == 4, "sizeof(F32) != 4" );
static_assert( sizeof( F64 ) == 8, "sizeof(F64) != 8" );
typedef S8 B8;
typedef S16 B16;
typedef S32 B32;
typedef void VoidProc(void);
distinct_register_selector(VoidProc);
////////////////////////////////
//~ NOTE(allen): Constants
#define SIGN32 0x80000000
#define EXPONENT32 0x7F800000
#define MANTISSA32 0x007FFFFF
#define BIG_GOLDEN32 1.61803398875f
#define SMALL_GOLDEN32 0.61803398875f
#define PI32 3.1415926535897f
#define MACHINE_EPSILON64 4.94065645841247e-324
#define MIN_U8 0u
#define MAX_U8 0xffu
#define MIN_S8 ( -0x7f - 1 )
#define MAX_S8 0x7f
#define MIN_U16 0u
#define MAX_U16 0xffffu
#define MIN_S16 ( -0x7fff - 1 )
#define MAX_S16 0x7fff
#define MIN_U32 0u
#define MAX_U32 0xffffffffu
#define MIN_S32 ( -0x7fffffff - 1 )
#define MAX_S32 0x7fffffff
#define MIN_U64 0ull
#define MAX_U64 0xffffffffffffffffull
#define MIN_S64 ( -0x7fffffffffffffffll - 1 )
#define MAX_S64 0x7fffffffffffffffll
#if ARCH_32BIT
# define MIN_USIZE U32_MIN
# define MAX_USIZE U32_MAX
# define MIN_SSIZE S32_MIN
# define MAX_SSIZE S32_MAX
#elif ARCH_64BIT
# define MIN_USIZE U64_MIN
# define MAX_USIZE U64_MAX
# define MIN_SSIZE S64_MIN
# define MAX_SSIZE S64_MAX
#else
# error Unknown architecture size. This library only supports 32 bit and 64 bit architectures.
#endif
#define MIN_F32 1.17549435e-38f
#define MAX_F32 3.40282347e+38f
#define MIN_F64 2.2250738585072014e-308
#define MAX_F64 1.7976931348623157e+308
#define BITMASK1 0x00000001
#define BITMASK2 0x00000003
#define BITMASK3 0x00000007
#define BITMASK4 0x0000000f
#define BITMASK5 0x0000001f
#define BITMASK6 0x0000003f
#define BITMASK7 0x0000007f
#define BITMASK8 0x000000ff
#define BITMASK9 0x000001ff
#define BITMASK10 0x000003ff
#define BITMASK11 0x000007ff
#define BITMASK12 0x00000fff
#define BITMASK13 0x00001fff
#define BITMASK14 0x00003fff
#define BITMASK15 0x00007fff
#define BITMASK16 0x0000ffff
#define BITMASK17 0x0001ffff
#define BITMASK18 0x0003ffff
#define BITMASK19 0x0007ffff
#define BITMASK20 0x000fffff
#define BITMASK21 0x001fffff
#define BITMASK22 0x003fffff
#define BITMASK23 0x007fffff
#define BITMASK24 0x00ffffff
#define BITMASK25 0x01ffffff
#define BITMASK26 0x03ffffff
#define BITMASK27 0x07ffffff
#define BITMASK28 0x0fffffff
#define BITMASK29 0x1fffffff
#define BITMASK30 0x3fffffff
#define BITMASK31 0x7fffffff
#define BITMASK32 0xffffffff
#define BITMASK33 0x00000001ffffffffull
#define BITMASK34 0x00000003ffffffffull
#define BITMASK35 0x00000007ffffffffull
#define BITMASK36 0x0000000fffffffffull
#define BITMASK37 0x0000001fffffffffull
#define BITMASK38 0x0000003fffffffffull
#define BITMASK39 0x0000007fffffffffull
#define BITMASK40 0x000000ffffffffffull
#define BITMASK41 0x000001ffffffffffull
#define BITMASK42 0x000003ffffffffffull
#define BITMASK43 0x000007ffffffffffull
#define BITMASK44 0x00000fffffffffffull
#define BITMASK45 0x00001fffffffffffull
#define BITMASK46 0x00003fffffffffffull
#define BITMASK47 0x00007fffffffffffull
#define BITMASK48 0x0000ffffffffffffull
#define BITMASK49 0x0001ffffffffffffull
#define BITMASK50 0x0003ffffffffffffull
#define BITMASK51 0x0007ffffffffffffull
#define BITMASK52 0x000fffffffffffffull
#define BITMASK53 0x001fffffffffffffull
#define BITMASK54 0x003fffffffffffffull
#define BITMASK55 0x007fffffffffffffull
#define BITMASK56 0x00ffffffffffffffull
#define BITMASK57 0x01ffffffffffffffull
#define BITMASK58 0x03ffffffffffffffull
#define BITMASK59 0x07ffffffffffffffull
#define BITMASK60 0x0fffffffffffffffull
#define BITMASK61 0x1fffffffffffffffull
#define BITMASK62 0x3fffffffffffffffull
#define BITMASK63 0x7fffffffffffffffull
#define BITMASK64 0xffffffffffffffffull
#define BIT1 (1 << 0)
#define BIT2 (1 << 1)
#define BIT3 (1 << 2)
#define BIT4 (1 << 3)
#define BIT5 (1 << 4)
#define BIT6 (1 << 5)
#define BIT7 (1 << 6)
#define BIT8 (1 << 7)
#define BIT9 (1 << 8)
#define BIT10 (1 << 9)
#define BIT11 (1 << 10)
#define BIT12 (1 << 11)
#define BIT13 (1 << 12)
#define BIT14 (1 << 13)
#define BIT15 (1 << 14)
#define BIT16 (1 << 15)
#define BIT17 (1 << 16)
#define BIT18 (1 << 17)
#define BIT19 (1 << 18)
#define BIT20 (1 << 19)
#define BIT21 (1 << 20)
#define BIT22 (1 << 21)
#define BIT23 (1 << 22)
#define BIT24 (1 << 23)
#define BIT25 (1 << 24)
#define BIT26 (1 << 25)
#define BIT27 (1 << 26)
#define BIT28 (1 << 27)
#define BIT29 (1 << 28)
#define BIT30 (1 << 29)
#define BIT31 (1 << 30)
#define BIT32 (1 << 31)
#define BIT33 (1ull << 32)
#define BIT34 (1ull << 33)
#define BIT35 (1ull << 34)
#define BIT36 (1ull << 35)
#define BIT37 (1ull << 36)
#define BIT38 (1ull << 37)
#define BIT39 (1ull << 38)
#define BIT40 (1ull << 39)
#define BIT41 (1ull << 40)
#define BIT42 (1ull << 41)
#define BIT43 (1ull << 42)
#define BIT44 (1ull << 43)
#define BIT45 (1ull << 44)
#define BIT46 (1ull << 45)
#define BIT47 (1ull << 46)
#define BIT48 (1ull << 47)
#define BIT49 (1ull << 48)
#define BIT50 (1ull << 49)
#define BIT51 (1ull << 50)
#define BIT52 (1ull << 51)
#define BIT53 (1ull << 52)
#define BIT54 (1ull << 53)
#define BIT55 (1ull << 54)
#define BIT56 (1ull << 55)
#define BIT57 (1ull << 56)
#define BIT58 (1ull << 57)
#define BIT59 (1ull << 58)
#define BIT60 (1ull << 59)
#define BIT61 (1ull << 60)
#define BIT62 (1ull << 61)
#define BIT63 (1ull << 62)
#define BIT64 (1ull << 63)
////////////////////////////////
//~ Globally Unique Ids
typedef union Guid Guid;
union Guid
{
struct
{
U32 data1;
U16 data2;
U16 data3;
U8 data4[8];
};
U8 v[16];
};
static_assert(size_of(Guid) == 16, "Guid is not 16 bytes");
////////////////////////////////
//~ Arrays
typedef struct U16Array U16Array;
struct U16Array
{
U64 count;
U16* v;
};
typedef struct U32Array U32Array;
struct U32Array
{
U64 count;
U32* v;
};
typedef struct U64Array U64Array;
struct U64Array
{
U64 count;
U64* v;
};
typedef struct U128Array U128Array;
struct U128Array
{
U64 count;
U128* v;
};
+165
View File
@@ -0,0 +1,165 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "command_line.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ NOTE(rjf): Command Line Option Parsing
CmdLineOpt**
cmd_line_slot_from_string(CmdLine* cmd_line, String8 string) {
CmdLineOpt** slot = 0;
if (cmd_line->option_table_size != 0)
{
U64 hash = cmd_line_hash_from_string(string);
U64 bucket = hash % cmd_line->option_table_size;
slot = &cmd_line->option_table[bucket];
}
return slot;
}
CmdLineOpt*
cmd_line_opt_from_slot(CmdLineOpt** slot, String8 string) {
CmdLineOpt* result = 0;
for (CmdLineOpt* var = *slot; var; var = var->hash_next)
{
if (str8_match(string, var->string, 0)) {
result = var;
break;
}
}
return result;
}
CmdLineOpt*
cmd_line_insert_opt__ainfo(AllocatorInfo ainfo, CmdLine* cmd_line, String8 string, String8List values)
{
CmdLineOpt *var = 0;
CmdLineOpt **slot = cmd_line_slot_from_string(cmd_line, string);
CmdLineOpt *existing_var = cmd_line_opt_from_slot(slot, string);
if(existing_var != 0)
{
var = existing_var;
}
else
{
var = alloc_array(ainfo, CmdLineOpt, 1);
var->hash_next = *slot;
var->hash = cmd_line_hash_from_string(string);
var->string = str8_copy(ainfo, string);
var->value_strings = values;
StringJoin join = {0};
join.pre = str8_lit("");
join.sep = str8_lit(",");
join.post = str8_lit("");
var->value_string = str8_list_join(ainfo, &var->value_strings, &join);
*slot = var;
cmd_line_push_opt(&cmd_line->options, var);
}
return var;
}
CmdLine
cmd_line_from_string_list__ainfo(AllocatorInfo ainfo, String8List command_line)
{
CmdLine parsed = {0};
parsed.exe_name = command_line.first->string;
// NOTE(rjf): Set up config option table.
{
parsed.option_table_size = 4096;
parsed.option_table = alloc_array(ainfo, CmdLineOpt*, parsed.option_table_size);
}
// NOTE(rjf): Parse command line.
B32 after_passthrough_option = 0;
B32 first_passthrough = 1;
for (String8Node* node = command_line.first->next, *next = 0; node != 0; node = next)
{
next = node->next;
String8 option_name = node->string;
// NOTE(rjf): Look at -- or - at the start of an argument to determine if it's
// a flag option. All arguments after a single "--" (with no trailing string
// on the command line will be considered as input files.
B32 is_option = 1;
if(after_passthrough_option == 0)
{
if (str8_match(node->string, str8_lit("--"), 0)) {
after_passthrough_option = 1;
is_option = 0;
}
else if (str8_match(str8_prefix(node->string, 2), str8_lit("--"), 0)) {
option_name = str8_skip(option_name, 2);
}
else if (str8_match(str8_prefix(node->string, 1), str8_lit("-"), 0)) {
option_name = str8_skip(option_name, 1);
}
else {
is_option = 0;
}
}
else
{
is_option = 0;
}
// NOTE(rjf): This string is an option.
if(is_option)
{
B32 has_arguments = 0;
U64 arg_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
U64 arg_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
U64 arg_signifier_position = min(arg_signifier_position1, arg_signifier_position2);
String8 arg_portion_this_string = str8_skip(option_name, arg_signifier_position+1);
if (arg_signifier_position < option_name.size) {
has_arguments = 1;
}
option_name = str8_prefix(option_name, arg_signifier_position);
String8List arguments = {0};
// NOTE(rjf): Parse arguments.
if (has_arguments)
{
for (String8Node* n = node; n; n = n->next)
{
next = n->next;
String8 string = n->string;
if (n == node) {
string = arg_portion_this_string;
}
U8 splits[] = { ',' };
String8List args_in_this_string = str8_split(ainfo, string, splits, array_count(splits), 0);
for (String8Node* sub_arg = args_in_this_string.first; sub_arg; sub_arg = sub_arg->next) {
str8_list_push(ainfo, &arguments, sub_arg->string);
}
if ( !str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) && (n != node || arg_portion_this_string.size != 0)) {
break;
}
}
}
// NOTE(rjf): Register config variable.
cmd_line_insert_opt(ainfo, &parsed, option_name, arguments);
}
// NOTE(rjf): Default path, treat as a passthrough config option to be
// handled by tool-specific code.
else if ( !str8_match(node->string, str8_lit("--"), 0) || !first_passthrough) {
str8_list_push(ainfo, &parsed.inputs, node->string);
after_passthrough_option = 1;
first_passthrough = 0;
}
}
return parsed;
}
+106
View File
@@ -0,0 +1,106 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "strings.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Parsed Command Line Types
typedef struct CmdLineOpt CmdLineOpt;
struct CmdLineOpt
{
CmdLineOpt* next;
CmdLineOpt* hash_next;
U64 hash;
String8 string;
String8List value_strings;
String8 value_string;
};
typedef struct CmdLineOptList CmdLineOptList;
struct CmdLineOptList
{
U64 count;
CmdLineOpt* first;
CmdLineOpt* last;
};
typedef struct CmdLine CmdLine;
struct CmdLine
{
String8 exe_name;
CmdLineOptList options;
String8List inputs;
U64 option_table_size;
CmdLineOpt** option_table;
};
////////////////////////////////
//~ NOTE(rjf): Command Line Option Parsing
U64 cmd_line_hash_from_string(String8 string);
MD_API CmdLineOpt** cmd_line_slot_from_string(CmdLine* cmd_line, String8 string);
MD_API CmdLineOpt* cmd_line_opt_from_slot (CmdLineOpt** slot, String8 string);
void cmd_line_push_opt (CmdLineOptList* list, CmdLineOpt* var);
CmdLineOpt* cmd_line_opt_from_string (CmdLine* cmd_line, String8 name);
String8List cmd_line_strings (CmdLine* cmd_line, String8 name);
String8 cmd_line_string (CmdLine* cmd_line, String8 name);
B32 cmd_line_has_flag (CmdLine* cmd_line, String8 name);
B32 cmd_line_has_argument (CmdLine* cmd_line, String8 name);
inline CmdLineOpt* cmd_line_insert_opt__arena (Arena* arena, CmdLine* cmd_line, String8 string, String8List values);
MD_API CmdLineOpt* cmd_line_insert_opt__ainfo (AllocatorInfo ainfo, CmdLine* cmd_line, String8 string, String8List values);
inline CmdLine cmd_line_from_string_list__arena(Arena* arena, String8List arguments);
MD_API CmdLine cmd_line_from_string_list__ainfo(AllocatorInfo ainfo, String8List arguments);
#define cmd_line_insert_opt(allocator, cmd_line, string, values) \
_Generic(allocator, \
Arena*: cmd_line_insert_opt__arena, \
AllocatorInfo: cmd_line_insert_opt__ainfo, \
default: assert_generic_sel_fail \
) generic_call(allocator, cmd_line, string, values)
#define cmd_line_from_string_list(allocator, arguments) \
_Generic(allocator, \
Arena*: cmd_line_from_string_list__arena, \
AllocatorInfo: cmd_line_from_string_list__ainfo, \
default: assert_generic_sel_fail \
) generic_call(allocator, arguments)
inline U64
cmd_line_hash_from_string(String8 string) {
U64 result = 5381;
for(U64 i = 0; i < string.size; i += 1) {
result = ((result << 5) + result) + string.str[i];
}
return result;
}
force_inline CmdLineOpt* cmd_line_insert_opt__arena (Arena* arena, CmdLine* cmd_line, String8 string, String8List values) { return cmd_line_insert_opt__ainfo (arena_allocator(arena), cmd_line, string, values); }
force_inline CmdLine cmd_line_from_string_list__arena(Arena* arena, String8List command_line) { return cmd_line_from_string_list__ainfo(arena_allocator(arena), command_line); }
inline CmdLineOpt* cmd_line_opt_from_string(CmdLine *cmd_line, String8 name) { return cmd_line_opt_from_slot(cmd_line_slot_from_string(cmd_line, name), name); }
inline B32 cmd_line_has_flag (CmdLine *cmd_line, String8 name) { CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name); return(var != 0); }
inline B32 cmd_line_has_argument (CmdLine *cmd_line, String8 name) { CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name); return(var != 0 && var->value_strings.node_count > 0); }
inline String8List
cmd_line_strings(CmdLine *cmd_line, String8 name) {
String8List result = {0};
CmdLineOpt* var = cmd_line_opt_from_string(cmd_line, name);
if (var != 0) { result = var->value_strings; }
return result;
}
inline String8
cmd_line_string(CmdLine *cmd_line, String8 name) {
String8 result = {0};
CmdLineOpt* var = cmd_line_opt_from_string(cmd_line, name);
if (var != 0) { result = var->value_string; }
return result;
}
inline void cmd_line_push_opt(CmdLineOptList* list, CmdLineOpt* var) { sll_queue_push(list->first, list->last, var); list->count += 1; }
+326
View File
@@ -0,0 +1,326 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
#endif
#pragma region Build Options
////////////////////////////////
//~ rjf: Build Options
#if ! defined(BUILD_DEBUG)
# define BUILD_DEBUG 1
#endif
#if ! defined(BUILD_STATIC)
# define BUILD_STATIC 0
#endif
#if ! defined(BUILD_DYANMIC)
# define BUILD_DYANMIC 0
#endif
#if ! defined(BUILD_API_EXPORT)
# define BUILD_API_EXPORT 0
#endif
#if !defined(BUILD_ENTRY_DEFINING_UNIT)
# define BUILD_ENTRY_DEFINING_UNIT 0
#endif
#if !defined(BUILD_CONSOLE_INTERFACE)
# define BUILD_CONSOLE_INTERFACE 0
#endif
#if !defined(BUILD_VERSION_MAJOR)
# define BUILD_VERSION_MAJOR 0
#endif
#if !defined(BUILD_VERSION_MINOR)
# define BUILD_VERSION_MINOR 1
#endif
#if !defined(BUILD_VERSION_PATCH)
# define BUILD_VERSION_PATCH 0
#endif
#define BUILD_VERSION_STRING_LITERAL stringify(BUILD_VERSION_MAJOR) "." stringify(BUILD_VERSION_MINOR) "." stringify(BUILD_VERSION_PATCH)
#if BUILD_DEBUG
# define BUILD_MODE_STRING_LITERAL_APPEND " [Debug]"
#else
# define BUILD_MODE_STRING_LITERAL_APPEND ""
#endif
#if defined(BUILD_GIT_HASH)
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND " [" BUILD_GIT_HASH "]"
#else
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND ""
#endif
#if !defined(BUILD_TITLE)
# define BUILD_TITLE "Untitled"
#endif
#if !defined(BUILD_RELEASE_PHASE_STRING_LITERAL)
# define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA"
#endif
#if !defined(BUILD_ISSUES_LINK_STRING_LITERAL)
# define BUILD_ISSUES_LINK_STRING_LITERAL "ADD_BUILD_ISSUES_LINK"
#endif
#define BUILD_TITLE_STRING_LITERAL BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ") - " __DATE__ "" BUILD_GIT_HASH_STRING_LITERAL_APPEND BUILD_MODE_STRING_LITERAL_APPEND
#pragma endregion Build Options
#pragma region Vendor
#if defined( _MSC_VER )
# pragma message("Detected MSVC")
// # define COMPILER_CLANG 0
# define COMPILER_MSVC 1
// # define COMPILER_GCC 0
# if _MSC_VER >= 1920
# define COMPILER_MSVC_YEAR 2019
# elif _MSC_VER >= 1910
# define COMPILER_MSVC_YEAR 2017
# elif _MSC_VER >= 1900
# define COMPILER_MSVC_YEAR 2015
# elif _MSC_VER >= 1800
# define COMPILER_MSVC_YEAR 2013
# elif _MSC_VER >= 1700
# define COMPILER_MSVC_YEAR 2012
# elif _MSC_VER >= 1600
# define COMPILER_MSVC_YEAR 2010
# elif _MSC_VER >= 1500
# define M_DCOMPILER_MSVC_YEAR 2008
# elif _MSC_VER >= 1400
# define COMPILER_MSVC_YEAR 2005
# else
# define COMPILER_MSVC_YEAR 0
# endif
#elif defined( __GNUC__ )
# pragma message("Detected GCC")
// # define COMPILER_CLANG 0
// # define COMPILER_MSVC 0
# define COMPILER_GCC 1
#elif defined( __clang__ )
# pragma message("Detected CLANG")
# define COMPILER_CLANG 1
// # define COMPILER_MSVC 0
// # define COMPILER_GCC 0
#else
# error Unknown compiler
#endif
#if defined( __has_attribute )
# define HAS_ATTRIBUTE( attribute ) __has_attribute( attribute )
#else
# define HAS_ATTRIBUTE( attribute ) ( 0 )
#endif
#if defined(GCC_VERSION_CHECK)
# undef GCC_VERSION_CHECK
#endif
#if defined(GEN_GCC_VERSION)
# define GCC_VERSION_CHECK(major,minor,patch) (GEN_GCC_VERSION >= GEN_VERSION_ENCODE(major, minor, patch))
#else
# define GCC_VERSION_CHECK(major,minor,patch) (0)
#endif
#pragma endregion Vendor
#pragma region Language
#if ! defined(LANG_C)
# ifdef __cplusplus
# define LANG_C 0
# define LANG_CPP 1
# else
# if defined(__STDC__)
# define LANG_C 1
# define LANG_CPP 0
# else
// Fallback for very old C compilers
# define LANG_C 1
# define LANG_CPP 0
# endif
# endif
#endif
#if LANG_C
# pragma message("MD: Detected C")
#endif
#if LANG_CPP
# pragma message("MD: Detected CPP")
#endif
#pragma endregion Langauge
#pragma region Hardware Architecture
#if COMPILER_CLANG
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
# define ARCH_X64 1
# elif defined(i386) || defined(__i386) || defined(__i386__)
# define ARCH_X86 1
# elif defined(__aarch64__)
# define ARCH_ARM64 1
# elif defined(__arm__)
# define ARCH_ARM32 1
# else
# error Architecture not supported.
# endif
#endif // COMPILER_CLANG
#if COMPILER_MSVC
# if defined(_M_AMD64)
# define ARCH_X64 1
# elif defined(_M_IX86)
# define ARCH_X86 1
# elif defined(_M_ARM64)
# define ARCH_ARM64 1
# elif defined(_M_ARM)
# define ARCH_ARM32 1
# else
# error Architecture not supported.
# endif
#endif // COMPILER_MSVC
#if COMPILER_GCC
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
# define ARCH_X64 1
# elif defined(i386) || defined(__i386) || defined(__i386__)
# define ARCH_X86 1
# elif defined(__aarch64__)
# define ARCH_ARM64 1
# elif defined(__arm__)
# define ARCH_ARM32 1
# else
# error Architecture not supported.
# endif
#endif // COMPILER_GCC
#if defined(ARCH_X64)
# define ARCH_64BIT 1
#elif defined(ARCH_X86)
# define ARCH_32BIT 1
#endif
#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86
# define ARCH_LITTLE_ENDIAN 1
#else
# error Endianness of this architecture not understood by context cracker.
#endif
#pragma endregion Hardware Architecture
#pragma region Operating System
#if defined( _WIN32 ) || defined( _WIN64 )
# ifndef OS_WINDOWS
# define OS_WINDOWS 1
# endif
#elif defined( __APPLE__ ) && defined( __MACH__ )
# ifndef OS_OSX
# define OS_OSX 1
# endif
# ifndef OS_MACOS
# define OS_MACOS 1
# endif
#elif defined( __unix__ )
# ifndef OS_UNIX
# define OS_UNIX 1
# endif
# if defined( ANDROID ) || defined( __ANDROID__ )
# ifndef OS_ANDROID
# define OS_ANDROID 1
# endif
# ifndef OS_LINUX
# define OS_LINUX 1
# endif
# elif defined( __linux__ )
# ifndef OS_LINUX
# define OS_LINUX 1
# endif
# elif defined( __FreeBSD__ ) || defined( __FreeBSD_kernel__ )
# ifndef OS_FREEBSD
# define OS_FREEBSD 1
# endif
# elif defined( __OpenBSD__ )
# ifndef OS_OPENBSD
# define OS_OPENBSD 1
# endif
# elif defined( __EMSCRIPTEN__ )
# ifndef OS_EMSCRIPTEN
# define OS_EMSCRIPTEN 1
# endif
# elif defined( __CYGWIN__ )
# ifndef OS_CYGWIN
# define OS_CYGWIN 1
# endif
# else
# error This UNIX operating system is not supported
# endif
#else
# error This operating system is not supported
#endif
#pragma endregion Operating System
////////////////////////////////
//~ rjf: Zero All Undefined Options
#if !defined(ARCH_32BIT)
# define ARCH_32BIT 0
#endif
#if !defined(ARCH_64BIT)
# define ARCH_64BIT 0
#endif
#if !defined(ARCH_X64)
# define ARCH_X64 0
#endif
#if !defined(ARCH_X86)
# define ARCH_X86 0
#endif
#if !defined(ARCH_ARM64)
# define ARCH_ARM64 0
#endif
#if !defined(ARCH_ARM32)
# define ARCH_ARM32 0
#endif
#if !defined(COMPILER_MSVC)
# define COMPILER_MSVC 0
#endif
#if !defined(COMPILER_GCC)
# define COMPILER_GCC 0
#endif
#if !defined(COMPILER_CLANG)
# define COMPILER_CLANG 0
#endif
#if !defined(OS_WINDOWS)
# define OS_WINDOWS 0
#endif
#if !defined(OS_LINUX)
# define OS_LINUX 0
#endif
#if !defined(OS_MAC)
# define OS_MAC 0
#endif
#if !defined(LANG_CPP)
# define LANG_CPP 0
#endif
#if !defined(LANG_C)
# define LANG_C 0
#endif
////////////////////////////////
//~ rjf: Unsupported Errors
#if ARCH_X86
# error You tried to build in x86 (32 bit) mode, but currently, only building in x64 (64 bit) mode is supported.
#endif
#if ! ARCH_X64
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
#endif
+26
View File
@@ -0,0 +1,26 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "strings.h"
# include "debug.h"
# include "platform.c"
#endif
#define md__printf_err( fmt, ... ) fprintf( stderr, fmt, __VA_ARGS__ )
#define md__printf_err_va( fmt, va ) vfprintf( stderr, fmt, va )
void assert_handler( char const* condition, char const* file, char const* function, S32 line, char const* msg, ... )
{
md__printf_err( "%s - %s:(%d): Assert Failure: ", file, function, line );
if ( condition )
md__printf_err( "`%s` \n", condition );
if ( msg )
{
va_list va;
va_start( va, msg );
md__printf_err_va( msg, va );
va_end( va );
}
md__printf_err( "%s", "\n" );
}
+63
View File
@@ -0,0 +1,63 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "context_cracking.h"
# include "linkage.h"
# include "macros.h"
# include "base_types.h"
#endif
// TODO(Ed): Review this
////////////////////////////////
//~ rjf: Asserts
#ifndef trap
# if COMPILER_MSVC
# if _MSC_VER < 1300
# define trap() __asm int 3 /* Trap to debugger! */
# else
# define trap() __debugbreak()
# endif
# elif COMPILER_CLANG || COMPILER_GCC
# define trap() __builtin_trap()
# else
# error Unknown trap intrinsic for this compiler.
# endif
#endif
#define assert_msg( cond, msg, ... ) \
do \
{ \
if ( ! ( cond ) ) \
{ \
assert_handler( #cond, __FILE__, __func__, scast( S64, __LINE__ ), msg, ##__VA_ARGS__ ); \
trap(); \
} \
} while ( 0 )
#ifndef assert_always
#define assert_always(x) do { if ( !(x) ) { trap(); } } while(0)
#endif
#ifndef assert
# if BUILD_DEBUG
# define assert(x) assert_always(x)
# else
# define assert(x) (void)(x)
# endif
#endif
#ifndef invalid_path
#define invalid_path assert( ! "Invalid Path!")
#endif
#ifndef not_implemented
#define not_implemented assert( ! "Not Implemented!")
#endif
#ifndef no_op
#define no_op ((void)0)
#endif
#ifndef md_static_assert
#define md_static_assert(C, ID) global U8 glue(ID, __LINE__)[ (C) ? 1 : -1 ]
#endif
MD_API void assert_handler( char const* condition, char const* file, char const* function, S32 line, char const* msg, ... );
+47
View File
@@ -0,0 +1,47 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "entry_point.h"
# include "profiling.h"
# include "arena.h"
# include "thread_context.h"
# include "os/os.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
void main_thread_base_entry_point(MainThread_EntryPointProc* entry_point, char** arguments, U64 arguments_count)
{
#if PROFILE_TELEMETRY
local_persist U8 tm_data[MB(64)];
tmLoadLibrary(TM_RELEASE);
tmSetMaxThreadCount(256);
tmInitialize(sizeof(tm_data), (char *)tm_data);
#endif
thread_namef("[main thread]");
TempArena scratch = scratch_begin(0, 0);
String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, (int)arguments_count, arguments);
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture"));
if (capture) {
prof_begin_capture(arguments[0]);
}
entry_point(&cmdline);
if (capture) {
prof_end_capture();
}
scratch_end(scratch);
}
void
supplement_thread_base_entry_point(SupplementThread_EntryPointProc* entry_point, void* params)
{
TCTX tctx;
tctx_init_and_equip(&tctx);
entry_point(params);
tctx_release();
}
+15
View File
@@ -0,0 +1,15 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "context_cracking.h"
# include "linkage.h"
# include "command_line.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
typedef void (MainThread_EntryPointProc) (CmdLine* cmd_line);
typedef void (SupplementThread_EntryPointProc)(void* params);
MD_API void main_thread_base_entry_point (MainThread_EntryPointProc* entry_point, char** arguments, U64 arguments_count);
MD_API void supplement_thread_base_entry_point(SupplementThread_EntryPointProc* entry_point, void* params);
+23
View File
@@ -0,0 +1,23 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "base_types.h"
# include "time.h"
#endif
////////////////////////////////
//~ allen: Files
typedef U32 FilePropertyFlags;
enum
{
FilePropertyFlag_IsFolder = (1 << 0),
};
typedef struct FileProperties FileProperties;
struct FileProperties
{
U64 size;
DenseTime modified;
DenseTime created;
FilePropertyFlags flags;
};
+172
View File
@@ -0,0 +1,172 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
// NOTE(Ed): For C++ generation, this file will not be injected, any macros that are used will either be injected as transparent defines
// or have their usage removed during the library generation pass.
#endif
// ____ _ ______ _ _ ____ _ __ _
// / ___} (_) | ____} | | (_) / __ \ | | | |(_)
// | | ___ ___ _ __ ___ _ __ _ ___ | |__ _ _ _ __ ___| |_ _ ___ _ __ | | | |_ _____ _ __ | | ___ __ _ __| | _ _ __ __ _
// | |{__ |/ _ \ '_ \ / _ \ '__} |/ __| | __} | | | '_ \ / __} __} |/ _ \| '_ \ | | | \ \ / / _ \ '_ }| |/ _ \ / _` |/ _` || | '_ \ / _` |
// | |__j | __/ | | | __/ | | | (__ | | | |_| | | | | (__| l_| | (_) | | | | | l__| |\ V / __/ | | | (_) | (_| | (_| || | | | | (_| |
// \____/ \___}_l l_l\___}_l l_l\___| l_l \__,_l_l l_l\___}\__}_l\___/l_l l_l \____/ \_/ \___}_l l_l\___/ \__,_l\__,_l|_|_| |_|\__, |
// This implemnents macros for utilizing "The Naive Extendible _Generic Macro" explained in: __| |
// https://github.com/JacksonAllan/CC/blob/main/articles/Better_C_Generics_Part_1_The_Extendible_Generic.md {___/
// It was choosen over the more novel implementations to keep the macros as easy to understand and unobfuscated as possible.
// --------------------------------------------------------------------------------------------------------------------------------------------
// For explanation of intended usage with staged metaprogramming see: https://github.com/Ed94/gencpp/tree/main/gen_c_library#macro-usage
// Techncially this can be used for more than just implementing function overloading.
// Additional info: https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/c11-generic/
// --------------------------------------------------------------------------------------------------------------------------------------------
#ifndef COMMA_OPERATOR
#define COMMA_OPERATOR , // The comma operator is used by preprocessor macros to delimit arguments, so we have to represent it via a macro to prevent parsing incorrectly.
#endif
// Helper macros for argument selection
#ifndef select_arg_1
#define select_arg_1( _1, ... ) _1 // <-- Of all th args passed pick _1.
#define select_arg_2( _1, _2, ... ) _2 // <-- Of all the args passed pick _2.
#define select_arg_3( _1, _2, _3, ... ) _3 // etc..
#define generic_sel_entry_type select_arg_1 // Use the arg expansion macro to select arg 1 which should have the type.
#define generic_sel_entry_function select_arg_2 // Use the arg expansion macro to select arg 2 which should have the function.
#define generic_sel_entry_comma_delimiter select_arg_3 // Use the arg expansion macro to select arg 3 which should have the comma delimiter ','.
#endif
#ifndef generic_call
#define generic_call // Just used to indicate where the call "occurs"
#endif
// ----------------------------------------------------------------------------------------------------------------------------------
#ifndef if_generic_selector_defined_include_slot
// if_generic_selector_defined_include_slot( macro ) includes a _Generic slot only if the specified macro is defined (as type, function_name).
// It takes advantage of the fact that if the macro is defined, then the expanded text will contain a comma.
// Expands to ',' if it can find (type): (function) <comma_operator: ',' >
// Where generic_sel_entry_comma_delimiter is specifically looking for that <comma> ,
#define if_generic_selector_defined_include_slot( slot_exp ) generic_sel_entry_comma_delimiter( slot_exp, generic_sel_entry_type( slot_exp, ): generic_sel_entry_function( slot_exp, ) COMMA_OPERATOR, , )
// ^ Selects the comma ^ is the type ^ is the function ^ Insert a comma
// The slot won't exist if that comma is not found.
#endif
// For the occastion where an expression didn't resolve to a selection option the "default: <value>" will be set to:
typedef struct UNRESOLVED_GENERIC_SELECTION UNRESOLVED_GENERIC_SELECTION;
struct UNRESOLVED_GENERIC_SELECTION {
void* _THE_VOID_SLOT_;
};
UNRESOLVED_GENERIC_SELECTION const assert_generic_sel_fail = {0};
// Which will provide the message: error: called object type 'struct NO_RESOLVED_GENERIC_SELECTION' is not a function or function pointer
// ----------------------------------------------------------------------------------------------------------------------------------
// Below are generated on demand for an overlaod depdendent on a type:
// ----------------------------------------------------------------------------------------------------------------------------------
#define function_generic_example( selector_arg ) _Generic( \
(selector_arg), /* Select Via Expression*/ \
/* Extendibility slots: */ \
if_generic_selector_defined_include_slot( GENERIC_SLOT_1__function_sig ) \
if_generic_selector_defined_include_slot( GENERIC_SLOT_2__function_sig ) \
default: assert_generic_sel_fail \
) generic_call( selector_arg )
// ----------------------------------------------------------------------------------------------------------------------------------
// Then each definiton of a function has an associated define:
// #define GENERIC_SLOT_<#>_<generic identifier> <typename>, <function_to_resolve>
// Then somehwere later on
// <etc> <return_type> <function_id> ( <arguments> ) { <implementation> }
// Concrete example:
// To add support for long:
#define GENERIC_SLOT_1__example_hash long, generic_example_hash__P_long
size_t generic_example_hash__P_long( long val ) { return val * 2654435761ull; }
// To add support for long long:
#define GENERIC_SLOT_2__example_hash long long, generic_example_hash__P_long_long
size_t generic_example_hash__P_long_long( long long val ) { return val * 2654435761ull; }
// If using an Editor with support for syntax hightlighting macros:
// GENERIC_SLOT_1__example_hash and GENERIC_SLOT_2__example_hash should show color highlighting indicating the slot is enabled,
// or, "defined" for usage during the compilation pass that handles the _Generic instrinsic.
#define generic_example_hash( function_arguments ) _Generic( \
(function_arguments), /* Select Via Expression*/ \
/* Extendibility slots: */ \
if_generic_selector_defined_include_slot( GENERIC_SLOT_1__example_hash ) \
if_generic_selector_defined_include_slot( GENERIC_SLOT_2__example_hash ) \
if_generic_selector_defined_include_slot( GENERIC_SLOT_3__example_hash ) \
if_generic_selector_defined_include_slot( GENERIC_SLOT_4__example_hash ) \
if_generic_selector_defined_include_slot( GENERIC_SLOT_5__example_hash ) \
if_generic_selector_defined_include_slot( GENERIC_SLOT_6__example_hash ) \
if_generic_selector_defined_include_slot( GENERIC_SLOT_7__example_hash ) \
if_generic_selector_defined_include_slot( GENERIC_SLOT_8__example_hash ) \
default: assert_generic_sel_fail \
) generic_call( function_arguments )
// Additional Variations:
// If the function takes more than one argument the following is used:
#define function_generic_example_varadic( selector_arg, ... ) _Generic( \
(selector_arg), \
if_generic_selector_defined_include_slot( GENERIC_SLOT_1__function_sig ) \
if_generic_selector_defined_include_slot( GENERIC_SLOT_2__function_sig ) \
/* ... */ \
if_generic_selector_defined_include_slot(GENERIC_SLOT_N__function_sig ) \
default: assert_generic_sel_fail \
) generic_call( selector_arg, __VA_ARG__ )
// If the function does not take the arugment as a parameter:
#define function_generic_example_direct_type( selector_arg ) _Generic( \
( type_to_expression(selector_arg) ), \
if_generic_selector_defined_include_slot( GENERIC_SLOT_1__function_sig ) \
if_generic_selector_defined_include_slot( GENERIC_SLOT_2__function_sig ) \
/* ... */ \
if_generic_selector_defined_include_slot(GENERIC_SLOT_N__function_sig ) \
default: assert_generic_sel_fail \
) generic_call(selector_arg)
#ifndef type_to_expression
// Used to keep the _Generic keyword happy as bare types are not considered "expressions"
#define type_to_expression(type) (* (type*)NULL)
// Instead of using this macro, it should be directly expanded by code generation.
#endif
// _Generic also suffers from type compability flatting distinctions between typedef by resolving the selection to the underling type and qualifier.
// To resolve this these distinctions must be enforce by keeping "compatible" types in separate _Generic expressions:
#define example_with__l2(expr) _Generic( \
(expr), \
S64 : example_with_s64, \
default: assert_generic_sel_fail \
)
#define example_with(expr) \
_Generic((expr), \
SSIZE : example_with_SSIZEZ \
default : example_with_not_SSIZE(allocator, in) \
) generic_call(allocator, in)
// This can be made more concise with he following "layer" indicating _Generic macros
#define _Generic_L2(expr, ...) default: _Generic(expr, __VA_ARGS__)
#define _Generic_L3(expr, ...) default: _Generic(expr, __VA_ARGS__)
#define example_with_generic_layers(expr) \
_Generic( (expr), \
S64 : example_with_s64, \
_Generic_L2((expr), \
SSIZE: example_with_SSIZZE \
default: assert_generic_sel_fail \
), \
) generic_call(expr)
// Removing example definitions
#undef example_with
#undef example_with__l2
#undef example_with_generic_layers
#undef function_generic_example
#undef GENERIC_SLOT_1__example_hash
#undef GENERIC_SLOT_2__example_hash
#undef generic_example_hash
#undef function_generic_example_varadic
#undef function_generic_example_direct_type
#undef generic_example_do_something_with
+49
View File
@@ -0,0 +1,49 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "context_cracking.h"
#endif
#ifndef MD_API
#if COMPILER_MSVC
# if BUILD_DYANMIC
# if BUILD_API_EXPORT
# define MD_API __declspec(dllexport)
# else
# define MD_API __declspec(dllimport)
# endif
# else
# define MD_API // Empty for static builds
# endif
#else
# ifdef BUILD_DYANMIC
# define MD_API __attribute__((visibility("default")))
# else
# define MD_API // Empty for static builds
# endif
#endif
#endif // GEN_API
#ifndef MD_API_C_BEGIN
# if LANG_C
# define MD_API_C_BEGIN
# define MD_API_C_END
# define MD_API_C
# else
# define MD_API_C_BEGIN extern "C" {
# define MD_API_C_END }
# define MD_API_C_END extern "C"
# endif
#endif
#ifndef global // Global variables
# if BUILD_API_EXPORT || BUILD_STATIC
# define global
# else
# define global static
# endif
#endif
// Internal Linkage
#ifndef internal
#define internal static
#endif
+89
View File
@@ -0,0 +1,89 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "logger.h"
# include "thread_context.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Globals/Thread-Locals
MD_API_C thread_static Log* log_active;
#if !BUILD_SUPPLEMENTARY_UNIT
MD_API_C thread_static Log* log_active = 0;
#endif
////////////////////////////////
//~ rjf: Log Creation/Selection
void
log_select(Log* log) {
log_active = log;
}
////////////////////////////////
//~ rjf: Log Building
void
log_msg(LogMsgKind kind, String8 string) {
if(log_active != 0 && log_active->top_scope != 0) {
String8 string_copy = str8_copy(log_active->arena, string);
str8_list_push(log_active->arena, &log_active->top_scope->strings[kind], string_copy);
}
}
void
log_msgf(LogMsgKind kind, char *fmt, ...) {
if(log_active != 0)
{
TempArena scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = str8fv(scratch.arena, fmt, args);
log_msg(kind, string);
va_end(args);
scratch_end(scratch);
}
}
////////////////////////////////
//~ rjf: Log Scopes
void
log_scope_begin(void) {
if (log_active != 0) {
U64 pos = arena_pos(log_active->arena);
LogScope* scope = push_array(log_active->arena, LogScope, 1);
scope->pos = pos;
sll_stack_push(log_active->top_scope, scope);
}
}
LogScopeResult
log_scope_end(Arena *arena)
{
LogScopeResult result = {0};
if(log_active != 0)
{
LogScope* scope = log_active->top_scope;
if(scope != 0)
{
sll_stack_pop(log_active->top_scope);
if(arena != 0)
{
for (each_enum_val(LogMsgKind, kind)) {
TempArena scratch = scratch_begin(&arena, 1);
String8
result_unindented = str8_list_join(scratch.arena, &scope->strings[kind], 0);
result.strings[kind] = indented_from_string(arena, result_unindented);
scratch_end(scratch);
}
}
arena_pop_to(log_active->arena, scope->pos);
}
}
return result;
}
+86
View File
@@ -0,0 +1,86 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "base_types.h"
# include "strings.h"
# include "arena.h"
# include "thread_context.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Log Types
typedef enum LogMsgKind LogMsgKind;
enum LogMsgKind
{
LogMsgKind_Info,
LogMsgKind_UserError,
LogMsgKind_COUNT
};
typedef struct LogScope LogScope;
struct LogScope
{
LogScope* next;
U64 pos;
String8List strings[LogMsgKind_COUNT];
};
typedef struct LogScopeResult LogScopeResult;
struct LogScopeResult
{
String8 strings[LogMsgKind_COUNT];
};
typedef struct Log Log;
struct Log
{
Arena* arena;
LogScope* top_scope;
};
#ifndef LOG_DEFAULT_ARENA_BLOCK_SIZE
#define LOG_DEFAULT_ARENA_BLOCK_SIZE VARENA_DEFAULT_RESERVE
#endif
////////////////////////////////
//~ rjf: Log Creation/Selection
Log* log_alloc(AllocatorInfo ainfo, U64 arena_block_size);
void log_release(Log* log);
MD_API void log_select (Log* log);
inline Log*
log_alloc(AllocatorInfo ainfo, U64 arena_block_size) {
if (arena_block_size == 0) {
arena_block_size = LOG_DEFAULT_ARENA_BLOCK_SIZE;
}
Arena* arena = arena_alloc(.backing = ainfo, .block_size = arena_block_size);
Log* log = push_array(arena, Log, 1);
log->arena = arena;
return log;
}
inline void log_release(Log* log) { arena_release(log->arena); }
////////////////////////////////
//~ rjf: Log Building
MD_API void log_msg (LogMsgKind kind, String8 string);
MD_API void log_msgf(LogMsgKind kind, char* fmt, ...);
#define log_info(s) log_msg (LogMsgKind_Info, (s))
#define log_infof(fmt, ...) log_msgf(LogMsgKind_Info, (fmt), __VA_ARGS__)
#define log_user_error(s) log_msg (LogMsgKind_UserError, (s))
#define log_user_errorf(fmt, ...) log_msgf(LogMsgKind_UserError, (fmt), __VA_ARGS__)
#define log_info_named_block(s) defer_loop(log_infof("%S:\n{\n", (s)), log_infof("}\n"))
#define log_info_named_blockf(fmt, ...) defer_loop((log_infof(fmt, __VA_ARGS__), log_infof(":\n{\n")), log_infof("}\n"))
////////////////////////////////
//~ rjf: Log Scopes
void log_scope_begin(void);
MD_API LogScopeResult log_scope_end(Arena* arena);
+187
View File
@@ -0,0 +1,187 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "context_cracking.h"
# include "linkage.h"
#endif
////////////////////////////////
//~ rjf: Branch Predictor Hints
#if COMPILER_CLANG
# define expect(expr, val) __builtin_expect((expr), (val))
#else
# define expect(expr, val) (expr)
#endif
#define likely(expr) expect(expr, 1)
#define unlikely(expr) expect(expr, 0)
////////////////////////////////
//~ erg: type casting
#if LANG_CPP
# ifndef ccast
# define ccast( type, value ) ( const_cast< type >( (value) ) )
# endif
# ifndef pcast
# define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) )
# endif
# ifndef rcast
# define rcast( type, value ) reinterpret_cast< type >( value )
# endif
# ifndef scast
# define scast( type, value ) static_cast< type >( value )
# endif
#else
# ifndef ccast
# define ccast( type, value ) ( (type)(value) )
# endif
# ifndef pcast
# define pcast( type, value ) ( * (type*)(& value) )
# endif
# ifndef rcast
# define rcast( type, value ) ( (type)(value) )
# endif
# ifndef scast
# define scast( type, value ) ( (type)(value) )
# endif
#endif
#if ! defined(typeof) && ( ! LANG_C || __STDC_VERSION__ < 202311L)
# if ! LANG_C
# define typeof decltype
# elif defined(_MSC_VER)
# define typeof __typeof__
# elif defined(__GNUC__) || defined(__clang__)
# define typeof __typeof__
# else
# error "Compiler not supported"
# endif
#endif
#if LANG_C
# if __STDC_VERSION__ >= 202311L
# define enum_underlying(type) : type
# else
# define enum_underlying(type)
# endif
#else
# define enum_underlying(type) : type
#endif
#if LANG_C
# ifndef nullptr
# define nullptr NULL
# endif
# ifndef MD_REMOVE_PTR
# define MD_REMOVE_PTR(type) typeof(* ( (type) NULL) )
# endif
#endif
#if ! defined(PARAM_DEFAULT) && LANG_CPP
# define PARAM_DEFAULT = {}
#else
# define PARAM_DEFAULT
#endif
#if LANG_C
# ifndef static_assert
# undef static_assert
# if __STDC_VERSION__ >= 201112L
# define static_assert(condition, message) _Static_assert(condition, message)
# else
# define static_assert(condition, message) typedef char static_assertion_##__LINE__[(condition)?1:-1]
# endif
# endif
#endif
#ifndef force_inline
# if COMPILER_MSVC
# define force_inline __forceinline
# elif COMPILER_GCC
# define force_inline inline __attribute__((__always_inline__))
# elif COMPILER_CLANG
# if __has_attribute(__always_inline__)
# define force_inline inline __attribute__((__always_inline__))
# else
# define force_inline
# endif
# else
# define force_inline
# endif
#endif
#ifndef never_inline
# if COMPILER_MSVC
# define never_inline __declspec( noinline )
# elif COMPILER_GCC
# define never_inline __attribute__( ( __noinline__ ) )
# elif COMPILER_CLANG
# if __has_attribute(__always_inline__)
# define never_inline __attribute__( ( __noinline__ ) )
# else
# define never_inline
# endif
# else
# define never_inline
# endif
#endif
////////////////////////////////
//~ rjf: For-Loop Construct Macros
#ifndef defer_loop
#define defer_loop(begin, end) for (int _i_ = ((begin), 0); ! _i_; _i_ += 1, (end))
#endif
#ifndef defer_loop_checked
#define defer_loop_checked(begin, end) for (int _i_ = 2 * ! (begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end))
#endif
#ifndef each_enum_val
#define each_enum_val(type, it) type it = (type) 0; it < type ## _COUNT; it = (type)( it + 1 )
#endif
#ifndef each_non_zero_enum_val
#define each_non_zero_enum_val(type, it) type it = (type) 1; it < type ## _COUNT; it = (type)( it + 1 )
#endif
#ifndef stringify
#define stringify_(S) #S
#define stringify(S) stringify_(S)
#endif
#ifndef glue
#define glue_(A, B) A ## B
#define glue(A, B) glue_(A,B)
#endif
#define src_line_str stringify(__LINE__)
#ifndef do_once
#define do_once() \
local_persist int __do_once_counter_##src_line_str = 0; \
for(; __do_once_counter_##src_line_str != 1; __do_once_counter_##src_line_str = 1 ) \
#define do_once_defer( expression ) \
local_persist int __do_once_counter_##src_line_str = 0; \
for(;__do_once_counter_##src_line_str != 1; __do_once_counter_##src_line_str = 1, (expression)) \
#define do_once_start \
do \
{ \
local_persist \
bool done = false; \
if ( done ) \
break; \
done = true;
#define do_once_end \
} \
while(0);
#endif
#define ct_if(expr, then, else) _Generic( \
(&(char[1 + !!(EXPR)]){0}), \
char (*)[2]: (THEN), \
char (*)[1]: (ELSE) \
)
+10
View File
@@ -0,0 +1,10 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "markup.h"
#endif
inline void
set_thread_name(String8 string) {
prof_thread_name("%.*s", str8_varg(string));
os_set_thread_name(string);
}
+28
View File
@@ -0,0 +1,28 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "linkage.h"
# include "strings.h"
# include "thread_context.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
MD_API void set_thread_name(String8 string);
inline void
set_thread_namef(char *fmt, ...)
{
TempArena scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = str8fv(scratch.arena, fmt, args);
set_thread_name(string);
va_end(args);
scratch_end(scratch);
}
#define thread_namef(...) (set_thread_namef(__VA_ARGS__))
#define thread_name(str) (set_thread_name(str))
+1001
View File
File diff suppressed because it is too large Load Diff
+993
View File
@@ -0,0 +1,993 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "context_cracking.h"
# include "linkage.h"
# include "macros.h"
# include "platform.h"
# include "base_types.h"
#endif
////////////////////////////////
//~ rjf: Units
#ifndef KILOBTYES
#define KILOBYTES( x ) ( ( x ) * ( S64 )( 1024 ) )
#endif
#ifndef MEGABYTES
#define MEGABYTES( x ) ( MD_KILOBYTES( x ) * ( S64 )( 1024 ) )
#endif
#ifndef GIGABYTES
#define GIGABYTES( x ) ( MD_MEGABYTES( x ) * ( S64 )( 1024 ) )
#endif
#ifndef TERABYTES
#define TERABYTES( x ) ( MD_GIGABYTES( x ) * ( S64 )( 1024 ) )
#endif
#ifndef KB
#define KB(n) (((U64)(n)) << 10)
#endif
#ifndef MB
#define MB(n) (((U64)(n)) << 20)
#endif
#ifndef GB
#define GB(n) (((U64)(n)) << 30)
#endif
#ifndef TB
#define TB(n) (((U64)(n)) << 40)
#endif
#ifndef thosuand
#define thousand(n) ((n) * 1000)
#endif
#ifndef million
#define million(n) ((n) * 1000000)
#endif
#ifndef billion
#define billion(n) ((n) * 1000000000)
#endif
////////////////////////////////
//~ rjf: Type -> Alignment
#ifndef align_of
# if COMPILER_MSVC
# define align_of(T) __alignof(T)
# elif COMPILER_CLANG
# define align_of(T) __alignof(T)
# elif COMPILER_GCC
# define align_of(T) __alignof__(T)
# else
# error AlignOf not defined for this compiler.
# endif
#endif
////////////////////////////////
//~ rjf: Member Offsets
#ifndef member
#define member(T, m) ( ((T*) 0)->m )
#endif
#ifndef offset_of
#define offset_of(T, m) int_from_ptr(& member(T, m))
#endif
#ifndef member_from_offset
#define member_from_offset(T, ptr, off) (T) ((((U8 *) ptr) + (off)))
#endif
#ifndef cast_from_member
#define cast_from_member(T, m, ptr) (T*) (((U8*)ptr) - offset_of(T, m))
#endif
////////////////////////////////
//~ rjf: Memory Operation Macros
// TODO(Ed): Review usage of memmove here...(I guess wanting to avoid overlap faults..)
#ifndef memory_copy
# if OS_WINDOWS
void* memcpy_intrinsic(void* dest, const void* src, size_t count)
{
if (dest == NULL || src == NULL || count == 0) {
return NULL;
}
__movsb((unsigned char*)dest, (const unsigned char*)src, count);
return dest;
}
# define memory_copy(dst, src, size) memcpy_intrinsic((dst), (src), (size))
# else
# define memory_copy(dst, src, size) memmove((dst), (src), (size))
# endif
#endif
#ifndef memory_set
# if USE_VENDOR_MEMORY_OPS
# define memory_set(dst, byte, size) memset((dst), (byte), (size))
# else
# define memory_set(dst, byte, size) mem_set((dst), (byte), (size))
# endif
#endif
#ifndef memory_compare
#define memory_compare(a, b, size) memcmp((a), (b), (size))
#endif
#ifndef memory_str_len
#define memory_str_len(ptr) cstr_len(ptr)
#endif
#ifndef memory_copy_struct
#define memory_copy_struct(d, s) memory_copy((d), (s), sizeof( *(d)))
#endif
#ifndef memory_copy_array
#define memory_copy_array(d, s) memory_copy((d), (s), sizeof( d))
#endif
#ifndef memory_copy_type
#define memory_copy_type(d, s, c) memory_copy((d), (s), sizeof( *(d)) * (c))
#endif
#ifndef memory_zero
#define memory_zero(s,z) memory_set((s), 0, (z))
#endif
#ifndef memory_zero_struct
#define memory_zero_struct(s) memory_zero((s), sizeof( *(s)))
#endif
#ifndef memory_zero_array
#define memory_zero_array(a) memory_zero((a), sizeof(a))
#endif
#ifndef memory_zero_type
#define memory_zero_type(m, c) memory_zero((m), sizeof( *(m)) * (c))
#endif
#ifndef memory_match
#define memory_match(a, b, z) (memory_compare((a), (b), (z)) == 0)
#endif
#ifndef memory_match_struct
#define memory_match_struct(a, b) memory_match((a), (b), sizeof(*(a)))
#endif
#ifndef memory_match_array
#define memory_match_array(a, b) memory_match((a), (b), sizeof(a))
#endif
#ifndef memory_read
#define memory_read(T, p, e) ( ((p) + sizeof(T) <= (e)) ? ( *(T*)(p)) : (0) )
#endif
#ifndef memory_consume
#define memory_consume(T, p, e) ( ((p) + sizeof(T) <= (e)) ? ((p) += sizeof(T), *(T*)((p) - sizeof(T))) : ((p) = (e),0) )
#endif
////////////////////////////////
//~ rjf: Memory Functions
inline B32
memory_is_zero(void* ptr, U64 size)
{
B32 result = 1;
// break down size
U64 extra = (size & 0x7);
U64 count8 = (size >> 3);
// check with 8-byte stride
U64* p64 = (U64*)ptr;
if (result)
{
for (U64 i = 0; i < count8; i += 1, p64 += 1) {
if (*p64 != 0){
result = 0;
goto done;
}
}
}
// check extra
if (result)
{
U8* p8 = (U8*)p64;
for (U64 i = 0; i < extra; i += 1, p8 += 1) {
if (*p8 != 0) {
result = 0;
goto done;
}
}
}
done:;
return(result);
}
inline
void* mem_move( void* destination, void const* source, SSIZE byte_count )
{
if ( destination == NULL )
{
return NULL;
}
U8* dest_ptr = rcast( U8*, destination);
U8 const* src_ptr = rcast( U8 const*, source);
if ( dest_ptr == src_ptr )
return dest_ptr;
// NOTE: Non-overlapping
if ( src_ptr + byte_count <= dest_ptr || dest_ptr + byte_count <= src_ptr ) {
return memory_copy( dest_ptr, src_ptr, byte_count );
}
if ( dest_ptr < src_ptr )
{
if ( scast(UPTR, src_ptr) % size_of( SSIZE ) == scast(UPTR, dest_ptr) % size_of( SSIZE ) )
{
while ( pcast( UPTR, dest_ptr) % size_of( SSIZE ) )
{
if ( ! byte_count-- )
return destination;
*dest_ptr++ = *src_ptr++;
}
while ( byte_count >= size_of( SSIZE ) )
{
* rcast(SSIZE*, dest_ptr) = * rcast(SSIZE const*, src_ptr);
byte_count -= size_of( SSIZE );
dest_ptr += size_of( SSIZE );
src_ptr += size_of( SSIZE );
}
}
for ( ; byte_count; byte_count-- )
*dest_ptr++ = *src_ptr++;
}
else
{
if ( ( scast(UPTR, src_ptr) % size_of( SSIZE ) ) == ( scast(UPTR, dest_ptr) % size_of( SSIZE ) ) )
{
while ( scast(UPTR, dest_ptr + byte_count ) % size_of( SSIZE ) )
{
if ( ! byte_count-- )
return destination;
dest_ptr[ byte_count ] = src_ptr[ byte_count ];
}
while ( byte_count >= size_of( SSIZE ) )
{
byte_count -= size_of( SSIZE );
* rcast(SSIZE*, dest_ptr + byte_count ) = * rcast( SSIZE const*, src_ptr + byte_count );
}
}
while ( byte_count )
byte_count--, dest_ptr[ byte_count ] = src_ptr[ byte_count ];
}
return destination;
}
inline
void* mem_set( void* destination, U8 fill_byte, SSIZE byte_count )
{
if ( destination == NULL )
{
return NULL;
}
SSIZE align_offset;
U8* dest_ptr = rcast( U8*, destination);
U32 fill_word = ( ( U32 )-1 ) / 255 * fill_byte;
if ( byte_count == 0 )
return destination;
dest_ptr[ 0 ] = dest_ptr[ byte_count - 1 ] = fill_byte;
if ( byte_count < 3 )
return destination;
dest_ptr[ 1 ] = dest_ptr[ byte_count - 2 ] = fill_byte;
dest_ptr[ 2 ] = dest_ptr[ byte_count - 3 ] = fill_byte;
if ( byte_count < 7 )
return destination;
dest_ptr[ 3 ] = dest_ptr[ byte_count - 4 ] = fill_byte;
if ( byte_count < 9 )
return destination;
align_offset = -scast(SPTR, dest_ptr ) & 3;
dest_ptr += align_offset;
byte_count -= align_offset;
byte_count &= -4;
* rcast( U32*, ( dest_ptr + 0 ) ) = fill_word;
* rcast( U32*, ( dest_ptr + byte_count - 4 ) ) = fill_word;
if ( byte_count < 9 )
return destination;
* rcast( U32*, dest_ptr + 4 ) = fill_word;
* rcast( U32*, dest_ptr + 8 ) = fill_word;
* rcast( U32*, dest_ptr + byte_count - 12 ) = fill_word;
* rcast( U32*, dest_ptr + byte_count - 8 ) = fill_word;
if ( byte_count < 25 )
return destination;
* rcast( U32*, dest_ptr + 12 ) = fill_word;
* rcast( U32*, dest_ptr + 16 ) = fill_word;
* rcast( U32*, dest_ptr + 20 ) = fill_word;
* rcast( U32*, dest_ptr + 24 ) = fill_word;
* rcast( U32*, dest_ptr + byte_count - 28 ) = fill_word;
* rcast( U32*, dest_ptr + byte_count - 24 ) = fill_word;
* rcast( U32*, dest_ptr + byte_count - 20 ) = fill_word;
* rcast( U32*, dest_ptr + byte_count - 16 ) = fill_word;
align_offset = 24 + scast(UPTR, dest_ptr ) & 4;
dest_ptr += align_offset;
byte_count -= align_offset;
{
U64 fill_doubleword = ( scast( U64, fill_word) << 32 ) | fill_word;
while ( byte_count > 31 )
{
* rcast( U64*, dest_ptr + 0 ) = fill_doubleword;
* rcast( U64*, dest_ptr + 8 ) = fill_doubleword;
* rcast( U64*, dest_ptr + 16 ) = fill_doubleword;
* rcast( U64*, dest_ptr + 24 ) = fill_doubleword;
byte_count -= 32;
dest_ptr += 32;
}
}
return destination;
}
////////////////////////////////
//~ rjf: Atomic Operations
#ifndef ins_atomic_u64_eval
# if OS_WINDOWS
# if ARCH_X64
# define ins_atomic_u64_eval(x) InterlockedAdd64((volatile __int64 *)(x), 0)
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x), (c))
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((volatile __int64 *)(x), c)
# define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((volatile __int64 *)(x), (k), (c))
# define ins_atomic_u32_eval(x,c) InterlockedAdd((volatile LONG *)(x), 0)
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x), (c))
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x), (k), (c))
# define ins_atomic_ptr_eval_assign(x,c) (void*) ins_atomic_u64_eval_assign((volatile __int64 *)(x), (__int64)(c))
# else
# error Atomic intrinsics not defined for this operating system / architecture combination.
# endif
# elif OS_LINUX
# if ARCH_X64
# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1)
# else
# error Atomic intrinsics not defined for this operating system / architecture combination.
# endif
# else
# error Atomic intrinsics not defined for this operating system.
# endif
#endif
////////////////////////////////
//~ rjf: Linked List Building Macros
//- rjf: linked list macro helpers
#ifndef check_nil
#define check_nil(nil, p) ((p) == 0 || (p) == nil)
#endif
#ifndef set_nil
#define set_nil(nil, p) ((p) = nil)
#endif
//- rjf: doubly-linked-lists
#ifndef MD_LINKED_LIST_PURE_MACRO
#define MD_LINKED_LIST_PURE_MACRO 0
#endif
#ifndef dll_insert_npz
// TODO(Ed): Review...
inline void
dll__insert_npz(
void* nil,
void** f, void** f_prev,
void** l, void** l_next,
void* p, void** p_next, void** p_next_prev,
void* n, void** n_prev, void** n_next
)
{
if (check_nil(nil, *f)) {
*f = n;
*l = n;
*n_prev = nil;
*n_next = nil;
}
else
{
if (check_nil(nil, p)) {
*n_next = *f;
*f_prev = n;
*f = n;
*n_prev = nil;
}
else
{
if (p == *l) {
*l_next = n;
*n_prev = *l;
*l = n;
*n_next = nil;
}
else
{
if ( ! check_nil(nil, p) && check_nil(nil, *p_next)) {
*p_next_prev = n;
}
*n_next = *p_next;
*p_next = n;
*n_prev = p;
}
}
}
}
#if ! MD_LINKED_LIST_PURE_MACRO
// insert next-previous with nil
#define dll_insert_npz(nil, f, l, p, n, next, prev) dll__insert_npz(nil, &f, &f->prev, &l, &l->next, p, &p->next, &p->next->prev, n, &n->prev, &n->next)
#else
// insert next-previous with nil
#define dll_insert_npz(nil, f, l, p, n, next, prev) \
( \
check_nil(nil, f) ? ( \
(f) = (l) = (n), \
set_nil(nil, (n)->next), \
set_nil(nil, (n)->prev) \
) \
: ( \
check_nil(nil, p) ? ( \
(n)->next = (f), \
(f)->prev = (n), \
(f) = (n), \
set_nil(nil,(n)->prev) \
) \
: ((p) == (l)) ? ( \
(l)->next = (n), \
(n)->prev = (l), \
(l) = (n), \
set_nil(nil, (n)->next) \
) \
: ( \
( \
( ! check_nil(nil, p) && check_nil(nil, (p)->next) ) ? \
(0) \
: ( (p)->next->prev = (n) ) \
), \
((n)->next = (p)->next), \
((p)->next = (n)), \
((n)->prev = (p)) \
) \
) \
)
// ! MD_LINKED_LIST_PURE_MACRO
#endif
// dll_insert_npz
#endif
#ifndef dll_push_back_npz
// push-back next-previous with nil
#define dll_push_back_npz(nil, f, l, n, next, prev) dll_insert_npz(nil, f, l, l, n, next, prev)
#endif
#ifndef dll_push_front_npz
// push-fornt next-previous with nil
#define dll_push_front_npz(nil, f, l, n, next, prev) dll_insert_npz(nil, l, f, f, n, prev, next)
#endif
#ifndef dll_remove_npz
inline void
dll__remove_npz(
void* nil,
void** f,
void** l, void* l_prev,
void* n, void* n_next, void** n_next_prev,
void* n_prev, void** n_prev_next
)
{
if (n == *f) {
*f = n_next;
}
if (n == *l) {
*l = l_prev;
}
if (check_nil(nil, n_prev)) {
*n_prev_next = n_next;
}
if (! check_nil(nil, n_next)) {
*n_next_prev = n_prev;
}
}
#if ! MD_LINKED_LIST_PURE_MACRO
// remove next-previous with nil
#define dll_remove_npz(nil, f, l, n, next, prev) dll__remove_npz(nil, &f, &l, l->prev, n, n->next, &n->next->prev, n->prev, &n->prev->next)
#else
// remove next-previous with nil
#define dll_remove_npz(nil, f, l, n, next, prev) \
( \
( \
(n) == (f) ? \
(f) = (n)->next \
: (0) \
), \
( \
(n) == (l) ? \
(l) = (l)->prev \
: (0) \
), \
( \
check_nil(nil,(n)->prev) ? \
(0) \
: ((n)->prev->next = (n)->next) \
), \
( \
check_nil(nil,(n)->next) ? \
(0) \
: ((n)->next->prev = (n)->prev) \
) \
)
// ! MD_LINKED_LIST_PURE_MACRO
#endif
// dll_remove_npz
#endif
//- rjf: singly-linked, doubly-headed lists (queues)
#ifndef sll_queue_push_nz
inline void
sll__queue_push_nz(
void* nil,
void** f,
void** l, void** l_next,
void* n, void** n_next
)
{
if (check_nil(nil, *f)) {
*f = n;
*l = n;
*n_next = nil;
}
else {
*l_next = n;
*l = n;
*n_next = nil;
}
}
// queue-push next with nil
#if ! MD_LINKED_LIST_PURE_MACRO
#define sll_queue_push_nz(nil, f, l, n, next) sll__queue_push_nz(nil, &f, &l, &l->next, n, &n->next)
#else
#define sll_queue_push_nz(nil, f, l, n, next) \
( \
check_nil(nil, f) ? ( \
(f) = (l) = (n), \
set_nil(nil, (n)->next) \
) \
: ( \
(l)->next=(n), \
(l) = (n), \
set_nil(nil,(n)->next) \
) \
)
// ! MD_LINKED_LIST_PURE_MACRO
#endif
// sll_queue_push_nz
#endif
#ifndef sll_queue_push_front_nz
inline void
sll__queue_push_front_nz(void* nil, void** f, void** l, void* n, void** n_next) {
if (check_nil(nil, *f)) {
*f = n;
*l = n;
*n_next = nil;
}
else {
*n_next = f;
*f = n;
}
}
// queue-push-front next with nil
#if ! MD_LINKED_LIST_PURE_MACRO
#define sll_queue_push_front_nz(nil, f, l, n, next) sll__queue_push_front_nz(nil, &f, &l, n, &n->next)
#else
#define sll_queue_push_front_nz(nil, f, l, n, next) \
( \
check_nil(nil, f) ? ( \
(f) = (l) = (n), \
set_nil(nil,(n)->next) \
) \
: ( \
(n)->next = (f), \
(f) = (n) \
) \
)
// ! MD_LINKED_LIST_PURE_MACRO
#endif
#endif
#ifndef sll_queue_pop_nz
inline void
sll__queue_pop_nz(void* nil, void** f, void* f_next, void** l)
{
if (*f == *l) {
*f = nil;
*l = nil;
}
else {
*f = f_next;
}
}
// queue-pop next with nil
#if ! MD_LINKED_LIST_PURE_MACRO
#define sll_queue_pop_nz(nil, f, l, next) sll__queue_pop_nz(nil, &f, f->next, &l)
#else
#define sll_queue_pop_nz(nil, f, l, next) \
( \
(f) == (l) ? ( \
set_nil(nil,f), \
set_nil(nil,l) \
) \
: ( \
(f)=(f)->next \
) \
)
// ! MD_LINKED_LIST_PURE_MACRO
#endif
// sll_queue_pop_nz
#endif
//- rjf: singly-linked, singly-headed lists (stacks)
#ifndef sll_stack_push_n
#define sll_stack_push_n(f,n,next) ( (n)->next = (f), (f) = (n) )
#endif
#ifndef sll_stack_pop_n
#define sll_stack_pop_n(f,next) ( (f) = (f)->next )
#endif
//- rjf: doubly-linked-list helpers
#ifndef dll_insert_np
#define dll_insert_np(f, l, p, n, next, prev) dll_insert_npz (0, f, l, p, n, next, prev)
#endif
#ifndef dll_push_back_np
#define dll_push_back_np(f, l, n, next, prev) dll_push_back_npz (0, f, l, n, next, prev)
#endif
#ifndef dll_push_front_np
#define dll_push_front_np(f, l, n, next, prev) dll_push_front_npz(0, f, l, n, next, prev)
#endif
#ifndef dll_remove_np
#define dll_remove_np(f, l, n, next, prev) dll_remove_npz (0, f, l, n, next, prev)
#endif
#ifndef dll_insert
#define dll_insert(f, l, p, n) dll_insert_npz (0, f, l, p, n, next, prev)
#endif
#ifndef dll_push_back
#define dll_push_back(f, l, n) dll_push_back_npz (0, f, l, n, next, prev)
#endif
#ifndef dll_push_front
#define dll_push_front(f, l, n) dll_push_front_npz(0, f, l, n, next, prev)
#endif
#ifndef dll_remove
#define dll_remove(f, l, n) dll_remove_npz (0, f, l, n, next, prev)
#endif
//- rjf: singly-linked, doubly-headed list helpers
#ifndef sll_queue_push_n
#define sll_queue_push_n(f, l, n, next) sll_queue_push_nz (0, f, l, n, next)
#endif
#ifndef sll_queue_push_front_n
#define sll_queue_push_front_n(f, l, n, next) sll_queue_push_front_nz(0, f, l, n, next)
#endif
#ifndef sll_queue_pop_n
#define sll_queue_pop_n(f, l, next) sll_queue_pop_nzs (0, f, l, next)
#endif
#ifndef sll_queue_push
#define sll_queue_push(f, l, n) sll_queue_push_nz (0, f, l, n, next)
#endif
#ifndef sll_queue_push_front
#define sll_queue_push_front(f, l ,n) sll_queue_push_front_nz(0, f, l, n, next)
#endif
#ifndef sll_queue_pop
#define sll_queue_pop(f, l) sll_queue_pop_nz (0, f, l, next)
#endif
//- rjf: singly-linked, singly-headed list helpers
#ifndef sll_stack_push
#define sll_stack_push(f, n) sll_stack_push_n(f, n, next)
#endif
#ifndef sll_stack_pop
#define sll_stack_pop(f) sll_stack_pop_n (f, next)
#endif
////////////////////////////////
//~ rjf: Address Sanitizer Markup
#ifndef NO_ASAN
# if COMPILER_MSVC
# if defined(__SANITIZE_ADDRESS__)
# define ASAN_ENABLED 1
# define NO_ASAN __declspec(no_sanitize_address)
# else
# define NO_ASAN
# endif
# elif COMPILER_CLANG
# if defined(__has_feature)
# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
# define ASAN_ENABLED 1
# endif
# endif
# define NO_ASAN __attribute__((no_sanitize("address")))
# else
# define NO_ASAN
# endif
#endif
#ifndef asan_poison_memory_region
# if MD_ASAN_ENABLED
# pragma comment(lib, "clang_rt.asan-x86_64.lib")
MD_C_API void __asan_poison_memory_region(void const volatile *addr, size_t size);
MD_C_API void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
# define asan_poison_memory_region(addr, size) __asan_poison_memory_region((addr), (size))
# define asan_unpoison_memory_region(addr, size) __asan_unpoison_memory_region((addr), (size))
# else
# define asan_poison_memory_region(addr, size) ((void)(addr), (void)(size))
# define asan_unpoison_memory_region(addr, size) ((void)(addr), (void)(size))
# endif
#endif
////////////////////////////////
//~ rjf: Misc. Helper Macros
#ifndef array_count
#define array_count(a) (sizeof(a) / sizeof((a)[0]))
#endif
#ifndef ceil_integer_div
#define ceil_integer_div(a,b) (((a) + (b) - 1) / (b))
#endif
#ifndef swap
#define swap(T, a, b) do { T t__ = a; a = b; b = t__; } while(0)
#endif
#ifndef int_from_ptr
# if ARCH_64BIT
# define int_from_ptr(ptr) ((U64)(ptr))
# elif ARCH_32BIT
# define int_from_ptr(ptr) ((U32)(ptr))
# else
# error Missing pointer-to-integer cast for this architecture.
# endif
#endif
#ifndef ptr_from_int
#define ptr_from_int(i) (void*)((U8*)0 + (i))
#endif
#ifndef compose_64bit
#define compose_64bit(a,b) ((((U64)a) << 32) | ((U64)b));
#endif
#ifndef align_pow2
#define align_pow2(x,b) (((x) + (b) - 1) & ( ~((b) - 1)))
#endif
#ifndef align_down_pow2
#define align_down_pow2(x,b) ((x) & (~((b) - 1)))
#endif
#ifndef align_pad_pow2
#define align_pad_pow2(x,b) ((0-(x)) & ((b) - 1))
#endif
#ifndef is_pow2
#define is_pow2(x) ((x) != 0 && ((x ) & ((x) - 1)) == 0)
#endif
#ifndef is_pow2_or_zero
#define is_pow2_or_zero(x) ((((x) - 1) & (x)) == 0)
#endif
#ifndef extract_bit
#define extract_bit(word, idx) (((word) >> (idx)) & 1)
#endif
#ifndef zero_struct
# if LANG_CPP
# define zero_struct {}
# else
# define zero_struct {0}
# endif
#endif
#ifndef this_function_name
# if COMPILER_MSVC && COMPILER_MSVC_YEAR < 2015
# define this_function_name "unknown"
# else
# define this_function_name __func__
# endif
#endif
#ifndef read_only
# if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
# pragma section(".rdata$", read)
# define read_only __declspec(allocate(".rdata$"))
# elif (COMPILER_CLANG && OS_LINUX)
# define read_only __attribute__((section(".rodata")))
# else
// NOTE(rjf): I don't know of a useful way to do this in GCC land.
// __attribute__((section(".rodata"))) looked promising, but it introduces a
// strange warning about malformed section attributes, and it doesn't look
// like writing to that section reliably produces access violations, strangely
// enough. (It does on Clang)
# define read_only
# endif
#endif
#ifndef local_persist
#define local_persist static
#endif
#if COMPILER_MSVC
# define thread_static __declspec(thread)
#elif COMPILER_CLANG || COMPILER_GCC
# define thread_static __thread
#endif
#if COMPILER_CPP
// Already Defined
#elif COMPILER_C && __STDC_VERSION__ >= 201112L
# define thread_local _Thread_local
#elif COMPILER_MSVC
# define thread_local __declspec(thread)
#elif COMPILER_CLANG
# define thread_local __thread
#else
# error "No thread local support"
#endif
////////////////////////////////
//~ rjf: Safe Casts
inline U16
safe_cast_u16(U32 x) {
assert_always(x <= MAX_U16);
U16 result = (U16)x;
return result;
}
inline U32
safe_cast_u32(U64 x) {
assert_always(x <= MAX_U32);
U32 result = (U32)x;
return result;
}
inline S32
safe_cast_s32(S64 x) {
assert_always(x <= MAX_S32);
S32 result = (S32)x;
return result;
}
////////////////////////////////
//~ rjf: Large Base Type Functions
inline U128 u128_zero (void) { U128 v = {0}; return v; }
inline U128 u128_make (U64 v0, U64 v1) { U128 v = {v0, v1}; return v; }
inline B32 u128_match(U128 a, U128 b) { return memory_match_struct(&a, &b); }
////////////////////////////////
//~ rjf: Bit Patterns
inline U32 u32_from_u64_saturate(U64 x) { U32 x32 = (x > MAX_U32) ? MAX_U32 : (U32)x; return(x32); }
inline U64
u64_up_to_pow2(U64 x) {
if (x == 0) {
x = 1;
}
else {
x -= 1;
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
x |= (x >> 32);
x += 1;
}
return(x);
}
inline S32
extend_sign32(U32 x, U32 size) {
U32 high_bit = size * 8;
U32 shift = 32 - high_bit;
S32 result = ((S32)x << shift) >> shift;
return result;
}
inline S64
extend_sign64(U64 x, U64 size) {
U64 high_bit = size * 8;
U64 shift = 64 - high_bit;
S64 result = ((S64)x << shift) >> shift;
return result;
}
inline F32 inf32 (void) { union { U32 u; F32 f; } x; x.u = EXPONENT32; return(x.f); }
inline F32 neg_inf32(void) { union { U32 u; F32 f; } x; x.u = SIGN32 | EXPONENT32; return(x.f); }
inline U16
bswap_u16(U16 x)
{
U16 result = (((x & 0xFF00) >> 8) |
((x & 0x00FF) << 8));
return result;
}
inline U32
bswap_u32(U32 x)
{
U32 result = (((x & 0xFF000000) >> 24) |
((x & 0x00FF0000) >> 8) |
((x & 0x0000FF00) << 8) |
((x & 0x000000FF) << 24));
return result;
}
inline U64
bswap_u64(U64 x)
{
// TODO(nick): naive bswap, replace with something that is faster like an intrinsic
U64 result = (((x & 0xFF00000000000000ULL) >> 56) |
((x & 0x00FF000000000000ULL) >> 40) |
((x & 0x0000FF0000000000ULL) >> 24) |
((x & 0x000000FF00000000ULL) >> 8) |
((x & 0x00000000FF000000ULL) << 8) |
((x & 0x0000000000FF0000ULL) << 24) |
((x & 0x000000000000FF00ULL) << 40) |
((x & 0x00000000000000FFULL) << 56));
return result;
}
#if ARCH_LITTLE_ENDIAN
# define from_be_u16(x) bswap_u16(x)
# define from_be_u32(x) bswap_u32(x)
# define from_be_u64(x) bswap_u64(x)
#else
# define from_be_u16(x) (x)
# define from_be_u32(x) (x)
# define from_be_u64(x) (x)
#endif
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
inline U64 count_bits_set16(U16 val) { return __popcnt16(val); }
inline U64 count_bits_set32(U32 val) { return __popcnt (val); }
inline U64 count_bits_set64(U64 val) { return __popcnt64(val); }
inline U64 ctz32(U32 mask) { unsigned long idx; _BitScanForward (&idx, mask); return idx; }
inline U64 ctz64(U64 mask) { unsigned long idx; _BitScanForward64(&idx, mask); return idx; }
inline U64 clz32(U32 mask) { unsigned long idx; _BitScanReverse (&idx, mask); return 31 - idx; }
inline U64 clz64(U64 mask) { unsigned long idx; _BitScanReverse64(&idx, mask); return 63 - idx; }
#elif COMPILER_CLANG || COMPILER_GCC
inline U64 count_bits_set16(U16 val) { NotImplemented; return 0; }
inline U64 count_bits_set32(U32 val) { NotImplemented; return 0; }
inline U64 count_bits_set64(U64 val) { NotImplemented; return 0; }
inline U64 ctz32(U32 val) { NotImplemented; return 0; }
inline U64 ctz64(U32 val) { NotImplemented; return 0; }
inline U64 clz32(U32 val) { NotImplemented; return 0; }
inline U64 clz64(U64 val) { NotImplemented; return 0; }
#else
# error "Bit intrinsic functions not defined for this compiler."
#endif
+486
View File
@@ -0,0 +1,486 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "memory.h"
# include "memory_substrate.h"
# include "../os/os.h"
#endif
void*
default_resize_align( AllocatorInfo a, void* old_memory, SSIZE old_size, SSIZE new_size, SSIZE alignment )
{
if ( ! old_memory )
return alloc_align( a, new_size, alignment );
if ( new_size == 0 )
{
alloc_free( a, old_memory );
return nullptr;
}
if ( new_size < old_size )
new_size = old_size;
if ( old_size == new_size )
{
return old_memory;
}
else
{
void* new_memory = alloc_align( a, new_size, alignment );
if ( ! new_memory )
return nullptr;
mem_move( new_memory, old_memory, md_min( new_size, old_size ) );
alloc_free( a, old_memory );
return new_memory;
}
}
#ifdef MD_HEAP_ANALYSIS
#define GEN_HEAP_STATS_MAGIC 0xDEADC0DE
typedef struct _heap_stats _heap_stats;
struct _heap_stats
{
U32 magic;
SSIZE used_memory;
SSIZE alloc_count;
};
global _heap_stats _heap_stats_info;
void
heap_stats_init( void )
{
memory_zero_struct( &_heap_stats_info );
_heap_stats_info.magic = GEN_HEAP_STATS_MAGIC;
}
SSIZE
heap_stats_used_memory( void )
{
assert_msg( _heap_stats_info.magic == GEN_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" );
return _heap_stats_info.used_memory;
}
SSIZE
heap_stats_alloc_count( void )
{
assert_msg( _heap_stats_info.magic == GEN_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" );
return _heap_stats_info.alloc_count;
}
void
heap_stats_check( void )
{
assert_msg( _heap_stats_info.magic == GEN_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" );
assert( _heap_stats_info.used_memory == 0 );
assert( _heap_stats_info.alloc_count == 0 );
}
typedef struct _heap_alloc_info _heap_alloc_info;
struct _heap_alloc_info
{
SSIZE size;
void* physical_start;
};
#endif
void*
heap_allocator_proc( void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags )
{
void* ptr = nullptr;
// unused( allocator_data );
// unused( old_size );
if ( ! alignment )
alignment = MD_DEFAULT_MEMORY_ALIGNMENT;
#ifdef MD_HEAP_ANALYSIS
ssize alloc_info_size = size_of( _heap_alloc_info );
ssize alloc_info_remainder = ( alloc_info_size % alignment );
ssize track_size = max( alloc_info_size, alignment ) + alloc_info_remainder;
switch ( type )
{
case EAllocatorMode_FREE :
{
if ( ! old_memory )
break;
_heap_alloc_info* alloc_info = rcast( _heap_alloc_info*, old_memory) - 1;
_heap_stats_info.used_memory -= alloc_info->size;
_heap_stats_info.alloc_count--;
old_memory = alloc_info->physical_start;
}
break;
case EAllocatorMode_ALLOC :
{
size += track_size;
}
break;
default :
break;
}
#endif
switch ( mode )
{
#if defined( COMPILER_MSVC ) || ( defined( COMPILER_GCC ) && defined( OS_WINDOWS ) ) || ( defined( COMPILER_TINYC ) && defined( OS_WINDOWS ) )
case AllocatorMode_Alloc:
{
ptr = _aligned_malloc( size, alignment );
if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO )
memory_zero( ptr, size );
}
break;
case AllocatorMode_Free:
_aligned_free( old_memory );
break;
case AllocatorMode_Resize:
{
AllocatorInfo a = heap();
ptr = default_resize_align( a, old_memory, old_size, size, alignment );
}
break;
#elif defined( OS_LINUX ) && ! defined( CPU_ARM ) && ! defined( COMPILER_TINYC )
case EAllocation_ALLOC :
{
ptr = aligned_alloc( alignment, ( size + alignment - 1 ) & ~( alignment - 1 ) );
if ( flags & GEN_ALLOCATOR_FLAG_CLEAR_TO_ZERO )
{
zero_size( ptr, size );
}
}
break;
case EAllocation_Freee :
{
free( old_memory );
}
break;
case EAllocation_RESIZE :
{
AllocatorInfo a = heap();
ptr = default_resize_align( a, old_memory, old_size, size, alignment );
}
break;
#else
case EAllocType_ALLOC :
{
posix_memalign( &ptr, alignment, size );
if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO )
{
zero_size( ptr, size );
}
}
break;
case EAllocType_FREE :
{
free( old_memory );
}
break;
case EAllocType_RESIZE :
{
AllocatorInfo a = heap();
ptr = default_resize_align( a, old_memory, old_size, size, alignment );
}
break;
#endif
case AllocatorMode_FreeAll:
break;
case AllocatorMode_QueryType:
return (void*) AllocatorType_Heap;
case AllocatorMode_QuerySupport:
return (void*) (
AllocatorQuery_Alloc | AllocatorQuery_Free | AllocatorQuery_Resize | AllocatorQuery_ResizeGrow | AllocatorQuery_ResizeShrink
);
}
#ifdef GEN_HEAP_ANALYSIS
if ( type == AllocatorMode_Alloc )
{
_heap_alloc_info* alloc_info = rcast( _heap_alloc_info*, rcast( char*, ptr) + alloc_info_remainder );
zero_item( alloc_info );
alloc_info->size = size - track_size;
alloc_info->physical_start = ptr;
ptr = rcast( void*, alloc_info + 1 );
_heap_stats_info.used_memory += alloc_info->size;
_heap_stats_info.alloc_count++;
}
#endif
return ptr;
}
VArena*
varena__alloc(VArenaParams params)
{
if (params.reserve_size == 0) {
params.reserve_size = VARENA_DEFAULT_RESERVE;
}
if (params.commit_size == 0) {
params.commit_size = VARENA_DEFAULT_COMMIT;
}
// rjf: round up reserve/commit sizes
U64 reserve_size = params.reserve_size;
U64 commit_size = params.commit_size;
void* base = nullptr;
if (params.flags & VArenaFlag_LargePages)
{
reserve_size = align_pow2(reserve_size, os_get_system_info()->large_page_size);
commit_size = align_pow2(commit_size, os_get_system_info()->large_page_size);
base = os_reserve_large(reserve_size);
os_commit_large(base, commit_size);
asan_poison_memory_region(base, params.commit_size);
}
else
{
reserve_size = align_pow2(reserve_size, os_get_system_info()->page_size);
commit_size = align_pow2(commit_size, os_get_system_info()->page_size);
base = os_reserve(reserve_size);
B32 commit_result = os_commit(base, commit_size);
assert(commit_result == 1);
asan_poison_memory_region(base, params.commit_size);
}
// NOTE(Ed): Panic on varena creation failure
#if OS_FEATURE_GRAPHICAL
if(unlikely(base == 0))
{
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
os_abort(1);
}
#endif
SPTR header_size = align_pow2(size_of(VArena), MD_DEFAULT_MEMORY_ALIGNMENT);
asan_unpoison_memory_region(base, header_size);
VArena* vm = rcast(VArena*, base);
vm->reserve_start = rcast(SPTR, base) + header_size;
vm->reserve = reserve_size;
vm->commit_size = params.commit_size;
vm->committed = commit_size;
vm->commit_used = 0;
vm->flags = params.flags;
return vm;
}
void
varena_release(VArena* arena)
{
os_release(arena, arena->reserve);
arena = nullptr;
}
void*
varena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE requested_size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags)
{
OS_SystemInfo const* info = os_get_system_info();
VArena* vm = rcast(VArena*, allocator_data);
void* allocated_mem = nullptr;
switch (mode)
{
case AllocatorMode_Alloc:
{
assert_msg(requested_size != 0, "requested_size is 0");
requested_size = align_pow2(requested_size, alignment);
UPTR current_offset = vm->reserve_start + vm->commit_used;
UPTR size_to_allocate = requested_size;
UPTR to_be_used = vm->commit_used + size_to_allocate;
SPTR reserve_left = vm->reserve - vm->committed;
assert(to_be_used < reserve_left);
UPTR header_offset = vm->reserve_start - scast(UPTR, vm);
UPTR commit_left = vm->committed - vm->commit_used - header_offset;
B32 needs_more_commited = commit_left < size_to_allocate;
if (needs_more_commited)
{
UPTR next_commit_size;
if (vm->flags & VArenaFlag_LargePages) {
next_commit_size = reserve_left > 0 ? md_max(vm->commit_size, size_to_allocate) : scast(UPTR, align_pow2( abs(reserve_left), os_get_system_info()->large_page_size));
}
else {
next_commit_size = reserve_left > 0 ? md_max(vm->commit_size, size_to_allocate) : scast(UPTR, align_pow2(abs(reserve_left), os_get_system_info()->page_size));
}
if (next_commit_size) {
void* next_commit_start = rcast(void*, rcast(UPTR, vm) + vm->committed);
B32 commit_result = os_commit(next_commit_start, next_commit_size);
if (commit_result == false) {
break;
}
vm->committed += next_commit_size;
}
}
allocated_mem = rcast(void*, current_offset);
vm->commit_used += size_to_allocate;
}
break;
case AllocatorMode_Free:
{
}
break;
case AllocatorMode_FreeAll:
{
vm->commit_used = 0;
}
break;
case AllocatorMode_Resize:
{
assert(old_memory != nullptr);
assert(old_size > 0);
assert_msg(old_size == requested_size, "Requested resize when none needed");
requested_size = align_pow2(requested_size, alignment);
old_size = align_pow2(old_size, alignment);
UPTR old_memory_offset = scast(UPTR, old_memory) + scast(UPTR, old_size);
UPTR current_offset = scast(UPTR, vm->reserve_start) + scast(UPTR, vm->commit_used);
assert_msg(old_memory_offset == current_offset, "Cannot resize existing allocation in VArena unless it was the last allocated");
B32 requested_shrink = requested_size >= old_size;
if (requested_shrink) {
vm->commit_used -= rcast(UPTR, align_pow2(requested_size, alignment));
allocated_mem = old_memory;
break;
}
UPTR size_to_allocate = requested_size - old_size, alignment;
UPTR header_offset = vm->reserve_start - scast(UPTR, vm);
UPTR commit_left = vm->committed - vm->commit_used - header_offset;
B32 needs_more_commited = commit_left < size_to_allocate;
if (needs_more_commited)
{
SPTR reserve_left = vm->reserve - vm->committed;
UPTR next_commit_size;
if (vm->flags & VArenaFlag_LargePages) {
next_commit_size = reserve_left > 0 ? vm->commit_size : scast(UPTR, align_pow2( -reserve_left, os_get_system_info()->large_page_size));
}
else {
next_commit_size = reserve_left > 0 ? vm->commit_size : scast(UPTR, align_pow2(abs(reserve_left), os_get_system_info()->page_size));
}
if (next_commit_size) {
B32 commit_result = os_commit(vm, next_commit_size);
if (commit_result == false) {
break;
}
}
}
allocated_mem = old_memory;
vm->commit_used += size_to_allocate;
}
break;
case AllocatorMode_QueryType:
{
return (void*) AllocatorType_VArena;
}
break;
case AllocatorMode_QuerySupport:
{
return (void*) (
AllocatorQuery_Alloc | AllocatorQuery_FreeAll | AllocatorQuery_Resize | AllocatorQuery_ResizeGrow | AllocatorQuery_ResizeShrink
);
}
break;
}
return allocated_mem;
}
void*
farena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags)
{
FArena* arena = rcast(FArena*, allocator_data);
void* allocated_mem = nullptr;
switch (mode)
{
case AllocatorMode_Alloc:
{
SPTR end = scast(SPTR, arena->slice.data) + arena->used;
SSIZE total_size = align_pow2(size, alignment);
if (arena->used + total_size > arena->slice.len ) {
// Out of memory
return allocated_mem;
}
allocated_mem = scast(void*, end);
arena->used += total_size;
}
break;
case AllocatorMode_Free:
{
}
break;
case AllocatorMode_FreeAll:
{
arena->used = 0;
}
break;
case AllocatorMode_Resize:
{
assert(old_memory != nullptr);
assert(old_size > 0);
assert_msg(old_size == size, "Requested resize when none needed");
size = align_pow2(size, alignment);
old_size = align_pow2(size, alignment);
SPTR old_memory_offset = scast(SPTR, old_memory) + old_size;
SPTR current_offset = scast(SPTR, arena->slice.data) + arena->used;
assert_msg(old_memory_offset == current_offset, "Cannot resize existing allocation in VArena unless it was the last allocated");
B32 requested_shrink = size >= old_size;
if (requested_shrink) {
arena->used -= size;
allocated_mem = old_memory;
break;
}
allocated_mem = old_memory;
arena->used += size;
}
break;
case AllocatorMode_QueryType:
return (void*) AllocatorType_FArena;
break;
case AllocatorMode_QuerySupport:
return (void*) (
AllocatorQuery_Alloc | AllocatorQuery_FreeAll | AllocatorQuery_Resize | AllocatorQuery_ResizeGrow | AllocatorQuery_ResizeShrink
);
break;
}
return allocated_mem;
}
+293
View File
@@ -0,0 +1,293 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "context_cracking.h"
# include "linkage.h"
# include "macros.h"
# include "platform.h"
# include "base_types.h"
# include "memory.h"
#endif
// This provides an alterntive memory strategy to HMH/Casey Muratori/RJF styled arenas
// The library is derived from zpl-c which in-turn
// is related to the gb headers an thus the Odin-lang memory strategy
// Users can override the underlying memory allocator used, even for the HMH arena memory strategy.
#ifndef MD__ONES
#define MD__ONES ( scast( GEN_NS usize, - 1) / MD_U8_MAX )
#define MD__HIGHS ( MD__ONES * ( MD_U8_MAX / 2 + 1 ) )
#define MD__HAS_ZERO( x ) ( ( ( x ) - MD__ONES ) & ~( x ) & MD__HIGHS )
#endif
// Return value of allocator_type
typedef U64 AllocatorType;
enum
{
AllocatorType_Heap = 0, // Genreal heap allocator
AllocatorType_VArena = 1, // Arena allocator backed by virtual address space
AllocatorType_FArena = 2, // Fixed arena backed back by a fixed size block of memory (usually a byte slice)
AllocatorType_Arena = 3, // Composite arena used originally by RAD Debugger & Metadesk
};
typedef U32 AllocatorMode;
enum AllocatorMode
{
AllocatorMode_Alloc,
AllocatorMode_Free,
AllocatorMode_FreeAll,
AllocatorMode_Resize,
AllocatorMode_QueryType,
AllocatorMode_QuerySupport,
};
typedef U64 AllocatorQueryFlags;
enum
{
AllocatorQuery_Alloc = (1 << 0),
AllocatorQuery_Free = (1 << 1),
AllocatorQuery_FreeAll = (1 << 2),
AllocatorQuery_Resize = (1 << 3), // Supports both grow and shrink
AllocatorQuery_ResizeShrink = (1 << 4),
AllocatorQuery_ResizeGrow = (1 << 5),
};
typedef void*(AllocatorProc)( void* allocator_data, AllocatorMode type, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags );
typedef struct AllocatorInfo AllocatorInfo;
struct AllocatorInfo
{
AllocatorProc* proc;
void* data;
};
// Overridable by the user by defining MD_OVERRIDE_DEFAULT_ALLOCATOR
AllocatorInfo default_allocator();
enum AllocFlag
{
ALLOCATOR_FLAG_CLEAR_TO_ZERO = (1 << 0),
};
#ifndef MD_DEFAULT_MEMORY_ALIGNMENT
# define MD_DEFAULT_MEMORY_ALIGNMENT ( 2 * size_of( void* ) )
#endif
#ifndef MD_DEFAULT_ALLOCATOR_FLAGS
# define MD_DEFAULT_ALLOCATOR_FLAGS ( ALLOCATOR_FLAG_CLEAR_TO_ZERO )
#endif
// Retrieve which type of allocator
AllocatorType allocator_type(AllocatorInfo a);
// Retreive which modes the allocator supports
AllocatorQueryFlags allocator_query_support(AllocatorInfo a);
// Allocate memory with default alignment.
void* alloc( AllocatorInfo a, SSIZE size );
// Allocate memory with specified alignment.
void* alloc_align( AllocatorInfo a, SSIZE size, SSIZE alignment );
// Free allocated memory.
void alloc_free( AllocatorInfo a, void* ptr );
// Free all memory allocated by an allocator.
void free_all( AllocatorInfo a );
// Resize an allocated memory.
void* resize( AllocatorInfo a, void* ptr, SSIZE old_size, SSIZE new_size );
// Resize an allocated memory with specified alignment.
void* resize_align( AllocatorInfo a, void* ptr, SSIZE old_size, SSIZE new_size, SSIZE alignment );
#ifndef alloc_item
// Allocate memory for an item.
#define alloc_item(allocator, Type) (Type*)memory_zero(alloc(allocator, size_of(Type)), size_of(Type))
// Allocate memory for an item.
#define alloc_item_no_zero( allocator, Type ) (Type*) alloc(allocator, size_of(Type))
#endif
#ifndef alloc_array
// Allocate memory for an array of items.
#define alloc_array( allocator_, Type, count ) (Type*)memory_zero(alloc( allocator_, size_of(Type) * (count) ), size_of(Type) * (count))
// Allocate memory for an array of items. (Don't zero initialize)
#define alloc_array_no_zero( allocator_, Type, count ) (Type*) alloc( allocator_, size_of(Type) * (count) )
#endif
// Allocate/Resize memory using default options.
// Use this if you don't need a "fancy" resize allocation
void* default_resize_align( AllocatorInfo a, void* ptr, SSIZE old_size, SSIZE new_size, SSIZE alignment );
#ifdef MD_HEAP_ANALYSIS
/* heap memory analysis tools */
/* define GEN_HEAP_ANALYSIS to enable this feature */
/* call zpl_heap_stats_init at the beginning of the entry point */
/* you can call zpl_heap_stats_check near the end of the execution to validate any possible leaks */
MD_API void heap_stats_init( void );
MD_API SSIZE heap_stats_used_memory( void );
MD_API SSIZE heap_stats_alloc_count( void );
MD_API void heap_stats_check( void );
#endif
MD_API void* heap_allocator_proc( void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags );
#ifndef heap
// The heap allocator backed by the platform vendor's malloc & free.
#define heap() (AllocatorInfo){ heap_allocator_proc, nullptr }
#endif
#ifndef md_malloc
// Helper to allocate memory using heap allocator.
#define md_malloc( sz ) alloc( heap(), sz )
#endif
#ifndef md_free
// Helper to free memory allocated by heap allocator.
#define md_free( ptr ) alloc_free( heap(), ptr )
#endif
/* Virtual Memory Arena
This is separate from the composite arena used by HMH/Casey Muratori/RJF
This arena stricly manages one reservation of the process's virtual address space.
Segregating this from composite Arena style causes more moremoy to be used for "allocator headers", however it allows
users of a library to have greater control over the allocation strategy used from their side instead of the library itself.
Like with the composite Arena, the VArena has its struct as the header of the reserve of memory.
*/
#ifndef VARENA_DEFUALT_RESERVE
#define VARENA_DEFAULT_RESERVE MB(64)
#endif
#ifndef VARENA_DEFUALT_COMMIT
#define VARENA_DEFAULT_COMMIT KB(64)
#endif
typedef U32 VArenaFlags;
enum
{
VArenaFlag_LargePages = (1 << 0),
};
typedef struct VArenaParams VArenaParams;
struct VArenaParams
{
U64 base_addr;
VArenaFlags flags;
U64 reserve_size;
U64 commit_size;
};
typedef struct VArena VArena;
struct VArena
{
SSIZE reserve_start;
SSIZE reserve;
SSIZE commit_size;
SSIZE committed;
SSIZE commit_used;
VArenaFlags flags;
};
MD_API VArena* varena__alloc(VArenaParams params PARAM_DEFAULT);
#define varena_alloc(...) varena__alloc( (VArenaParams){__VA_ARGS__} )
MD_API void varena_commit (VArena* vm, SSIZE commit_size);
MD_API void varena_release(VArena* vm);
force_inline void varena_rewind(VArena* vm, SSIZE pos) { vm->commit_used = pos; }
MD_API void* varena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags);
#define varena_allocator(vm) (AllocatorInfo) { varena_allocator_proc, vm }
typedef struct ByteSlice ByteSlice;
struct ByteSlice
{
U8* data;
SSIZE len;
};
#define mem_to_byteslice(data, len) (ByteSlice){ (U8*)(data), (SSIZE)(len) }
// Fixed size arena
typedef struct FArena FArena;
struct FArena
{
ByteSlice slice;
SSIZE used;
};
#define farena_from_byteslice(slice) (FArena) { slice, 0 }
#define farena_from_memory(data, len) (FArena) { mem_to_byteslice(data, len), 0 }
MD_API void* farena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags);
#define farena_allocator(arena) (AllocatorInfo){ farena_allocator_proc, & arena }
// Inlines
inline AllocatorType
allocator_type(AllocatorInfo a) {
if (a.proc == nullptr) {
a = default_allocator();
}
return (AllocatorType) a.proc(a.data, AllocatorMode_QueryType, 0, 0, nullptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS);
}
inline AllocatorQueryFlags
allocator_query_support(AllocatorInfo a) {
if (a.proc == nullptr) {
a = default_allocator();
}
return (AllocatorType) a.proc(a.data, AllocatorMode_QuerySupport, 0, 0, nullptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS);
}
inline void*
alloc_align( AllocatorInfo a, SSIZE size, SSIZE alignment ) {
if (a.proc == nullptr) {
a = default_allocator();
}
return a.proc( a.data, AllocatorMode_Alloc, size, alignment, nullptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS );
}
inline void*
alloc( AllocatorInfo a, SSIZE size ) {
if (a.proc == nullptr) {
a = default_allocator();
}
return alloc_align( a, size, MD_DEFAULT_MEMORY_ALIGNMENT );
}
inline void
alloc_free( AllocatorInfo a, void* ptr ) {
if (a.proc == nullptr) {
a = default_allocator();
}
if ( ptr != nullptr ) {
a.proc( a.data, AllocatorMode_Free, 0, 0, ptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS );
}
}
inline void
free_all( AllocatorInfo a ) {
if (a.proc == nullptr) {
a = default_allocator();
}
a.proc( a.data, AllocatorMode_FreeAll, 0, 0, nullptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS );
}
inline void*
resize( AllocatorInfo a, void* ptr, SSIZE old_size, SSIZE new_size ) {
if (a.proc == nullptr) {
a = default_allocator();
}
return resize_align( a, ptr, old_size, new_size, MD_DEFAULT_ALLOCATOR_FLAGS );
}
inline void*
resize_align( AllocatorInfo a, void* ptr, SSIZE old_size, SSIZE new_size, SSIZE alignment ) {
if (a.proc == nullptr) {
a = default_allocator();
}
return a.proc( a.data, AllocatorMode_Resize, new_size, alignment, ptr, old_size, MD_DEFAULT_ALLOCATOR_FLAGS );
}
+24
View File
@@ -0,0 +1,24 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "context_cracking.h"
#endif
// C++ namespace support
#if defined(MD_DONT_USE_NAMESPACE) || LANG_C
# if LANG_C
# define MD_NS
# define MD_NS_BEGIN
# define MD_NS_END
# else
# define MD_NS ::
# define MD_NS_BEGIN
# define MD_NS_END
# endif
#else
namespace MD {}
namespace md = MD;
# define MD_NS MD::
# define MD_NS_BEGIN namespace MD {
# define MD_NS_END }
#endif
+5
View File
@@ -0,0 +1,5 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "platform.h"
#endif
#include <stdio.h>
+18
View File
@@ -0,0 +1,18 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "context_cracking.h"
#endif
#include <stdarg.h>
#include <stddef.h>
#if defined( OS_WINDOWS )
# include <intrin.h>
# include <tmmintrin.h>
# include <wmmintrin.h>
#endif
#if LANG_C
# include <assert.h>
# include <stdbool.h>
#endif
+77
View File
@@ -0,0 +1,77 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "macros.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Zero Settings
#if !defined(PROFILE_TELEMETRY)
# define PROFILE_TELEMETRY 0
#endif
#if !defined(MARKUP_LAYER_COLOR)
# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f
#endif
////////////////////////////////
//~ rjf: Third Party Includes
#if PROFILE_TELEMETRY
# include "rad_tm.h"
# if OS_WINDOWS
# pragma comment(lib, "rad_tm_win64.lib")
# endif
#endif
////////////////////////////////
//~ rjf: Telemetry Profile Defines
#if PROFILE_TELEMETRY
# define prof_begin(...) tmEnter(0, 0, __VA_ARGS__)
# define prof_begin_dynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
# define prof_end(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0)
# define prof_tick(...) tmTick(0)
# define prof_is_capturing(...) tmRunning()
# define prof_begin_capture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100)
# define prof_end_capture(...) tmClose(0)
# define prof_thread_name(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0)
# define prof_msg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
# define prof_begin_lock_wait(...) tmStartWaitForLock(0, 0, __VA_ARGS__)
# define prof_end_lock_wait(...) tmEndWaitForLock(0)
# define prof_lock_take(...) tmAcquiredLock(0, 0, __VA_ARGS__)
# define prof_lock_drop(...) tmReleasedLock(0, __VA_ARGS__)
# define prof_color(color) tmZoneColorSticky(color)
#endif
// TODO(Ed): Support spall?
// TODO(Ed): Support tracey?
////////////////////////////////
//~ rjf: Zeroify Undefined Defines
#if !defined(prof_begin)
# define prof_begin(...) (0)
# define prof_begin_dynamic(...) (0)
# define prof_end(...) (0)
# define prof_tick(...) (0)
# define prof_is_capturing(...) (0)
# define prof_begin_capture(...) (0)
# define prof_end_capture(...) (0)
# define prof_thread_name(...) (0)
# define prof_msg(...) (0)
# define prof_end_lock_wait(...) (0)
# define prof_end_lock_wait(...) (0)
# define prof_lock_take(...) (0)
# define prof_lock_drop(...) (0)
# define prof_color(...) (0)
#endif
////////////////////////////////
//~ rjf: Helper Wrappers
#define prof_begin_function(...) prof_begin(this_function_name)
#define prof_scope(...) defer_loop(prof_begin_dynamic(__VA_ARGS__), ProfEnd())
+46
View File
@@ -0,0 +1,46 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "base_types.h"
#endif
////////////////////////////////
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
U64 ring_write(U8* ring_base, U64 ring_size, U64 ring_pos, void* src_data, U64 src_data_size);
U64 ring_read (U8* ring_base, U64 ring_size, U64 ring_pos, void* dst_data, U64 read_size);
#define ring_write_struct(ring_base, ring_size, ring_pos, ptr) ring_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
#define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read ((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
////////////////////////////////
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
inline U64
ring_write(U8* ring_base, U64 ring_size, U64 ring_pos, void* src_data, U64 src_data_size) {
assert(src_data_size <= ring_size);
{
U64 ring_off = ring_pos % ring_size;
U64 bytes_before_split = ring_size - ring_off;
U64 pre_split_bytes = min(bytes_before_split, src_data_size);
U64 pst_split_bytes = src_data_size - pre_split_bytes;
void* pre_split_data = src_data;
void* pst_split_data = ((U8*)src_data + pre_split_bytes);
memory_copy(ring_base + ring_off, pre_split_data, pre_split_bytes);
memory_copy(ring_base + 0, pst_split_data, pst_split_bytes);
}
return src_data_size;
}
inline U64
ring_read(U8* ring_base, U64 ring_size, U64 ring_pos, void* dst_data, U64 read_size) {
assert(read_size <= ring_size);
{
U64 ring_off = ring_pos % ring_size;
U64 bytes_before_split = ring_size-ring_off;
U64 pre_split_bytes = min(bytes_before_split, read_size);
U64 pst_split_bytes = read_size - pre_split_bytes;
memory_copy(dst_data, ring_base+ring_off, pre_split_bytes);
memory_copy((U8*)dst_data + pre_split_bytes, ring_base + 0, pst_split_bytes);
}
return read_size;
}
+10
View File
@@ -0,0 +1,10 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "platform.h"
#endif
////////////////////////////////
//~ rjf: Sorts
#ifndef quick_sort
#define quick_sort(ptr, count, element_size, cmp_function) qsort((ptr), (count), (element_size), (int (*)(const void *, const void *))(cmp_function))
#endif
+67
View File
@@ -0,0 +1,67 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "base_types.h"
#endif
////////////////////////////////
//~ rjf: Basic Types & Spaces
typedef enum Dimension Dimension;
enum Dimension
{
Dimension_X,
Dimension_Y,
Dimension_Z,
Dimension_W,
};
typedef enum Side Side;
enum Side
{
Side_Invalid = -1,
Side_Min,
Side_Max,
Side_COUNT,
};
#define side_flip(s) ((Side)(!(s)))
typedef enum Axis2 Axis2;
enum Axis2
{
Axis2_Invalid = -1,
Axis2_X,
Axis2_Y,
Axis2_COUNT,
};
#define axis2_flip(a) ((Axis2)(!(a)))
typedef enum Corner Corner;
enum Corner
{
Corner_Invalid = -1,
Corner_00,
Corner_01,
Corner_10,
Corner_11,
Corner_COUNT
};
typedef enum Dir2 Dir2;
enum Dir2
{
Dir2_Invalid = -1,
Dir2_Left,
Dir2_Up,
Dir2_Right,
Dir2_Down,
Dir2_COUNT
};
#define axis2_from_dir2(d) (((d) & 1) ? Axis2_Y : Axis2_X)
#define side_from_dir2(d) (((d) < Dir2_Right) ? Side_Min : Side_Max)
////////////////////////////////
//~ rjf: Enum -> Sign
inline S32 sign_from_side_S32(Side side) { return((side == Side_Min) ? -1 : 1 ); }
inline F32 sign_from_side_F32(Side side) { return((side == Side_Min) ? -1.f : 1.f); }
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+54
View File
@@ -0,0 +1,54 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "text.h"
#endif
////////////////////////////////
//~ rjf: Text Path Helpers
String8TxtPtPair
str8_txt_pt_pair_from_string(String8 string)
{
String8TxtPtPair pair = {0};
{
String8 file_part = {0};
String8 line_part = {0};
String8 col_part = {0};
// rjf: grab file part
for(U64 idx = 0; idx <= string.size; idx += 1)
{
U8 byte = (idx < string.size) ? (string.str[idx ]) : 0;
U8 next_byte = ((idx + 1 < string.size) ? (string.str[idx + 1]) : 0);
if(byte == ':' && next_byte != '/' && next_byte != '\\') {
file_part = str8_prefix(string, idx);
line_part = str8_skip(string, idx+1);
break;
}
else if(byte == 0) {
file_part = string;
break;
}
}
// rjf: grab line/column
{
U64 colon_pos = str8_find_needle(line_part, 0, str8_lit(":"), 0);
if(colon_pos < line_part.size) {
col_part = str8_skip (line_part, colon_pos + 1);
line_part = str8_prefix(line_part, colon_pos);
}
}
// rjf: convert line/column strings to numerics
U64 line = 0;
U64 column = 0;
try_u64_from_str8_c_rules(line_part, &line);
try_u64_from_str8_c_rules(col_part, &column);
// rjf: fill
pair.string = file_part;
pair.pt = txt_pt((S64)line, (S64)column);
if(pair.pt.line == 0) { pair.pt.line = 1; }
if(pair.pt.column == 0) { pair.pt.column = 1; }
}
return pair;
}
+106
View File
@@ -0,0 +1,106 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "strings.h"
#endif
////////////////////////////////
//~ rjf: Text 2D Coordinates & Ranges
typedef struct TxtPt TxtPt;
struct TxtPt
{
S64 line;
S64 column;
};
typedef struct TxtRng TxtRng;
struct TxtRng
{
TxtPt min;
TxtPt max;
};
////////////////////////////////
//~ rjf: String Pair Types
typedef struct String8TxtPtPair String8TxtPtPair;
struct String8TxtPtPair
{
String8 string;
TxtPt pt;
};
////////////////////////////////
//~ rjf: Text Path Helpers
MD_API String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
////////////////////////////////
//~ rjf: Text 2D Coordinate/Range Functions
inline TxtPt txt_pt(S64 line, S64 column) { TxtPt p = { line, column }; return p; }
inline B32 txt_pt_match(TxtPt a, TxtPt b) { return a.line == b.line && a.column == b.column; }
inline TxtPt txt_pt_min (TxtPt a, TxtPt b) { TxtPt result = b; if (txt_pt_less_than(a, b)) { result = a; } return result; }
inline TxtPt txt_pt_max (TxtPt a, TxtPt b) { TxtPt result = a; if (txt_pt_less_than(a, b)) { result = b; } return result; }
B32 txt_pt_less_than (TxtPt a, TxtPt b);
TxtRng txt_rng (TxtPt min, TxtPt max);
TxtRng txt_rng_intersect(TxtRng a, TxtRng b);
TxtRng txt_rng_union (TxtRng a, TxtRng b);
B32 txt_rng_contains (TxtRng r, TxtPt pt);
inline B32
txt_pt_less_than(TxtPt a, TxtPt b)
{
B32 result = 0;
if (a.line < b.line) {
result = 1;
}
else if (a.line == b.line) {
result = a.column < b.column;
}
return result;
}
inline TxtRng
txt_rng(TxtPt min, TxtPt max)
{
TxtRng range = {0};
if(txt_pt_less_than(min, max)) {
range.min = min;
range.max = max;
}
else {
range.min = max;
range.max = min;
}
return range;
}
inline TxtRng
txt_rng_intersect(TxtRng a, TxtRng b)
{
TxtRng result = {0};
result.min = txt_pt_max(a.min, b.min);
result.max = txt_pt_min(a.max, b.max);
if (txt_pt_less_than(result.max, result.min)) {
MemoryZeroStruct(&result);
}
return result;
}
inline TxtRng
txt_rng_union(TxtRng a, TxtRng b)
{
TxtRng result = {0};
result.min = txt_pt_min(a.min, b.min);
result.max = txt_pt_max(a.max, b.max);
return result;
}
inline B32
txt_rng_contains(TxtRng r, TxtPt pt) {
B32 result = ((txt_pt_less_than(r.min, pt) || txt_pt_match(r.min, pt)) && txt_pt_less_than(pt, r.max));
return result;
}
+87
View File
@@ -0,0 +1,87 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "arena.h"
# include "thread_context.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
// NOTE(allen): Thread Context Functions
MD_API_C thread_static TCTX* tctx_thread_local;
#if ! MD_BUILD_SUPPLEMENTARY_UNIT
MD_API_C thread_static TCTX* tctx_thread_local = 0;
#endif
void
tctx_init_and_equip(TCTX* tctx)
{
// memory_zero_struct(tctx);
Arena** arena_ptr = tctx->arenas;
for (U64 i = 0; i < array_count(tctx->arenas); i += 1, arena_ptr += 1)
{
if (*arena_ptr == nullptr)
{
VArena* vm = varena_alloc(.reserve_size = VARENA_DEFAULT_RESERVE, .commit_size = VARENA_DEFAULT_COMMIT);
*arena_ptr = arena_alloc(.backing = varena_allocator(vm));
}
}
tctx_thread_local = tctx;
}
void
tctx_init_and_equip_alloc(TCTX* tctx, AllocatorInfo ainfo)
{
memory_zero_struct(tctx);
Arena** arena_ptr = tctx->arenas;
for (U64 i = 0; i < array_count(tctx->arenas); i += 1, arena_ptr += 1)
{
if (*arena_ptr == nullptr)
{
*arena_ptr = arena_alloc(.backing = ainfo);
}
}
tctx_thread_local = tctx;
}
void
tctx_release(void) {
for (U64 i = 0; i < array_count(tctx_thread_local->arenas); i += 1) {
arena_release(tctx_thread_local->arenas[i]);
}
}
TCTX*
tctx_get_equipped(void){
return(tctx_thread_local);
}
Arena*
tctx_get_scratch(Arena** conflicts, U64 count)
{
TCTX* tctx = tctx_get_equipped();
Arena* result = 0;
Arena** arena_ptr = tctx->arenas;
for (U64 i = 0; i < array_count(tctx->arenas); i += 1, arena_ptr += 1)
{
Arena** conflict_ptr = conflicts;
B32 has_conflict = 0;
for (U64 j = 0; j < count; j += 1, conflict_ptr += 1)
{
if (*arena_ptr == *conflict_ptr) {
has_conflict = 1;
break;
}
}
if ( ! has_conflict){
result = *arena_ptr;
break;
}
}
return(result);
}
+90
View File
@@ -0,0 +1,90 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "arena.h"
# include "string.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
// NOTE(allen): Thread Context
typedef struct TCTX TCTX;
struct TCTX
{
Arena* arenas[2];
U8 thread_name[32];
U64 thread_name_size;
char* file_name;
U64 line_number;
};
////////////////////////////////
// NOTE(allen): Thread Context Functions
MD_API void tctx_init_and_equip (TCTX* tctx);
MD_API void tctx_init_and_equip_alloc(TCTX* tctx, AllocatorInfo ainfo);
MD_API void tctx_release (void);
MD_API TCTX* tctx_get_equipped (void);
MD_API Arena* tctx_get_scratch(Arena** conflicts, U64 count);
void tctx_set_thread_name(String8 name);
String8 tctx_get_thread_name(void);
void tctx_write_srcloc(char* file_name, U64 line_number);
void tctx_read_srcloc (char** file_name, U64* line_number);
#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__)
typedef struct { U64 count; } Opt_ScratchBegin;
inline TempArena
scratch_begin__ainfo(AllocatorInfo ainfo, Opt_ScratchBegin opt) {
Arena* arena = extract_arena(ainfo);
TempArena scratch = temp_begin(tctx_get_scratch(&arena, arena != nullptr));
return scratch;
}
force_inline TempArena scratch_begin__arena(Arena** arena, Opt_ScratchBegin opt) { TempArena scratch = temp_begin(tctx_get_scratch(arena, opt.count)); return scratch; }
#define scratch_begin(conflicts, ...) \
_Generic(conflicts, \
int : scratch_begin__arena, \
Arena** : scratch_begin__arena, \
AllocatorInfo: scratch_begin__ainfo, \
default : assert_generic_sel_fail \
) generic_call(conflicts, (Opt_ScratchBegin){__VA_ARGS__})
#define scratch_end(scratch) temp_end(scratch)
inline void
tctx_set_thread_name(String8 string){
TCTX* tctx = tctx_get_equipped();
U64 size = clamp_top(string.size, sizeof(tctx->thread_name));
memory_copy(tctx->thread_name, string.str, size);
tctx->thread_name_size = size;
}
inline String8
tctx_get_thread_name(void) {
TCTX* tctx = tctx_get_equipped();
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
return(result);
}
inline void
tctx_write_srcloc(char* file_name, U64 line_number){
TCTX *tctx = tctx_get_equipped();
tctx->file_name = file_name;
tctx->line_number = line_number;
}
inline void
tctx_read_srcloc(char** file_name, U64* line_number){
TCTX* tctx = tctx_get_equipped();
*file_name = tctx->file_name;
*line_number = tctx->line_number;
}
+58
View File
@@ -0,0 +1,58 @@
#ifdef INTELLISENSE_DIRECTIVES
# include "debug.h"
# include "time.h"
#endif
DateTime
date_time_from_unix_time(U64 unix_time)
{
DateTime date = {0};
date.year = 1970;
date.day = 1 + (unix_time / 86400);
date.sec = (U32) unix_time % 60;
date.min = (U32)(unix_time / 60) % 60;
date.hour = (U32)(unix_time / 3600) % 24;
for(;;)
{
for(date.month = 0; date.month < 12; ++date.month)
{
U64 c = 0;
switch(date.month)
{
case Month_Jan: c = 31; break;
case Month_Feb:
{
if((date.year % 4 == 0) && ((date.year % 100) != 0 || (date.year % 400) == 0))
{
c = 29;
}
else
{
c = 28;
}
} break;
case Month_Mar: c = 31; break;
case Month_Apr: c = 30; break;
case Month_May: c = 31; break;
case Month_Jun: c = 30; break;
case Month_Jul: c = 31; break;
case Month_Aug: c = 31; break;
case Month_Sep: c = 30; break;
case Month_Oct: c = 31; break;
case Month_Nov: c = 30; break;
case Month_Dec: c = 31; break;
default: invalid_path;
}
if(date.day <= c)
{
goto exit;
}
date.day -= c;
}
++date.year;
}
exit:;
return date;
}
+115
View File
@@ -0,0 +1,115 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "base_types.h"
#endif
////////////////////////////////
//~ allen: Time
typedef enum WeekDay WeekDay;
enum WeekDay
{
WeekDay_Sun,
WeekDay_Mon,
WeekDay_Tue,
WeekDay_Wed,
WeekDay_Thu,
WeekDay_Fri,
WeekDay_Sat,
WeekDay_COUNT,
};
typedef enum Month Month;
enum Month
{
Month_Jan,
Month_Feb,
Month_Mar,
Month_Apr,
Month_May,
Month_Jun,
Month_Jul,
Month_Aug,
Month_Sep,
Month_Oct,
Month_Nov,
Month_Dec,
Month_COUNT,
};
typedef struct DateTime DateTime;
struct DateTime
{
U16 micro_sec; // [0,999]
U16 msec; // [0,999]
U16 sec; // [0,60]
U16 min; // [0,59]
U16 hour; // [0,24]
U16 day; // [0,30]
union
{
WeekDay week_day;
U32 wday;
};
union
{
Month month;
U32 mon;
};
U32 year; // 1 = 1 CE, 0 = 1 BC
};
typedef U64 DenseTime;
////////////////////////////////
//~ rjf: Time Functions
DenseTime dense_time_from_date_time (DateTime date_time);
DateTime date_time_from_dense_time (DenseTime time);
DateTime date_time_from_micro_seconds(U64 time);
DateTime date_time_from_unix_time (U64 unix_time);
////////////////////////////////
//~ rjf: Time Functions
inline DenseTime
dense_time_from_date_time(DateTime date_time) {
DenseTime result = 0;
result += date_time.year; result *= 12;
result += date_time.mon; result *= 31;
result += date_time.day; result *= 24;
result += date_time.hour; result *= 60;
result += date_time.min; result *= 61;
result += date_time.sec; result *= 1000;
result += date_time.msec;
return(result);
}
inline DateTime
date_time_from_dense_time(DenseTime time) {
DateTime result = {0};
result.msec = time % 1000; time /= 1000;
result.sec = time % 61; time /= 61;
result.min = time % 60; time /= 60;
result.hour = time % 24; time /= 24;
result.day = time % 31; time /= 31;
result.mon = time % 12; time /= 12;
assert(time <= MAX_U32);
result.year = (U32)time;
return(result);
}
inline DateTime
date_time_from_micro_seconds(U64 time){
DateTime result = {0};
result.micro_sec = time % 1000; time /= 1000;
result.msec = time % 1000; time /= 1000;
result.sec = time % 60; time /= 60;
result.min = time % 60; time /= 60;
result.hour = time % 24; time /= 24;
result.day = time % 31; time /= 31;
result.mon = time % 12; time /= 12;
assert(time <= MAX_U32);
result.year = (U32)time;
return(result);
}
+115
View File
@@ -0,0 +1,115 @@
#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "base_types.h"
#endif
////////////////////////////////
//~ rjf: Toolchain/Environment Enums
typedef enum OperatingSystem OperatingSystem;
enum OperatingSystem
{
OperatingSystem_Null,
OperatingSystem_Windows,
OperatingSystem_Linux,
OperatingSystem_Mac,
OperatingSystem_COUNT,
};
typedef enum ImageType ImageType;
enum ImageType
{
Image_Null,
Image_CoffPe,
Image_Elf32,
Image_Elf64,
Image_Macho
};
typedef enum Arch Arch;
enum Arch
{
Arch_Null,
Arch_x64,
Arch_x86,
Arch_arm64,
Arch_arm32,
Arch_COUNT,
};
typedef enum Compiler Compiler;
enum Compiler
{
Compiler_Null,
Compiler_msvc,
Compiler_gcc,
Compiler_clang,
Compiler_COUNT,
};
////////////////////////////////
//~ rjf: Toolchain/Environment Enum Functions
inline U64
bit_size_from_arch(Arch arch)
{
// TODO(rjf): metacode
U64 arch_bitsize = 0;
switch(arch)
{
case Arch_x64: arch_bitsize = 64; break;
case Arch_x86: arch_bitsize = 32; break;
case Arch_arm64: arch_bitsize = 64; break;
case Arch_arm32: arch_bitsize = 32; break;
default: break;
}
return arch_bitsize;
}
inline U64
max_instruction_size_from_arch(Arch arch)
{
// TODO(rjf): make this real
return 64;
}
inline OperatingSystem
operating_system_from_context(void) {
OperatingSystem os = OperatingSystem_Null;
#if OS_WINDOWS
os = OperatingSystem_Windows;
#elif OS_LINUX
os = OperatingSystem_Linux;
#elif OS_MAC
os = OperatingSystem_Mac;
#endif
return os;
}
inline Arch
arch_from_context(void) {
Arch arch = Arch_Null;
#if ARCH_X64
arch = Arch_x64;
#elif ARCH_X86
arch = Arch_x86;
#elif ARCH_ARM64
arch = Arch_arm64;
#elif ARCH_ARM32
arch = Arch_arm32;
#endif
return arch;
}
inline Compiler
compiler_from_context(void) {
Compiler compiler = Compiler_Null;
#if COMPILER_MSVC
compiler = Compiler_msvc;
#elif COMPILER_GCC
compiler = Compiler_gcc;
#elif COMPILER_CLANG
compiler = Compiler_clang;
#endif
return compiler;
}