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