#ifndef SLIBS_H #define SLIBS_H #include #include #include #include #include #pragma region Memory typedef struct sl_metadata { uint8_t magic; uint32_t size; } sl_metadata; #define MD_SZ sizeof(sl_metadata) #define MD_MAGIC 0xDE typedef void *sl_mem; void *sl_get_memory(sl_metadata *m); sl_metadata *sl_get_metadata(sl_mem ptr); void *sl_malloc(uint32_t size); void *sl_realloc(sl_mem ptr, uint32_t size); sl_mem __sl_serialize_struct(void *struc, size_t size); #define sl_serialize_struct(struc) __sl_serialize_struct((void *)&struc, sizeof(struc)) #ifdef SL_IMPLEMENTATION sl_mem sl_get_memory(sl_metadata *md) { return (sl_mem)((uintptr_t)md + MD_SZ); } sl_metadata *sl_get_metadata(sl_mem ptr) { sl_metadata *md = (sl_metadata *)((uintptr_t)ptr - MD_SZ); assert(md->magic == MD_MAGIC && "Metadata magic does not match."); return md; } sl_mem sl_malloc(uint32_t size) { sl_metadata *md = (sl_metadata *)malloc(size + MD_SZ); md->magic = MD_MAGIC; md->size = size; return sl_get_memory(md); } void *sl_realloc(sl_mem ptr, uint32_t size) { sl_metadata *md = (sl_metadata *)realloc(sl_get_metadata(ptr), size); md->size = size; return sl_get_memory(md); } sl_mem __sl_serialize_struct(sl_mem struc, size_t size) { sl_mem mem = NULL; size_t offset = 0; for (int i = 0; i < size / sizeof(uintptr_t); i++) { sl_mem ptr = *(sl_mem *)(struc + i * sizeof(void *)); sl_metadata *md = sl_get_metadata(ptr); size_t full_size = md->size + MD_SZ; if (mem == NULL) { mem = sl_malloc(full_size); } else { sl_metadata *mem_md = sl_get_metadata(mem); mem = sl_realloc(mem, mem_md->size + full_size); } memcpy(mem + offset, md, MD_SZ); offset += MD_SZ; memcpy(mem + offset, ptr, md->size); offset += md->size; } return mem; } #endif #pragma endregion #pragma region Miscellaneous #define sl_auto(name, x) typeof(x) name = x #define sl_new(type, ...) \ ({ \ type *ptr = sl_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 #pragma endregion #pragma region 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; \ if ((vec).data == NULL) \ ptr = sl_malloc((vec).capacity * sizeof(*(vec).data)); \ else \ ptr = sl_realloc((vec).data, (vec).capacity * sizeof(*(vec).data)); \ assert(ptr != NULL); \ (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_shift(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_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) #pragma endregion #pragma region 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 *)sl_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) #define sl_c_str(str) \ ({ \ sl_vec_push((str), '\0'); \ (str).size--; \ (str).data; \ }) #pragma endregion #pragma region 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); \ }); void sl_read_file(const char *filename, sl_string *buffer); void sl_write_file(const char *filename, const sl_string *buffer); void sl_write_bytes(const char *filename, const uint8_t *data, size_t length); uint8_t *sl_read_bytes(const char *filename, size_t *length); void sl_write_metadata(const char *filename, sl_metadata *m); void sl_write_memory(const char *filename, void *ptr); #ifdef SL_IMPLEMENTATION void sl_read_file(const char *filename, sl_string *buffer) { FILE *file = fopen(filename, "r"); if (!file) { fprintf(stderr, "Error: could not open file %s\n", filename); exit(1); } fseek(file, 0, SEEK_END); size_t file_size = ftell(file); fseek(file, 0, SEEK_SET); for (size_t i = 0; i < file_size; i++) { sl_vec_push(*buffer, fgetc(file)); } fclose(file); } void sl_write_file(const char *filename, const sl_string *buffer) { FILE *file = fopen(filename, "w"); if (!file) { fprintf(stderr, "Error: could not open file %s\n", filename); exit(1); } for (size_t i = 0; i < buffer->size; i++) { fputc(buffer->data[i], file); } fclose(file); } void sl_write_bytes(const char *filename, const uint8_t *data, size_t length) { FILE *file = fopen(filename, "wb"); if (!file) { fprintf(stderr, "Error: could not open file %s\n", filename); exit(1); } size_t written = fwrite(data, sizeof(uint8_t), length, file); if (written != length) { fprintf(stderr, "Error: could not write all data to file %s\n", filename); fclose(file); exit(1); } fclose(file); } uint8_t *sl_read_bytes(const char *filename, size_t *length) { FILE *file = fopen(filename, "rb"); if (!file) { fprintf(stderr, "Error: could not open file %s\n", filename); exit(1); } fseek(file, 0, SEEK_END); size_t file_size = ftell(file); fseek(file, 0, SEEK_SET); uint8_t *data = (uint8_t *)sl_malloc(file_size); if (!data) { fprintf(stderr, "Error: could not allocate memory\n"); fclose(file); exit(1); } size_t read = fread(data, sizeof(uint8_t), file_size, file); if (read != file_size) { fprintf(stderr, "Error: could not read all data from file %s\n", filename); free(data); fclose(file); exit(1); } fclose(file); if (length != NULL) *length = file_size; return data; } void sl_write_metadata(const char *filename, sl_metadata *m) { sl_write_bytes(filename, sl_get_memory(m), m->size); } void sl_write_memory(const char *filename, void *ptr) { sl_write_metadata(filename, sl_get_metadata(ptr)); } #endif #pragma endregion #endif // SLIBS_H