diff --git a/include/macros.h b/include/macros.h index 309c068..553235f 100644 --- a/include/macros.h +++ b/include/macros.h @@ -44,6 +44,25 @@ #define restrict __restrict__ #endif +// Function conventions + +#define _cconv__mixin _mixin +#define _cconv__pure _pure +#define _cconv__readonly _readonly +#define _cconv__cold _cold +#define _cconv__dead _dead +#define _cconv__unused _dead +#define _cconv__hot _hot +#define _cconv__entry __attribute__((constructor)) +#define _cconv__exit __attribute__((destructor)) +#define _cconv__alloc __attribute__((malloc)) +#define _callcv(name) _cconv__ ## name +#define _callconv(name) _callcv(name) + +#define _callat_entry _callcv(entry) +#define _callat_exit _callcv(exit) +#define _callat(when) _callat_ ## when + // Argument attribute // Used like: `int *pOUT output, const int *pIN input` @@ -110,6 +129,7 @@ _mixin void _drain_val(void* x, ...) { IGNORE(x); } // This compiles to no-op on // Allocation macros #define box(t) aligned_alloc(_Alignof(t), sizeof(t)) +#define box_value(v) ({ let _box = box(var(v)); *_box = (v); _box; }) #define stackalloc(t) __builtin_alloca_with_align(sizeof(t), _Alignof(t)) // Function macros diff --git a/include/str.h b/include/str.h new file mode 100644 index 0000000..e6d2e47 --- /dev/null +++ b/include/str.h @@ -0,0 +1,45 @@ +//! Better string handling +#ifndef _STR_H +#define _STR_H + +#include +#include + +#define STRF_OWNED AS(1ul << 5, int) +#define STRF_DERRIVED AS(1ul << 6, int) +enum str_ownership { + STR_NULL = 0, + + STR_OWNED = STRF_OWNED, + STR_OWNED_STATIC, + STR_OWNED_MALLOC, + STR_OWNED_STACK, + + STR_DERRIVED = STRF_DERRIVED, + STR_DERRIVED_STATIC, + STR_DERRIVED_MALLOC, + STR_DERRIVED_STACK, +}; + +//TODO: Complete rework +typedef struct string { + usize len, cap; + struct str_meta { + struct string* _shared derrived; + _Atomic usize refs; + void (*m_free)(void*); + + enum str_ownership owned; + } meta; + union { + char* slice; + char str[]; + }; +} *str_t; + +str_t* str_alloc(usize cap) _cconv(alloc); +char* str_new(const char* pIN cstr) _cconv(alloc); + +void str_free(str_t* restrict str); + +#endif /* _STR_H */ diff --git a/src/str.c b/src/str.c new file mode 100644 index 0000000..bdf160d --- /dev/null +++ b/src/str.c @@ -0,0 +1,66 @@ + +#include +#include +#include + +#include + +static str_t _str_alloc_new(usize reserve) +{ + return aligned_alloc(_Alignof(struct string), sizeof(struct string) + reserve + 1); +} + +inline static str_t _str_unbox(str_t* restrict boxed) +{ + str_t unboxed = *boxed; + free(boxed); + return unboxed; +} + +_cconv(alloc) str_t* str_alloc(usize cap) +{ + str_t unboxed = _str_alloc_new(cap); + unboxed->cap = cap; + unboxed->len = 0; + unboxed->meta = (struct str_meta){ + .derrived = NULL, + .refs = 0, + .m_free = &free, + .owned = STR_OWNED_MALLOC, + }; + memset(unboxed->str, 0, cap+1); + + return box_value(unboxed); +} + +void str_free(str_t* restrict str) +{ + str_t ub = _str_unbox(str); + + void* to_free = (void*)ub; + let _cont[] = { &&_done, &&_finish_free_derrived }; + usize cont = 0; + switch(ub->meta.owned) { + case STR_DERRIVED_MALLOC: + ub->meta.derrived->meta.refs -=1; + to_free = NULL; + cont = 1; + case STR_OWNED_MALLOC: + //TODO: How to handle this refcounting? + if(ub->meta.refs > 0) WARN("Freeing referenced string"); + //if(ub->meta.refs == 0) + if(to_free) + (ub->meta.m_free ?: &free)(to_free); + /*else { + ub->meta.refs -=1; + break; + }*/ + goto _cont[cont]; + _finish_free_derrived: + free(ub); + default: + _done: + break; + } + +}