#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; }