You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
1.5 KiB

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdarg.h>
#include <rc.h>
#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;
}