diff --git a/include/macros.h b/include/macros.h index 553235f..fde7315 100644 --- a/include/macros.h +++ b/include/macros.h @@ -130,6 +130,7 @@ _mixin void _drain_val(void* x, ...) { IGNORE(x); } // This compiles to no-op on #define box(t) aligned_alloc(_Alignof(t), sizeof(t)) #define box_value(v) ({ let _box = box(var(v)); *_box = (v); _box; }) +#define unbox_value(v) ({ let _v = (v); let _res = *_v; free(_v); _res; } #define stackalloc(t) __builtin_alloca_with_align(sizeof(t), _Alignof(t)) // Function macros diff --git a/include/str.h b/include/str.h index e6d2e47..ecd647c 100644 --- a/include/str.h +++ b/include/str.h @@ -21,24 +21,10 @@ enum str_ownership { 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); +typedef struct string str_t; + +str_t* str_alloc(usize cap) _callconv(alloc); +char* str_new(const char* pIN cstr) _callconv(alloc); void str_free(str_t* restrict str); diff --git a/src/str.c b/src/str.c index bdf160d..a85a6a4 100644 --- a/src/str.c +++ b/src/str.c @@ -5,62 +5,63 @@ #include -static str_t _str_alloc_new(usize reserve) +struct string { + usize len, cap; + struct str_meta { + enum str_ownership owned; + union _str_meta_inner { + // `STRF_OWNED` + struct { + _Atomic usize refs; // Number of derrivations from this + void (*m_free)(void*); // How to free (when `_MALLOC`). + } owned; + // `STRF_DERRIVED` + struct { + // String this is derrived from, can be either owned or derrived. + struct string* _shared parent; + // `str`'s offset from `parent->str`. + usize offset; + } derrived; + } _inner; + } meta; + // The start of this string slice. Regardless of slicing + char* str; +}; + +//TODO: We can use offsetof() to reverse the result of `str_new()` from char* (str field) to str_t*. + +inline static bool _str_meta_is_owned(enum str_ownership owned) { - return aligned_alloc(_Alignof(struct string), sizeof(struct string) + reserve + 1); + return AS(owned, u32) & AS(STRF_OWNED, u32); } -inline static str_t _str_unbox(str_t* restrict boxed) +inline static bool _str_is_owned(const str_t*pIN str) { - str_t unboxed = *boxed; - free(boxed); - return unboxed; + return _str_meta_is_owned(str->meta.owned); } -_cconv(alloc) str_t* str_alloc(usize cap) +static union _str_meta_inner _str_default_meta(enum str_ownership oship) { - 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); + bool owned = _str_meta_is_owned(oship); + switch(oship) + { + + } + TODO("default str metadata"); } -void str_free(str_t* restrict str) +static str_t _str_alloc_bare(usize cap, enum str_ownership owned) { - 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; - } - + bool is_owned = _str_meta_is_owned(owned); + struct str_meta meta = { + .owned = owned, + ._inner = _str_default_meta(owned), + }; + str_t str = { + .len = 0, + .cap = cap, + .meta = meta, + }; + str.str = is_owned ? calloc(cap+1, 1) : NULL; + return str; }