#define panicf(...) base_panicf(__FILE__, __LINE__, __VA_ARGS__) #define len(x) (sizeof((x))/sizeof((x)[0])) #define ilen(x) ((int)len(x)) _Noreturn void base_panicf(char *file, int line, const char *fmt, ...) { fprintf(stderr, "%s:%d: ", file, line); va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n"); fflush(stderr); fflush(stdout); exit(1); } #define Vec(T) struct { T *data; int len; int cap; } typedef Vec(void) VecVoid; #define vec_push(arr, elem) \ (vec_grow((VecVoid *)(arr), sizeof((arr)->data[0]), 1), (arr)->data[(arr)->len++] = (elem)) #define vec_insert(arr, idx, elem) do { \ assert((idx) >= 0 && (idx) <= (arr)->len); \ vec_grow((VecVoid *)(arr), sizeof((arr)->data[0]), 1); \ memmove(&(arr)->data[(idx) + 1], &(arr)->data[(idx)], sizeof((arr)->data[0]) * ((arr)->len - (idx))); \ (arr)->data[(idx)] = (elem); \ (arr)->len += 1; \ } while (0) #define vec_pop(arr) \ (assert((arr)->len > 0), (arr)->data[--(arr)->len]) #define vec_del(arr, idx) do { \ assert((idx) >= 0 && (idx) < (arr)->len); \ memmove(&(arr)->data[(idx)], &(arr)->data[(idx) + 1], sizeof((arr)->data[0]) * ((arr)->len - (idx) - 1)); \ (arr)->len -= 1; \ } while (0) #define vec_swap_del(arr, idx) do { \ assert((idx) >= 0 && (idx) < (arr)->len); \ (arr)->data[(idx)] = (arr)->data[(arr)->len - 1]; \ (arr)->len -= 1; \ } while (0) #define vec_free(arr) do { \ free((arr)->data); \ (arr)->data = NULL; \ (arr)->len = 0; \ (arr)->cap = 0; \ } while (0) void vec_grow(VecVoid *array, int elem_size, int add_len) { if (array->len + add_len > array->cap) { int cap = array->cap ? array->cap : 15; int new_cap = (cap + add_len) * 2; assert(new_cap > array->len + add_len); array->data = realloc(array->data, elem_size * new_cap); assert(array->data); array->cap = new_cap; } } void vec_test(void) { Vec(int) int_vec = {0}; assert(int_vec.data == NULL); assert(int_vec.len == 0); assert(int_vec.cap == 0); for (int i = 0; i < 32; i += 1) { vec_push(&int_vec, i * 3); assert(int_vec.len == i + 1); assert(int_vec.cap >= int_vec.len); assert(int_vec.data[int_vec.len - 1] == i * 3); } for (int i = 0; i < 32; i += 1) { assert(int_vec.data[i] == i * 3); } int cap_after_ints = int_vec.cap; vec_push(&int_vec, 12345); assert(int_vec.len == 33); assert(int_vec.data[32] == 12345); assert(int_vec.cap >= cap_after_ints); vec_insert(&int_vec, 0, 111); assert(int_vec.len == 34); assert(int_vec.data[0] == 111); assert(int_vec.data[1] == 0); vec_insert(&int_vec, 5, 222); assert(int_vec.len == 35); assert(int_vec.data[5] == 222); assert(int_vec.data[6] == 12); vec_insert(&int_vec, int_vec.len, 333); assert(int_vec.len == 36); assert(int_vec.data[int_vec.len - 1] == 333); int popped = vec_pop(&int_vec); assert(popped == 333); assert(int_vec.len == 35); vec_del(&int_vec, 5); assert(int_vec.len == 34); assert(int_vec.data[5] == 12); int before_swap_del = int_vec.data[int_vec.len - 1]; vec_swap_del(&int_vec, 1); assert(int_vec.len == 33); assert(int_vec.data[1] == before_swap_del); vec_free(&int_vec); assert(int_vec.data == NULL); assert(int_vec.len == 0); assert(int_vec.cap == 0); Vec(char *) str_vec = {0}; vec_push(&str_vec, "a"); vec_push(&str_vec, "bb"); vec_push(&str_vec, "ccc"); assert(str_vec.len == 3); assert(strcmp(str_vec.data[0], "a") == 0); assert(strcmp(str_vec.data[1], "bb") == 0); assert(strcmp(str_vec.data[2], "ccc") == 0); vec_insert(&str_vec, 1, "inserted"); assert(str_vec.len == 4); assert(strcmp(str_vec.data[1], "inserted") == 0); assert(strcmp(str_vec.data[2], "bb") == 0); assert(strcmp(vec_pop(&str_vec), "ccc") == 0); assert(str_vec.len == 3); vec_del(&str_vec, 1); assert(str_vec.len == 2); assert(strcmp(str_vec.data[0], "a") == 0); assert(strcmp(str_vec.data[1], "bb") == 0); vec_swap_del(&str_vec, 0); assert(str_vec.len == 1); assert(strcmp(str_vec.data[0], "bb") == 0); vec_free(&str_vec); assert(str_vec.data == NULL); assert(str_vec.len == 0); assert(str_vec.cap == 0); printf("vector tests passed\n"); }