Commit | Line | Data |
---|---|---|
01bf7a3a PP |
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_INTERNAL_SHARED_OBJ_HPP | |
8 | #define BABELTRACE_CPP_COMMON_BT2_INTERNAL_SHARED_OBJ_HPP | |
9 | ||
10 | #include "common/assert.h" | |
11 | #include "cpp-common/optional.hpp" | |
12 | ||
13 | namespace bt2 { | |
14 | namespace internal { | |
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 invalid, in that | |
22 | * operator*() and operator->() will either fail to assert in debug mode | |
23 | * or trigger a segmentation fault. | |
24 | * | |
25 | * `LibObjT` is the direct libbabeltrace2 object type, for example | |
26 | * `bt_stream_class` or `const bt_value`. | |
27 | * | |
28 | * RefFuncsT::get() must accept a `const LibObjT *` value and increment | |
29 | * its reference count. | |
30 | * | |
31 | * RefFuncsT::put() must accept a `const LibObjT *` value and decrement | |
32 | * its reference count. | |
33 | */ | |
34 | template <typename ObjT, typename LibObjT, typename RefFuncsT> | |
35 | class SharedObj final | |
36 | { | |
37 | /* | |
38 | * This makes it possible for a | |
39 | * `SharedObj<Something, bt_something, ...>` instance to get | |
40 | * assigned an instance of | |
41 | * `SharedObj<SpecificSomething, bt_something, ...>` (copy/move | |
42 | * constructor and assignment operator), given that | |
43 | * `SpecificSomething` inherits `Something`. | |
44 | */ | |
45 | template <typename AnyObjT, typename AnyLibObjT, typename AnyRefFuncsT> | |
46 | friend class SharedObj; | |
47 | ||
c9c0b6e2 PP |
48 | private: |
49 | /* | |
50 | * Builds a shared object from `obj` without getting a reference. | |
51 | */ | |
52 | explicit SharedObj(const ObjT& obj) noexcept : _mObj {obj} | |
53 | { | |
54 | } | |
55 | ||
01bf7a3a | 56 | public: |
c9c0b6e2 PP |
57 | /* |
58 | * Builds a shared object from `obj` without getting a reference. | |
59 | */ | |
60 | static SharedObj createWithoutRef(const ObjT& obj) noexcept | |
61 | { | |
62 | return SharedObj {obj}; | |
63 | } | |
01bf7a3a PP |
64 | |
65 | /* | |
c9c0b6e2 PP |
66 | * Builds a shared object from `libObjPtr` without getting a |
67 | * reference. | |
01bf7a3a | 68 | */ |
c9c0b6e2 | 69 | static SharedObj createWithoutRef(LibObjT * const libObjPtr) noexcept |
01bf7a3a | 70 | { |
c9c0b6e2 | 71 | return SharedObj::createWithoutRef(ObjT {libObjPtr}); |
01bf7a3a PP |
72 | } |
73 | ||
74 | /* | |
c9c0b6e2 PP |
75 | * Builds a shared object from `obj`, immediately getting a new |
76 | * reference. | |
01bf7a3a | 77 | */ |
c9c0b6e2 | 78 | static SharedObj createWithRef(const ObjT& obj) noexcept |
01bf7a3a | 79 | { |
c9c0b6e2 | 80 | SharedObj sharedObj {obj}; |
01bf7a3a PP |
81 | |
82 | sharedObj._getRef(); | |
83 | return sharedObj; | |
84 | } | |
85 | ||
c9c0b6e2 PP |
86 | /* |
87 | * Builds a shared object from `libObjPtr`, immediately getting a new | |
88 | * reference. | |
89 | */ | |
90 | static SharedObj createWithRef(LibObjT * const libObjPtr) noexcept | |
91 | { | |
92 | return SharedObj::createWithRef(ObjT {libObjPtr}); | |
93 | } | |
94 | ||
01bf7a3a PP |
95 | /* |
96 | * Generic copy constructor. | |
97 | * | |
98 | * See the `friend class SharedObj` comment above. | |
99 | */ | |
100 | template <typename OtherObjT, typename OtherLibObjT> | |
101 | SharedObj(const SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>& other) noexcept : | |
102 | _mObj {other._mObj} | |
103 | { | |
104 | this->_getRef(); | |
105 | } | |
106 | ||
107 | /* | |
108 | * Generic move constructor. | |
109 | * | |
110 | * See the `friend class SharedObj` comment above. | |
111 | */ | |
112 | template <typename OtherObjT, typename OtherLibObjT> | |
113 | SharedObj(SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>&& other) noexcept : _mObj {other._mObj} | |
114 | { | |
b5f55e9f | 115 | /* Reset moved-from object */ |
01bf7a3a PP |
116 | other._reset(); |
117 | } | |
118 | ||
119 | /* | |
120 | * Generic copy assignment operator. | |
121 | * | |
122 | * See the `friend class SharedObj` comment above. | |
123 | */ | |
124 | template <typename OtherObjT, typename OtherLibObjT> | |
c9c0b6e2 | 125 | SharedObj& operator=(const SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>& other) noexcept |
01bf7a3a | 126 | { |
b5f55e9f | 127 | /* Put current object's reference */ |
01bf7a3a PP |
128 | this->_putRef(); |
129 | ||
b5f55e9f | 130 | /* Set new current object and get a reference */ |
01bf7a3a PP |
131 | _mObj = other._mObj; |
132 | this->_getRef(); | |
133 | ||
134 | return *this; | |
135 | } | |
136 | ||
137 | /* | |
138 | * Generic move assignment operator. | |
139 | * | |
140 | * See the `friend class SharedObj` comment above. | |
141 | */ | |
142 | template <typename OtherObjT, typename OtherLibObjT> | |
c9c0b6e2 | 143 | SharedObj& operator=(SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>&& other) noexcept |
01bf7a3a | 144 | { |
b5f55e9f | 145 | /* Put current object's reference */ |
01bf7a3a PP |
146 | this->_putRef(); |
147 | ||
b5f55e9f | 148 | /* Set new current object */ |
01bf7a3a PP |
149 | _mObj = other._mObj; |
150 | ||
b5f55e9f | 151 | /* Reset moved-from object */ |
01bf7a3a PP |
152 | other._reset(); |
153 | ||
154 | return *this; | |
155 | } | |
156 | ||
157 | ~SharedObj() | |
158 | { | |
159 | this->_putRef(); | |
160 | } | |
161 | ||
162 | ObjT& operator*() noexcept | |
163 | { | |
164 | BT_ASSERT_DBG(_mObj); | |
165 | return *_mObj; | |
166 | } | |
167 | ||
168 | const ObjT& operator*() const noexcept | |
169 | { | |
170 | BT_ASSERT_DBG(_mObj); | |
171 | return *_mObj; | |
172 | } | |
173 | ||
174 | ObjT *operator->() noexcept | |
175 | { | |
176 | BT_ASSERT_DBG(_mObj); | |
177 | return &*_mObj; | |
178 | } | |
179 | ||
180 | const ObjT *operator->() const noexcept | |
181 | { | |
182 | BT_ASSERT_DBG(_mObj); | |
183 | return &*_mObj; | |
184 | } | |
185 | ||
186 | private: | |
187 | /* | |
188 | * Resets this shared object. | |
189 | * | |
190 | * To be used when moving it. | |
191 | */ | |
192 | void _reset() noexcept | |
193 | { | |
194 | _mObj.reset(); | |
195 | } | |
196 | ||
197 | /* | |
198 | * Gets a new reference using the configured libbabeltrace2 | |
199 | * reference incrementation function. | |
200 | */ | |
201 | void _getRef() const noexcept | |
202 | { | |
203 | if (_mObj) { | |
341a67c4 | 204 | RefFuncsT::get(_mObj->libObjPtr()); |
01bf7a3a PP |
205 | } |
206 | } | |
207 | ||
208 | /* | |
209 | * Puts a reference using the configured libbabeltrace2 reference | |
210 | * decrementation function. | |
211 | */ | |
212 | void _putRef() const noexcept | |
213 | { | |
214 | if (_mObj) { | |
341a67c4 | 215 | RefFuncsT::put(_mObj->libObjPtr()); |
01bf7a3a PP |
216 | } |
217 | } | |
218 | ||
219 | nonstd::optional<ObjT> _mObj; | |
220 | }; | |
221 | ||
b5f55e9f PP |
222 | } /* namespace internal */ |
223 | } /* namespace bt2 */ | |
01bf7a3a | 224 | |
b5f55e9f | 225 | #endif /* BABELTRACE_CPP_COMMON_BT2_INTERNAL_SHARED_OBJ_HPP */ |