0
Fork 0

lesson-1 initial commit

main
Allen Webster 2025-10-17 15:49:52 -07:00
commit fd187edbaf
10 changed files with 3499 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/*

49
aritynode.blank.c Normal file
View File

@ -0,0 +1,49 @@
////////////////////////////////
// Functions: Arity Node
// construction
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_empty(Arena *arena){
return(0);
}
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_singleton(Arena *arena){
return(0);
}
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_arrow(Arena *arena, DS_ArityNode *domain, DS_ArityNode *codomain){
return(0);
}
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_paste(Arena *arena, DS_ArityNode *a, DS_ArityNode *b){
return(0);
}
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_sum(Arena *arena, ...){
va_list args;
va_start(args, arena);
va_end(args);
return(0);
}
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_ktuple(Arena *arena, U32 coefficient){
return(0);
}
// operations
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_copy(Arena *arena, DS_ArityNode *arity){
return(0);
}
MR4TH_SYMBOL B32
ds_aritynode_equal(DS_ArityNode *a, DS_ArityNode *b){
return(0);
}

359
aritynode.c Normal file
View File

@ -0,0 +1,359 @@
////////////////////////////////
// Functions: Arity Node
// construction
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_empty(Arena *arena){
DS_ArityNode *node = push_array(arena, DS_ArityNode, 1);
node->kind = DS_ArityKind_Empty;
return(node);
}
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_singleton(Arena *arena){
DS_ArityNode *node = push_array(arena, DS_ArityNode, 1);
node->kind = DS_ArityKind_Singleton;
node->coefficient = 1;
return(node);
}
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_arrow(Arena *arena, DS_ArityNode *domain, DS_ArityNode *codomain){
DS_ArityNode *node = 0;
if (domain->kind == DS_ArityKind_Empty ||
codomain->kind == DS_ArityKind_Empty){
node = codomain;
}
else{
node = push_array(arena, DS_ArityNode, 1);
node->kind = DS_ArityKind_Arrow;
node->coefficient = 1;
node->arrow.domain = domain;
node->arrow.codomain = codomain;
}
return(node);
}
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_paste(Arena *arena, DS_ArityNode *a, DS_ArityNode *b){
ArenaTemp scratch = arena_get_scratch(&arena, 1);
DS_ArityNode *node = 0;
if (a->kind == DS_ArityKind_Empty){
node = b;
}
else if (b->kind == DS_ArityKind_Empty){
node = a;
}
else{
// count parts
U64 max_part_count = 0;
if (a->kind != DS_ArityKind_Tuple){
max_part_count += 1;
}
else{
max_part_count += a->tuple.part_count;
}
if (b->kind != DS_ArityKind_Tuple){
max_part_count += 1;
}
else{
max_part_count += b->tuple.part_count;
}
// fill parts
DS_ArityNode **parts = push_array(scratch.arena, DS_ArityNode*, max_part_count);
DS_ArityNode **part_ptr = parts;
if (a->kind != DS_ArityKind_Tuple){
*part_ptr = ds_aritynode__part_copy(arena, a);
(*part_ptr)->coefficient = 1;
part_ptr += 1;
}
else{
for (U64 i = 0; i < a->tuple.part_count; i += 1){
DS_ArityNode *a_part = a->tuple.parts[i];
*part_ptr = ds_aritynode__part_copy(arena, a_part);
(*part_ptr)->coefficient = a_part->coefficient;
part_ptr += 1;
}
}
if (b->kind != DS_ArityKind_Tuple){
DS_ArityNode *match_pos = ds_aritynode__part_find_match(parts, part_ptr, b);
if (match_pos != 0){
match_pos->coefficient += 1;
}
else{
*part_ptr = ds_aritynode__part_copy(arena, b);
(*part_ptr)->coefficient = 1;
part_ptr += 1;
}
}
else{
for (U64 j = 0; j < b->tuple.part_count; j += 1){
DS_ArityNode *b_part = b->tuple.parts[j];
DS_ArityNode *match_pos = ds_aritynode__part_find_match(parts, part_ptr, b_part);
if (match_pos != 0){
match_pos->coefficient += b_part->coefficient;
}
else{
*part_ptr = ds_aritynode__part_copy(arena, b_part);
(*part_ptr)->coefficient = b_part->coefficient;
part_ptr += 1;
}
}
}
// final part count
U64 part_count = (U64)(part_ptr - parts);
// fill result node
Assert(part_count > 1 ||
part_count == 1 && parts[0]->coefficient > 1);
DS_ArityNode **parts_final = push_array(arena, DS_ArityNode*, part_count);
MemoryCopy(parts_final, parts, sizeof(*parts)*part_count);
node = push_array(arena, DS_ArityNode, 1);
node->kind = DS_ArityKind_Tuple;
node->coefficient = 1;
node->tuple.parts = parts_final;
node->tuple.part_count = part_count;
}
arena_release_scratch(&scratch);
return(node);
}
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_sum(Arena *arena, ...){
va_list args;
va_start(args, arena);
va_list args2;
va_copy(args2, args);
ArenaTemp scratch = arena_get_scratch(&arena, 1);
// count parts
U64 max_part_count = 0;
for (;;){
U32 multiplier = va_arg(args, U32);
if (multiplier == 0){
break;
}
DS_ArityNode *arity = va_arg(args, DS_ArityNode*);
if (arity->kind == DS_ArityKind_Empty){
// do nothing
}
else if (arity->kind != DS_ArityKind_Tuple){
max_part_count += 1;
}
else{
max_part_count += arity->tuple.part_count;
}
}
// fill parts
DS_ArityNode **parts = push_array(scratch.arena, DS_ArityNode*, max_part_count);
DS_ArityNode **part_ptr = parts;
for (;;){
U32 multiplier = va_arg(args2, U32);
if (multiplier == 0){
break;
}
DS_ArityNode *arity = va_arg(args2, DS_ArityNode*);
if (arity->kind == DS_ArityKind_Empty){
// do nothing
}
else if (arity->kind != DS_ArityKind_Tuple){
DS_ArityNode *match_pos = ds_aritynode__part_find_match(parts, part_ptr, arity);
if (match_pos != 0){
match_pos->coefficient += multiplier;
}
else{
*part_ptr = ds_aritynode__part_copy(arena, arity);
(*part_ptr)->coefficient = multiplier;
part_ptr += 1;
}
}
else{
for (U64 j = 0; j < arity->tuple.part_count; j += 1){
DS_ArityNode *b_part = arity->tuple.parts[j];
DS_ArityNode *match_pos = ds_aritynode__part_find_match(parts, part_ptr, b_part);
if (match_pos != 0){
match_pos->coefficient += multiplier*b_part->coefficient;
}
else{
*part_ptr = ds_aritynode__part_copy(arena, b_part);
(*part_ptr)->coefficient = multiplier*b_part->coefficient;
part_ptr += 1;
}
}
}
}
// final part count
U64 part_count = (U64)(part_ptr - parts);
// fill result node
DS_ArityNode *node = 0;
if (part_count == 0){
node = ds_aritynode_empty(arena);
}
else if (part_count == 1 &&
parts[0]->coefficient == 1){
node = parts[0];
}
else{
DS_ArityNode **parts_final = push_array(arena, DS_ArityNode*, part_count);
MemoryCopy(parts_final, parts, sizeof(*parts)*part_count);
node = push_array(arena, DS_ArityNode, 1);
node->kind = DS_ArityKind_Tuple;
node->coefficient = 1;
node->tuple.parts = parts_final;
node->tuple.part_count = part_count;
}
arena_release_scratch(&scratch);
va_end(args2);
va_end(args);
return(node);
}
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_ktuple(Arena *arena, U32 coefficient){
DS_ArityNode *result = 0;
if (coefficient > 1){
result = push_array(arena, DS_ArityNode, 1);
DS_ArityNode **parts = push_array(arena, DS_ArityNode*, 1);
DS_ArityNode *singleton = push_array(arena, DS_ArityNode, 1);
result->kind = DS_ArityKind_Tuple;
result->coefficient = 1;
result->tuple.parts = parts;
result->tuple.part_count = 1;
parts[0] = singleton;
singleton->kind = DS_ArityKind_Singleton;
singleton->coefficient = coefficient;
}
else if (coefficient == 1){
result = ds_aritynode_singleton(arena);
}
else{
result = ds_aritynode_empty(arena);
}
return(result);
}
// operations
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode_copy(Arena *arena, DS_ArityNode *arity){
DS_ArityNode *result = push_array(arena, DS_ArityNode, 1);
result->kind = arity->kind;
result->coefficient = arity->coefficient;
switch (result->kind){
case DS_ArityKind_Arrow:
{
result->arrow.domain = ds_aritynode_copy(arena, arity->arrow.domain);
result->arrow.codomain = ds_aritynode_copy(arena, arity->arrow.codomain);
}break;
case DS_ArityKind_Tuple:
{
U64 part_count = arity->tuple.part_count;
DS_ArityNode **parts = push_array(arena, DS_ArityNode*, part_count);
for (U64 i = 0; i < part_count; i += 1){
parts[i] = ds_aritynode_copy(arena, arity->tuple.parts[i]);
}
result->tuple.parts = parts;
result->tuple.part_count = part_count;
}break;
}
return(result);
}
MR4TH_SYMBOL B32
ds_aritynode_equal(DS_ArityNode *a, DS_ArityNode *b){
B32 result = 0;
if (a->kind == b->kind){
switch (a->kind){
case DS_ArityKind_Empty:
case DS_ArityKind_Singleton: result = 1; break;
case DS_ArityKind_Arrow:
{
if (ds_aritynode_equal(a->arrow.domain, b->arrow.domain) &&
ds_aritynode_equal(a->arrow.codomain, b->arrow.codomain)){
result = 1;
}
}break;
case DS_ArityKind_Tuple:
{
if (a->tuple.part_count == b->tuple.part_count){
result = 1;
for (U64 i = 0; i < a->tuple.part_count; i += 1){
DS_ArityNode *a_part = a->tuple.parts[i];
B32 found_match = 0;
for (U64 j = 0; j < b->tuple.part_count; j += 1){
DS_ArityNode *b_part = b->tuple.parts[j];
if (b_part->coefficient == a_part->coefficient &&
ds_aritynode_equal(a_part, b_part)){
found_match = 1;
break;
}
}
if (!found_match){
result = 0;
break;
}
}
}
}break;
}
}
return(result);
}
// helpers
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode__part_copy(Arena *arena, DS_ArityNode *node){
Assert(node->kind != DS_ArityKind_Tuple);
DS_ArityNode *result = push_array(arena, DS_ArityNode, 1);
result->kind = node->kind;
if (result->kind == DS_ArityKind_Arrow){
result->arrow.domain = node->arrow.domain;
result->arrow.codomain = node->arrow.codomain;
}
return(result);
}
MR4TH_SYMBOL DS_ArityNode*
ds_aritynode__part_find_match(DS_ArityNode **parts_first, DS_ArityNode **parts_opl, DS_ArityNode *key){
DS_ArityNode **part = parts_first;
DS_ArityNode *match = 0;
for (; part < parts_opl; part += 1){
if (ds_aritynode_equal(*part, key)){
match = *part;
break;
}
}
return(match);
}

92
aritynode.h Normal file
View File

@ -0,0 +1,92 @@
#ifndef ARITYNODE_H
#define ARITYNODE_H
////////////////////////////////
// Type: Arity Node
typedef enum DS_ArityKind{
DS_ArityKind_Empty = 0,
DS_ArityKind_Singleton = 1,
DS_ArityKind_Arrow = 2,
DS_ArityKind_Tuple = 3,
} DS_ArityKind;
typedef struct DS_ArityNode{
DS_ArityKind kind;
U32 coefficient;
union{
struct{
struct DS_ArityNode *domain;
struct DS_ArityNode *codomain;
} arrow;
struct{
struct DS_ArityNode **parts;
U64 part_count;
} tuple;
};
} DS_ArityNode;
////////////////////////////////
// Functions: Arity Node
// construction
/* NOTE:
** Construction functions that take in arity node(s) require
** that the arena that allocated the input arity node(s)
** is the same arena that is used in the current call, and
** that the arena has not popped the nodes.
**
** Example of misuse:
**
** GIVEN Arena *a1; Arena *a2;
** WITH (a1 != a2):
** DS_ArityNode *n1 = ds_aritynode_singleton(a1);
** DS_ArityNode *n2 = ds_aritynode_arrow(a2, n1); @bad - changing arenas
**
** Why this matters:
**
** We don't want to have to deep copy every node we ever see as input,
** so construction functions just keep pointers to their inputs, or
** sometimes make shallow copies but still keep the original versions
** of the deeper nodes. Because of the way arenas work, if these
** all exist on one arena, later nodes always point towards earlier
** nodes, and so if a node is still on the arena, so are all of the nodes
** that it depends on. However, if we start crossing arenas, we would
** have to be much more careful not to start generating use-after-free
** issues.
**
** If you think it through and you *know what you're doing* you can
** break this rule, but as a rule of thumb, it usually works best if you
** can put all the nodes that work together into the same arena.
*/
MR4TH_SYMBOL DS_ArityNode* ds_aritynode_empty(Arena *arena);
MR4TH_SYMBOL DS_ArityNode* ds_aritynode_singleton(Arena *arena);
MR4TH_SYMBOL DS_ArityNode* ds_aritynode_arrow(Arena *arena, DS_ArityNode *domain, DS_ArityNode *codomain);
MR4TH_SYMBOL DS_ArityNode* ds_aritynode_paste(Arena *arena, DS_ArityNode *a, DS_ArityNode *b);
/* NOTE:
** ds_aritynode_sum takes the variadic layout:
** (coeff_1:U32, arity_1:DS_ArityNode*, ..., coeff_k:U32, arity_k:DS_ArityNode*, 0)
*/
MR4TH_SYMBOL DS_ArityNode* ds_aritynode_sum(Arena *arena, ...);
MR4TH_SYMBOL DS_ArityNode* ds_aritynode_ktuple(Arena *arena, U32 coefficient);
// operations
/* NOTE:
** ds_aritynode_copy is not a "construction function"
** it can deep copy an arity node from one arena to another.
*/
MR4TH_SYMBOL DS_ArityNode* ds_aritynode_copy(Arena *arena, DS_ArityNode *arity);
MR4TH_SYMBOL B32 ds_aritynode_equal(DS_ArityNode *a, DS_ArityNode *b);
// helpers
MR4TH_SYMBOL DS_ArityNode* ds_aritynode__part_copy(Arena *arena, DS_ArityNode *node);
MR4TH_SYMBOL DS_ArityNode* ds_aritynode__part_find_match(DS_ArityNode **parts_first, DS_ArityNode **parts_opl, DS_ArityNode *key);
#endif //ARITYNODE_H

57
aritynode.test.c Normal file
View File

@ -0,0 +1,57 @@
////////////////////////////////
// Arity Node Sanity Test Function
MR4TH_SYMBOL void
ds_aritynode__test(void){
ArenaTemp scratch = arena_get_scratch(0, 0);
DS_ArityNode *a_empty = ds_aritynode_empty(scratch.arena);
DS_ArityNode *a_s1 = ds_aritynode_singleton(scratch.arena);
DS_ArityNode *a_s2 = ds_aritynode_paste(scratch.arena, a_s1, a_s1);
DS_ArityNode *a_s3 = ds_aritynode_paste(scratch.arena, a_s2, a_s1);
DS_ArityNode *a_ar1 = ds_aritynode_arrow(scratch.arena, a_s1, a_s1);
Assert(ds_aritynode_equal(a_empty, a_empty));
Assert(ds_aritynode_equal(a_s1, a_s1));
Assert(ds_aritynode_equal(a_s2, a_s2));
Assert(ds_aritynode_equal(a_s3, a_s3));
Assert(ds_aritynode_equal(a_ar1, a_ar1));
Assert(!ds_aritynode_equal(a_empty, a_s1));
Assert(!ds_aritynode_equal(a_s1, a_s2));
Assert(!ds_aritynode_equal(a_ar1, a_s1));
DS_ArityNode *a_s2x = ds_aritynode_sum(scratch.arena, 2, a_s1, 0);
DS_ArityNode *a_s3x = ds_aritynode_sum(scratch.arena, 3, a_s1, 0);
Assert(ds_aritynode_equal(a_s2, a_s2x));
Assert(ds_aritynode_equal(a_s3, a_s3x));
DS_ArityNode *a_s1_ar1 = ds_aritynode_paste(scratch.arena, a_s1, a_ar1);
DS_ArityNode *a_s2_ar1 = ds_aritynode_paste(scratch.arena, a_s1_ar1, a_s1);
DS_ArityNode *a_s2_ar1_x = ds_aritynode_paste(scratch.arena, a_s2, a_ar1);
Assert(ds_aritynode_equal(a_s2_ar1, a_s2_ar1_x));
DS_ArityNode *a_ar1_2 = ds_aritynode_arrow(scratch.arena, a_s1, a_s2);
DS_ArityNode *a_ar1_3 = ds_aritynode_arrow(scratch.arena, a_s1, a_s3);
DS_ArityNode *a_ar_ar1 = ds_aritynode_arrow(scratch.arena, a_ar1, a_ar1);
DS_ArityNode *a_ar_ar2 = ds_aritynode_arrow(scratch.arena, a_ar1, a_ar1_2);
DS_ArityNode *a_ar_ar3 = ds_aritynode_arrow(scratch.arena, a_ar1, a_ar1_3);
Assert(!ds_aritynode_equal(a_ar1, a_ar_ar1));
Assert(!ds_aritynode_equal(a_ar_ar1, a_ar_ar2));
Assert(!ds_aritynode_equal(a_ar_ar1, a_ar_ar3));
Assert(!ds_aritynode_equal(a_ar_ar2, a_ar_ar3));
DS_ArityNode *a_ar1x = ds_aritynode_sum(scratch.arena, 1, a_ar1, 3, a_empty, 1, a_empty, 0);
Assert(ds_aritynode_equal(a_ar1, a_ar1x));
DS_ArityNode *a_s17 = ds_aritynode_sum(scratch.arena, 17, a_s1, 0);
DS_ArityNode *a_s17x = ds_aritynode_ktuple(scratch.arena, 17);
Assert(ds_aritynode_equal(a_s17, a_s17x));
arena_release_scratch(&scratch);
}

2260
base.c Normal file

File diff suppressed because it is too large Load Diff

634
base.h Normal file
View File

@ -0,0 +1,634 @@
#ifndef BASE_H
#define BASE_H
#if !defined(MR4TH_SYMBOL)
# define MR4TH_SYMBOL static
#endif
// untangle compiler, os, & architecture
#if defined(__clang__)
# define COMPILER_CLANG 1
# if defined(_WIN32)
# define OS_WINDOWS 1
# elif defined(__gnu_linux__)
# define OS_LINUX 1
# elif defined(__APPLE__) && defined(__MACH__)
# define OS_MAC 1
# else
# error missing OS detection
# endif
# if defined(__amd64__)
# define ARCH_X64 1
// TODO(allen): verify this works on clang
# elif defined(__i386__)
# define ARCH_X86 1
// TODO(allen): verify this works on clang
# elif defined(__arm__)
# define ARCH_ARM 1
// TODO(allen): verify this works on clang
# elif defined(__aarch64__)
# define ARCH_ARM64 1
# else
# error missing ARCH detection
# endif
#elif defined(_MSC_VER)
# define COMPILER_CL 1
# if defined(_WIN32)
# define OS_WINDOWS 1
# else
# error missing OS detection
# endif
# if defined(_M_AMD64)
# define ARCH_X64 1
# elif defined(_M_I86)
# define ARCH_X86 1
# elif defined(_M_ARM)
# define ARCH_ARM 1
// TODO(allen): ARM64?
# else
# error missing ARCH detection
# endif
#elif defined(__GNUC__)
# define COMPILER_GCC 1
# if defined(_WIN32)
# define OS_WINDOWS 1
# elif defined(__gnu_linux__)
# define OS_LINUX 1
# elif defined(__APPLE__) && defined(__MACH__)
# define OS_MAC 1
# else
# error missing OS detection
# endif
# if defined(__amd64__)
# define ARCH_X64 1
# elif defined(__i386__)
# define ARCH_X86 1
# elif defined(__arm__)
# define ARCH_ARM 1
# elif defined(__aarch64__)
# define ARCH_ARM64 1
# else
# error missing ARCH detection
# endif
#else
# error no context cracking for this compiler
#endif
#if !defined(COMPILER_CL)
# define COMPILER_CL 0
#endif
#if !defined(COMPILER_CLANG)
# define COMPILER_CLANG 0
#endif
#if !defined(COMPILER_GCC)
# define COMPILER_GCC 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(ARCH_X64)
# define ARCH_X64 0
#endif
#if !defined(ARCH_X86)
# define ARCH_X86 0
#endif
#if !defined(ARCH_ARM)
# define ARCH_ARM 0
#endif
#if !defined(ARCH_ARM64)
# define ARCH_ARM64 0
#endif
#if COMPILER_CL
# define MR4TH_THREADVAR __declspec(thread)
#elif COMPILER_CLANG || COMPILER_GCC
# define MR4TH_THREADVAR __thread
#else
# error MR4TH_THREADVAR not defined for this compiler
#endif
// setup pointer size macro
#if ARCH_X64 || ARCH_ARM64
# define ARCH_ADDRSIZE 64
#else
# define ARCH_ADDRSIZE 32
#endif
////////////////////////////////
// Macros: Assert
#if !defined(AssertBreak)
# define AssertBreak() (*(volatile int*)0 = 0)
#endif
#define Assert(c) do{ if (!(c)){ AssertBreak(); } }while(0)
#define StaticAssert(c,l) typedef U8 Glue(l,__LINE__) [(c)?1:-1]
////////////////////////////////
// Macros: Memory
#include <string.h>
#define MemoryZero(p,z) memset((p), 0, (z))
#define MemoryZeroStruct(p) MemoryZero((p), sizeof(*(p)))
#define MemoryZeroArray(p) MemoryZero((p), sizeof(p))
#define MemoryZeroTyped(p,c) MemoryZero((p), sizeof(*(p))*(c))
#define MemoryMatch(a,b,z) (memcmp((a),(b),(z)) == 0)
#define MemoryCopy(d,s,z) memmove((d), (s), (z))
#define MemoryCopyStruct(d,s) MemoryCopy((d),(s),Min(sizeof(*(d)),sizeof(*(s))))
#define MemoryCopyArray(d,s) MemoryCopy((d),(s),Min(sizeof(s),sizeof(d)))
#define MemoryCopyTyped(d,s,c) MemoryCopy((d),(s),Min(sizeof(*(d)),sizeof(*(s)))*(c))
////////////////////////////////
// Macros: Linked Lists
#define DLLPushBack_NPZ(f,l,n,next,prev,nil)\
(((f) == (nil))?\
((f)=(l)=(n),(n)->next=(n)->prev=(nil)):\
((n)->prev=(l),(l)->next=(n),(l)=(n),(n)->next=(nil)))
#define DLLPushBack(f,l,n) DLLPushBack_NPZ(f,l,n,next,prev,0)
#define DLLPushFront(f,l,n) DLLPushBack_NPZ(l,f,n,prev,next,0)
#define DLLInsert_NPZ(f,l,p,n,next,prev,nil) \
(((p) != (l))?\
((n)->next = (p)->next,\
(n)->prev = (p),\
(p)->next->prev = (n),\
(p)->next = (n))\
:((n)->next = (nil),\
(n)->prev = (l),\
(l)->next = (n),\
(l) = (n)))
#define DLLInsert(f,l,p,n) DLLInsert_NPZ(f,l,p,n,next,prev,0)
#define DLLRemove_NPZ(f,l,n,next,prev,nil)\
((f)==(n)?\
((f)==(l)?\
((f)=(l)=(nil)):\
((f)=(f)->next,(f)->prev=(nil))):\
(l)==(n)?\
((l)=(l)->prev,(l)->next=(nil)):\
((n)->next->prev=(n)->prev,\
(n)->prev->next=(n)->next))
#define DLLRemove(f,l,n) DLLRemove_NPZ(f,l,n,next,prev,0)
#define SLLQueuePush_NZ(f,l,n,next,nil) (((f)==(nil)?\
(f)=(l)=(n):\
((l)->next=(n),(l)=(n))),\
(n)->next=(nil))
#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(f,l,n,next,0)
#define SLLQueuePushFront_NZ(f,l,n,next,nil) ((f)==(nil)?\
((f)=(l)=(n),(n)->next=(nil)):\
((n)->next=(f),(f)=(n)))
#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(f,l,n,next,0)
#define SLLQueuePop_NZ(f,l,next,nil) ((f)==(l)?\
(f)=(l)=(nil):\
((f)=(f)->next))
#define SLLQueuePop(f,l) SLLQueuePop_NZ(f,l,next,0)
#define SLLStackPush_N(f,n,next) ((n)->next=(f),(f)=(n))
#define SLLStackPush(f,n) SLLStackPush_N(f,n,next)
#define SLLStackPop_NZ(f,next,nil) ((f)==(nil)?(nil):\
((f)=(f)->next))
#define SLLStackPop(f) SLLStackPop_NZ(f,next,0)
////////////////////////////////
// Macros: Common Expressions
#define ArrayCount(a) (sizeof(a)/sizeof(*(a)))
#define IntFromPtr(p) (UAddr)(p)
#define PtrFromInt(n) (void*)((UAddr)(n))
#define PtrDif(a,b) ((U8*)(a) - (U8*)(b))
#define AlignUpPow2(x,p) (((x) + (p) - 1)&~((p) - 1))
#define AlignDownPow2(x,p) ((x)&~((p) - 1))
#define IsPow2OrZero(x) (((x)&((x)-1)) == 0)
#define Min(a,b) (((a)<(b))?(a):(b))
#define Max(a,b) (((a)>(b))?(a):(b))
#define Clamp(a,x,b) (((x)<(a))?(a):\
((b)<(x))?(b):(x))
#define ClampTop(a,b) Min(a,b)
#define ClampBot(a,b) Max(a,b)
#define KB(x) ((U64)(x) << 10)
#define MB(x) ((U64)(x) << 20)
#define GB(x) ((U64)(x) << 30)
#define TB(x) ((U64)(x) << 40llu)
////////////////////////////////
// Types: Basic
#include <stdint.h>
#include <stdarg.h>
typedef int8_t S8;
typedef int16_t S16;
typedef int32_t S32;
typedef int64_t S64;
typedef uint8_t U8;
typedef uint16_t U16;
typedef uint32_t U32;
typedef uint64_t U64;
typedef S8 B8;
typedef S16 B16;
typedef S32 B32;
typedef S64 B64;
typedef float F32;
typedef double F64;
#if ARCH_ADDRSIZE == 32
typedef U32 UAddr;
typedef S32 SAddr;
#elif ARCH_ADDRSIZE == 64
typedef U64 UAddr;
typedef S64 SAddr;
#else
# error UAddr and SAddr not defined for this architecture
#endif
typedef void VoidFunc(void);
////////////////////////////////
// Types: Arena
typedef struct Arena{
struct Arena *current;
struct Arena *prev;
U64 alignment;
B8 growing;
U8 filler[7];
U64 base_pos;
U64 chunk_cap;
U64 chunk_pos;
U64 chunk_commit_pos;
} Arena;
typedef struct ArenaTemp{
Arena *arena;
U64 pos;
} ArenaTemp;
////////////////////////////////
// Types: String
typedef struct String8{
U8 *str;
U64 size;
} String8;
////////////////////////////////
// Types: Stream
#include <stdio.h>
typedef void STREAM_Handle;
typedef struct STREAM_Node{
struct STREAM_Node *next;
U64 size;
U8 data[0];
} STREAM_Node;
#define STREAM_NODE_FROM_DATA(d) (STREAM_Node*)((U8*)(d) - sizeof(STREAM_Node))
typedef struct STREAM{
Arena *arena;
U64 clear_pos;
STREAM_Node *first_node;
STREAM_Node *last_node;
U64 buffer_cap;
U64 total_size;
STREAM_Node *unused_node;
} STREAM;
#define STREAM_ALLOC_SIZE MB(16)
////////////////////////////////
// Functions: Arenas
// arena core
MR4TH_SYMBOL Arena* arena_alloc_reserve(U64 reserve_size, B32 growing);
MR4TH_SYMBOL Arena* arena_alloc(void);
MR4TH_SYMBOL void arena_release(Arena *arena);
MR4TH_SYMBOL void* arena_push_no_zero(Arena *arena, U64 size);
MR4TH_SYMBOL void arena_pop_to(Arena *arena, U64 pos);
MR4TH_SYMBOL U64 arena_current_pos(Arena *arena);
MR4TH_SYMBOL void* arena_push(Arena *arena, U64 size);
MR4TH_SYMBOL void arena_align(Arena *arena, U64 pow2_align);
MR4TH_SYMBOL void arena_pop_amount(Arena *arena, U64 amount);
#define push_array(a,T,c) (T*)arena_push((a), sizeof(T)*(c))
#define push_array_no_zero(a,T,c) (T*)arena_push_no_zero((a), sizeof(T)*(c))
#define push_array_copy(a,T,s,c) \
(T*)memory_move(push_array_no_zero(a,T,c), (s), sizeof(T)*(c))
// arena temp
MR4TH_SYMBOL ArenaTemp arena_begin_temp(Arena *arena);
MR4TH_SYMBOL void arena_end_temp(ArenaTemp *temp);
// scratch
MR4TH_SYMBOL ArenaTemp arena_get_scratch(Arena **conflict_array, U32 count);
#define arena_release_scratch(temp) arena_end_temp(temp)
////////////////////////////////
// Functions: Strings
MR4TH_SYMBOL String8 str8(U8 *str, U64 size);
MR4TH_SYMBOL String8 str8_range(U8 *first, U8 *opl);
MR4TH_SYMBOL String8 str8_cstring(U8 *cstr);
MR4TH_SYMBOL String8 str8_cstring_capped(U8 *cstr, U8 *opl);
#define str8_lit(s) str8((U8*)(s), sizeof(s) - 1)
#define str8_struct(s) str8((U8*)(s), sizeof(*(s)))
#define str8_array(s) str8((U8*)(s), sizeof(s))
#define str8_lit_const(s) { (U8*)(s), sizeof(s) - 1 }
MR4TH_SYMBOL U32 u32_from_str8_base10(String8 string);
////////////////////////////////
// Functions: Stream
// stream core
MR4TH_SYMBOL STREAM* stream_new(void);
MR4TH_SYMBOL void stream_release(STREAM *stream);
MR4TH_SYMBOL void stream_clear(STREAM *stream);
MR4TH_SYMBOL void stream_write(STREAM *stream, String8 data);
MR4TH_SYMBOL U8* stream_allocate(STREAM *stream, U64 size);
MR4TH_SYMBOL U64 stream_total_size(STREAM *stream);
MR4TH_SYMBOL STREAM_Handle* stream_next_chunk(STREAM *stream, STREAM_Handle *handle, String8 *chunk_out);
// stream helpers
MR4TH_SYMBOL String8 stream_read(Arena *arena, STREAM *stream);
MR4TH_SYMBOL void stream_printfv(STREAM *stream, char *fmt, va_list args);
MR4TH_SYMBOL void stream_printf(STREAM *stream, char *fmt, ...);
MR4TH_SYMBOL void stream_fprint(FILE *file, STREAM *stream);
////////////////////////////////
// Implementable Functions: Memory Functions
MR4TH_SYMBOL void* os_memory_reserve(U64 size);
MR4TH_SYMBOL B32 os_memory_commit(void *ptr, U64 size);
MR4TH_SYMBOL void os_memory_decommit(void *ptr, U64 size);
MR4TH_SYMBOL void os_memory_release(void *ptr, U64 size);
#if OS_WINDOWS
////////////////////////////////
// Win32: Includes
#include <Windows.h>
#include <userenv.h>
#include <psapi.h>
#elif OS_LINUX
////////////////////////////////
// Linux: Includes
#include <sys/mman.h>
// OS Missing
#else
# error not implemented on this OS
#endif
////////////////////////////////////////////////
////////////////////////////////////////////////
/// stb_sprintf.h STB_SPRINTF_H_INCLUDE ////
////////////////////////////////////////////////
////////////////////////////////////////////////
#define STB_SPRINTF_DECORATE(name) m4_##name
/*
Single file sprintf replacement.
Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20.
Hereby placed in public domain.
This is a full sprintf replacement that supports everything that
the C runtime sprintfs support, including float/double, 64-bit integers,
hex floats, field parameters (%*.*d stuff), length reads backs, etc.
Why would you need this if sprintf already exists? Well, first off,
it's *much* faster (see below). It's also much smaller than the CRT
versions code-space-wise. We've also added some simple improvements
that are super handy (commas in thousands, callbacks at buffer full,
for example). Finally, the format strings for MSVC and GCC differ
for 64-bit integers (among other small things), so this lets you use
the same format strings in cross platform code.
It uses the standard single file trick of being both the header file
and the source itself. If you just include it normally, you just get
the header file function definitions. To get the code, you include
it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first.
It only uses va_args macros from the C runtime to do it's work. It
does cast doubles to S64s and shifts and divides U64s, which does
drag in CRT code on most platforms.
It compiles to roughly 8K with float support, and 4K without.
As a comparison, when using MSVC static libs, calling sprintf drags
in 16K.
API:
====
int stbsp_sprintf( char * buf, char const * fmt, ... )
int stbsp_snprintf( char * buf, int count, char const * fmt, ... )
Convert an arg list into a buffer. stbsp_snprintf always returns
a zero-terminated string (unlike regular snprintf).
int stbsp_vsprintf( char * buf, char const * fmt, va_list va )
int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va )
Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns
a zero-terminated string (unlike regular snprintf).
int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va )
typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len );
Convert into a buffer, calling back every STB_SPRINTF_MIN chars.
Your callback can then copy the chars out, print them or whatever.
This function is actually the workhorse for everything else.
The buffer you pass in must hold at least STB_SPRINTF_MIN characters.
// you return the next buffer to use or 0 to stop converting
void stbsp_set_separators( char comma, char period )
Set the comma and period characters to use.
FLOATS/DOUBLES:
===============
This code uses a internal float->ascii conversion method that uses
doubles with error correction (double-doubles, for ~105 bits of
precision). This conversion is round-trip perfect - that is, an atof
of the values output here will give you the bit-exact double back.
One difference is that our insignificant digits will be different than
with MSVC or GCC (but they don't match each other either). We also
don't attempt to find the minimum length matching float (pre-MSVC15
doesn't either).
If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT
and you'll save 4K of code space.
NOTE(allen): MODIFICATION - I've hard coded that this copy *does* use floats
64-BIT INTS:
============
This library also supports 64-bit integers and you can use MSVC style or
GCC style indicators (%I64d or %lld). It supports the C99 specifiers
for size_t and ptr_diff_t (%jd %zd) as well.
EXTRAS:
=======
Like some GCCs, for integers and floats, you can use a ' (single quote)
specifier and commas will be inserted on the thousands: "%'d" on 12345
would print 12,345.
For integers and floats, you can use a "$" specifier and the number
will be converted to float and then divided to get kilo, mega, giga or
tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is
"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn
2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three
$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the
suffix, add "_" specifier: "%_$d" -> "2.53M".
In addition to octal and hexadecimal conversions, you can print
integers in binary: "%b" for 256 would print 100.
PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC):
===================================================================
"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC)
"%24d" across all 32-bit ints (4.5x/4.2x faster)
"%x" across all 32-bit ints (4.5x/3.8x faster)
"%08x" across all 32-bit ints (4.3x/3.8x faster)
"%f" across e-10 to e+10 floats (7.3x/6.0x faster)
"%e" across e-10 to e+10 floats (8.1x/6.0x faster)
"%g" across e-10 to e+10 floats (10.0x/7.1x faster)
"%f" for values near e-300 (7.9x/6.5x faster)
"%f" for values near e+300 (10.0x/9.1x faster)
"%e" for values near e-300 (10.1x/7.0x faster)
"%e" for values near e+300 (9.2x/6.0x faster)
"%.320f" for values near e-300 (12.6x/11.2x faster)
"%a" for random values (8.6x/4.3x faster)
"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster)
"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster)
"%s%s%s" for 64 char strings (7.1x/7.3x faster)
"...512 char string..." ( 35.0x/32.5x faster!)
*/
#if defined(__clang__)
#if defined(__has_feature) && defined(__has_attribute)
#if __has_feature(address_sanitizer)
#if __has_attribute(__no_sanitize__)
#define STBSP__ASAN __attribute__((__no_sanitize__("address")))
#elif __has_attribute(__no_sanitize_address__)
#define STBSP__ASAN __attribute__((__no_sanitize_address__))
#elif __has_attribute(__no_address_safety_analysis__)
#define STBSP__ASAN __attribute__((__no_address_safety_analysis__))
#endif
#endif
#endif
#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
#if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__
#define STBSP__ASAN __attribute__((__no_sanitize_address__))
#endif
#endif
#ifndef STBSP__ASAN
#define STBSP__ASAN
#endif
#ifdef STB_SPRINTF_STATIC
#define STBSP__PUBLICDEC static
#define STBSP__PUBLICDEF static STBSP__ASAN
#else
#ifdef __cplusplus
#define STBSP__PUBLICDEC extern "C"
#define STBSP__PUBLICDEF extern "C" STBSP__ASAN
#else
#define STBSP__PUBLICDEC extern
#define STBSP__PUBLICDEF STBSP__ASAN
#endif
#endif
#if defined(__has_attribute)
#if __has_attribute(format)
#define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va)))
#endif
#endif
#ifndef STBSP__ATTRIBUTE_FORMAT
#define STBSP__ATTRIBUTE_FORMAT(fmt,va)
#endif
#ifdef _MSC_VER
#define STBSP__NOTUSED(v) (void)(v)
#else
#define STBSP__NOTUSED(v) (void)sizeof(v)
#endif
#include <stdarg.h> // for va_arg(), va_list()
#include <stddef.h> // size_t, ptrdiff_t
#ifndef STB_SPRINTF_MIN
#define STB_SPRINTF_MIN 512 // how many characters per callback
#endif
typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len);
#ifndef STB_SPRINTF_DECORATE
#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names
#endif
STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va);
STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va);
STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3);
STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4);
STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va);
STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period);
#endif //BASE_H

10
build.bat Normal file
View File

@ -0,0 +1,10 @@
@echo off
set src=%cd%
set opts=-nologo -Zi -Fetest
if not exist "build" mkdir build
pushd build
cl %opts% %src%\test.c
popd

12
build.sh Normal file
View File

@ -0,0 +1,12 @@
#!/bin/bash
src=$PWD
opts=-Wno-switch
mkdir -p "build"
cd build
clang $opts $src/test.c --output test
cd ..

25
test.c Normal file
View File

@ -0,0 +1,25 @@
//#define BLANK_MODE "aritynode.blank.c"
#include "base.h"
#include "aritynode.h"
#include "base.c"
#include "aritynode.test.c"
#ifndef BLANK_MODE
# include "aritynode.c"
#endif
#ifdef BLANK_MODE
# include BLANK_MODE
#endif
#include <stdio.h>
int
main(int argc, char **argv){
ds_aritynode__test();
fprintf(stdout, "Completed tests without problem\n");
return(0);
}