1 |
// Copyright (C) 2011 - 2012 Andrzej Krzemienski. |
2 |
// |
3 |
// Use, modification, and distribution is subject to the Boost Software |
4 |
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
5 |
// http://www.boost.org/LICENSE_1_0.txt) |
6 |
// |
7 |
// The idea and interface is based on Boost.Optional library |
8 |
// authored by Fernando Luis Cacciola Carballal |
9 |
|
10 |
# ifndef ___OPTIONAL_HPP___ |
11 |
# define ___OPTIONAL_HPP___ |
12 |
|
13 |
# include <utility> |
14 |
# include <type_traits> |
15 |
# include <initializer_list> |
16 |
# include <cassert> |
17 |
# include <functional> |
18 |
# include <string> |
19 |
# include <stdexcept> |
20 |
|
21 |
# define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false |
22 |
|
23 |
# if defined __GNUC__ // NOTE: GNUC is also defined for Clang |
24 |
# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) |
25 |
# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ |
26 |
# elif (__GNUC__ > 4) |
27 |
# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ |
28 |
# endif |
29 |
# |
30 |
# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) |
31 |
# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ |
32 |
# elif (__GNUC__ > 4) |
33 |
# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ |
34 |
# endif |
35 |
# |
36 |
# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) |
37 |
# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ |
38 |
# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) |
39 |
# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ |
40 |
# elif (__GNUC__ > 4) |
41 |
# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ |
42 |
# endif |
43 |
# endif |
44 |
# |
45 |
# if defined __clang_major__ |
46 |
# if (__clang_major__ == 3 && __clang_minor__ >= 5) |
47 |
# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ |
48 |
# elif (__clang_major__ > 3) |
49 |
# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ |
50 |
# endif |
51 |
# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ |
52 |
# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ |
53 |
# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) |
54 |
# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ |
55 |
# endif |
56 |
# endif |
57 |
# |
58 |
# if defined _MSC_VER |
59 |
# if (_MSC_VER >= 1900) |
60 |
# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ |
61 |
# endif |
62 |
# endif |
63 |
|
64 |
# if defined __clang__ |
65 |
# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) |
66 |
# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 |
67 |
# else |
68 |
# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 |
69 |
# endif |
70 |
# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ |
71 |
# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 |
72 |
# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ |
73 |
# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 |
74 |
# else |
75 |
# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 |
76 |
# endif |
77 |
|
78 |
|
79 |
# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ |
80 |
# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 |
81 |
# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr |
82 |
# else |
83 |
# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 |
84 |
# define OPTIONAL_CONSTEXPR_INIT_LIST |
85 |
# endif |
86 |
|
87 |
# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L) |
88 |
# define OPTIONAL_HAS_MOVE_ACCESSORS 1 |
89 |
# else |
90 |
# define OPTIONAL_HAS_MOVE_ACCESSORS 0 |
91 |
# endif |
92 |
|
93 |
# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr |
94 |
# if (defined __cplusplus) && (__cplusplus == 201103L) |
95 |
# define OPTIONAL_MUTABLE_CONSTEXPR |
96 |
# else |
97 |
# define OPTIONAL_MUTABLE_CONSTEXPR constexpr |
98 |
# endif |
99 |
|
100 |
namespace std{ |
101 |
|
102 |
namespace experimental{ |
103 |
|
104 |
// BEGIN workaround for missing is_trivially_destructible |
105 |
# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ |
106 |
// leave it: it is already there |
107 |
# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ |
108 |
// leave it: it is already there |
109 |
# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ |
110 |
// leave it: it is already there |
111 |
# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS |
112 |
// leave it: the user doesn't want it |
113 |
# else |
114 |
template <typename T> |
115 |
using is_trivially_destructible = std::has_trivial_destructor<T>; |
116 |
# endif |
117 |
// END workaround for missing is_trivially_destructible |
118 |
|
119 |
# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) |
120 |
// leave it; our metafunctions are already defined. |
121 |
# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ |
122 |
// leave it; our metafunctions are already defined. |
123 |
# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ |
124 |
// leave it: it is already there |
125 |
# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS |
126 |
// leave it: the user doesn't want it |
127 |
# else |
128 |
|
129 |
|
130 |
// workaround for missing traits in GCC and CLANG |
131 |
template <class T> |
132 |
struct is_nothrow_move_constructible |
133 |
{ |
134 |
constexpr static bool value = std::is_nothrow_constructible<T, T&&>::value; |
135 |
}; |
136 |
|
137 |
|
138 |
template <class T, class U> |
139 |
struct is_assignable |
140 |
{ |
141 |
template <class X, class Y> |
142 |
constexpr static bool has_assign(...) { return false; } |
143 |
|
144 |
template <class X, class Y, size_t S = sizeof((std::declval<X>() = std::declval<Y>(), true)) > |
145 |
// the comma operator is necessary for the cases where operator= returns void |
146 |
constexpr static bool has_assign(bool) { return true; } |
147 |
|
148 |
constexpr static bool value = has_assign<T, U>(true); |
149 |
}; |
150 |
|
151 |
|
152 |
template <class T> |
153 |
struct is_nothrow_move_assignable |
154 |
{ |
155 |
template <class X, bool has_any_move_assign> |
156 |
struct has_nothrow_move_assign { |
157 |
constexpr static bool value = false; |
158 |
}; |
159 |
|
160 |
template <class X> |
161 |
struct has_nothrow_move_assign<X, true> { |
162 |
constexpr static bool value = noexcept( std::declval<X&>() = std::declval<X&&>() ); |
163 |
}; |
164 |
|
165 |
constexpr static bool value = has_nothrow_move_assign<T, is_assignable<T&, T&&>::value>::value; |
166 |
}; |
167 |
// end workaround |
168 |
|
169 |
|
170 |
# endif |
171 |
|
172 |
|
173 |
|
174 |
// 20.5.4, optional for object types |
175 |
template <class T> class optional; |
176 |
|
177 |
// 20.5.5, optional for lvalue reference types |
178 |
template <class T> class optional<T&>; |
179 |
|
180 |
|
181 |
// workaround: std utility functions aren't constexpr yet |
182 |
template <class T> inline constexpr T&& constexpr_forward(typename std::remove_reference<T>::type& t) noexcept |
183 |
{ |
184 |
return static_cast<T&&>(t); |
185 |
} |
186 |
|
187 |
template <class T> inline constexpr T&& constexpr_forward(typename std::remove_reference<T>::type&& t) noexcept |
188 |
{ |
189 |
static_assert(!std::is_lvalue_reference<T>::value, "!!"); |
190 |
return static_cast<T&&>(t); |
191 |
} |
192 |
|
193 |
template <class T> inline constexpr typename std::remove_reference<T>::type&& constexpr_move(T&& t) noexcept |
194 |
{ |
195 |
return static_cast<typename std::remove_reference<T>::type&&>(t); |
196 |
} |
197 |
|
198 |
|
199 |
#if defined NDEBUG |
200 |
# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) |
201 |
#else |
202 |
# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR))) |
203 |
#endif |
204 |
|
205 |
|
206 |
namespace detail_ |
207 |
{ |
208 |
|
209 |
// static_addressof: a constexpr version of addressof |
210 |
template <typename T> |
211 |
struct has_overloaded_addressof |
212 |
{ |
213 |
template <class X> |
214 |
constexpr static bool has_overload(...) { return false; } |
215 |
|
216 |
template <class X, size_t S = sizeof(std::declval<X&>().operator&()) > |
217 |
constexpr static bool has_overload(bool) { return true; } |
218 |
|
219 |
constexpr static bool value = has_overload<T>(true); |
220 |
}; |
221 |
|
222 |
template <typename T, TR2_OPTIONAL_REQUIRES(!has_overloaded_addressof<T>)> |
223 |
constexpr T* static_addressof(T& ref) |
224 |
{ |
225 |
return &ref; |
226 |
} |
227 |
|
228 |
template <typename T, TR2_OPTIONAL_REQUIRES(has_overloaded_addressof<T>)> |
229 |
T* static_addressof(T& ref) |
230 |
{ |
231 |
return std::addressof(ref); |
232 |
} |
233 |
|
234 |
|
235 |
// the call to convert<A>(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A |
236 |
template <class U> |
237 |
constexpr U convert(U v) { return v; } |
238 |
|
239 |
} // namespace detail |
240 |
|
241 |
|
242 |
constexpr struct trivial_init_t{} trivial_init{}; |
243 |
|
244 |
|
245 |
// 20.5.6, In-place construction |
246 |
constexpr struct in_place_t{} in_place{}; |
247 |
|
248 |
|
249 |
// 20.5.7, Disengaged state indicator |
250 |
struct nullopt_t |
251 |
{ |
252 |
struct init{}; |
253 |
constexpr explicit nullopt_t(init){} |
254 |
}; |
255 |
constexpr nullopt_t nullopt{nullopt_t::init()}; |
256 |
|
257 |
|
258 |
// 20.5.8, class bad_optional_access |
259 |
class bad_optional_access : public logic_error { |
260 |
public: |
261 |
explicit bad_optional_access(const string& what_arg) : logic_error{what_arg} {} |
262 |
explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {} |
263 |
}; |
264 |
|
265 |
|
266 |
template <class T> |
267 |
union storage_t |
268 |
{ |
269 |
unsigned char dummy_; |
270 |
T value_; |
271 |
|
272 |
constexpr storage_t( trivial_init_t ) noexcept : dummy_() {}; |
273 |
|
274 |
template <class... Args> |
275 |
constexpr storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {} |
276 |
|
277 |
~storage_t(){} |
278 |
}; |
279 |
|
280 |
|
281 |
template <class T> |
282 |
union constexpr_storage_t |
283 |
{ |
284 |
unsigned char dummy_; |
285 |
T value_; |
286 |
|
287 |
constexpr constexpr_storage_t( trivial_init_t ) noexcept : dummy_() {}; |
288 |
|
289 |
template <class... Args> |
290 |
constexpr constexpr_storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {} |
291 |
|
292 |
~constexpr_storage_t() = default; |
293 |
}; |
294 |
|
295 |
|
296 |
template <class T> |
297 |
struct optional_base |
298 |
{ |
299 |
bool init_; |
300 |
storage_t<T> storage_; |
301 |
|
302 |
constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {}; |
303 |
|
304 |
explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {} |
305 |
|
306 |
explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} |
307 |
|
308 |
template <class... Args> explicit optional_base(in_place_t, Args&&... args) |
309 |
: init_(true), storage_(constexpr_forward<Args>(args)...) {} |
310 |
|
311 |
template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)> |
312 |
explicit optional_base(in_place_t, std::initializer_list<U> il, Args&&... args) |
313 |
: init_(true), storage_(il, std::forward<Args>(args)...) {} |
314 |
|
315 |
~optional_base() { if (init_) storage_.value_.T::~T(); } |
316 |
}; |
317 |
|
318 |
|
319 |
template <class T> |
320 |
struct constexpr_optional_base |
321 |
{ |
322 |
bool init_; |
323 |
constexpr_storage_t<T> storage_; |
324 |
|
325 |
constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {}; |
326 |
|
327 |
explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_(v) {} |
328 |
|
329 |
explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} |
330 |
|
331 |
template <class... Args> explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) |
332 |
: init_(true), storage_(constexpr_forward<Args>(args)...) {} |
333 |
|
334 |
template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)> |
335 |
OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, std::initializer_list<U> il, Args&&... args) |
336 |
: init_(true), storage_(il, std::forward<Args>(args)...) {} |
337 |
|
338 |
~constexpr_optional_base() = default; |
339 |
}; |
340 |
|
341 |
template <class T> |
342 |
using OptionalBase = typename std::conditional< |
343 |
is_trivially_destructible<T>::value, // if possible |
344 |
constexpr_optional_base<typename std::remove_const<T>::type>, // use base with trivial destructor |
345 |
optional_base<typename std::remove_const<T>::type> |
346 |
>::type; |
347 |
|
348 |
|
349 |
|
350 |
template <class T> |
351 |
class optional : private OptionalBase<T> |
352 |
{ |
353 |
static_assert( !std::is_same<typename std::decay<T>::type, nullopt_t>::value, "bad T" ); |
354 |
static_assert( !std::is_same<typename std::decay<T>::type, in_place_t>::value, "bad T" ); |
355 |
|
356 |
|
357 |
constexpr bool initialized() const noexcept { return OptionalBase<T>::init_; } |
358 |
typename std::remove_const<T>::type* dataptr() { return std::addressof(OptionalBase<T>::storage_.value_); } |
359 |
constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase<T>::storage_.value_); } |
360 |
|
361 |
# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 |
362 |
constexpr const T& contained_val() const& { return OptionalBase<T>::storage_.value_; } |
363 |
# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 |
364 |
OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return std::move(OptionalBase<T>::storage_.value_); } |
365 |
OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase<T>::storage_.value_; } |
366 |
# else |
367 |
T& contained_val() & { return OptionalBase<T>::storage_.value_; } |
368 |
T&& contained_val() && { return std::move(OptionalBase<T>::storage_.value_); } |
369 |
# endif |
370 |
# else |
371 |
constexpr const T& contained_val() const { return OptionalBase<T>::storage_.value_; } |
372 |
T& contained_val() { return OptionalBase<T>::storage_.value_; } |
373 |
# endif |
374 |
|
375 |
void clear() noexcept { |
376 |
if (initialized()) dataptr()->T::~T(); |
377 |
OptionalBase<T>::init_ = false; |
378 |
} |
379 |
|
380 |
template <class... Args> |
381 |
void initialize(Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...))) |
382 |
{ |
383 |
assert(!OptionalBase<T>::init_); |
384 |
::new (static_cast<void*>(dataptr())) T(std::forward<Args>(args)...); |
385 |
OptionalBase<T>::init_ = true; |
386 |
} |
387 |
|
388 |
template <class U, class... Args> |
389 |
void initialize(std::initializer_list<U> il, Args&&... args) noexcept(noexcept(T(il, std::forward<Args>(args)...))) |
390 |
{ |
391 |
assert(!OptionalBase<T>::init_); |
392 |
::new (static_cast<void*>(dataptr())) T(il, std::forward<Args>(args)...); |
393 |
OptionalBase<T>::init_ = true; |
394 |
} |
395 |
|
396 |
public: |
397 |
typedef T value_type; |
398 |
|
399 |
// 20.5.5.1, constructors |
400 |
constexpr optional() noexcept : OptionalBase<T>() {}; |
401 |
constexpr optional(nullopt_t) noexcept : OptionalBase<T>() {}; |
402 |
|
403 |
optional(const optional& rhs) |
404 |
: OptionalBase<T>() |
405 |
{ |
406 |
if (rhs.initialized()) { |
407 |
::new (static_cast<void*>(dataptr())) T(*rhs); |
408 |
OptionalBase<T>::init_ = true; |
409 |
} |
410 |
} |
411 |
|
412 |
optional(optional&& rhs) noexcept(is_nothrow_move_constructible<T>::value) |
413 |
: OptionalBase<T>() |
414 |
{ |
415 |
if (rhs.initialized()) { |
416 |
::new (static_cast<void*>(dataptr())) T(std::move(*rhs)); |
417 |
OptionalBase<T>::init_ = true; |
418 |
} |
419 |
} |
420 |
|
421 |
constexpr optional(const T& v) : OptionalBase<T>(v) {} |
422 |
|
423 |
constexpr optional(T&& v) : OptionalBase<T>(constexpr_move(v)) {} |
424 |
|
425 |
template <class... Args> |
426 |
explicit constexpr optional(in_place_t, Args&&... args) |
427 |
: OptionalBase<T>(in_place_t{}, constexpr_forward<Args>(args)...) {} |
428 |
|
429 |
template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)> |
430 |
OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, std::initializer_list<U> il, Args&&... args) |
431 |
: OptionalBase<T>(in_place_t{}, il, constexpr_forward<Args>(args)...) {} |
432 |
|
433 |
// 20.5.4.2, Destructor |
434 |
~optional() = default; |
435 |
|
436 |
// 20.5.4.3, assignment |
437 |
optional& operator=(nullopt_t) noexcept |
438 |
{ |
439 |
clear(); |
440 |
return *this; |
441 |
} |
442 |
|
443 |
optional& operator=(const optional& rhs) |
444 |
{ |
445 |
if (initialized() == true && rhs.initialized() == false) clear(); |
446 |
else if (initialized() == false && rhs.initialized() == true) initialize(*rhs); |
447 |
else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; |
448 |
return *this; |
449 |
} |
450 |
|
451 |
optional& operator=(optional&& rhs) |
452 |
noexcept(is_nothrow_move_assignable<T>::value && is_nothrow_move_constructible<T>::value) |
453 |
{ |
454 |
if (initialized() == true && rhs.initialized() == false) clear(); |
455 |
else if (initialized() == false && rhs.initialized() == true) initialize(std::move(*rhs)); |
456 |
else if (initialized() == true && rhs.initialized() == true) contained_val() = std::move(*rhs); |
457 |
return *this; |
458 |
} |
459 |
|
460 |
template <class U> |
461 |
auto operator=(U&& v) |
462 |
-> typename enable_if |
463 |
< |
464 |
is_same<typename decay<U>::type, T>::value, |
465 |
optional& |
466 |
>::type |
467 |
{ |
468 |
if (initialized()) { contained_val() = std::forward<U>(v); } |
469 |
else { initialize(std::forward<U>(v)); } |
470 |
return *this; |
471 |
} |
472 |
|
473 |
|
474 |
template <class... Args> |
475 |
void emplace(Args&&... args) |
476 |
{ |
477 |
clear(); |
478 |
initialize(std::forward<Args>(args)...); |
479 |
} |
480 |
|
481 |
template <class U, class... Args> |
482 |
void emplace(initializer_list<U> il, Args&&... args) |
483 |
{ |
484 |
clear(); |
485 |
initialize<U, Args...>(il, std::forward<Args>(args)...); |
486 |
} |
487 |
|
488 |
// 20.5.4.4, Swap |
489 |
void swap(optional<T>& rhs) noexcept(is_nothrow_move_constructible<T>::value && noexcept(swap(declval<T&>(), declval<T&>()))) |
490 |
{ |
491 |
if (initialized() == true && rhs.initialized() == false) { rhs.initialize(std::move(**this)); clear(); } |
492 |
else if (initialized() == false && rhs.initialized() == true) { initialize(std::move(*rhs)); rhs.clear(); } |
493 |
else if (initialized() == true && rhs.initialized() == true) { using std::swap; swap(**this, *rhs); } |
494 |
} |
495 |
|
496 |
// 20.5.4.5, Observers |
497 |
|
498 |
explicit constexpr operator bool() const noexcept { return initialized(); } |
499 |
constexpr bool has_value() const noexcept { return initialized(); } |
500 |
|
501 |
constexpr T const* operator ->() const { |
502 |
return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); |
503 |
} |
504 |
|
505 |
# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 |
506 |
|
507 |
OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { |
508 |
assert (initialized()); |
509 |
return dataptr(); |
510 |
} |
511 |
|
512 |
constexpr T const& operator *() const& { |
513 |
return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); |
514 |
} |
515 |
|
516 |
OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { |
517 |
assert (initialized()); |
518 |
return contained_val(); |
519 |
} |
520 |
|
521 |
OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { |
522 |
assert (initialized()); |
523 |
return constexpr_move(contained_val()); |
524 |
} |
525 |
|
526 |
constexpr T const& value() const& { |
527 |
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); |
528 |
} |
529 |
|
530 |
OPTIONAL_MUTABLE_CONSTEXPR T& value() & { |
531 |
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); |
532 |
} |
533 |
|
534 |
OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { |
535 |
if (!initialized()) throw bad_optional_access("bad optional access"); |
536 |
return std::move(contained_val()); |
537 |
} |
538 |
|
539 |
# else |
540 |
|
541 |
T* operator ->() { |
542 |
assert (initialized()); |
543 |
return dataptr(); |
544 |
} |
545 |
|
546 |
constexpr T const& operator *() const { |
547 |
return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); |
548 |
} |
549 |
|
550 |
T& operator *() { |
551 |
assert (initialized()); |
552 |
return contained_val(); |
553 |
} |
554 |
|
555 |
constexpr T const& value() const { |
556 |
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); |
557 |
} |
558 |
|
559 |
T& value() { |
560 |
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); |
561 |
} |
562 |
|
563 |
# endif |
564 |
|
565 |
# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 |
566 |
|
567 |
template <class V> |
568 |
constexpr T value_or(V&& v) const& |
569 |
{ |
570 |
return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v)); |
571 |
} |
572 |
|
573 |
# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 |
574 |
|
575 |
template <class V> |
576 |
OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && |
577 |
{ |
578 |
return *this ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v)); |
579 |
} |
580 |
|
581 |
# else |
582 |
|
583 |
template <class V> |
584 |
T value_or(V&& v) && |
585 |
{ |
586 |
return *this ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v)); |
587 |
} |
588 |
|
589 |
# endif |
590 |
|
591 |
# else |
592 |
|
593 |
template <class V> |
594 |
constexpr T value_or(V&& v) const |
595 |
{ |
596 |
return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v)); |
597 |
} |
598 |
|
599 |
# endif |
600 |
|
601 |
// 20.6.3.6, modifiers |
602 |
void reset() noexcept { clear(); } |
603 |
}; |
604 |
|
605 |
|
606 |
template <class T> |
607 |
class optional<T&> |
608 |
{ |
609 |
static_assert( !std::is_same<T, nullopt_t>::value, "bad T" ); |
610 |
static_assert( !std::is_same<T, in_place_t>::value, "bad T" ); |
611 |
T* ref; |
612 |
|
613 |
public: |
614 |
|
615 |
// 20.5.5.1, construction/destruction |
616 |
constexpr optional() noexcept : ref(nullptr) {} |
617 |
|
618 |
constexpr optional(nullopt_t) noexcept : ref(nullptr) {} |
619 |
|
620 |
constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} |
621 |
|
622 |
optional(T&&) = delete; |
623 |
|
624 |
constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} |
625 |
|
626 |
explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} |
627 |
|
628 |
explicit optional(in_place_t, T&&) = delete; |
629 |
|
630 |
~optional() = default; |
631 |
|
632 |
// 20.5.5.2, mutation |
633 |
optional& operator=(nullopt_t) noexcept { |
634 |
ref = nullptr; |
635 |
return *this; |
636 |
} |
637 |
|
638 |
// optional& operator=(const optional& rhs) noexcept { |
639 |
// ref = rhs.ref; |
640 |
// return *this; |
641 |
// } |
642 |
|
643 |
// optional& operator=(optional&& rhs) noexcept { |
644 |
// ref = rhs.ref; |
645 |
// return *this; |
646 |
// } |
647 |
|
648 |
template <typename U> |
649 |
auto operator=(U&& rhs) noexcept |
650 |
-> typename enable_if |
651 |
< |
652 |
is_same<typename decay<U>::type, optional<T&>>::value, |
653 |
optional& |
654 |
>::type |
655 |
{ |
656 |
ref = rhs.ref; |
657 |
return *this; |
658 |
} |
659 |
|
660 |
template <typename U> |
661 |
auto operator=(U&& rhs) noexcept |
662 |
-> typename enable_if |
663 |
< |
664 |
!is_same<typename decay<U>::type, optional<T&>>::value, |
665 |
optional& |
666 |
>::type |
667 |
= delete; |
668 |
|
669 |
void emplace(T& v) noexcept { |
670 |
ref = detail_::static_addressof(v); |
671 |
} |
672 |
|
673 |
void emplace(T&&) = delete; |
674 |
|
675 |
|
676 |
void swap(optional<T&>& rhs) noexcept |
677 |
{ |
678 |
std::swap(ref, rhs.ref); |
679 |
} |
680 |
|
681 |
// 20.5.5.3, observers |
682 |
constexpr T* operator->() const { |
683 |
return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); |
684 |
} |
685 |
|
686 |
constexpr T& operator*() const { |
687 |
return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); |
688 |
} |
689 |
|
690 |
constexpr T& value() const { |
691 |
return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref); |
692 |
} |
693 |
|
694 |
explicit constexpr operator bool() const noexcept { |
695 |
return ref != nullptr; |
696 |
} |
697 |
|
698 |
constexpr bool has_value() const noexcept { |
699 |
return ref != nullptr; |
700 |
} |
701 |
|
702 |
template <class V> |
703 |
constexpr typename decay<T>::type value_or(V&& v) const |
704 |
{ |
705 |
return *this ? **this : detail_::convert<typename decay<T>::type>(constexpr_forward<V>(v)); |
706 |
} |
707 |
|
708 |
// x.x.x.x, modifiers |
709 |
void reset() noexcept { ref = nullptr; } |
710 |
}; |
711 |
|
712 |
|
713 |
template <class T> |
714 |
class optional<T&&> |
715 |
{ |
716 |
static_assert( sizeof(T) == 0, "optional rvalue references disallowed" ); |
717 |
}; |
718 |
|
719 |
|
720 |
// 20.5.8, Relational operators |
721 |
template <class T> constexpr bool operator==(const optional<T>& x, const optional<T>& y) |
722 |
{ |
723 |
return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; |
724 |
} |
725 |
|
726 |
template <class T> constexpr bool operator!=(const optional<T>& x, const optional<T>& y) |
727 |
{ |
728 |
return !(x == y); |
729 |
} |
730 |
|
731 |
template <class T> constexpr bool operator<(const optional<T>& x, const optional<T>& y) |
732 |
{ |
733 |
return (!y) ? false : (!x) ? true : *x < *y; |
734 |
} |
735 |
|
736 |
template <class T> constexpr bool operator>(const optional<T>& x, const optional<T>& y) |
737 |
{ |
738 |
return (y < x); |
739 |
} |
740 |
|
741 |
template <class T> constexpr bool operator<=(const optional<T>& x, const optional<T>& y) |
742 |
{ |
743 |
return !(y < x); |
744 |
} |
745 |
|
746 |
template <class T> constexpr bool operator>=(const optional<T>& x, const optional<T>& y) |
747 |
{ |
748 |
return !(x < y); |
749 |
} |
750 |
|
751 |
|
752 |
// 20.5.9, Comparison with nullopt |
753 |
template <class T> constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept |
754 |
{ |
755 |
return (!x); |
756 |
} |
757 |
|
758 |
template <class T> constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept |
759 |
{ |
760 |
return (!x); |
761 |
} |
762 |
|
763 |
template <class T> constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept |
764 |
{ |
765 |
return bool(x); |
766 |
} |
767 |
|
768 |
template <class T> constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept |
769 |
{ |
770 |
return bool(x); |
771 |
} |
772 |
|
773 |
template <class T> constexpr bool operator<(const optional<T>&, nullopt_t) noexcept |
774 |
{ |
775 |
return false; |
776 |
} |
777 |
|
778 |
template <class T> constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept |
779 |
{ |
780 |
return bool(x); |
781 |
} |
782 |
|
783 |
template <class T> constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept |
784 |
{ |
785 |
return (!x); |
786 |
} |
787 |
|
788 |
template <class T> constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept |
789 |
{ |
790 |
return true; |
791 |
} |
792 |
|
793 |
template <class T> constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept |
794 |
{ |
795 |
return bool(x); |
796 |
} |
797 |
|
798 |
template <class T> constexpr bool operator>(nullopt_t, const optional<T>&) noexcept |
799 |
{ |
800 |
return false; |
801 |
} |
802 |
|
803 |
template <class T> constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept |
804 |
{ |
805 |
return true; |
806 |
} |
807 |
|
808 |
template <class T> constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept |
809 |
{ |
810 |
return (!x); |
811 |
} |
812 |
|
813 |
|
814 |
|
815 |
// 20.5.10, Comparison with T |
816 |
template <class T> constexpr bool operator==(const optional<T>& x, const T& v) |
817 |
{ |
818 |
return bool(x) ? *x == v : false; |
819 |
} |
820 |
|
821 |
template <class T> constexpr bool operator==(const T& v, const optional<T>& x) |
822 |
{ |
823 |
return bool(x) ? v == *x : false; |
824 |
} |
825 |
|
826 |
template <class T> constexpr bool operator!=(const optional<T>& x, const T& v) |
827 |
{ |
828 |
return bool(x) ? *x != v : true; |
829 |
} |
830 |
|
831 |
template <class T> constexpr bool operator!=(const T& v, const optional<T>& x) |
832 |
{ |
833 |
return bool(x) ? v != *x : true; |
834 |
} |
835 |
|
836 |
template <class T> constexpr bool operator<(const optional<T>& x, const T& v) |
837 |
{ |
838 |
return bool(x) ? *x < v : true; |
839 |
} |
840 |
|
841 |
template <class T> constexpr bool operator>(const T& v, const optional<T>& x) |
842 |
{ |
843 |
return bool(x) ? v > *x : true; |
844 |
} |
845 |
|
846 |
template <class T> constexpr bool operator>(const optional<T>& x, const T& v) |
847 |
{ |
848 |
return bool(x) ? *x > v : false; |
849 |
} |
850 |
|
851 |
template <class T> constexpr bool operator<(const T& v, const optional<T>& x) |
852 |
{ |
853 |
return bool(x) ? v < *x : false; |
854 |
} |
855 |
|
856 |
template <class T> constexpr bool operator>=(const optional<T>& x, const T& v) |
857 |
{ |
858 |
return bool(x) ? *x >= v : false; |
859 |
} |
860 |
|
861 |
template <class T> constexpr bool operator<=(const T& v, const optional<T>& x) |
862 |
{ |
863 |
return bool(x) ? v <= *x : false; |
864 |
} |
865 |
|
866 |
template <class T> constexpr bool operator<=(const optional<T>& x, const T& v) |
867 |
{ |
868 |
return bool(x) ? *x <= v : true; |
869 |
} |
870 |
|
871 |
template <class T> constexpr bool operator>=(const T& v, const optional<T>& x) |
872 |
{ |
873 |
return bool(x) ? v >= *x : true; |
874 |
} |
875 |
|
876 |
|
877 |
// Comparison of optional<T&> with T |
878 |
template <class T> constexpr bool operator==(const optional<T&>& x, const T& v) |
879 |
{ |
880 |
return bool(x) ? *x == v : false; |
881 |
} |
882 |
|
883 |
template <class T> constexpr bool operator==(const T& v, const optional<T&>& x) |
884 |
{ |
885 |
return bool(x) ? v == *x : false; |
886 |
} |
887 |
|
888 |
template <class T> constexpr bool operator!=(const optional<T&>& x, const T& v) |
889 |
{ |
890 |
return bool(x) ? *x != v : true; |
891 |
} |
892 |
|
893 |
template <class T> constexpr bool operator!=(const T& v, const optional<T&>& x) |
894 |
{ |
895 |
return bool(x) ? v != *x : true; |
896 |
} |
897 |
|
898 |
template <class T> constexpr bool operator<(const optional<T&>& x, const T& v) |
899 |
{ |
900 |
return bool(x) ? *x < v : true; |
901 |
} |
902 |
|
903 |
template <class T> constexpr bool operator>(const T& v, const optional<T&>& x) |
904 |
{ |
905 |
return bool(x) ? v > *x : true; |
906 |
} |
907 |
|
908 |
template <class T> constexpr bool operator>(const optional<T&>& x, const T& v) |
909 |
{ |
910 |
return bool(x) ? *x > v : false; |
911 |
} |
912 |
|
913 |
template <class T> constexpr bool operator<(const T& v, const optional<T&>& x) |
914 |
{ |
915 |
return bool(x) ? v < *x : false; |
916 |
} |
917 |
|
918 |
template <class T> constexpr bool operator>=(const optional<T&>& x, const T& v) |
919 |
{ |
920 |
return bool(x) ? *x >= v : false; |
921 |
} |
922 |
|
923 |
template <class T> constexpr bool operator<=(const T& v, const optional<T&>& x) |
924 |
{ |
925 |
return bool(x) ? v <= *x : false; |
926 |
} |
927 |
|
928 |
template <class T> constexpr bool operator<=(const optional<T&>& x, const T& v) |
929 |
{ |
930 |
return bool(x) ? *x <= v : true; |
931 |
} |
932 |
|
933 |
template <class T> constexpr bool operator>=(const T& v, const optional<T&>& x) |
934 |
{ |
935 |
return bool(x) ? v >= *x : true; |
936 |
} |
937 |
|
938 |
// Comparison of optional<T const&> with T |
939 |
template <class T> constexpr bool operator==(const optional<const T&>& x, const T& v) |
940 |
{ |
941 |
return bool(x) ? *x == v : false; |
942 |
} |
943 |
|
944 |
template <class T> constexpr bool operator==(const T& v, const optional<const T&>& x) |
945 |
{ |
946 |
return bool(x) ? v == *x : false; |
947 |
} |
948 |
|
949 |
template <class T> constexpr bool operator!=(const optional<const T&>& x, const T& v) |
950 |
{ |
951 |
return bool(x) ? *x != v : true; |
952 |
} |
953 |
|
954 |
template <class T> constexpr bool operator!=(const T& v, const optional<const T&>& x) |
955 |
{ |
956 |
return bool(x) ? v != *x : true; |
957 |
} |
958 |
|
959 |
template <class T> constexpr bool operator<(const optional<const T&>& x, const T& v) |
960 |
{ |
961 |
return bool(x) ? *x < v : true; |
962 |
} |
963 |
|
964 |
template <class T> constexpr bool operator>(const T& v, const optional<const T&>& x) |
965 |
{ |
966 |
return bool(x) ? v > *x : true; |
967 |
} |
968 |
|
969 |
template <class T> constexpr bool operator>(const optional<const T&>& x, const T& v) |
970 |
{ |
971 |
return bool(x) ? *x > v : false; |
972 |
} |
973 |
|
974 |
template <class T> constexpr bool operator<(const T& v, const optional<const T&>& x) |
975 |
{ |
976 |
return bool(x) ? v < *x : false; |
977 |
} |
978 |
|
979 |
template <class T> constexpr bool operator>=(const optional<const T&>& x, const T& v) |
980 |
{ |
981 |
return bool(x) ? *x >= v : false; |
982 |
} |
983 |
|
984 |
template <class T> constexpr bool operator<=(const T& v, const optional<const T&>& x) |
985 |
{ |
986 |
return bool(x) ? v <= *x : false; |
987 |
} |
988 |
|
989 |
template <class T> constexpr bool operator<=(const optional<const T&>& x, const T& v) |
990 |
{ |
991 |
return bool(x) ? *x <= v : true; |
992 |
} |
993 |
|
994 |
template <class T> constexpr bool operator>=(const T& v, const optional<const T&>& x) |
995 |
{ |
996 |
return bool(x) ? v >= *x : true; |
997 |
} |
998 |
|
999 |
|
1000 |
// 20.5.12, Specialized algorithms |
1001 |
template <class T> |
1002 |
void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y))) |
1003 |
{ |
1004 |
x.swap(y); |
1005 |
} |
1006 |
|
1007 |
|
1008 |
template <class T> |
1009 |
constexpr optional<typename decay<T>::type> make_optional(T&& v) |
1010 |
{ |
1011 |
return optional<typename decay<T>::type>(constexpr_forward<T>(v)); |
1012 |
} |
1013 |
|
1014 |
template <class X> |
1015 |
constexpr optional<X&> make_optional(reference_wrapper<X> v) |
1016 |
{ |
1017 |
return optional<X&>(v.get()); |
1018 |
} |
1019 |
|
1020 |
|
1021 |
} // namespace experimental |
1022 |
} // namespace std |
1023 |
|
1024 |
namespace std |
1025 |
{ |
1026 |
template <typename T> |
1027 |
struct hash<std::experimental::optional<T>> |
1028 |
{ |
1029 |
typedef typename hash<T>::result_type result_type; |
1030 |
typedef std::experimental::optional<T> argument_type; |
1031 |
|
1032 |
constexpr result_type operator()(argument_type const& arg) const { |
1033 |
return arg ? std::hash<T>{}(*arg) : result_type{}; |
1034 |
} |
1035 |
}; |
1036 |
|
1037 |
template <typename T> |
1038 |
struct hash<std::experimental::optional<T&>> |
1039 |
{ |
1040 |
typedef typename hash<T>::result_type result_type; |
1041 |
typedef std::experimental::optional<T&> argument_type; |
1042 |
|
1043 |
constexpr result_type operator()(argument_type const& arg) const { |
1044 |
return arg ? std::hash<T>{}(*arg) : result_type{}; |
1045 |
} |
1046 |
}; |
1047 |
} |
1048 |
|
1049 |
# undef TR2_OPTIONAL_REQUIRES |
1050 |
# undef TR2_OPTIONAL_ASSERTED_EXPRESSION |
1051 |
|
1052 |
# endif //___OPTIONAL_HPP___ |