From 034d197e7eb3749f9f5b347595abdcfe2d086965 Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Wed, 23 Jul 2025 14:42:48 +0200 Subject: fix(json): Reduce memory usage and fix memory bugs --- README.md | 2 + json.c | 279 ++++++++++++++++++++++++++++++---------------------------- json.h | 27 ++++-- string.c | 12 +-- string.h | 2 +- test_json.c | 99 ++++++++++----------- test_string.c | 6 +- test_vec.c | 12 +-- vec.c | 17 ++-- vec.h | 4 +- 10 files changed, 244 insertions(+), 216 deletions(-) diff --git a/README.md b/README.md index b8b1035..7083968 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ - Static functions for private? - JSON: tagged union for memory, remove pointer and use bitflag - `valgrind --leak-check=full ./your_program` +- assert with error msg? +- negative numbers ## Resources diff --git a/json.c b/json.c index cf78baa..e189032 100644 --- a/json.c +++ b/json.c @@ -14,77 +14,121 @@ JSONObject *JSONObject_new(Arena *a) { JSONObject *object = new(a, JSONObject, 1); object->len = 0; - object->keys = *Vec_new(a, Str, 2); - object->values = *Vec_new(a, JSON, 2); + object->keys = Vec_new(a, Str, 2); + object->values = Vec_new(a, JSON, 2); return object; } +JSON JSON_integer(i32 value) { + JSON json = {0}; + json.type = JSON_INTEGER; + json.as.integer = value; + return json; +} + +JSON JSON_float(f32 value) { + JSON json = {0}; + json.type = JSON_FLOAT; + json.as.floating = value; + return json; +} + +JSON JSON_array(Vec items) { + JSON json = {0}; + json.type = JSON_ARRAY; + json.as.array = items; + return json; +} + +JSON JSON_string(Str value) { + JSON json = {0}; + json.type = JSON_STRING; + json.as.string = value; + return json; +} + +JSON JSON_object(size len, Vec keys, Vec values) { + assert(len == keys.len && len == values.len); + JSON json = {0}; + json.type = JSON_OBJECT; + json.as.object.len = len; + json.as.object.keys = keys; + json.as.object.values = values; + return json; +} + +JSON JSON_boolean(bool value) { + JSON json = {0}; + json.type = JSON_BOOL; + json.as.boolean = value; + return json; +} + +JSON JSON_null() { + JSON json = {0}; + json.type = JSON_NULL; + return json; +} + i32 JSON_fprint(FILE *w, JSON json) { - if (json.string != 0) { + switch (json.type) { + case JSON_STRING: fprintf(w, "\""); - Str_fprint(w, *json.string); + Str_fprint(w, json.as.string); return fprintf(w, "\""); - } - if (json.integer != 0) - return fprintf(w, "%d", *json.integer); - if (json.floating != 0) - return fprintf(w, "%f", *json.floating); - if (json.boolean != 0) - return fprintf(w, "%s", *json.boolean ? "true" : "false"); - if (json.object != 0) { + case JSON_INTEGER: + return fprintf(w, "%d", json.as.integer); + case JSON_FLOAT: + return fprintf(w, "%f", json.as.floating); + case JSON_NULL: + return fprintf(w, "null"); + case JSON_BOOL: + return fprintf(w, "%s", json.as.boolean ? "true" : "false"); + case JSON_ARRAY: + fprintf(w, "["); + for (size i = 0; i < json.as.array.len; i++) { + JSON value = *Vec_get(json.as.array, JSON, i); + JSON_fprint(w, value); + if (i < json.as.array.len - 1) + fprintf(w, ", "); + } + fprintf(w, "]"); + return 0; + case JSON_OBJECT: fprintf(w, "{"); - for (size i = 0; i < json.object->len; i++) { - Str key = *Vec_get(&json.object->keys, Str, i); + for (size i = 0; i < json.as.object.len; i++) { + Str key = *Vec_get(json.as.object.keys, Str, i); fprintf(w, "\""); Str_fprint(w, key); fprintf(w, "\": "); - JSON value = *Vec_get(&json.object->values, JSON, i); + JSON value = *Vec_get(json.as.object.values, JSON, i); JSON_fprint(w, value); - if (i < json.object->len - 1) + if (i < json.as.object.len - 1) fprintf(w, ", "); } fprintf(w, "}"); return 0; } - if (json.array != 0) { - fprintf(w, "["); - for (size i = 0; i < json.array->len; i++) { - JSON value = *Vec_get(json.array, JSON, i); - JSON_fprint(w, value); - if (i < json.array->len - 1) - fprintf(w, ", "); - } - fprintf(w, "]"); - return 0; - } - return fprintf(w, "null"); + assert(false); } typedef struct { - JSON *value; + JSON value; uptr pos; -} parse_any_result; -parse_any_result parse_any(Arena *a, byte *src, uptr pos); +} parse_result; -typedef struct { - i32 *integer; - f32 *floating; - uptr pos; -} parse_number_result; +parse_result parse_any(Arena *a, byte *src, uptr pos); -parse_number_result parse_number(Arena *a, byte *src, uptr start_pos) { - parse_number_result result = {0}; +parse_result parse_number(byte *src, uptr start_pos) { + parse_result result = {0}; result.pos = start_pos; - result.floating = 0; - result.integer = 0; i32 integer = 0; while (isdigit(src[result.pos])) { integer = integer * 10 + (src[result.pos] - '0'); result.pos++; } if (src[result.pos] != '.') { - result.integer = new(a, int, 1); - *result.integer = integer; + result.value = JSON_integer(integer); return result; } result.pos++; @@ -95,8 +139,7 @@ parse_number_result parse_number(Arena *a, byte *src, uptr start_pos) { decimal_place *= 0.1; result.pos++; } - result.floating = new(a, f32, 1); - *result.floating = (f32)integer + fractional_part; + result.value = JSON_float((f32)integer + fractional_part); return result; } @@ -108,25 +151,20 @@ uptr absorb_whitespaces(byte *src, uptr start_pos) { return pos; } -typedef struct { - Vec *items; // Vec - uptr pos; -} parse_array_result; - -parse_array_result parse_array(Arena *a, byte *src, uptr start_pos) { +parse_result parse_array(Arena *a, byte *src, uptr start_pos) { assert(src[start_pos] == '['); - parse_array_result result = {0}; + parse_result result = {0}; result.pos = start_pos + 1; - result.items = Vec_new(a, JSON, 2); if (src[result.pos] == ']') { result.pos++; return result; } + Vec items = Vec_new(a, JSON, 2); for (;;) { result.pos = absorb_whitespaces(src, result.pos); - parse_any_result any_result = parse_any(a, src, result.pos); - Vec_push(a, result.items, any_result.value); - result.pos = absorb_whitespaces(src, any_result.pos); + parse_result item_result = parse_any(a, src, result.pos); + Vec_push(a, &items, &item_result.value); + result.pos = absorb_whitespaces(src, item_result.pos); if (src[result.pos] == ',') { result.pos++; } else { @@ -135,55 +173,49 @@ parse_array_result parse_array(Arena *a, byte *src, uptr start_pos) { }; assert(src[result.pos] == ']'); result.pos++; + result.value = JSON_array(items); return result; } -typedef struct { - Str *string; - uptr pos; -} parse_string_result; - -parse_string_result parse_string(Arena *a, byte *src, uptr start_pos) { +parse_result parse_string(Arena *a, byte *src, uptr start_pos) { assert(src[start_pos] == '"'); - parse_string_result result = {0}; + parse_result result = {0}; result.pos = start_pos + 1; while (src[result.pos] != '"' && src[result.pos - 1] != '\\') { result.pos++; } assert(src[result.pos] == '"'); - result.string = - Str_copy(a, &src[start_pos + 1], result.pos - start_pos - 1); + result.value = JSON_string( + Str_copy(a, &src[start_pos + 1], result.pos - start_pos - 1)); result.pos++; return result; } -typedef struct { - JSONObject *object; - uptr pos; -} parse_object_result; - -parse_object_result parse_object(Arena *a, byte *src, uptr start_pos) { +parse_result parse_object(Arena *a, byte *src, uptr start_pos) { assert(src[start_pos] == '{'); - parse_object_result result = {0}; - result.pos = start_pos + 1; - result.object = JSONObject_new(a); - result.pos = absorb_whitespaces(src, result.pos); + parse_result result = {0}; + result.pos = absorb_whitespaces(src, start_pos + 1); + size len = 0; + Vec keys = Vec_new(a, Str, 2); + Vec values = Vec_new(a, JSON, 2); if (src[result.pos] == '}') { result.pos++; + result.value = JSON_object(len, keys, values); return result; } for (;;) { assert(src[result.pos] == '"'); - parse_string_result key_result = parse_string(a, src, result.pos); + parse_result key_result = parse_string(a, src, result.pos); result.pos = absorb_whitespaces(src, key_result.pos); assert(src[result.pos] == ':'); result.pos = absorb_whitespaces(src, result.pos + 1); - parse_any_result value_result = parse_any(a, src, result.pos); - result.object->len++; - Vec_push(a, &result.object->keys, key_result.string); - Vec_push(a, &result.object->values, value_result.value); + parse_result value_result = parse_any(a, src, result.pos); + len++; + assert(key_result.value.type == JSON_STRING); + Vec_push(a, &keys, &key_result.value.as.string); + Vec_push(a, &values, &value_result.value); result.pos = absorb_whitespaces(src, value_result.pos); if (src[result.pos] != ',') { break; @@ -192,67 +224,48 @@ parse_object_result parse_object(Arena *a, byte *src, uptr start_pos) { } assert(src[result.pos] == '}'); result.pos++; + result.value = JSON_object(len, keys, values); return result; } -parse_any_result parse_any(Arena *a, byte *src, uptr start_pos) { - parse_any_result result = {0}; - result.pos = start_pos; - result.value = new(a, JSON, 1); - if (isdigit(src[result.pos])) { - parse_number_result number_result = parse_number(a, src, result.pos); - if (number_result.integer != 0) - result.value->integer = number_result.integer; - else if (number_result.floating != 0) - result.value->floating = number_result.floating; - result.pos = number_result.pos; - } else if (src[result.pos] == '[') { - parse_array_result array_result = parse_array(a, src, result.pos); - result.value->array = array_result.items; - result.pos = array_result.pos; - } else if (src[result.pos] == '"') { - parse_string_result string_result = parse_string(a, src, result.pos); - result.value->string = string_result.string; - result.pos = string_result.pos; - } else if (src[result.pos] == '{') { - parse_object_result object_result = parse_object(a, src, result.pos); - result.value->object = object_result.object; - result.pos = object_result.pos; - } else if (memcmp(src + result.pos, "true", 4) == 0) { - result.value->boolean = new(a, i32, 1); - *result.value->boolean = 1; - result.pos = start_pos + 4; - } else if (memcmp(src + result.pos, "false", 5) == 0) { - result.value->boolean = new(a, i32, 1); - *result.value->boolean = 0; - result.pos = start_pos + 5; - } else if (memcmp(src + result.pos, "null", 4) == 0) { - result.value->null = new(a, i32, 1); - result.pos = start_pos + 4; - } else { - assert(false); +parse_result parse_any(Arena *a, byte *src, uptr pos) { + pos = absorb_whitespaces(src, pos); + if (isdigit(src[pos])) + return parse_number(src, pos); + if (src[pos] == '[') + return parse_array(a, src, pos); + if (src[pos] == '"') + return parse_string(a, src, pos); + if (src[pos] == '{') + return parse_object(a, src, pos); + if (memcmp(src + pos, "true", 4) == 0) { + parse_result result = {0}; + result.value = JSON_boolean(true); + result.pos = pos + 4; + return result; } - - return result; -} - -JSON JSON_parse(Arena *a, byte *src) { - parse_any_result result = parse_any(a, src, 0); - return *result.value; + if (memcmp(src + pos, "false", 5) == 0) { + parse_result result = {0}; + result.value = JSON_boolean(false); + result.pos = pos + 5; + return result; + } + if (memcmp(src + pos, "null", 4) == 0) { + parse_result result = {0}; + result.value = JSON_null(); + result.pos = pos + 4; + return result; + } + assert(false); } -JSON JSON_Int(Arena *a, i32 val) { - JSON json = {0}; - json.integer = new(a, i32, 1); - *json.integer = val; - return json; -} +JSON JSON_parse(Arena *a, byte *src) { return parse_any(a, src, 0).value; } -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); +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 0; + assert(false); } diff --git a/json.h b/json.h index 99e3e75..60e853c 100644 --- a/json.h +++ b/json.h @@ -9,16 +9,27 @@ typedef struct { Vec values; // Vec size len; } JSONObject; +typedef enum { + JSON_NULL, + JSON_BOOL, + JSON_INTEGER, + JSON_FLOAT, + JSON_STRING, + JSON_ARRAY, + JSON_OBJECT +} JSONType; typedef struct { - i32 *boolean; - i32 *integer; - f32 *floating; - Vec *array; // Vec - Str *string; - void *null; - JSONObject *object; + JSONType type; + union { + bool boolean; + i32 integer; + f32 floating; + Vec array; // Vec + Str string; + JSONObject object; + } as; } JSON; -JSON *JSONObject_get(JSONObject *obj, Str key); +JSON *JSONObject_get(JSONObject obj, Str key); i32 JSON_fprint(FILE *w, JSON json); JSON JSON_parse(Arena *a, byte *src); JSON JSON_Int(Arena *a, i32 val); diff --git a/string.c b/string.c index 2c4e749..0d6fa7c 100644 --- a/string.c +++ b/string.c @@ -20,12 +20,12 @@ u64 Str_hash64(Str s) { 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); +Str Str_copy(Arena *a, byte *data, size len) { + Str str = {0}; + str.len = len; + str.data = new(a, byte, len); + if (str.len) + memcpy(str.data, data, len); return str; } diff --git a/string.h b/string.h index aed7945..a4c1e1a 100644 --- a/string.h +++ b/string.h @@ -15,6 +15,6 @@ typedef struct { } Str; i32 Str_equals(Str a, Str b); u64 Str_hash64(Str s); -Str *Str_copy(Arena *a, byte *data, size len); +Str Str_copy(Arena *a, byte *data, size len); i32 Str_fprint(FILE *w, Str s); #endif diff --git a/test_json.c b/test_json.c index 7f0d07c..7243a34 100644 --- a/test_json.c +++ b/test_json.c @@ -6,8 +6,8 @@ i32 test_json_integer() { JSON json_int = JSON_parse(&perm, "123"); - t_assert(*json_int.integer == 123); - t_assert_equal(Arena_get_used(perm), 60); + t_assert(json_int.as.integer == 123); + t_assert_equal(Arena_get_used(perm), 0); return 0; } @@ -16,20 +16,20 @@ i32 test_json_int_array() { JSON json_int_array = JSON_parse(&perm, "[1,2,3]"); - t_assert(json_int_array.integer == 0); - t_assert_equal(json_int_array.array->len, 3); + t_assert(json_int_array.type == JSON_ARRAY); + t_assert_equal(json_int_array.as.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; + for (int i = 0; i < json_int_array.as.array.len; i++) { + JSON *item = Vec_get(json_int_array.as.array, JSON, i); + ints[i] = item->as.integer; + sum += item->as.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), 624); + t_assert_equal(Arena_get_used(perm), 576); return 0; } @@ -39,8 +39,8 @@ i32 test_json_empty_array() { JSON json_empty_array = JSON_parse(&perm, "[]"); - t_assert(json_empty_array.array->len == 0); - t_assert_equal(Arena_get_used(perm), 208); + t_assert(json_empty_array.as.array.len == 0); + t_assert_equal(Arena_get_used(perm), 0); // TODO: weird return 0; } @@ -50,14 +50,14 @@ i32 test_json_nested_array() { JSON doc = JSON_parse(&perm, "[[1,\"abc\"]]"); - 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; + JSON sub_array = *Vec_get(doc.as.array, JSON, 0); + JSON val_1 = *Vec_get(sub_array.as.array, JSON, 0); + t_assert(val_1.as.integer == 1); + JSON val_2 = *Vec_get(sub_array.as.array, JSON, 1); + Str str = val_2.as.string; Str expected = S("abc"); t_assert(Str_equals(str, expected)); - t_assert_equal(Arena_get_used(perm), 555); + t_assert_equal(Arena_get_used(perm), 387); return 0; } @@ -67,8 +67,8 @@ i32 test_json_string() { JSON js = JSON_parse(&perm, "\"abc\""); - t_assert(Str_equals(*js.string, S("abc"))); - t_assert_equal(Arena_get_used(perm), 75); + t_assert(Str_equals(js.as.string, S("abc"))); + t_assert_equal(Arena_get_used(perm), 3); return 0; } @@ -78,8 +78,8 @@ i32 test_json_empty_object() { JSON doc = JSON_parse(&perm, "{}"); - t_assert_equal(doc.object->len, 0); - t_assert_equal(Arena_get_used(perm), 368); + t_assert_equal(doc.as.object.len, 0); + t_assert_equal(Arena_get_used(perm), 224); return 0; } @@ -89,11 +89,11 @@ i32 test_json_object() { JSON doc = JSON_parse(&perm, "{\"key\": \"value\"}"); - t_assert_equal(doc.object->len, 1); - t_assert(Str_equals(*Vec_get(&doc.object->keys, Str, 0), S("key"))); - JSON value = *JSONObject_get(doc.object, S("key")); - t_assert(Str_equals(*value.string, S("value"))); - t_assert_equal(Arena_get_used(perm), 469); + t_assert_equal(doc.as.object.len, 1); + t_assert(Str_equals(*Vec_get(doc.as.object.keys, Str, 0), S("key"))); + JSON value = *JSONObject_get(doc.as.object, S("key")); + t_assert(Str_equals(value.as.string, S("value"))); + t_assert_equal(Arena_get_used(perm), 232); return 0; } @@ -103,11 +103,11 @@ i32 test_json_boolean() { JSON doc = JSON_parse(&perm, "{\"a\": true, \"b\": false}"); - JSON a = *JSONObject_get(doc.object, S("a")); - t_assert(*a.boolean == 1); - JSON b = *JSONObject_get(doc.object, S("b")); - t_assert(*b.boolean == 0); - t_assert_equal(Arena_get_used(perm), 540); + JSON a = *JSONObject_get(doc.as.object, S("a")); + t_assert(a.as.boolean == true); + JSON b = *JSONObject_get(doc.as.object, S("b")); + t_assert(b.as.boolean == false); + t_assert_equal(Arena_get_used(perm), 226); return 0; } @@ -116,12 +116,12 @@ i32 test_json_float() { Arena perm = Arena_new(128e3); JSON doc = JSON_parse(&perm, "[1.2, 2.3]"); - t_assert_equal(doc.array->len, 2); - JSON first = *Vec_get(doc.array, JSON, 0); - t_assert_fequal(*first.floating, 1.2); - JSON second = *Vec_get(doc.array, JSON, 1); - t_assert_fequal(*second.floating, 2.3); - t_assert_equal(Arena_get_used(perm), 332); + t_assert_equal(doc.as.array.len, 2); + JSON first = *Vec_get(doc.as.array, JSON, 0); + t_assert_fequal(first.as.floating, 1.2); + JSON second = *Vec_get(doc.as.array, JSON, 1); + t_assert_fequal(second.as.floating, 2.3); + t_assert_equal(Arena_get_used(perm), 192); return 0; } @@ -130,10 +130,10 @@ i32 test_json_null() { Arena perm = Arena_new(128e3); JSON doc = JSON_parse(&perm, "[null]"); - t_assert_equal(doc.array->len, 1); - JSON first = *Vec_get(doc.array, JSON, 0); - t_assert(first.null != 0); - t_assert_equal(Arena_get_used(perm), 268); + t_assert_equal(doc.as.array.len, 1); + JSON first = *Vec_get(doc.as.array, JSON, 0); + t_assert(first.type == JSON_NULL); + t_assert_equal(Arena_get_used(perm), 192); return 0; } @@ -147,10 +147,11 @@ i32 test_json_multiline() { " \"target_size_mb\": 1,\n" " \"generator_version\": \"1.0\"\n" "}"); - JSON target_size_mb = *JSONObject_get(doc.object, S("target_size_mb")); - t_assert(*target_size_mb.integer == 1); - JSON generated_at = *JSONObject_get(doc.object, S("generated_at")); - t_assert(Str_equals(*generated_at.string, S("2025-07-22T10:36:30.974926"))); + JSON target_size_mb = *JSONObject_get(doc.as.object, S("target_size_mb")); + t_assert(target_size_mb.as.integer == 1); + JSON generated_at = *JSONObject_get(doc.as.object, S("generated_at")); + t_assert( + Str_equals(generated_at.as.string, S("2025-07-22T10:36:30.974926"))); return 0; } @@ -160,9 +161,9 @@ i32 test_json_nested_object() { JSON doc = JSON_parse(&perm, "{\"1\":{\"2\":{}}}"); - JSON lvl_1 = *JSONObject_get(doc.object, S("1")); - t_assert(lvl_1.object != 0); - JSON lvl_2 = *JSONObject_get(lvl_1.object, S("2")); - t_assert(lvl_2.object != 0); + JSON lvl_1 = *JSONObject_get(doc.as.object, S("1")); + t_assert(lvl_1.type == JSON_OBJECT); + JSON lvl_2 = *JSONObject_get(lvl_1.as.object, S("2")); + t_assert(lvl_2.type == JSON_OBJECT); return 0; } diff --git a/test_string.c b/test_string.c index 7b37e0d..0d6dd71 100644 --- a/test_string.c +++ b/test_string.c @@ -10,10 +10,10 @@ i32 test_string_copy() { 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), 5); return 0; } diff --git a/test_vec.c b/test_vec.c index 18cb880..180ba41 100644 --- a/test_vec.c +++ b/test_vec.c @@ -4,22 +4,22 @@ i32 test_int_vec() { Arena perm = Arena_new(128e3); - Vec *vec = Vec_new(&perm, i32, 2); + Vec vec = Vec_new(&perm, i32, 2); i32 *tmp = new(&perm, i32, 1); *tmp = 1; - Vec_push(&perm, vec, tmp); + Vec_push(&perm, &vec, tmp); *tmp = 2; - Vec_push(&perm, vec, tmp); + Vec_push(&perm, &vec, tmp); t_assert_equal(*Vec_get(vec, i32, 0), 1); t_assert_equal(*Vec_get(vec, i32, 1), 2); - t_assert_equal(vec->cap, 2); + t_assert_equal(vec.cap, 2); *tmp = 3; - Vec_push(&perm, vec, tmp); + Vec_push(&perm, &vec, tmp); t_assert_equal(*Vec_get(vec, i32, 2), 3); - t_assert_equal(vec->cap, 4); + t_assert_equal(vec.cap, 4); return 0; } diff --git a/vec.c b/vec.c index e91147e..3dfbf31 100644 --- a/vec.c +++ b/vec.c @@ -4,14 +4,14 @@ #include "types.h" #include "vec.h" -Vec *_Vec_new(Arena *a, size tsize, size cap, size align) { +Vec _Vec_new(Arena *a, size tsize, size cap, size align) { assert(cap > 0); - Vec *v = new(a, Vec, 1); - v->tsize = tsize; - v->cap = cap; - v->align = align; - v->len = 0; - v->data = alloc(a, cap, tsize, align); + Vec v = {0}; + v.tsize = tsize; + v.cap = cap; + v.align = align; + v.len = 0; + v.data = alloc(a, cap, tsize, align); return v; } @@ -20,9 +20,10 @@ void Vec_push(Arena *a, Vec *v, void *data) { void *cpy = alloc(a, v->cap * 2, v->tsize, v->align); memcpy(cpy, v->data, v->len * v->tsize); v->cap *= 2; + v->data = cpy; } memcpy(v->data + v->len * v->tsize, data, v->tsize); v->len++; } -void *_Vec_get(Vec *v, size pos) { return v->data + v->tsize * pos; } +void *_Vec_get(Vec v, size pos) { return v.data + v.tsize * pos; } diff --git a/vec.h b/vec.h index 8a9a0e8..1d1999b 100644 --- a/vec.h +++ b/vec.h @@ -14,8 +14,8 @@ typedef struct { size 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, size align); +Vec _Vec_new(Arena *a, size tsize, size cap, size align); void Vec_push(Arena *a, Vec *v, void *data); #define Vec_get(v, T, p) (T *)_Vec_get(v, p) -void *_Vec_get(Vec *v, size pos); +void *_Vec_get(Vec v, size pos); #endif -- cgit v1.3