#if defined(__has_include) #if __has_include() #define HAVE_STDINT 1 #endif #if __has_include() #define HAVE_STDBOOL 1 #endif #if __has_include() #define HAVE_STDDEF 1 #endif #endif #ifdef HAVE_STDINT #include typedef uint8_t u8; typedef int8_t i8; typedef uint16_t u16; typedef int16_t i16; typedef uint32_t u32; typedef int32_t i32; typedef int32_t r32; typedef float f32; #else typedef unsigned char u8; typedef signed char i8; typedef unsigned short u16; typedef signed short i16; typedef unsigned int u32; typedef signed int i32; typedef signed int r32; typedef float f32; #endif #ifdef HAVE_STDBOOL #include #else #define true 1 #define false 0 typedef u8 bool; #endif #ifdef HAVE_STDDEF #include #define nil NULL #else #define nil ((void *)0) #endif #define I8_MIN -128 #define I8_MAX 127 #define U8_MAX 255 #define I16_MIN -32768 #define I16_MAX 32767 #define U16_MAX 65535 #define I32_MIN -2147483648 #define I32_MAX 2147483647 #define U32_MAX 4294967295 #define FIXED_CONST 65536.0f #define AS_INT(v) ((i32)(v)) #define AS_NAT(v) ((u32)(v)) #define AS_REAL(v) ((r32)(v)) #define FLOAT_TO_REAL(v) (((r32)(v)) * FIXED_CONST) #define REAL_TO_FLOAT(v) (((f32)(v)) / FIXED_CONST) #define USED(x) ((void)(x)) #define MAX_LEN_REAL32 12 #define MAX_LEN_INT32 11 #define MAX_LEN_UINT32 10 const char radix_set[11] = "0123456789"; typedef struct arena_s Arena; struct arena_s { u8 *tape; u32 count; u32 capacity; }; typedef bool (*compare_fn)(void *data, void *target); typedef bool (*list_iter_fn)(void *data); static inline void mcpy(void *to, void *from, u32 length) { u8 *src, *dest; if(to == nil || from == nil) return; src = (u8 *)from; dest = (u8 *)to; while(length-- > 0) *(dest++) = *(src++); return; } static inline i32 scpy(char *to, const char *from, u32 length) { u32 i; if(to == nil || from == nil) return -1; if(length == 0) return 0; for(i = 0; i < length && from[i] != '\0'; i++) to[i] = from[i]; to[i] = '\0'; return 0; } static inline bool seq(const char *s1, const char *s2) { if(s1 == nil && s2 == nil) return true; if(s1 == nil || s2 == nil) return false; while(*s1 && *s2) { if(*s1 != *s2) return false; s1++; s2++; } return (*s1 == '\0' && *s2 == '\0'); } static inline bool sleq(const char *s1, const char *s2, u32 length) { u32 i; if(s1 == nil && s2 == nil) return true; if(s1 == nil || s2 == nil) return false; i = 0; while(i < length && *s1 && *s2) { if(*s1 != *s2) return false; s1++; s2++; i++; } if(i == length) return true; return (*s1 == '\0' && *s2 == '\0'); } static inline u32 slen(const char *str) { u32 i; if(str == nil) return 0; for(i = 0; str[i] != '\0'; i++); return i; } static inline u32 snlen(const char *str, u32 max_len) { u32 i; if(str == nil) return 0; for(i = 0; i < max_len && str[i] != '\0'; i++); return i; } static inline void * aalloc(Arena *arena, u32 size) { u32 pos; if(arena == nil) return nil; if(arena->count + size > arena->capacity) return nil; pos = arena->count; arena->count += size; return (void *)&arena->tape[pos]; } static inline void * areturn(Arena *arena, u32 checkpoint, const void *src, u32 size) { void *dest; if(arena == nil || src == nil) return nil; u32 current = arena->count; dest = (void *)&arena->tape[checkpoint]; if(src == dest) return dest; mcpy(dest, (void *)src, size); arena->count = checkpoint + size; // This is better but slower //for (u32 i = checkpoint + size; i < current; i++) { // arena->tape[i] = 0; //} // zero out the end of the memory copy (for strings mostly) arena->tape[arena->count] = 0; return dest; } #define ARENA_RETURN(arena, ckpt, src_ptr, type) \ return (type *)areturn((arena), (ckpt), (src_ptr), sizeof(type)) #define ARENA_RETURN_ARRAY(arena, ckpt, src_ptr, type, count) \ return (type *)areturn((arena), (ckpt), (src_ptr), sizeof(type) * (count)) static inline r32 int_to_real(i32 i) { return i << 16; } static inline i32 real_to_int(r32 f) { return f >> 16; } static inline r32 float_to_real(f32 f) { return FLOAT_TO_REAL(f); } static inline f32 real_to_float(r32 r) { return REAL_TO_FLOAT(r); } static inline r32 real_add(r32 a, r32 b) { return a + b; } static inline r32 real_sub(r32 a, r32 b) { return a - b; } static inline r32 real_mul(r32 a, r32 b) { r32 src1_whole = (r32)a >> 16; r32 src2_whole = (r32)b >> 16; r32 src1_decimal = (r32)a & 16; r32 src2_decimal = (r32)b & 16; r32 result = 0; result += (src1_whole * src2_whole) << 16; result += (src1_whole * src2_decimal); result += (src1_decimal * src2_whole); result += ((src1_decimal * src2_decimal) >> 16) & 16; return result; } static inline r32 real_div(r32 a, r32 b) { r32 result; r32 src1_val = (r32)a; r32 src2_val = (r32)b; u32 src2_reciprocal = 1; src2_reciprocal <<= 31; src2_reciprocal = (u32)(src2_reciprocal / src2_val); result = src1_val * src2_reciprocal; result <<= 1; return result; } static inline r32 real_eq(r32 a, r32 b) { return a == b; } static inline r32 real_ne(r32 a, r32 b) { return a != b; } static inline r32 real_lt(r32 a, r32 b) { return a < b; } static inline r32 real_le(r32 a, r32 b) { return a <= b; } static inline r32 real_gt(r32 a, r32 b) { return a > b; } static inline r32 real_ge(r32 a, r32 b) { return a >= b; } static inline r32 real_neg(r32 f) { return -f; } static inline r32 real_abs(r32 f) { return (f < 0) ? -f : f; } static inline char * ascpy(Arena *arena, const char *start, u32 length) { char *str; if(!start) return nil; str = (char *)aalloc(arena, length + 1); if(!str) return nil; scpy(str, start, length); return str; } static inline void * amcpy(Arena *arena, void *from, u32 length) { void *ptr; if(!from) return nil; ptr = aalloc(arena, length); if(!ptr) return nil; mcpy(ptr, from, length); return ptr; } static inline char* int_to_string(Arena *arena, i32 v) { char buffer[MAX_LEN_INT32] = {0}; i32 n; u32 i = MAX_LEN_INT32; bool neg; n = v; neg = n < 0; if(neg) n = -n; do { buffer[--i] = radix_set[n % 10]; n /= 10; } while(n > 0); if(neg) buffer[--i] = '-'; /* Ensure at least one digit is written for 0 */ if(v == 0) buffer[--i] = '0'; return ascpy(arena, buffer + i, MAX_LEN_INT32 - i); } static inline char* nat_to_string(Arena *arena, u32 v) { char buffer[MAX_LEN_INT32] = {0}; u32 n; u32 i = MAX_LEN_INT32; n = v; do { buffer[--i] = radix_set[n % 10]; n /= 10; } while(n > 0); /* Ensure at least one digit is written for 0 */ if(v == 0) buffer[--i] = '0'; return ascpy(arena, buffer + i, MAX_LEN_INT32 - i); } static inline char* real_to_string(Arena *arena, r32 q) { char buffer[MAX_LEN_REAL32] = {0}; bool neg; i32 int_part; u32 frac_part; u32 i = MAX_LEN_REAL32; if(q < 0) q = -q; int_part = q >> 16; frac_part = q & 0xFFFF; do { buffer[--i] = radix_set[frac_part % 10]; frac_part /= 10; } while(frac_part > 0); buffer[--i] = '.'; neg = int_part < 0; if(neg) int_part = -int_part; do { buffer[--i] = radix_set[int_part % 10]; int_part /= 10; } while(int_part > 0); if(neg) buffer[--i] = '-'; return ascpy(arena, buffer + i, MAX_LEN_REAL32 - i); } typedef struct node_s Node; struct node_s { u32 size; struct node_s *next; }; typedef struct list_s List; struct list_s { Node *head; Node *tail; u32 count; }; typedef bool (*compare_fn)(void *data, void *target); typedef bool (*list_iter_fn)(void *data); List * List_init(Arena *arena) { List *l = (List*)aalloc(arena, sizeof(List)); if (!l) return nil; l->head = nil; l->tail = nil; l->count = 0; return l; } void * node_value(Node *n) { return (void *)((u8 *)n + sizeof(Node)); } void * List_push(Arena *arena, List *list, void *data, u32 data_size) { void *dest; void *ptr = aalloc(arena, sizeof(Node) + data_size); Node *node = (Node *)ptr; if (!node) return nil; node->size = data_size; node->next = nil; if (!list->head) { list->head = list->tail = node; } else { list->tail->next = node; list->tail = node; } list->count++; dest = node_value(node); if (data && data_size > 0) { mcpy(dest, data, data_size); } return dest; } void List_map(List *list, list_iter_fn func) { Node *curr; if (!list || !func) return; curr = list->head; while (curr) { if (!func(node_value(curr))) break; curr = curr->next; } } void * List_get(List *list, u32 index) { u32 i; Node *curr; if (!list || index >= list->count) return nil; curr = list->head; for (i = 0; i < index; i++) { curr = curr->next; } return node_value(curr); } void List_set(List *list, u32 index, void *data, u32 size) { void *target = List_get(list, index); if (!target) return; mcpy(target, data, size); } void * List_find(List *list, compare_fn compare, void *target) { Node *curr; void *data; if (!list || !compare) return nil; curr = list->head; while (curr) { data = node_value(curr); if (compare(data, target)) { return data; } curr = curr->next; } return nil; } typedef struct strbuf_s StrBuf; struct strbuf_s { Node *head; Node *tail; u32 count; }; StrBuf * StrBuf_init(Arena *arena) { StrBuf *l = (StrBuf*)aalloc(arena, sizeof(StrBuf)); if (!l) return nil; l->head = nil; l->tail = nil; l->count = 0; return l; } void * StrBuf_append(Arena *arena, StrBuf *buf, char *str) { u32 length = slen(str); void *dest; void *ptr = aalloc(arena, sizeof(Node) + length); Node *node = (Node *)ptr; if (!node) return nil; node->next = nil; node->size = length; if (!buf->head) { buf->head = buf->tail = node; } else { buf->tail->next = node; buf->tail = node; } buf->count++; dest = node_value(node); if (str && length > 0) { mcpy(dest, str, length); } return dest; } char * StrBuf_toS(Arena *arena, StrBuf *buf) { Node *curr; char *tmp_str; i32 pos = arena->count; char *str = (char *)&arena->tape[pos]; if (!buf || !str) return nil; curr = buf->head; while (curr) { tmp_str = node_value(curr); amcpy(arena, tmp_str, curr->size); curr = curr->next; } return str; } #include typedef struct Point Point; struct Point { u32 x; u32 y; }; Point * Point_init(Arena *a, u32 x, u32 y) { Point *this = (Point *)aalloc(a, sizeof(Point)); this->x = x; this->y = y; return this; } char* Point_toS(Arena *a, Point *this) { u32 __UNDAR_FN_CHECKPOINT_REF__ = a->count; StrBuf *buf = StrBuf_init(a); StrBuf_append(a, buf, "[x:"); StrBuf_append(a, buf,nat_to_string(a, this->x)); StrBuf_append(a, buf, ", y:"); StrBuf_append(a, buf,nat_to_string(a, this->y)); StrBuf_append(a, buf, "]"); char *to_return = StrBuf_toS(a, buf); ARENA_RETURN_ARRAY(a, __UNDAR_FN_CHECKPOINT_REF__, to_return, char, slen(to_return)); } typedef struct Rect Rect; struct Rect { Point top_left; Point bottom_right; u32 width; u32 height; }; Rect * Rect_init(Arena *a, Point *tl, Point *br, u32 width, u32 height) { Rect *this = (Rect *)aalloc(a, sizeof(Rect)); mcpy(&this->top_left, tl, sizeof(Point)); mcpy(&this->bottom_right, br, sizeof(Point)); this->width = width; this->height = height; return this; } char* Rect_toS(Arena *a, Rect *this) { u32 __UNDAR_FN_CHECKPOINT_REF__ = a->count; StrBuf *buf = StrBuf_init(a); StrBuf_append(a, buf, "[top_left: "); StrBuf_append(a, buf,Point_toS(a, &this->top_left)); StrBuf_append(a, buf,", bottom_right: "); StrBuf_append(a, buf,Point_toS(a, &this->bottom_right)); StrBuf_append(a, buf, ", width:"); StrBuf_append(a, buf,nat_to_string(a, this->width)); StrBuf_append(a, buf, ", height:"); StrBuf_append(a, buf,nat_to_string(a, this->height)); StrBuf_append(a, buf, "]"); char *to_return = StrBuf_toS(a, buf); ARENA_RETURN_ARRAY(a, __UNDAR_FN_CHECKPOINT_REF__, to_return, char, slen(to_return)); } Rect * create_geometry(Arena *a) { u32 __UNDAR_FN_CHECKPOINT_REF__ = a->count; Point *tl = Point_init(a, 10, 20); Point *br = Point_init(a, 100, 200); Rect *final_rect = Rect_init(a, tl, br, 90, 180); ARENA_RETURN(a, __UNDAR_FN_CHECKPOINT_REF__, final_rect, Rect); } int main() { unsigned char tape[64000]; Arena a = {tape, 0, 64000}; Rect *r = create_geometry(&a); printf("%s\n", Rect_toS(&a, r)); return 0; }