CVB++ 15.0
optional.hpp
1#pragma once
2
8
13
14#include <exception>
15#include <new>
16#include <utility>
17
18#include "../namespace.hpp"
19#include "utilities.hpp"
20
21namespace Cvb
22{
23
24 CVB_BEGIN_INLINE_NS
25
26 namespace Shims
27 {
28
33 {
34 public:
37 };
38
47 struct nullopt_t
48 {
49 };
50
52 static constexpr nullopt_t nullopt = {};
53
58 template <class T>
59 class optional final // NOLINT(cppcoreguidelines-special-member-functions) requires generated no default move to
60 // work correctly
61 {
62 using Storage = typename std::aligned_storage<sizeof(T), alignof(T)>::type;
63
65 bool has_value_;
67 Storage value_;
68
69 public:
70 using value_type = T;
71
73 optional() noexcept
74 : has_value_(false)
75 {
76 }
77
79 optional(nullopt_t) noexcept // NOLINT
80 : has_value_(false)
81 {
82 }
83
90 template <class... ARGS>
91 optional(in_place_t, ARGS &&...args) // NOLINT
92 : has_value_(true)
93 {
94 new (&value_) T(std::forward<ARGS>(args)...);
95 }
96
103 template <class U, typename std::enable_if<std::is_assignable<T &, U>::value, int>::type = 0>
104 optional(U &&value) // NOLINT
105 : has_value_(true)
106 {
107 new (&value_) T(std::forward<U>(value));
108 }
109
117 template <class U, typename std::enable_if<std::is_assignable<T &, U>::value, int>::type = 0>
119 {
120 if (this->has_value_)
121 {
122 reinterpret_cast<T &>(value_).operator=(std::forward<U>(value));
123 }
124 else
125 {
126 new (&value_) T(std::forward<U>(value));
127 has_value_ = true;
128 }
129
130 return *this;
131 }
132
138 template <typename std::enable_if<std::is_copy_constructible<T>::value, int>::type = 0>
139 optional(const optional &rhs) // NOLINT
140 : has_value_(rhs.has_value_)
141 {
142 if (rhs.has_value_)
143 {
144 new (&value_) T(*rhs);
145 }
146 }
147
154 template <typename std::enable_if<std::is_copy_assignable<T>::value, int>::type = 0>
156 {
157 if (this != &rhs)
158 {
159 if (has_value_)
160 {
161 if (rhs.has_value_)
162 reinterpret_cast<T &>(value_).operator=(*rhs);
163 else
164 this->reset();
165 }
166 else if (rhs.has_value_)
167 {
168 new (&value_) T(*rhs);
169 has_value_ = true;
170 }
171 }
172
173 return *this;
174 }
175
181 template <typename std::enable_if<std::is_move_constructible<T>::value, int>::type = 0>
182 optional(optional &&rhs) // NOLINT
183 : has_value_(rhs.has_value_)
184 {
185 if (rhs.has_value_)
186 {
187 new (&value_) T(std::move(*rhs));
188 rhs.reset();
189 }
190 }
191
198 template <typename std::enable_if<std::is_move_assignable<T>::value, int>::type = 0>
200 {
201 if (this != &rhs)
202 {
203 if (has_value_)
204 {
205 if (rhs.has_value_)
206 {
207 reinterpret_cast<T &>(value_).operator=(std::move(*rhs));
208 rhs.reset();
209 }
210 else
211 {
212 this->reset();
213 }
214 }
215 else if (rhs.has_value_)
216 {
217 new (&value_) T(std::move(*rhs));
218 has_value_ = true;
219 rhs.reset();
220 }
221 }
222
223 return *this;
224 }
225
226 optional(const optional &other) = default;
227 optional &operator=(const optional &other) = default;
228 ~optional()
229 {
230 this->reset();
231 }
232
241 const T *operator->() const noexcept
242 {
243 return &reinterpret_cast<const T &>(value_);
244 }
245
254 T *operator->() noexcept
255 {
256 return &reinterpret_cast<T &>(value_);
257 }
258
267 const T &operator*() const noexcept
268 {
269 return reinterpret_cast<const T &>(value_);
270 }
271
280 T &operator*() noexcept
281 {
282 return reinterpret_cast<T &>(value_);
283 }
284
290 explicit operator bool() const noexcept
291 {
292 return has_value_;
293 }
294
305 template <class... ARGS>
306 T &emplace(ARGS &&...args)
307 {
308 this->reset();
309 auto pValue = new (&value_) T(std::forward<ARGS>(args)...); // NOLINT(cppcoreguidelines-owning-memory)
310 has_value_ = true;
311 return *pValue;
312 }
313
319 bool has_value() const noexcept
320 {
321 return has_value_;
322 }
323
327 void reset()
328 {
329 if (has_value_)
330 {
331 reinterpret_cast<T &>(value_).~T();
332 has_value_ = false;
333 }
334 }
335
343 void swap(optional &other)
344 {
345 auto old = std::move(*this);
346 *this = std::move(other);
347 other = std::move(old);
348 }
349
356 const T &value() const
357 {
358 if (!has_value_)
359 throw bad_optional_access{};
360
361 return reinterpret_cast<const T &>(value_);
362 }
363
370 T &value()
371 {
372 if (!has_value_)
373 throw bad_optional_access{};
374
375 return reinterpret_cast<T &>(value_);
376 }
377
384 template <class U, typename std::enable_if<std::is_assignable<T &, U>::value, int>::type = 0>
385 T value_or(U &&default_value) const
386 {
387 if (has_value_)
388 return reinterpret_cast<const T &>(value_);
389 else
390 return default_value;
391 }
392 };
393
402 template <class T>
407
417 template <class T, class... ARGS>
419 {
420 return optional<T>{in_place, std::forward<ARGS>(args)...};
421 }
422
423 } // namespace Shims
424
425 CVB_END_INLINE_NS
426
427} // namespace Cvb
428
429namespace std // NOLINT(cert-dcl58-cpp)
430{
432 template <class T>
433 void swap(Cvb::Shims::optional<T> &lhs, Cvb::Shims::optional<T> &rhs) // NOLINT(cert-dcl58-cpp)
434 {
435 lhs.swap(rhs);
436 }
437} // namespace std
Error when accessing not set value.
Definition optional.hpp:33
bad_optional_access()=default
Default ctor.
This class is a replacement for C++17 std::optional.
Definition optional.hpp:61
optional(U &&value)
Ctor from an object assignable to T.
Definition optional.hpp:104
optional & operator=(U &&value)
Assignment operator for an object assignable to T.
Definition optional.hpp:118
optional & operator=(optional &&rhs)
Move operator.
Definition optional.hpp:199
T value_or(U &&default_value) const
Gets the contained value if has_value() is true; default_value otherwise.
Definition optional.hpp:385
optional(nullopt_t) noexcept
Ctor for explicitly not storing a value.
Definition optional.hpp:79
const T & operator*() const noexcept
Gets the reference to the stored object.
Definition optional.hpp:267
optional & operator=(const optional &rhs)
Copy operator.
Definition optional.hpp:155
void swap(optional &other)
Swaps this object with the other object.
Definition optional.hpp:343
optional() noexcept
Default ctor not storing a value.
Definition optional.hpp:73
const T * operator->() const noexcept
Gets the reference to the stored object.
Definition optional.hpp:241
bool has_value() const noexcept
Gets whether this optional contains a value.
Definition optional.hpp:319
optional(optional &&rhs)
Move ctor.
Definition optional.hpp:182
T & value()
Gets the contained value.
Definition optional.hpp:370
const T & value() const
Gets the contained value.
Definition optional.hpp:356
optional(const optional &rhs)
Copy ctor.
Definition optional.hpp:139
optional(in_place_t, ARGS &&...args)
In-place constructs a new T object.
Definition optional.hpp:91
void reset()
Destroys any contained value.
Definition optional.hpp:327
T * operator->() noexcept
Gets the reference to the stored object.
Definition optional.hpp:254
T & emplace(ARGS &&...args)
Constructs a new T in-place.
Definition optional.hpp:306
T & operator*() noexcept
Gets the reference to the stored object.
Definition optional.hpp:280
bad_optional_access()=default
Default ctor.
optional() noexcept
Default ctor not storing a value.
Definition optional.hpp:73
This class is a replacement for C++17 std::optional.
optional< T > make_optional(ARGS &&...args)
Factory function to in-place construct a T in an optional.
Definition optional.hpp:418
optional< typename std::decay< T >::type > make_optional(T &&value)
Factory function to create an optional from a T object.
Definition optional.hpp:403
T forward(T... args)
T move(T... args)
static constexpr nullopt_t nullopt
Tag to indicate an optional not containing a value.
Definition optional.hpp:52
static constexpr in_place_t in_place
Tag to indicate an optional to in-place construct a value.
Definition utilities.hpp:28
Root namespace for the Image Manager interface.
Definition c_bayer_to_rgb.h:17
Disambiguation tags that can be passed to the constructors of optional() to indicate that the contain...
Definition utilities.hpp:24
Indicates optional() type with uninitialized state.
Definition optional.hpp:48
T swap(T... args)