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