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