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