From ac7ec87484894c040681e7d59c6b12a966a23f7b Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 14 Mar 2022 17:00:10 +0000 Subject: [PATCH] Start: string_view for C MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fortune for sink's current commit: Small curse − 小凶 --- Makefile | 2 +- view.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ view.h | 22 ++++++++++++++ 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 view.c create mode 100644 view.h diff --git a/Makefile b/Makefile index bf580dc..2e3dc7b 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ RELEASE_LDFLAGS+= -Wl,-O3 -Wl,-flto DEBUG_CFLAGS+=-Og -g3 -ggdb -gz -DDEBUG DEBUG_LDFLASG+=-Wl,-g -CFLAGS += $(COMMON_FLAGS) --std=gnu17 +CFLAGS += $(COMMON_FLAGS) --std=gnu2x LDFLAGS += ifneq ($(SHARED),yes) diff --git a/view.c b/view.c new file mode 100644 index 0000000..b96a9bf --- /dev/null +++ b/view.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +#include "view.h" + +#define S_PTR_MASK (0xcafebeef00000000ul) /* XXX: Should this frob the high or end parts of the pointer? We'll go with high? */ + +#define $mixin __attribute__((__gnu_inline__, __always_inline__, __artificial__)) inline +#define $nullchk(ptr, or) ({ __auto_type _$p = (ptr); \ + __builtin_expect(_$p == NULL, false) ? ({ or; }),NULL : _$p; }) + +typedef uint8_t byte_t; + +__attribute__((packed)) +struct string_metadata { + bool is_owned : 1; // was the string malloc()'d + bool has_nul : 1; // does this string have a nul terminator +}; + +struct string_data { + struct string_metadata meta; + + uintptr_t ptr_frob; + + + struct /*_Alignas(struct string_view)*/ { + size_t len; + char ptr[]; + } __attribute__((aligned(_Alignof(struct string_view)))); //__attribute__((align(struct string_view))); +}; + +#define _s_frob_pointer_(p, f) ((/*__typeof((p))*/void*) (((uintptr_t)(p)) ^ ((uintptr_t)(f)))) +__attribute__((const)) +$mixin static void* _s_frob_pointer(void* p) +{ + return _s_frob_pointer_(p, S_PTR_MASK); +} +#define _s_frob_pointer(p) _s_frob_pointer_((p), S_PTR_MASK) + +#define $frob(v, w) _s_frob_pointer_((v), (w)) + +static inline struct string* _s_frob(struct string_data* restrict d) { + return (struct string*) _s_frob_pointer(d->ptr); +} +static inline struct string_data* _s_unfrob(struct string *restrict ptr) { +// static const off64_t O_this = offsetof(struct string_data, ptr); + + struct string_data* restrict base = (void*)((byte_t*)_s_frob_pointer(ptr)) - offsetof(struct string_data, ptr); + + uintptr_t frob = base->ptr_frob; + if(frob != ((uintptr_t)_s_frob_pointer(base))) return NULL; //XXX: TODO: Is this valid? Probably, since struct string_data will only ever be heap-allocated. + + return base; +} + +$mixin static char* _s_str(struct string_data* restrict data) { return data->ptr; } + +$mixin extern struct string_data* _s_data(char* str, bool check) { + struct string_data* sd = (struct string_data*)( ((byte_t*)str) - offsetof(struct string_data, ptr) ); + + if(__builtin_constant_p(check) && !check) return sd; + else if(check && sd->ptr_frob != ((uintptr_t)_s_frob_pointer(sd))) return NULL; + else return sd; +} +static struct string_data* _s_data(char* str, bool check) { + static const size_t O_base = offsetof(struct string_data, ptr); + struct string_data* sd = (struct string_data*)( ((byte_t*)str) - O_base ); + + if(__builtin_constant_p(check) && !check) return sd; + else if(check && sd->ptr_frob != ((uintptr_t)_s_frob_pointer(sd))) return NULL; + else return sd; +} + +__attribute__((pure)) +str_info_t s_get_info(sv_t str) +{ + return _s_data($nullchk(str.ptr, return NULL), true); +} + +__attribute__((pure)) +sv_t s_get_str(str_info_t data) +{ + return (sv_t) { + .len = data->len, + .ptr = (unsigned char*)data->ptr, + }; +} diff --git a/view.h b/view.h new file mode 100644 index 0000000..78191c0 --- /dev/null +++ b/view.h @@ -0,0 +1,22 @@ +#ifndef _VIEW_H +#define _VIEW_H + +#include +#include + +typedef struct string_view { + size_t len; + unsigned char* ptr; +} sv_t; + +struct string_data; +typedef struct string_data* str_info_t; + +struct string; + +// Functions // + +sv_t s_get_str(str_info_t data) __attribute__((pure)); +str_info_t s_get_info(sv_t str) __attribute__((pure)); + +#endif /* _VIEW_H */