2023-09-25 20:14:42 +13:00
|
|
|
#ifndef SLIBS_H
|
|
|
|
#define SLIBS_H
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#pragma region 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")
|
|
|
|
|
2023-09-27 19:42:18 +13:00
|
|
|
#define sl_stringify(x) #x
|
|
|
|
|
2024-07-09 22:00:50 +12:00
|
|
|
#pragma endregion
|
|
|
|
#pragma region Memory
|
|
|
|
|
2024-07-09 21:59:35 +12:00
|
|
|
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
|
|
|
|
|
2023-09-25 20:14:42 +13:00
|
|
|
#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 = 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_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 *)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); \
|
|
|
|
});
|
|
|
|
|
2024-07-09 21:59:35 +12:00
|
|
|
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
|
2023-09-27 19:42:18 +13:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-07-09 21:59:35 +12:00
|
|
|
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 *)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
|
|
|
|
|
2023-09-25 20:14:42 +13:00
|
|
|
#pragma endregion
|
|
|
|
|
2023-11-11 13:02:55 +13:00
|
|
|
#endif // SLIBS_H
|