100abf4def965da8b4ccc25ea4d1c46a58c1ab82
[babeltrace.git] / src / cpp-common / bt2 / optional-borrowed-object.hpp
1 /*
2 * Copyright (c) 2023 Philippe Proulx <pproulx@efficios.com>
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7 #ifndef BABELTRACE_CPP_COMMON_BT2_OPTIONAL_BORROWED_OBJECT_HPP
8 #define BABELTRACE_CPP_COMMON_BT2_OPTIONAL_BORROWED_OBJECT_HPP
9
10 #include <type_traits>
11
12 #include "common/assert.h"
13
14 #include "borrowed-object-proxy.hpp"
15
16 namespace bt2 {
17
18 /*
19 * An instance of this class template manages an optional contained
20 * borrowed object of type `ObjT`, that is, a borrowed object that may
21 * or may not be present.
22 *
23 * Such an object considers that a `nullptr` libbabeltrace2 object
24 * pointer means none. Therefore, using an `OptionalBorrowedObject`
25 * isn't more costly, in time and space, as using a libbabeltrace2
26 * object pointer in C, but offers the typical C++ optional interface.
27 *
28 * There's no `bt2s::nullopt` equivalent: just use the default
29 * constructor or call reset().
30 *
31 * There are a constructors an assignment operators which accept an
32 * instance of another wrapper object or of another optional borrowed
33 * object. For those, static assertions make sure that the assignment
34 * would work with borrowed objects, for example:
35 *
36 * auto sharedIntVal = createValue(23L);
37 *
38 * OptionalBorrowedObject<Value> myVal {*sharedIntVal};
39 *
40 * This is needed because `OptionalBorrowedObject` only keeps a
41 * libbabeltrace2 pointer (`_mLibObjPtr`), therefore it doesn't
42 * automatically know the relation between wrapper classes.
43 */
44 template <typename ObjT>
45 class OptionalBorrowedObject final
46 {
47 public:
48 using Obj = ObjT;
49 using LibObjPtr = typename ObjT::LibObjPtr;
50
51 /*
52 * Builds an optional borrowed object without an object.
53 *
54 * Intentionally not explicit.
55 */
56 OptionalBorrowedObject() noexcept = default;
57
58 /*
59 * Builds an optional borrowed object with an instance of `ObjT`
60 * wrapping the libbabeltrace2 pointer `libObjPtr`.
61 *
62 * Intentionally not explicit.
63 */
64 OptionalBorrowedObject(const LibObjPtr libObjPtr) noexcept : _mLibObjPtr {libObjPtr}
65 {
66 }
67
68 /*
69 * Builds an optional borrowed object with an instance of `ObjT`
70 * constructed from `obj`.
71 *
72 * It must be possible to construct an instance of `ObjT` with an
73 * instance of `OtherObjT`.
74 *
75 * Intentionally not explicit.
76 */
77 template <typename OtherObjT>
78 OptionalBorrowedObject(const OtherObjT obj) noexcept : _mLibObjPtr {obj.libObjPtr()}
79 {
80 static_assert(std::is_constructible<ObjT, OtherObjT>::value,
81 "`ObjT` is constructible with an instance of `OtherObjT`.");
82 }
83
84 /*
85 * Builds an optional borrowed object from `optObj`, with or without
86 * an object.
87 *
88 * It must be possible to construct an instance of `ObjT` with an
89 * instance of `OtherObjT`.
90 *
91 * Intentionally not explicit.
92 */
93 template <typename OtherObjT>
94 OptionalBorrowedObject(const OptionalBorrowedObject<OtherObjT> optObj) noexcept :
95 _mLibObjPtr {optObj.libObjPtr()}
96 {
97 static_assert(std::is_constructible<ObjT, OtherObjT>::value,
98 "`ObjT` is constructible with an instance of `OtherObjT`.");
99 }
100
101 /*
102 * Makes this optional borrowed object have an instance of `ObjT`
103 * wrapping the libbabeltrace2 pointer `libObjPtr`.
104 */
105 OptionalBorrowedObject& operator=(const LibObjPtr libObjPtr) noexcept
106 {
107 _mLibObjPtr = libObjPtr;
108 return *this;
109 }
110
111 /*
112 * Makes this optional borrowed object have an instance of `ObjT`
113 * constructed from `obj`.
114 *
115 * It must be possible to construct an instance of `ObjT` with an
116 * instance of `OtherObjT`.
117 */
118 template <typename OtherObjT>
119 OptionalBorrowedObject& operator=(const ObjT obj) noexcept
120 {
121 static_assert(std::is_constructible<ObjT, OtherObjT>::value,
122 "`ObjT` is constructible with an instance of `OtherObjT`.");
123 _mLibObjPtr = obj.libObjPtr();
124 return *this;
125 }
126
127 /*
128 * Sets this optional borrowed object to `optObj`.
129 *
130 * It must be possible to construct an instance of `ObjT` with an
131 * instance of `OtherObjT`.
132 */
133 template <typename OtherObjT>
134 OptionalBorrowedObject& operator=(const OptionalBorrowedObject<ObjT> optObj) noexcept
135 {
136 static_assert(std::is_constructible<ObjT, OtherObjT>::value,
137 "`ObjT` is constructible with an instance of `OtherObjT`.");
138 _mLibObjPtr = optObj.libObjPtr();
139 return *this;
140 }
141
142 /* Wrapped libbabeltrace2 object pointer (may be `nullptr`) */
143 LibObjPtr libObjPtr() const noexcept
144 {
145 return _mLibObjPtr;
146 }
147
148 ObjT object() const noexcept
149 {
150 BT_ASSERT_DBG(_mLibObjPtr);
151 return ObjT {_mLibObjPtr};
152 }
153
154 ObjT operator*() const noexcept
155 {
156 return this->object();
157 }
158
159 /*
160 * We want to return the address of an `ObjT` instance here, but we
161 * only have a library pointer (`_mLibObjPtr`) because an `ObjT`
162 * instance may not wrap `nullptr`.
163 *
164 * Therefore, return a proxy object which holds an internal
165 * `ObjT` instance and implements operator->() itself.
166 *
167 * In other words, doing `myOptObj->something()` is equivalent to
168 * calling `myOptObj.operator->().operator->()->something()`.
169 */
170 BorrowedObjectProxy<ObjT> operator->() const noexcept
171 {
172 return BorrowedObjectProxy<ObjT> {_mLibObjPtr};
173 }
174
175 bool hasObject() const noexcept
176 {
177 return _mLibObjPtr;
178 }
179
180 operator bool() const noexcept
181 {
182 return this->hasObject();
183 }
184
185 void reset() noexcept
186 {
187 _mLibObjPtr = nullptr;
188 }
189
190 private:
191 typename ObjT::LibObjPtr _mLibObjPtr = nullptr;
192 };
193
194 } /* namespace bt2 */
195
196 #endif /* BABELTRACE_CPP_COMMON_BT2_OPTIONAL_BORROWED_OBJECT_HPP */
This page took 0.033845 seconds and 3 git commands to generate.