Commit | Line | Data |
---|---|---|
01bf7a3a PP |
1 | /* |
2 | * Copyright (c) 2019-2020 Philippe Proulx <pproulx@efficios.com> | |
3 | * | |
4 | * SPDX-License-Identifier: MIT | |
5 | */ | |
6 | ||
7 | #ifndef BABELTRACE_CPP_COMMON_BT2_INTERNAL_SHARED_OBJ_HPP | |
8 | #define BABELTRACE_CPP_COMMON_BT2_INTERNAL_SHARED_OBJ_HPP | |
9 | ||
10 | #include "common/assert.h" | |
11 | #include "cpp-common/optional.hpp" | |
12 | ||
13 | namespace bt2 { | |
14 | namespace internal { | |
15 | ||
16 | /* | |
17 | * An instance of this class wraps an optional instance of `ObjT` and | |
18 | * manages the reference counting of the underlying libbabeltrace2 | |
19 | * object. | |
20 | * | |
21 | * When you move a shared object, it becomes invalid, in that | |
22 | * operator*() and operator->() will either fail to assert in debug mode | |
23 | * or trigger a segmentation fault. | |
24 | * | |
25 | * `LibObjT` is the direct libbabeltrace2 object type, for example | |
26 | * `bt_stream_class` or `const bt_value`. | |
27 | * | |
28 | * RefFuncsT::get() must accept a `const LibObjT *` value and increment | |
29 | * its reference count. | |
30 | * | |
31 | * RefFuncsT::put() must accept a `const LibObjT *` value and decrement | |
32 | * its reference count. | |
33 | */ | |
34 | template <typename ObjT, typename LibObjT, typename RefFuncsT> | |
35 | class SharedObj final | |
36 | { | |
37 | /* | |
38 | * This makes it possible for a | |
39 | * `SharedObj<Something, bt_something, ...>` instance to get | |
40 | * assigned an instance of | |
41 | * `SharedObj<SpecificSomething, bt_something, ...>` (copy/move | |
e60a53f1 | 42 | * constructors and assignment operators), given that |
01bf7a3a PP |
43 | * `SpecificSomething` inherits `Something`. |
44 | */ | |
45 | template <typename AnyObjT, typename AnyLibObjT, typename AnyRefFuncsT> | |
46 | friend class SharedObj; | |
47 | ||
c9c0b6e2 PP |
48 | private: |
49 | /* | |
50 | * Builds a shared object from `obj` without getting a reference. | |
51 | */ | |
52 | explicit SharedObj(const ObjT& obj) noexcept : _mObj {obj} | |
53 | { | |
54 | } | |
55 | ||
e60a53f1 PP |
56 | /* |
57 | * Common generic "copy" constructor. | |
58 | * | |
59 | * This constructor is meant to be delegated to by the copy | |
60 | * constructor and the generic "copy" constructor. | |
61 | * | |
62 | * The second parameter, of type `int`, makes it possible to | |
63 | * delegate by deduction as you can't explicit the template | |
64 | * parameters when delegating to a constructor template. | |
65 | */ | |
66 | template <typename OtherObjT, typename OtherLibObjT> | |
67 | SharedObj(const SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>& other, int) noexcept : | |
68 | _mObj {other._mObj} | |
69 | { | |
70 | this->_getRef(); | |
71 | } | |
72 | ||
73 | /* | |
74 | * Common generic "move" constructor. | |
75 | * | |
76 | * See the comment of the common generic "copy" constructor above. | |
77 | */ | |
78 | template <typename OtherObjT, typename OtherLibObjT> | |
79 | SharedObj(SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>&& other, int) noexcept : | |
80 | _mObj {other._mObj} | |
81 | { | |
82 | /* Reset moved-from object */ | |
83 | other._reset(); | |
84 | } | |
85 | ||
01bf7a3a | 86 | public: |
c9c0b6e2 PP |
87 | /* |
88 | * Builds a shared object from `obj` without getting a reference. | |
89 | */ | |
90 | static SharedObj createWithoutRef(const ObjT& obj) noexcept | |
91 | { | |
92 | return SharedObj {obj}; | |
93 | } | |
01bf7a3a PP |
94 | |
95 | /* | |
c9c0b6e2 PP |
96 | * Builds a shared object from `libObjPtr` without getting a |
97 | * reference. | |
01bf7a3a | 98 | */ |
c9c0b6e2 | 99 | static SharedObj createWithoutRef(LibObjT * const libObjPtr) noexcept |
01bf7a3a | 100 | { |
c9c0b6e2 | 101 | return SharedObj::createWithoutRef(ObjT {libObjPtr}); |
01bf7a3a PP |
102 | } |
103 | ||
104 | /* | |
c9c0b6e2 PP |
105 | * Builds a shared object from `obj`, immediately getting a new |
106 | * reference. | |
01bf7a3a | 107 | */ |
c9c0b6e2 | 108 | static SharedObj createWithRef(const ObjT& obj) noexcept |
01bf7a3a | 109 | { |
c9c0b6e2 | 110 | SharedObj sharedObj {obj}; |
01bf7a3a PP |
111 | |
112 | sharedObj._getRef(); | |
113 | return sharedObj; | |
114 | } | |
115 | ||
c9c0b6e2 PP |
116 | /* |
117 | * Builds a shared object from `libObjPtr`, immediately getting a new | |
118 | * reference. | |
119 | */ | |
120 | static SharedObj createWithRef(LibObjT * const libObjPtr) noexcept | |
121 | { | |
122 | return SharedObj::createWithRef(ObjT {libObjPtr}); | |
123 | } | |
124 | ||
01bf7a3a | 125 | /* |
e60a53f1 PP |
126 | * Copy constructor. |
127 | */ | |
128 | SharedObj(const SharedObj& other) noexcept : SharedObj {other, 0} | |
129 | { | |
130 | } | |
131 | ||
132 | /* | |
133 | * Move constructor. | |
134 | */ | |
135 | SharedObj(SharedObj&& other) noexcept : SharedObj {std::move(other), 0} | |
136 | { | |
137 | } | |
138 | ||
139 | /* | |
140 | * Copy assignment operator. | |
141 | */ | |
142 | SharedObj& operator=(const SharedObj& other) noexcept | |
143 | { | |
144 | /* Use generic "copy" assignment operator */ | |
145 | return this->operator=<ObjT, LibObjT>(other); | |
146 | } | |
147 | ||
148 | /* | |
149 | * Move assignment operator. | |
150 | */ | |
151 | SharedObj& operator=(SharedObj&& other) noexcept | |
152 | { | |
153 | /* Use generic "move" assignment operator */ | |
154 | return this->operator=<ObjT, LibObjT>(std::move(other)); | |
155 | } | |
156 | ||
157 | /* | |
158 | * Generic "copy" constructor. | |
01bf7a3a PP |
159 | * |
160 | * See the `friend class SharedObj` comment above. | |
161 | */ | |
162 | template <typename OtherObjT, typename OtherLibObjT> | |
163 | SharedObj(const SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>& other) noexcept : | |
e60a53f1 | 164 | SharedObj {other, 0} |
01bf7a3a | 165 | { |
01bf7a3a PP |
166 | } |
167 | ||
168 | /* | |
e60a53f1 | 169 | * Generic "move" constructor. |
01bf7a3a PP |
170 | * |
171 | * See the `friend class SharedObj` comment above. | |
172 | */ | |
173 | template <typename OtherObjT, typename OtherLibObjT> | |
e60a53f1 PP |
174 | SharedObj(SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>&& other) noexcept : |
175 | SharedObj {std::move(other), 0} | |
01bf7a3a | 176 | { |
01bf7a3a PP |
177 | } |
178 | ||
179 | /* | |
e60a53f1 | 180 | * Generic "copy" assignment operator. |
01bf7a3a PP |
181 | * |
182 | * See the `friend class SharedObj` comment above. | |
183 | */ | |
184 | template <typename OtherObjT, typename OtherLibObjT> | |
c9c0b6e2 | 185 | SharedObj& operator=(const SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>& other) noexcept |
01bf7a3a | 186 | { |
b5f55e9f | 187 | /* Put current object's reference */ |
01bf7a3a PP |
188 | this->_putRef(); |
189 | ||
b5f55e9f | 190 | /* Set new current object and get a reference */ |
01bf7a3a PP |
191 | _mObj = other._mObj; |
192 | this->_getRef(); | |
193 | ||
194 | return *this; | |
195 | } | |
196 | ||
197 | /* | |
e60a53f1 | 198 | * Generic "move" assignment operator. |
01bf7a3a PP |
199 | * |
200 | * See the `friend class SharedObj` comment above. | |
201 | */ | |
202 | template <typename OtherObjT, typename OtherLibObjT> | |
c9c0b6e2 | 203 | SharedObj& operator=(SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>&& other) noexcept |
01bf7a3a | 204 | { |
b5f55e9f | 205 | /* Put current object's reference */ |
01bf7a3a PP |
206 | this->_putRef(); |
207 | ||
b5f55e9f | 208 | /* Set new current object */ |
01bf7a3a PP |
209 | _mObj = other._mObj; |
210 | ||
b5f55e9f | 211 | /* Reset moved-from object */ |
01bf7a3a PP |
212 | other._reset(); |
213 | ||
214 | return *this; | |
215 | } | |
216 | ||
217 | ~SharedObj() | |
218 | { | |
219 | this->_putRef(); | |
220 | } | |
221 | ||
222 | ObjT& operator*() noexcept | |
223 | { | |
224 | BT_ASSERT_DBG(_mObj); | |
225 | return *_mObj; | |
226 | } | |
227 | ||
228 | const ObjT& operator*() const noexcept | |
229 | { | |
230 | BT_ASSERT_DBG(_mObj); | |
231 | return *_mObj; | |
232 | } | |
233 | ||
234 | ObjT *operator->() noexcept | |
235 | { | |
236 | BT_ASSERT_DBG(_mObj); | |
237 | return &*_mObj; | |
238 | } | |
239 | ||
240 | const ObjT *operator->() const noexcept | |
241 | { | |
242 | BT_ASSERT_DBG(_mObj); | |
243 | return &*_mObj; | |
244 | } | |
245 | ||
246 | private: | |
247 | /* | |
248 | * Resets this shared object. | |
249 | * | |
250 | * To be used when moving it. | |
251 | */ | |
252 | void _reset() noexcept | |
253 | { | |
254 | _mObj.reset(); | |
255 | } | |
256 | ||
257 | /* | |
258 | * Gets a new reference using the configured libbabeltrace2 | |
259 | * reference incrementation function. | |
260 | */ | |
261 | void _getRef() const noexcept | |
262 | { | |
263 | if (_mObj) { | |
341a67c4 | 264 | RefFuncsT::get(_mObj->libObjPtr()); |
01bf7a3a PP |
265 | } |
266 | } | |
267 | ||
268 | /* | |
269 | * Puts a reference using the configured libbabeltrace2 reference | |
270 | * decrementation function. | |
271 | */ | |
272 | void _putRef() const noexcept | |
273 | { | |
274 | if (_mObj) { | |
341a67c4 | 275 | RefFuncsT::put(_mObj->libObjPtr()); |
01bf7a3a PP |
276 | } |
277 | } | |
278 | ||
279 | nonstd::optional<ObjT> _mObj; | |
280 | }; | |
281 | ||
b5f55e9f PP |
282 | } /* namespace internal */ |
283 | } /* namespace bt2 */ | |
01bf7a3a | 284 | |
b5f55e9f | 285 | #endif /* BABELTRACE_CPP_COMMON_BT2_INTERNAL_SHARED_OBJ_HPP */ |