diff --git a/tl/optional.hpp b/tl/optional.hpp index 4759bef..8e7890b 100644 --- a/tl/optional.hpp +++ b/tl/optional.hpp @@ -72,339 +72,337 @@ #define TL_OPTIONAL_11_CONSTEXPR constexpr #endif - namespace tl { +namespace tl { #ifndef TL_MONOSTATE_INPLACE_MUTEX #define TL_MONOSTATE_INPLACE_MUTEX - /// \brief Used to represent an optional with no data; essentially a bool - class monostate {}; +/// \brief Used to represent an optional with no data; essentially a bool +class monostate {}; - /// \brief A tag type to tell optional to construct its value in-place - struct in_place_t { - explicit in_place_t() = default; - }; - /// \brief A tag to tell optional to construct its value in-place - static constexpr in_place_t in_place{}; +/// \brief A tag type to tell optional to construct its value in-place +struct in_place_t { + explicit in_place_t() = default; +}; +/// \brief A tag to tell optional to construct its value in-place +static constexpr in_place_t in_place{}; #endif - template class optional; +template class optional; - /// \exclude - namespace detail { +/// \exclude +namespace detail { #ifndef TL_TRAITS_MUTEX #define TL_TRAITS_MUTEX - // C++14-style aliases for brevity - template using remove_const_t = typename std::remove_const::type; - template - using remove_reference_t = typename std::remove_reference::type; - template using decay_t = typename std::decay::type; - template - using enable_if_t = typename std::enable_if::type; - template - using conditional_t = typename std::conditional::type; +// C++14-style aliases for brevity +template using remove_const_t = typename std::remove_const::type; +template +using remove_reference_t = typename std::remove_reference::type; +template using decay_t = typename std::decay::type; +template +using enable_if_t = typename std::enable_if::type; +template +using conditional_t = typename std::conditional::type; - // std::conjunction from C++17 - template struct conjunction : std::true_type {}; - template struct conjunction : B {}; - template - struct conjunction - : std::conditional, B>::type {}; +// std::conjunction from C++17 +template struct conjunction : std::true_type {}; +template struct conjunction : B {}; +template +struct conjunction + : std::conditional, B>::type {}; - // std::invoke from C++17 - // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround - template >{}>, - int = 0> - constexpr auto invoke(Fn &&f, Args &&... args) noexcept( - noexcept(std::mem_fn(f)(std::forward(args)...))) - -> decltype(std::mem_fn(f)(std::forward(args)...)) { - return std::mem_fn(f)(std::forward(args)...); - } +// std::invoke from C++17 +// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround +template >{}>, + int = 0> +constexpr auto invoke(Fn &&f, Args &&... args) noexcept( + noexcept(std::mem_fn(f)(std::forward(args)...))) + -> decltype(std::mem_fn(f)(std::forward(args)...)) { + return std::mem_fn(f)(std::forward(args)...); +} - template >{}>> - constexpr auto invoke(Fn &&f, Args &&... args) noexcept( - noexcept(std::forward(f)(std::forward(args)...))) - -> decltype(std::forward(f)(std::forward(args)...)) { - return std::forward(f)(std::forward(args)...); - } +template >{}>> +constexpr auto invoke(Fn &&f, Args &&... args) noexcept( + noexcept(std::forward(f)(std::forward(args)...))) + -> decltype(std::forward(f)(std::forward(args)...)) { + return std::forward(f)(std::forward(args)...); +} - // std::invoke_result from C++17 - template struct invoke_result_impl; +// std::invoke_result from C++17 +template struct invoke_result_impl; - template - struct invoke_result_impl< - F, decltype(invoke(std::declval(), std::declval()...), void()), - Us...> { - using type = decltype(invoke(std::declval(), std::declval()...)); - }; +template +struct invoke_result_impl< + F, decltype(invoke(std::declval(), std::declval()...), void()), + Us...> { + using type = decltype(invoke(std::declval(), std::declval()...)); +}; - template - using invoke_result = invoke_result_impl; +template +using invoke_result = invoke_result_impl; - template - using invoke_result_t = typename invoke_result::type; +template +using invoke_result_t = typename invoke_result::type; #endif - // std::void_t from C++17 - template struct voider { using type = void; }; - template using void_t = typename voider::type; +// std::void_t from C++17 +template struct voider { using type = void; }; +template using void_t = typename voider::type; - // Trait for checking if a type is a tl::optional - template struct is_optional_impl : std::false_type {}; - template struct is_optional_impl> : std::true_type {}; - template using is_optional = is_optional_impl>; +// Trait for checking if a type is a tl::optional +template struct is_optional_impl : std::false_type {}; +template struct is_optional_impl> : std::true_type {}; +template using is_optional = is_optional_impl>; - // Change void to tl::monostate - template - using fixup_void = conditional_t::value, monostate, U>; +// Change void to tl::monostate +template +using fixup_void = conditional_t::value, monostate, U>; - template > - using get_map_return = optional>>; +template > +using get_map_return = optional>>; - // Check if invoking F for some Us returns void - template struct returns_void_impl; - template - struct returns_void_impl>, U...> - : std::is_void> {}; - template - using returns_void = returns_void_impl; +// Check if invoking F for some Us returns void +template struct returns_void_impl; +template +struct returns_void_impl>, U...> + : std::is_void> {}; +template +using returns_void = returns_void_impl; - template - using enable_if_ret_void = enable_if_t::value>; +template +using enable_if_ret_void = enable_if_t::value>; - template - using disable_if_ret_void = enable_if_t::value>; +template +using disable_if_ret_void = enable_if_t::value>; - template - using enable_forward_value = detail::enable_if_t< - std::is_constructible::value && - !std::is_same, in_place_t>::value && - !std::is_same, detail::decay_t>::value>; +template +using enable_forward_value = + detail::enable_if_t::value && + !std::is_same, in_place_t>::value && + !std::is_same, detail::decay_t>::value>; - template - using enable_from_other = detail::enable_if_t< - std::is_constructible::value && - !std::is_constructible &>::value && - !std::is_constructible &&>::value && - !std::is_constructible &>::value && - !std::is_constructible &&>::value && - !std::is_convertible &, T>::value && - !std::is_convertible &&, T>::value && - !std::is_convertible &, T>::value && - !std::is_convertible &&, T>::value>; +template +using enable_from_other = detail::enable_if_t< + std::is_constructible::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value>; - template - using enable_assign_forward = detail::enable_if_t< - !std::is_same, detail::decay_t>::value && - !detail::conjunction, - std::is_same>>::value && - std::is_constructible::value && std::is_assignable::value>; +template +using enable_assign_forward = detail::enable_if_t< + !std::is_same, detail::decay_t>::value && + !detail::conjunction, + std::is_same>>::value && + std::is_constructible::value && std::is_assignable::value>; - template - using enable_assign_from_other = detail::enable_if_t< - std::is_constructible::value && - std::is_assignable::value && - !std::is_constructible &>::value && - !std::is_constructible &&>::value && - !std::is_constructible &>::value && - !std::is_constructible &&>::value && - !std::is_convertible &, T>::value && - !std::is_convertible &&, T>::value && - !std::is_convertible &, T>::value && - !std::is_convertible &&, T>::value && - !std::is_assignable &>::value && - !std::is_assignable &&>::value && - !std::is_assignable &>::value && - !std::is_assignable &&>::value>; +template +using enable_assign_from_other = detail::enable_if_t< + std::is_constructible::value && + std::is_assignable::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_assignable &>::value && + !std::is_assignable &&>::value && + !std::is_assignable &>::value && + !std::is_assignable &&>::value>; #ifdef _MSC_VER - // TODO make a version which works with MSVC - template struct is_swappable : std::true_type {}; +// TODO make a version which works with MSVC +template struct is_swappable : std::true_type {}; - template - struct is_nothrow_swappable : std::true_type {}; +template struct is_nothrow_swappable : std::true_type {}; #else - // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept - namespace swap_adl_tests { - // if swap ADL finds this then it would call std::swap otherwise (same - // signature) - struct tag {}; +// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept +namespace swap_adl_tests { +// if swap ADL finds this then it would call std::swap otherwise (same +// signature) +struct tag {}; - template tag swap(T &, T &); - template tag swap(T (&a)[N], T (&b)[N]); +template tag swap(T &, T &); +template tag swap(T (&a)[N], T (&b)[N]); - // helper functions to test if an unqualified swap is possible, and if it - // becomes std::swap - template std::false_type can_swap(...) noexcept(false); - template (), std::declval()))> - std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), - std::declval()))); +// helper functions to test if an unqualified swap is possible, and if it +// becomes std::swap +template std::false_type can_swap(...) noexcept(false); +template (), std::declval()))> +std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), + std::declval()))); - template std::false_type uses_std(...); - template - std::is_same(), std::declval())), tag> - uses_std(int); +template std::false_type uses_std(...); +template +std::is_same(), std::declval())), tag> +uses_std(int); - template - struct is_std_swap_noexcept - : std::integral_constant::value && - std::is_nothrow_move_assignable::value> { - }; +template +struct is_std_swap_noexcept + : std::integral_constant::value && + std::is_nothrow_move_assignable::value> {}; - template - struct is_std_swap_noexcept : is_std_swap_noexcept {}; +template +struct is_std_swap_noexcept : is_std_swap_noexcept {}; - template - struct is_adl_swap_noexcept - : std::integral_constant(0))> {}; - } // namespace swap_adl_tests +template +struct is_adl_swap_noexcept + : std::integral_constant(0))> {}; +} // namespace swap_adl_tests - template - struct is_swappable - : std::integral_constant< - bool, - decltype(detail::swap_adl_tests::can_swap(0))::value && - (!decltype(detail::swap_adl_tests::uses_std(0))::value || - (std::is_move_assignable::value && - std::is_move_constructible::value))> {}; +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype(detail::swap_adl_tests::uses_std(0))::value || + (std::is_move_assignable::value && + std::is_move_constructible::value))> {}; - template - struct is_swappable - : std::integral_constant< - bool, - decltype(detail::swap_adl_tests::can_swap(0))::value && - (!decltype( - detail::swap_adl_tests::uses_std(0))::value || - is_swappable::value)> {}; +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype( + detail::swap_adl_tests::uses_std(0))::value || + is_swappable::value)> {}; - template - struct is_nothrow_swappable - : std::integral_constant< - bool, - is_swappable::value && - ((decltype(detail::swap_adl_tests::uses_std(0))::value && - detail::swap_adl_tests::is_std_swap_noexcept::value) || - (!decltype(detail::swap_adl_tests::uses_std(0))::value - &&detail::swap_adl_tests::is_adl_swap_noexcept< - T, U>::value))> {}; +template +struct is_nothrow_swappable + : std::integral_constant< + bool, + is_swappable::value && + ((decltype(detail::swap_adl_tests::uses_std(0))::value + &&detail::swap_adl_tests::is_std_swap_noexcept::value) || + (!decltype(detail::swap_adl_tests::uses_std(0))::value && + detail::swap_adl_tests::is_adl_swap_noexcept::value))> { +}; #endif - // The storage base manages the actual storage, and correctly propagates - // trivial destruction from T This case is for when T is trivially - // destructible - template ::value> - struct optional_storage_base { - TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept - : m_dummy(), m_has_value(false) {} +// The storage base manages the actual storage, and correctly propagates +// trivial destruction from T This case is for when T is trivially +// destructible +template ::value> +struct optional_storage_base { + TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept + : m_dummy(), m_has_value(false) {} - template - TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) - : m_value(std::forward(u)...), m_has_value(true) {} + template + TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) + : m_value(std::forward(u)...), m_has_value(true) {} - ~optional_storage_base() { - if (m_has_value) { - m_value.~T(); - m_has_value = false; - } + ~optional_storage_base() { + if (m_has_value) { + m_value.~T(); + m_has_value = false; } + } - struct dummy {}; - union { - dummy m_dummy; - T m_value; - }; - - bool m_has_value; + struct dummy {}; + union { + dummy m_dummy; + T m_value; }; - // This case is for when T is not trivially destructible - template struct optional_storage_base { - TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept - : m_dummy(), m_has_value(false) {} + bool m_has_value; +}; - template - TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) - : m_value(std::forward(u)...), m_has_value(true) {} +// This case is for when T is not trivially destructible +template struct optional_storage_base { + TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept + : m_dummy(), m_has_value(false) {} - // No destructor, so this class is trivially destructible + template + TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) + : m_value(std::forward(u)...), m_has_value(true) {} - struct dummy {}; - union { - dummy m_dummy; - T m_value; - }; + // No destructor, so this class is trivially destructible - bool m_has_value = false; + struct dummy {}; + union { + dummy m_dummy; + T m_value; }; - // This base class provides some handy member functions which can be used in - // further derived classes - template - struct optional_operations_base : optional_storage_base { - using optional_storage_base::optional_storage_base; + bool m_has_value = false; +}; - void hard_reset() noexcept { - get().~T(); - this->m_has_value = false; - } +// This base class provides some handy member functions which can be used in +// further derived classes +template struct optional_operations_base : optional_storage_base { + using optional_storage_base::optional_storage_base; - template void construct(Args &&... args) noexcept { - new (std::addressof(this->m_value)) T(std::forward(args)...); - this->m_has_value = true; - } + void hard_reset() noexcept { + get().~T(); + this->m_has_value = false; + } - template void assign(Opt &&rhs) { - if (this->has_value()) { - if (rhs.has_value()) { - this->m_value = std::forward(rhs).get(); - } else { - this->m_value.~T(); - this->m_has_value = false; - } - } + template void construct(Args &&... args) noexcept { + new (std::addressof(this->m_value)) T(std::forward(args)...); + this->m_has_value = true; + } + template void assign(Opt &&rhs) { + if (this->has_value()) { if (rhs.has_value()) { - construct(std::forward(rhs).get()); - } - } - - bool has_value() const { return this->m_has_value; } - - TL_OPTIONAL_11_CONSTEXPR T &get() & { return this->m_value; } - TL_OPTIONAL_11_CONSTEXPR const T &get() const & { return this->m_value; } - TL_OPTIONAL_11_CONSTEXPR T &&get() && { std::move(this->m_value); } -#ifndef TL_OPTIONAL_NO_CONSTRR - constexpr const T &&get() const && { return std::move(this->m_value); } -#endif - }; - - // This class manages conditionally having a trivial copy constructor - // This specialization is for when T is trivially copy constructible - template - struct optional_copy_base : optional_operations_base { - using optional_operations_base::optional_operations_base; - }; - - // This specialization is for when T is not trivially copy constructible - template - struct optional_copy_base : optional_operations_base { - using optional_operations_base::optional_operations_base; - - optional_copy_base() = default; - optional_copy_base(const optional_copy_base &rhs) { - if (rhs.has_value()) { - this->construct(rhs.get()); + this->m_value = std::forward(rhs).get(); } else { + this->m_value.~T(); this->m_has_value = false; } } - optional_copy_base(optional_copy_base &&rhs) = default; - optional_copy_base &operator=(const optional_copy_base &rhs) = default; - optional_copy_base &operator=(optional_copy_base &&rhs) = default; - }; + if (rhs.has_value()) { + construct(std::forward(rhs).get()); + } + } + + bool has_value() const { return this->m_has_value; } + + TL_OPTIONAL_11_CONSTEXPR T &get() & { return this->m_value; } + TL_OPTIONAL_11_CONSTEXPR const T &get() const & { return this->m_value; } + TL_OPTIONAL_11_CONSTEXPR T &&get() && { std::move(this->m_value); } +#ifndef TL_OPTIONAL_NO_CONSTRR + constexpr const T &&get() const && { return std::move(this->m_value); } +#endif +}; + +// This class manages conditionally having a trivial copy constructor +// This specialization is for when T is trivially copy constructible +template +struct optional_copy_base : optional_operations_base { + using optional_operations_base::optional_operations_base; +}; + +// This specialization is for when T is not trivially copy constructible +template +struct optional_copy_base : optional_operations_base { + using optional_operations_base::optional_operations_base; + + optional_copy_base() = default; + optional_copy_base(const optional_copy_base &rhs) { + if (rhs.has_value()) { + this->construct(rhs.get()); + } else { + this->m_has_value = false; + } + } + + optional_copy_base(optional_copy_base &&rhs) = default; + optional_copy_base &operator=(const optional_copy_base &rhs) = default; + optional_copy_base &operator=(optional_copy_base &&rhs) = default; +}; // This class manages conditionally having a trivial move constructor // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it @@ -412,55 +410,54 @@ // have to make do with a non-trivial move constructor even if T is trivially // move constructible #ifndef TL_OPTIONAL_GCC49 - template ::value> - struct optional_move_base : optional_copy_base { - using optional_copy_base::optional_copy_base; - }; +template ::value> +struct optional_move_base : optional_copy_base { + using optional_copy_base::optional_copy_base; +}; #else - template struct optional_move_base; +template struct optional_move_base; #endif - template - struct optional_move_base : optional_copy_base { - using optional_copy_base::optional_copy_base; +template struct optional_move_base : optional_copy_base { + using optional_copy_base::optional_copy_base; - optional_move_base() = default; - optional_move_base(const optional_move_base &rhs) = default; + optional_move_base() = default; + optional_move_base(const optional_move_base &rhs) = default; - optional_move_base(optional_move_base &&rhs) noexcept( - std::is_nothrow_move_constructible::value) { - if (rhs.has_value()) { - this->construct(std::move(rhs.get())); - } else { - this->m_has_value = false; - } + optional_move_base(optional_move_base &&rhs) noexcept( + std::is_nothrow_move_constructible::value) { + if (rhs.has_value()) { + this->construct(std::move(rhs.get())); + } else { + this->m_has_value = false; } - optional_move_base &operator=(const optional_move_base &rhs) = default; - optional_move_base &operator=(optional_move_base &&rhs) = default; - }; + } + optional_move_base &operator=(const optional_move_base &rhs) = default; + optional_move_base &operator=(optional_move_base &&rhs) = default; +}; - // This class manages conditionally having a trivial copy assignment operator - template - struct optional_copy_assign_base : optional_move_base { - using optional_move_base::optional_move_base; - }; +// This class manages conditionally having a trivial copy assignment operator +template +struct optional_copy_assign_base : optional_move_base { + using optional_move_base::optional_move_base; +}; - template - struct optional_copy_assign_base : optional_move_base { - using optional_move_base::optional_move_base; +template +struct optional_copy_assign_base : optional_move_base { + using optional_move_base::optional_move_base; - optional_copy_assign_base() = default; - optional_copy_assign_base(const optional_copy_assign_base &rhs) = default; + optional_copy_assign_base() = default; + optional_copy_assign_base(const optional_copy_assign_base &rhs) = default; - optional_copy_assign_base(optional_copy_assign_base &&rhs) = default; - optional_copy_assign_base &operator=(const optional_copy_assign_base &rhs) { - this->assign(rhs); - return *this; - } - optional_copy_assign_base & - operator=(optional_copy_assign_base &&rhs) = default; - }; + optional_copy_assign_base(optional_copy_assign_base &&rhs) = default; + optional_copy_assign_base &operator=(const optional_copy_assign_base &rhs) { + this->assign(rhs); + return *this; + } + optional_copy_assign_base & + operator=(optional_copy_assign_base &&rhs) = default; +}; // This class manages conditionally having a trivial move assignment operator // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it @@ -468,1192 +465,2018 @@ // to make do with a non-trivial move assignment operator even if T is trivially // move assignable #ifndef TL_OPTIONAL_GCC49 - template ::value - &&std::is_trivially_move_constructible::value - &&std::is_trivially_move_assignable::value> - struct optional_move_assign_base : optional_copy_assign_base { - using optional_copy_assign_base::optional_copy_assign_base; - }; +template ::value + &&std::is_trivially_move_constructible::value + &&std::is_trivially_move_assignable::value> +struct optional_move_assign_base : optional_copy_assign_base { + using optional_copy_assign_base::optional_copy_assign_base; +}; #else - template struct optional_move_assign_base; +template struct optional_move_assign_base; #endif - template - struct optional_move_assign_base : optional_copy_assign_base { - using optional_copy_assign_base::optional_copy_assign_base; +template +struct optional_move_assign_base : optional_copy_assign_base { + using optional_copy_assign_base::optional_copy_assign_base; - optional_move_assign_base() = default; - optional_move_assign_base(const optional_move_assign_base &rhs) = default; + optional_move_assign_base() = default; + optional_move_assign_base(const optional_move_assign_base &rhs) = default; - optional_move_assign_base(optional_move_assign_base &&rhs) = default; + optional_move_assign_base(optional_move_assign_base &&rhs) = default; - optional_move_assign_base & - operator=(const optional_move_assign_base &rhs) = default; + optional_move_assign_base & + operator=(const optional_move_assign_base &rhs) = default; - optional_move_assign_base & - operator=(optional_move_assign_base &&rhs) noexcept( - std::is_nothrow_move_constructible::value - &&std::is_nothrow_move_assignable::value) { - this->assign(std::move(rhs)); - return *this; - } - }; + optional_move_assign_base & + operator=(optional_move_assign_base &&rhs) noexcept( + std::is_nothrow_move_constructible::value + &&std::is_nothrow_move_assignable::value) { + this->assign(std::move(rhs)); + return *this; + } +}; - // optional_delete_ctor_base will conditionally delete copy and move - // constructors depending on whether T is copy/move constructible - template ::value, - bool EnableMove = std::is_move_constructible::value> - struct optional_delete_ctor_base { - optional_delete_ctor_base() = default; - optional_delete_ctor_base(const optional_delete_ctor_base &) = default; - optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default; - optional_delete_ctor_base & - operator=(const optional_delete_ctor_base &) = default; - optional_delete_ctor_base & - operator=(optional_delete_ctor_base &&) noexcept = default; - }; +// optional_delete_ctor_base will conditionally delete copy and move +// constructors depending on whether T is copy/move constructible +template ::value, + bool EnableMove = std::is_move_constructible::value> +struct optional_delete_ctor_base { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base &) = default; + optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default; + optional_delete_ctor_base & + operator=(const optional_delete_ctor_base &) = default; + optional_delete_ctor_base & + operator=(optional_delete_ctor_base &&) noexcept = default; +}; - template struct optional_delete_ctor_base { - optional_delete_ctor_base() = default; - optional_delete_ctor_base(const optional_delete_ctor_base &) = default; - optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete; - optional_delete_ctor_base & - operator=(const optional_delete_ctor_base &) = default; - optional_delete_ctor_base & - operator=(optional_delete_ctor_base &&) noexcept = default; - }; +template struct optional_delete_ctor_base { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base &) = default; + optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete; + optional_delete_ctor_base & + operator=(const optional_delete_ctor_base &) = default; + optional_delete_ctor_base & + operator=(optional_delete_ctor_base &&) noexcept = default; +}; - template struct optional_delete_ctor_base { - optional_delete_ctor_base() = default; - optional_delete_ctor_base(const optional_delete_ctor_base &) = delete; - optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default; - optional_delete_ctor_base & - operator=(const optional_delete_ctor_base &) = default; - optional_delete_ctor_base & - operator=(optional_delete_ctor_base &&) noexcept = default; - }; +template struct optional_delete_ctor_base { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base &) = delete; + optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default; + optional_delete_ctor_base & + operator=(const optional_delete_ctor_base &) = default; + optional_delete_ctor_base & + operator=(optional_delete_ctor_base &&) noexcept = default; +}; - template struct optional_delete_ctor_base { - optional_delete_ctor_base() = default; - optional_delete_ctor_base(const optional_delete_ctor_base &) = delete; - optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete; - optional_delete_ctor_base & - operator=(const optional_delete_ctor_base &) = default; - optional_delete_ctor_base & - operator=(optional_delete_ctor_base &&) noexcept = default; - }; +template struct optional_delete_ctor_base { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base &) = delete; + optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete; + optional_delete_ctor_base & + operator=(const optional_delete_ctor_base &) = default; + optional_delete_ctor_base & + operator=(optional_delete_ctor_base &&) noexcept = default; +}; - // optional_delete_assign_base will conditionally delete copy and move - // constructors depending on whether T is copy/move constructible + assignable - template ::value && - std::is_copy_assignable::value), - bool EnableMove = (std::is_move_constructible::value && - std::is_move_assignable::value)> - struct optional_delete_assign_base { - optional_delete_assign_base() = default; - optional_delete_assign_base(const optional_delete_assign_base &) = default; - optional_delete_assign_base(optional_delete_assign_base &&) noexcept = - default; - optional_delete_assign_base & - operator=(const optional_delete_assign_base &) = default; - optional_delete_assign_base & - operator=(optional_delete_assign_base &&) noexcept = default; - }; +// optional_delete_assign_base will conditionally delete copy and move +// constructors depending on whether T is copy/move constructible + assignable +template ::value && + std::is_copy_assignable::value), + bool EnableMove = (std::is_move_constructible::value && + std::is_move_assignable::value)> +struct optional_delete_assign_base { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base &) = default; + optional_delete_assign_base(optional_delete_assign_base &&) noexcept = + default; + optional_delete_assign_base & + operator=(const optional_delete_assign_base &) = default; + optional_delete_assign_base & + operator=(optional_delete_assign_base &&) noexcept = default; +}; - template struct optional_delete_assign_base { - optional_delete_assign_base() = default; - optional_delete_assign_base(const optional_delete_assign_base &) = default; - optional_delete_assign_base(optional_delete_assign_base &&) noexcept = - default; - optional_delete_assign_base & - operator=(const optional_delete_assign_base &) = default; - optional_delete_assign_base & - operator=(optional_delete_assign_base &&) noexcept = delete; - }; +template struct optional_delete_assign_base { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base &) = default; + optional_delete_assign_base(optional_delete_assign_base &&) noexcept = + default; + optional_delete_assign_base & + operator=(const optional_delete_assign_base &) = default; + optional_delete_assign_base & + operator=(optional_delete_assign_base &&) noexcept = delete; +}; - template struct optional_delete_assign_base { - optional_delete_assign_base() = default; - optional_delete_assign_base(const optional_delete_assign_base &) = default; - optional_delete_assign_base(optional_delete_assign_base &&) noexcept = - default; - optional_delete_assign_base & - operator=(const optional_delete_assign_base &) = delete; - optional_delete_assign_base & - operator=(optional_delete_assign_base &&) noexcept = default; - }; +template struct optional_delete_assign_base { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base &) = default; + optional_delete_assign_base(optional_delete_assign_base &&) noexcept = + default; + optional_delete_assign_base & + operator=(const optional_delete_assign_base &) = delete; + optional_delete_assign_base & + operator=(optional_delete_assign_base &&) noexcept = default; +}; - template struct optional_delete_assign_base { - optional_delete_assign_base() = default; - optional_delete_assign_base(const optional_delete_assign_base &) = default; - optional_delete_assign_base(optional_delete_assign_base &&) noexcept = - default; - optional_delete_assign_base & - operator=(const optional_delete_assign_base &) = delete; - optional_delete_assign_base & - operator=(optional_delete_assign_base &&) noexcept = delete; - }; +template struct optional_delete_assign_base { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base &) = default; + optional_delete_assign_base(optional_delete_assign_base &&) noexcept = + default; + optional_delete_assign_base & + operator=(const optional_delete_assign_base &) = delete; + optional_delete_assign_base & + operator=(optional_delete_assign_base &&) noexcept = delete; +}; - } // namespace detail +} // namespace detail - /// \brief A tag type to represent an empty optional - struct nullopt_t { - struct do_not_use {}; - constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {} - }; - /// \brief Represents an empty optional - /// \synopsis static constexpr nullopt_t nullopt; - /// - /// *Examples*: - /// ``` - /// tl::optional a = tl::nullopt; - /// void foo (tl::optional); - /// foo(tl::nullopt); //pass an empty optional - /// ``` - static constexpr nullopt_t nullopt{nullopt_t::do_not_use{}, - nullopt_t::do_not_use{}}; +/// \brief A tag type to represent an empty optional +struct nullopt_t { + struct do_not_use {}; + constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {} +}; +/// \brief Represents an empty optional +/// \synopsis static constexpr nullopt_t nullopt; +/// +/// *Examples*: +/// ``` +/// tl::optional a = tl::nullopt; +/// void foo (tl::optional); +/// foo(tl::nullopt); //pass an empty optional +/// ``` +static constexpr nullopt_t nullopt{nullopt_t::do_not_use{}, + nullopt_t::do_not_use{}}; - class bad_optional_access : public std::exception { - public: - bad_optional_access() = default; - const char *what() const noexcept { return "Optional has no value"; } - }; +class bad_optional_access : public std::exception { +public: + bad_optional_access() = default; + const char *what() const noexcept { return "Optional has no value"; } +}; - /// An optional object is an object that contains the storage for another - /// object and manages the lifetime of this contained object, if any. The - /// contained object may be initialized after the optional object has been - /// initialized, and may be destroyed before the optional object has been - /// destroyed. The initialization state of the contained object is tracked by - /// the optional object. - template - class optional : private detail::optional_move_assign_base, - private detail::optional_delete_ctor_base, - private detail::optional_delete_assign_base { - using base = detail::optional_move_assign_base; +/// An optional object is an object that contains the storage for another +/// object and manages the lifetime of this contained object, if any. The +/// contained object may be initialized after the optional object has been +/// initialized, and may be destroyed before the optional object has been +/// destroyed. The initialization state of the contained object is tracked by +/// the optional object. +template +class optional : private detail::optional_move_assign_base, + private detail::optional_delete_ctor_base, + private detail::optional_delete_assign_base { + using base = detail::optional_move_assign_base; - static_assert( - !std::is_reference::value, - "instantiation of optional with a reference type is ill-formed"); - static_assert(!std::is_same::value, - "instantiation of optional with in_place_t is ill-formed"); - static_assert(!std::is_same, nullopt_t>::value, - "instantiation of optional with nullopt_t is ill-formed"); + static_assert(!std::is_same::value, + "instantiation of optional with in_place_t is ill-formed"); + static_assert(!std::is_same, nullopt_t>::value, + "instantiation of optional with nullopt_t is ill-formed"); - public: +public: // The different versions for C++14 and 11 are needed because deduced return // types are not SFINAE-safe. This provides better support for things like // generic lambdas. C.f. // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) - /// \group and_then - /// Carries out some operation which returns an optional on the stored - /// object if there is one. \requires `std::invoke(std::forward(f), - /// value())` returns a `std::optional` for some `U`. \returns Let `U` be - /// the result of `std::invoke(std::forward(f), value())`. Returns a - /// `std::optional`. The return value is empty if `*this` is empty, - /// otherwise the return value of `std::invoke(std::forward(f), value())` - /// is returned. - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) &; - template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & { - using result = detail::invoke_result_t; - static_assert(detail::is_optional::value, - "F must return an optional"); + /// \group and_then + /// Carries out some operation which returns an optional on the stored + /// object if there is one. \requires `std::invoke(std::forward(f), + /// value())` returns a `std::optional` for some `U`. \returns Let `U` be + /// the result of `std::invoke(std::forward(f), value())`. Returns a + /// `std::optional`. The return value is empty if `*this` is empty, + /// otherwise the return value of `std::invoke(std::forward(f), value())` + /// is returned. + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) &; + template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); - return has_value() ? detail::invoke(std::forward(f), **this) - : result(nullopt); - } + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) &&; - template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && { - using result = detail::invoke_result_t; - static_assert(detail::is_optional::value, - "F must return an optional"); + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) &&; + template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); - return has_value() ? detail::invoke(std::forward(f), std::move(**this)) - : result(nullopt); - } + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) const &; - template constexpr auto and_then(F &&f) const & { - using result = detail::invoke_result_t; - static_assert(detail::is_optional::value, - "F must return an optional"); + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) const &; + template constexpr auto and_then(F &&f) const & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); - return has_value() ? detail::invoke(std::forward(f), **this) - : result(nullopt); - } + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } #ifndef TL_OPTIONAL_NO_CONSTRR - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) const &&; - template constexpr auto and_then(F &&f) const && { - using result = detail::invoke_result_t; - static_assert(detail::is_optional::value, - "F must return an optional"); + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) const &&; + template constexpr auto and_then(F &&f) const && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); - return has_value() ? detail::invoke(std::forward(f), std::move(**this)) - : result(nullopt); - } + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } #endif #else - /// \group and_then - /// Carries out some operation which returns an optional on the stored - /// object if there is one. \requires `std::invoke(std::forward(f), - /// value())` returns a `std::optional` for some `U`. \returns Let `U` be - /// the result of `std::invoke(std::forward(f), value())`. Returns a - /// `std::optional`. The return value is empty if `*this` is empty, - /// otherwise the return value of `std::invoke(std::forward(f), value())` - /// is returned. - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) &; - template - TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & { - using result = detail::invoke_result_t; - static_assert(detail::is_optional::value, - "F must return an optional"); + /// \group and_then + /// Carries out some operation which returns an optional on the stored + /// object if there is one. \requires `std::invoke(std::forward(f), + /// value())` returns a `std::optional` for some `U`. \returns Let `U` be + /// the result of `std::invoke(std::forward(f), value())`. Returns a + /// `std::optional`. The return value is empty if `*this` is empty, + /// otherwise the return value of `std::invoke(std::forward(f), value())` + /// is returned. + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) &; + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); - return has_value() ? detail::invoke(std::forward(f), **this) - : result(nullopt); - } + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) &&; - template - TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t - and_then(F &&f) && { - using result = detail::invoke_result_t; - static_assert(detail::is_optional::value, - "F must return an optional"); + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) &&; + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); - return has_value() ? detail::invoke(std::forward(f), std::move(**this)) - : result(nullopt); - } + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) const &; - template - constexpr detail::invoke_result_t and_then(F &&f) const & { - using result = detail::invoke_result_t; - static_assert(detail::is_optional::value, - "F must return an optional"); + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) const &; + template + constexpr detail::invoke_result_t and_then(F &&f) const & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); - return has_value() ? detail::invoke(std::forward(f), **this) - : result(nullopt); - } + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } #ifndef TL_OPTIONAL_NO_CONSTRR - /// \group and_then - /// \synopsis template \nconstexpr auto and_then(F &&f) const &&; - template - constexpr detail::invoke_result_t and_then(F &&f) const && { - using result = detail::invoke_result_t; - static_assert(detail::is_optional::value, - "F must return an optional"); + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) const &&; + template + constexpr detail::invoke_result_t and_then(F &&f) const && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); - return has_value() ? detail::invoke(std::forward(f), std::move(**this)) - : result(nullopt); - } + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } #endif #endif #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) - /// \brief Carries out some operation on the stored object if there is one. - /// \returns Let `U` be the result of `std::invoke(std::forward(f), - /// value())`. Returns a `std::optional`. The return value is empty if - /// `*this` is empty, otherwise an `optional` is constructed from the - /// return value of `std::invoke(std::forward(f), value())` and is - /// returned. - /// - /// \group map - /// \synopsis template constexpr auto map(F &&f) &; - template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & { - return map_impl(*this, std::forward(f)); - } - - /// \group map - /// \synopsis template constexpr auto map(F &&f) &&; - template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && { - return map_impl(std::move(*this), std::forward(f)); - } - - /// \group map - /// \synopsis template constexpr auto map(F &&f) const&; - template constexpr auto map(F &&f) const & { - return map_impl(*this, std::forward(f)); - } - - /// \group map - /// \synopsis template constexpr auto map(F &&f) const&&; - template constexpr auto map(F &&f) const && { - return map_impl(std::move(*this), std::forward(f)); - } -#else - /// \brief Carries out some operation on the stored object if there is one. - /// \returns Let `U` be the result of `std::invoke(std::forward(f), - /// value())`. Returns a `std::optional`. The return value is empty if - /// `*this` is empty, otherwise an `optional` is constructed from the - /// return value of `std::invoke(std::forward(f), value())` and is - /// returned. - /// - /// \group map - /// \synopsis template auto map(F &&f) &; - template - TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval(), - std::declval())) - map(F &&f) & { - return map_impl(*this, std::forward(f)); - } - - /// \group map - /// \synopsis template auto map(F &&f) &&; - template - TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval(), - std::declval())) - map(F &&f) && { - return map_impl(std::move(*this), std::forward(f)); - } - - /// \group map - /// \synopsis template auto map(F &&f) const&; - template - constexpr decltype(map_impl(std::declval(), - std::declval())) - map(F &&f) const & { - return map_impl(*this, std::forward(f)); - } - -#ifndef TL_OPTIONAL_NO_CONSTRR - /// \group map - /// \synopsis template auto map(F &&f) const&&; - template - constexpr decltype(map_impl(std::declval(), - std::declval())) - map(F &&f) const && { - return map_impl(std::move(*this), std::forward(f)); - } -#endif -#endif - - /// \brief Calls `f` if the optional is empty - /// \requires `std::invoke_result_t` must be void or convertible to - /// `optional`. \effects If `*this` has a value, returns `*this`. - /// Otherwise, if `f` returns `void`, calls `std::forward(f)` and returns - /// `std::nullopt`. Otherwise, returns `std::forward(f)()`. - /// - /// \group or_else - /// \synopsis template optional or_else (F &&f) &; - template * = nullptr> - optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { - if (has_value()) - return *this; - - std::forward(f)(); - return nullopt; - } - - /// \exclude - template * = nullptr> - optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { - return has_value() ? *this : std::forward(f)(); - } - - /// \group or_else - /// \synopsis template optional or_else (F &&f) &&; - template * = nullptr> - optional or_else(F &&f) && { - if (has_value()) - return std::move(*this); - - std::forward(f)(); - return nullopt; - } - - /// \exclude - template * = nullptr> - optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && { - return has_value() ? std::move(*this) : std::forward(f)(); - } - - /// \group or_else - /// \synopsis template optional or_else (F &&f) const &; - template * = nullptr> - optional or_else(F &&f) const & { - if (has_value()) - return *this; - - std::forward(f)(); - return nullopt; - } - - /// \exclude - template * = nullptr> - optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & { - return has_value() ? *this : std::forward(f)(); - } - -#ifndef TL_OPTIONAL_NO_CONSTRR - /// \exclude - template * = nullptr> - optional or_else(F &&f) const && { - if (has_value()) - return std::move(*this); - - std::forward(f)(); - return nullopt; - } - - /// \exclude - template * = nullptr> - optional or_else(F &&f) const && { - return has_value() ? std::move(*this) : std::forward(f)(); - } -#endif - - /// \brief Maps the stored value with `f` if there is one, otherwise returns - /// `u`. - /// - /// \details If there is a value stored, then `f` is called with `**this` - /// and the value is returned. Otherwise `u` is returned. - /// - /// \group map_or - template U map_or(F &&f, U &&u) & { - return has_value() ? detail::invoke(std::forward(f), **this) - : std::forward(u); - } - - /// \group map_or - template U map_or(F &&f, U &&u) && { - return has_value() ? detail::invoke(std::forward(f), std::move(**this)) - : std::forward(u); - } - - /// \group map_or - template U map_or(F &&f, U &&u) const & { - return has_value() ? detail::invoke(std::forward(f), **this) - : std::forward(u); - } - -#ifndef TL_OPTIONAL_NO_CONSTRR - /// \group map_or - template U map_or(F &&f, U &&u) const && { - return has_value() ? detail::invoke(std::forward(f), std::move(**this)) - : std::forward(u); - } -#endif - - /// \brief Maps the stored value with `f` if there is one, otherwise calls - /// `u` and returns the result. - /// - /// \details If there is a value stored, then `f` is - /// called with `**this` and the value is returned. Otherwise - /// `std::forward(u)()` is returned. - /// - /// \group map_or_else - /// \synopsis template \nauto map_or_else(F &&f, U &&u) &; - template - detail::invoke_result_t map_or_else(F &&f, U &&u) & { - return has_value() ? detail::invoke(std::forward(f), **this) - : std::forward(u)(); - } - - /// \group map_or_else - /// \synopsis template \nauto map_or_else(F &&f, U &&u) - /// &&; - template - detail::invoke_result_t map_or_else(F &&f, U &&u) && { - return has_value() ? detail::invoke(std::forward(f), std::move(**this)) - : std::forward(u)(); - } - - /// \group map_or_else - /// \synopsis template \nauto map_or_else(F &&f, U &&u) - /// const &; - template - detail::invoke_result_t map_or_else(F &&f, U &&u) const & { - return has_value() ? detail::invoke(std::forward(f), **this) - : std::forward(u)(); - } - -#ifndef TL_OPTIONAL_NO_CONSTRR - /// \group map_or_else - /// \synopsis template \nauto map_or_else(F &&f, U &&u) - /// const &&; - template - detail::invoke_result_t map_or_else(F &&f, U &&u) const && { - return has_value() ? detail::invoke(std::forward(f), std::move(**this)) - : std::forward(u)(); - } -#endif - - /// \returns `u` if `*this` has a value, otherwise an empty optional. - template - constexpr optional::type> conjunction(U &&u) const { - using result = optional>; - return has_value() ? result{u} : result{nullopt}; - } - - /// \returns `rhs` if `*this` is empty, otherwise the current value. - /// \group disjunction - TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & { - return has_value() ? *this : rhs; - } - - /// \group disjunction - constexpr optional disjunction(const optional &rhs) const & { - return has_value() ? *this : rhs; - } - - /// \group disjunction - TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && { - return has_value() ? std::move(*this) : rhs; - } - -#ifndef TL_OPTIONAL_NO_CONSTRR - /// \group disjunction - constexpr optional disjunction(const optional &rhs) const && { - return has_value() ? std::move(*this) : rhs; - } -#endif - - /// \group disjunction - TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & { - return has_value() ? *this : std::move(rhs); - } - - /// \group disjunction - constexpr optional disjunction(optional &&rhs) const & { - return has_value() ? *this : std::move(rhs); - } - - /// \group disjunction - TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && { - return has_value() ? std::move(*this) : std::move(rhs); - } - -#ifndef TL_OPTIONAL_NO_CONSTRR - /// \group disjunction - constexpr optional disjunction(optional &&rhs) const && { - return has_value() ? std::move(*this) : std::move(rhs); - } -#endif - - /// Takes the value out of the optional, leaving it empty - /// \group take - optional take() & { - optional ret = *this; - reset(); - return ret; - } - - /// \group take - optional take() const & { - optional ret = *this; - reset(); - return ret; - } - - /// \group take - optional take() && { - optional ret = std::move(*this); - reset(); - return ret; - } - -#ifndef TL_OPTIONAL_NO_CONSTRR - /// \group take - optional take() const && { - optional ret = std::move(*this); - reset(); - return ret; - } -#endif - - using value_type = T; - - /// Constructs an optional that does not contain a value. - /// \group ctor_empty - constexpr optional() noexcept = default; - - /// \group ctor_empty - constexpr optional(nullopt_t) noexcept {} - - /// Copy constructor - /// - /// If `rhs` contains a value, the stored value is direct-initialized with - /// it. Otherwise, the constructed optional is empty. - TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) = default; - - /// Move constructor - /// - /// If `rhs` contains a value, the stored value is direct-initialized with - /// it. Otherwise, the constructed optional is empty. - TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) = default; - - /// Constructs the stored value in-place using the given arguments. - /// \group in_place - /// \synopsis template constexpr explicit - /// optional(in_place_t, Args&&... args); - template - constexpr explicit optional( - detail::enable_if_t::value, - in_place_t>, - Args &&... args) - : base(in_place, std::forward(args)...) {} - - /// \group in_place - /// \synopsis template \nconstexpr explicit - /// optional(in_place_t, std::initializer_list&, Args&&... args); - template - TL_OPTIONAL_11_CONSTEXPR explicit optional( - detail::enable_if_t &, - Args &&...>::value, - in_place_t>, - std::initializer_list il, Args &&... args) { - this->construct(il, std::forward(args)...); - } - - /// Constructs the stored value with `u`. - /// \synopsis template constexpr optional(U &&u); - template < - class U = T, - detail::enable_if_t::value> * = nullptr, - detail::enable_forward_value * = nullptr> - constexpr optional(U &&u) : base(in_place, std::forward(u)) {} - - /// \exclude - template < - class U = T, - detail::enable_if_t::value> * = nullptr, - detail::enable_forward_value * = nullptr> - constexpr explicit optional(U &&u) : base(in_place, std::forward(u)) {} - - /// Converting copy constructor. - /// \synopsis template optional(const optional &rhs); - template * = nullptr, - detail::enable_if_t::value> * = - nullptr> - optional(const optional &rhs) { - this->construct(*rhs); - } - - /// \exclude - template * = nullptr, - detail::enable_if_t::value> * = - nullptr> - explicit optional(const optional &rhs) { - this->construct(*rhs); - } - - /// Converting move constructor. - /// \synopsis template optional(optional &&rhs); - template < - class U, detail::enable_from_other * = nullptr, - detail::enable_if_t::value> * = nullptr> - optional(optional &&rhs) { - this->construct(std::move(*rhs)); - } - - /// \exclude - template < - class U, detail::enable_from_other * = nullptr, - detail::enable_if_t::value> * = nullptr> - explicit optional(optional &&rhs) { - this->construct(std::move(*rhs)); - } - - /// Destroys the stored value if there is one. - ~optional() = default; - - /// Assignment to empty. - /// - /// Destroys the current value if there is one. - optional &operator=(nullopt_t) noexcept { - if (has_value()) { - this->m_value.~T(); - this->m_has_value = false; - } - - return *this; - } - - /// Copy assignment. - /// - /// Copies the value from `rhs` if there is one. Otherwise resets the stored - /// value in `*this`. - optional &operator=(const optional &rhs) = default; - - /// Move assignment. - /// - /// Moves the value from `rhs` if there is one. Otherwise resets the stored - /// value in `*this`. - optional &operator=(optional &&rhs) = default; - - /// Assigns the stored value from `u`, destroying the old value if there was - /// one. - /// \synopsis optional &operator=(U &&u); - template * = nullptr> - optional &operator=(U &&u) { - if (has_value()) { - this->m_value = std::forward(u); - } else { - this->construct(std::forward(u)); - } - - return *this; - } - - /// Converting copy assignment operator. - /// - /// Copies the value from `rhs` if there is one. Otherwise resets the stored - /// value in `*this`. - /// \synopsis optional &operator=(const optional & rhs); - template * = nullptr> - optional &operator=(const optional &rhs) { - if (has_value()) { - if (rhs.has_value()) { - this->m_value = *rhs; - } else { - this->hard_reset(); - } - } - - if (rhs.has_value()) { - this->construct(*rhs); - } - - return *this; - } - - // TODO check exception guarantee - /// Converting move assignment operator. - /// - /// Moves the value from `rhs` if there is one. Otherwise resets the stored - /// value in `*this`. - /// \synopsis optional &operator=(optional && rhs); - template * = nullptr> - optional &operator=(optional &&rhs) { - if (has_value()) { - if (rhs.has_value()) { - this->m_value = std::move(*rhs); - } else { - this->hard_reset(); - } - } - - if (rhs.has_value()) { - this->construct(std::move(*rhs)); - } - - return *this; - } - - /// Constructs the value in-place, destroying the current one if there is - /// one. \group emplace - template T &emplace(Args &&... args) { - static_assert(std::is_constructible::value, - "T must be constructible with Args"); - - *this = nullopt; - this->construct(std::forward(args)...); - } - - /// \group emplace - /// \synopsis template \nT& - /// emplace(std::initializer_list il, Args &&... args); - template - detail::enable_if_t< - std::is_constructible &, Args &&...>::value, - T &> - emplace(std::initializer_list il, Args &&... args) { - *this = nullopt; - this->construct(il, std::forward(args)...); - } - - /// Swaps this optional with the other. - /// - /// If neither optionals have a value, nothing happens. - /// If both have a value, the values are swapped. - /// If one has a value, it is moved to the other and the movee is left - /// valueless. - void - swap(optional &rhs) noexcept(std::is_nothrow_move_constructible::value - &&detail::is_nothrow_swappable::value) { - if (has_value()) { - if (rhs.has_value()) { - using std::swap; - swap(**this, *rhs); - } else { - new (std::addressof(rhs.m_value)) T(std::move(this->m_value)); - this->m_value.T::~T(); - } - } else if (rhs.has_value()) { - new (std::addressof(this->m_value)) T(std::move(rhs.m_value)); - rhs.m_value.T::~T(); - } - } - - /// \returns a pointer to the stored value - /// \requires a value is stored - /// \group pointer - /// \synopsis constexpr const T *operator->() const; - constexpr const T *operator->() const { - return std::addressof(this->m_value); - } - - /// \group pointer - /// \synopsis constexpr T *operator->(); - TL_OPTIONAL_11_CONSTEXPR T *operator->() { - return std::addressof(this->m_value); - } - - /// \returns the stored value - /// \requires a value is stored - /// \group deref - /// \synopsis constexpr T &operator*(); - TL_OPTIONAL_11_CONSTEXPR T &operator*() & { return this->m_value; } - - /// \group deref - /// \synopsis constexpr const T &operator*() const; - constexpr const T &operator*() const & { return this->m_value; } - - /// \exclude - TL_OPTIONAL_11_CONSTEXPR T &&operator*() && { - return std::move(this->m_value); - } - -#ifndef TL_OPTIONAL_NO_CONSTRR - /// \exclude - constexpr const T &&operator*() const && { - return std::move(this->m_value); - } -#endif - - /// \returns whether or not the optional has a value - /// \group has_value - constexpr bool has_value() const noexcept { return this->m_has_value; } - - /// \group has_value - constexpr explicit operator bool() const noexcept { - return this->m_has_value; - } - - /// \returns the contained value if there is one, otherwise throws - /// [bad_optional_access] - /// \group value - /// synopsis constexpr T &value(); - TL_OPTIONAL_11_CONSTEXPR T &value() & { - if (has_value()) - return this->m_value; - throw bad_optional_access(); - } - /// \group value - /// \synopsis constexpr const T &value() const; - TL_OPTIONAL_11_CONSTEXPR const T &value() const & { - if (has_value()) - return this->m_value; - throw bad_optional_access(); - } - /// \exclude - TL_OPTIONAL_11_CONSTEXPR T &&value() && { - if (has_value()) - return std::move(this->m_value); - throw bad_optional_access(); - } - -#ifndef TL_OPTIONAL_NO_CONSTRR - /// \exclude - constexpr const T &&value() const && { - if (has_value()) - return std::move(this->m_value); - throw bad_optional_access(); - } -#endif - - /// \returns the stored value if there is one, otherwise returns `u` - /// \group value_or - template constexpr T value_or(U &&u) const & { - static_assert(std::is_copy_constructible::value && - std::is_convertible::value, - "T must be copy constructible and convertible from U"); - return has_value() ? **this : static_cast(std::forward(u)); - } - - /// \group value_or - template constexpr T value_or(U &&u) && { - static_assert(std::is_move_constructible::value && - std::is_convertible::value, - "T must be move constructible and convertible from U"); - return has_value() ? **this : static_cast(std::forward(u)); - } - - /// Destroys the stored value if one exists, making the optional empty - void reset() noexcept { - if (has_value()) { - this->m_value.~T(); - this->m_has_value = false; - } - } - }; // namespace tl - - /// \group relop - /// \brief Compares two optional objects - /// \details If both optionals contain a value, they are compared with `T`s - /// relational operators. Otherwise `lhs` and `rhs` are equal only if they are - /// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs` - /// is not. - template - inline constexpr bool operator==(const optional &lhs, - const optional &rhs) { - return lhs.has_value() == rhs.has_value() && - (!lhs.has_value() || *lhs == *rhs); - } - /// \group relop - template - inline constexpr bool operator!=(const optional &lhs, - const optional &rhs) { - return lhs.has_value() != rhs.has_value() || - (lhs.has_value() && *lhs != *rhs); - } - /// \group relop - template - inline constexpr bool operator<(const optional &lhs, - const optional &rhs) { - return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); - } - /// \group relop - template - inline constexpr bool operator>(const optional &lhs, - const optional &rhs) { - return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); - } - /// \group relop - template - inline constexpr bool operator<=(const optional &lhs, - const optional &rhs) { - return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); - } - /// \group relop - template - inline constexpr bool operator>=(const optional &lhs, - const optional &rhs) { - return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); + /// \brief Carries out some operation on the stored object if there is one. + /// \returns Let `U` be the result of `std::invoke(std::forward(f), + /// value())`. Returns a `std::optional`. The return value is empty if + /// `*this` is empty, otherwise an `optional` is constructed from the + /// return value of `std::invoke(std::forward(f), value())` and is + /// returned. + /// + /// \group map + /// \synopsis template constexpr auto map(F &&f) &; + template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & { + return map_impl(*this, std::forward(f)); } - /// \group relop_nullopt - /// \brief Compares an optional to a `nullopt` - /// \details Equivalent to comparing the optional to an empty optional - template - inline constexpr bool operator==(const optional &lhs, nullopt_t) noexcept { - return !lhs.has_value(); - } - /// \group relop_nullopt - template - inline constexpr bool operator==(nullopt_t, const optional &rhs) noexcept { - return !rhs.has_value(); - } - /// \group relop_nullopt - template - inline constexpr bool operator!=(const optional &lhs, nullopt_t) noexcept { - return lhs.has_value(); - } - /// \group relop_nullopt - template - inline constexpr bool operator!=(nullopt_t, const optional &rhs) noexcept { - return rhs.has_value(); - } - /// \group relop_nullopt - template - inline constexpr bool operator<(const optional &, nullopt_t) noexcept { - return false; - } - /// \group relop_nullopt - template - inline constexpr bool operator<(nullopt_t, const optional &rhs) noexcept { - return rhs.has_value(); - } - /// \group relop_nullopt - template - inline constexpr bool operator<=(const optional &lhs, nullopt_t) noexcept { - return !lhs.has_value(); - } - /// \group relop_nullopt - template - inline constexpr bool operator<=(nullopt_t, const optional &) noexcept { - return true; - } - /// \group relop_nullopt - template - inline constexpr bool operator>(const optional &lhs, nullopt_t) noexcept { - return lhs.has_value(); - } - /// \group relop_nullopt - template - inline constexpr bool operator>(nullopt_t, const optional &) noexcept { - return false; - } - /// \group relop_nullopt - template - inline constexpr bool operator>=(const optional &, nullopt_t) noexcept { - return true; - } - /// \group relop_nullopt - template - inline constexpr bool operator>=(nullopt_t, const optional &rhs) noexcept { - return !rhs.has_value(); + /// \group map + /// \synopsis template constexpr auto map(F &&f) &&; + template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && { + return map_impl(std::move(*this), std::forward(f)); } - /// \group relop_t - /// \brief Compares the optional with a value. - /// \details If the optional has a value, it is compared with the other value - /// using `T`s relational operators. Otherwise, the optional is considered - /// less than the value. - template - inline constexpr bool operator==(const optional &lhs, const U &rhs) { - return lhs.has_value() ? *lhs == rhs : false; - } - /// \group relop_t - template - inline constexpr bool operator==(const U &lhs, const optional &rhs) { - return rhs.has_value() ? lhs == *rhs : false; - } - /// \group relop_t - template - inline constexpr bool operator!=(const optional &lhs, const U &rhs) { - return lhs.has_value() ? *lhs != rhs : true; - } - /// \group relop_t - template - inline constexpr bool operator!=(const U &lhs, const optional &rhs) { - return rhs.has_value() ? lhs != *rhs : true; - } - /// \group relop_t - template - inline constexpr bool operator<(const optional &lhs, const U &rhs) { - return lhs.has_value() ? *lhs < rhs : true; - } - /// \group relop_t - template - inline constexpr bool operator<(const U &lhs, const optional &rhs) { - return rhs.has_value() ? lhs < *rhs : false; - } - /// \group relop_t - template - inline constexpr bool operator<=(const optional &lhs, const U &rhs) { - return lhs.has_value() ? *lhs <= rhs : true; - } - /// \group relop_t - template - inline constexpr bool operator<=(const U &lhs, const optional &rhs) { - return rhs.has_value() ? lhs <= *rhs : false; - } - /// \group relop_t - template - inline constexpr bool operator>(const optional &lhs, const U &rhs) { - return lhs.has_value() ? *lhs > rhs : false; - } - /// \group relop_t - template - inline constexpr bool operator>(const U &lhs, const optional &rhs) { - return rhs.has_value() ? lhs > *rhs : true; - } - /// \group relop_t - template - inline constexpr bool operator>=(const optional &lhs, const U &rhs) { - return lhs.has_value() ? *lhs >= rhs : false; - } - /// \group relop_t - template - inline constexpr bool operator>=(const U &lhs, const optional &rhs) { - return rhs.has_value() ? lhs >= *rhs : true; + /// \group map + /// \synopsis template constexpr auto map(F &&f) const&; + template constexpr auto map(F &&f) const & { + return map_impl(*this, std::forward(f)); } - /// \synopsis template \nvoid swap(optional &lhs, optional - /// &rhs); - template ::value> * = - nullptr, - detail::enable_if_t::value> * = nullptr> - void swap(optional & lhs, - optional & rhs) noexcept(noexcept(lhs.swap(rhs))) { - return lhs.swap(rhs); - } - - template - inline constexpr optional> make_optional(T && v) { - return optional>(std::forward(v)); - } - template - inline constexpr optional make_optional(Args && ... args) { - return optional(in_place, std::forward(args)...); - } - template - inline constexpr optional make_optional(std::initializer_list il, - Args && ... args) { - return optional(in_place, il, std::forward(args)...); - } - -#if __cplusplus >= 201703L - template optional(T)->optional; -#endif - - /// \exclude - namespace detail { -#ifdef TL_OPTIONAL_CX14 - template (), - *std::declval())), - detail::enable_if_t::value> * = nullptr> - constexpr auto map_impl(Opt &&opt, F &&f) { - return opt.has_value() - ? detail::invoke(std::forward(f), *std::forward(opt)) - : optional>(nullopt); - } - - template (), - *std::declval())), - detail::enable_if_t::value> * = nullptr> - auto map_impl(Opt &&opt, F &&f) { - if (opt.has_value()) { - detail::invoke(std::forward(f), *std::forward(opt)); - return monostate{}; - } - - return optional(nullopt); + /// \group map + /// \synopsis template constexpr auto map(F &&f) const&&; + template constexpr auto map(F &&f) const && { + return map_impl(std::move(*this), std::forward(f)); } #else - template (), - *std::declval())), - detail::enable_if_t::value> * = nullptr> - - constexpr auto map_impl(Opt &&opt, F &&f) -> optional> { - return opt.has_value() - ? detail::invoke(std::forward(f), *std::forward(opt)) - : optional>(nullopt); + /// \brief Carries out some operation on the stored object if there is one. + /// \returns Let `U` be the result of `std::invoke(std::forward(f), + /// value())`. Returns a `std::optional`. The return value is empty if + /// `*this` is empty, otherwise an `optional` is constructed from the + /// return value of `std::invoke(std::forward(f), value())` and is + /// returned. + /// + /// \group map + /// \synopsis template auto map(F &&f) &; + template + TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval(), + std::declval())) + map(F &&f) & { + return map_impl(*this, std::forward(f)); } - template (), - *std::declval())), - detail::enable_if_t::value> * = nullptr> + /// \group map + /// \synopsis template auto map(F &&f) &&; + template + TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval(), + std::declval())) + map(F &&f) && { + return map_impl(std::move(*this), std::forward(f)); + } - auto map_impl(Opt &&opt, F &&f) -> optional { - if (opt.has_value()) { - detail::invoke(std::forward(f), *std::forward(opt)); - return monostate{}; - } + /// \group map + /// \synopsis template auto map(F &&f) const&; + template + constexpr decltype(map_impl(std::declval(), + std::declval())) + map(F &&f) const & { + return map_impl(*this, std::forward(f)); + } +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group map + /// \synopsis template auto map(F &&f) const&&; + template + constexpr decltype(map_impl(std::declval(), + std::declval())) + map(F &&f) const && { + return map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + + /// \brief Calls `f` if the optional is empty + /// \requires `std::invoke_result_t` must be void or convertible to + /// `optional`. \effects If `*this` has a value, returns `*this`. + /// Otherwise, if `f` returns `void`, calls `std::forward(f)` and returns + /// `std::nullopt`. Otherwise, returns `std::forward(f)()`. + /// + /// \group or_else + /// \synopsis template optional or_else (F &&f) &; + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { + if (has_value()) + return *this; + + std::forward(f)(); return nullopt; } + + /// \exclude + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { + return has_value() ? *this : std::forward(f)(); + } + + /// \group or_else + /// \synopsis template optional or_else (F &&f) &&; + template * = nullptr> + optional or_else(F &&f) && { + if (has_value()) + return std::move(*this); + + std::forward(f)(); + return nullopt; + } + + /// \exclude + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && { + return has_value() ? std::move(*this) : std::forward(f)(); + } + + /// \group or_else + /// \synopsis template optional or_else (F &&f) const &; + template * = nullptr> + optional or_else(F &&f) const & { + if (has_value()) + return *this; + + std::forward(f)(); + return nullopt; + } + + /// \exclude + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & { + return has_value() ? *this : std::forward(f)(); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \exclude + template * = nullptr> + optional or_else(F &&f) const && { + if (has_value()) + return std::move(*this); + + std::forward(f)(); + return nullopt; + } + + /// \exclude + template * = nullptr> + optional or_else(F &&f) const && { + return has_value() ? std::move(*this) : std::forward(f)(); + } #endif - } // namespace detail + + /// \brief Maps the stored value with `f` if there is one, otherwise returns + /// `u`. + /// + /// \details If there is a value stored, then `f` is called with `**this` + /// and the value is returned. Otherwise `u` is returned. + /// + /// \group map_or + template U map_or(F &&f, U &&u) & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u); + } + + /// \group map_or + template U map_or(F &&f, U &&u) && { + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u); + } + + /// \group map_or + template U map_or(F &&f, U &&u) const & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group map_or + template U map_or(F &&f, U &&u) const && { + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u); + } +#endif + + /// \brief Maps the stored value with `f` if there is one, otherwise calls + /// `u` and returns the result. + /// + /// \details If there is a value stored, then `f` is + /// called with `**this` and the value is returned. Otherwise + /// `std::forward(u)()` is returned. + /// + /// \group map_or_else + /// \synopsis template \nauto map_or_else(F &&f, U &&u) &; + template + detail::invoke_result_t map_or_else(F &&f, U &&u) & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u)(); + } + + /// \group map_or_else + /// \synopsis template \nauto map_or_else(F &&f, U &&u) + /// &&; + template + detail::invoke_result_t map_or_else(F &&f, U &&u) && { + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u)(); + } + + /// \group map_or_else + /// \synopsis template \nauto map_or_else(F &&f, U &&u) + /// const &; + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u)(); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group map_or_else + /// \synopsis template \nauto map_or_else(F &&f, U &&u) + /// const &&; + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const && { + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u)(); + } +#endif + + /// \returns `u` if `*this` has a value, otherwise an empty optional. + template + constexpr optional::type> conjunction(U &&u) const { + using result = optional>; + return has_value() ? result{u} : result{nullopt}; + } + + /// \returns `rhs` if `*this` is empty, otherwise the current value. + /// \group disjunction + TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & { + return has_value() ? *this : rhs; + } + + /// \group disjunction + constexpr optional disjunction(const optional &rhs) const & { + return has_value() ? *this : rhs; + } + + /// \group disjunction + TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && { + return has_value() ? std::move(*this) : rhs; + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group disjunction + constexpr optional disjunction(const optional &rhs) const && { + return has_value() ? std::move(*this) : rhs; + } +#endif + + /// \group disjunction + TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & { + return has_value() ? *this : std::move(rhs); + } + + /// \group disjunction + constexpr optional disjunction(optional &&rhs) const & { + return has_value() ? *this : std::move(rhs); + } + + /// \group disjunction + TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && { + return has_value() ? std::move(*this) : std::move(rhs); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group disjunction + constexpr optional disjunction(optional &&rhs) const && { + return has_value() ? std::move(*this) : std::move(rhs); + } +#endif + + /// Takes the value out of the optional, leaving it empty + /// \group take + optional take() & { + optional ret = *this; + reset(); + return ret; + } + + /// \group take + optional take() const & { + optional ret = *this; + reset(); + return ret; + } + + /// \group take + optional take() && { + optional ret = std::move(*this); + reset(); + return ret; + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group take + optional take() const && { + optional ret = std::move(*this); + reset(); + return ret; + } +#endif + + using value_type = T; + + /// Constructs an optional that does not contain a value. + /// \group ctor_empty + constexpr optional() noexcept = default; + + /// \group ctor_empty + constexpr optional(nullopt_t) noexcept {} + + /// Copy constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) = default; + + /// Move constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) = default; + + /// Constructs the stored value in-place using the given arguments. + /// \group in_place + /// \synopsis template constexpr explicit + /// optional(in_place_t, Args&&... args); + template + constexpr explicit optional( + detail::enable_if_t::value, in_place_t>, + Args &&... args) + : base(in_place, std::forward(args)...) {} + + /// \group in_place + /// \synopsis template \nconstexpr explicit + /// optional(in_place_t, std::initializer_list&, Args&&... args); + template + TL_OPTIONAL_11_CONSTEXPR explicit optional( + detail::enable_if_t &, + Args &&...>::value, + in_place_t>, + std::initializer_list il, Args &&... args) { + this->construct(il, std::forward(args)...); + } + + /// Constructs the stored value with `u`. + /// \synopsis template constexpr optional(U &&u); + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::enable_forward_value * = nullptr> + constexpr optional(U &&u) : base(in_place, std::forward(u)) {} + + /// \exclude + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::enable_forward_value * = nullptr> + constexpr explicit optional(U &&u) : base(in_place, std::forward(u)) {} + + /// Converting copy constructor. + /// \synopsis template optional(const optional &rhs); + template < + class U, detail::enable_from_other * = nullptr, + detail::enable_if_t::value> * = nullptr> + optional(const optional &rhs) { + this->construct(*rhs); + } + + /// \exclude + template * = nullptr, + detail::enable_if_t::value> * = + nullptr> + explicit optional(const optional &rhs) { + this->construct(*rhs); + } + + /// Converting move constructor. + /// \synopsis template optional(optional &&rhs); + template < + class U, detail::enable_from_other * = nullptr, + detail::enable_if_t::value> * = nullptr> + optional(optional &&rhs) { + this->construct(std::move(*rhs)); + } + + /// \exclude + template < + class U, detail::enable_from_other * = nullptr, + detail::enable_if_t::value> * = nullptr> + explicit optional(optional &&rhs) { + this->construct(std::move(*rhs)); + } + + /// Destroys the stored value if there is one. + ~optional() = default; + + /// Assignment to empty. + /// + /// Destroys the current value if there is one. + optional &operator=(nullopt_t) noexcept { + if (has_value()) { + this->m_value.~T(); + this->m_has_value = false; + } + + return *this; + } + + /// Copy assignment. + /// + /// Copies the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + optional &operator=(const optional &rhs) = default; + + /// Move assignment. + /// + /// Moves the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + optional &operator=(optional &&rhs) = default; + + /// Assigns the stored value from `u`, destroying the old value if there was + /// one. + /// \synopsis optional &operator=(U &&u); + template * = nullptr> + optional &operator=(U &&u) { + if (has_value()) { + this->m_value = std::forward(u); + } else { + this->construct(std::forward(u)); + } + + return *this; + } + + /// Converting copy assignment operator. + /// + /// Copies the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + /// \synopsis optional &operator=(const optional & rhs); + template * = nullptr> + optional &operator=(const optional &rhs) { + if (has_value()) { + if (rhs.has_value()) { + this->m_value = *rhs; + } else { + this->hard_reset(); + } + } + + if (rhs.has_value()) { + this->construct(*rhs); + } + + return *this; + } + + // TODO check exception guarantee + /// Converting move assignment operator. + /// + /// Moves the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + /// \synopsis optional &operator=(optional && rhs); + template * = nullptr> + optional &operator=(optional &&rhs) { + if (has_value()) { + if (rhs.has_value()) { + this->m_value = std::move(*rhs); + } else { + this->hard_reset(); + } + } + + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } + + return *this; + } + + /// Constructs the value in-place, destroying the current one if there is + /// one. \group emplace + template T &emplace(Args &&... args) { + static_assert(std::is_constructible::value, + "T must be constructible with Args"); + + *this = nullopt; + this->construct(std::forward(args)...); + } + + /// \group emplace + /// \synopsis template \nT& + /// emplace(std::initializer_list il, Args &&... args); + template + detail::enable_if_t< + std::is_constructible &, Args &&...>::value, + T &> + emplace(std::initializer_list il, Args &&... args) { + *this = nullopt; + this->construct(il, std::forward(args)...); + } + + /// Swaps this optional with the other. + /// + /// If neither optionals have a value, nothing happens. + /// If both have a value, the values are swapped. + /// If one has a value, it is moved to the other and the movee is left + /// valueless. + void + swap(optional &rhs) noexcept(std::is_nothrow_move_constructible::value + &&detail::is_nothrow_swappable::value) { + if (has_value()) { + if (rhs.has_value()) { + using std::swap; + swap(**this, *rhs); + } else { + new (std::addressof(rhs.m_value)) T(std::move(this->m_value)); + this->m_value.T::~T(); + } + } else if (rhs.has_value()) { + new (std::addressof(this->m_value)) T(std::move(rhs.m_value)); + rhs.m_value.T::~T(); + } + } + + /// \returns a pointer to the stored value + /// \requires a value is stored + /// \group pointer + /// \synopsis constexpr const T *operator->() const; + constexpr const T *operator->() const { + return std::addressof(this->m_value); + } + + /// \group pointer + /// \synopsis constexpr T *operator->(); + TL_OPTIONAL_11_CONSTEXPR T *operator->() { + return std::addressof(this->m_value); + } + + /// \returns the stored value + /// \requires a value is stored + /// \group deref + /// \synopsis constexpr T &operator*(); + TL_OPTIONAL_11_CONSTEXPR T &operator*() & { return this->m_value; } + + /// \group deref + /// \synopsis constexpr const T &operator*() const; + constexpr const T &operator*() const & { return this->m_value; } + + /// \exclude + TL_OPTIONAL_11_CONSTEXPR T &&operator*() && { + return std::move(this->m_value); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \exclude + constexpr const T &&operator*() const && { return std::move(this->m_value); } +#endif + + /// \returns whether or not the optional has a value + /// \group has_value + constexpr bool has_value() const noexcept { return this->m_has_value; } + + /// \group has_value + constexpr explicit operator bool() const noexcept { + return this->m_has_value; + } + + /// \returns the contained value if there is one, otherwise throws + /// [bad_optional_access] + /// \group value + /// synopsis constexpr T &value(); + TL_OPTIONAL_11_CONSTEXPR T &value() & { + if (has_value()) + return this->m_value; + throw bad_optional_access(); + } + /// \group value + /// \synopsis constexpr const T &value() const; + TL_OPTIONAL_11_CONSTEXPR const T &value() const & { + if (has_value()) + return this->m_value; + throw bad_optional_access(); + } + /// \exclude + TL_OPTIONAL_11_CONSTEXPR T &&value() && { + if (has_value()) + return std::move(this->m_value); + throw bad_optional_access(); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \exclude + constexpr const T &&value() const && { + if (has_value()) + return std::move(this->m_value); + throw bad_optional_access(); + } +#endif + + /// \returns the stored value if there is one, otherwise returns `u` + /// \group value_or + template constexpr T value_or(U &&u) const & { + static_assert(std::is_copy_constructible::value && + std::is_convertible::value, + "T must be copy constructible and convertible from U"); + return has_value() ? **this : static_cast(std::forward(u)); + } + + /// \group value_or + template constexpr T value_or(U &&u) && { + static_assert(std::is_move_constructible::value && + std::is_convertible::value, + "T must be move constructible and convertible from U"); + return has_value() ? **this : static_cast(std::forward(u)); + } + + /// Destroys the stored value if one exists, making the optional empty + void reset() noexcept { + if (has_value()) { + this->m_value.~T(); + this->m_has_value = false; + } + } +}; // namespace tl + +/// \group relop +/// \brief Compares two optional objects +/// \details If both optionals contain a value, they are compared with `T`s +/// relational operators. Otherwise `lhs` and `rhs` are equal only if they are +/// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs` +/// is not. +template +inline constexpr bool operator==(const optional &lhs, + const optional &rhs) { + return lhs.has_value() == rhs.has_value() && + (!lhs.has_value() || *lhs == *rhs); +} +/// \group relop +template +inline constexpr bool operator!=(const optional &lhs, + const optional &rhs) { + return lhs.has_value() != rhs.has_value() || + (lhs.has_value() && *lhs != *rhs); +} +/// \group relop +template +inline constexpr bool operator<(const optional &lhs, + const optional &rhs) { + return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); +} +/// \group relop +template +inline constexpr bool operator>(const optional &lhs, + const optional &rhs) { + return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); +} +/// \group relop +template +inline constexpr bool operator<=(const optional &lhs, + const optional &rhs) { + return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); +} +/// \group relop +template +inline constexpr bool operator>=(const optional &lhs, + const optional &rhs) { + return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); +} + +/// \group relop_nullopt +/// \brief Compares an optional to a `nullopt` +/// \details Equivalent to comparing the optional to an empty optional +template +inline constexpr bool operator==(const optional &lhs, nullopt_t) noexcept { + return !lhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator==(nullopt_t, const optional &rhs) noexcept { + return !rhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator!=(const optional &lhs, nullopt_t) noexcept { + return lhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator!=(nullopt_t, const optional &rhs) noexcept { + return rhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator<(const optional &, nullopt_t) noexcept { + return false; +} +/// \group relop_nullopt +template +inline constexpr bool operator<(nullopt_t, const optional &rhs) noexcept { + return rhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator<=(const optional &lhs, nullopt_t) noexcept { + return !lhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator<=(nullopt_t, const optional &) noexcept { + return true; +} +/// \group relop_nullopt +template +inline constexpr bool operator>(const optional &lhs, nullopt_t) noexcept { + return lhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator>(nullopt_t, const optional &) noexcept { + return false; +} +/// \group relop_nullopt +template +inline constexpr bool operator>=(const optional &, nullopt_t) noexcept { + return true; +} +/// \group relop_nullopt +template +inline constexpr bool operator>=(nullopt_t, const optional &rhs) noexcept { + return !rhs.has_value(); +} + +/// \group relop_t +/// \brief Compares the optional with a value. +/// \details If the optional has a value, it is compared with the other value +/// using `T`s relational operators. Otherwise, the optional is considered +/// less than the value. +template +inline constexpr bool operator==(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs == rhs : false; +} +/// \group relop_t +template +inline constexpr bool operator==(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs == *rhs : false; +} +/// \group relop_t +template +inline constexpr bool operator!=(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs != rhs : true; +} +/// \group relop_t +template +inline constexpr bool operator!=(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs != *rhs : true; +} +/// \group relop_t +template +inline constexpr bool operator<(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs < rhs : true; +} +/// \group relop_t +template +inline constexpr bool operator<(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs < *rhs : false; +} +/// \group relop_t +template +inline constexpr bool operator<=(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs <= rhs : true; +} +/// \group relop_t +template +inline constexpr bool operator<=(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs <= *rhs : false; +} +/// \group relop_t +template +inline constexpr bool operator>(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs > rhs : false; +} +/// \group relop_t +template +inline constexpr bool operator>(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs > *rhs : true; +} +/// \group relop_t +template +inline constexpr bool operator>=(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs >= rhs : false; +} +/// \group relop_t +template +inline constexpr bool operator>=(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs >= *rhs : true; +} + +/// \synopsis template \nvoid swap(optional &lhs, optional +/// &rhs); +template ::value> * = nullptr, + detail::enable_if_t::value> * = nullptr> +void swap(optional &lhs, + optional &rhs) noexcept(noexcept(lhs.swap(rhs))) { + return lhs.swap(rhs); +} + +template +inline constexpr optional> make_optional(T &&v) { + return optional>(std::forward(v)); +} +template +inline constexpr optional make_optional(Args &&... args) { + return optional(in_place, std::forward(args)...); +} +template +inline constexpr optional make_optional(std::initializer_list il, + Args &&... args) { + return optional(in_place, il, std::forward(args)...); +} + +#if __cplusplus >= 201703L +template optional(T)->optional; +#endif + +/// An optional object is an object that contains the storage for another +/// object and manages the lifetime of this contained object, if any. The +/// contained object may be initialized after the optional object has been +/// initialized, and may be destroyed before the optional object has been +/// destroyed. The initialization state of the contained object is tracked by +/// the optional object. +template class optional { +public: +// The different versions for C++14 and 11 are needed because deduced return +// types are not SFINAE-safe. This provides better support for things like +// generic lambdas. C.f. +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html +#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) + /// \group and_then + /// Carries out some operation which returns an optional on the stored + /// object if there is one. \requires `std::invoke(std::forward(f), + /// value())` returns a `std::optional` for some `U`. \returns Let `U` be + /// the result of `std::invoke(std::forward(f), value())`. Returns a + /// `std::optional`. The return value is empty if `*this` is empty, + /// otherwise the return value of `std::invoke(std::forward(f), value())` + /// is returned. + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) &; + template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) &&; + template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } + + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) const &; + template constexpr auto and_then(F &&f) const & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) const &&; + template constexpr auto and_then(F &&f) const && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } +#endif +#else + /// \group and_then + /// Carries out some operation which returns an optional on the stored + /// object if there is one. \requires `std::invoke(std::forward(f), + /// value())` returns a `std::optional` for some `U`. \returns Let `U` be + /// the result of `std::invoke(std::forward(f), value())`. Returns a + /// `std::optional`. The return value is empty if `*this` is empty, + /// otherwise the return value of `std::invoke(std::forward(f), value())` + /// is returned. + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) &; + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) &&; + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } + + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) const &; + template + constexpr detail::invoke_result_t and_then(F &&f) const & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) const &&; + template + constexpr detail::invoke_result_t and_then(F &&f) const && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } +#endif +#endif + +#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) + /// \brief Carries out some operation on the stored object if there is one. + /// \returns Let `U` be the result of `std::invoke(std::forward(f), + /// value())`. Returns a `std::optional`. The return value is empty if + /// `*this` is empty, otherwise an `optional` is constructed from the + /// return value of `std::invoke(std::forward(f), value())` and is + /// returned. + /// + /// \group map + /// \synopsis template constexpr auto map(F &&f) &; + template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & { + return map_impl(*this, std::forward(f)); + } + + /// \group map + /// \synopsis template constexpr auto map(F &&f) &&; + template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && { + return map_impl(std::move(*this), std::forward(f)); + } + + /// \group map + /// \synopsis template constexpr auto map(F &&f) const&; + template constexpr auto map(F &&f) const & { + return map_impl(*this, std::forward(f)); + } + + /// \group map + /// \synopsis template constexpr auto map(F &&f) const&&; + template constexpr auto map(F &&f) const && { + return map_impl(std::move(*this), std::forward(f)); + } +#else + /// \brief Carries out some operation on the stored object if there is one. + /// \returns Let `U` be the result of `std::invoke(std::forward(f), + /// value())`. Returns a `std::optional`. The return value is empty if + /// `*this` is empty, otherwise an `optional` is constructed from the + /// return value of `std::invoke(std::forward(f), value())` and is + /// returned. + /// + /// \group map + /// \synopsis template auto map(F &&f) &; + template + TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval(), + std::declval())) + map(F &&f) & { + return map_impl(*this, std::forward(f)); + } + + /// \group map + /// \synopsis template auto map(F &&f) &&; + template + TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval(), + std::declval())) + map(F &&f) && { + return map_impl(std::move(*this), std::forward(f)); + } + + /// \group map + /// \synopsis template auto map(F &&f) const&; + template + constexpr decltype(map_impl(std::declval(), + std::declval())) + map(F &&f) const & { + return map_impl(*this, std::forward(f)); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group map + /// \synopsis template auto map(F &&f) const&&; + template + constexpr decltype(map_impl(std::declval(), + std::declval())) + map(F &&f) const && { + return map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + + /// \brief Calls `f` if the optional is empty + /// \requires `std::invoke_result_t` must be void or convertible to + /// `optional`. \effects If `*this` has a value, returns `*this`. + /// Otherwise, if `f` returns `void`, calls `std::forward(f)` and returns + /// `std::nullopt`. Otherwise, returns `std::forward(f)()`. + /// + /// \group or_else + /// \synopsis template optional or_else (F &&f) &; + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { + if (has_value()) + return *this; + + std::forward(f)(); + return nullopt; + } + + /// \exclude + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { + return has_value() ? *this : std::forward(f)(); + } + + /// \group or_else + /// \synopsis template optional or_else (F &&f) &&; + template * = nullptr> + optional or_else(F &&f) && { + if (has_value()) + return std::move(*this); + + std::forward(f)(); + return nullopt; + } + + /// \exclude + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && { + return has_value() ? std::move(*this) : std::forward(f)(); + } + + /// \group or_else + /// \synopsis template optional or_else (F &&f) const &; + template * = nullptr> + optional or_else(F &&f) const & { + if (has_value()) + return *this; + + std::forward(f)(); + return nullopt; + } + + /// \exclude + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & { + return has_value() ? *this : std::forward(f)(); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \exclude + template * = nullptr> + optional or_else(F &&f) const && { + if (has_value()) + return std::move(*this); + + std::forward(f)(); + return nullopt; + } + + /// \exclude + template * = nullptr> + optional or_else(F &&f) const && { + return has_value() ? std::move(*this) : std::forward(f)(); + } +#endif + + /// \brief Maps the stored value with `f` if there is one, otherwise returns + /// `u`. + /// + /// \details If there is a value stored, then `f` is called with `**this` + /// and the value is returned. Otherwise `u` is returned. + /// + /// \group map_or + template U map_or(F &&f, U &&u) & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u); + } + + /// \group map_or + template U map_or(F &&f, U &&u) && { + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u); + } + + /// \group map_or + template U map_or(F &&f, U &&u) const & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group map_or + template U map_or(F &&f, U &&u) const && { + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u); + } +#endif + + /// \brief Maps the stored value with `f` if there is one, otherwise calls + /// `u` and returns the result. + /// + /// \details If there is a value stored, then `f` is + /// called with `**this` and the value is returned. Otherwise + /// `std::forward(u)()` is returned. + /// + /// \group map_or_else + /// \synopsis template \nauto map_or_else(F &&f, U &&u) &; + template + detail::invoke_result_t map_or_else(F &&f, U &&u) & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u)(); + } + + /// \group map_or_else + /// \synopsis template \nauto map_or_else(F &&f, U &&u) + /// &&; + template + detail::invoke_result_t map_or_else(F &&f, U &&u) && { + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u)(); + } + + /// \group map_or_else + /// \synopsis template \nauto map_or_else(F &&f, U &&u) + /// const &; + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const & { + return has_value() ? detail::invoke(std::forward(f), **this) + : std::forward(u)(); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group map_or_else + /// \synopsis template \nauto map_or_else(F &&f, U &&u) + /// const &&; + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const && { + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : std::forward(u)(); + } +#endif + + /// \returns `u` if `*this` has a value, otherwise an empty optional. + template + constexpr optional::type> conjunction(U &&u) const { + using result = optional>; + return has_value() ? result{u} : result{nullopt}; + } + + /// \returns `rhs` if `*this` is empty, otherwise the current value. + /// \group disjunction + TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & { + return has_value() ? *this : rhs; + } + + /// \group disjunction + constexpr optional disjunction(const optional &rhs) const & { + return has_value() ? *this : rhs; + } + + /// \group disjunction + TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && { + return has_value() ? std::move(*this) : rhs; + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group disjunction + constexpr optional disjunction(const optional &rhs) const && { + return has_value() ? std::move(*this) : rhs; + } +#endif + + /// \group disjunction + TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & { + return has_value() ? *this : std::move(rhs); + } + + /// \group disjunction + constexpr optional disjunction(optional &&rhs) const & { + return has_value() ? *this : std::move(rhs); + } + + /// \group disjunction + TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && { + return has_value() ? std::move(*this) : std::move(rhs); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group disjunction + constexpr optional disjunction(optional &&rhs) const && { + return has_value() ? std::move(*this) : std::move(rhs); + } +#endif + + /// Takes the value out of the optional, leaving it empty + /// \group take + optional take() & { + optional ret = *this; + reset(); + return ret; + } + + /// \group take + optional take() const & { + optional ret = *this; + reset(); + return ret; + } + + /// \group take + optional take() && { + optional ret = std::move(*this); + reset(); + return ret; + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group take + optional take() const && { + optional ret = std::move(*this); + reset(); + return ret; + } +#endif + + using value_type = T &; + + /// Constructs an optional that does not contain a value. + /// \group ctor_empty + constexpr optional() noexcept : m_value(nullptr) {} + + /// \group ctor_empty + constexpr optional(nullopt_t) noexcept : m_value(nullptr) {} + + /// Copy constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) noexcept = default; + + /// Move constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) = default; + + /// Constructs the stored value with `u`. + /// \synopsis template constexpr optional(U &&u); + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t>> * = nullptr> + constexpr optional(U &&u) : m_value(std::addressof(u)) {} + + /// \exclude + template ::value> * = nullptr> + constexpr optional(U &&u) : base(in_place, std::forward(u)) {} + + /// \exclude + template ::value> * = nullptr> + constexpr explicit optional(const optional &rhs) : optional(*rhs) {} + + /// No-op + ~optional() = default; + + /// Assignment to empty. + /// + /// Destroys the current value if there is one. + optional &operator=(nullopt_t) noexcept { + m_value = nullptr; + return *this; + } + + /// Copy assignment. + /// + /// Copies the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + optional &operator=(const optional &rhs) = default; + + /// Assigns the stored value from `u`, destroying the old value if there was + /// one. + /// \synopsis optional &operator=(U &&u); + template >::value> + * = nullptr> + optional &operator=(U &&u) { + m_value = std::addressof(u); + return *this; + } + + /// Converting copy assignment operator. + /// + /// Copies the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + /// \synopsis optional &operator=(const optional & rhs); + template ::value> * = nullptr> + optional &operator=(const optional &rhs) { + m_value = std::addressof(rhs.value()); + return *this; + } + + /// Constructs the value in-place, destroying the current one if there is + /// one. \group emplace + template T &emplace(Args &&... args) noexcept { + static_assert(std::is_constructible::value, + "T must be constructible with Args"); + + *this = nullopt; + this->construct(std::forward(args)...); + } + + /// Swaps this optional with the other. + /// + /// If neither optionals have a value, nothing happens. + /// If both have a value, the values are swapped. + /// If one has a value, it is moved to the other and the movee is left + /// valueless. + void + swap(optional &rhs) noexcept { + std::swap(m_value, rhs.m_value); + } + + /// \returns a pointer to the stored value + /// \requires a value is stored + /// \group pointer + /// \synopsis constexpr const T *operator->() const; + constexpr const T *operator->() const { + return m_value; + } + + /// \group pointer + /// \synopsis constexpr T *operator->(); + TL_OPTIONAL_11_CONSTEXPR T *operator->() { + return m_value; + } + + /// \returns the stored value + /// \requires a value is stored + /// \group deref + /// \synopsis constexpr T &operator*(); + TL_OPTIONAL_11_CONSTEXPR T &operator*() & { return *m_value; } + + /// \group deref + /// \synopsis constexpr const T &operator*() const; + constexpr const T &operator*() const & { return *m_value; } + + /// \exclude + TL_OPTIONAL_11_CONSTEXPR T &&operator*() && { + return std::move(*m_value); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \exclude + constexpr const T &&operator*() const && { return std::move(*m_value); } +#endif + + /// \returns whether or not the optional has a value + /// \group has_value + constexpr bool has_value() const noexcept { return m_value != nullptr; } + + /// \group has_value + constexpr explicit operator bool() const noexcept { + return m_value != nullptr; + } + + /// \returns the contained value if there is one, otherwise throws + /// [bad_optional_access] + /// \group value + /// synopsis constexpr T &value(); + TL_OPTIONAL_11_CONSTEXPR T &value() & { + if (has_value()) + return *m_value; + throw bad_optional_access(); + } + /// \group value + /// \synopsis constexpr const T &value() const; + TL_OPTIONAL_11_CONSTEXPR const T &value() const & { + if (has_value()) + return *m_value; + throw bad_optional_access(); + } + /// \exclude + TL_OPTIONAL_11_CONSTEXPR T &&value() && { + if (has_value()) + return std::move(*m_value); + throw bad_optional_access(); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \exclude + constexpr const T &&value() const && { + if (has_value()) + return std::move(*m_value); + throw bad_optional_access(); + } +#endif + + /// \returns the stored value if there is one, otherwise returns `u` + /// \group value_or + template constexpr T value_or(U &&u) const & { + static_assert(std::is_copy_constructible::value && + std::is_convertible::value, + "T must be copy constructible and convertible from U"); + return has_value() ? **this : static_cast(std::forward(u)); + } + + /// \group value_or + template constexpr T value_or(U &&u) && { + static_assert(std::is_move_constructible::value && + std::is_convertible::value, + "T must be move constructible and convertible from U"); + return has_value() ? **this : static_cast(std::forward(u)); + } + + /// Destroys the stored value if one exists, making the optional empty + void reset() noexcept { + m_value = nullptr; + } +}; // namespace tl + +/// \group relop +/// \brief Compares two optional objects +/// \details If both optionals contain a value, they are compared with `T`s +/// relational operators. Otherwise `lhs` and `rhs` are equal only if they are +/// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs` +/// is not. +template +inline constexpr bool operator==(const optional &lhs, + const optional &rhs) { + return lhs.has_value() == rhs.has_value() && + (!lhs.has_value() || *lhs == *rhs); +} +/// \group relop +template +inline constexpr bool operator!=(const optional &lhs, + const optional &rhs) { + return lhs.has_value() != rhs.has_value() || + (lhs.has_value() && *lhs != *rhs); +} +/// \group relop +template +inline constexpr bool operator<(const optional &lhs, + const optional &rhs) { + return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); +} +/// \group relop +template +inline constexpr bool operator>(const optional &lhs, + const optional &rhs) { + return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); +} +/// \group relop +template +inline constexpr bool operator<=(const optional &lhs, + const optional &rhs) { + return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); +} +/// \group relop +template +inline constexpr bool operator>=(const optional &lhs, + const optional &rhs) { + return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); +} + +/// \group relop_nullopt +/// \brief Compares an optional to a `nullopt` +/// \details Equivalent to comparing the optional to an empty optional +template +inline constexpr bool operator==(const optional &lhs, nullopt_t) noexcept { + return !lhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator==(nullopt_t, const optional &rhs) noexcept { + return !rhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator!=(const optional &lhs, nullopt_t) noexcept { + return lhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator!=(nullopt_t, const optional &rhs) noexcept { + return rhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator<(const optional &, nullopt_t) noexcept { + return false; +} +/// \group relop_nullopt +template +inline constexpr bool operator<(nullopt_t, const optional &rhs) noexcept { + return rhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator<=(const optional &lhs, nullopt_t) noexcept { + return !lhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator<=(nullopt_t, const optional &) noexcept { + return true; +} +/// \group relop_nullopt +template +inline constexpr bool operator>(const optional &lhs, nullopt_t) noexcept { + return lhs.has_value(); +} +/// \group relop_nullopt +template +inline constexpr bool operator>(nullopt_t, const optional &) noexcept { + return false; +} +/// \group relop_nullopt +template +inline constexpr bool operator>=(const optional &, nullopt_t) noexcept { + return true; +} +/// \group relop_nullopt +template +inline constexpr bool operator>=(nullopt_t, const optional &rhs) noexcept { + return !rhs.has_value(); +} + +/// \group relop_t +/// \brief Compares the optional with a value. +/// \details If the optional has a value, it is compared with the other value +/// using `T`s relational operators. Otherwise, the optional is considered +/// less than the value. +template +inline constexpr bool operator==(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs == rhs : false; +} +/// \group relop_t +template +inline constexpr bool operator==(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs == *rhs : false; +} +/// \group relop_t +template +inline constexpr bool operator!=(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs != rhs : true; +} +/// \group relop_t +template +inline constexpr bool operator!=(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs != *rhs : true; +} +/// \group relop_t +template +inline constexpr bool operator<(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs < rhs : true; +} +/// \group relop_t +template +inline constexpr bool operator<(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs < *rhs : false; +} +/// \group relop_t +template +inline constexpr bool operator<=(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs <= rhs : true; +} +/// \group relop_t +template +inline constexpr bool operator<=(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs <= *rhs : false; +} +/// \group relop_t +template +inline constexpr bool operator>(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs > rhs : false; +} +/// \group relop_t +template +inline constexpr bool operator>(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs > *rhs : true; +} +/// \group relop_t +template +inline constexpr bool operator>=(const optional &lhs, const U &rhs) { + return lhs.has_value() ? *lhs >= rhs : false; +} +/// \group relop_t +template +inline constexpr bool operator>=(const U &lhs, const optional &rhs) { + return rhs.has_value() ? lhs >= *rhs : true; +} + +/// \synopsis template \nvoid swap(optional &lhs, optional +/// &rhs); +template ::value> * = nullptr, + detail::enable_if_t::value> * = nullptr> +void swap(optional &lhs, + optional &rhs) noexcept(noexcept(lhs.swap(rhs))) { + return lhs.swap(rhs); +} + +template +inline constexpr optional> make_optional(T &&v) { + return optional>(std::forward(v)); +} +template +inline constexpr optional make_optional(Args &&... args) { + return optional(in_place, std::forward(args)...); +} +template +inline constexpr optional make_optional(std::initializer_list il, + Args &&... args) { + return optional(in_place, il, std::forward(args)...); +} + +/// \exclude +namespace detail { +#ifdef TL_OPTIONAL_CX14 +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_impl(Opt &&opt, F &&f) { + return opt.has_value() + ? detail::invoke(std::forward(f), *std::forward(opt)) + : optional>(nullopt); +} + +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +auto map_impl(Opt &&opt, F &&f) { + if (opt.has_value()) { + detail::invoke(std::forward(f), *std::forward(opt)); + return monostate{}; + } + + return optional(nullopt); +} +#else +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> + +constexpr auto map_impl(Opt &&opt, F &&f) -> optional> { + return opt.has_value() + ? detail::invoke(std::forward(f), *std::forward(opt)) + : optional>(nullopt); +} + +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> + +auto map_impl(Opt &&opt, F &&f) -> optional { + if (opt.has_value()) { + detail::invoke(std::forward(f), *std::forward(opt)); + return monostate{}; + } + + return nullopt; +} +#endif +} // namespace detail } // namespace tl