| // -*- C++ -*- |
| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| #ifndef _LIBCPP___EXPECTED_EXPECTED_H |
| #define _LIBCPP___EXPECTED_EXPECTED_H |
| |
| #include <__assert> |
| #include <__config> |
| #include <__expected/bad_expected_access.h> |
| #include <__expected/unexpect.h> |
| #include <__expected/unexpected.h> |
| #include <__memory/addressof.h> |
| #include <__memory/construct_at.h> |
| #include <__type_traits/conjunction.h> |
| #include <__type_traits/disjunction.h> |
| #include <__type_traits/is_assignable.h> |
| #include <__type_traits/is_constructible.h> |
| #include <__type_traits/is_convertible.h> |
| #include <__type_traits/is_copy_assignable.h> |
| #include <__type_traits/is_copy_constructible.h> |
| #include <__type_traits/is_default_constructible.h> |
| #include <__type_traits/is_function.h> |
| #include <__type_traits/is_move_assignable.h> |
| #include <__type_traits/is_move_constructible.h> |
| #include <__type_traits/is_nothrow_constructible.h> |
| #include <__type_traits/is_nothrow_copy_assignable.h> |
| #include <__type_traits/is_nothrow_copy_constructible.h> |
| #include <__type_traits/is_nothrow_default_constructible.h> |
| #include <__type_traits/is_nothrow_move_assignable.h> |
| #include <__type_traits/is_nothrow_move_constructible.h> |
| #include <__type_traits/is_reference.h> |
| #include <__type_traits/is_same.h> |
| #include <__type_traits/is_swappable.h> |
| #include <__type_traits/is_trivially_copy_constructible.h> |
| #include <__type_traits/is_trivially_destructible.h> |
| #include <__type_traits/is_trivially_move_constructible.h> |
| #include <__type_traits/is_void.h> |
| #include <__type_traits/lazy.h> |
| #include <__type_traits/negation.h> |
| #include <__type_traits/remove_cv.h> |
| #include <__type_traits/remove_cvref.h> |
| #include <__utility/exception_guard.h> |
| #include <__utility/forward.h> |
| #include <__utility/in_place.h> |
| #include <__utility/move.h> |
| #include <__utility/swap.h> |
| #include <cstdlib> // for std::abort |
| #include <initializer_list> |
| |
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
| # pragma GCC system_header |
| #endif |
| |
| #if _LIBCPP_STD_VER >= 23 |
| |
| _LIBCPP_BEGIN_NAMESPACE_STD |
| |
| namespace __expected { |
| |
| template <class _Err, class _Arg> |
| _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) { |
| # ifndef _LIBCPP_NO_EXCEPTIONS |
| throw bad_expected_access<_Err>(std::forward<_Arg>(__arg)); |
| # else |
| (void)__arg; |
| std::abort(); |
| # endif |
| } |
| |
| } // namespace __expected |
| |
| template <class _Tp, class _Err> |
| class expected { |
| static_assert( |
| !is_reference_v<_Tp> && |
| !is_function_v<_Tp> && |
| !is_same_v<remove_cv_t<_Tp>, in_place_t> && |
| !is_same_v<remove_cv_t<_Tp>, unexpect_t> && |
| !__is_std_unexpected<remove_cv_t<_Tp>>::value && |
| __valid_std_unexpected<_Err>::value |
| , |
| "[expected.object.general] A program that instantiates the definition of template expected<T, E> for a " |
| "reference type, a function type, or for possibly cv-qualified types in_place_t, unexpect_t, or a " |
| "specialization of unexpected for the T parameter is ill-formed. A program that instantiates the " |
| "definition of the template expected<T, E> with a type for the E parameter that is not a valid " |
| "template argument for unexpected is ill-formed."); |
| |
| template <class _Up, class _OtherErr> |
| friend class expected; |
| |
| public: |
| using value_type = _Tp; |
| using error_type = _Err; |
| using unexpected_type = unexpected<_Err>; |
| |
| template <class _Up> |
| using rebind = expected<_Up, error_type>; |
| |
| // [expected.object.ctor], constructors |
| _LIBCPP_HIDE_FROM_ABI constexpr expected() |
| noexcept(is_nothrow_default_constructible_v<_Tp>) // strengthened |
| requires is_default_constructible_v<_Tp> |
| : __has_val_(true) { |
| std::construct_at(std::addressof(__union_.__val_)); |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete; |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) |
| requires(is_copy_constructible_v<_Tp> && |
| is_copy_constructible_v<_Err> && |
| is_trivially_copy_constructible_v<_Tp> && |
| is_trivially_copy_constructible_v<_Err>) |
| = default; |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __other) |
| noexcept(is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_constructible_v<_Err>) // strengthened |
| requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> && |
| !(is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>)) |
| : __has_val_(__other.__has_val_) { |
| if (__has_val_) { |
| std::construct_at(std::addressof(__union_.__val_), __other.__union_.__val_); |
| } else { |
| std::construct_at(std::addressof(__union_.__unex_), __other.__union_.__unex_); |
| } |
| } |
| |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&) |
| requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> |
| && is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>) |
| = default; |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __other) |
| noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_move_constructible_v<_Err>) |
| requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> && |
| !(is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)) |
| : __has_val_(__other.__has_val_) { |
| if (__has_val_) { |
| std::construct_at(std::addressof(__union_.__val_), std::move(__other.__union_.__val_)); |
| } else { |
| std::construct_at(std::addressof(__union_.__unex_), std::move(__other.__union_.__unex_)); |
| } |
| } |
| |
| private: |
| template <class _Up, class _OtherErr, class _UfQual, class _OtherErrQual> |
| using __can_convert = |
| _And< is_constructible<_Tp, _UfQual>, |
| is_constructible<_Err, _OtherErrQual>, |
| _Not<is_constructible<_Tp, expected<_Up, _OtherErr>&>>, |
| _Not<is_constructible<_Tp, expected<_Up, _OtherErr>>>, |
| _Not<is_constructible<_Tp, const expected<_Up, _OtherErr>&>>, |
| _Not<is_constructible<_Tp, const expected<_Up, _OtherErr>>>, |
| _Not<is_convertible<expected<_Up, _OtherErr>&, _Tp>>, |
| _Not<is_convertible<expected<_Up, _OtherErr>&&, _Tp>>, |
| _Not<is_convertible<const expected<_Up, _OtherErr>&, _Tp>>, |
| _Not<is_convertible<const expected<_Up, _OtherErr>&&, _Tp>>, |
| _Not<is_constructible<unexpected<_Err>, expected<_Up, _OtherErr>&>>, |
| _Not<is_constructible<unexpected<_Err>, expected<_Up, _OtherErr>>>, |
| _Not<is_constructible<unexpected<_Err>, const expected<_Up, _OtherErr>&>>, |
| _Not<is_constructible<unexpected<_Err>, const expected<_Up, _OtherErr>>> >; |
| |
| |
| public: |
| template <class _Up, class _OtherErr> |
| requires __can_convert<_Up, _OtherErr, const _Up&, const _OtherErr&>::value |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _Up&, _Tp> || |
| !is_convertible_v<const _OtherErr&, _Err>) |
| expected(const expected<_Up, _OtherErr>& __other) |
| noexcept(is_nothrow_constructible_v<_Tp, const _Up&> && |
| is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened |
| : __has_val_(__other.__has_val_) { |
| if (__has_val_) { |
| std::construct_at(std::addressof(__union_.__val_), __other.__union_.__val_); |
| } else { |
| std::construct_at(std::addressof(__union_.__unex_), __other.__union_.__unex_); |
| } |
| } |
| |
| template <class _Up, class _OtherErr> |
| requires __can_convert<_Up, _OtherErr, _Up, _OtherErr>::value |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp> || !is_convertible_v<_OtherErr, _Err>) |
| expected(expected<_Up, _OtherErr>&& __other) |
| noexcept(is_nothrow_constructible_v<_Tp, _Up> && is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened |
| : __has_val_(__other.__has_val_) { |
| if (__has_val_) { |
| std::construct_at(std::addressof(__union_.__val_), std::move(__other.__union_.__val_)); |
| } else { |
| std::construct_at(std::addressof(__union_.__unex_), std::move(__other.__union_.__unex_)); |
| } |
| } |
| |
| template <class _Up = _Tp> |
| requires(!is_same_v<remove_cvref_t<_Up>, in_place_t> && !is_same_v<expected, remove_cvref_t<_Up>> && |
| !__is_std_unexpected<remove_cvref_t<_Up>>::value && is_constructible_v<_Tp, _Up>) |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp>) |
| expected(_Up&& __u) |
| noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened |
| : __has_val_(true) { |
| std::construct_at(std::addressof(__union_.__val_), std::forward<_Up>(__u)); |
| } |
| |
| |
| template <class _OtherErr> |
| requires is_constructible_v<_Err, const _OtherErr&> |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>) |
| expected(const unexpected<_OtherErr>& __unex) |
| noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened |
| : __has_val_(false) { |
| std::construct_at(std::addressof(__union_.__unex_), __unex.error()); |
| } |
| |
| template <class _OtherErr> |
| requires is_constructible_v<_Err, _OtherErr> |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>) |
| expected(unexpected<_OtherErr>&& __unex) |
| noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened |
| : __has_val_(false) { |
| std::construct_at(std::addressof(__union_.__unex_), std::move(__unex.error())); |
| } |
| |
| template <class... _Args> |
| requires is_constructible_v<_Tp, _Args...> |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, _Args&&... __args) |
| noexcept(is_nothrow_constructible_v<_Tp, _Args...>) // strengthened |
| : __has_val_(true) { |
| std::construct_at(std::addressof(__union_.__val_), std::forward<_Args>(__args)...); |
| } |
| |
| template <class _Up, class... _Args> |
| requires is_constructible_v< _Tp, initializer_list<_Up>&, _Args... > |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit |
| expected(in_place_t, initializer_list<_Up> __il, _Args&&... __args) |
| noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>) // strengthened |
| : __has_val_(true) { |
| std::construct_at(std::addressof(__union_.__val_), __il, std::forward<_Args>(__args)...); |
| } |
| |
| template <class... _Args> |
| requires is_constructible_v<_Err, _Args...> |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args) |
| noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened |
| : __has_val_(false) { |
| std::construct_at(std::addressof(__union_.__unex_), std::forward<_Args>(__args)...); |
| } |
| |
| template <class _Up, class... _Args> |
| requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... > |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit |
| expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args) |
| noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened |
| : __has_val_(false) { |
| std::construct_at(std::addressof(__union_.__unex_), __il, std::forward<_Args>(__args)...); |
| } |
| |
| // [expected.object.dtor], destructor |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr ~expected() |
| requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>) |
| = default; |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr ~expected() |
| requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>) |
| { |
| if (__has_val_) { |
| std::destroy_at(std::addressof(__union_.__val_)); |
| } else { |
| std::destroy_at(std::addressof(__union_.__unex_)); |
| } |
| } |
| |
| private: |
| template <class _T1, class _T2, class... _Args> |
| _LIBCPP_HIDE_FROM_ABI static constexpr void __reinit_expected(_T1& __newval, _T2& __oldval, _Args&&... __args) { |
| if constexpr (is_nothrow_constructible_v<_T1, _Args...>) { |
| std::destroy_at(std::addressof(__oldval)); |
| std::construct_at(std::addressof(__newval), std::forward<_Args>(__args)...); |
| } else if constexpr (is_nothrow_move_constructible_v<_T1>) { |
| _T1 __tmp(std::forward<_Args>(__args)...); |
| std::destroy_at(std::addressof(__oldval)); |
| std::construct_at(std::addressof(__newval), std::move(__tmp)); |
| } else { |
| static_assert( |
| is_nothrow_move_constructible_v<_T2>, |
| "To provide strong exception guarantee, T2 has to satisfy `is_nothrow_move_constructible_v` so that it can " |
| "be reverted to the previous state in case an exception is thrown during the assignment."); |
| _T2 __tmp(std::move(__oldval)); |
| std::destroy_at(std::addressof(__oldval)); |
| __exception_guard __trans([&] { std::construct_at(std::addressof(__oldval), std::move(__tmp)); }); |
| std::construct_at(std::addressof(__newval), std::forward<_Args>(__args)...); |
| __trans.__complete(); |
| } |
| } |
| |
| public: |
| // [expected.object.assign], assignment |
| _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete; |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) |
| noexcept(is_nothrow_copy_assignable_v<_Tp> && |
| is_nothrow_copy_constructible_v<_Tp> && |
| is_nothrow_copy_assignable_v<_Err> && |
| is_nothrow_copy_constructible_v<_Err>) // strengthened |
| requires(is_copy_assignable_v<_Tp> && |
| is_copy_constructible_v<_Tp> && |
| is_copy_assignable_v<_Err> && |
| is_copy_constructible_v<_Err> && |
| (is_nothrow_move_constructible_v<_Tp> || |
| is_nothrow_move_constructible_v<_Err>)) |
| { |
| if (__has_val_ && __rhs.__has_val_) { |
| __union_.__val_ = __rhs.__union_.__val_; |
| } else if (__has_val_) { |
| __reinit_expected(__union_.__unex_, __union_.__val_, __rhs.__union_.__unex_); |
| } else if (__rhs.__has_val_) { |
| __reinit_expected(__union_.__val_, __union_.__unex_, __rhs.__union_.__val_); |
| } else { |
| __union_.__unex_ = __rhs.__union_.__unex_; |
| } |
| // note: only reached if no exception+rollback was done inside __reinit_expected |
| __has_val_ = __rhs.__has_val_; |
| return *this; |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&& __rhs) |
| noexcept(is_nothrow_move_assignable_v<_Tp> && |
| is_nothrow_move_constructible_v<_Tp> && |
| is_nothrow_move_assignable_v<_Err> && |
| is_nothrow_move_constructible_v<_Err>) |
| requires(is_move_constructible_v<_Tp> && |
| is_move_assignable_v<_Tp> && |
| is_move_constructible_v<_Err> && |
| is_move_assignable_v<_Err> && |
| (is_nothrow_move_constructible_v<_Tp> || |
| is_nothrow_move_constructible_v<_Err>)) |
| { |
| if (__has_val_ && __rhs.__has_val_) { |
| __union_.__val_ = std::move(__rhs.__union_.__val_); |
| } else if (__has_val_) { |
| __reinit_expected(__union_.__unex_, __union_.__val_, std::move(__rhs.__union_.__unex_)); |
| } else if (__rhs.__has_val_) { |
| __reinit_expected(__union_.__val_, __union_.__unex_, std::move(__rhs.__union_.__val_)); |
| } else { |
| __union_.__unex_ = std::move(__rhs.__union_.__unex_); |
| } |
| // note: only reached if no exception+rollback was done inside __reinit_expected |
| __has_val_ = __rhs.__has_val_; |
| return *this; |
| } |
| |
| template <class _Up = _Tp> |
| _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(_Up&& __v) |
| requires(!is_same_v<expected, remove_cvref_t<_Up>> && |
| !__is_std_unexpected<remove_cvref_t<_Up>>::value && |
| is_constructible_v<_Tp, _Up> && |
| is_assignable_v<_Tp&, _Up> && |
| (is_nothrow_constructible_v<_Tp, _Up> || |
| is_nothrow_move_constructible_v<_Tp> || |
| is_nothrow_move_constructible_v<_Err>)) |
| { |
| if (__has_val_) { |
| __union_.__val_ = std::forward<_Up>(__v); |
| } else { |
| __reinit_expected(__union_.__val_, __union_.__unex_, std::forward<_Up>(__v)); |
| __has_val_ = true; |
| } |
| return *this; |
| } |
| |
| private: |
| template <class _OtherErrQual> |
| static constexpr bool __can_assign_from_unexpected = |
| _And< is_constructible<_Err, _OtherErrQual>, |
| is_assignable<_Err&, _OtherErrQual>, |
| _Lazy<_Or, |
| is_nothrow_constructible<_Err, _OtherErrQual>, |
| is_nothrow_move_constructible<_Tp>, |
| is_nothrow_move_constructible<_Err>> >::value; |
| |
| public: |
| template <class _OtherErr> |
| requires(__can_assign_from_unexpected<const _OtherErr&>) |
| _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) { |
| if (__has_val_) { |
| __reinit_expected(__union_.__unex_, __union_.__val_, __un.error()); |
| __has_val_ = false; |
| } else { |
| __union_.__unex_ = __un.error(); |
| } |
| return *this; |
| } |
| |
| template <class _OtherErr> |
| requires(__can_assign_from_unexpected<_OtherErr>) |
| _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) { |
| if (__has_val_) { |
| __reinit_expected(__union_.__unex_, __union_.__val_, std::move(__un.error())); |
| __has_val_ = false; |
| } else { |
| __union_.__unex_ = std::move(__un.error()); |
| } |
| return *this; |
| } |
| |
| template <class... _Args> |
| requires is_nothrow_constructible_v<_Tp, _Args...> |
| _LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(_Args&&... __args) noexcept { |
| if (__has_val_) { |
| std::destroy_at(std::addressof(__union_.__val_)); |
| } else { |
| std::destroy_at(std::addressof(__union_.__unex_)); |
| __has_val_ = true; |
| } |
| return *std::construct_at(std::addressof(__union_.__val_), std::forward<_Args>(__args)...); |
| } |
| |
| template <class _Up, class... _Args> |
| requires is_nothrow_constructible_v< _Tp, initializer_list<_Up>&, _Args... > |
| _LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) noexcept { |
| if (__has_val_) { |
| std::destroy_at(std::addressof(__union_.__val_)); |
| } else { |
| std::destroy_at(std::addressof(__union_.__unex_)); |
| __has_val_ = true; |
| } |
| return *std::construct_at(std::addressof(__union_.__val_), __il, std::forward<_Args>(__args)...); |
| } |
| |
| |
| public: |
| // [expected.object.swap], swap |
| _LIBCPP_HIDE_FROM_ABI constexpr void swap(expected& __rhs) |
| noexcept(is_nothrow_move_constructible_v<_Tp> && |
| is_nothrow_swappable_v<_Tp> && |
| is_nothrow_move_constructible_v<_Err> && |
| is_nothrow_swappable_v<_Err>) |
| requires(is_swappable_v<_Tp> && |
| is_swappable_v<_Err> && |
| is_move_constructible_v<_Tp> && |
| is_move_constructible_v<_Err> && |
| (is_nothrow_move_constructible_v<_Tp> || |
| is_nothrow_move_constructible_v<_Err>)) |
| { |
| auto __swap_val_unex_impl = [&](expected& __with_val, expected& __with_err) { |
| if constexpr (is_nothrow_move_constructible_v<_Err>) { |
| _Err __tmp(std::move(__with_err.__union_.__unex_)); |
| std::destroy_at(std::addressof(__with_err.__union_.__unex_)); |
| __exception_guard __trans([&] { |
| std::construct_at(std::addressof(__with_err.__union_.__unex_), std::move(__tmp)); |
| }); |
| std::construct_at(std::addressof(__with_err.__union_.__val_), std::move(__with_val.__union_.__val_)); |
| __trans.__complete(); |
| std::destroy_at(std::addressof(__with_val.__union_.__val_)); |
| std::construct_at(std::addressof(__with_val.__union_.__unex_), std::move(__tmp)); |
| } else { |
| static_assert(is_nothrow_move_constructible_v<_Tp>, |
| "To provide strong exception guarantee, Tp has to satisfy `is_nothrow_move_constructible_v` so " |
| "that it can be reverted to the previous state in case an exception is thrown during swap."); |
| _Tp __tmp(std::move(__with_val.__union_.__val_)); |
| std::destroy_at(std::addressof(__with_val.__union_.__val_)); |
| __exception_guard __trans([&] { |
| std::construct_at(std::addressof(__with_val.__union_.__val_), std::move(__tmp)); |
| }); |
| std::construct_at(std::addressof(__with_val.__union_.__unex_), std::move(__with_err.__union_.__unex_)); |
| __trans.__complete(); |
| std::destroy_at(std::addressof(__with_err.__union_.__unex_)); |
| std::construct_at(std::addressof(__with_err.__union_.__val_), std::move(__tmp)); |
| } |
| __with_val.__has_val_ = false; |
| __with_err.__has_val_ = true; |
| }; |
| |
| if (__has_val_) { |
| if (__rhs.__has_val_) { |
| using std::swap; |
| swap(__union_.__val_, __rhs.__union_.__val_); |
| } else { |
| __swap_val_unex_impl(*this, __rhs); |
| } |
| } else { |
| if (__rhs.__has_val_) { |
| __swap_val_unex_impl(__rhs, *this); |
| } else { |
| using std::swap; |
| swap(__union_.__unex_, __rhs.__union_.__unex_); |
| } |
| } |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(expected& __x, expected& __y) |
| noexcept(noexcept(__x.swap(__y))) |
| requires requires { __x.swap(__y); } |
| { |
| __x.swap(__y); |
| } |
| |
| // [expected.object.obs], observers |
| _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* operator->() const noexcept { |
| _LIBCPP_ASSERT(__has_val_, "expected::operator-> requires the expected to contain a value"); |
| return std::addressof(__union_.__val_); |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr _Tp* operator->() noexcept { |
| _LIBCPP_ASSERT(__has_val_, "expected::operator-> requires the expected to contain a value"); |
| return std::addressof(__union_.__val_); |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept { |
| _LIBCPP_ASSERT(__has_val_, "expected::operator* requires the expected to contain a value"); |
| return __union_.__val_; |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept { |
| _LIBCPP_ASSERT(__has_val_, "expected::operator* requires the expected to contain a value"); |
| return __union_.__val_; |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept { |
| _LIBCPP_ASSERT(__has_val_, "expected::operator* requires the expected to contain a value"); |
| return std::move(__union_.__val_); |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept { |
| _LIBCPP_ASSERT(__has_val_, "expected::operator* requires the expected to contain a value"); |
| return std::move(__union_.__val_); |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __has_val_; } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __has_val_; } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& { |
| if (!__has_val_) { |
| __expected::__throw_bad_expected_access<_Err>(__union_.__unex_); |
| } |
| return __union_.__val_; |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & { |
| if (!__has_val_) { |
| __expected::__throw_bad_expected_access<_Err>(__union_.__unex_); |
| } |
| return __union_.__val_; |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& { |
| if (!__has_val_) { |
| __expected::__throw_bad_expected_access<_Err>(std::move(__union_.__unex_)); |
| } |
| return std::move(__union_.__val_); |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && { |
| if (!__has_val_) { |
| __expected::__throw_bad_expected_access<_Err>(std::move(__union_.__unex_)); |
| } |
| return std::move(__union_.__val_); |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { |
| _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); |
| return __union_.__unex_; |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { |
| _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); |
| return __union_.__unex_; |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { |
| _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); |
| return std::move(__union_.__unex_); |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { |
| _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); |
| return std::move(__union_.__unex_); |
| } |
| |
| template <class _Up> |
| _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& { |
| static_assert(is_copy_constructible_v<_Tp>, "value_type has to be copy constructible"); |
| static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type"); |
| return __has_val_ ? __union_.__val_ : static_cast<_Tp>(std::forward<_Up>(__v)); |
| } |
| |
| template <class _Up> |
| _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && { |
| static_assert(is_move_constructible_v<_Tp>, "value_type has to be move constructible"); |
| static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type"); |
| return __has_val_ ? std::move(__union_.__val_) : static_cast<_Tp>(std::forward<_Up>(__v)); |
| } |
| |
| // [expected.object.eq], equality operators |
| template <class _T2, class _E2> |
| requires(!is_void_v<_T2>) |
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) { |
| if (__x.__has_val_ != __y.__has_val_) { |
| return false; |
| } else { |
| if (__x.__has_val_) { |
| return __x.__union_.__val_ == __y.__union_.__val_; |
| } else { |
| return __x.__union_.__unex_ == __y.__union_.__unex_; |
| } |
| } |
| } |
| |
| template <class _T2> |
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const _T2& __v) { |
| return __x.__has_val_ && static_cast<bool>(__x.__union_.__val_ == __v); |
| } |
| |
| template <class _E2> |
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e) { |
| return !__x.__has_val_ && static_cast<bool>(__x.__union_.__unex_ == __e.error()); |
| } |
| |
| private: |
| struct __empty_t {}; |
| // use named union because [[no_unique_address]] cannot be applied to an unnamed union |
| _LIBCPP_NO_UNIQUE_ADDRESS union __union_t { |
| _LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {} |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() |
| requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>) |
| = default; |
| |
| // the expected's destructor handles this |
| _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() |
| requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>) |
| {} |
| |
| _LIBCPP_NO_UNIQUE_ADDRESS __empty_t __empty_; |
| _LIBCPP_NO_UNIQUE_ADDRESS _Tp __val_; |
| _LIBCPP_NO_UNIQUE_ADDRESS _Err __unex_; |
| } __union_; |
| |
| bool __has_val_; |
| }; |
| |
| template <class _Tp, class _Err> |
| requires is_void_v<_Tp> |
| class expected<_Tp, _Err> { |
| static_assert(__valid_std_unexpected<_Err>::value, |
| "[expected.void.general] A program that instantiates expected<T, E> with a E that is not a " |
| "valid argument for unexpected<E> is ill-formed"); |
| |
| template <class, class> |
| friend class expected; |
| |
| template <class _Up, class _OtherErr, class _OtherErrQual> |
| using __can_convert = |
| _And< is_void<_Up>, |
| is_constructible<_Err, _OtherErrQual>, |
| _Not<is_constructible<unexpected<_Err>, expected<_Up, _OtherErr>&>>, |
| _Not<is_constructible<unexpected<_Err>, expected<_Up, _OtherErr>>>, |
| _Not<is_constructible<unexpected<_Err>, const expected<_Up, _OtherErr>&>>, |
| _Not<is_constructible<unexpected<_Err>, const expected<_Up, _OtherErr>>>>; |
| |
| public: |
| using value_type = _Tp; |
| using error_type = _Err; |
| using unexpected_type = unexpected<_Err>; |
| |
| template <class _Up> |
| using rebind = expected<_Up, error_type>; |
| |
| // [expected.void.ctor], constructors |
| _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept : __has_val_(true) {} |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete; |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) |
| requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>) |
| = default; |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __rhs) |
| noexcept(is_nothrow_copy_constructible_v<_Err>) // strengthened |
| requires(is_copy_constructible_v<_Err> && !is_trivially_copy_constructible_v<_Err>) |
| : __has_val_(__rhs.__has_val_) { |
| if (!__rhs.__has_val_) { |
| std::construct_at(std::addressof(__union_.__unex_), __rhs.__union_.__unex_); |
| } |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&) |
| requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>) |
| = default; |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __rhs) |
| noexcept(is_nothrow_move_constructible_v<_Err>) |
| requires(is_move_constructible_v<_Err> && !is_trivially_move_constructible_v<_Err>) |
| : __has_val_(__rhs.__has_val_) { |
| if (!__rhs.__has_val_) { |
| std::construct_at(std::addressof(__union_.__unex_), std::move(__rhs.__union_.__unex_)); |
| } |
| } |
| |
| template <class _Up, class _OtherErr> |
| requires __can_convert<_Up, _OtherErr, const _OtherErr&>::value |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>) |
| expected(const expected<_Up, _OtherErr>& __rhs) |
| noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened |
| : __has_val_(__rhs.__has_val_) { |
| if (!__rhs.__has_val_) { |
| std::construct_at(std::addressof(__union_.__unex_), __rhs.__union_.__unex_); |
| } |
| } |
| |
| template <class _Up, class _OtherErr> |
| requires __can_convert<_Up, _OtherErr, _OtherErr>::value |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>) |
| expected(expected<_Up, _OtherErr>&& __rhs) |
| noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened |
| : __has_val_(__rhs.__has_val_) { |
| if (!__rhs.__has_val_) { |
| std::construct_at(std::addressof(__union_.__unex_), std::move(__rhs.__union_.__unex_)); |
| } |
| } |
| |
| template <class _OtherErr> |
| requires is_constructible_v<_Err, const _OtherErr&> |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>) |
| expected(const unexpected<_OtherErr>& __unex) |
| noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened |
| : __has_val_(false) { |
| std::construct_at(std::addressof(__union_.__unex_), __unex.error()); |
| } |
| |
| template <class _OtherErr> |
| requires is_constructible_v<_Err, _OtherErr> |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>) |
| expected(unexpected<_OtherErr>&& __unex) |
| noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened |
| : __has_val_(false) { |
| std::construct_at(std::addressof(__union_.__unex_), std::move(__unex.error())); |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __has_val_(true) {} |
| |
| template <class... _Args> |
| requires is_constructible_v<_Err, _Args...> |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args) |
| noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened |
| : __has_val_(false) { |
| std::construct_at(std::addressof(__union_.__unex_), std::forward<_Args>(__args)...); |
| } |
| |
| template <class _Up, class... _Args> |
| requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... > |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args) |
| noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened |
| : __has_val_(false) { |
| std::construct_at(std::addressof(__union_.__unex_), __il, std::forward<_Args>(__args)...); |
| } |
| |
| // [expected.void.dtor], destructor |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr ~expected() |
| requires is_trivially_destructible_v<_Err> |
| = default; |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr ~expected() |
| requires(!is_trivially_destructible_v<_Err>) |
| { |
| if (!__has_val_) { |
| std::destroy_at(std::addressof(__union_.__unex_)); |
| } |
| } |
| |
| // [expected.void.assign], assignment |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete; |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) |
| noexcept(is_nothrow_copy_assignable_v<_Err> && is_nothrow_copy_constructible_v<_Err>) // strengthened |
| requires(is_copy_assignable_v<_Err> && is_copy_constructible_v<_Err>) |
| { |
| if (__has_val_) { |
| if (!__rhs.__has_val_) { |
| std::construct_at(std::addressof(__union_.__unex_), __rhs.__union_.__unex_); |
| __has_val_ = false; |
| } |
| } else { |
| if (__rhs.__has_val_) { |
| std::destroy_at(std::addressof(__union_.__unex_)); |
| __has_val_ = true; |
| } else { |
| __union_.__unex_ = __rhs.__union_.__unex_; |
| } |
| } |
| return *this; |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&&) = delete; |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&& __rhs) |
| noexcept(is_nothrow_move_assignable_v<_Err> && |
| is_nothrow_move_constructible_v<_Err>) |
| requires(is_move_assignable_v<_Err> && |
| is_move_constructible_v<_Err>) |
| { |
| if (__has_val_) { |
| if (!__rhs.__has_val_) { |
| std::construct_at(std::addressof(__union_.__unex_), std::move(__rhs.__union_.__unex_)); |
| __has_val_ = false; |
| } |
| } else { |
| if (__rhs.__has_val_) { |
| std::destroy_at(std::addressof(__union_.__unex_)); |
| __has_val_ = true; |
| } else { |
| __union_.__unex_ = std::move(__rhs.__union_.__unex_); |
| } |
| } |
| return *this; |
| } |
| |
| template <class _OtherErr> |
| requires(is_constructible_v<_Err, const _OtherErr&> && is_assignable_v<_Err&, const _OtherErr&>) |
| _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) { |
| if (__has_val_) { |
| std::construct_at(std::addressof(__union_.__unex_), __un.error()); |
| __has_val_ = false; |
| } else { |
| __union_.__unex_ = __un.error(); |
| } |
| return *this; |
| } |
| |
| template <class _OtherErr> |
| requires(is_constructible_v<_Err, _OtherErr> && is_assignable_v<_Err&, _OtherErr>) |
| _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) { |
| if (__has_val_) { |
| std::construct_at(std::addressof(__union_.__unex_), std::move(__un.error())); |
| __has_val_ = false; |
| } else { |
| __union_.__unex_ = std::move(__un.error()); |
| } |
| return *this; |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr void emplace() noexcept { |
| if (!__has_val_) { |
| std::destroy_at(std::addressof(__union_.__unex_)); |
| __has_val_ = true; |
| } |
| } |
| |
| // [expected.void.swap], swap |
| _LIBCPP_HIDE_FROM_ABI constexpr void swap(expected& __rhs) |
| noexcept(is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>) |
| requires(is_swappable_v<_Err> && is_move_constructible_v<_Err>) |
| { |
| auto __swap_val_unex_impl = [&](expected& __with_val, expected& __with_err) { |
| std::construct_at(std::addressof(__with_val.__union_.__unex_), std::move(__with_err.__union_.__unex_)); |
| std::destroy_at(std::addressof(__with_err.__union_.__unex_)); |
| __with_val.__has_val_ = false; |
| __with_err.__has_val_ = true; |
| }; |
| |
| if (__has_val_) { |
| if (!__rhs.__has_val_) { |
| __swap_val_unex_impl(*this, __rhs); |
| } |
| } else { |
| if (__rhs.__has_val_) { |
| __swap_val_unex_impl(__rhs, *this); |
| } else { |
| using std::swap; |
| swap(__union_.__unex_, __rhs.__union_.__unex_); |
| } |
| } |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(expected& __x, expected& __y) |
| noexcept(noexcept(__x.swap(__y))) |
| requires requires { __x.swap(__y); } |
| { |
| __x.swap(__y); |
| } |
| |
| // [expected.void.obs], observers |
| _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __has_val_; } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __has_val_; } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr void operator*() const noexcept { |
| _LIBCPP_ASSERT(__has_val_, "expected::operator* requires the expected to contain a value"); |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr void value() const& { |
| if (!__has_val_) { |
| __expected::__throw_bad_expected_access<_Err>(__union_.__unex_); |
| } |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr void value() && { |
| if (!__has_val_) { |
| __expected::__throw_bad_expected_access<_Err>(std::move(__union_.__unex_)); |
| } |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { |
| _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); |
| return __union_.__unex_; |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { |
| _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); |
| return __union_.__unex_; |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { |
| _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); |
| return std::move(__union_.__unex_); |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { |
| _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); |
| return std::move(__union_.__unex_); |
| } |
| |
| // [expected.void.eq], equality operators |
| template <class _T2, class _E2> |
| requires is_void_v<_T2> |
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) { |
| if (__x.__has_val_ != __y.__has_val_) { |
| return false; |
| } else { |
| return __x.__has_val_ || static_cast<bool>(__x.__union_.__unex_ == __y.__union_.__unex_); |
| } |
| } |
| |
| template <class _E2> |
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __y) { |
| return !__x.__has_val_ && static_cast<bool>(__x.__union_.__unex_ == __y.error()); |
| } |
| |
| private: |
| struct __empty_t {}; |
| // use named union because [[no_unique_address]] cannot be applied to an unnamed union |
| _LIBCPP_NO_UNIQUE_ADDRESS union __union_t { |
| _LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {} |
| |
| _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() |
| requires(is_trivially_destructible_v<_Err>) |
| = default; |
| |
| // the expected's destructor handles this |
| _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() |
| requires(!is_trivially_destructible_v<_Err>) |
| {} |
| |
| _LIBCPP_NO_UNIQUE_ADDRESS __empty_t __empty_; |
| _LIBCPP_NO_UNIQUE_ADDRESS _Err __unex_; |
| } __union_; |
| |
| bool __has_val_; |
| }; |
| |
| _LIBCPP_END_NAMESPACE_STD |
| |
| #endif // _LIBCPP_STD_VER >= 23 |
| |
| #endif // _LIBCPP___EXPECTED_EXPECTED_H |