2 * Copyright (c) 2023 Philippe Proulx <pproulx@efficios.com>
4 * SPDX-License-Identifier: MIT
7 #ifndef BABELTRACE_CPP_COMMON_BT2_OPTIONAL_BORROWED_OBJECT_HPP
8 #define BABELTRACE_CPP_COMMON_BT2_OPTIONAL_BORROWED_OBJECT_HPP
10 #include <type_traits>
12 #include "borrowed-object-proxy.hpp"
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.
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.
26 * There's no `bt2s::nullopt` equivalent: just use the default
27 * constructor or call reset().
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:
34 * auto sharedIntVal = createValue(23L);
36 * OptionalBorrowedObject<Value> myVal {*sharedIntVal};
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.
42 template <typename ObjT>
43 class OptionalBorrowedObject final
47 using LibObjPtr = typename ObjT::LibObjPtr;
50 * Builds an optional borrowed object without an object.
52 * Intentionally not explicit.
54 OptionalBorrowedObject() noexcept = default;
57 * Builds an optional borrowed object with an instance of `ObjT`
58 * wrapping the libbabeltrace2 pointer `libObjPtr`.
60 * Intentionally not explicit.
62 OptionalBorrowedObject(const LibObjPtr libObjPtr) noexcept : _mLibObjPtr {libObjPtr}
67 * Builds an optional borrowed object with an instance of `ObjT`
68 * constructed from `obj`.
70 * It must be possible to construct an instance of `ObjT` with an
71 * instance of `OtherObjT`.
73 * Intentionally not explicit.
75 template <typename OtherObjT>
76 OptionalBorrowedObject(const OtherObjT obj) noexcept : _mLibObjPtr {obj.libObjPtr()}
78 static_assert(std::is_constructible<ObjT, OtherObjT>::value,
79 "`ObjT` is constructible with an instance of `OtherObjT`.");
83 * Builds an optional borrowed object from `optObj`, with or without
86 * It must be possible to construct an instance of `ObjT` with an
87 * instance of `OtherObjT`.
89 * Intentionally not explicit.
91 template <typename OtherObjT>
92 OptionalBorrowedObject(const OptionalBorrowedObject<OtherObjT> optObj) noexcept :
93 _mLibObjPtr {optObj.libObjPtr()}
95 static_assert(std::is_constructible<ObjT, OtherObjT>::value,
96 "`ObjT` is constructible with an instance of `OtherObjT`.");
100 * Makes this optional borrowed object have an instance of `ObjT`
101 * wrapping the libbabeltrace2 pointer `libObjPtr`.
103 OptionalBorrowedObject& operator=(const LibObjPtr libObjPtr) noexcept
105 _mLibObjPtr = libObjPtr;
110 * Makes this optional borrowed object have an instance of `ObjT`
111 * constructed from `obj`.
113 * It must be possible to construct an instance of `ObjT` with an
114 * instance of `OtherObjT`.
116 template <typename OtherObjT>
117 OptionalBorrowedObject& operator=(const ObjT obj) noexcept
119 static_assert(std::is_constructible<ObjT, OtherObjT>::value,
120 "`ObjT` is constructible with an instance of `OtherObjT`.");
121 _mLibObjPtr = obj.libObjPtr();
126 * Sets this optional borrowed object to `optObj`.
128 * It must be possible to construct an instance of `ObjT` with an
129 * instance of `OtherObjT`.
131 template <typename OtherObjT>
132 OptionalBorrowedObject& operator=(const OptionalBorrowedObject<ObjT> optObj) noexcept
134 static_assert(std::is_constructible<ObjT, OtherObjT>::value,
135 "`ObjT` is constructible with an instance of `OtherObjT`.");
136 _mLibObjPtr = optObj.libObjPtr();
140 /* Wrapped libbabeltrace2 object pointer (may be `nullptr`) */
141 LibObjPtr libObjPtr() const noexcept
146 ObjT object() const noexcept
148 return ObjT {_mLibObjPtr};
151 ObjT operator*() const noexcept
153 return this->object();
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`.
161 * Therefore, return a proxy object which holds an internal
162 * `ObjT` instance and implements operator->() itself.
164 * In other words, doing `myOptObj->something()` is equivalent to
165 * calling `myOptObj.operator->().operator->()->something()`.
167 BorrowedObjectProxy<ObjT> operator->() const noexcept
169 return BorrowedObjectProxy<ObjT> {_mLibObjPtr};
172 bool hasObject() const noexcept
177 explicit operator bool() const noexcept
179 return this->hasObject();
182 void reset() noexcept
184 _mLibObjPtr = nullptr;
188 typename ObjT::LibObjPtr _mLibObjPtr = nullptr;
191 } /* namespace bt2 */
193 #endif /* BABELTRACE_CPP_COMMON_BT2_OPTIONAL_BORROWED_OBJECT_HPP */