40 ensure(count > 0,
"DOUBLE RELEASE DETECTED!");
45 u64 val() {
return count; }
48 enum class StrongReleaseAction {
55 struct ThreadLocalRefCount {
57 u64 strongCounter = 1;
60 bool acquireStrong() {
61 if (strongCounter == 0 || value ==
nullptr) {
69 if (strongCounter == 0 && weakCounter == 0) {
76 StrongReleaseAction releaseStrong() {
77 ensure(strongCounter > 0,
"Double release detected");
79 if (strongCounter > 0) {
80 return StrongReleaseAction::NONE;
82 else if (weakCounter == 0) {
83 return StrongReleaseAction::CLEANUP_RC;
86 return StrongReleaseAction::CLEANUP_VAR_ONLY;
91 ensure(weakCounter > 0,
"Double release detected");
93 return weakCounter == 0 && strongCounter == 0;
125 impl::ThreadLocalRefCount<T> *
rc =
nullptr;
145 if (
rc->releaseWeak()) {
153 [[nodiscard]]
bool valid()
const {
return rc !=
nullptr; }
158 [[nodiscard]]
operator bool()
const {
return valid(); }
165 if (!
rc->acquireWeak()) {
174 impl::ThreadLocalRefCount<T> *
rc =
nullptr;
205 if (other ==
nullptr &&
rc ==
nullptr) {
209 return rc->value == other;
214 if (other ==
nullptr &&
rc ==
nullptr) {
218 return rc->value == other;
222 [[nodiscard]]
bool valid()
const {
return rc !=
nullptr &&
rc->value !=
nullptr; }
225 [[nodiscard]]
operator bool()
const {
return valid(); }
234 template<
typename... Args>
241 return valRes.
error();
243 T *val = valRes.
value();
245 auto rcRes = alloc.
create<impl::ThreadLocalRefCount<T>>();
246 if (rcRes.is_error()) {
261 if (!
rc->acquireStrong()) {
278 switch (impl::StrongReleaseAction action =
rc->releaseStrong()) {
279 case impl::StrongReleaseAction::NONE:
281 case impl::StrongReleaseAction::CLEANUP_RC:
286 case impl::StrongReleaseAction::CLEANUP_VAR_ONLY:
302 if (!
rc->acquireWeak()) {
312 if (!
rc->acquireStrong()) {
#define ensure(check,...)
Ensures that a check holds true, aborts the program if not true Will print error if the condition is ...
Success< void > success()
Creates a successful void Result object.
Error< Underlying > error(Underlying err)
Creates an error.
uint64_t u64
Alias for 64-bit unsigned ints.
Core library for C++ with Zig-related functionality.
RcError
Error for thread-local reference counting.
Represents a memory allocator Exact behavior depends on the underlying VTable used Should use the a_*...
Result< T *, AllocationError > create(Args... args)
Allocates some block of memory with an allocator with a known type Will pass arguments to the constru...
void destroy(T *&ptr)
Destroys an object allocated by this allocator by calling the destructor and freeing memory.
Thread-local reference counted pointer Not thread safe, don't share Reference counting for cleaning u...
void deinit(Allocator &alloc)
Same as release.
T * operator->()
Dereferences pointer.
bool operator==(const T *other) const
Compares to a pointer.
Result< WeakRc< T >, RcError > weak()
Attempts to get a weak reference.
bool operator==(T *other) const
Compares to a pointer.
T & operator*()
Dereferences pointer.
Result< void, AllocationError > init(Allocator &alloc, Args... args)
Initializes a reference counter to point to a new entity.
const T & operator*() const
Dereferences pointer.
const T * operator->() const
Dereferences pointer.
bool operator==(const Rc &other) const
Compares to a pointer.
void release(Allocator &alloc)
Releases a reference.
bool valid() const
Checks if is valid.
impl::ThreadLocalRefCount< T > * rc
Result< Rc, RcError > acquire()
Tries to acquire another strong reference Will return either another strong reference or an error.
Represents a Result that may have an error (error code) or a success value A type of "void" means the...
T value() const noexcept
Checks if is a successful Result (aka.
bool is_error() const noexcept
Checks if is an error Result.
ErrVal error() const noexcept
Returns the associated error Fails if there is no error;.
Thread-local weak reference counted pointer Not thread safe, don't share Does not hold lifetime.
Result< WeakRc, RcError > copy()
Tries to copy a weak reference.
Result< Rc< T >, RcError > obtain(Allocator &alloc)
Tries to obtain a strong reference May error if could not obtain (e.g.
void deinit(Allocator &alloc)
Deinitializes a weak pointer Will decrement weak count and may clean up counter.
impl::ThreadLocalRefCount< T > * rc
bool valid() const
Checks if weak reference is valid.