From 0e3c5739c3478c3c55fc7bef5c6c4f70e60e8f16 Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 16 Nov 2020 14:30:14 +0000 Subject: [PATCH] initial commit --- .gitignore | 4 +++ Makefile | 39 +++++++++++++++++++++++++++ README | 1 + include/rc.h | 27 +++++++++++++++++++ src/rc.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 145 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README create mode 100644 include/rc.h create mode 100644 src/rc.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5812b96 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +*~ +*.a +*.so diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..762f9ff --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +SRC = $(wildcard src/*.c) +INCLUDE = include + +CFLAGS = -Wall $(addprefix -I,$(INCLUDE)) --std=gnu11 -pedantic +CFLAGS+= -O3 -flto -fgraphite + +LDFLAGS = -O3 -flto + +OBJ:= obj + +STATIC = $(addprefix $(OBJ)/static/,$(SRC:.c=.o)) +SHARED = $(addprefix $(OBJ)/shared/,$(SRC:.c=.o)) + +BUILD = librc + +.PHONY: all +all: dirs $(BUILD) + +dirs: + @mkdir -p obj/{shared,static}/src + +obj/static/%.o: %.c + $(CC) -c $< $(CFLAGS) -o $@ + +obj/shared/%.o: %.c + $(CC) -fPIC -c $< $(CFLAGS) -o $@ + +$(BUILD).a: $(STATIC) + ar rcs $@ $^ + +$(BUILD).so: $(SHARED) + $(CC) -shared $^ $(CFLAGS) -o $@ $(LDFLAGS) + strip $@ + +$(BUILD): $(BUILD).a $(BUILD).so + +clean: + rm -f $(BUILD).{a,so} + rm -rf obj diff --git a/README b/README new file mode 100644 index 0000000..f60294b --- /dev/null +++ b/README @@ -0,0 +1 @@ +Owned pointers in C diff --git a/include/rc.h b/include/rc.h new file mode 100644 index 0000000..f23cb2a --- /dev/null +++ b/include/rc.h @@ -0,0 +1,27 @@ +#ifndef _RC_H +#define _RC_H + +#ifdef __cplusplus +#define _rc_restrict __restrict +extern "C" { +#else +#define _rc_restrict restrict +#endif + +#ifndef __GNUC__ +#define _rc_attr(_) +#else +#define _rc_attr(v) __attribute__(v) +#endif + +typedef struct rc* rc_t; + +void* _rc_restrict rc_malloc(size_t sz) _rc_attr((malloc, alloc_size(1), returns_nonnull)); +void rc_free(void* ptr) _rc_attr((nonnull)); +void* _rc_attr((may_alias)) rc_clone(void* ptr) _rc_attr((pure, nonnull, returns_nonnull)); + +#ifdef __cplusplus +} +#endif + +#endif /* _RC_H */ diff --git a/src/rc.c b/src/rc.c new file mode 100644 index 0000000..530ac2e --- /dev/null +++ b/src/rc.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +#include + +#define RC_CHK 0xabadcafe + +struct rc { + uint32_t check; + _Atomic size_t refs; + + uint8_t ptr[]; +}; + +_rc_attr((noreturn)) static void panic(const char* string, ...) +{ + va_list args; + va_start(args, string); + fprintf(stderr, "(librc) Fatal error: "); + vfprintf(stderr, string, args); + va_end(args); + fprintf(stderr, "\n"); + abort(); +} + +_rc_attr((noinline, noreturn, cold)) static void _fail_invptr() +{ + panic("Invalid RC pointer"); +} + + _rc_attr((noinline, noreturn, cold)) static void _fail_malloc(size_t sz) +{ + panic("malloc() failed to allocate %d bytes (%d + sizeof(struct rc))", sz+sizeof(struct rc), sz); +} + +_rc_attr((artificial, always_inline)) inline static rc_t ptr_rev(void* ptr) +{ + if (!ptr) _fail_invptr(); + return (rc_t)(((uint8_t*)ptr) - sizeof(struct rc)); +} + +_rc_attr((nonnull)) inline static void rc_checkptr(const rc_t rc) +{ + if (rc->check != RC_CHK) _fail_invptr(); +} + + _rc_attr((malloc, alloc_size(1), returns_nonnull)) void* restrict rc_malloc(size_t sz) +{ + register rc_t rc = malloc(sz + sizeof(struct rc)); + + if (!rc) _fail_malloc(sz); + + rc->check = RC_CHK; + rc->refs = 1; + + return (void*) rc->ptr; +} + + _rc_attr((nonnull)) void rc_free(void* ptr) +{ + register rc_t rc = ptr_rev(ptr); + rc_checkptr(rc); + if (!--rc->refs) free(rc); +} + +_rc_attr((pure, nonnull, returns_nonnull)) void* _rc_attr((may_alias)) rc_clone(void* ptr) +{ + register rc_t rc = ptr_rev(ptr); + rc_checkptr(rc); + ++rc->refs; + return ptr; +}