#pragma once #include #include #include #include #include #include #define DECLARE_VEC(T, Name) \ typedef struct { \ T **blocks; \ size_t count; \ size_t used; \ size_t cap; \ size_t block_size; \ } Name; \ \ static inline Name make_##Name(size_t block_size) { \ return (Name){ \ .blocks = NULL, \ .count = 0, \ .used = 0, \ .cap = 0, \ .block_size = block_size, \ }; \ } \ \ static inline T *push_to_##Name(Name *vec, T item) { \ size_t block_index = vec->count / vec->block_size; \ size_t item_index = vec->count % vec->block_size; \ \ if (block_index == vec->used) { \ if (vec->used == vec->cap) { \ size_t new_cap = vec->cap \ ? vec->cap * 2 \ : 8; \ \ T **new_blocks = realloc( \ vec->blocks, \ new_cap * sizeof(T *) \ ); \ \ if (!new_blocks) abort(); \ \ vec->blocks = new_blocks; \ vec->cap = new_cap; \ } \ \ vec->blocks[vec->used] = \ malloc(vec->block_size * sizeof(T)); \ \ if (!vec->blocks[vec->used]) abort(); \ \ vec->used++; \ } \ \ T *ptr = &vec->blocks[block_index][item_index]; \ *ptr = item; \ \ vec->count++; \ return ptr; \ } \ \ static inline T* get_from_##Name(Name *vec, size_t index) { \ if (index >= vec->count) return NULL; \ \ return &vec->blocks \ [index / vec->block_size] \ [index % vec->block_size]; \ } DECLARE_VEC(int, IntVec) DECLARE_VEC(char, String); DECLARE_VEC(char*, StrVec) static void append_str_to_String(String* target, const char* src_str) { size_t len = strlen(src_str); for (size_t i = 0; i < len; i++) { push_to_String(target, src_str[i]); } } static inline char* inner(String* str) { char *out = malloc(str->count + 1); if (!out) abort(); for (size_t i = 0; i < str->count; i++) { out[i] = *get_from_String(str, i); } out[str->count] = '\0'; return out; } #define DECLARE_MAYBE(T, Name) \ typedef struct { \ bool some; \ T value; \ } Name; DECLARE_MAYBE(char*, MaybeStr) typedef struct { char* key; char* val; } StrPair; DECLARE_VEC(StrPair, KeyValMap) void set_map_pair(KeyValMap* map, char* key, char* val) { for (int i = 0; i < map->count; i++) { char* key_i = get_from_KeyValMap(map, i)->key; if (key_i == NULL) continue; if (strcmp(key_i, key) == 0) { // TODO: maybe copy instead strcpy( map->blocks[i / map->block_size][i % map->block_size].val, val ); break; } } } MaybeStr get_map_value(KeyValMap* map, char* key) { for (int i = 0; i < map->count; i++) { char* key_i = get_from_KeyValMap(map, i)->key; if (key_i == NULL) continue; if (strcmp(key_i, key) == 0) { return (MaybeStr){ .some = true, .value = get_from_KeyValMap(map, i)->val }; } } return (MaybeStr){.some = false}; } void unset_map_key(KeyValMap* map, char* key) { for (int i = 0; i < map->count; i++) { char* key_i = get_from_KeyValMap(map, i)->key; if (key_i == NULL) continue; if (strcmp(key_i, key) == 0) { map->blocks[i / map->block_size][i % map->block_size].key = NULL; break; } } }