lesson-1 initial commit
commit
fd187edbaf
|
|
@ -0,0 +1 @@
|
||||||
|
build/*
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
src=$PWD
|
||||||
|
opts=-Wno-switch
|
||||||
|
|
||||||
|
mkdir -p "build"
|
||||||
|
|
||||||
|
cd build
|
||||||
|
clang $opts $src/test.c --output test
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue