cpp-common/bt2: add `bt2::OptionalBorrowedObject`
[babeltrace.git] / src / cpp-common / bt2 / shared-object.hpp
... / ...
CommitLineData
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 "common/assert.h"
11#include "cpp-common/bt2s/optional.hpp"
12
13namespace bt2 {
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 *
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.
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 */
37template <typename ObjT, typename LibObjT, typename RefFuncsT>
38class SharedObject final
39{
40 /*
41 * This makes it possible for a
42 * `SharedObject<Something, bt_something, ...>` instance to get
43 * assigned an instance of
44 * `SharedObject<SpecificSomething, bt_something, ...>` (copy/move
45 * constructors and assignment operators), given that
46 * `SpecificSomething` inherits `Something`.
47 */
48 template <typename, typename, typename>
49 friend class SharedObject;
50
51public:
52 /*
53 * Builds an empty shared object.
54 */
55 explicit SharedObject() noexcept
56 {
57 }
58
59private:
60 /*
61 * Builds a shared object from `obj` without getting a reference.
62 */
63 explicit SharedObject(const ObjT& obj) noexcept : _mObj {obj}
64 {
65 }
66
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>
78 SharedObject(const SharedObject<OtherObjT, OtherLibObjT, RefFuncsT>& other, int) noexcept :
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>
90 SharedObject(SharedObject<OtherObjT, OtherLibObjT, RefFuncsT>&& other, int) noexcept :
91 _mObj {other._mObj}
92 {
93 /* Reset moved-from object */
94 other._reset();
95 }
96
97public:
98 /*
99 * Builds a shared object from `obj` without getting a reference.
100 */
101 static SharedObject createWithoutRef(const ObjT& obj) noexcept
102 {
103 return SharedObject {obj};
104 }
105
106 /*
107 * Builds a shared object from `libObjPtr` without getting a
108 * reference.
109 */
110 static SharedObject createWithoutRef(LibObjT * const libObjPtr) noexcept
111 {
112 return SharedObject::createWithoutRef(ObjT {libObjPtr});
113 }
114
115 /*
116 * Builds a shared object from `obj`, immediately getting a new
117 * reference.
118 */
119 static SharedObject createWithRef(const ObjT& obj) noexcept
120 {
121 SharedObject sharedObj {obj};
122
123 sharedObj._getRef();
124 return sharedObj;
125 }
126
127 /*
128 * Builds a shared object from `libObjPtr`, immediately getting a
129 * new reference.
130 */
131 static SharedObject createWithRef(LibObjT * const libObjPtr) noexcept
132 {
133 return SharedObject::createWithRef(ObjT {libObjPtr});
134 }
135
136 /*
137 * Copy constructor.
138 */
139 SharedObject(const SharedObject& other) noexcept : SharedObject {other, 0}
140 {
141 }
142
143 /*
144 * Move constructor.
145 */
146 SharedObject(SharedObject&& other) noexcept : SharedObject {std::move(other), 0}
147 {
148 }
149
150 /*
151 * Copy assignment operator.
152 */
153 SharedObject& operator=(const SharedObject& other) noexcept
154 {
155 /* Use generic "copy" assignment operator */
156 return this->operator=<ObjT, LibObjT>(other);
157 }
158
159 /*
160 * Move assignment operator.
161 */
162 SharedObject& operator=(SharedObject&& other) noexcept
163 {
164 /* Use generic "move" assignment operator */
165 return this->operator=<ObjT, LibObjT>(std::move(other));
166 }
167
168 /*
169 * Generic "copy" constructor.
170 *
171 * See the `friend class SharedObject` comment above.
172 */
173 template <typename OtherObjT, typename OtherLibObjT>
174 SharedObject(const SharedObject<OtherObjT, OtherLibObjT, RefFuncsT>& other) noexcept :
175 SharedObject {other, 0}
176 {
177 }
178
179 /*
180 * Generic "move" constructor.
181 *
182 * See the `friend class SharedObject` comment above.
183 */
184 template <typename OtherObjT, typename OtherLibObjT>
185 SharedObject(SharedObject<OtherObjT, OtherLibObjT, RefFuncsT>&& other) noexcept :
186 SharedObject {std::move(other), 0}
187 {
188 }
189
190 /*
191 * Generic "copy" assignment operator.
192 *
193 * See the `friend class SharedObject` comment above.
194 */
195 template <typename OtherObjT, typename OtherLibObjT>
196 SharedObject& operator=(const SharedObject<OtherObjT, OtherLibObjT, RefFuncsT>& other) noexcept
197 {
198 /* Put current object's reference */
199 this->_putRef();
200
201 /* Set new current object and get a reference */
202 _mObj = other._mObj;
203 this->_getRef();
204
205 return *this;
206 }
207
208 /*
209 * Generic "move" assignment operator.
210 *
211 * See the `friend class SharedObject` comment above.
212 */
213 template <typename OtherObjT, typename OtherLibObjT>
214 SharedObject& operator=(SharedObject<OtherObjT, OtherLibObjT, RefFuncsT>&& other) noexcept
215 {
216 /* Put current object's reference */
217 this->_putRef();
218
219 /* Set new current object */
220 _mObj = other._mObj;
221
222 /* Reset moved-from object */
223 other._reset();
224
225 return *this;
226 }
227
228 ~SharedObject()
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
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
273 /*
274 * Transfers the reference of the object which this shared object
275 * wrapper manages and returns it, making the caller become an
276 * active owner.
277 *
278 * This method makes this object empty.
279 */
280 ObjT release() noexcept
281 {
282 BT_ASSERT_DBG(_mObj);
283
284 const auto obj = *_mObj;
285
286 this->_reset();
287 return obj;
288 }
289
290private:
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) {
308 RefFuncsT::get(_mObj->libObjPtr());
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) {
319 RefFuncsT::put(_mObj->libObjPtr());
320 }
321 }
322
323 bt2s::optional<ObjT> _mObj;
324};
325
326} /* namespace bt2 */
327
328#endif /* BABELTRACE_CPP_COMMON_BT2_SHARED_OBJECT_HPP */
This page took 0.023579 seconds and 4 git commands to generate.