aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2025-07-21 17:06:53 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2025-07-21 17:09:42 +0200
commit0be32393e54bed6bbf5890edba72b8808d276289 (patch)
treeba83502753e64f0c60f5202a8d224b57b52cf14f
parent85b0db24804e6a8a66f557ac8917596db5fc5d9f (diff)
format
-rw-r--r--.clang-format3
-rw-r--r--Makefile3
-rw-r--r--README.md8
-rw-r--r--base_test.c20
-rw-r--r--json.c168
-rw-r--r--json.h12
-rw-r--r--log.c10
-rw-r--r--log.h2
-rw-r--r--main.c6
-rw-r--r--memory.c20
-rw-r--r--memory.h6
-rw-r--r--string.c32
-rw-r--r--string.h6
-rw-r--r--test_json.c84
-rw-r--r--test_string.c16
-rw-r--r--testing.h21
-rw-r--r--types.h4
-rw-r--r--vec.c24
-rw-r--r--vec.h10
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
diff --git a/Makefile b/Makefile
index 2ded5a1..234128c 100644
--- a/Makefile
+++ b/Makefile
@@ -14,3 +14,6 @@ test:
fish generate.fish;
make debug;
./Debug/test;
+
+format:
+ clang-format -i *.c *.h
diff --git a/README.md b/README.md
index b78c3ae..bacfc0d 100644
--- a/README.md
+++ b/README.md
@@ -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;
diff --git a/json.c b/json.c
index 94dab1d..05ea3fb 100644
--- a/json.c
+++ b/json.c
@@ -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;
}
diff --git a/json.h b/json.h
index fc2dcfe..13a3f11 100644
--- a/json.h
+++ b/json.h
@@ -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
diff --git a/log.c b/log.c
index d95299d..9cff1a0 100644
--- a/log.c
+++ b/log.c
@@ -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");
+ }
}
diff --git a/log.h b/log.h
index a2744f1..1458f03 100644
--- a/log.h
+++ b/log.h
@@ -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, ...);
diff --git a/main.c b/main.c
index 3d23212..3f63be0 100644
--- a/main.c
+++ b/main.c
@@ -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; }
diff --git a/memory.c b/memory.c
index f11af57..7fa3e1d 100644
--- a/memory.c
+++ b/memory.c
@@ -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); }
diff --git a/memory.h b/memory.h
index 846a40d..b12f4f9 100644
--- a/memory.h
+++ b/memory.h
@@ -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);
diff --git a/string.c b/string.c
index 3d5841a..d174ed4 100644
--- a/string.c
+++ b/string.c
@@ -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); }
diff --git a/string.h b/string.h
index 3c05bc2..2420f91 100644
--- a/string.h
+++ b/string.h
@@ -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;
}
diff --git a/testing.h b/testing.h
index 0b479c9..3fc5df5 100644
--- a/testing.h
+++ b/testing.h
@@ -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; \
+ }
diff --git a/types.h b/types.h
index 584da21..1c84c74 100644
--- a/types.h
+++ b/types.h
@@ -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)
diff --git a/vec.c b/vec.c
index c9fe4b5..e9df934 100644
--- a/vec.c
+++ b/vec.c
@@ -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; }
diff --git a/vec.h b/vec.h
index d43fafb..a9b4f92 100644
--- a/vec.h
+++ b/vec.h
@@ -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);