406172d80577b929ea0a8745e6544425fd6a7791
[babeltrace.git] / src / cpp-common / bt2 / shared-object.hpp
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_SHARED_OBJECT_HPP
8 #define BABELTRACE_CPP_COMMON_BT2_SHARED_OBJECT_HPP
9
10 #include <utility>
11
12 #include "common/assert.h"
13
14 #include "optional-borrowed-object.hpp"
15
16 namespace bt2 {
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 *
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.
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>
41 class SharedObject final
42 {
43 /*
44 * This makes it possible for a
45 * `SharedObject<Something, bt_something, ...>` instance to get
46 * assigned an instance of
47 * `SharedObject<SpecificSomething, bt_something, ...>` (copy/move
48 * constructors and assignment operators), given that
49 * `SpecificSomething` inherits `Something`.
50 */
51 template <typename, typename, typename>
52 friend class SharedObject;
53
54 public:
55 /*
56 * Builds an empty shared object.
57 */
58 explicit SharedObject() noexcept
59 {
60 }
61
62 private:
63 /*
64 * Builds a shared object from `obj` without getting a reference.
65 */
66 explicit SharedObject(const ObjT& obj) noexcept : _mObj {obj}
67 {
68 }
69
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>
81 SharedObject(const SharedObject<OtherObjT, OtherLibObjT, RefFuncsT>& other, int) noexcept :
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>
93 SharedObject(SharedObject<OtherObjT, OtherLibObjT, RefFuncsT>&& other, int) noexcept :
94 _mObj {other._mObj}
95 {
96 /* Reset moved-from object */
97 other._reset();
98 }
99
100 public:
101 /*
102 * Builds a shared object from `obj` without getting a reference.
103 */
104 static SharedObject createWithoutRef(const ObjT& obj) noexcept
105 {
106 return SharedObject {obj};
107 }
108
109 /*
110 * Builds a shared object from `libObjPtr` without getting a
111 * reference.
112 */
113 static SharedObject createWithoutRef(LibObjT * const libObjPtr) noexcept
114 {
115 return SharedObject::createWithoutRef(ObjT {libObjPtr});
116 }
117
118 /*
119 * Builds a shared object from `obj`, immediately getting a new
120 * reference.
121 */
122 static SharedObject createWithRef(const ObjT& obj) noexcept
123 {
124 SharedObject sharedObj {obj};
125
126 sharedObj._getRef();
127 return sharedObj;
128 }
129
130 /*
131 * Builds a shared object from `libObjPtr`, immediately getting a
132 * new reference.
133 */
134 static SharedObject createWithRef(LibObjT * const libObjPtr) noexcept
135 {
136 return SharedObject::createWithRef(ObjT {libObjPtr});
137 }
138
139 /*
140 * Copy constructor.
141 */
142 SharedObject(const SharedObject& other) noexcept : SharedObject {other, 0}
143 {
144 }
145
146 /*
147 * Move constructor.
148 */
149 SharedObject(SharedObject&& other) noexcept : SharedObject {std::move(other), 0}
150 {
151 }
152
153 /*
154 * Copy assignment operator.
155 */
156 SharedObject& operator=(const SharedObject& other) noexcept
157 {
158 /* Use generic "copy" assignment operator */
159 return this->operator=<ObjT, LibObjT>(other);
160 }
161
162 /*
163 * Move assignment operator.
164 */
165 SharedObject& operator=(SharedObject&& other) noexcept
166 {
167 /* Use generic "move" assignment operator */
168 return this->operator=<ObjT, LibObjT>(std::move(other));
169 }
170
171 /*
172 * Generic "copy" constructor.
173 *
174 * See the `friend class SharedObject` comment above.
175 */
176 template <typename OtherObjT, typename OtherLibObjT>
177 SharedObject(const SharedObject<OtherObjT, OtherLibObjT, RefFuncsT>& other) noexcept :
178 SharedObject {other, 0}
179 {
180 }
181
182 /*
183 * Generic "move" constructor.
184 *
185 * See the `friend class SharedObject` comment above.
186 */
187 template <typename OtherObjT, typename OtherLibObjT>
188 SharedObject(SharedObject<OtherObjT, OtherLibObjT, RefFuncsT>&& other) noexcept :
189 SharedObject {std::move(other), 0}
190 {
191 }
192
193 /*
194 * Generic "copy" assignment operator.
195 *
196 * See the `friend class SharedObject` comment above.
197 */
198 template <typename OtherObjT, typename OtherLibObjT>
199 SharedObject& operator=(const SharedObject<OtherObjT, OtherLibObjT, RefFuncsT>& other) noexcept
200 {
201 /* Put current object's reference */
202 this->_putRef();
203
204 /* Set new current object and get a reference */
205 _mObj = other._mObj;
206 this->_getRef();
207
208 return *this;
209 }
210
211 /*
212 * Generic "move" assignment operator.
213 *
214 * See the `friend class SharedObject` comment above.
215 */
216 template <typename OtherObjT, typename OtherLibObjT>
217 SharedObject& operator=(SharedObject<OtherObjT, OtherLibObjT, RefFuncsT>&& other) noexcept
218 {
219 /* Put current object's reference */
220 this->_putRef();
221
222 /* Set new current object */
223 _mObj = other._mObj;
224
225 /* Reset moved-from object */
226 other._reset();
227
228 return *this;
229 }
230
231 ~SharedObject()
232 {
233 this->_putRef();
234 }
235
236 ObjT operator*() const noexcept
237 {
238 BT_ASSERT_DBG(_mObj);
239 return *_mObj;
240 }
241
242 BorrowedObjectProxy<ObjT> operator->() const noexcept
243 {
244 BT_ASSERT_DBG(_mObj);
245 return _mObj.operator->();
246 }
247
248 operator bool() const noexcept
249 {
250 return _mObj.hasObject();
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
264 /*
265 * Transfers the reference of the object which this shared object
266 * wrapper manages and returns it, making the caller become an
267 * active owner.
268 *
269 * This method makes this object empty.
270 */
271 ObjT release() noexcept
272 {
273 BT_ASSERT_DBG(_mObj);
274
275 const auto obj = *_mObj;
276
277 this->_reset();
278 return obj;
279 }
280
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 {
298 RefFuncsT::get(_mObj.libObjPtr());
299 }
300
301 /*
302 * Puts a reference using the configured libbabeltrace2 reference
303 * decrementation function.
304 */
305 void _putRef() const noexcept
306 {
307 RefFuncsT::put(_mObj.libObjPtr());
308 }
309
310 OptionalBorrowedObject<ObjT> _mObj;
311 };
312
313 } /* namespace bt2 */
314
315 #endif /* BABELTRACE_CPP_COMMON_BT2_SHARED_OBJECT_HPP */
This page took 0.03603 seconds and 3 git commands to generate.