| |
| /// |
| // optional - An implementation of std::optional with extensions |
| // Written in 2017 by Simon Brand (@TartanLlama) |
| // |
| // To the extent possible under law, the author(s) have dedicated all |
| // copyright and related and neighboring rights to this software to the |
| // public domain worldwide. This software is distributed without any warranty. |
| // |
| // You should have received a copy of the CC0 Public Domain Dedication |
| // along with this software. If not, see |
| // <http://creativecommons.org/publicdomain/zero/1.0/>. |
| /// |
| |
| #ifndef TL_OPTIONAL_HPP |
| #define TL_OPTIONAL_HPP |
| |
| #define TL_OPTIONAL_VERSION_MAJOR 0 |
| #define TL_OPTIONAL_VERSION_MINOR 5 |
| |
| #include <exception> |
| #include <functional> |
| #include <new> |
| #include <type_traits> |
| #include <utility> |
| |
| #if (defined(_MSC_VER) && _MSC_VER == 1900) |
| #define TL_OPTIONAL_MSVC2015 |
| #endif |
| |
| // TODO(Brian): We use libstdc++ with clang too. Sort this out nicely. |
| #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ |
| !(defined(__clang__) && defined(_LIBCPP_VERSION))) |
| #define TL_OPTIONAL_GCC49 |
| #endif |
| |
| #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ |
| !defined(__clang__)) |
| #define TL_OPTIONAL_GCC54 |
| #endif |
| |
| #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ |
| !defined(__clang__)) |
| #define TL_OPTIONAL_GCC55 |
| #endif |
| |
| #ifdef TL_OPTIONAL_GCC49 |
| // GCC < 5 doesn't support overloading on const&& for member functions |
| #define TL_OPTIONAL_NO_CONSTRR |
| |
| // GCC < 5 doesn't support some standard C++11 type traits |
| #define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ |
| std::has_trivial_copy_constructor<T>::value |
| #define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign<T>::value |
| |
| // This one will be different for GCC 5.7 if it's ever supported |
| #define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value |
| |
| // GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks std::vector |
| // for non-copyable types |
| #elif (defined(__GNUC__) && __GNUC__ < 8 && \ |
| !defined(__clang__)) |
| #ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX |
| #define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX |
| namespace tl { |
| namespace detail { |
| template<class T> |
| struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T>{}; |
| #ifdef _GLIBCXX_VECTOR |
| template<class T, class A> |
| struct is_trivially_copy_constructible<std::vector<T,A>> |
| : std::is_trivially_copy_constructible<T>{}; |
| #endif |
| } |
| } |
| #endif |
| |
| #define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ |
| tl::detail::is_trivially_copy_constructible<T>::value |
| #define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ |
| std::is_trivially_copy_assignable<T>::value |
| #define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value |
| #else |
| #define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ |
| std::is_trivially_copy_constructible<T>::value |
| #define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ |
| std::is_trivially_copy_assignable<T>::value |
| #define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value |
| #endif |
| |
| #if __cplusplus > 201103L |
| // TODO(Brian): Re-enable this once we have full C++14 support. |
| //#define TL_OPTIONAL_CXX14 |
| #endif |
| |
| // constexpr implies const in C++11, not C++14 |
| #if (__cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || \ |
| defined(TL_OPTIONAL_GCC49)) |
| /// \exclude |
| #define TL_OPTIONAL_11_CONSTEXPR |
| #else |
| /// \exclude |
| #define TL_OPTIONAL_11_CONSTEXPR constexpr |
| #endif |
| |
| 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 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 T> class optional; |
| |
| /// \exclude |
| namespace detail { |
| #ifndef TL_TRAITS_MUTEX |
| #define TL_TRAITS_MUTEX |
| // C++14-style aliases for brevity |
| template <class T> using remove_const_t = typename std::remove_const<T>::type; |
| template <class T> |
| using remove_reference_t = typename std::remove_reference<T>::type; |
| template <class T> using decay_t = typename std::decay<T>::type; |
| template <bool E, class T = void> |
| using enable_if_t = typename std::enable_if<E, T>::type; |
| template <bool B, class T, class F> |
| using conditional_t = typename std::conditional<B, T, F>::type; |
| |
| // std::conjunction from C++17 |
| template <class...> struct conjunction : std::true_type {}; |
| template <class B> struct conjunction<B> : B {}; |
| template <class B, class... Bs> |
| struct conjunction<B, Bs...> |
| : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {}; |
| |
| #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L |
| #define TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND |
| #endif |
| |
| // In C++11 mode, there's an issue in libc++'s std::mem_fn |
| // which results in a hard-error when using it in a noexcept expression |
| // in some cases. This is a check to workaround the common failing case. |
| #ifdef TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND |
| template <class T> struct is_pointer_to_non_const_member_func : std::false_type{}; |
| template <class T, class Ret, class... Args> |
| struct is_pointer_to_non_const_member_func<Ret (T::*) (Args...)> : std::true_type{}; |
| template <class T, class Ret, class... Args> |
| struct is_pointer_to_non_const_member_func<Ret (T::*) (Args...)&> : std::true_type{}; |
| template <class T, class Ret, class... Args> |
| struct is_pointer_to_non_const_member_func<Ret (T::*) (Args...)&&> : std::true_type{}; |
| template <class T, class Ret, class... Args> |
| struct is_pointer_to_non_const_member_func<Ret (T::*) (Args...) volatile> : std::true_type{}; |
| template <class T, class Ret, class... Args> |
| struct is_pointer_to_non_const_member_func<Ret (T::*) (Args...) volatile&> : std::true_type{}; |
| template <class T, class Ret, class... Args> |
| struct is_pointer_to_non_const_member_func<Ret (T::*) (Args...) volatile&&> : std::true_type{}; |
| |
| template <class T> struct is_const_or_const_ref : std::false_type{}; |
| template <class T> struct is_const_or_const_ref<T const&> : std::true_type{}; |
| template <class T> struct is_const_or_const_ref<T const> : std::true_type{}; |
| #endif |
| |
| // std::invoke from C++17 |
| // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround |
| template <typename Fn, typename... Args, |
| #ifdef TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND |
| typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value |
| && is_const_or_const_ref<Args...>::value)>, |
| #endif |
| typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, |
| int = 0> |
| constexpr auto invoke(Fn &&f, Args &&... args) noexcept( |
| noexcept(std::mem_fn(f)(std::forward<Args>(args)...))) |
| -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) { |
| return std::mem_fn(f)(std::forward<Args>(args)...); |
| } |
| |
| template <typename Fn, typename... Args, |
| typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>> |
| constexpr auto invoke(Fn &&f, Args &&... args) noexcept( |
| noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...))) |
| -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) { |
| return std::forward<Fn>(f)(std::forward<Args>(args)...); |
| } |
| |
| // std::invoke_result from C++17 |
| template <class F, class, class... Us> struct invoke_result_impl; |
| |
| template <class F, class... Us> |
| struct invoke_result_impl< |
| F, decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()), |
| Us...> { |
| using type = decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...)); |
| }; |
| |
| template <class F, class... Us> |
| using invoke_result = invoke_result_impl<F, void, Us...>; |
| |
| template <class F, class... Us> |
| using invoke_result_t = typename invoke_result<F, Us...>::type; |
| #endif |
| |
| // std::void_t from C++17 |
| template <class...> struct voider { using type = void; }; |
| template <class... Ts> using void_t = typename voider<Ts...>::type; |
| |
| // Trait for checking if a type is a tl::optional |
| template <class T> struct is_optional_impl : std::false_type {}; |
| template <class T> struct is_optional_impl<optional<T>> : std::true_type {}; |
| template <class T> using is_optional = is_optional_impl<decay_t<T>>; |
| |
| // Change void to tl::monostate |
| template <class U> |
| using fixup_void = conditional_t<std::is_void<U>::value, monostate, U>; |
| |
| template <class F, class U, class = invoke_result_t<F, U>> |
| using get_map_return = optional<fixup_void<invoke_result_t<F, U>>>; |
| |
| // Check if invoking F for some Us returns void |
| template <class F, class = void, class... U> struct returns_void_impl; |
| template <class F, class... U> |
| struct returns_void_impl<F, void_t<invoke_result_t<F, U...>>, U...> |
| : std::is_void<invoke_result_t<F, U...>> {}; |
| template <class F, class... U> |
| using returns_void = returns_void_impl<F, void, U...>; |
| |
| template <class T, class... U> |
| using enable_if_ret_void = enable_if_t<returns_void<T &&, U...>::value>; |
| |
| template <class T, class... U> |
| using disable_if_ret_void = enable_if_t<!returns_void<T &&, U...>::value>; |
| |
| template <class T, class U> |
| using enable_forward_value = |
| detail::enable_if_t<std::is_constructible<T, U &&>::value && |
| !std::is_same<detail::decay_t<U>, in_place_t>::value && |
| !std::is_same<optional<T>, detail::decay_t<U>>::value>; |
| |
| template <class T, class U, class Other> |
| using enable_from_other = detail::enable_if_t< |
| std::is_constructible<T, Other>::value && |
| !std::is_constructible<T, optional<U> &>::value && |
| !std::is_constructible<T, optional<U> &&>::value && |
| !std::is_constructible<T, const optional<U> &>::value && |
| !std::is_constructible<T, const optional<U> &&>::value && |
| !std::is_convertible<optional<U> &, T>::value && |
| !std::is_convertible<optional<U> &&, T>::value && |
| !std::is_convertible<const optional<U> &, T>::value && |
| !std::is_convertible<const optional<U> &&, T>::value>; |
| |
| template <class T, class U> |
| using enable_assign_forward = detail::enable_if_t< |
| !std::is_same<optional<T>, detail::decay_t<U>>::value && |
| !detail::conjunction<std::is_scalar<T>, |
| std::is_same<T, detail::decay_t<U>>>::value && |
| std::is_constructible<T, U>::value && std::is_assignable<T &, U>::value>; |
| |
| template <class T, class U, class Other> |
| using enable_assign_from_other = detail::enable_if_t< |
| std::is_constructible<T, Other>::value && |
| std::is_assignable<T &, Other>::value && |
| !std::is_constructible<T, optional<U> &>::value && |
| !std::is_constructible<T, optional<U> &&>::value && |
| !std::is_constructible<T, const optional<U> &>::value && |
| !std::is_constructible<T, const optional<U> &&>::value && |
| !std::is_convertible<optional<U> &, T>::value && |
| !std::is_convertible<optional<U> &&, T>::value && |
| !std::is_convertible<const optional<U> &, T>::value && |
| !std::is_convertible<const optional<U> &&, T>::value && |
| !std::is_assignable<T &, optional<U> &>::value && |
| !std::is_assignable<T &, optional<U> &&>::value && |
| !std::is_assignable<T &, const optional<U> &>::value && |
| !std::is_assignable<T &, const optional<U> &&>::value>; |
| |
| #ifdef _MSC_VER |
| // TODO make a version which works with MSVC |
| template <class T, class U = T> struct is_swappable : std::true_type {}; |
| |
| template <class T, class U = T> 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 {}; |
| |
| template <class T> tag swap(T &, T &); |
| template <class T, std::size_t N> 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 <class, class> std::false_type can_swap(...) noexcept(false); |
| template <class T, class U, |
| class = decltype(swap(std::declval<T &>(), std::declval<U &>()))> |
| std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(), |
| std::declval<U &>()))); |
| |
| template <class, class> std::false_type uses_std(...); |
| template <class T, class U> |
| std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag> |
| uses_std(int); |
| |
| template <class T> |
| struct is_std_swap_noexcept |
| : std::integral_constant<bool, |
| std::is_nothrow_move_constructible<T>::value && |
| std::is_nothrow_move_assignable<T>::value> {}; |
| |
| template <class T, std::size_t N> |
| struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {}; |
| |
| template <class T, class U> |
| struct is_adl_swap_noexcept |
| : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {}; |
| } // namespace swap_adl_tests |
| |
| template <class T, class U = T> |
| struct is_swappable |
| : std::integral_constant< |
| bool, |
| decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value && |
| (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value || |
| (std::is_move_assignable<T>::value && |
| std::is_move_constructible<T>::value))> {}; |
| |
| template <class T, std::size_t N> |
| struct is_swappable<T[N], T[N]> |
| : std::integral_constant< |
| bool, |
| decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value && |
| (!decltype( |
| detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value || |
| is_swappable<T, T>::value)> {}; |
| |
| template <class T, class U = T> |
| struct is_nothrow_swappable |
| : std::integral_constant< |
| bool, |
| is_swappable<T, U>::value && |
| ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value |
| &&detail::swap_adl_tests::is_std_swap_noexcept<T>::value) || |
| (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value && |
| detail::swap_adl_tests::is_adl_swap_noexcept<T, |
| U>::value))> { |
| }; |
| #endif |
| |
| // The storage base manages the actual storage, and correctly propagates |
| // trivial destruction from T. This case is for when T is not trivially |
| // destructible. |
| template <class T, bool = ::std::is_trivially_destructible<T>::value> |
| struct optional_storage_base { |
| TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept |
| : m_dummy(), m_has_value(false) {} |
| |
| template <class... U> |
| TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) |
| : m_value(std::forward<U>(u)...), m_has_value(true) {} |
| |
| ~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; |
| }; |
| |
| // This case is for when T is trivially destructible. |
| template <class T> struct optional_storage_base<T, true> { |
| TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept |
| : m_dummy(), m_has_value(false) {} |
| |
| template <class... U> |
| TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) |
| : m_value(std::forward<U>(u)...), m_has_value(true) {} |
| |
| // No destructor, so this class is trivially destructible |
| |
| struct dummy {}; |
| union { |
| dummy m_dummy; |
| T m_value; |
| }; |
| |
| bool m_has_value = false; |
| }; |
| |
| // This base class provides some handy member functions which can be used in |
| // further derived classes |
| template <class T> struct optional_operations_base : optional_storage_base<T> { |
| using optional_storage_base<T>::optional_storage_base; |
| |
| void hard_reset() noexcept { |
| get().~T(); |
| this->m_has_value = false; |
| } |
| |
| template <class... Args> void construct(Args &&... args) noexcept { |
| new (std::addressof(this->m_value)) T(std::forward<Args>(args)...); |
| this->m_has_value = true; |
| } |
| |
| template <class Opt> void assign(Opt &&rhs) { |
| if (this->has_value()) { |
| if (rhs.has_value()) { |
| this->m_value = std::forward<Opt>(rhs).get(); |
| } else { |
| this->m_value.~T(); |
| this->m_has_value = false; |
| } |
| } |
| |
| else if (rhs.has_value()) { |
| construct(std::forward<Opt>(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() && { return 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 <class T, bool = TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)> |
| struct optional_copy_base : optional_operations_base<T> { |
| using optional_operations_base<T>::optional_operations_base; |
| }; |
| |
| // This specialization is for when T is not trivially copy constructible |
| template <class T> |
| struct optional_copy_base<T, false> : optional_operations_base<T> { |
| using optional_operations_base<T>::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 |
| // doesn't implement an analogue to std::is_trivially_move_constructible. We |
| // have to make do with a non-trivial move constructor even if T is trivially |
| // move constructible |
| #ifndef TL_OPTIONAL_GCC49 |
| template <class T, bool = std::is_trivially_move_constructible<T>::value> |
| struct optional_move_base : optional_copy_base<T> { |
| using optional_copy_base<T>::optional_copy_base; |
| }; |
| #else |
| template <class T, bool = false> struct optional_move_base; |
| #endif |
| template <class T> struct optional_move_base<T, false> : optional_copy_base<T> { |
| using optional_copy_base<T>::optional_copy_base; |
| |
| 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<T>::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; |
| }; |
| |
| // This class manages conditionally having a trivial copy assignment operator |
| template <class T, bool = TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) && |
| TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) && |
| TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T)> |
| struct optional_copy_assign_base : optional_move_base<T> { |
| using optional_move_base<T>::optional_move_base; |
| }; |
| |
| template <class T> |
| struct optional_copy_assign_base<T, false> : optional_move_base<T> { |
| using optional_move_base<T>::optional_move_base; |
| |
| 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; |
| }; |
| |
| // This class manages conditionally having a trivial move assignment operator |
| // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it |
| // doesn't implement an analogue to std::is_trivially_move_assignable. We have |
| // to make do with a non-trivial move assignment operator even if T is trivially |
| // move assignable |
| #ifndef TL_OPTIONAL_GCC49 |
| template <class T, bool = std::is_trivially_destructible<T>::value |
| &&std::is_trivially_move_constructible<T>::value |
| &&std::is_trivially_move_assignable<T>::value> |
| struct optional_move_assign_base : optional_copy_assign_base<T> { |
| using optional_copy_assign_base<T>::optional_copy_assign_base; |
| }; |
| #else |
| template <class T, bool = false> struct optional_move_assign_base; |
| #endif |
| |
| template <class T> |
| struct optional_move_assign_base<T, false> : optional_copy_assign_base<T> { |
| using optional_copy_assign_base<T>::optional_copy_assign_base; |
| |
| 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 & |
| operator=(const optional_move_assign_base &rhs) = default; |
| |
| optional_move_assign_base & |
| operator=(optional_move_assign_base &&rhs) noexcept( |
| std::is_nothrow_move_constructible<T>::value |
| &&std::is_nothrow_move_assignable<T>::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 <class T, bool EnableCopy = std::is_copy_constructible<T>::value, |
| bool EnableMove = std::is_move_constructible<T>::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 <class T> struct optional_delete_ctor_base<T, true, false> { |
| 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 <class T> struct optional_delete_ctor_base<T, false, true> { |
| 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 <class T> struct optional_delete_ctor_base<T, false, false> { |
| 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 <class T, |
| bool EnableCopy = (std::is_copy_constructible<T>::value && |
| std::is_copy_assignable<T>::value), |
| bool EnableMove = (std::is_move_constructible<T>::value && |
| std::is_move_assignable<T>::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 <class T> struct optional_delete_assign_base<T, true, false> { |
| 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 <class T> struct optional_delete_assign_base<T, false, true> { |
| 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 <class T> struct optional_delete_assign_base<T, false, false> { |
| 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 |
| |
| /// \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<int> a = tl::nullopt; |
| /// void foo (tl::optional<int>); |
| /// 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"; } |
| }; |
| |
| /// 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 T> |
| class optional : private detail::optional_move_assign_base<T>, |
| private detail::optional_delete_ctor_base<T>, |
| private detail::optional_delete_assign_base<T> { |
| using base = detail::optional_move_assign_base<T>; |
| |
| static_assert(!std::is_same<T, in_place_t>::value, |
| "instantiation of optional with in_place_t is ill-formed"); |
| static_assert(!std::is_same<detail::decay_t<T>, nullopt_t>::value, |
| "instantiation of optional with nullopt_t is ill-formed"); |
| |
| 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) && !defined(TL_OPTIONAL_GCC55) |
| /// \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>(f), |
| /// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be |
| /// the result of `std::invoke(std::forward<F>(f), value())`. Returns a |
| /// `std::optional<U>`. The return value is empty if `*this` is empty, |
| /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` |
| /// is returned. |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; |
| template <class F> TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & { |
| using result = detail::invoke_result_t<F, T &>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : result(nullopt); |
| } |
| |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; |
| template <class F> TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && { |
| using result = detail::invoke_result_t<F, T &&>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) |
| : result(nullopt); |
| } |
| |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; |
| template <class F> constexpr auto and_then(F &&f) const & { |
| using result = detail::invoke_result_t<F, const T &>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : result(nullopt); |
| } |
| |
| #ifndef TL_OPTIONAL_NO_CONSTRR |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; |
| template <class F> constexpr auto and_then(F &&f) const && { |
| using result = detail::invoke_result_t<F, const T &&>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(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>(f), |
| /// value())` returns a `std::optional<U>` for some `U`. |
| /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), |
| /// value())`. Returns a `std::optional<U>`. The return value is empty if |
| /// `*this` is empty, otherwise the return value of |
| /// `std::invoke(std::forward<F>(f), value())` is returned. |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; |
| template <class F> |
| TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T &> and_then(F &&f) & { |
| using result = detail::invoke_result_t<F, T &>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : result(nullopt); |
| } |
| |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; |
| template <class F> |
| TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T &&> and_then(F &&f) && { |
| using result = detail::invoke_result_t<F, T &&>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) |
| : result(nullopt); |
| } |
| |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; |
| template <class F> |
| constexpr detail::invoke_result_t<F, const T &> and_then(F &&f) const & { |
| using result = detail::invoke_result_t<F, const T &>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : result(nullopt); |
| } |
| |
| #ifndef TL_OPTIONAL_NO_CONSTRR |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; |
| template <class F> |
| constexpr detail::invoke_result_t<F, const T &&> and_then(F &&f) const && { |
| using result = detail::invoke_result_t<F, const T &&>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) |
| : result(nullopt); |
| } |
| #endif |
| #endif |
| |
| #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ |
| !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) |
| /// \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>(f), |
| /// value())`. Returns a `std::optional<U>`. The return value is empty if |
| /// `*this` is empty, otherwise an `optional<U>` is constructed from the |
| /// return value of `std::invoke(std::forward<F>(f), value())` and is |
| /// returned. |
| /// |
| /// \group map |
| /// \synopsis template <class F> constexpr auto map(F &&f) &; |
| template <class F> TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & { |
| return optional_map_impl(*this, std::forward<F>(f)); |
| } |
| |
| /// \group map |
| /// \synopsis template <class F> constexpr auto map(F &&f) &&; |
| template <class F> TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && { |
| return optional_map_impl(std::move(*this), std::forward<F>(f)); |
| } |
| |
| /// \group map |
| /// \synopsis template <class F> constexpr auto map(F &&f) const&; |
| template <class F> constexpr auto map(F &&f) const & { |
| return optional_map_impl(*this, std::forward<F>(f)); |
| } |
| |
| /// \group map |
| /// \synopsis template <class F> constexpr auto map(F &&f) const&&; |
| template <class F> constexpr auto map(F &&f) const && { |
| return optional_map_impl(std::move(*this), std::forward<F>(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>(f), |
| /// value())`. Returns a `std::optional<U>`. The return value is empty if |
| /// `*this` is empty, otherwise an `optional<U>` is constructed from the |
| /// return value of `std::invoke(std::forward<F>(f), value())` and is |
| /// returned. |
| /// |
| /// \group map |
| /// \synopsis template <class F> auto map(F &&f) &; |
| template <class F> |
| TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval<optional &>(), |
| std::declval<F &&>())) |
| map(F &&f) & { |
| return optional_map_impl(*this, std::forward<F>(f)); |
| } |
| |
| /// \group map |
| /// \synopsis template <class F> auto map(F &&f) &&; |
| template <class F> |
| TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval<optional &&>(), |
| std::declval<F &&>())) |
| map(F &&f) && { |
| return optional_map_impl(std::move(*this), std::forward<F>(f)); |
| } |
| |
| /// \group map |
| /// \synopsis template <class F> auto map(F &&f) const&; |
| template <class F> |
| constexpr decltype(optional_map_impl(std::declval<const optional &>(), |
| std::declval<F &&>())) |
| map(F &&f) const & { |
| return optional_map_impl(*this, std::forward<F>(f)); |
| } |
| |
| #ifndef TL_OPTIONAL_NO_CONSTRR |
| /// \group map |
| /// \synopsis template <class F> auto map(F &&f) const&&; |
| template <class F> |
| constexpr decltype(optional_map_impl(std::declval<const optional &&>(), |
| std::declval<F &&>())) |
| map(F &&f) const && { |
| return optional_map_impl(std::move(*this), std::forward<F>(f)); |
| } |
| #endif |
| #endif |
| |
| /// \brief Calls `f` if the optional is empty |
| /// \requires `std::invoke_result_t<F>` must be void or convertible to |
| /// `optional<T>`. |
| /// \effects If `*this` has a value, returns `*this`. |
| /// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns |
| /// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`. |
| /// |
| /// \group or_else |
| /// \synopsis template <class F> optional<T> or_else (F &&f) &; |
| template <class F, detail::enable_if_ret_void<F> * = nullptr> |
| optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { |
| if (has_value()) |
| return *this; |
| |
| std::forward<F>(f)(); |
| return nullopt; |
| } |
| |
| /// \exclude |
| template <class F, detail::disable_if_ret_void<F> * = nullptr> |
| optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { |
| return has_value() ? *this : std::forward<F>(f)(); |
| } |
| |
| /// \group or_else |
| /// \synopsis template <class F> optional<T> or_else (F &&f) &&; |
| template <class F, detail::enable_if_ret_void<F> * = nullptr> |
| optional<T> or_else(F &&f) && { |
| if (has_value()) |
| return std::move(*this); |
| |
| std::forward<F>(f)(); |
| return nullopt; |
| } |
| |
| /// \exclude |
| template <class F, detail::disable_if_ret_void<F> * = nullptr> |
| optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && { |
| return has_value() ? std::move(*this) : std::forward<F>(f)(); |
| } |
| |
| /// \group or_else |
| /// \synopsis template <class F> optional<T> or_else (F &&f) const &; |
| template <class F, detail::enable_if_ret_void<F> * = nullptr> |
| optional<T> or_else(F &&f) const & { |
| if (has_value()) |
| return *this; |
| |
| std::forward<F>(f)(); |
| return nullopt; |
| } |
| |
| /// \exclude |
| template <class F, detail::disable_if_ret_void<F> * = nullptr> |
| optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & { |
| return has_value() ? *this : std::forward<F>(f)(); |
| } |
| |
| #ifndef TL_OPTIONAL_NO_CONSTRR |
| /// \exclude |
| template <class F, detail::enable_if_ret_void<F> * = nullptr> |
| optional<T> or_else(F &&f) const && { |
| if (has_value()) |
| return std::move(*this); |
| |
| std::forward<F>(f)(); |
| return nullopt; |
| } |
| |
| /// \exclude |
| template <class F, detail::disable_if_ret_void<F> * = nullptr> |
| optional<T> or_else(F &&f) const && { |
| return has_value() ? std::move(*this) : std::forward<F>(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 <class F, class U> U map_or(F &&f, U &&u) & { |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : std::forward<U>(u); |
| } |
| |
| /// \group map_or |
| template <class F, class U> U map_or(F &&f, U &&u) && { |
| return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) |
| : std::forward<U>(u); |
| } |
| |
| /// \group map_or |
| template <class F, class U> U map_or(F &&f, U &&u) const & { |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : std::forward<U>(u); |
| } |
| |
| #ifndef TL_OPTIONAL_NO_CONSTRR |
| /// \group map_or |
| template <class F, class U> U map_or(F &&f, U &&u) const && { |
| return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) |
| : std::forward<U>(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>(u)()` is returned. |
| /// |
| /// \group map_or_else |
| /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) &; |
| template <class F, class U> |
| detail::invoke_result_t<U> map_or_else(F &&f, U &&u) & { |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : std::forward<U>(u)(); |
| } |
| |
| /// \group map_or_else |
| /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) |
| /// &&; |
| template <class F, class U> |
| detail::invoke_result_t<U> map_or_else(F &&f, U &&u) && { |
| return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) |
| : std::forward<U>(u)(); |
| } |
| |
| /// \group map_or_else |
| /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) |
| /// const &; |
| template <class F, class U> |
| detail::invoke_result_t<U> map_or_else(F &&f, U &&u) const & { |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : std::forward<U>(u)(); |
| } |
| |
| #ifndef TL_OPTIONAL_NO_CONSTRR |
| /// \group map_or_else |
| /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) |
| /// const &&; |
| template <class F, class U> |
| detail::invoke_result_t<U> map_or_else(F &&f, U &&u) const && { |
| return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) |
| : std::forward<U>(u)(); |
| } |
| #endif |
| |
| /// \returns `u` if `*this` has a value, otherwise an empty optional. |
| template <class U> |
| constexpr optional<typename std::decay<U>::type> conjunction(U &&u) const { |
| using result = optional<detail::decay_t<U>>; |
| 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 <class... Args> constexpr explicit optional(in_place_t, Args&&... args); |
| template <class... Args> |
| constexpr explicit optional( |
| detail::enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>, |
| Args &&... args) |
| : base(in_place, std::forward<Args>(args)...) {} |
| |
| /// \group in_place |
| /// \synopsis template <class U, class... Args>\nconstexpr explicit optional(in_place_t, std::initializer_list<U>&, Args&&... args); |
| template <class U, class... Args> |
| TL_OPTIONAL_11_CONSTEXPR explicit optional( |
| detail::enable_if_t<std::is_constructible<T, std::initializer_list<U> &, |
| Args &&...>::value, |
| in_place_t>, |
| std::initializer_list<U> il, Args &&... args) { |
| this->construct(il, std::forward<Args>(args)...); |
| } |
| |
| /// Constructs the stored value with `u`. |
| /// \synopsis template <class U=T> constexpr optional(U &&u); |
| template < |
| class U = T, |
| detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr, |
| detail::enable_forward_value<T, U> * = nullptr> |
| constexpr optional(U &&u) : base(in_place, std::forward<U>(u)) {} |
| |
| /// \exclude |
| template < |
| class U = T, |
| detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr, |
| detail::enable_forward_value<T, U> * = nullptr> |
| constexpr explicit optional(U &&u) : base(in_place, std::forward<U>(u)) {} |
| |
| /// Converting copy constructor. |
| /// \synopsis template <class U> optional(const optional<U> &rhs); |
| template < |
| class U, detail::enable_from_other<T, U, const U &> * = nullptr, |
| detail::enable_if_t<std::is_convertible<const U &, T>::value> * = nullptr> |
| optional(const optional<U> &rhs) { |
| this->construct(*rhs); |
| } |
| |
| /// \exclude |
| template <class U, detail::enable_from_other<T, U, const U &> * = nullptr, |
| detail::enable_if_t<!std::is_convertible<const U &, T>::value> * = |
| nullptr> |
| explicit optional(const optional<U> &rhs) { |
| this->construct(*rhs); |
| } |
| |
| /// Converting move constructor. |
| /// \synopsis template <class U> optional(optional<U> &&rhs); |
| template < |
| class U, detail::enable_from_other<T, U, U &&> * = nullptr, |
| detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr> |
| optional(optional<U> &&rhs) { |
| this->construct(std::move(*rhs)); |
| } |
| |
| /// \exclude |
| template < |
| class U, detail::enable_from_other<T, U, U &&> * = nullptr, |
| detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr> |
| explicit optional(optional<U> &&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 <class U = T, detail::enable_assign_forward<T, U> * = nullptr> |
| optional &operator=(U &&u) { |
| if (has_value()) { |
| this->m_value = std::forward<U>(u); |
| } else { |
| this->construct(std::forward<U>(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<U> & rhs); |
| template <class U, |
| detail::enable_assign_from_other<T, U, const U &> * = nullptr> |
| optional &operator=(const optional<U> &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<U> && rhs); |
| template <class U, detail::enable_assign_from_other<T, U, U> * = nullptr> |
| optional &operator=(optional<U> &&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 <class... Args> T &emplace(Args &&... args) { |
| static_assert(std::is_constructible<T, Args &&...>::value, |
| "T must be constructible with Args"); |
| |
| *this = nullopt; |
| this->construct(std::forward<Args>(args)...); |
| return value(); |
| } |
| |
| /// \group emplace |
| /// \synopsis template <class U, class... Args>\nT& emplace(std::initializer_list<U> il, Args &&... args); |
| template <class U, class... Args> |
| detail::enable_if_t< |
| std::is_constructible<T, std::initializer_list<U> &, Args &&...>::value, |
| T &> |
| emplace(std::initializer_list<U> il, Args &&... args) { |
| *this = nullopt; |
| this->construct(il, std::forward<Args>(args)...); |
| return value(); |
| } |
| |
| /// 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<T>::value |
| &&detail::is_nothrow_swappable<T>::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 |
| TL_OPTIONAL_11_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 <class U> constexpr T value_or(U &&u) const & { |
| static_assert(std::is_copy_constructible<T>::value && |
| std::is_convertible<U &&, T>::value, |
| "T must be copy constructible and convertible from U"); |
| return has_value() ? **this : static_cast<T>(std::forward<U>(u)); |
| } |
| |
| /// \group value_or |
| template <class U> TL_OPTIONAL_11_CONSTEXPR T value_or(U &&u) && { |
| static_assert(std::is_move_constructible<T>::value && |
| std::is_convertible<U &&, T>::value, |
| "T must be move constructible and convertible from U"); |
| return has_value() ? **this : static_cast<T>(std::forward<U>(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 <class T, class U> |
| inline constexpr bool operator==(const optional<T> &lhs, |
| const optional<U> &rhs) { |
| return lhs.has_value() == rhs.has_value() && |
| (!lhs.has_value() || *lhs == *rhs); |
| } |
| /// \group relop |
| template <class T, class U> |
| inline constexpr bool operator!=(const optional<T> &lhs, |
| const optional<U> &rhs) { |
| return lhs.has_value() != rhs.has_value() || |
| (lhs.has_value() && *lhs != *rhs); |
| } |
| /// \group relop |
| template <class T, class U> |
| inline constexpr bool operator<(const optional<T> &lhs, |
| const optional<U> &rhs) { |
| return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); |
| } |
| /// \group relop |
| template <class T, class U> |
| inline constexpr bool operator>(const optional<T> &lhs, |
| const optional<U> &rhs) { |
| return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); |
| } |
| /// \group relop |
| template <class T, class U> |
| inline constexpr bool operator<=(const optional<T> &lhs, |
| const optional<U> &rhs) { |
| return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); |
| } |
| /// \group relop |
| template <class T, class U> |
| inline constexpr bool operator>=(const optional<T> &lhs, |
| const optional<U> &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 <class T> |
| inline constexpr bool operator==(const optional<T> &lhs, nullopt_t) noexcept { |
| return !lhs.has_value(); |
| } |
| /// \group relop_nullopt |
| template <class T> |
| inline constexpr bool operator==(nullopt_t, const optional<T> &rhs) noexcept { |
| return !rhs.has_value(); |
| } |
| /// \group relop_nullopt |
| template <class T> |
| inline constexpr bool operator!=(const optional<T> &lhs, nullopt_t) noexcept { |
| return lhs.has_value(); |
| } |
| /// \group relop_nullopt |
| template <class T> |
| inline constexpr bool operator!=(nullopt_t, const optional<T> &rhs) noexcept { |
| return rhs.has_value(); |
| } |
| /// \group relop_nullopt |
| template <class T> |
| inline constexpr bool operator<(const optional<T> &, nullopt_t) noexcept { |
| return false; |
| } |
| /// \group relop_nullopt |
| template <class T> |
| inline constexpr bool operator<(nullopt_t, const optional<T> &rhs) noexcept { |
| return rhs.has_value(); |
| } |
| /// \group relop_nullopt |
| template <class T> |
| inline constexpr bool operator<=(const optional<T> &lhs, nullopt_t) noexcept { |
| return !lhs.has_value(); |
| } |
| /// \group relop_nullopt |
| template <class T> |
| inline constexpr bool operator<=(nullopt_t, const optional<T> &) noexcept { |
| return true; |
| } |
| /// \group relop_nullopt |
| template <class T> |
| inline constexpr bool operator>(const optional<T> &lhs, nullopt_t) noexcept { |
| return lhs.has_value(); |
| } |
| /// \group relop_nullopt |
| template <class T> |
| inline constexpr bool operator>(nullopt_t, const optional<T> &) noexcept { |
| return false; |
| } |
| /// \group relop_nullopt |
| template <class T> |
| inline constexpr bool operator>=(const optional<T> &, nullopt_t) noexcept { |
| return true; |
| } |
| /// \group relop_nullopt |
| template <class T> |
| inline constexpr bool operator>=(nullopt_t, const optional<T> &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 <class T, class U> |
| inline constexpr bool operator==(const optional<T> &lhs, const U &rhs) { |
| return lhs.has_value() ? *lhs == rhs : false; |
| } |
| /// \group relop_t |
| template <class T, class U> |
| inline constexpr bool operator==(const U &lhs, const optional<T> &rhs) { |
| return rhs.has_value() ? lhs == *rhs : false; |
| } |
| /// \group relop_t |
| template <class T, class U> |
| inline constexpr bool operator!=(const optional<T> &lhs, const U &rhs) { |
| return lhs.has_value() ? *lhs != rhs : true; |
| } |
| /// \group relop_t |
| template <class T, class U> |
| inline constexpr bool operator!=(const U &lhs, const optional<T> &rhs) { |
| return rhs.has_value() ? lhs != *rhs : true; |
| } |
| /// \group relop_t |
| template <class T, class U> |
| inline constexpr bool operator<(const optional<T> &lhs, const U &rhs) { |
| return lhs.has_value() ? *lhs < rhs : true; |
| } |
| /// \group relop_t |
| template <class T, class U> |
| inline constexpr bool operator<(const U &lhs, const optional<T> &rhs) { |
| return rhs.has_value() ? lhs < *rhs : false; |
| } |
| /// \group relop_t |
| template <class T, class U> |
| inline constexpr bool operator<=(const optional<T> &lhs, const U &rhs) { |
| return lhs.has_value() ? *lhs <= rhs : true; |
| } |
| /// \group relop_t |
| template <class T, class U> |
| inline constexpr bool operator<=(const U &lhs, const optional<T> &rhs) { |
| return rhs.has_value() ? lhs <= *rhs : false; |
| } |
| /// \group relop_t |
| template <class T, class U> |
| inline constexpr bool operator>(const optional<T> &lhs, const U &rhs) { |
| return lhs.has_value() ? *lhs > rhs : false; |
| } |
| /// \group relop_t |
| template <class T, class U> |
| inline constexpr bool operator>(const U &lhs, const optional<T> &rhs) { |
| return rhs.has_value() ? lhs > *rhs : true; |
| } |
| /// \group relop_t |
| template <class T, class U> |
| inline constexpr bool operator>=(const optional<T> &lhs, const U &rhs) { |
| return lhs.has_value() ? *lhs >= rhs : false; |
| } |
| /// \group relop_t |
| template <class T, class U> |
| inline constexpr bool operator>=(const U &lhs, const optional<T> &rhs) { |
| return rhs.has_value() ? lhs >= *rhs : true; |
| } |
| |
| /// \synopsis template <class T>\nvoid swap(optional<T> &lhs, optional<T> &rhs); |
| template <class T, |
| detail::enable_if_t<std::is_move_constructible<T>::value> * = nullptr, |
| detail::enable_if_t<detail::is_swappable<T>::value> * = nullptr> |
| void swap(optional<T> &lhs, |
| optional<T> &rhs) noexcept(noexcept(lhs.swap(rhs))) { |
| return lhs.swap(rhs); |
| } |
| |
| namespace detail { |
| struct i_am_secret {}; |
| } // namespace detail |
| |
| template <class T = detail::i_am_secret, class U, |
| class Ret = |
| detail::conditional_t<std::is_same<T, detail::i_am_secret>::value, |
| detail::decay_t<U>, T>> |
| inline constexpr optional<Ret> make_optional(U &&v) { |
| return optional<Ret>(std::forward<U>(v)); |
| } |
| |
| template <class T, class... Args> |
| inline constexpr optional<T> make_optional(Args &&... args) { |
| return optional<T>(in_place, std::forward<Args>(args)...); |
| } |
| template <class T, class U, class... Args> |
| inline constexpr optional<T> make_optional(std::initializer_list<U> il, |
| Args &&... args) { |
| return optional<T>(in_place, il, std::forward<Args>(args)...); |
| } |
| |
| #if __cplusplus >= 201703L |
| template <class T> optional(T)->optional<T>; |
| #endif |
| |
| /// \exclude |
| namespace detail { |
| #ifdef TL_OPTIONAL_CXX14 |
| template <class Opt, class F, |
| class Ret = decltype(detail::invoke(std::declval<F>(), |
| *std::declval<Opt>())), |
| detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> |
| constexpr auto optional_map_impl(Opt &&opt, F &&f) { |
| return opt.has_value() |
| ? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)) |
| : optional<Ret>(nullopt); |
| } |
| |
| template <class Opt, class F, |
| class Ret = decltype(detail::invoke(std::declval<F>(), |
| *std::declval<Opt>())), |
| detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> |
| auto optional_map_impl(Opt &&opt, F &&f) { |
| if (opt.has_value()) { |
| detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)); |
| return make_optional(monostate{}); |
| } |
| |
| return optional<monostate>(nullopt); |
| } |
| #else |
| template <class Opt, class F, |
| class Ret = decltype(detail::invoke(std::declval<F>(), |
| *std::declval<Opt>())), |
| detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> |
| |
| constexpr auto optional_map_impl(Opt &&opt, F &&f) -> optional<Ret> { |
| return opt.has_value() |
| ? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)) |
| : optional<Ret>(nullopt); |
| } |
| |
| template <class Opt, class F, |
| class Ret = decltype(detail::invoke(std::declval<F>(), |
| *std::declval<Opt>())), |
| detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> |
| |
| auto optional_map_impl(Opt &&opt, F &&f) -> optional<monostate> { |
| if (opt.has_value()) { |
| detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)); |
| return monostate{}; |
| } |
| |
| return nullopt; |
| } |
| #endif |
| } // namespace detail |
| |
| /// Specialization for when `T` is a reference. `optional<T&>` acts similarly |
| /// to a `T*`, but provides more operations and shows intent more clearly. |
| /// |
| /// *Examples*: |
| /// |
| /// ``` |
| /// int i = 42; |
| /// tl::optional<int&> o = i; |
| /// *o == 42; //true |
| /// i = 12; |
| /// *o = 12; //true |
| /// &*o == &i; //true |
| /// ``` |
| /// |
| /// Assignment has rebind semantics rather than assign-through semantics: |
| /// |
| /// ``` |
| /// int j = 8; |
| /// o = j; |
| /// |
| /// &*o == &j; //true |
| /// ``` |
| template <class T> class optional<T &> { |
| 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) && !defined(TL_OPTIONAL_GCC55) |
| /// \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>(f), |
| /// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be |
| /// the result of `std::invoke(std::forward<F>(f), value())`. Returns a |
| /// `std::optional<U>`. The return value is empty if `*this` is empty, |
| /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` |
| /// is returned. |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; |
| template <class F> TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & { |
| using result = detail::invoke_result_t<F, T &>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : result(nullopt); |
| } |
| |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; |
| template <class F> TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && { |
| using result = detail::invoke_result_t<F, T &>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : result(nullopt); |
| } |
| |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; |
| template <class F> constexpr auto and_then(F &&f) const & { |
| using result = detail::invoke_result_t<F, const T &>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : result(nullopt); |
| } |
| |
| #ifndef TL_OPTIONAL_NO_CONSTRR |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; |
| template <class F> constexpr auto and_then(F &&f) const && { |
| using result = detail::invoke_result_t<F, const T &>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), **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>(f), |
| /// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be |
| /// the result of `std::invoke(std::forward<F>(f), value())`. Returns a |
| /// `std::optional<U>`. The return value is empty if `*this` is empty, |
| /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` |
| /// is returned. |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; |
| template <class F> |
| TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T &> and_then(F &&f) & { |
| using result = detail::invoke_result_t<F, T &>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : result(nullopt); |
| } |
| |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; |
| template <class F> |
| TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T &> and_then(F &&f) && { |
| using result = detail::invoke_result_t<F, T &>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : result(nullopt); |
| } |
| |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; |
| template <class F> |
| constexpr detail::invoke_result_t<F, const T &> and_then(F &&f) const & { |
| using result = detail::invoke_result_t<F, const T &>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : result(nullopt); |
| } |
| |
| #ifndef TL_OPTIONAL_NO_CONSTRR |
| /// \group and_then |
| /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; |
| template <class F> |
| constexpr detail::invoke_result_t<F, const T &> and_then(F &&f) const && { |
| using result = detail::invoke_result_t<F, const T &>; |
| static_assert(detail::is_optional<result>::value, |
| "F must return an optional"); |
| |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : result(nullopt); |
| } |
| #endif |
| #endif |
| |
| #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ |
| !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) |
| /// \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>(f), |
| /// value())`. Returns a `std::optional<U>`. The return value is empty if |
| /// `*this` is empty, otherwise an `optional<U>` is constructed from the |
| /// return value of `std::invoke(std::forward<F>(f), value())` and is |
| /// returned. |
| /// |
| /// \group map |
| /// \synopsis template <class F> constexpr auto map(F &&f) &; |
| template <class F> TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & { |
| return detail::optional_map_impl(*this, std::forward<F>(f)); |
| } |
| |
| /// \group map |
| /// \synopsis template <class F> constexpr auto map(F &&f) &&; |
| template <class F> TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && { |
| return detail::optional_map_impl(std::move(*this), std::forward<F>(f)); |
| } |
| |
| /// \group map |
| /// \synopsis template <class F> constexpr auto map(F &&f) const&; |
| template <class F> constexpr auto map(F &&f) const & { |
| return detail::optional_map_impl(*this, std::forward<F>(f)); |
| } |
| |
| /// \group map |
| /// \synopsis template <class F> constexpr auto map(F &&f) const&&; |
| template <class F> constexpr auto map(F &&f) const && { |
| return detail::optional_map_impl(std::move(*this), std::forward<F>(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>(f), |
| /// value())`. Returns a `std::optional<U>`. The return value is empty if |
| /// `*this` is empty, otherwise an `optional<U>` is constructed from the |
| /// return value of `std::invoke(std::forward<F>(f), value())` and is |
| /// returned. |
| /// |
| /// \group map |
| /// \synopsis template <class F> auto map(F &&f) &; |
| template <class F> |
| TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval<optional &>(), |
| std::declval<F &&>())) |
| map(F &&f) & { |
| return detail::optional_map_impl(*this, std::forward<F>(f)); |
| } |
| |
| /// \group map |
| /// \synopsis template <class F> auto map(F &&f) &&; |
| template <class F> |
| TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval<optional &&>(), |
| std::declval<F &&>())) |
| map(F &&f) && { |
| return detail::optional_map_impl(std::move(*this), std::forward<F>(f)); |
| } |
| |
| /// \group map |
| /// \synopsis template <class F> auto map(F &&f) const&; |
| template <class F> |
| constexpr decltype(detail::optional_map_impl(std::declval<const optional &>(), |
| std::declval<F &&>())) |
| map(F &&f) const & { |
| return detail::optional_map_impl(*this, std::forward<F>(f)); |
| } |
| |
| #ifndef TL_OPTIONAL_NO_CONSTRR |
| /// \group map |
| /// \synopsis template <class F> auto map(F &&f) const&&; |
| template <class F> |
| constexpr decltype(detail::optional_map_impl(std::declval<const optional &&>(), |
| std::declval<F &&>())) |
| map(F &&f) const && { |
| return detail::optional_map_impl(std::move(*this), std::forward<F>(f)); |
| } |
| #endif |
| #endif |
| |
| /// \brief Calls `f` if the optional is empty |
| /// \requires `std::invoke_result_t<F>` must be void or convertible to |
| /// `optional<T>`. \effects If `*this` has a value, returns `*this`. |
| /// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns |
| /// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`. |
| /// |
| /// \group or_else |
| /// \synopsis template <class F> optional<T> or_else (F &&f) &; |
| template <class F, detail::enable_if_ret_void<F> * = nullptr> |
| optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { |
| if (has_value()) |
| return *this; |
| |
| std::forward<F>(f)(); |
| return nullopt; |
| } |
| |
| /// \exclude |
| template <class F, detail::disable_if_ret_void<F> * = nullptr> |
| optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { |
| return has_value() ? *this : std::forward<F>(f)(); |
| } |
| |
| /// \group or_else |
| /// \synopsis template <class F> optional<T> or_else (F &&f) &&; |
| template <class F, detail::enable_if_ret_void<F> * = nullptr> |
| optional<T> or_else(F &&f) && { |
| if (has_value()) |
| return std::move(*this); |
| |
| std::forward<F>(f)(); |
| return nullopt; |
| } |
| |
| /// \exclude |
| template <class F, detail::disable_if_ret_void<F> * = nullptr> |
| optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && { |
| return has_value() ? std::move(*this) : std::forward<F>(f)(); |
| } |
| |
| /// \group or_else |
| /// \synopsis template <class F> optional<T> or_else (F &&f) const &; |
| template <class F, detail::enable_if_ret_void<F> * = nullptr> |
| optional<T> or_else(F &&f) const & { |
| if (has_value()) |
| return *this; |
| |
| std::forward<F>(f)(); |
| return nullopt; |
| } |
| |
| /// \exclude |
| template <class F, detail::disable_if_ret_void<F> * = nullptr> |
| optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & { |
| return has_value() ? *this : std::forward<F>(f)(); |
| } |
| |
| #ifndef TL_OPTIONAL_NO_CONSTRR |
| /// \exclude |
| template <class F, detail::enable_if_ret_void<F> * = nullptr> |
| optional<T> or_else(F &&f) const && { |
| if (has_value()) |
| return std::move(*this); |
| |
| std::forward<F>(f)(); |
| return nullopt; |
| } |
| |
| /// \exclude |
| template <class F, detail::disable_if_ret_void<F> * = nullptr> |
| optional<T> or_else(F &&f) const && { |
| return has_value() ? std::move(*this) : std::forward<F>(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 <class F, class U> U map_or(F &&f, U &&u) & { |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : std::forward<U>(u); |
| } |
| |
| /// \group map_or |
| template <class F, class U> U map_or(F &&f, U &&u) && { |
| return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) |
| : std::forward<U>(u); |
| } |
| |
| /// \group map_or |
| template <class F, class U> U map_or(F &&f, U &&u) const & { |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : std::forward<U>(u); |
| } |
| |
| #ifndef TL_OPTIONAL_NO_CONSTRR |
| /// \group map_or |
| template <class F, class U> U map_or(F &&f, U &&u) const && { |
| return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) |
| : std::forward<U>(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>(u)()` is returned. |
| /// |
| /// \group map_or_else |
| /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) &; |
| template <class F, class U> |
| detail::invoke_result_t<U> map_or_else(F &&f, U &&u) & { |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : std::forward<U>(u)(); |
| } |
| |
| /// \group map_or_else |
| /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) |
| /// &&; |
| template <class F, class U> |
| detail::invoke_result_t<U> map_or_else(F &&f, U &&u) && { |
| return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) |
| : std::forward<U>(u)(); |
| } |
| |
| /// \group map_or_else |
| /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) |
| /// const &; |
| template <class F, class U> |
| detail::invoke_result_t<U> map_or_else(F &&f, U &&u) const & { |
| return has_value() ? detail::invoke(std::forward<F>(f), **this) |
| : std::forward<U>(u)(); |
| } |
| |
| #ifndef TL_OPTIONAL_NO_CONSTRR |
| /// \group map_or_else |
| /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) |
| /// const &&; |
| template <class F, class U> |
| detail::invoke_result_t<U> map_or_else(F &&f, U &&u) const && { |
| return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) |
| : std::forward<U>(u)(); |
| } |
| #endif |
| |
| /// \returns `u` if `*this` has a value, otherwise an empty optional. |
| template <class U> |
| constexpr optional<typename std::decay<U>::type> conjunction(U &&u) const { |
| using result = optional<detail::decay_t<U>>; |
| 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 <class U=T> constexpr optional(U &&u); |
| template <class U = T, |
| detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value> |
| * = nullptr> |
| constexpr optional(U &&u) : m_value(std::addressof(u)) { |
| static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue"); |
| } |
| |
| /// \exclude |
| template <class U> |
| constexpr explicit optional(const optional<U> &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. |
| /// |
| /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise |
| /// resets the stored value in `*this`. |
| optional &operator=(const optional &rhs) = default; |
| |
| /// Rebinds this optional to `u`. |
| /// |
| /// \requires `U` must be an lvalue reference. |
| /// \synopsis optional &operator=(U &&u); |
| template <class U = T, |
| detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value> |
| * = nullptr> |
| optional &operator=(U &&u) { |
| static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue"); |
| m_value = std::addressof(u); |
| return *this; |
| } |
| |
| /// Converting copy assignment operator. |
| /// |
| /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise |
| /// resets the stored value in `*this`. |
| template <class U> optional &operator=(const optional<U> &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 <class... Args> T &emplace(Args &&... args) noexcept { |
| static_assert(std::is_constructible<T, Args &&...>::value, |
| "T must be constructible with Args"); |
| |
| *this = nullopt; |
| this->construct(std::forward<Args>(args)...); |
| return value(); |
| } |
| |
| /// 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; } |
| |
| /// \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(); |
| } |
| |
| /// \returns the stored value if there is one, otherwise returns `u` |
| /// \group value_or |
| template <class U> constexpr T value_or(U &&u) const & { |
| static_assert(std::is_copy_constructible<T>::value && |
| std::is_convertible<U &&, T>::value, |
| "T must be copy constructible and convertible from U"); |
| return has_value() ? **this : static_cast<T>(std::forward<U>(u)); |
| } |
| |
| /// \group value_or |
| template <class U> TL_OPTIONAL_11_CONSTEXPR T value_or(U &&u) && { |
| static_assert(std::is_move_constructible<T>::value && |
| std::is_convertible<U &&, T>::value, |
| "T must be move constructible and convertible from U"); |
| return has_value() ? **this : static_cast<T>(std::forward<U>(u)); |
| } |
| |
| /// Destroys the stored value if one exists, making the optional empty |
| void reset() noexcept { m_value = nullptr; } |
| |
| private: |
| T *m_value; |
| }; // namespace tl |
| |
| |
| |
| } // namespace tl |
| |
| namespace std { |
| // TODO SFINAE |
| template <class T> struct hash<tl::optional<T>> { |
| ::std::size_t operator()(const tl::optional<T> &o) const { |
| if (!o.has_value()) |
| return 0; |
| |
| return std::hash<tl::detail::remove_const_t<T>>()(*o); |
| } |
| }; |
| } // namespace std |
| |
| #endif |