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