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