Ditto
4.6.0
Loading...
Searching...
No Matches
include
Arc.hpp
1
#ifndef _ARC_
2
#define _ARC_
3
4
#include <atomic>
5
#include <cassert>
6
#include <utility>
7
8
namespace
ditto {
9
10
template
<
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
18
template
<
typename
T>
class
Arc
{
19
public
:
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
{
78
ArcPointee<T>
*
rhs_ptr
=
rhs
.ptr;
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
{
99
Arc<T>
temporary
{
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
119
private
:
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_
ditto::Arc
Definition
Arc.hpp:18
ditto::ArcPointee
Definition
Arc.hpp:10
Generated by
1.10.0