mirror of
https://github.com/Ed94/metadesk.git
synced 2026-07-29 02:40:02 +00:00
adjusting repo for removing extra features not part of the original library
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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; }
|
||||
@@ -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
|
||||
@@ -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" );
|
||||
}
|
||||
@@ -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, ... );
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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) \
|
||||
)
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
# include "platform.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -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
|
||||
@@ -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())
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user