19#ifndef MTCORE_MTTHREAD_ARC_HPP
20#define MTCORE_MTTHREAD_ARC_HPP
25#ifndef MTCORE_NO_STACKTRACE
26#include <cpptrace/basic.hpp>
40 static constexpr u64 zero_flag =
static_cast<u64>(0x1) <<
static_cast<u64>(63);
41 static constexpr u64 helped_flag =
static_cast<u64>(0x1) <<
static_cast<u64>(62);
42 std::atomic_uint64_t count = 1;
44 [[nodiscard]]
bool acquire() {
return !(count.fetch_add(1) & zero_flag); }
46 [[nodiscard]]
bool release() {
47 if (count.fetch_sub(1) == 1) {
49 if (count.compare_exchange_strong(e, zero_flag)) {
52 return (e & helped_flag) && count.exchange(zero_flag) & helped_flag;
58 auto v = count.load();
59 if (v == 0 && count.compare_exchange_strong(v, zero_flag | helped_flag)) {
62 return (v & zero_flag) ? 0 : v;
82 RefCount(T *val) : value(
val) {}
83 RefCount(RefCount &) =
default;
84 RefCount(RefCount &&) noexcept = default;
85 RefCount &operator=(const RefCount &) = default;
86 RefCount &operator=(RefCount &&) noexcept = default;
88 template<typename... Args>
89 [[nodiscard]] static Result<RefCount *,
AllocationError> make(Allocator &alloc, Args... args) {
90 auto v = alloc.create<T>(args...);
95 auto res = alloc.create<RefCount>(v.value());
99 bool acquire() {
return c.acquire(); }
101 bool release(Allocator &alloc) {
103 alloc.destroy(value);
142 impl::RefCount<impl::RefCount<T>> *
rc =
nullptr;
160 ensure(
rc->value,
"Arc is invalid");
161 if (
rc->release(alloc)) {
174 [[nodiscard]]
bool valid()
const {
return rc !=
nullptr; }
191 impl::RefCount<impl::RefCount<T>> *
rc =
nullptr;
199 ensure(
rc->value->value,
"Invalid Arc");
200 return rc->value->value;
209 ensure(
rc->value->value,
"Invalid Arc");
210 return rc->value->value;
219 ensure(
rc->value->value,
"Invalid Arc");
220 return *
rc->value->value;
229 ensure(
rc->value->value,
"Invalid Arc");
230 return *
rc->value->value;
242 if (other ==
nullptr &&
rc ==
nullptr) {
247 ensure(
rc->value->value,
"Invalid Arc");
248 return rc->value->value == other;
255 if (other ==
nullptr &&
rc ==
nullptr) {
260 ensure(
rc->value->value,
"Invalid Arc");
261 return rc->value->value == other;
267 [[nodiscard]]
bool valid()
const {
return rc !=
nullptr &&
rc->value !=
nullptr &&
rc->value->value; }
272 [[nodiscard]]
operator bool()
const {
return valid(); }
281 template<
typename... Args>
288 return valRes.
error();
290 T *val = valRes.
value();
292 auto outerRcRes = impl::RefCount<impl::RefCount<T>>::make(alloc);
293 if (outerRcRes.is_error()) {
295 return outerRcRes.error();
297 impl::RefCount<impl::RefCount<T>> *outerRc = outerRcRes.value();
298 outerRc->value->value = valRes.
value();
310 if (!
rc->acquire()) {
313 ensure(
rc->value,
"Arc is invalid");
314 if (!
rc->value->acquire()) {
330 ensure(
rc->value,
"Arc is invalid");
331 (void)
rc->value->release(alloc);
332 if (
rc->release(alloc)) {
351 if (!
rc->acquire()) {
361 if (!
rc->acquire()) {
365 if (!
rc->value->acquire()) {
ValIter< T > val(const T &r)
Generic value iterator that uses the operator[] and incrementing indexes to iterate over a collection...
ArcError
Error when cannot acquire an ARC.
AllocationError
Error indicating failed allocation.
@ CannotAcquire
Error when a new Arc reference cannot be acquired (e.g.
#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.
Thread-related namespace The methods and classes provided by this class are thread-safe Classes and m...
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.
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;.
bool operator==(T *other) const
Checks if an Arc is equivalent to a pointer (used for nullptr checks)
const T & operator*() const
Dereferences an Arc pointer.
Result< Arc, ArcError > acquire(Allocator &alloc)
Acquires a new Arc reference (increments ref count by 1)
Result< WeakArc< T >, ArcError > weak()
Tries to get a weak pointer.
T * operator->()
Dereferences an Arc pointer.
bool operator==(const T *other) const
Checks if an Arc is equivalent to a pointer (used for nullptr checks)
bool operator==(const Arc &o) const
Checks if an Arc is equivalent to another Arc.
impl::RefCount< impl::RefCount< T > > * rc
bool valid() const
Checks if an Arc is valid (it points to something, and that something still exists)
void deinit(Allocator &alloc)
void release(Allocator &alloc)
Releases an Arc reference (decrements ref count by 1)
Result< void, AllocationError > init(Allocator &alloc, Args... args)
Tries to initialize an ARC to point to a new object.
const T * operator->() const
Dereferences an Arc pointer.
T & operator*()
Dereferences an Arc pointer.
Weak Automic Reference Count.
Result< WeakArc, ArcError > copy()
Tries to copy a weak reference.
Result< Arc< T >, ArcError > obtain(Allocator &alloc)
Tries to obtain a strong reference to what's pointed at.
void deinit(Allocator &alloc)
Deinitializes a weak pointer (may Result in memory cleanup if last weak counter)
impl::RefCount< impl::RefCount< T > > * rc
bool valid() const
Checks if a weak pointer is "valid" as in it's set to point to something Does NOT check if the refere...