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 "common/assert.h"
14 #include "borrowed-object-proxy.hpp"
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.
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.
28 * There's no `bt2s::nullopt` equivalent: just use the default
29 * constructor or call reset().
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:
36 * auto sharedIntVal = createValue(23L);
38 * OptionalBorrowedObject<Value> myVal {*sharedIntVal};
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.
44 template <typename ObjT>
45 class OptionalBorrowedObject final
49 using LibObjPtr = typename ObjT::LibObjPtr;
52 * Builds an optional borrowed object without an object.
54 * Intentionally not explicit.
56 OptionalBorrowedObject() noexcept = default;
59 * Builds an optional borrowed object with an instance of `ObjT`
60 * wrapping the libbabeltrace2 pointer `libObjPtr`.
62 * Intentionally not explicit.
64 OptionalBorrowedObject(const LibObjPtr libObjPtr) noexcept : _mLibObjPtr {libObjPtr}
69 * Builds an optional borrowed object with an instance of `ObjT`
70 * constructed from `obj`.
72 * It must be possible to construct an instance of `ObjT` with an
73 * instance of `OtherObjT`.
75 * Intentionally not explicit.
77 template <typename OtherObjT>
78 OptionalBorrowedObject(const OtherObjT obj) noexcept : _mLibObjPtr {obj.libObjPtr()}
80 static_assert(std::is_constructible<ObjT, OtherObjT>::value,
81 "`ObjT` is constructible with an instance of `OtherObjT`.");
85 * Builds an optional borrowed object from `optObj`, with or without
88 * It must be possible to construct an instance of `ObjT` with an
89 * instance of `OtherObjT`.
91 * Intentionally not explicit.
93 template <typename OtherObjT>
94 OptionalBorrowedObject(const OptionalBorrowedObject<OtherObjT> optObj) noexcept :
95 _mLibObjPtr {optObj.libObjPtr()}
97 static_assert(std::is_constructible<ObjT, OtherObjT>::value,
98 "`ObjT` is constructible with an instance of `OtherObjT`.");
102 * Makes this optional borrowed object have an instance of `ObjT`
103 * wrapping the libbabeltrace2 pointer `libObjPtr`.
105 OptionalBorrowedObject& operator=(const LibObjPtr libObjPtr) noexcept
107 _mLibObjPtr = libObjPtr;
112 * Makes this optional borrowed object have an instance of `ObjT`
113 * constructed from `obj`.
115 * It must be possible to construct an instance of `ObjT` with an
116 * instance of `OtherObjT`.
118 template <typename OtherObjT>
119 OptionalBorrowedObject& operator=(const ObjT obj) noexcept
121 static_assert(std::is_constructible<ObjT, OtherObjT>::value,
122 "`ObjT` is constructible with an instance of `OtherObjT`.");
123 _mLibObjPtr = obj.libObjPtr();
128 * Sets this optional borrowed object to `optObj`.
130 * It must be possible to construct an instance of `ObjT` with an
131 * instance of `OtherObjT`.
133 template <typename OtherObjT>
134 OptionalBorrowedObject& operator=(const OptionalBorrowedObject<ObjT> optObj) noexcept
136 static_assert(std::is_constructible<ObjT, OtherObjT>::value,
137 "`ObjT` is constructible with an instance of `OtherObjT`.");
138 _mLibObjPtr = optObj.libObjPtr();
142 /* Wrapped libbabeltrace2 object pointer (may be `nullptr`) */
143 LibObjPtr libObjPtr() const noexcept
148 ObjT object() const noexcept
150 BT_ASSERT_DBG(_mLibObjPtr);
151 return ObjT {_mLibObjPtr};
154 ObjT operator*() const noexcept
156 return this->object();
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`.
164 * Therefore, return a proxy object which holds an internal
165 * `ObjT` instance and implements operator->() itself.
167 * In other words, doing `myOptObj->something()` is equivalent to
168 * calling `myOptObj.operator->().operator->()->something()`.
170 BorrowedObjectProxy<ObjT> operator->() const noexcept
172 return BorrowedObjectProxy<ObjT> {_mLibObjPtr};
175 bool hasObject() const noexcept
180 operator bool() const noexcept
182 return this->hasObject();
185 void reset() noexcept
187 _mLibObjPtr = nullptr;
191 typename ObjT::LibObjPtr _mLibObjPtr = nullptr;
194 } /* namespace bt2 */
196 #endif /* BABELTRACE_CPP_COMMON_BT2_OPTIONAL_BORROWED_OBJECT_HPP */