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