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 | ||
48 | public: | |
49 | // This complete shared object | |
50 | using ThisSharedObj = SharedObj<ObjT, LibObjT, RefFuncsT>; | |
51 | ||
52 | /* | |
53 | * Builds a shared object from `obj` without an initial reference. | |
54 | * | |
55 | * Use this constructor to build a shared object wrapping a newly | |
56 | * created libbabeltrace2 object. | |
57 | * | |
58 | * Use createWithInitialRef() to build a shared object having an | |
59 | * initial reference count. | |
60 | */ | |
61 | explicit SharedObj(const ObjT& obj) noexcept : _mObj {obj} | |
62 | { | |
63 | } | |
64 | ||
65 | /* | |
66 | * Builds a shared object from `obj` with an initial reference. | |
67 | * | |
68 | * Use this constructor to build a shared object wrapping a newly | |
69 | * created libbabeltrace2 object. | |
70 | */ | |
71 | static ThisSharedObj createWithInitialRef(const ObjT& obj) noexcept | |
72 | { | |
73 | ThisSharedObj sharedObj {obj}; | |
74 | ||
75 | sharedObj._getRef(); | |
76 | return sharedObj; | |
77 | } | |
78 | ||
79 | /* | |
80 | * Generic copy constructor. | |
81 | * | |
82 | * See the `friend class SharedObj` comment above. | |
83 | */ | |
84 | template <typename OtherObjT, typename OtherLibObjT> | |
85 | SharedObj(const SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>& other) noexcept : | |
86 | _mObj {other._mObj} | |
87 | { | |
88 | this->_getRef(); | |
89 | } | |
90 | ||
91 | /* | |
92 | * Generic move constructor. | |
93 | * | |
94 | * See the `friend class SharedObj` comment above. | |
95 | */ | |
96 | template <typename OtherObjT, typename OtherLibObjT> | |
97 | SharedObj(SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>&& other) noexcept : _mObj {other._mObj} | |
98 | { | |
99 | // Reset moved-from object | |
100 | other._reset(); | |
101 | } | |
102 | ||
103 | /* | |
104 | * Generic copy assignment operator. | |
105 | * | |
106 | * See the `friend class SharedObj` comment above. | |
107 | */ | |
108 | template <typename OtherObjT, typename OtherLibObjT> | |
109 | ThisSharedObj& operator=(const SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>& other) noexcept | |
110 | { | |
111 | // Put current object's reference | |
112 | this->_putRef(); | |
113 | ||
114 | // Set new current object and get a reference | |
115 | _mObj = other._mObj; | |
116 | this->_getRef(); | |
117 | ||
118 | return *this; | |
119 | } | |
120 | ||
121 | /* | |
122 | * Generic move assignment operator. | |
123 | * | |
124 | * See the `friend class SharedObj` comment above. | |
125 | */ | |
126 | template <typename OtherObjT, typename OtherLibObjT> | |
127 | ThisSharedObj& operator=(SharedObj<OtherObjT, OtherLibObjT, RefFuncsT>&& other) noexcept | |
128 | { | |
129 | // Put current object's reference | |
130 | this->_putRef(); | |
131 | ||
132 | // Set new current object | |
133 | _mObj = other._mObj; | |
134 | ||
135 | // Reset moved-from object | |
136 | other._reset(); | |
137 | ||
138 | return *this; | |
139 | } | |
140 | ||
141 | ~SharedObj() | |
142 | { | |
143 | this->_putRef(); | |
144 | } | |
145 | ||
146 | ObjT& operator*() noexcept | |
147 | { | |
148 | BT_ASSERT_DBG(_mObj); | |
149 | return *_mObj; | |
150 | } | |
151 | ||
152 | const ObjT& operator*() const noexcept | |
153 | { | |
154 | BT_ASSERT_DBG(_mObj); | |
155 | return *_mObj; | |
156 | } | |
157 | ||
158 | ObjT *operator->() noexcept | |
159 | { | |
160 | BT_ASSERT_DBG(_mObj); | |
161 | return &*_mObj; | |
162 | } | |
163 | ||
164 | const ObjT *operator->() const noexcept | |
165 | { | |
166 | BT_ASSERT_DBG(_mObj); | |
167 | return &*_mObj; | |
168 | } | |
169 | ||
170 | private: | |
171 | /* | |
172 | * Resets this shared object. | |
173 | * | |
174 | * To be used when moving it. | |
175 | */ | |
176 | void _reset() noexcept | |
177 | { | |
178 | _mObj.reset(); | |
179 | } | |
180 | ||
181 | /* | |
182 | * Gets a new reference using the configured libbabeltrace2 | |
183 | * reference incrementation function. | |
184 | */ | |
185 | void _getRef() const noexcept | |
186 | { | |
187 | if (_mObj) { | |
188 | RefFuncsT::get(_mObj->_libObjPtr()); | |
189 | } | |
190 | } | |
191 | ||
192 | /* | |
193 | * Puts a reference using the configured libbabeltrace2 reference | |
194 | * decrementation function. | |
195 | */ | |
196 | void _putRef() const noexcept | |
197 | { | |
198 | if (_mObj) { | |
199 | RefFuncsT::put(_mObj->_libObjPtr()); | |
200 | } | |
201 | } | |
202 | ||
203 | nonstd::optional<ObjT> _mObj; | |
204 | }; | |
205 | ||
206 | } // namespace internal | |
207 | } // namespace bt2 | |
208 | ||
209 | #endif // BABELTRACE_CPP_COMMON_BT2_INTERNAL_SHARED_OBJ_HPP |