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
66 inline constexpr T&& constexpr_forward(
typename std::remove_reference<T>::type& t) noexcept {
67 return static_cast<T&&
> (t);
71 inline constexpr T&& constexpr_forward(
typename std::remove_reference<T>::type&& t) noexcept {
72 static_assert(!std::is_lvalue_reference<T>::value,
"!!");
73 return static_cast<T&&
> (t);
77 inline constexpr
typename std::remove_reference<T>::type&& constexpr_move(T&& t) noexcept {
78 return static_cast<typename std::remove_reference<T>::type&&
> (t);
83 #define GUL_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR)
85 #define GUL_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR)))
94 struct has_overloaded_addressof {
97 constexpr
static bool has_overload(...) {
101 template <class X, size_t S = sizeof (std::declval<X&>().operator&()) >
102 constexpr
static bool has_overload(
bool) {
106 constexpr
static bool value = has_overload<T>(
true);
109 template <
typename T, GUL_OPTIONAL_REQUIRES(!has_overloaded_addressof<T>)>
110 constexpr T* static_addressof(T& ref) {
114 template <
typename T, GUL_OPTIONAL_REQUIRES(has_overloaded_addressof<T>) >
115 T* static_addressof(T& ref) {
116 return std::addressof(ref);
123 constexpr U convert(U v) {
132 void adl_swap(T& t, T& u) noexcept(noexcept(
swap(t, u))) {
140 constexpr
struct trivial_init_t {
151 constexpr
explicit nullopt_t(init) {
154 constexpr nullopt_t nullopt{nullopt_t::init()};
159 class bad_optional_access :
public std::logic_error {
161 explicit bad_optional_access(
const std::string& what_arg) : std::logic_error{what_arg}
164 explicit bad_optional_access(
const char* what_arg) : std::logic_error{what_arg}
171 unsigned char dummy_;
174 constexpr storage_t(trivial_init_t) noexcept : dummy_() {
177 template <
class... Args>
178 constexpr storage_t(Args&&... args) : value_(constexpr_forward<Args>(args)...) {
186 union constexpr_storage_t {
187 unsigned char dummy_;
190 constexpr constexpr_storage_t(trivial_init_t) noexcept : dummy_() {
193 template <
class... Args>
194 constexpr constexpr_storage_t(Args&&... args) : value_(constexpr_forward<Args>(args)...) {
197 ~constexpr_storage_t() =
default;
201 struct optional_base {
203 storage_t<T> storage_;
205 constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {
208 explicit constexpr optional_base(
const T& v) : init_(true), storage_(v) {
211 explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {
214 template <
class... Args>
explicit optional_base(in_place_t, Args&&... args)
215 : init_(true), storage_(constexpr_forward<Args>(args)...) {
218 template <
class U,
class... Args, GUL_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
219 explicit optional_base(in_place_t, std::initializer_list<U> il, Args&&... args)
220 : init_(true), storage_(il, std::forward<Args>(args)...) {
224 if (init_) storage_.value_.T::~T();
229 struct constexpr_optional_base {
231 constexpr_storage_t<T> storage_;
233 constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {
236 explicit constexpr constexpr_optional_base(
const T& v) : init_(true), storage_(v) {
239 explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {
242 template <
class... Args>
explicit constexpr constexpr_optional_base(in_place_t, Args&&... args)
243 : init_(true), storage_(constexpr_forward<Args>(args)...) {
246 template <
class U,
class... Args, GUL_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
247 constexpr
explicit constexpr_optional_base(in_place_t, std::initializer_list<U> il, Args&&... args)
248 : init_(true), storage_(il, std::forward<Args>(args)...) {
251 ~constexpr_optional_base() =
default;
255 using OptionalBase =
typename std::conditional<
256 std::is_trivially_destructible<T>::value,
257 constexpr_optional_base<typename std::remove_const<T>::type>,
258 optional_base<typename std::remove_const<T>::type>
276 static_assert( !std::is_same<
typename std::decay<T>::type, nullopt_t>::value,
"bad T");
277 static_assert( !std::is_same<
typename std::decay<T>::type,
in_place_t>::value,
"bad T");
279 constexpr
bool initialized()
const noexcept {
280 return OptionalBase<T>::init_;
283 typename std::remove_const<T>::type* dataptr() {
284 return std::addressof(OptionalBase<T>::storage_.value_);
287 constexpr
const T* dataptr()
const {
288 return detail_::static_addressof(OptionalBase<T>::storage_.value_);
291 constexpr
const T& contained_val()
const& {
292 return OptionalBase<T>::storage_.value_;
295 constexpr T&& contained_val() && {
296 return std::move(OptionalBase<T>::storage_.value_);
299 constexpr T& contained_val() & {
300 return OptionalBase<T>::storage_.value_;
303 void clear() noexcept {
304 if (initialized()) dataptr()->T::~T();
305 OptionalBase<T>::init_ =
false;
308 template <
class... Args>
309 void initialize(Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
310 assert(!OptionalBase<T>::init_);
311 ::new (
static_cast<void*
> (dataptr())) T(std::forward<Args>(args)...);
312 OptionalBase<T>::init_ =
true;
315 template <
class U,
class... Args>
316 void initialize(std::initializer_list<U> il, Args&&... args) noexcept(noexcept(T(il, std::forward<Args>(args)...))) {
317 assert(!OptionalBase<T>::init_);
318 ::new (
static_cast<void*
> (dataptr())) T(il, std::forward<Args>(args)...);
319 OptionalBase<T>::init_ =
true;
323 typedef T value_type;
327 constexpr
optional() noexcept : OptionalBase<T>() {
330 constexpr
optional(nullopt_t) noexcept : OptionalBase<T>() {
334 : OptionalBase<T>() {
335 if (rhs.initialized()) {
336 ::new (
static_cast<void*
> (dataptr())) T(*rhs);
337 OptionalBase<T>::init_ =
true;
341 optional(
optional&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value)
342 : OptionalBase<T>() {
343 if (rhs.initialized()) {
344 ::new (
static_cast<void*
> (dataptr())) T(std::move(*rhs));
345 OptionalBase<T>::init_ =
true;
349 constexpr
optional(
const T& v) : OptionalBase<T>(v) {
352 constexpr
optional(T&& v) : OptionalBase<T>(constexpr_move(v)) {
355 template <
class... Args>
357 : OptionalBase<T>(
in_place_t{}, constexpr_forward<Args>(args)...) {
360 template <
class U,
class... Args, GUL_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
362 : OptionalBase<T>(
in_place_t{}, il, constexpr_forward<Args>(args)...) {
370 optional& operator=(nullopt_t) noexcept {
376 if (initialized() ==
true && rhs.initialized() ==
false) clear();
377 else if (initialized() ==
false && rhs.initialized() ==
true) initialize(*rhs);
378 else if (initialized() ==
true && rhs.initialized() ==
true) contained_val() = *rhs;
383 noexcept(std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value) {
384 if (initialized() ==
true && rhs.initialized() ==
false) clear();
385 else if (initialized() ==
false && rhs.initialized() ==
true) initialize(std::move(*rhs));
386 else if (initialized() ==
true && rhs.initialized() ==
true) contained_val() = std::move(*rhs);
391 auto operator=(U&& v)
392 ->
typename std::enable_if<std::is_same<typename std::decay<U>::type, T>::value,
optional&>::type {
394 contained_val() = std::forward<U>(v);
396 initialize(std::forward<U>(v));
401 template <
class... Args>
402 void emplace(Args&&... args) {
404 initialize(std::forward<Args>(args)...);
407 template <
class U,
class... Args>
408 void emplace(std::initializer_list<U> il, Args&&... args) {
410 initialize<U, Args...>(il, std::forward<Args>(args)...);
415 void swap(
optional<T>& rhs) noexcept(std::is_nothrow_move_constructible<T>::value
416 && noexcept(detail_::swap_ns::adl_swap(std::declval<T&>(), std::declval<T&>()))) {
417 if (initialized() ==
true && rhs.initialized() ==
false) {
418 rhs.initialize(std::move(* *
this));
420 }
else if (initialized() ==
false && rhs.initialized() ==
true) {
421 initialize(std::move(*rhs));
423 }
else if (initialized() ==
true && rhs.initialized() ==
true) {
425 swap(* *
this, *rhs);
431 explicit constexpr
operator bool()
const noexcept {
432 return initialized();
435 constexpr
bool has_value()
const noexcept {
436 return initialized();
439 constexpr T
const* operator->()
const {
440 return GUL_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr());
443 constexpr T* operator->() {
444 assert(initialized());
448 constexpr T
const& operator*()
const& {
449 return GUL_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val());
452 constexpr T& operator*() & {
453 assert(initialized());
454 return contained_val();
457 constexpr T&& operator*() && {
458 assert(initialized());
459 return constexpr_move(contained_val());
462 constexpr T
const& value()
const& {
463 return initialized() ? contained_val() : (
throw bad_optional_access(
"bad optional access"), contained_val());
466 constexpr T& value() & {
467 if (!initialized())
throw bad_optional_access(
"bad optional access");
468 return contained_val();
471 constexpr T&& value() && {
472 if (!initialized())
throw bad_optional_access(
"bad optional access");
473 return std::move(contained_val());
477 #pragma warning(push)
478 #pragma warning(disable: 4244)
482 constexpr T value_or(V&& v)
const& {
483 return *
this ? * * this : detail_::convert<T>(constexpr_forward<V>(v));
487 constexpr T value_or(V&& v) && {
488 return *
this ? constexpr_move(
const_cast<optional<T>&
> (*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v));
496 void reset() noexcept {
515 static_assert( !std::is_same<T, nullopt_t>::value,
"bad T");
516 static_assert( !std::is_same<T, in_place_t>::value,
"bad T");
523 constexpr
optional() noexcept : ref(
nullptr) {
526 constexpr
optional(nullopt_t) noexcept : ref(
nullptr) {
529 constexpr
optional(T& v) noexcept : ref(detail_::static_addressof(v)) {
537 explicit constexpr
optional(
in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {
546 optional& operator=(nullopt_t) noexcept {
561 template <
typename U>
562 auto operator=(U&& rhs) noexcept
563 ->
typename std::enable_if
565 std::is_same<typename std::decay<U>::type,
optional<T&>>::value,
573 template <
typename U>
574 auto operator=(U&& rhs) noexcept
575 ->
typename std::enable_if
577 !std::is_same<typename std::decay<U>::type,
optional<T&>>::value,
582 void emplace(T& v) noexcept {
583 ref = detail_::static_addressof(v);
586 void emplace(T&&) =
delete;
594 constexpr T* operator->()
const {
595 return GUL_OPTIONAL_ASSERTED_EXPRESSION(ref, ref);
598 constexpr T& operator*()
const {
599 return GUL_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref);
602 constexpr T& value()
const {
603 return ref ? *ref : (
throw bad_optional_access(
"bad optional access"), *ref);
606 explicit constexpr
operator bool()
const noexcept {
607 return ref !=
nullptr;
610 constexpr
bool has_value()
const noexcept {
611 return ref !=
nullptr;
615 constexpr
typename std::decay<T>::type value_or(V&& v)
const {
616 return *
this ? * * this : detail_::convert<typename std::decay<T>::type > (constexpr_forward<V>(v));
621 void reset() noexcept {
632 static_assert(
sizeof (T) == 0,
"optional rvalue references disallowed");
638 template <
class T> constexpr
bool operator==(
const optional<T>& x,
const optional<T>& y) {
639 return bool(x) != bool(y) ? false : bool(x) ==
false ? true : *x == *y;
642 template <
class T> constexpr
bool operator!=(
const optional<T>& x,
const optional<T>& y) {
646 template <
class T> constexpr
bool operator<(
const optional<T>& x,
const optional<T>& y) {
647 return (!y) ? false : (!x) ?
true : *x < *y;
650 template <
class T> constexpr
bool operator>(
const optional<T>& x,
const optional<T>& y) {
654 template <
class T> constexpr
bool operator<=(
const optional<T>& x,
const optional<T>& y) {
658 template <
class T> constexpr
bool operator>=(
const optional<T>& x,
const optional<T>& y) {
665 template <
class T> constexpr
bool operator==(
const optional<T>& x, nullopt_t) noexcept {
669 template <
class T> constexpr
bool operator==(nullopt_t,
const optional<T>& x) noexcept {
673 template <
class T> constexpr
bool operator!=(
const optional<T>& x, nullopt_t) noexcept {
677 template <
class T> constexpr
bool operator!=(nullopt_t,
const optional<T>& x) noexcept {
681 template <
class T> constexpr
bool operator<(
const optional<T>&, nullopt_t) noexcept {
685 template <
class T> constexpr
bool operator<(nullopt_t,
const optional<T>& x) noexcept {
689 template <
class T> constexpr
bool operator<=(
const optional<T>& x, nullopt_t) noexcept {
693 template <
class T> constexpr
bool operator<=(nullopt_t,
const optional<T>&) noexcept {
697 template <
class T> constexpr
bool operator>(
const optional<T>& x, nullopt_t) noexcept {
701 template <
class T> constexpr
bool operator>(nullopt_t,
const optional<T>&) noexcept {
705 template <
class T> constexpr
bool operator>=(
const optional<T>&, nullopt_t) noexcept {
709 template <
class T> constexpr
bool operator>=(nullopt_t,
const optional<T>& x) noexcept {
717 template <
class T> constexpr
bool operator==(
const optional<T>& x,
const T& v) {
718 return bool(x) ? *x == v :
false;
721 template <
class T> constexpr
bool operator==(
const T& v,
const optional<T>& x) {
722 return bool(x) ? v == *x :
false;
725 template <
class T> constexpr
bool operator!=(
const optional<T>& x,
const T& v) {
726 return bool(x) ? *x != v :
true;
729 template <
class T> constexpr
bool operator!=(
const T& v,
const optional<T>& x) {
730 return bool(x) ? v != *x :
true;
733 template <
class T> constexpr
bool operator<(
const optional<T>& x,
const T& v) {
734 return bool(x) ? *x < v :
true;
737 template <
class T> constexpr
bool operator>(
const T& v,
const optional<T>& x) {
738 return bool(x) ? v > *x :
true;
741 template <
class T> constexpr
bool operator>(
const optional<T>& x,
const T& v) {
742 return bool(x) ? *x > v :
false;
745 template <
class T> constexpr
bool operator<(
const T& v,
const optional<T>& x) {
746 return bool(x) ? v < *x :
false;
749 template <
class T> constexpr
bool operator>=(
const optional<T>& x,
const T& v) {
750 return bool(x) ? *x >= v :
false;
753 template <
class T> constexpr
bool operator<=(
const T& v,
const optional<T>& x) {
754 return bool(x) ? v <= *x :
false;
757 template <
class T> constexpr
bool operator<=(
const optional<T>& x,
const T& v) {
758 return bool(x) ? *x <= v :
true;
761 template <
class T> constexpr
bool operator>=(
const T& v,
const optional<T>& x) {
762 return bool(x) ? v >= *x :
true;
768 template <
class T> constexpr
bool operator==(
const optional<T&>& x,
const T& v) {
769 return bool(x) ? *x == v :
false;
772 template <
class T> constexpr
bool operator==(
const T& v,
const optional<T&>& x) {
773 return bool(x) ? v == *x :
false;
776 template <
class T> constexpr
bool operator!=(
const optional<T&>& x,
const T& v) {
777 return bool(x) ? *x != v :
true;
780 template <
class T> constexpr
bool operator!=(
const T& v,
const optional<T&>& x) {
781 return bool(x) ? v != *x :
true;
784 template <
class T> constexpr
bool operator<(
const optional<T&>& x,
const T& v) {
785 return bool(x) ? *x < v :
true;
788 template <
class T> constexpr
bool operator>(
const T& v,
const optional<T&>& x) {
789 return bool(x) ? v > *x :
true;
792 template <
class T> constexpr
bool operator>(
const optional<T&>& x,
const T& v) {
793 return bool(x) ? *x > v :
false;
796 template <
class T> constexpr
bool operator<(
const T& v,
const optional<T&>& x) {
797 return bool(x) ? v < *x :
false;
800 template <
class T> constexpr
bool operator>=(
const optional<T&>& x,
const T& v) {
801 return bool(x) ? *x >= v :
false;
804 template <
class T> constexpr
bool operator<=(
const T& v,
const optional<T&>& x) {
805 return bool(x) ? v <= *x :
false;
808 template <
class T> constexpr
bool operator<=(
const optional<T&>& x,
const T& v) {
809 return bool(x) ? *x <= v :
true;
812 template <
class T> constexpr
bool operator>=(
const T& v,
const optional<T&>& x) {
813 return bool(x) ? v >= *x :
true;
818 template <
class T> constexpr
bool operator==(
const optional<const T&>& x,
const T& v) {
819 return bool(x) ? *x == v :
false;
822 template <
class T> constexpr
bool operator==(
const T& v,
const optional<const T&>& x) {
823 return bool(x) ? v == *x :
false;
826 template <
class T> constexpr
bool operator!=(
const optional<const T&>& x,
const T& v) {
827 return bool(x) ? *x != v :
true;
830 template <
class T> constexpr
bool operator!=(
const T& v,
const optional<const T&>& x) {
831 return bool(x) ? v != *x :
true;
834 template <
class T> constexpr
bool operator<(
const optional<const T&>& x,
const T& v) {
835 return bool(x) ? *x < v :
true;
838 template <
class T> constexpr
bool operator>(
const T& v,
const optional<const T&>& x) {
839 return bool(x) ? v > *x :
true;
842 template <
class T> constexpr
bool operator>(
const optional<const T&>& x,
const T& v) {
843 return bool(x) ? *x > v :
false;
846 template <
class T> constexpr
bool operator<(
const T& v,
const optional<const T&>& x) {
847 return bool(x) ? v < *x :
false;
850 template <
class T> constexpr
bool operator>=(
const optional<const T&>& x,
const T& v) {
851 return bool(x) ? *x >= v :
false;
854 template <
class T> constexpr
bool operator<=(
const T& v,
const optional<const T&>& x) {
855 return bool(x) ? v <= *x :
false;
858 template <
class T> constexpr
bool operator<=(
const optional<const T&>& x,
const T& v) {
859 return bool(x) ? *x <= v :
true;
862 template <
class T> constexpr
bool operator>=(
const T& v,
const optional<const T&>& x) {
863 return bool(x) ? v >= *x :
true;
870 void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y))) {
875 constexpr optional<typename std::decay<T>::type> make_optional(T&& v) {
876 return optional<typename std::decay<T>::type > (constexpr_forward<T>(v));
880 constexpr optional<X&> make_optional(std::reference_wrapper<X> v) {
881 return optional<X&>(v.get());
894 template <
typename T>
895 struct hash<
gul14::optional<T>>
897 typedef typename hash<T>::result_type result_type;
900 constexpr result_type operator()(argument_type
const& arg)
const {
901 return arg ? std::hash<T>{}(*arg) : result_type{};
905 template <
typename T>
906 struct hash<
gul14::optional<T&>>
908 typedef typename hash<T>::result_type result_type;
911 constexpr result_type operator()(argument_type
const& arg)
const {
912 return arg ? std::hash<T>{}(*arg) : result_type{};
918 #undef GUL_OPTIONAL_REQUIRES
919 #undef GUL_OPTIONAL_ASSERTED_EXPRESSION
A class template that can either contain a value of a certain type or not.
Definition: optional.h:513
A class template that can either contain a value of a certain type or not.
Definition: optional.h:274
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:1656
Definition of macros used internally by GUL.
Namespace gul14 contains all functions and classes of the General Utility Library.
Definition: doxygen.h:26
A type for constructor disambiguation, used by gul14::expected, gul14::optional, and gul14::variant.
Definition: utility.h:42
Declaration of the in_place_t family of types and constants and of the monostate type.