rcx

library of miscellaneous bits of C code
git clone git://git.rr3.xyz/rcx
Log | Files | Refs | README | LICENSE

commit f9c9b2e6ba52e9455fb41da4149c6eb02f74ccd2
parent 58461ad3af99902e7ef1a93c40d90ae031f9d9b5
Author: Robert Russell <robertrussell.72001@gmail.com>
Date:   Sun, 20 Aug 2023 16:40:51 -0700

Remove Buf and RcStr; reorganize Str stuff

I don't really see any use cases for Buf and RcStr. My attempts
to use Buf in the compiler didn't really work well. If we really
want them back in the future, they're in the git history.

Also, move str_slice to header so it can be inlined, and turn
it into a macro again (I changed my mind).

Diffstat:
MMakefile | 4+---
Minc/all.h | 1-
Dinc/buffer.h | 116-------------------------------------------------------------------------------
Minc/string.h | 70++++++++++++++++++----------------------------------------------------
Dsrc/buffer.c | 117-------------------------------------------------------------------------------
Msrc/string.c | 15---------------
6 files changed, 19 insertions(+), 304 deletions(-)

diff --git a/Makefile b/Makefile @@ -5,7 +5,6 @@ include config.mk SRC =\ src/alloc.c\ src/bench.c\ - src/buffer.c\ src/debug.c\ src/dict.c\ src/log.c\ @@ -26,14 +25,13 @@ librcx.a: $(SRC:.c=.o) src/alloc.o: src/alloc.c inc/alloc.h inc/def.h inc/log.h inc/rcx.h inc/internal/util.h config.mk src/bench.o: src/bench.c inc/bench.h inc/def.h inc/log.h inc/rcx.h config.mk -src/buffer.o: src/buffer.c inc/alloc.h inc/buffer.h inc/debug.h inc/def.h inc/log.h inc/rcx.h inc/string.h config.mk src/debug.o: src/debug.c inc/debug.h inc/def.h inc/rcx.h config.mk src/dict.o: src/dict.c inc/bits.h inc/debug.h inc/def.h inc/dict.h inc/dict-defaults.h inc/internal/util.h inc/log.h inc/rand.h inc/rcx.h inc/string.h config.mk src/log.o: src/log.c inc/def.h inc/log.h inc/rcx.h config.mk src/opt.o: src/opt.c inc/def.h inc/opt.h inc/rcx.h config.mk src/rand.o: src/rand.c inc/bits.h inc/def.h inc/rand.h inc/rcx.h inc/unix.h config.mk src/str.o: src/str.c inc/alloc.h inc/debug.h inc/def.h inc/log.h inc/rcx.h inc/str.h config.mk -src/string.o: src/string.c inc/alloc.h inc/buffer.h inc/debug.h inc/def.h inc/rcx.h inc/string.h inc/utf8.h config.mk +src/string.o: src/string.c inc/alloc.h inc/debug.h inc/def.h inc/rcx.h inc/string.h inc/utf8.h config.mk src/unicode.o: src/unicode.c inc/def.h inc/rcx.h gen/ucattab.inc config.mk src/unix.o: src/unix.c inc/debug.h inc/def.h inc/rcx.h inc/unix.h config.mk src/utf8.o: src/utf8.c inc/def.h inc/rcx.h inc/utf8.h config.mk diff --git a/inc/all.h b/inc/all.h @@ -2,7 +2,6 @@ #include "alloc.h" #include "bits.h" -#include "buffer.h" #include "debug.h" #include "deque.h" #include "dict.h" diff --git a/inc/buffer.h b/inc/buffer.h @@ -1,116 +0,0 @@ -#pragma once - -#include <stdalign.h> - -#include "alloc.h" -#include "debug.h" -#include "def.h" -#include "log.h" - -/* TODO: Optimization opportunity: Use headers with different cap field sizes - * to reduce waste in the common case of small strings. The flags field can be - * used to encode which header is used. It's probably only worth having - * variants for u8 and usize cap; further distinguishing u16 and u32 doesn't - * really make sense, since eventually the header size becomes negligible. - * We could also use a flag bit to disable the refcnt field. */ - -#define BUF_HEADER_SIZE (sizeof(BufHdr_)) - -typedef struct buf_hdr_ BufHdr_; -typedef u8 *Buf; - -enum buf_flags_ { - BUF_FLAG_FREE_ = 1<<0, -}; - -struct buf_hdr_ { - usize cap; - u32 refcnt; - u8 flags; - // Followed padding and then data -}; - -#define buf_hdr_const_(n) struct { \ - usize cap; \ - u32 refcnt; \ - u8 flags; \ - alignas(BufHdr_) u8 data[n]; \ - } - -#define buf_stack(s, ...) ((Buf)((BufHdr_ *)&(buf_hdr_const_( \ - VA_DEFAULT(,##__VA_ARGS__, sizeof(s) - 1))){ \ - .cap = VA_DEFAULT(,##__VA_ARGS__, sizeof(s) - 1), \ - .refcnt = 1, \ - .flags = 0, \ - .data = s /* This is an error if s is not a string literal */ \ - } + 1)) - -#define buf_static(s, ...) ((Buf)((BufHdr_ *)STATIC(buf_hdr_const_( \ - VA_DEFAULT(,##__VA_ARGS__, sizeof(s) - 1)), { \ - .cap = VA_DEFAULT(,##__VA_ARGS__, sizeof(s) - 1), \ - .refcnt = 1, \ - .flags = 0, \ - .data = s /* This is an error if s is not a string literal */ \ - }) + 1)) - -Buf buf_memory(void *mem, usize cap); - -Buf buf_alloc(usize cap); -Buf buf_allocz(usize cap); -Buf buf_ealloc(usize cap); -Buf buf_eallocz(usize cap); -int buf_realloc(Buf *b, usize cap); -int buf_reallocz(Buf *b, usize cap); -int buf_erealloc(Buf *b, usize cap); -int buf_ereallocz(Buf *b, usize cap); - -static inline usize -buf_cap(Buf b) { - return ((BufHdr_ *)b - 1)->cap; -} - -static inline u64 -buf_refcnt(Buf b) { - return ((BufHdr_ *)b - 1)->refcnt; -} - -static inline Buf -buf_ref(Buf b) { - BufHdr_ *h = (BufHdr_ *)b - 1; - if unlikely (h->refcnt == U32_MAX) { - /* XXX: This is a tough situation to be in. For now, we mark the buffer - * as nonfreeable, because surely a memory leak is better than - * spontaneously freeing the buffer. Another option would be to just - * abort the program. */ - r_errorf("buf_ref: reference count overflow"); - h->flags &= ~BUF_FLAG_FREE_; - } - h->refcnt += 1; - return b; -} - -static inline void -buf_drop(Buf b) { - BufHdr_ *h = (BufHdr_ *)b - 1; - ASSERT(h->refcnt > 0, "buf_drop: no references held"); - h->refcnt -= 1; - if (h->refcnt == 0 && (h->flags & BUF_FLAG_FREE_)) - free(h); -} - -/* XXX: circular include */ -#include "string.h" - -Str buf_slice(Buf b, usize l, usize u); - -static inline Str -buf_slice_to_end(Buf b, usize l) { - return buf_slice(b, l, buf_cap(b)); -} - -RcStr buf_slice_rc_ref(Buf b, usize l, usize u); - -static inline RcStr -buf_slice_to_end_rc_ref(Buf b, usize l) { - return buf_slice_rc_ref(b, l, buf_cap(b)); -} diff --git a/inc/string.h b/inc/string.h @@ -11,28 +11,18 @@ #define STR_FMT(s) (ASSERT(str_len(s) <= INT_MAX), (int)str_len(s)), str_bytes(s) typedef struct str Str; -typedef struct rc_str RcStr; struct str { usize len; u8 *data; }; -struct rc_str { - usize off; - usize len; - u8 *data; /* &buf->data[off] */ -}; - -/* XXX: circular include */ -#include "buffer.h" - -#define str_stack(s, ...) (Str){ \ +#define str_stack(s) (Str){ \ .len = sizeof(s) - 1, \ - .data = (u8[]){s} \ + .data = (u8[MAX(sizeof(s) - 1, 1)]){s} \ } -#define str_static(s, ...) (Str){ \ +#define str_static(s) (Str){ \ .len = sizeof(s) - 1, \ .data = (u8 *)s \ } @@ -65,49 +55,25 @@ str_utf8_decode(rune *c, Str s) { return r_utf8_decode(c, (char *)s.data, s.len); } -/* Like sprintf and vsprintf, but for Str's. The result must be freed with - * free(str_bytes(*str)). */ -int str_alloc_printf(Str *str, char *fmt, ...); -int str_alloc_vprintf(Str *str, char *fmt, va_list args); - -Str str_slice(Str s, isize l, isize u); +#define str_slice(s, l, ...) r_str_slice_((s), (l), VA_DEFAULT(,##__VA_ARGS__, str_len(s))) static inline Str -str_slice_to_end(Str s, isize l) { - return str_slice(s, l, str_len(s)); -} - -char *str_alloc_cstr(Str s); - -static inline usize -rcstr_off(RcStr s) { - return s.off; -} +r_str_slice_(Str s, isize l, isize u) { + if (l < 0) l += s.len; + ASSERT(0 <= l && l <= s.len, "str_slice: lower index out of bounds"); -static inline usize -rcstr_len(RcStr s) { - return s.len; -} - -static inline Buf -rcstr_buf(RcStr s) { - return (void *)(s.data - s.off); -} + if (u < 0) u += s.len; + ASSERT(0 <= u && u <= s.len, "str_slice: upper index out of bounds"); -static inline u8 * -rcstr_bytes(RcStr s) { - return s.data; + return (Str){ + .len = l < u ? u - l : 0, + .data = s.data + l, + }; } -static inline RcStr -rcstr_ref(RcStr s) { - buf_ref(rcstr_buf(s)); - return s; -} - -static inline void -rcstr_drop(RcStr s) { - buf_drop(rcstr_buf(s)); -} +/* Like sprintf and vsprintf, but for Str's. The result must be freed with + * free(str_bytes(*str)). */ +int str_alloc_printf(Str *str, char *fmt, ...); +int str_alloc_vprintf(Str *str, char *fmt, va_list args); -/* TODO: functions like above, but operating on RcStr's instead of Str's */ +char *str_alloc_cstr(Str s); diff --git a/src/buffer.c b/src/buffer.c @@ -1,117 +0,0 @@ -#include "alloc.h" -#include "buffer.h" -#include "debug.h" -#include "rcx.h" - -Buf -buf_memory(void *mem, usize cap) { - REQUIRE(((uptr)mem & (alignof(BufHdr_) - 1)) == 0, - "buf_memory: bad alignment"); - BufHdr_ *h = mem; - *h = (BufHdr_){cap, 1, 0}; - return (Buf)(h + 1); -} - -Buf -buf_alloc(usize cap) { - BufHdr_ *h = r_alloc(sizeof *h + cap); - if (!h) return 0; - *h = (BufHdr_){cap, 1, BUF_FLAG_FREE_}; - return (Buf)(h + 1); -} - -Buf -buf_allocz(usize cap) { - BufHdr_ *h = r_allocz(sizeof *h + cap); - if (!h) return 0; - *h = (BufHdr_){cap, 1, BUF_FLAG_FREE_}; - return (Buf)(h + 1); -} - -Buf -buf_ealloc(usize cap) { - BufHdr_ *h = r_ealloc(sizeof *h + cap); - *h = (BufHdr_){cap, 1, BUF_FLAG_FREE_}; - return (Buf)(h + 1); -} - -Buf -buf_eallocz(usize cap) { - BufHdr_ *h = r_eallocz(sizeof *h + cap); - *h = (BufHdr_){cap, 1, BUF_FLAG_FREE_}; - return (Buf)(h + 1); -} - -int -buf_realloc(Buf *b, usize cap) { - BufHdr_ *h = *b ? (BufHdr_ *)*b - 1 : 0; - if (r_realloc(&h, sizeof *h + cap) < 0) return -1; - if (!*b) *h = (BufHdr_){cap, 1, BUF_FLAG_FREE_}; - *b = (Buf)(h + 1); - return 0; -} - -int -buf_reallocz(Buf *b, usize cap) { - BufHdr_ *h = *b ? (BufHdr_ *)*b - 1 : 0; - if (r_reallocz(&h, sizeof *h + h->cap, sizeof *h + cap) < 0) return -1; - if (!*b) *h = (BufHdr_){cap, 1, BUF_FLAG_FREE_}; - *b = (Buf)(h + 1); - return 0; -} - -int -buf_erealloc(Buf *b, usize cap) { - BufHdr_ *h = *b ? (BufHdr_ *)*b - 1 : 0; - r_erealloc(&h, sizeof *h + cap); - if (!*b) *h = (BufHdr_){cap, 1, BUF_FLAG_FREE_}; - *b = (Buf)(h + 1); - return 0; -} - -int -buf_ereallocz(Buf *b, usize cap) { - BufHdr_ *h = *b ? (BufHdr_ *)*b - 1 : 0; - r_ereallocz(&h, sizeof *h + h->cap, sizeof *h + cap); - if (!*b) *h = (BufHdr_){cap, 1, BUF_FLAG_FREE_}; - *b = (Buf)(h + 1); - return 0; -} - -Str -buf_slice(Buf b, usize l, usize u) { - BufHdr_ *h = (BufHdr_ *)b - 1; - ASSERT(!(h->flags & BUF_FLAG_FREE_), "buf_slice: can not take " - "non-reference-counted slice of reference-counted Buf"); - - usize cap = buf_cap(b); - - if (l < 0) l += cap; - ASSERT(0 <= l && l <= cap, "buf_slice: lower index out of bounds"); - - if (u < 0) u += cap; - ASSERT(0 <= u && u <= cap, "buf_slice: upper index out of bounds"); - - return (Str){ - .len = l < u ? u - l : 0, - .data = b + l, - }; -} - -RcStr -buf_slice_rc_ref(Buf b, usize l, usize u) { - usize cap = buf_cap(b); - - if (l < 0) l += cap; - ASSERT(0 <= l && l <= cap, "buf_slice_rc_ref: lower index out of bounds"); - - if (u < 0) u += cap; - ASSERT(0 <= u && u <= cap, "buf_slice_rc_ref: upper index out of bounds"); - - buf_ref(b); - return (RcStr){ - .off = l, - .len = l < u ? u - l : 0, - .data = b + l, - }; -} diff --git a/src/string.c b/src/string.c @@ -2,7 +2,6 @@ #include <string.h> #include "alloc.h" -#include "debug.h" #include "rcx.h" #include "string.h" @@ -41,20 +40,6 @@ str_alloc_vprintf(Str *str, char *fmt, va_list args) { return 0; } -Str -str_slice(Str s, isize l, isize u) { - if (l < 0) l += s.len; - ASSERT(0 <= l && l <= s.len, "str_slice: lower index out of bounds"); - - if (u < 0) u += s.len; - ASSERT(0 <= u && u <= s.len, "str_slice: upper index out of bounds"); - - return (Str){ - .len = l < u ? u - l : 0, - .data = s.data + l, - }; -} - char * str_alloc_cstr(Str s) { char *c = r_alloc(s.len + 1);