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