CVB++ 14.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
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
79 : has_value_(false)
80 {
81 }
82
89 template <class... ARGS>
90 optional(in_place_t, ARGS &&... args)
91 : has_value_(true)
92 {
93 new(&value_) T(std::forward<ARGS>(args)...);
94 }
95
102 template <class U, typename std::enable_if<std::is_assignable<T&, U>::value, int>::type = 0>
104 : has_value_(true)
105 {
106 new(&value_) T(std::forward<U>(value));
107 }
108
116 template <class U, typename std::enable_if<std::is_assignable<T&, U>::value, int>::type = 0>
118 {
119 if(this->has_value_)
120 {
121 reinterpret_cast<T &>(value_).operator=(std::forward<U>(value));
122 }
123 else
124 {
125 new(&value_) T(std::forward<U>(value));
126 has_value_ = true;
127 }
128
129 return *this;
130 }
131
137 template <typename std::enable_if<std::is_copy_constructible<T>::value, int>::type = 0>
138 optional(const optional &rhs)
139 : has_value_(rhs.has_value_)
140 {
141 if(rhs.has_value_)
142 {
143 new(&value_) T(*rhs);
144 }
145 }
146
153 template <typename std::enable_if<std::is_copy_assignable<T>::value, int>::type = 0>
155 {
156 if(this != &rhs)
157 {
158 if(has_value_)
159 {
160 if(rhs.has_value_)
161 reinterpret_cast<T &>(value_).operator=(*rhs);
162 else
163 this->reset();
164 }
165 else if(rhs.has_value_)
166 {
167 new(&value_) T(*rhs);
168 has_value_ = true;
169 }
170 }
171
172 return *this;
173 }
174
180 template <typename std::enable_if<std::is_move_constructible<T>::value, int>::type = 0>
182 : has_value_(rhs.has_value_)
183 {
184 if(rhs.has_value_)
185 {
186 new(&value_) T(std::move(*rhs));
187 rhs.reset();
188 }
189 }
190
197 template <typename std::enable_if<std::is_move_assignable<T>::value, int>::type = 0>
199 {
200 if(this != &rhs)
201 {
202 if(has_value_)
203 {
204 if(rhs.has_value_)
205 {
206 reinterpret_cast<T &>(value_).operator=(std::move(*rhs));
207 rhs.reset();
208 }
209 else
210 {
211 this->reset();
212 }
213 }
214 else if(rhs.has_value_)
215 {
216 new(&value_) T(std::move(*rhs));
217 has_value_ = true;
218 rhs.reset();
219 }
220 }
221
222 return *this;
223 }
224
227 {
228 this->reset();
229 }
230
239 const T *operator->() const noexcept
240 {
241 return &reinterpret_cast<const T &>(value_);
242 }
243
252 T *operator->() noexcept
253 {
254 return &reinterpret_cast<T &>(value_);
255 }
256
265 const T &operator*() const noexcept
266 {
267 return reinterpret_cast<const T &>(value_);
268 }
269
278 T &operator*() noexcept
279 {
280 return reinterpret_cast<T &>(value_);
281 }
282
288 explicit operator bool() const noexcept
289 {
290 return has_value_;
291 }
292
303 template <class... ARGS>
304 T &emplace(ARGS &&... args)
305 {
306 this->reset();
307 auto pValue = new(&value_) T(std::forward<ARGS>(args)...);
308 has_value_ = true;
309 return *pValue;
310 }
311
317 bool has_value() const noexcept
318 {
319 return has_value_;
320 }
321
325 void reset()
326 {
327 if(has_value_)
328 {
329 reinterpret_cast<T &>(value_).~T();
330 has_value_ = false;
331 }
332 }
333
341 void swap(optional &other)
342 {
343 auto old = std::move(*this);
344 *this = std::move(other);
345 other = std::move(old);
346 }
347
354 const T &value() const
355 {
356 if(!has_value_)
357 throw bad_optional_access{};
358
359 return reinterpret_cast<const T &>(value_);
360 }
361
368 T &value()
369 {
370 if(!has_value_)
371 throw bad_optional_access{};
372
373 return reinterpret_cast<T &>(value_);
374 }
375
382 template <class U, typename std::enable_if<std::is_assignable<T&, U>::value, int>::type = 0>
383 T value_or(U &&default_value) const
384 {
385 if(has_value_)
386 return reinterpret_cast<const T &>(value_);
387 else
388 return default_value;
389 }
390};
391
400template <class T>
402{
403 return optional<typename std::decay<T>::type>{std::forward<T>(value)};
404}
405
415template <class T, class... ARGS>
417{
418 return optional<T>{in_place, std::forward<ARGS>(args)...};
419}
420
421} // namespace Shims
422
423CVB_END_INLINE_NS
424
425} // namespace Cvb
426
427namespace std
428{
430template <class T>
432{
433 lhs.swap(rhs);
434}
435} // 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:103
optional & operator=(U &&value)
Assignment operator for an object assignable to T.
Definition: optional.hpp:117
optional< T > make_optional(ARGS &&... args)
Factory function to in-place construct a T in an optional.
Definition: optional.hpp:416
optional & operator=(optional &&rhs)
Move operator.
Definition: optional.hpp:198
T value_or(U &&default_value) const
Gets the contained value if has_value() is true; default_value otherwise.
Definition: optional.hpp:383
optional(nullopt_t) noexcept
Ctor for explicitly not storing a value.
Definition: optional.hpp:78
const T & operator*() const noexcept
Gets the reference to the stored object.
Definition: optional.hpp:265
optional & operator=(const optional &rhs)
Copy operator.
Definition: optional.hpp:154
void swap(optional &other)
Swaps this object with the other object.
Definition: optional.hpp:341
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:239
optional< typename std::decay< T >::type > make_optional(T &&value)
Factory function to create an optional from a T object.
Definition: optional.hpp:401
bool has_value() const noexcept
Gets whether this optional contains a value.
Definition: optional.hpp:317
optional(in_place_t, ARGS &&... args)
In-place constructs a new T object.
Definition: optional.hpp:90
optional(optional &&rhs)
Move ctor.
Definition: optional.hpp:181
T & emplace(ARGS &&... args)
Constructs a new T in-place.
Definition: optional.hpp:304
T & value()
Gets the contained value.
Definition: optional.hpp:368
const T & value() const
Gets the contained value.
Definition: optional.hpp:354
optional(const optional &rhs)
Copy ctor.
Definition: optional.hpp:138
void reset()
Destroys any contained value.
Definition: optional.hpp:325
T * operator->() noexcept
Gets the reference to the stored object.
Definition: optional.hpp:252
T & operator*() noexcept
Gets the reference to the stored object.
Definition: optional.hpp:278
~optional()
Dtor.
Definition: optional.hpp:226
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