27 #ifndef GUL14_OPTIONAL_H_
28 #define GUL14_OPTIONAL_H_
32 #include <initializer_list>
35 #include <type_traits>
40 #define GUL_OPTIONAL_REQUIRES(...) typename std::enable_if<__VA_ARGS__::value, bool>::type = false
58 inline constexpr T&& constexpr_forward(
typename std::remove_reference<T>::type& t) noexcept {
59 return static_cast<T&&
> (t);
63 inline constexpr T&& constexpr_forward(
typename std::remove_reference<T>::type&& t) noexcept {
64 static_assert(!std::is_lvalue_reference<T>::value,
"!!");
65 return static_cast<T&&
> (t);
69 inline constexpr
typename std::remove_reference<T>::type&& constexpr_move(T&& t) noexcept {
70 return static_cast<typename std::remove_reference<T>::type&&
> (t);
75 #define GUL_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR)
77 #define GUL_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR)))
86 struct has_overloaded_addressof {
89 constexpr
static bool has_overload(...) {
93 template <class X, size_t S = sizeof (std::declval<X&>().operator&()) >
94 constexpr
static bool has_overload(
bool) {
98 constexpr
static bool value = has_overload<T>(
true);
101 template <
typename T, GUL_OPTIONAL_REQUIRES(!has_overloaded_addressof<T>)>
102 constexpr T* static_addressof(T& ref) {
106 template <
typename T, GUL_OPTIONAL_REQUIRES(has_overloaded_addressof<T>) >
107 T* static_addressof(T& ref) {
108 return std::addressof(ref);
115 constexpr U convert(U v) {
124 void adl_swap(T& t, T& u) noexcept(noexcept(
swap(t, u))) {
132 constexpr
struct trivial_init_t {
138 constexpr
struct in_place_t {
149 constexpr
explicit nullopt_t(init) {
152 constexpr nullopt_t nullopt{nullopt_t::init()};
157 class bad_optional_access :
public std::logic_error {
159 explicit bad_optional_access(
const std::string& what_arg) : std::logic_error{what_arg}
162 explicit bad_optional_access(
const char* what_arg) : std::logic_error{what_arg}
169 unsigned char dummy_;
172 constexpr storage_t(trivial_init_t) noexcept : dummy_() {
175 template <
class... Args>
176 constexpr storage_t(Args&&... args) : value_(constexpr_forward<Args>(args)...) {
184 union constexpr_storage_t {
185 unsigned char dummy_;
188 constexpr constexpr_storage_t(trivial_init_t) noexcept : dummy_() {
191 template <
class... Args>
192 constexpr constexpr_storage_t(Args&&... args) : value_(constexpr_forward<Args>(args)...) {
195 ~constexpr_storage_t() =
default;
199 struct optional_base {
201 storage_t<T> storage_;
203 constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {
206 explicit constexpr optional_base(
const T& v) : init_(true), storage_(v) {
209 explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {
212 template <
class... Args>
explicit optional_base(in_place_t, Args&&... args)
213 : init_(true), storage_(constexpr_forward<Args>(args)...) {
216 template <
class U,
class... Args, GUL_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
217 explicit optional_base(in_place_t, std::initializer_list<U> il, Args&&... args)
218 : init_(true), storage_(il, std::forward<Args>(args)...) {
222 if (init_) storage_.value_.T::~T();
227 struct constexpr_optional_base {
229 constexpr_storage_t<T> storage_;
231 constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {
234 explicit constexpr constexpr_optional_base(
const T& v) : init_(true), storage_(v) {
237 explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {
240 template <
class... Args>
explicit constexpr constexpr_optional_base(in_place_t, Args&&... args)
241 : init_(true), storage_(constexpr_forward<Args>(args)...) {
244 template <
class U,
class... Args, GUL_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
245 constexpr
explicit constexpr_optional_base(in_place_t, std::initializer_list<U> il, Args&&... args)
246 : init_(true), storage_(il, std::forward<Args>(args)...) {
249 ~constexpr_optional_base() =
default;
253 using OptionalBase =
typename std::conditional<
254 std::is_trivially_destructible<T>::value,
255 constexpr_optional_base<typename std::remove_const<T>::type>,
256 optional_base<typename std::remove_const<T>::type>
274 static_assert( !std::is_same<
typename std::decay<T>::type, nullopt_t>::value,
"bad T");
275 static_assert( !std::is_same<
typename std::decay<T>::type, in_place_t>::value,
"bad T");
277 constexpr
bool initialized()
const noexcept {
278 return OptionalBase<T>::init_;
281 typename std::remove_const<T>::type* dataptr() {
282 return std::addressof(OptionalBase<T>::storage_.value_);
285 constexpr
const T* dataptr()
const {
286 return detail_::static_addressof(OptionalBase<T>::storage_.value_);
289 constexpr
const T& contained_val()
const& {
290 return OptionalBase<T>::storage_.value_;
293 constexpr T&& contained_val() && {
294 return std::move(OptionalBase<T>::storage_.value_);
297 constexpr T& contained_val() & {
298 return OptionalBase<T>::storage_.value_;
301 void clear() noexcept {
302 if (initialized()) dataptr()->T::~T();
303 OptionalBase<T>::init_ =
false;
306 template <
class... Args>
307 void initialize(Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
308 assert(!OptionalBase<T>::init_);
309 ::new (
static_cast<void*
> (dataptr())) T(std::forward<Args>(args)...);
310 OptionalBase<T>::init_ =
true;
313 template <
class U,
class... Args>
314 void initialize(std::initializer_list<U> il, Args&&... args) noexcept(noexcept(T(il, std::forward<Args>(args)...))) {
315 assert(!OptionalBase<T>::init_);
316 ::new (
static_cast<void*
> (dataptr())) T(il, std::forward<Args>(args)...);
317 OptionalBase<T>::init_ =
true;
321 typedef T value_type;
325 constexpr
optional() noexcept : OptionalBase<T>() {
328 constexpr
optional(nullopt_t) noexcept : OptionalBase<T>() {
332 : OptionalBase<T>() {
333 if (rhs.initialized()) {
334 ::new (
static_cast<void*
> (dataptr())) T(*rhs);
335 OptionalBase<T>::init_ =
true;
339 optional(
optional&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value)
340 : OptionalBase<T>() {
341 if (rhs.initialized()) {
342 ::new (
static_cast<void*
> (dataptr())) T(std::move(*rhs));
343 OptionalBase<T>::init_ =
true;
347 constexpr
optional(
const T& v) : OptionalBase<T>(v) {
350 constexpr
optional(T&& v) : OptionalBase<T>(constexpr_move(v)) {
353 template <
class... Args>
354 explicit constexpr
optional(in_place_t, Args&&... args)
355 : OptionalBase<T>(in_place_t{}, constexpr_forward<Args>(args)...) {
358 template <
class U,
class... Args, GUL_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
359 constexpr
explicit optional(in_place_t, std::initializer_list<U> il, Args&&... args)
360 : OptionalBase<T>(in_place_t{}, il, constexpr_forward<Args>(args)...) {
368 optional& operator=(nullopt_t) noexcept {
374 if (initialized() ==
true && rhs.initialized() ==
false) clear();
375 else if (initialized() ==
false && rhs.initialized() ==
true) initialize(*rhs);
376 else if (initialized() ==
true && rhs.initialized() ==
true) contained_val() = *rhs;
381 noexcept(std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value) {
382 if (initialized() ==
true && rhs.initialized() ==
false) clear();
383 else if (initialized() ==
false && rhs.initialized() ==
true) initialize(std::move(*rhs));
384 else if (initialized() ==
true && rhs.initialized() ==
true) contained_val() = std::move(*rhs);
389 auto operator=(U&& v)
390 ->
typename std::enable_if<std::is_same<typename std::decay<U>::type, T>::value,
optional&>::type {
392 contained_val() = std::forward<U>(v);
394 initialize(std::forward<U>(v));
399 template <
class... Args>
400 void emplace(Args&&... args) {
402 initialize(std::forward<Args>(args)...);
405 template <
class U,
class... Args>
406 void emplace(std::initializer_list<U> il, Args&&... args) {
408 initialize<U, Args...>(il, std::forward<Args>(args)...);
413 void swap(
optional<T>& rhs) noexcept(std::is_nothrow_move_constructible<T>::value
414 && noexcept(detail_::swap_ns::adl_swap(std::declval<T&>(), std::declval<T&>()))) {
415 if (initialized() ==
true && rhs.initialized() ==
false) {
416 rhs.initialize(std::move(* *
this));
418 }
else if (initialized() ==
false && rhs.initialized() ==
true) {
419 initialize(std::move(*rhs));
421 }
else if (initialized() ==
true && rhs.initialized() ==
true) {
423 swap(* *
this, *rhs);
429 explicit constexpr
operator bool()
const noexcept {
430 return initialized();
433 constexpr
bool has_value()
const noexcept {
434 return initialized();
437 constexpr T
const* operator->()
const {
438 return GUL_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr());
441 constexpr T* operator->() {
442 assert(initialized());
446 constexpr T
const& operator*()
const& {
447 return GUL_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val());
450 constexpr T& operator*() & {
451 assert(initialized());
452 return contained_val();
455 constexpr T&& operator*() && {
456 assert(initialized());
457 return constexpr_move(contained_val());
460 constexpr T
const& value()
const& {
461 return initialized() ? contained_val() : (
throw bad_optional_access(
"bad optional access"), contained_val());
464 constexpr T& value() & {
465 if (!initialized())
throw bad_optional_access(
"bad optional access");
466 return contained_val();
469 constexpr T&& value() && {
470 if (!initialized())
throw bad_optional_access(
"bad optional access");
471 return std::move(contained_val());
475 #pragma warning(push)
476 #pragma warning(disable: 4244)
480 constexpr T value_or(V&& v)
const& {
481 return *
this ? * * this : detail_::convert<T>(constexpr_forward<V>(v));
485 constexpr T value_or(V&& v) && {
486 return *
this ? constexpr_move(
const_cast<optional<T>&
> (*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v));
494 void reset() noexcept {
513 static_assert( !std::is_same<T, nullopt_t>::value,
"bad T");
514 static_assert( !std::is_same<T, in_place_t>::value,
"bad T");
521 constexpr
optional() noexcept : ref(
nullptr) {
524 constexpr
optional(nullopt_t) noexcept : ref(
nullptr) {
527 constexpr
optional(T& v) noexcept : ref(detail_::static_addressof(v)) {
535 explicit constexpr
optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {
538 explicit optional(in_place_t, T&&) =
delete;
544 optional& operator=(nullopt_t) noexcept {
559 template <
typename U>
560 auto operator=(U&& rhs) noexcept
561 ->
typename std::enable_if
563 std::is_same<typename std::decay<U>::type,
optional<T&>>::value,
571 template <
typename U>
572 auto operator=(U&& rhs) noexcept
573 ->
typename std::enable_if
575 !std::is_same<typename std::decay<U>::type,
optional<T&>>::value,
580 void emplace(T& v) noexcept {
581 ref = detail_::static_addressof(v);
584 void emplace(T&&) =
delete;
592 constexpr T* operator->()
const {
593 return GUL_OPTIONAL_ASSERTED_EXPRESSION(ref, ref);
596 constexpr T& operator*()
const {
597 return GUL_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref);
600 constexpr T& value()
const {
601 return ref ? *ref : (
throw bad_optional_access(
"bad optional access"), *ref);
604 explicit constexpr
operator bool()
const noexcept {
605 return ref !=
nullptr;
608 constexpr
bool has_value()
const noexcept {
609 return ref !=
nullptr;
613 constexpr
typename std::decay<T>::type value_or(V&& v)
const {
614 return *
this ? * * this : detail_::convert<typename std::decay<T>::type > (constexpr_forward<V>(v));
619 void reset() noexcept {
630 static_assert(
sizeof (T) == 0,
"optional rvalue references disallowed");
636 template <
class T> constexpr
bool operator==(
const optional<T>& x,
const optional<T>& y) {
637 return bool(x) != bool(y) ? false : bool(x) ==
false ? true : *x == *y;
640 template <
class T> constexpr
bool operator!=(
const optional<T>& x,
const optional<T>& y) {
644 template <
class T> constexpr
bool operator<(
const optional<T>& x,
const optional<T>& y) {
645 return (!y) ? false : (!x) ?
true : *x < *y;
648 template <
class T> constexpr
bool operator>(
const optional<T>& x,
const optional<T>& y) {
652 template <
class T> constexpr
bool operator<=(
const optional<T>& x,
const optional<T>& y) {
656 template <
class T> constexpr
bool operator>=(
const optional<T>& x,
const optional<T>& y) {
663 template <
class T> constexpr
bool operator==(
const optional<T>& x, nullopt_t) noexcept {
667 template <
class T> constexpr
bool operator==(nullopt_t,
const optional<T>& x) noexcept {
671 template <
class T> constexpr
bool operator!=(
const optional<T>& x, nullopt_t) noexcept {
675 template <
class T> constexpr
bool operator!=(nullopt_t,
const optional<T>& x) noexcept {
679 template <
class T> constexpr
bool operator<(
const optional<T>&, nullopt_t) noexcept {
683 template <
class T> constexpr
bool operator<(nullopt_t,
const optional<T>& x) noexcept {
687 template <
class T> constexpr
bool operator<=(
const optional<T>& x, nullopt_t) noexcept {
691 template <
class T> constexpr
bool operator<=(nullopt_t,
const optional<T>&) noexcept {
695 template <
class T> constexpr
bool operator>(
const optional<T>& x, nullopt_t) noexcept {
699 template <
class T> constexpr
bool operator>(nullopt_t,
const optional<T>&) noexcept {
703 template <
class T> constexpr
bool operator>=(
const optional<T>&, nullopt_t) noexcept {
707 template <
class T> constexpr
bool operator>=(nullopt_t,
const optional<T>& x) noexcept {
715 template <
class T> constexpr
bool operator==(
const optional<T>& x,
const T& v) {
716 return bool(x) ? *x == v :
false;
719 template <
class T> constexpr
bool operator==(
const T& v,
const optional<T>& x) {
720 return bool(x) ? v == *x :
false;
723 template <
class T> constexpr
bool operator!=(
const optional<T>& x,
const T& v) {
724 return bool(x) ? *x != v :
true;
727 template <
class T> constexpr
bool operator!=(
const T& v,
const optional<T>& x) {
728 return bool(x) ? v != *x :
true;
731 template <
class T> constexpr
bool operator<(
const optional<T>& x,
const T& v) {
732 return bool(x) ? *x < v :
true;
735 template <
class T> constexpr
bool operator>(
const T& v,
const optional<T>& x) {
736 return bool(x) ? v > *x :
true;
739 template <
class T> constexpr
bool operator>(
const optional<T>& x,
const T& v) {
740 return bool(x) ? *x > v :
false;
743 template <
class T> constexpr
bool operator<(
const T& v,
const optional<T>& x) {
744 return bool(x) ? v < *x :
false;
747 template <
class T> constexpr
bool operator>=(
const optional<T>& x,
const T& v) {
748 return bool(x) ? *x >= v :
false;
751 template <
class T> constexpr
bool operator<=(
const T& v,
const optional<T>& x) {
752 return bool(x) ? v <= *x :
false;
755 template <
class T> constexpr
bool operator<=(
const optional<T>& x,
const T& v) {
756 return bool(x) ? *x <= v :
true;
759 template <
class T> constexpr
bool operator>=(
const T& v,
const optional<T>& x) {
760 return bool(x) ? v >= *x :
true;
766 template <
class T> constexpr
bool operator==(
const optional<T&>& x,
const T& v) {
767 return bool(x) ? *x == v :
false;
770 template <
class T> constexpr
bool operator==(
const T& v,
const optional<T&>& x) {
771 return bool(x) ? v == *x :
false;
774 template <
class T> constexpr
bool operator!=(
const optional<T&>& x,
const T& v) {
775 return bool(x) ? *x != v :
true;
778 template <
class T> constexpr
bool operator!=(
const T& v,
const optional<T&>& x) {
779 return bool(x) ? v != *x :
true;
782 template <
class T> constexpr
bool operator<(
const optional<T&>& x,
const T& v) {
783 return bool(x) ? *x < v :
true;
786 template <
class T> constexpr
bool operator>(
const T& v,
const optional<T&>& x) {
787 return bool(x) ? v > *x :
true;
790 template <
class T> constexpr
bool operator>(
const optional<T&>& x,
const T& v) {
791 return bool(x) ? *x > v :
false;
794 template <
class T> constexpr
bool operator<(
const T& v,
const optional<T&>& x) {
795 return bool(x) ? v < *x :
false;
798 template <
class T> constexpr
bool operator>=(
const optional<T&>& x,
const T& v) {
799 return bool(x) ? *x >= v :
false;
802 template <
class T> constexpr
bool operator<=(
const T& v,
const optional<T&>& x) {
803 return bool(x) ? v <= *x :
false;
806 template <
class T> constexpr
bool operator<=(
const optional<T&>& x,
const T& v) {
807 return bool(x) ? *x <= v :
true;
810 template <
class T> constexpr
bool operator>=(
const T& v,
const optional<T&>& x) {
811 return bool(x) ? v >= *x :
true;
816 template <
class T> constexpr
bool operator==(
const optional<const T&>& x,
const T& v) {
817 return bool(x) ? *x == v :
false;
820 template <
class T> constexpr
bool operator==(
const T& v,
const optional<const T&>& x) {
821 return bool(x) ? v == *x :
false;
824 template <
class T> constexpr
bool operator!=(
const optional<const T&>& x,
const T& v) {
825 return bool(x) ? *x != v :
true;
828 template <
class T> constexpr
bool operator!=(
const T& v,
const optional<const T&>& x) {
829 return bool(x) ? v != *x :
true;
832 template <
class T> constexpr
bool operator<(
const optional<const T&>& x,
const T& v) {
833 return bool(x) ? *x < v :
true;
836 template <
class T> constexpr
bool operator>(
const T& v,
const optional<const T&>& x) {
837 return bool(x) ? v > *x :
true;
840 template <
class T> constexpr
bool operator>(
const optional<const T&>& x,
const T& v) {
841 return bool(x) ? *x > v :
false;
844 template <
class T> constexpr
bool operator<(
const T& v,
const optional<const T&>& x) {
845 return bool(x) ? v < *x :
false;
848 template <
class T> constexpr
bool operator>=(
const optional<const T&>& x,
const T& v) {
849 return bool(x) ? *x >= v :
false;
852 template <
class T> constexpr
bool operator<=(
const T& v,
const optional<const T&>& x) {
853 return bool(x) ? v <= *x :
false;
856 template <
class T> constexpr
bool operator<=(
const optional<const T&>& x,
const T& v) {
857 return bool(x) ? *x <= v :
true;
860 template <
class T> constexpr
bool operator>=(
const T& v,
const optional<const T&>& x) {
861 return bool(x) ? v >= *x :
true;
868 void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y))) {
873 constexpr optional<typename std::decay<T>::type> make_optional(T&& v) {
874 return optional<typename std::decay<T>::type > (constexpr_forward<T>(v));
878 constexpr optional<X&> make_optional(std::reference_wrapper<X> v) {
879 return optional<X&>(v.get());
891 template <
typename T>
892 struct hash<
gul14::optional<T>>
894 typedef typename hash<T>::result_type result_type;
897 constexpr result_type operator()(argument_type
const& arg)
const {
898 return arg ? std::hash<T>{}(*arg) : result_type{};
902 template <
typename T>
903 struct hash<
gul14::optional<T&>>
905 typedef typename hash<T>::result_type result_type;
908 constexpr result_type operator()(argument_type
const& arg)
const {
909 return arg ? std::hash<T>{}(*arg) : result_type{};
915 #undef GUL_OPTIONAL_REQUIRES
916 #undef GUL_OPTIONAL_ASSERTED_EXPRESSION
A class template that can either contain a value of a certain type or not.
Definition: optional.h:511
A class template that can either contain a value of a certain type or not.
Definition: optional.h:272
Definition of macros used internally by GUL.
Namespace gul14 contains all functions and classes of the General Utility Library.
Definition: doxygen.h:26
void swap(SmallVector< ElementT, in_capacity > &a, SmallVector< ElementT, in_capacity > &b)
Exchange the contents of one SmallVector with those of another one.
Definition: SmallVector.h:1649