diff --git a/include/rc.h b/include/rc.h index d113d4b..a794441 100644 --- a/include/rc.h +++ b/include/rc.h @@ -45,8 +45,10 @@ rc_ptr_t rc_clone(rc_const_ptr_t ptr) _rc_mut_fn _rc_attr((returns_nonnull)); size_t rc_refs(rc_const_ptr_t ptr)_rc_fn; rc_bool rc_is_valid(rc_const_ptr_t ptr) _rc_fn; -rc_weak_t* _rc_restrict rc_create_weak(rc_const_ptr_t ptr) _rc_gmut_fn _rc_alloc_fn; +rc_weak_t* _rc_restrict rc_downgrade(rc_const_ptr_t ptr) _rc_gmut_fn _rc_alloc_fn; +rc_ptr_t rc_weak_upgrade(const rc_weak_t * _rc_restrict weak); void rc_weak_free(rc_weak_t* _rc_restrict ptr) _rc_gmut_fn; +rc_ptr_t rc_weak_upgrade(const rc_weak_t * _rc_restrict weak) _rc_mut_fn; #ifdef __cplusplus } diff --git a/src/rc.c b/src/rc.c index 99baff0..6454769 100644 --- a/src/rc.c +++ b/src/rc.c @@ -5,6 +5,8 @@ #include +#include "vector.h" + #define RC_CHK 0xabadcafe @@ -12,17 +14,18 @@ struct rc { uint32_t check; _Atomic size_t refs; _Atomic size_t weak_refs; - //TODO: Keep all weak pointers here. rc_weak_free() should remove its own pointer address from that. + + vec_t* _rc_restrict weaks; //vec type `rc_weak_t*` uint8_t ptr[]; }; struct rc_weak { - _Atomic int is_valid; + _Atomic rc_bool is_valid; const struct rc* _rc_attr((may_alias)) _ptr; }; -_rc_attr((noreturn)) static void panic(const char* string, ...) +_rc_attr((noreturn)) void panic(const char* string, ...) { va_list args; va_start(args, string); @@ -75,6 +78,7 @@ _rc_attr((nonnull)) inline static void rc_checkptr(const struct rc* rc) rc->check = RC_CHK; rc->refs = 1; rc->weak_refs =0; + rc->weaks = vec_new(); return (void*) rc->ptr; } @@ -83,7 +87,13 @@ _rc_attr((nonnull)) inline static void rc_checkptr(const struct rc* rc) { register rc_t rc = ptr_rev(ptr); rc_checkptr(rc); - if (!--rc->refs) free(rc); + if (!--rc->refs) { + for(size_t i=0;iweaks->len;i++) { + vec_tnptr(rc_weak_t, rc->weaks->buffer[i])->is_valid = RC_FALSE; + } + free(rc->weaks); + free(rc); + } } _rc_mut_fn _rc_attr((returns_nonnull)) rc_ptr_t rc_clone(rc_const_ptr_t ptr) @@ -108,13 +118,16 @@ _rc_fn rc_bool rc_is_valid(rc_const_ptr_t ptr) && rc->refs>0; } -_rc_alloc_fn _rc_gmut_fn rc_weak_t* _rc_restrict rc_create_weak(rc_const_ptr_t ptr) +_rc_alloc_fn _rc_gmut_fn rc_weak_t* _rc_restrict rc_downgrade(rc_const_ptr_t ptr) { register rc_t rc = ptr_ucrev(ptr); rc_weak_t* weak = calloc(sizeof(rc_weak_t), 1); + //TODO: push `weak` to rc->weaks + weak->_ptr = rc; - weak->is_valid = 1; + weak->is_valid = RC_TRUE; + rc->weak_refs++; return weak; @@ -125,7 +138,22 @@ _rc_gmut_fn void rc_weak_free(rc_weak_t* _rc_restrict ptr) if (ptr->is_valid) { struct rc* _rc_attr((may_alias)) rc = (struct rc* _rc_attr((may_alias)))ptr->_ptr; rc_checkptr(rc); + + //TODO: remove `weak` from `rc->weaks` rc->weak_refs--; } free(ptr); } + +_rc_mut_fn rc_ptr_t rc_weak_upgrade(const rc_weak_t * _rc_restrict weak) +{ + if (weak->is_valid) { + struct rc* _rc_attr((may_alias)) rc = (struct rc* _rc_attr((may_alias)))weak->_ptr; + + if (rc->check == RC_CHK && rc->refs>0) { + rc->refs++; + return rc->ptr; + } + } + return NULL; +} diff --git a/src/vector.c b/src/vector.c new file mode 100644 index 0000000..f4c33e7 --- /dev/null +++ b/src/vector.c @@ -0,0 +1,22 @@ +#include +#include + +#include "vector.h" + +extern void panic(const char* string, ...) _rc_attr((noreturn)); + +_rc_attr((noinline, noreturn, cold)) static void _fail_vec_alloc(size_t cap) +{ + panic("vec_alloc(): malloc() failed to allocate %d bytes (cap %d)", sizeof(vec_t) + (cap * sizeof(vec_elem_t)), cap); +} + +_rc_alloc_fn vec_t* _rc_restrict vec_alloc(size_t cap) +{ + vec_t* vec = malloc(sizeof(vec_t) + (cap * sizeof(vec_elem_t))); + if(!vec) _fail_vec_alloc(cap); + vec-> cap = cap; + vec-> scap = cap; + vec-> len = 0; + + return vec; +} diff --git a/src/vector.h b/src/vector.h new file mode 100644 index 0000000..6c5baae --- /dev/null +++ b/src/vector.h @@ -0,0 +1,27 @@ +#ifndef _VECTOR_H +#define _VECTOR_H + +#include + +#define VEC_DEFAULT_CAP 16 + + +typedef void* vec_elem_t; +typedef struct vec vec_t; + +struct vec { + size_t scap; + + size_t cap; + size_t len; + + vec_elem_t buffer[]; +}; + +#define vec_new() vec_alloc(VEC_DEFAULT_CAP) +#define vec_free(vec) free(vec) +#define vec_tnptr(ty, elem) ((ty *)(elem)) + +vec_t* _rc_restrict vec_alloc(size_t cap) _rc_alloc_fn; + +#endif /* _VECTOR_H */