CVB++ 15.0
optional.hpp
1#pragma once
2
14#include <exception>
15#include <new>
16#include <utility>
17
18#include "../namespace.hpp"
19#include "utilities.hpp"
20
21namespace Cvb
22{
23
24CVB_BEGIN_INLINE_NS
25
26namespace Shims
27{
28
33{
34public:
37};
38
48{
49};
50
52static constexpr nullopt_t nullopt = {};
53
58template <class T>
59class optional final // NOLINT(cppcoreguidelines-special-member-functions) requires generated no default move to work correctly
60{
61 using Storage = typename std::aligned_storage<sizeof(T), alignof(T)>::type;
62
64 bool has_value_;
66 Storage value_;
67
68public:
69 using value_type = T;
70
72 optional() noexcept
73 : has_value_(false)
74 {
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
402template <class T>
404{
405 return optional<typename std::decay<T>::type>{std::forward<T>(value)};
406}
407
417template <class T, class... ARGS>
419{
420 return optional<T>{in_place, std::forward<ARGS>(args)...};
421}
422
423} // namespace Shims
424
425CVB_END_INLINE_NS
426
427} // namespace Cvb
428
429namespace std // NOLINT(cert-dcl58-cpp)
430{
432template <class T>
433void 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:60
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:72
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(in_place_t, ARGS &&... args)
In-place constructs a new T object.
Definition: optional.hpp:91
optional(optional &&rhs)
Move ctor.
Definition: optional.hpp:182
T & emplace(ARGS &&... args)
Constructs a new T in-place.
Definition: optional.hpp:306
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
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 & operator*() noexcept
Gets the reference to the stored object.
Definition: optional.hpp:280
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
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_barcode.h:24
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)