diff options
| -rw-r--r-- | .clang-format | 3 | ||||
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | README.md | 8 | ||||
| -rw-r--r-- | base_test.c | 20 | ||||
| -rw-r--r-- | json.c | 168 | ||||
| -rw-r--r-- | json.h | 12 | ||||
| -rw-r--r-- | log.c | 10 | ||||
| -rw-r--r-- | log.h | 2 | ||||
| -rw-r--r-- | main.c | 6 | ||||
| -rw-r--r-- | memory.c | 20 | ||||
| -rw-r--r-- | memory.h | 6 | ||||
| -rw-r--r-- | string.c | 32 | ||||
| -rw-r--r-- | string.h | 6 | ||||
| -rw-r--r-- | test_json.c | 84 | ||||
| -rw-r--r-- | test_string.c | 16 | ||||
| -rw-r--r-- | testing.h | 21 | ||||
| -rw-r--r-- | types.h | 4 | ||||
| -rw-r--r-- | vec.c | 24 | ||||
| -rw-r--r-- | vec.h | 10 |
19 files changed, 235 insertions, 220 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..d180071 --- /dev/null +++ b/.clang-format @@ -0,0 +1,3 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +ColumnLimit: 80 @@ -14,3 +14,6 @@ test: fish generate.fish; make debug; ./Debug/test; + +format: + clang-format -i *.c *.h @@ -6,3 +6,11 @@ - Vec push no need to reallocate vec, only items. Same for Str? Read about stack pointers in C - Vec_get not safe, I made a type mistake. And should be more efficient for loops - Fix tests in release +- Benchmark 1MB file +- More modern include pragma (once) +- File structure +- Ignore some errors + +## Resources + +- https://nullprogram.com/blog/2023/10/08/ diff --git a/base_test.c b/base_test.c index c19806f..7a0c77b 100644 --- a/base_test.c +++ b/base_test.c @@ -1,15 +1,13 @@ -#include <stdio.h> - #define test(func) \ - switch (func()) { \ - case 0: \ - printf("✅ %s\n", #func); \ - success++; \ - break; \ - default: \ - failures++; \ - printf("🚫 %s\n", #func); \ - } + switch (func()) { \ + case 0: \ + printf("✅ %s\n", #func); \ + success++; \ + break; \ + default: \ + failures++; \ + printf("🚫 %s\n", #func); \ + } int success; int failures; @@ -9,86 +9,86 @@ #include "string.h" typedef struct { - JSON *value; - uptr pos; + JSON *value; + uptr pos; } parse_any_result; parse_any_result parse_any(Arena *a, byte *src, uptr pos); typedef struct { - int *value; - uptr pos; + int *value; + uptr pos; } parse_integer_result; parse_integer_result parse_integer(Arena *a, byte *src, uptr pos) { - byte ints[16]; - int i = 0; - while (isdigit(src[pos + i])) { - int val = (src[pos + i] - '0'); - ints[i] = val; - i++; - } - int *result = new (a, int, 1); - for (int j = 0; j < i; j++) { - *result += ints[j] * pow(10, (i - j - 1)); - } - return (parse_integer_result){result, pos + i}; + byte ints[16]; + int i = 0; + while (isdigit(src[pos + i])) { + int val = (src[pos + i] - '0'); + ints[i] = val; + i++; + } + int *result = new(a, int, 1); + for (int j = 0; j < i; j++) { + *result += ints[j] * pow(10, (i - j - 1)); + } + return (parse_integer_result){result, pos + i}; } uptr absorb_whitespaces(byte *src, uptr pos) { - int i = 0; - while (isspace(src[pos + i])) { - i++; - } - return pos + i; + int i = 0; + while (isspace(src[pos + i])) { + i++; + } + return pos + i; } typedef struct { - Vec *items; // Vec<JSON> - uptr pos; + Vec *items; // Vec<JSON> + uptr pos; } parse_array_result; parse_array_result parse_array(Arena *a, byte *src, uptr pos) { - assert(src[pos] == '['); - pos++; - Vec items = Vec_new(a, JSON, 2); - for (;;) { - pos = absorb_whitespaces(src, pos); - parse_any_result result = parse_any(a, src, pos); - Vec_push(a, &items, result.value); - pos = result.pos; - pos = absorb_whitespaces(src, pos); - if (src[pos] == ',') { - pos++; - } else { - break; - } - }; - assert(src[pos] == ']'); + assert(src[pos] == '['); + pos++; + Vec items = Vec_new(a, JSON, 2); + for (;;) { + pos = absorb_whitespaces(src, pos); + parse_any_result result = parse_any(a, src, pos); + Vec_push(a, &items, result.value); + pos = result.pos; + pos = absorb_whitespaces(src, pos); + if (src[pos] == ',') { + pos++; + } else { + break; + } + }; + assert(src[pos] == ']'); - return (parse_array_result){&items, pos + 1}; + return (parse_array_result){&items, pos + 1}; } typedef struct { - Str *string; - uptr pos; + Str *string; + uptr pos; } parse_string_result; parse_string_result parse_string(Arena *a, byte *src, uptr pos) { - assert(src[pos] == '"'); - int i = 1; + assert(src[pos] == '"'); + int i = 1; - while (src[pos + i] != '"' && src[pos + i - 1] != '\\') { - i++; - } - assert(src[pos + i] == '"'); - Str* s = Str_copy(a, &src[pos + 1], i - 1); + while (src[pos + i] != '"' && src[pos + i - 1] != '\\') { + i++; + } + assert(src[pos + i] == '"'); + Str *s = Str_copy(a, &src[pos + 1], i - 1); - return (parse_string_result){s, pos + i + 1}; + return (parse_string_result){s, pos + i + 1}; } typedef struct { - JSONObject *object; - uptr pos; + JSONObject *object; + uptr pos; } parse_object_result; parse_object_result parse_object(Arena *a, byte *src, uptr pos) { @@ -107,59 +107,61 @@ parse_object_result parse_object(Arena *a, byte *src, uptr pos) { Str *key = str_result.string; pos = absorb_whitespaces(src, str_result.pos); assert(src[pos] == ':'); - pos = absorb_whitespaces(src, pos+1); + pos = absorb_whitespaces(src, pos + 1); parse_any_result any_result = parse_any(a, src, pos); object->len++; Vec_push(a, &object->keys, key); Vec_push(a, &object->values, any_result.value); pos = absorb_whitespaces(src, any_result.pos); - if (src[pos] != ',') {break;} - pos = absorb_whitespaces(src, pos +1); + if (src[pos] != ',') { + break; + } + pos = absorb_whitespaces(src, pos + 1); } assert(src[pos] == '}'); - return (parse_object_result){object, pos+1}; + return (parse_object_result){object, pos + 1}; } parse_any_result parse_any(Arena *a, byte *src, uptr pos) { - JSON *value = new (a, JSON, 1); - if (isdigit(src[pos])) { - parse_integer_result result = parse_integer(a, src, pos); - value->integer = result.value; - pos = result.pos; - } else if (src[pos] == '[') { - parse_array_result result = parse_array(a, src, pos); - value->array = result.items; - pos = result.pos; - } else if (src[pos] == '"') { - parse_string_result result = parse_string(a, src, pos); - value->string = result.string; - pos = result.pos; - } else if (src[pos] == '{') { - parse_object_result result = parse_object(a, src, pos); - value->object = result.object; - pos = result.pos; - } + JSON *value = new(a, JSON, 1); + if (isdigit(src[pos])) { + parse_integer_result result = parse_integer(a, src, pos); + value->integer = result.value; + pos = result.pos; + } else if (src[pos] == '[') { + parse_array_result result = parse_array(a, src, pos); + value->array = result.items; + pos = result.pos; + } else if (src[pos] == '"') { + parse_string_result result = parse_string(a, src, pos); + value->string = result.string; + pos = result.pos; + } else if (src[pos] == '{') { + parse_object_result result = parse_object(a, src, pos); + value->object = result.object; + pos = result.pos; + } - return (parse_any_result){value, pos}; + return (parse_any_result){value, pos}; } JSON JSON_parse(Arena *a, byte *src) { - parse_any_result result = parse_any(a, src, 0); - return *result.value; + parse_any_result result = parse_any(a, src, 0); + return *result.value; } JSON JSON_Int(Arena *a, int val) { - JSON json = {0}; - json.integer = new (a, int, 1); - *json.integer = val; - return json; + JSON json = {0}; + json.integer = new(a, int, 1); + *json.integer = val; + return json; } -JSON* JSONObject_get(JSONObject *obj, Str key) { +JSON *JSONObject_get(JSONObject *obj, Str key) { for (size i = 0; i < obj->len; i++) { if (Str_equals(*Vec_get(&obj->keys, Str, i), key)) { return Vec_get(&obj->values, JSON, i); } } - return NULL; + return 0; } @@ -5,17 +5,17 @@ #include "vec.h" typedef struct { - Vec keys; // Vec<Str> + Vec keys; // Vec<Str> Vec values; // Vec<JSON> size len; } JSONObject; typedef struct { - int *integer; - Vec *array; // Vec<JSON> - Str *string; - JSONObject *object; + int *integer; + Vec *array; // Vec<JSON> + Str *string; + JSONObject *object; } JSON; -JSON* JSONObject_get(JSONObject *obj, Str key); +JSON *JSONObject_get(JSONObject *obj, Str key); JSON JSON_parse(Arena *a, byte *src); JSON JSON_Int(Arena *a, int val); #endif @@ -5,9 +5,9 @@ #include "types.h" void info(Logger l, const byte *name, const byte *str, ...) { - if (l.level >= INFO) { - printf("[%s] ", name); - printf(str); - printf("\n"); - } + if (l.level >= INFO) { + printf("[%s] ", name); + printf(str); + printf("\n"); + } } @@ -4,7 +4,7 @@ typedef enum { INFO } LogLevel; typedef struct { - LogLevel level; + LogLevel level; } Logger; void info(Logger l, const byte *name, const byte *str, ...); @@ -10,12 +10,8 @@ Inspirations: #include "string.h" #include "vec.h" -#define sizeof(x) (size)sizeof(x) -#define countof(a) (sizeof(a) / sizeof(*(a))) -#define lengthof(s) (countof(s) - 1) - typedef struct { - int age; + int age; } User; int main() { return 0; } @@ -7,21 +7,21 @@ #include "types.h" Arena Arena_new(size cap) { - Arena a = {0}; - a.cap = cap; - a.beg = malloc(cap); - a.end = a.beg ? a.beg + cap : 0; - return a; + Arena a = {0}; + a.cap = cap; + a.beg = malloc(cap); + a.end = a.beg ? a.beg + cap : 0; + return a; } // Magic to allow optimisation __attribute((malloc, alloc_size(2, 4), // alloc_align(3))) void *alloc(Arena *a, size count, size tsize, int align) { - int padding = -(uptr)a->beg & (align - 1); - assert(count < (a->end - a->beg - padding) / tsize); - void *cursor = a->beg + padding; - a->beg += padding + count * tsize; - return memset(cursor, 0, count * tsize); + int padding = -(uptr)a->beg & (align - 1); + assert(count < (a->end - a->beg - padding) / tsize); + void *cursor = a->beg + padding; + a->beg += padding + count * tsize; + return memset(cursor, 0, count * tsize); } int Arena_get_used(Arena a) { return a.cap - (a.end - a.beg); } @@ -4,9 +4,9 @@ #include "types.h" #define MEMORY_H typedef struct { - size cap; - byte *beg; - byte *end; + size cap; + byte *beg; + byte *end; } Arena; Arena Arena_new(size cap); @@ -8,27 +8,25 @@ // Returns 1 if strings are equal, 0 otherwise int Str_equals(Str a, Str b) { - return (a.len == b.len) && (!a.len || !memcmp(a.data, b.data, a.len)); + return (a.len == b.len) && (!a.len || !memcmp(a.data, b.data, a.len)); } uint64_t Str_hash64(Str s) { - uint64_t h = 0x100; - for (size i = 0; i < s.len; i++) { - h ^= s.data[i] & 255; - h *= 1111111111111111111; - } - return h; + uint64_t h = 0x100; + for (size i = 0; i < s.len; i++) { + h ^= s.data[i] & 255; + h *= 1111111111111111111; + } + return h; } -Str* Str_copy(Arena *a, byte *data, size len) { - Str *str = new(a, Str, 1); - str->len = len; - str->data = new (a, byte, len); - if (str->len) - memcpy(str->data, data, len); - return str; +Str *Str_copy(Arena *a, byte *data, size len) { + Str *str = new(a, Str, 1); + str->len = len; + str->data = new(a, byte, len); + if (str->len) + memcpy(str->data, data, len); + return str; } -void Str_print(Str s) { - printf("%.*s", (int)s.len, s.data); -} +void Str_print(Str s) { printf("%.*s", (int)s.len, s.data); } @@ -8,11 +8,11 @@ #define STRING_H #define S(s) (Str){s, sizeof(s) - 1} typedef struct { - byte *data; - size len; + byte *data; + size len; } Str; int Str_equals(Str a, Str b); uint64_t Str_hash64(Str s); -Str* Str_copy(Arena *a, byte *data, size len); +Str *Str_copy(Arena *a, byte *data, size len); void Str_print(Str s); #endif diff --git a/test_json.c b/test_json.c index ee7f0f3..5807524 100644 --- a/test_json.c +++ b/test_json.c @@ -3,66 +3,66 @@ #include <stdio.h> int test_json_integer() { - Arena perm = Arena_new(128e3); + Arena perm = Arena_new(128e3); - JSON json_int = JSON_parse(&perm, "123"); + JSON json_int = JSON_parse(&perm, "123"); - t_assert(*json_int.integer == 123); - t_assert_equal(Arena_get_used(perm), 36); - return 0; + t_assert(*json_int.integer == 123); + t_assert_equal(Arena_get_used(perm), 36); + return 0; } int test_json_int_array() { - Arena perm = Arena_new(128e3); + Arena perm = Arena_new(128e3); - JSON json_int_array = JSON_parse(&perm, "[1,2,3]"); + JSON json_int_array = JSON_parse(&perm, "[1,2,3]"); - t_assert(json_int_array.integer == NULL); - t_assert_equal(json_int_array.array->len, 3); - int ints[3]; - int sum = 0; - for (int i = 0; i < json_int_array.array->len; i++) { - JSON *item = Vec_get(json_int_array.array, JSON, i); - ints[i] = *item->integer; - sum += *item->integer; - } - t_assert(ints[0] == 1); - t_assert(ints[1] == 2); - t_assert(ints[2] == 3); - t_assert(sum == 6); - t_assert_equal(Arena_get_used(perm), 344); + t_assert(json_int_array.integer == 0); + t_assert_equal(json_int_array.array->len, 3); + int ints[3]; + int sum = 0; + for (int i = 0; i < json_int_array.array->len; i++) { + JSON *item = Vec_get(json_int_array.array, JSON, i); + ints[i] = *item->integer; + sum += *item->integer; + } + t_assert(ints[0] == 1); + t_assert(ints[1] == 2); + t_assert(ints[2] == 3); + t_assert(sum == 6); + t_assert_equal(Arena_get_used(perm), 344); - return 0; + return 0; } int test_json_nested_array() { - Arena perm = Arena_new(128e3); + Arena perm = Arena_new(128e3); - JSON doc = JSON_parse(&perm, "[[1,\"abc\"]]"); + JSON doc = JSON_parse(&perm, "[[1,\"abc\"]]"); - t_assert_equal(Arena_get_used(perm), 283); - JSON sub_array = *Vec_get(doc.array, JSON, 0); - JSON val_1 = *Vec_get(sub_array.array, JSON, 0); - t_assert(*val_1.integer == 1); - JSON val_2 = *Vec_get(sub_array.array, JSON, 1); - Str str = *val_2.string; - Str expected = S("abc"); - t_assert(Str_equals(str, expected)); - t_assert_equal(Arena_get_used(perm), 283); + t_assert_equal(Arena_get_used(perm), 283); + JSON sub_array = *Vec_get(doc.array, JSON, 0); + JSON val_1 = *Vec_get(sub_array.array, JSON, 0); + t_assert(*val_1.integer == 1); + JSON val_2 = *Vec_get(sub_array.array, JSON, 1); + Str str = *val_2.string; + Str expected = S("abc"); + t_assert(Str_equals(str, expected)); + t_assert_equal(Arena_get_used(perm), 283); - return 0; + return 0; } int test_json_string() { - Arena perm = Arena_new(128e3); + Arena perm = Arena_new(128e3); - JSON js = JSON_parse(&perm, "\"abc\""); + JSON js = JSON_parse(&perm, "\"abc\""); - t_assert_equal(Arena_get_used(perm), 51); - t_assert(Str_equals(*js.string, S("abc"))); - t_assert_equal(Arena_get_used(perm), 51); + t_assert_equal(Arena_get_used(perm), 51); + t_assert(Str_equals(*js.string, S("abc"))); + t_assert_equal(Arena_get_used(perm), 51); - return 0; + return 0; } int test_json_empty_object() { @@ -84,8 +84,8 @@ int test_json_object() { t_assert_equal(Arena_get_used(perm), 293); t_assert_equal(doc.object->len, 1); t_assert(Str_equals(*Vec_get(&doc.object->keys, Str, 0), S("key"))); - t_assert(Str_equals(*JSONObject_get(doc.object, S("key"))->string, S("value"))) - t_assert_equal(Arena_get_used(perm), 293); + t_assert(Str_equals(*JSONObject_get(doc.object, S("key"))->string, + S("value"))) t_assert_equal(Arena_get_used(perm), 293); return 0; } diff --git a/test_string.c b/test_string.c index 59da739..ff55e67 100644 --- a/test_string.c +++ b/test_string.c @@ -2,18 +2,18 @@ #include "testing.h" int test_string_literal_equality() { - t_assert(Str_equals(S("Bonjour"), S("Bonjour"))); - return 0; + t_assert(Str_equals(S("Bonjour"), S("Bonjour"))); + return 0; } int test_string_copy() { - Arena perm = Arena_new(128e3); - Str src = S("Hello"); + Arena perm = Arena_new(128e3); + Str src = S("Hello"); - Str *cpy = Str_copy(&perm, src.data, src.len); + Str *cpy = Str_copy(&perm, src.data, src.len); - t_assert(Str_equals(src, *cpy)); - t_assert_equal(Arena_get_used(perm), 21); + t_assert(Str_equals(src, *cpy)); + t_assert_equal(Arena_get_used(perm), 21); - return 0; + return 0; } @@ -1,13 +1,16 @@ #include <stdio.h> #define t_assert(fact) \ - if (!(fact)) { \ - fprintf(stderr, "Assertion failed: %s at %s:%d in %s()\n", #fact, __FILE__, __LINE__, __func__); \ - return 1; \ - } + if (!(fact)) { \ + fprintf(stderr, "Assertion failed: %s at %s:%d in %s()\n", #fact, \ + __FILE__, __LINE__, __func__); \ + return 1; \ + } - # define t_assert_equal(a, b) \ - if (!(a == b)) { \ - fprintf(stderr, "Assertion failed: %d (%s) != %d (%s) at %s:%d in %s()\n", a, #a, b, #b, __FILE__, __LINE__, __func__); \ - return 1; \ - } +#define t_assert_equal(a, b) \ + if (!(a == b)) { \ + fprintf(stderr, \ + "Assertion failed: %d (%s) != %d (%s) at %s:%d in %s()\n", a, \ + #a, b, #b, __FILE__, __LINE__, __func__); \ + return 1; \ + } @@ -4,3 +4,7 @@ typedef ptrdiff_t size; typedef char byte; typedef uintptr_t uptr; + +#define sizeof(x) (size)sizeof(x) +#define countof(a) (sizeof(a) / sizeof(*(a))) +#define lengthof(s) (countof(s) - 1) @@ -1,24 +1,24 @@ #include <string.h> #include "assert.h" -#include "vec.h" #include "types.h" +#include "vec.h" Vec _Vec_new(Arena *a, size tsize, size cap, int align) { - assert(cap > 0); - Vec v = {.size = tsize, .cap = cap, .len = 0, .align = align,.data = NULL}; - v.data = alloc(a, cap, tsize, align); - return v; + assert(cap > 0); + Vec v = {.size = tsize, .cap = cap, .len = 0, .align = align, .data = 0}; + v.data = alloc(a, cap, tsize, align); + return v; } void Vec_push(Arena *a, Vec *v, void *data) { - if (v->len == v->cap) { - void *cpy = alloc(a, v->cap * 2, v->size, v->align); - memcpy(cpy, v->data, v->len * v->size); - v->cap *= 2; - } - memcpy(v->data + v->len * v->size, data, v->size); - v->len++; + if (v->len == v->cap) { + void *cpy = alloc(a, v->cap * 2, v->size, v->align); + memcpy(cpy, v->data, v->len * v->size); + v->cap *= 2; + } + memcpy(v->data + v->len * v->size, data, v->size); + v->len++; } void *_Vec_get(Vec *v, int pos) { return v->data + v->size * pos; } @@ -7,11 +7,11 @@ #ifndef VEC_H #define VEC_H typedef struct { - void *data; - size len; - size cap; - size size; - int align; + void *data; + size len; + size cap; + size size; + int align; } Vec; #define Vec_new(a, T, cap) _Vec_new(a, sizeof(T), cap, _Alignof(T)) Vec _Vec_new(Arena *a, size tsize, size cap, int align); |
