ArmNN
 25.11
Loading...
Searching...
No Matches
Optional.hpp
Go to the documentation of this file.
1//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5#pragma once
6
7#include "Exceptions.hpp"
8
9#include <cstring>
10#include <type_traits>
11
12/// Optional is a drop in replacement for std::optional until we migrate
13/// to c++-17. Only a subset of the optional features are implemented that
14/// we intend to use in ArmNN.
15
16/// There are two distinct implementations here:
17///
18/// 1, for normal constructable/destructable types and reference types
19/// 2, for reference types
20
21/// The std::optional features we support are:
22///
23/// - has_value() and operator bool() to tell if the optional has a value
24/// - value() returns a reference to the held object
25///
26
27namespace armnn
28{
29
30/// EmptyOptional is used to initialize the Optional class in case we want
31/// to have default value for an Optional in a function declaration.
32struct EmptyOptional {};
33
34/// Disambiguation tag that can be passed to the constructor to indicate that
35/// the contained object should be constructed in-place
37{
38 explicit ConstructInPlace() = default;
39};
40
41#define CONSTRUCT_IN_PLACE armnn::ConstructInPlace{}
42
43/// OptionalBase is the common functionality between reference and non-reference
44/// optional types.
46{
47public:
48 OptionalBase() noexcept
49 : m_HasValue{false}
50 {
51 }
52
53 bool has_value() const noexcept
54 {
55 return m_HasValue;
56 }
57
58 /// Conversion to bool, so can be used in if-statements and similar contexts expecting a bool.
59 /// Note this is explicit so that it doesn't get implicitly converted to a bool in unwanted cases,
60 /// for example "Optional<TypeA> == Optional<TypeB>" should not compile.
61 explicit operator bool() const noexcept
62 {
63 return has_value();
64 }
65
66protected:
67 OptionalBase(bool hasValue) noexcept
68 : m_HasValue{hasValue}
69 {
70 }
71
73};
74
75///
76/// The default implementation is the non-reference case. This
77/// has an unsigned char array for storing the optional value which
78/// is in-place constructed there.
79///
80template <bool IsReference, typename T>
82{
83public:
85
86 OptionalReferenceSwitch() noexcept : Base{} {}
88
90 : Base{}
91 {
92 Construct(value);
93 }
94
95 template<class... Args>
97 : Base{}
98 {
99 Construct(CONSTRUCT_IN_PLACE, std::forward<Args>(args)...);
100 }
101
103 : Base{}
104 {
105 *this = other;
106 }
107
109 {
110 reset();
111 Construct(value);
112 return *this;
113 }
114
116 {
117 reset();
118 if (other.has_value())
119 {
120 Construct(other.value());
121 }
122
123 return *this;
124 }
125
127 {
128 reset();
129 return *this;
130 }
131
133 {
134 reset();
135 }
136
137 void reset()
138 {
139 if (Base::has_value())
140 {
141 value().T::~T();
142 Base::m_HasValue = false;
143 }
144 }
145
146 const T& value() const
147 {
148 if (!Base::has_value())
149 {
150 throw BadOptionalAccessException("Optional has no value");
151 }
152
153 auto valuePtr = reinterpret_cast<const T*>(m_Storage);
154 return *valuePtr;
155 }
156
157 T& value()
158 {
159 if (!Base::has_value())
160 {
161 throw BadOptionalAccessException("Optional has no value");
162 }
163
164 auto valuePtr = reinterpret_cast<T*>(m_Storage);
165 return *valuePtr;
166 }
167
168private:
169 void Construct(const T& value)
170 {
171 new (m_Storage) T(value);
172 m_HasValue = true;
173 }
174
175 template<class... Args>
176 void Construct(ConstructInPlace, Args&&... args)
177 {
178 new (m_Storage) T(std::forward<Args>(args)...);
179 m_HasValue = true;
180 }
181
182 alignas(alignof(T)) unsigned char m_Storage[sizeof(T)] = {};
183};
184
185///
186/// This is the special case for reference types. This holds a pointer
187/// to the referenced type. This doesn't own the referenced memory and
188/// it never calls delete on the pointer.
189///
190template <typename T>
192{
193public:
195 using NonRefT = typename std::remove_reference<T>::type;
196
197 OptionalReferenceSwitch() noexcept : Base{}, m_Storage{nullptr} {}
198 OptionalReferenceSwitch(EmptyOptional) noexcept : Base{}, m_Storage{nullptr} {}
199
201 {
202 *this = other;
203 }
204
206 : Base{true}
207 , m_Storage{&value}
208 {
209 }
210
211 template<class... Args>
212 OptionalReferenceSwitch(ConstructInPlace, Args&&... args) = delete;
213
215 {
216 m_Storage = &value;
217 Base::m_HasValue = true;
218 return *this;
219 }
220
222 {
223 m_Storage = other.m_Storage;
224 Base::m_HasValue = other.has_value();
225 return *this;
226 }
227
229 {
230 reset();
231 return *this;
232 }
233
235 {
236 reset();
237 }
238
239 void reset()
240 {
241 Base::m_HasValue = false;
242 m_Storage = nullptr;
243 }
244
245 const T value() const
246 {
247 if (!Base::has_value())
248 {
249 throw BadOptionalAccessException("Optional has no value");
250 }
251
252 return *m_Storage;
253 }
254
256 {
257 if (!Base::has_value())
258 {
259 throw BadOptionalAccessException("Optional has no value");
260 }
261
262 return *m_Storage;
263 }
264
265private:
266 NonRefT* m_Storage;
267};
268
269template <typename T>
270class Optional final : public OptionalReferenceSwitch<std::is_reference<T>::value, T>
271{
272public:
274
275 Optional() noexcept : BaseSwitch{} {}
277 Optional& operator=(const Optional& other) = default;
279 Optional(const Optional& other) : BaseSwitch{other} {}
280 Optional(const BaseSwitch& other) : BaseSwitch{other} {}
281
282 template<class... Args>
283 explicit Optional(ConstructInPlace, Args&&... args) :
284 BaseSwitch(CONSTRUCT_IN_PLACE, std::forward<Args>(args)...) {}
285
286 /// Two optionals are considered equal if they are both empty or both contain values which
287 /// themselves are considered equal (via their own == operator).
288 bool operator==(const Optional<T>& rhs) const
289 {
290 if (!this->has_value() && !rhs.has_value())
291 {
292 return true;
293 }
294 if (this->has_value() && rhs.has_value() && this->value() == rhs.value())
295 {
296 return true;
297 }
298 return false;
299 }
300};
301
302/// Utility template that constructs an object of type T in-place and wraps
303/// it inside an Optional<T> object
304template<typename T, class... Args>
306{
307 return Optional<T>(CONSTRUCT_IN_PLACE, std::forward<Args>(args)...);
308}
309
310}
#define CONSTRUCT_IN_PLACE
Definition Optional.hpp:41
OptionalBase(bool hasValue) noexcept
Definition Optional.hpp:67
bool has_value() const noexcept
Definition Optional.hpp:53
OptionalBase() noexcept
Definition Optional.hpp:48
Optional() noexcept
Definition Optional.hpp:275
Optional(ConstructInPlace, Args &&... args)
Definition Optional.hpp:283
Optional(EmptyOptional empty)
Definition Optional.hpp:278
bool operator==(const Optional< T > &rhs) const
Two optionals are considered equal if they are both empty or both contain values which themselves are...
Definition Optional.hpp:288
Optional(const Optional &other)
Definition Optional.hpp:279
OptionalReferenceSwitch< std::is_reference< T >::value, T > BaseSwitch
Definition Optional.hpp:273
Optional(const BaseSwitch &other)
Definition Optional.hpp:280
Optional(const T &value)
Definition Optional.hpp:276
Optional & operator=(const Optional &other)=default
OptionalReferenceSwitch & operator=(EmptyOptional)
Definition Optional.hpp:228
OptionalReferenceSwitch(EmptyOptional) noexcept
Definition Optional.hpp:198
OptionalReferenceSwitch(ConstructInPlace, Args &&... args)=delete
OptionalReferenceSwitch(const OptionalReferenceSwitch &other)
Definition Optional.hpp:200
typename std::remove_reference< T >::type NonRefT
Definition Optional.hpp:195
OptionalReferenceSwitch & operator=(const T value)
Definition Optional.hpp:214
OptionalReferenceSwitch & operator=(const OptionalReferenceSwitch &other)
Definition Optional.hpp:221
OptionalReferenceSwitch & operator=(const T &value)
Definition Optional.hpp:108
OptionalReferenceSwitch & operator=(EmptyOptional)
Definition Optional.hpp:126
OptionalReferenceSwitch(EmptyOptional) noexcept
Definition Optional.hpp:87
OptionalReferenceSwitch(ConstructInPlace, Args &&... args)
Definition Optional.hpp:96
OptionalReferenceSwitch(const OptionalReferenceSwitch &other)
Definition Optional.hpp:102
OptionalReferenceSwitch(const T &value)
Definition Optional.hpp:89
OptionalReferenceSwitch & operator=(const OptionalReferenceSwitch &other)
Definition Optional.hpp:115
Copyright (c) 2021 ARM Limited and Contributors.
Optional< T > MakeOptional(Args &&... args)
Utility template that constructs an object of type T in-place and wraps it inside an Optional<T> obje...
Definition Optional.hpp:305
Disambiguation tag that can be passed to the constructor to indicate that the contained object should...
Definition Optional.hpp:37
EmptyOptional is used to initialize the Optional class in case we want to have default value for an O...
Definition Optional.hpp:32