27 #ifndef GUL14_OPTIONAL_H_
28 #define GUL14_OPTIONAL_H_
32 #include <initializer_list>
35 #include <type_traits>
42 #define GUL_OPTIONAL_REQUIRES(...) typename std::enable_if<__VA_ARGS__::value, bool>::type = false
60 inline constexpr T&& constexpr_forward(
typename std::remove_reference<T>::type& t) noexcept {
61 return static_cast<T&&
> (t);
65 inline constexpr T&& constexpr_forward(
typename std::remove_reference<T>::type&& t) noexcept {
66 static_assert(!std::is_lvalue_reference<T>::value,
"!!");
67 return static_cast<T&&
> (t);
71 inline constexpr
typename std::remove_reference<T>::type&& constexpr_move(T&& t) noexcept {
72 return static_cast<typename std::remove_reference<T>::type&&
> (t);
77 #define GUL_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR)
79 #define GUL_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR)))
88 struct has_overloaded_addressof {
91 constexpr
static bool has_overload(...) {
95 template <class X, size_t S = sizeof (std::declval<X&>().operator&()) >
96 constexpr
static bool has_overload(
bool) {
100 constexpr
static bool value = has_overload<T>(
true);
103 template <
typename T, GUL_OPTIONAL_REQUIRES(!has_overloaded_addressof<T>)>
104 constexpr T* static_addressof(T& ref) {
108 template <
typename T, GUL_OPTIONAL_REQUIRES(has_overloaded_addressof<T>) >
109 T* static_addressof(T& ref) {
110 return std::addressof(ref);
117 constexpr U convert(U v) {
126 void adl_swap(T& t, T& u) noexcept(noexcept(
swap(t, u))) {
134 constexpr
struct trivial_init_t {
145 constexpr
explicit nullopt_t(init) {
148 constexpr nullopt_t nullopt{nullopt_t::init()};
153 class bad_optional_access :
public std::logic_error {
155 explicit bad_optional_access(
const std::string& what_arg) : std::logic_error{what_arg}
158 explicit bad_optional_access(
const char* what_arg) : std::logic_error{what_arg}
165 unsigned char dummy_;
168 constexpr storage_t(trivial_init_t) noexcept : dummy_() {
171 template <
class... Args>
172 constexpr storage_t(Args&&... args) : value_(constexpr_forward<Args>(args)...) {
180 union constexpr_storage_t {
181 unsigned char dummy_;
184 constexpr constexpr_storage_t(trivial_init_t) noexcept : dummy_() {
187 template <
class... Args>
188 constexpr constexpr_storage_t(Args&&... args) : value_(constexpr_forward<Args>(args)...) {
191 ~constexpr_storage_t() =
default;
195 struct optional_base {
197 storage_t<T> storage_;
199 constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {
202 explicit constexpr optional_base(
const T& v) : init_(true), storage_(v) {
205 explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {
208 template <
class... Args>
explicit optional_base(in_place_t, Args&&... args)
209 : init_(true), storage_(constexpr_forward<Args>(args)...) {
212 template <
class U,
class... Args, GUL_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
213 explicit optional_base(in_place_t, std::initializer_list<U> il, Args&&... args)
214 : init_(true), storage_(il, std::forward<Args>(args)...) {
218 if (init_) storage_.value_.T::~T();
223 struct constexpr_optional_base {
225 constexpr_storage_t<T> storage_;
227 constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {
230 explicit constexpr constexpr_optional_base(
const T& v) : init_(true), storage_(v) {
233 explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {
236 template <
class... Args>
explicit constexpr constexpr_optional_base(in_place_t, Args&&... args)
237 : init_(true), storage_(constexpr_forward<Args>(args)...) {
240 template <
class U,
class... Args, GUL_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
241 constexpr
explicit constexpr_optional_base(in_place_t, std::initializer_list<U> il, Args&&... args)
242 : init_(true), storage_(il, std::forward<Args>(args)...) {
245 ~constexpr_optional_base() =
default;
249 using OptionalBase =
typename std::conditional<
250 std::is_trivially_destructible<T>::value,
251 constexpr_optional_base<typename std::remove_const<T>::type>,
252 optional_base<typename std::remove_const<T>::type>
270 static_assert( !std::is_same<
typename std::decay<T>::type, nullopt_t>::value,
"bad T");
271 static_assert( !std::is_same<
typename std::decay<T>::type,
in_place_t>::value,
"bad T");
273 constexpr
bool initialized()
const noexcept {
274 return OptionalBase<T>::init_;
277 typename std::remove_const<T>::type* dataptr() {
278 return std::addressof(OptionalBase<T>::storage_.value_);
281 constexpr
const T* dataptr()
const {
282 return detail_::static_addressof(OptionalBase<T>::storage_.value_);
285 constexpr
const T& contained_val()
const& {
286 return OptionalBase<T>::storage_.value_;
289 constexpr T&& contained_val() && {
290 return std::move(OptionalBase<T>::storage_.value_);
293 constexpr T& contained_val() & {
294 return OptionalBase<T>::storage_.value_;
297 void clear() noexcept {
298 if (initialized()) dataptr()->T::~T();
299 OptionalBase<T>::init_ =
false;
302 template <
class... Args>
303 void initialize(Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
304 assert(!OptionalBase<T>::init_);
305 ::new (
static_cast<void*
> (dataptr())) T(std::forward<Args>(args)...);
306 OptionalBase<T>::init_ =
true;
309 template <
class U,
class... Args>
310 void initialize(std::initializer_list<U> il, Args&&... args) noexcept(noexcept(T(il, std::forward<Args>(args)...))) {
311 assert(!OptionalBase<T>::init_);
312 ::new (
static_cast<void*
> (dataptr())) T(il, std::forward<Args>(args)...);
313 OptionalBase<T>::init_ =
true;
317 typedef T value_type;
321 constexpr
optional() noexcept : OptionalBase<T>() {
324 constexpr
optional(nullopt_t) noexcept : OptionalBase<T>() {
328 : OptionalBase<T>() {
329 if (rhs.initialized()) {
330 ::new (
static_cast<void*
> (dataptr())) T(*rhs);
331 OptionalBase<T>::init_ =
true;
335 optional(
optional&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value)
336 : OptionalBase<T>() {
337 if (rhs.initialized()) {
338 ::new (
static_cast<void*
> (dataptr())) T(std::move(*rhs));
339 OptionalBase<T>::init_ =
true;
343 constexpr
optional(
const T& v) : OptionalBase<T>(v) {
346 constexpr
optional(T&& v) : OptionalBase<T>(constexpr_move(v)) {
349 template <
class... Args>
351 : OptionalBase<T>(
in_place_t{}, constexpr_forward<Args>(args)...) {
354 template <
class U,
class... Args, GUL_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
356 : OptionalBase<T>(
in_place_t{}, il, constexpr_forward<Args>(args)...) {
364 optional& operator=(nullopt_t) noexcept {
370 if (initialized() ==
true && rhs.initialized() ==
false) clear();
371 else if (initialized() ==
false && rhs.initialized() ==
true) initialize(*rhs);
372 else if (initialized() ==
true && rhs.initialized() ==
true) contained_val() = *rhs;
377 noexcept(std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value) {
378 if (initialized() ==
true && rhs.initialized() ==
false) clear();
379 else if (initialized() ==
false && rhs.initialized() ==
true) initialize(std::move(*rhs));
380 else if (initialized() ==
true && rhs.initialized() ==
true) contained_val() = std::move(*rhs);
385 auto operator=(U&& v)
386 ->
typename std::enable_if<std::is_same<typename std::decay<U>::type, T>::value,
optional&>::type {
388 contained_val() = std::forward<U>(v);
390 initialize(std::forward<U>(v));
395 template <
class... Args>
396 void emplace(Args&&... args) {
398 initialize(std::forward<Args>(args)...);
401 template <
class U,
class... Args>
402 void emplace(std::initializer_list<U> il, Args&&... args) {
404 initialize<U, Args...>(il, std::forward<Args>(args)...);
409 void swap(
optional<T>& rhs) noexcept(std::is_nothrow_move_constructible<T>::value
410 && noexcept(detail_::swap_ns::adl_swap(std::declval<T&>(), std::declval<T&>()))) {
411 if (initialized() ==
true && rhs.initialized() ==
false) {
412 rhs.initialize(std::move(* *
this));
414 }
else if (initialized() ==
false && rhs.initialized() ==
true) {
415 initialize(std::move(*rhs));
417 }
else if (initialized() ==
true && rhs.initialized() ==
true) {
419 swap(* *
this, *rhs);
425 explicit constexpr
operator bool()
const noexcept {
426 return initialized();
429 constexpr
bool has_value()
const noexcept {
430 return initialized();
433 constexpr T
const* operator->()
const {
434 return GUL_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr());
437 constexpr T* operator->() {
438 assert(initialized());
442 constexpr T
const& operator*()
const& {
443 return GUL_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val());
446 constexpr T& operator*() & {
447 assert(initialized());
448 return contained_val();
451 constexpr T&& operator*() && {
452 assert(initialized());
453 return constexpr_move(contained_val());
456 constexpr T
const& value()
const& {
457 return initialized() ? contained_val() : (
throw bad_optional_access(
"bad optional access"), contained_val());
460 constexpr T& value() & {
461 if (!initialized())
throw bad_optional_access(
"bad optional access");
462 return contained_val();
465 constexpr T&& value() && {
466 if (!initialized())
throw bad_optional_access(
"bad optional access");
467 return std::move(contained_val());
471 #pragma warning(push)
472 #pragma warning(disable: 4244)
476 constexpr T value_or(V&& v)
const& {
477 return *
this ? * * this : detail_::convert<T>(constexpr_forward<V>(v));
481 constexpr T value_or(V&& v) && {
482 return *
this ? constexpr_move(
const_cast<optional<T>&
> (*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v));
490 void reset() noexcept {
509 static_assert( !std::is_same<T, nullopt_t>::value,
"bad T");
510 static_assert( !std::is_same<T, in_place_t>::value,
"bad T");
517 constexpr
optional() noexcept : ref(
nullptr) {
520 constexpr
optional(nullopt_t) noexcept : ref(
nullptr) {
523 constexpr
optional(T& v) noexcept : ref(detail_::static_addressof(v)) {
531 explicit constexpr
optional(
in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {
540 optional& operator=(nullopt_t) noexcept {
555 template <
typename U>
556 auto operator=(U&& rhs) noexcept
557 ->
typename std::enable_if
559 std::is_same<typename std::decay<U>::type,
optional<T&>>::value,
567 template <
typename U>
568 auto operator=(U&& rhs) noexcept
569 ->
typename std::enable_if
571 !std::is_same<typename std::decay<U>::type,
optional<T&>>::value,
576 void emplace(T& v) noexcept {
577 ref = detail_::static_addressof(v);
580 void emplace(T&&) =
delete;
588 constexpr T* operator->()
const {
589 return GUL_OPTIONAL_ASSERTED_EXPRESSION(ref, ref);
592 constexpr T& operator*()
const {
593 return GUL_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref);
596 constexpr T& value()
const {
597 return ref ? *ref : (
throw bad_optional_access(
"bad optional access"), *ref);
600 explicit constexpr
operator bool()
const noexcept {
601 return ref !=
nullptr;
604 constexpr
bool has_value()
const noexcept {
605 return ref !=
nullptr;
609 constexpr
typename std::decay<T>::type value_or(V&& v)
const {
610 return *
this ? * * this : detail_::convert<typename std::decay<T>::type > (constexpr_forward<V>(v));
615 void reset() noexcept {
626 static_assert(
sizeof (T) == 0,
"optional rvalue references disallowed");
632 template <
class T> constexpr
bool operator==(
const optional<T>& x,
const optional<T>& y) {
633 return bool(x) != bool(y) ? false : bool(x) ==
false ? true : *x == *y;
636 template <
class T> constexpr
bool operator!=(
const optional<T>& x,
const optional<T>& y) {
640 template <
class T> constexpr
bool operator<(
const optional<T>& x,
const optional<T>& y) {
641 return (!y) ? false : (!x) ?
true : *x < *y;
644 template <
class T> constexpr
bool operator>(
const optional<T>& x,
const optional<T>& 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) {
659 template <
class T> constexpr
bool operator==(
const optional<T>& x, nullopt_t) noexcept {
663 template <
class T> constexpr
bool operator==(nullopt_t,
const optional<T>& x) noexcept {
667 template <
class T> constexpr
bool operator!=(
const optional<T>& x, nullopt_t) noexcept {
671 template <
class T> constexpr
bool operator!=(nullopt_t,
const optional<T>& x) noexcept {
675 template <
class T> constexpr
bool operator<(
const optional<T>&, nullopt_t) noexcept {
679 template <
class T> constexpr
bool operator<(nullopt_t,
const optional<T>& x) noexcept {
683 template <
class T> constexpr
bool operator<=(
const optional<T>& x, nullopt_t) noexcept {
687 template <
class T> constexpr
bool operator<=(nullopt_t,
const optional<T>&) noexcept {
691 template <
class T> constexpr
bool operator>(
const optional<T>& x, nullopt_t) noexcept {
695 template <
class T> constexpr
bool operator>(nullopt_t,
const optional<T>&) noexcept {
699 template <
class T> constexpr
bool operator>=(
const optional<T>&, nullopt_t) noexcept {
703 template <
class T> constexpr
bool operator>=(nullopt_t,
const optional<T>& x) noexcept {
711 template <
class T> constexpr
bool operator==(
const optional<T>& x,
const T& v) {
712 return bool(x) ? *x == v :
false;
715 template <
class T> constexpr
bool operator==(
const T& v,
const optional<T>& x) {
716 return bool(x) ? v == *x :
false;
719 template <
class T> constexpr
bool operator!=(
const optional<T>& x,
const T& v) {
720 return bool(x) ? *x != v :
true;
723 template <
class T> constexpr
bool operator!=(
const T& v,
const optional<T>& x) {
724 return bool(x) ? v != *x :
true;
727 template <
class T> constexpr
bool operator<(
const optional<T>& x,
const T& v) {
728 return bool(x) ? *x < v :
true;
731 template <
class T> constexpr
bool operator>(
const T& v,
const optional<T>& x) {
732 return bool(x) ? v > *x :
true;
735 template <
class T> constexpr
bool operator>(
const optional<T>& x,
const T& v) {
736 return bool(x) ? *x > v :
false;
739 template <
class T> constexpr
bool operator<(
const T& v,
const optional<T>& x) {
740 return bool(x) ? v < *x :
false;
743 template <
class T> constexpr
bool operator>=(
const optional<T>& x,
const T& v) {
744 return bool(x) ? *x >= v :
false;
747 template <
class T> constexpr
bool operator<=(
const T& v,
const optional<T>& x) {
748 return bool(x) ? v <= *x :
false;
751 template <
class T> constexpr
bool operator<=(
const optional<T>& x,
const T& v) {
752 return bool(x) ? *x <= v :
true;
755 template <
class T> constexpr
bool operator>=(
const T& v,
const optional<T>& x) {
756 return bool(x) ? v >= *x :
true;
762 template <
class T> constexpr
bool operator==(
const optional<T&>& x,
const T& v) {
763 return bool(x) ? *x == v :
false;
766 template <
class T> constexpr
bool operator==(
const T& v,
const optional<T&>& x) {
767 return bool(x) ? v == *x :
false;
770 template <
class T> constexpr
bool operator!=(
const optional<T&>& x,
const T& v) {
771 return bool(x) ? *x != v :
true;
774 template <
class T> constexpr
bool operator!=(
const T& v,
const optional<T&>& x) {
775 return bool(x) ? v != *x :
true;
778 template <
class T> constexpr
bool operator<(
const optional<T&>& x,
const T& v) {
779 return bool(x) ? *x < v :
true;
782 template <
class T> constexpr
bool operator>(
const T& v,
const optional<T&>& x) {
783 return bool(x) ? v > *x :
true;
786 template <
class T> constexpr
bool operator>(
const optional<T&>& x,
const T& v) {
787 return bool(x) ? *x > v :
false;
790 template <
class T> constexpr
bool operator<(
const T& v,
const optional<T&>& x) {
791 return bool(x) ? v < *x :
false;
794 template <
class T> constexpr
bool operator>=(
const optional<T&>& x,
const T& v) {
795 return bool(x) ? *x >= v :
false;
798 template <
class T> constexpr
bool operator<=(
const T& v,
const optional<T&>& x) {
799 return bool(x) ? v <= *x :
false;
802 template <
class T> constexpr
bool operator<=(
const optional<T&>& x,
const T& v) {
803 return bool(x) ? *x <= v :
true;
806 template <
class T> constexpr
bool operator>=(
const T& v,
const optional<T&>& x) {
807 return bool(x) ? v >= *x :
true;
812 template <
class T> constexpr
bool operator==(
const optional<const T&>& x,
const T& v) {
813 return bool(x) ? *x == v :
false;
816 template <
class T> constexpr
bool operator==(
const T& v,
const optional<const T&>& x) {
817 return bool(x) ? v == *x :
false;
820 template <
class T> constexpr
bool operator!=(
const optional<const T&>& x,
const T& v) {
821 return bool(x) ? *x != v :
true;
824 template <
class T> constexpr
bool operator!=(
const T& v,
const optional<const T&>& x) {
825 return bool(x) ? v != *x :
true;
828 template <
class T> constexpr
bool operator<(
const optional<const T&>& x,
const T& v) {
829 return bool(x) ? *x < v :
true;
832 template <
class T> constexpr
bool operator>(
const T& v,
const optional<const T&>& x) {
833 return bool(x) ? v > *x :
true;
836 template <
class T> constexpr
bool operator>(
const optional<const T&>& x,
const T& v) {
837 return bool(x) ? *x > v :
false;
840 template <
class T> constexpr
bool operator<(
const T& v,
const optional<const T&>& x) {
841 return bool(x) ? v < *x :
false;
844 template <
class T> constexpr
bool operator>=(
const optional<const T&>& x,
const T& v) {
845 return bool(x) ? *x >= v :
false;
848 template <
class T> constexpr
bool operator<=(
const T& v,
const optional<const T&>& x) {
849 return bool(x) ? v <= *x :
false;
852 template <
class T> constexpr
bool operator<=(
const optional<const T&>& x,
const T& v) {
853 return bool(x) ? *x <= v :
true;
856 template <
class T> constexpr
bool operator>=(
const T& v,
const optional<const T&>& x) {
857 return bool(x) ? v >= *x :
true;
864 void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y))) {
869 constexpr optional<typename std::decay<T>::type> make_optional(T&& v) {
870 return optional<typename std::decay<T>::type > (constexpr_forward<T>(v));
874 constexpr optional<X&> make_optional(std::reference_wrapper<X> v) {
875 return optional<X&>(v.get());
887 template <
typename T>
888 struct hash<
gul14::optional<T>>
890 typedef typename hash<T>::result_type result_type;
893 constexpr result_type operator()(argument_type
const& arg)
const {
894 return arg ? std::hash<T>{}(*arg) : result_type{};
898 template <
typename T>
899 struct hash<
gul14::optional<T&>>
901 typedef typename hash<T>::result_type result_type;
904 constexpr result_type operator()(argument_type
const& arg)
const {
905 return arg ? std::hash<T>{}(*arg) : result_type{};
911 #undef GUL_OPTIONAL_REQUIRES
912 #undef GUL_OPTIONAL_ASSERTED_EXPRESSION
A class template that can either contain a value of a certain type or not.
Definition: optional.h:507
A class template that can either contain a value of a certain type or not.
Definition: optional.h:268
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
A type for constructor disambiguation, used by gul14::expected, gul14::optional, and gul14::variant.
Definition: utility.h:36
Declaration of the in_place_t family of types and constants and of the monostate type.