#ifndef SLIBS_H #define SLIBS_H #include #include #include #include #include // Miscellaneous #define sl_auto(name, x) typeof(x) name = x #define sl_new(type, ...) \ ({ \ type *ptr = malloc(sizeof(type)); \ *ptr = (type){__VA_ARGS__}; \ ptr; \ }) #define sl_init(type, ...) \ (type) { __VA_ARGS__ } #define sl_array_len(arr) sizeof(arr) / sizeof(arr[0]) #define sl_fmt_spec(arg) \ _Generic((arg), \ int8_t: "%d", \ int16_t: "%d", \ int32_t: "%d", \ int64_t: "%lld", \ uint8_t: "%u", \ uint16_t: "%u", \ uint32_t: "%lu", \ uint64_t: "%llu", \ double: "%lf", \ float: "%f", \ char: "%c", \ char *: "%s", \ void *: "%p", \ default: "Unknown") #define sl_stringify(x) #x // Vector #define sl_vec(type) \ struct { \ type *data; \ size_t size; \ size_t capacity; \ } #define sl_vec_grow(vec) \ { \ (vec).capacity = (vec).capacity * 2 + 1; \ void *ptr = realloc((vec).data, (vec).capacity * sizeof(*(vec).data)); \ if (ptr) \ (vec).data = ptr; \ } #define sl_vec_push(vec, element) \ { \ if ((vec).size >= (vec).capacity) \ sl_vec_grow(vec); \ (vec).data[(vec).size++] = (element); \ } #define sl_vec_from_arr(vec, arr) \ { \ for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { \ sl_vec_push(vec, arr[i]); \ } \ } #define sl_vec_unshift(vec, element) \ { \ if ((vec).size >= (vec).capacity) \ sl_vec_grow(vec); \ memmove((vec).data + 1, (vec).data, (vec).size * sizeof(*(vec).data)); \ (vec).data[0] = (element); \ (vec).size++; \ } #define sl_vec_shift(vec) \ { \ memmove((vec).data, (vec).data + 1, (vec).size * sizeof(*(vec).data)); \ (vec).size--; \ } #define sl_vec_forward(vec) \ { (vec).data++; } #define sl_vec_backward(vec) \ { (vec).data--; } #define sl_vec_pop(vec) \ { \ if ((vec).size > 0) { \ (vec).size--; \ } \ } #define sl_vec_at(vec, index) ((vec).data[index]) #define sl_vec_size(vec) ((vec).size) #define sl_vec_capacity(vec) ((vec).capacity) #define sl_vec_free(vec) free((vec).data) #define sl_vec_begin(vec) (vec).data #define sl_vec_end(vec) ((vec).data + (vec).size) #define sl_vec_it(name, vec) \ sl_auto((name), sl_vec_begin(vec)); \ (name) != sl_vec_end(vec); \ ++(name) // TODO: Linked List // #define sl_list(name, type) \ // struct name \ // { \ // type *data; \ // struct name *next; \ // } // #define sl_list_append(list, value) \ // { \ // sl_auto(curr, list);\ // } \ // Hashmap #define SL_MAX_HASH_ENTRIES 512 int sl_hash(const char *str); #define sl_map(name, valuetype) \ typedef valuetype sl_##name##_type; \ \ typedef struct sl_##name##_entry { \ const char *key; \ sl_##name##_type value; \ } sl_##name##_entry; \ \ typedef sl_vec(sl_##name##_entry) sl_##name##_entry_vec; \ \ typedef struct sl_##name##_map { \ sl_##name##_entry_vec *entries[SL_MAX_HASH_ENTRIES]; \ } sl_##name##_map; \ \ sl_##name##_map name = {0}; #define sl_map_set(map, key_, val) \ { \ int hash = sl_hash(key_); \ sl_##map##_entry_vec *entry = map.entries[hash]; \ if (!entry) { \ entry = calloc(1, sizeof(sl_##map##_entry_vec)); \ map.entries[hash] = entry; \ } \ int found = 0; \ for (sl_vec_it(el, *entry)) { \ if (strcmp(el->key, key_) == 0) { \ el->value = val; \ found = 1; \ break; \ } \ } \ if (!found) { \ sl_##map##_entry new_entry = {key_, val}; \ sl_vec_push(*entry, new_entry) \ } \ } #define sl_map_get(map, key_) \ ({ \ sl_##map##_entry_vec *entry = map.entries[sl_hash(key_)]; \ sl_##map##_type *value = NULL; \ \ if (entry) { \ for (sl_vec_it(el, *entry)) { \ if (strcmp(el->key, key_) == 0) { \ value = &el->value; \ break; \ } \ } \ } \ \ value; \ }) #ifdef SL_IMPLEMENTATION int sl_hash(const char *str) { uint32_t seed = 0; size_t len = strlen(str); for (size_t i = 0; i < len && i < sizeof(uint32_t); i++) { seed <<= 8; seed |= str[i]; } srand(seed); return rand() % SL_MAX_HASH_ENTRIES; } #endif // String typedef sl_vec(char) sl_string; #define sl_string(c_str) \ ({ \ sl_string str = {0}; \ for (size_t i = 0; i < strlen((c_str)); i++) \ sl_vec_push(str, (c_str)[i]); \ str; \ }) #define sl_tostring(val) \ ({ \ sl_auto(len, snprintf(NULL, 0, sl_fmt_spec(val), val) + 1); \ sl_auto(buf, (char *)malloc(len)); \ snprintf(buf, len, sl_fmt_spec(val), val); \ sl_auto(str, sl_string(buf)); \ free(buf); \ str; \ }) #define sl_str_free(str) sl_vec_free(str) char *sl_c_str(sl_string str); #ifdef SL_IMPLEMENTATION char *sl_c_str(sl_string str) { sl_vec_push(str, '\0'); return str.data; } #endif void sl_append_c_str(sl_string *sl_str, const char *c_str); #ifdef SL_IMPLEMENTATION void sl_append_c_str(sl_string *sl_str, const char *c_str) { for (int i = 0; i < strlen(c_str); i++) { sl_vec_push(*sl_str, c_str[i]); } } #endif // Pointers #define sl_ptr(type) \ struct { \ type *ptr; \ int ref_count; \ } #define sl_ptr_make(raw_ptr) {raw_ptr, 1} #define sl_ptr_release(smart_ptr) \ ({ \ smart_ptr.ref_count--; \ if (smart_ptr.ref_count <= 0) { \ free(smart_ptr.ptr); \ } \ }) #define sl_ptr_get(smart_ptr, raw_ptr_name, scope) \ ({ \ assert(smart_ptr.ref_count > 0 && "Smart pointer already released!"); \ sl_auto(raw_ptr_name, smart_ptr.ptr); \ smart_ptr.ref_count++; \ scope; \ sl_ptr_release(smart_ptr); \ }); #define sl_ptr_scope(smart_ptr, scope) \ ({ \ scope; \ sl_ptr_release(smart_ptr); \ }); FILE *sl_open_file(const char *filename, const char *mode); sl_string *sl_read_file(const char *filename); void sl_write_file(const char *filename, const sl_string buffer); #ifdef SL_IMPLEMENTATION FILE *sl_open_file(const char *filename, const char *mode) { FILE *file = fopen(filename, mode); return file; } sl_string *sl_read_file(const char *filename) { FILE *file = sl_open_file(filename, "r"); if (!file) return NULL; fseek(file, 0, SEEK_END); size_t file_size = ftell(file); fseek(file, 0, SEEK_SET); sl_string *buffer = sl_new(sl_string, 0); for (size_t i = 0; i < file_size; i++) { sl_vec_push(*buffer, fgetc(file)); } fclose(file); return buffer; } void sl_write_file(const char *filename, sl_string buffer) { FILE *file = sl_open_file(filename, "w"); if (!file) return; fputs(sl_c_str(buffer), file); fclose(file); } #endif #endif // SLIBS_H