Ditto 4.6.0
Loading...
Searching...
No Matches
Arc.hpp
1#ifndef _ARC_
2#define _ARC_
3
4#include <atomic>
5#include <cassert>
6#include <utility>
7
8namespace ditto {
9
10template <typename T> struct ArcPointee {
11 T value;
12 mutable std::atomic<size_t> strong_count;
13
14 ArcPointee(T &&value, size_t strong_count)
15 : value /* = */ (std::move(value)), strong_count /* = */ (strong_count) {}
16};
17
18template <typename T> class Arc {
19public:
20 // Post-condition: refcount = 1.
21 Arc(T value) noexcept
22 : ptr /* = */ (new ArcPointee<T>(std::move(value), 1)) {}
23
24 // Post-condition: refcount ±= 0; schedules dtor glue to `-= 1`.
25 // There has to be a 1-to-1 relation between `into_raw()` and `from_raw()`.
26 static Arc<T> from_raw(void *ptr) noexcept {
27 return Arc(static_cast<ArcPointee<T> *>(ptr));
28 }
29
30 // The equivalent of boost's `detach()`.
31 // Post-condition: refcount ±= 0; disables the `-= 1` eventual dtor glue.
32 // There has to be a 1-to-1 relation between `into_raw()` and `from_raw()`.
33 static void *into_raw(ArcPointee<T> &&self) noexcept {
34 auto ptr = self.ptr;
35 self.ptr = nullptr;
36 return static_cast<void *>(ptr);
37 }
38
39 // The equivalent of boost's `get()`.
40 // Post-condition: refcount ±= 0; dtor untouched.
41 static void *as_raw(Arc<T> const &arc) noexcept { return arc.ptr; }
42
43 // Borrow a `void *` as a `Arc<T>`, *temporarily*.
44 // (i.e., without touching the refcount nor setting up any ownership).
45 // - You could then use the copy (clone) ctor to get back an owned `Arc<T>`,
46 // via the retain therein.
47 // Post-condition: refcount ±= 0; dtor not enabled.
48 static Arc<T> &borrow_from_raw(void *&ptr) noexcept {
49 return *reinterpret_cast<Arc<T> *>(&ptr);
50 }
51
52 // Copy (clone) constructor
53 // Post-condition: refcount += 1; schedules new `-= 1` dtor glue.
54 Arc(Arc<T> const &other) noexcept : ptr /* = */ (other.ptr) {
55 ++(ptr->strong_count);
56 }
57
58 // Destructor / dtor.
59 // Post-condition: refcount = -1.
60 ~Arc() {
61 if (ptr != nullptr) { // <- if not moved from.
62 size_t count = --(ptr->strong_count);
63 if (count == 0) {
64 delete ptr;
65 }
66 }
67 }
68
69 // Move constructor
70 // Post-condition: refcount ±= 0 (and `rhs.ptr == nullptr`); moves dtor glue
71 // from `rhs` to `this`.
72 Arc(Arc<T> &&rhs) noexcept : ptr /* = */ (rhs.ptr) { rhs.ptr = nullptr; }
73
74 // Using `swap()`, we can use temporaries to derive the tricky assignments
75 // semantics off the above constructor & destructor operations, thanks to the
76 // C++ RAII semantics of the temporary. Post-condition: refcount ±= 0.
77 void swap(Arc<T> &rhs) noexcept {
79 rhs.ptr = this->ptr;
80 this->ptr = rhs_ptr;
81 }
82
83 // Copy (clone) assignment.
84 // Post-condition: rhs refcount += 1; orig `*this` destroyed; schedules new
85 // `-= 1` dtor glue.
86 Arc<T> &operator=(Arc<T> const &rhs) noexcept {
87 {
88 Arc temporary{rhs}; // copy ctor: +1 of rhs
89 temporary.swap(*this);
90 } // dtor: -1 on what used to be `*this`.
91 return *this;
92 }
93
94 // Move assignment
95 // Post-condition: rhs refcount ±= 0; `rhs.ptr == nullptr`; orig `*this`
96 // destroyed. Moved dtor.
97 Arc<T> &operator=(Arc<T> &&rhs) noexcept {
98 {
100 std::move(rhs)}; // move ctor: +0 of rhs; `rhs` is now `nullptr`.
101 temporary.swap(*this);
102 } // dtor: -1 on what used to be `*this`.
103 return *this;
104 }
105
106 // Deref
107 // Post-condition: rhs refcount ±= 0; dtor untouched.
108 T &operator*() const noexcept {
109 assert(ptr != nullptr);
110 return ptr->value;
111 }
112
113 // Post-condition: rhs refcount ±= 0; dtor untouched.
114 T *operator->() const noexcept {
115 assert(ptr != nullptr);
116 return &ptr->value;
117 }
118
119private:
120 ArcPointee<T> *ptr;
121
122 // from raw
123 Arc<T>(ArcPointee<T> *ptr) : ptr(ptr) {}
124};
125
126#define DEFINE_RETAIN_RELEASE_FOR(T, retain, release) \
127 extern "C" { \
128 /* Post-condition: refcount += 1; dtor untouched. */ \
129 static void retain(void *ptr) { \
130 ++(static_cast<ditto::ArcPointee<T> *>(ptr)->strong_count); \
131 } \
132 \
133 /* Post-condition: refcount -= 1; dtor untouched. */ \
134 static void release(void *ptr) { ditto::Arc<T>::from_raw(ptr); } \
135 } \
136 static_assert(true, \
137 "") // <- to require a semi-colon when the macro is invoked.
138
139} // namespace ditto
140
141#endif // _ARC_
Definition Arc.hpp:18
Definition Arc.hpp:10