MT Core (C++)
Core library for replacing C++ standard in project usage
Loading...
Searching...
No Matches
rc.hpp
Go to the documentation of this file.
1#ifndef MTCORE_RC_HPP
2#define MTCORE_RC_HPP
3
4#include "mtcore/alloc.hpp"
6#include "mtcore/core.hpp"
7
8namespace mtcore {
9 namespace impl {
10 struct RcCounter {
11 u64 count = 1;
12
13 bool acquire() {
14 if (count == 0) {
15 return false;
16 }
17 ++count;
18 return true;
19 }
20
21 bool release() {
22 ensure(count > 0, "DOUBLE RELEASE DETECTED!");
23 --count;
24 return count == 0;
25 }
26
27 u64 val() { return count; }
28 };
29
30 enum class StrongReleaseAction {
31 NONE,
32 CLEANUP_RC,
33 CLEANUP_VAR_ONLY,
34 };
35
36 template<typename T>
37 struct ThreadLocalRefCount {
38 T *value = nullptr;
39 u64 strongCounter = 1;
40 u64 weakCounter = 0;
41
42 bool acquireStrong() {
43 if (strongCounter == 0 || value == nullptr) {
44 return false;
45 }
46 ++strongCounter;
47 return true;
48 }
49
50 bool acquireWeak() {
51 if (strongCounter == 0 && weakCounter == 0) {
52 return false;
53 }
54 ++weakCounter;
55 return true;
56 }
57
58 StrongReleaseAction releaseStrong() {
59 ensure(strongCounter > 0, "Double release detected");
60 --strongCounter;
61 if (strongCounter > 0) {
62 return StrongReleaseAction::NONE;
63 }
64 else if (weakCounter == 0) {
65 return StrongReleaseAction::CLEANUP_RC;
66 }
67 else {
68 return StrongReleaseAction::CLEANUP_VAR_ONLY;
69 }
70 }
71
72 bool releaseWeak() {
73 ensure(weakCounter > 0, "Double release detected");
74 --weakCounter;
75 return weakCounter == 0 && strongCounter == 0;
76 }
77 };
78 } // namespace impl
79
83 enum class RcError {
85 };
86
95 template<typename T>
96 struct Rc;
97
105 template<typename T>
106 struct WeakRc {
107 impl::ThreadLocalRefCount<T> *rc = nullptr;
108
115
121 void deinit(Allocator &alloc) {
122 if (!rc) {
123 return;
124 }
125
126 ensure(rc, "Rc is invalid");
127 if (rc->releaseWeak()) {
128 alloc.destroy(rc);
129 }
130 }
131
135 [[nodiscard]] bool valid() const { return rc != nullptr; }
136
140 [[nodiscard]] operator bool() const { return valid(); }
141
146 ensure(rc, "Rc is invalid");
147 if (!rc->acquireWeak()) {
149 }
150 return *this;
151 }
152 };
153
154 template<typename T>
155 struct Rc {
156 impl::ThreadLocalRefCount<T> *rc = nullptr;
157
159 [[nodiscard]] T& operator*() {
160 ensure(rc, "Invalid Rc");
161 return *rc->value;
162 }
163
165 [[nodiscard]] const T &operator*() const {
166 ensure(rc, "Invalid Rc");
167 return *rc->value;
168 }
169
171 [[nodiscard]] T *operator->() {
172 ensure(rc, "Invalid Rc");
173 return rc->value;
174 }
175
177 [[nodiscard]] const T *operator->() const {
178 ensure(rc, "Invalid Rc");
179 return rc->value;
180 }
181
183 [[nodiscard]] bool operator==(const Rc& other) const {
184 return rc == other.rc;
185 }
186
188 [[nodiscard]] bool operator==(T* other) const {
189 if (other == nullptr && rc == nullptr) {
190 return true;
191 }
192 ensure(rc, "Invalid Rc");
193 return rc->value == other;
194 }
195
197 [[nodiscard]] bool operator==(const T* other) const {
198 if (other == nullptr && rc == nullptr) {
199 return true;
200 }
201 ensure(rc, "Invalid Rc");
202 return rc->value == other;
203 }
204
206 [[nodiscard]] bool valid() const { return rc != nullptr && rc->value != nullptr; }
207
209 [[nodiscard]] operator bool() const { return valid(); }
210
218 template<typename... Args>
219 [[nodiscard]] Result<void, AllocationError> init(Allocator& alloc, Args... args) {
220 if (rc) {
221 release(alloc);
222 }
223 Result<T*, AllocationError> valRes = alloc.create<T>(args...);
224 if (valRes.is_error()) {
225 return valRes.error();
226 }
227 T* val = valRes.value();
228
229 auto rcRes = alloc.create<impl::ThreadLocalRefCount<T>>();
230 if (rcRes.is_error()) {
231 alloc.destroy(val);
233 }
234 rc = rcRes.value();
235 rc->value = val;
236 return success();
237 }
238
243 [[nodiscard]] Result<Rc, RcError> acquire() {
244 ensure(rc, "Rc is invalid");
245 if (!rc->acquireStrong()) {
247 }
248 ensure(rc->value, "Rc is invalid");
249 return *this;
250 }
251
256 void release(Allocator& alloc) {
257 if (!rc) {
258 return;
259 }
260 ensure(rc, "Rc is invalid");
261 ensure(rc->value, "Rc is invalid");
262 switch (impl::StrongReleaseAction action = rc->releaseStrong()) {
263 case impl::StrongReleaseAction::NONE:
264 break;
265 case impl::StrongReleaseAction::CLEANUP_RC:
266 alloc.destroy(rc->value);
267 rc->value = nullptr;
268 alloc.destroy(rc);
269 break;
270 case impl::StrongReleaseAction::CLEANUP_VAR_ONLY:
271 alloc.destroy(rc->value);
272 rc->value = nullptr;
273 break;
274 }
275 rc = nullptr;
276 }
277
279 void deinit(Allocator &alloc) {
280 release(alloc);
281 }
282
287 ensure(rc, "Invalid Rc");
288 if (!rc->acquireWeak()) {
290 }
291 return success(WeakRc<T>{rc});
292 }
293 };
294
295 template<typename T>
297 ensure(rc, "arc is invalid");
298 if (!rc->acquireStrong()) {
300 }
301 return Rc<T>{rc};
302 }
303
304} // namespace mtcore
305
306#endif // MTCORE_RC_HPP
#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.
Definition result.hpp:398
Error< Underlying > error(Underlying err)
Creates an error.
Definition result.hpp:425
uint64_t u64
Alias for 64-bit unsigned ints.
Core library for C++ with Zig-related functionality.
RcError
Error for thread-local reference counting.
Definition rc.hpp:83
@ CANNOT_ACQUIRE
Definition rc.hpp:84
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...
Definition rc.hpp:155
void deinit(Allocator &alloc)
Same as release.
Definition rc.hpp:279
T * operator->()
Dereferences pointer.
Definition rc.hpp:171
bool operator==(const T *other) const
Compares to a pointer.
Definition rc.hpp:197
Result< WeakRc< T >, RcError > weak()
Attempts to get a weak reference.
Definition rc.hpp:286
bool operator==(T *other) const
Compares to a pointer.
Definition rc.hpp:188
T & operator*()
Dereferences pointer.
Definition rc.hpp:159
Result< void, AllocationError > init(Allocator &alloc, Args... args)
Initializes a reference counter to point to a new entity.
Definition rc.hpp:219
const T & operator*() const
Dereferences pointer.
Definition rc.hpp:165
const T * operator->() const
Dereferences pointer.
Definition rc.hpp:177
bool operator==(const Rc &other) const
Compares to a pointer.
Definition rc.hpp:183
void release(Allocator &alloc)
Releases a reference.
Definition rc.hpp:256
bool valid() const
Checks if is valid.
Definition rc.hpp:206
impl::ThreadLocalRefCount< T > * rc
Definition rc.hpp:156
Result< Rc, RcError > acquire()
Tries to acquire another strong reference Will return either another strong reference or an error.
Definition rc.hpp:243
Represents a Result that may have an error (error code) or a success value A type of "void" means the...
Definition result.hpp:170
T value() const noexcept
Checks if is a successful Result (aka.
Definition result.hpp:258
bool is_error() const noexcept
Checks if is an error Result.
Definition result.hpp:266
ErrVal error() const noexcept
Returns the associated error Fails if there is no error;.
Definition result.hpp:294
Thread-local weak reference counted pointer Not thread safe, don't share Does not hold lifetime.
Definition rc.hpp:106
Result< WeakRc, RcError > copy()
Tries to copy a weak reference.
Definition rc.hpp:145
Result< Rc< T >, RcError > obtain(Allocator &alloc)
Tries to obtain a strong reference May error if could not obtain (e.g.
Definition rc.hpp:296
void deinit(Allocator &alloc)
Deinitializes a weak pointer Will decrement weak count and may clean up counter.
Definition rc.hpp:121
impl::ThreadLocalRefCount< T > * rc
Definition rc.hpp:107
bool valid() const
Checks if weak reference is valid.
Definition rc.hpp:135