// <expected> -*- C++ -*-

// Copyright The GNU Toolchain Authors.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file include/expected
 *  This is a Standard C++ Library header.
 */

#ifndef _GLIBCXX_EXPECTED
#define _GLIBCXX_EXPECTED

#pragma GCC system_header

#define __glibcxx_want_expected
#define __glibcxx_want_freestanding_expected
#include <bits/version.h>

#ifdef __cpp_lib_expected // C++ >= 23 && __cpp_concepts >= 202002L
#include <initializer_list>
#include <bits/exception.h>	// exception
#include <bits/invoke.h>	// __invoke
#include <bits/stl_construct.h>	// construct_at
#include <bits/utility.h>	// in_place_t

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

  /**
   * @defgroup expected_values Expected values
   * @addtogroup utilities
   * @since C++23
   * @{
   */

  /// Discriminated union that holds an expected value or an error value.
  /**
   * @since C++23
   */
  template<typename _Tp, typename _Er>
    class expected;

  /// Wrapper type used to pass an error value to a `std::expected`.
  /**
   * @since C++23
   */
  template<typename _Er>
    class unexpected;

  /// Exception thrown by std::expected when the value() is not present.
  /**
   * @since C++23
   */
  template<typename _Er>
    class bad_expected_access;

  template<>
    class bad_expected_access<void> : public exception
    {
    protected:
      bad_expected_access() noexcept { }
      bad_expected_access(const bad_expected_access&) = default;
      bad_expected_access(bad_expected_access&&) = default;
      bad_expected_access& operator=(const bad_expected_access&) = default;
      bad_expected_access& operator=(bad_expected_access&&) = default;
      ~bad_expected_access() = default;

    public:

      [[nodiscard]]
      const char*
      what() const noexcept override
      { return "bad access to std::expected without expected value"; }
    };

  template<typename _Er>
    class bad_expected_access : public bad_expected_access<void> {
    public:
      explicit
      bad_expected_access(_Er __e) : _M_unex(std::move(__e)) { }

      // XXX const char* what() const noexcept override;

      [[nodiscard]]
      _Er&
      error() & noexcept
      { return _M_unex; }

      [[nodiscard]]
      const _Er&
      error() const & noexcept
      { return _M_unex; }

      [[nodiscard]]
      _Er&&
      error() && noexcept
      { return std::move(_M_unex); }

      [[nodiscard]]
      const _Er&&
      error() const && noexcept
      { return std::move(_M_unex); }

    private:
      _Er _M_unex;
    };

  /// Tag type for constructing unexpected values in a std::expected
  /**
   * @since C++23
   */
  struct unexpect_t
  {
    explicit unexpect_t() = default;
  };

  /// Tag for constructing unexpected values in a std::expected
  /**
   * @since C++23
   */
  inline constexpr unexpect_t unexpect{};

/// @cond undocumented
namespace __expected
{
  template<typename _Tp>
    constexpr bool __is_expected = false;
  template<typename _Tp, typename _Er>
    constexpr bool __is_expected<expected<_Tp, _Er>> = true;

  template<typename _Tp>
    constexpr bool __is_unexpected = false;
  template<typename _Tp>
    constexpr bool __is_unexpected<unexpected<_Tp>> = true;

  template<typename _Fn, typename _Tp>
    using __result = remove_cvref_t<invoke_result_t<_Fn&&, _Tp&&>>;
  template<typename _Fn, typename _Tp>
    using __result_xform = remove_cv_t<invoke_result_t<_Fn&&, _Tp&&>>;
  template<typename _Fn>
    using __result0 = remove_cvref_t<invoke_result_t<_Fn&&>>;
  template<typename _Fn>
    using __result0_xform = remove_cv_t<invoke_result_t<_Fn&&>>;

  template<typename _Er>
    concept __can_be_unexpected
      = is_object_v<_Er> && (!is_array_v<_Er>)
	  && (!__expected::__is_unexpected<_Er>)
	  && (!is_const_v<_Er>) && (!is_volatile_v<_Er>);

  // Tag types for in-place construction from an invocation result.
  struct __in_place_inv { };
  struct __unexpect_inv { };
}
/// @endcond

  template<typename _Er>
    class unexpected
    {
      static_assert( __expected::__can_be_unexpected<_Er> );

    public:
      constexpr unexpected(const unexpected&) = default;
      constexpr unexpected(unexpected&&) = default;

      template<typename _Err = _Er>
	requires (!is_same_v<remove_cvref_t<_Err>, unexpected>)
	  && (!is_same_v<remove_cvref_t<_Err>, in_place_t>)
	  && is_constructible_v<_Er, _Err>
	constexpr explicit
	unexpected(_Err&& __e)
	noexcept(is_nothrow_constructible_v<_Er, _Err>)
	: _M_unex(std::forward<_Err>(__e))
	{ }

      template<typename... _Args>
	requires is_constructible_v<_Er, _Args...>
	constexpr explicit
	unexpected(in_place_t, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Er, _Args...>)
	: _M_unex(std::forward<_Args>(__args)...)
	{ }

      template<typename _Up, typename... _Args>
	requires is_constructible_v<_Er, initializer_list<_Up>&, _Args...>
	constexpr explicit
	unexpected(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Er, initializer_list<_Up>&,
					    _Args...>)
	: _M_unex(__il, std::forward<_Args>(__args)...)
	{ }

      constexpr unexpected& operator=(const unexpected&) = default;
      constexpr unexpected& operator=(unexpected&&) = default;


      [[nodiscard]]
      constexpr const _Er&
      error() const & noexcept { return _M_unex; }

      [[nodiscard]]
      constexpr _Er&
      error() & noexcept { return _M_unex; }

      [[nodiscard]]
      constexpr const _Er&&
      error() const && noexcept { return std::move(_M_unex); }

      [[nodiscard]]
      constexpr _Er&&
      error() && noexcept { return std::move(_M_unex); }

      constexpr void
      swap(unexpected& __other) noexcept(is_nothrow_swappable_v<_Er>)
      requires is_swappable_v<_Er>
      {
	using std::swap;
	swap(_M_unex, __other._M_unex);
      }

      template<typename _Err>
	[[nodiscard]]
	friend constexpr bool
	operator==(const unexpected& __x, const unexpected<_Err>& __y)
	{ return __x._M_unex == __y.error(); }

      friend constexpr void
      swap(unexpected& __x, unexpected& __y) noexcept(noexcept(__x.swap(__y)))
      requires is_swappable_v<_Er>
      { __x.swap(__y); }

    private:
      _Er _M_unex;
    };

  template<typename _Er> unexpected(_Er) -> unexpected<_Er>;

/// @cond undocumented
namespace __expected
{
  template<typename _Tp>
    struct _Guard
    {
      static_assert( is_nothrow_move_constructible_v<_Tp> );

      constexpr explicit
      _Guard(_Tp& __x)
      : _M_guarded(__builtin_addressof(__x)), _M_tmp(std::move(__x)) // nothrow
      { std::destroy_at(_M_guarded); }

      constexpr
      ~_Guard()
      {
	if (_M_guarded) [[unlikely]]
	  std::construct_at(_M_guarded, std::move(_M_tmp));
      }

      _Guard(const _Guard&) = delete;
      _Guard& operator=(const _Guard&) = delete;

      constexpr _Tp&&
      release() noexcept
      {
	_M_guarded = nullptr;
	return std::move(_M_tmp);
      }

    private:
      _Tp* _M_guarded;
      _Tp _M_tmp;
    };

  // reinit-expected helper from [expected.object.assign]
  template<typename _Tp, typename _Up, typename _Vp>
    constexpr void
    __reinit(_Tp* __newval, _Up* __oldval, _Vp&& __arg)
    noexcept(is_nothrow_constructible_v<_Tp, _Vp>)
    {
      if constexpr (is_nothrow_constructible_v<_Tp, _Vp>)
	{
	  std::destroy_at(__oldval);
	  std::construct_at(__newval, std::forward<_Vp>(__arg));
	}
      else if constexpr (is_nothrow_move_constructible_v<_Tp>)
	{
	  _Tp __tmp(std::forward<_Vp>(__arg)); // might throw
	  std::destroy_at(__oldval);
	  std::construct_at(__newval, std::move(__tmp));
	}
      else
	{
	  _Guard<_Up> __guard(*__oldval);
	  std::construct_at(__newval, std::forward<_Vp>(__arg)); // might throw
	  __guard.release();
	}
    }

  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 3836. std::expected<bool, E1> conversion constructor
  // expected(const expected<U, G>&) should take precedence over
  // expected(U&&) with operator bool

  // If T is cv bool, remove_cvref_t<U> is not a specialization of expected.
  template<typename _Tp, typename _Up>
    concept __not_constructing_bool_from_expected
      = ! is_same_v<remove_cv_t<_Tp>, bool>
	  || ! __is_expected<remove_cvref_t<_Up>>;
}
/// @endcond

  template<typename _Tp, typename _Er>
    class expected
    {
      static_assert( ! is_reference_v<_Tp> );
      static_assert( ! is_function_v<_Tp> );
      static_assert( ! is_same_v<remove_cv_t<_Tp>, in_place_t> );
      static_assert( ! is_same_v<remove_cv_t<_Tp>, unexpect_t> );
      static_assert( ! __expected::__is_unexpected<remove_cv_t<_Tp>> );
      static_assert( __expected::__can_be_unexpected<_Er> );

      // If T is not cv bool, converts-from-any-cvref<T, expected<U, G>> and
      // is_constructible<unexpected<E>, cv expected<U, G> ref-qual> are false.
      template<typename _Up, typename _Gr, typename _Unex = unexpected<_Er>,
	       typename = remove_cv_t<_Tp>>
	static constexpr bool __cons_from_expected
	  = __or_v<is_constructible<_Tp, expected<_Up, _Gr>&>,
		   is_constructible<_Tp, expected<_Up, _Gr>>,
		   is_constructible<_Tp, const expected<_Up, _Gr>&>,
		   is_constructible<_Tp, const expected<_Up, _Gr>>,
		   is_convertible<expected<_Up, _Gr>&, _Tp>,
		   is_convertible<expected<_Up, _Gr>, _Tp>,
		   is_convertible<const expected<_Up, _Gr>&, _Tp>,
		   is_convertible<const expected<_Up, _Gr>, _Tp>,
		   is_constructible<_Unex, expected<_Up, _Gr>&>,
		   is_constructible<_Unex, expected<_Up, _Gr>>,
		   is_constructible<_Unex, const expected<_Up, _Gr>&>,
		   is_constructible<_Unex, const expected<_Up, _Gr>>
		  >;

      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // If t is cv bool, we know it can be constructed from expected<U, G>,
      // but we don't want to cause the expected(U&&) constructor to be used,
      // so we only check the is_constructible<unexpected<E>, ...> cases.
      template<typename _Up, typename _Gr, typename _Unex>
	static constexpr bool __cons_from_expected<_Up, _Gr, _Unex, bool>
	  = __or_v<is_constructible<_Unex, expected<_Up, _Gr>&>,
		   is_constructible<_Unex, expected<_Up, _Gr>>,
		   is_constructible<_Unex, const expected<_Up, _Gr>&>,
		   is_constructible<_Unex, const expected<_Up, _Gr>>
		  >;

      template<typename _Up, typename _Gr>
	constexpr static bool __explicit_conv
	  = __or_v<__not_<is_convertible<_Up, _Tp>>,
		   __not_<is_convertible<_Gr, _Er>>
		  >;

      template<typename _Up>
	static constexpr bool __same_val
	  = is_same_v<typename _Up::value_type, _Tp>;

      template<typename _Up>
	static constexpr bool __same_err
	  = is_same_v<typename _Up::error_type, _Er>;

    public:
      using value_type = _Tp;
      using error_type = _Er;
      using unexpected_type = unexpected<_Er>;

      template<typename _Up>
	using rebind = expected<_Up, error_type>;

      constexpr
      expected()
      noexcept(is_nothrow_default_constructible_v<_Tp>)
      requires is_default_constructible_v<_Tp>
      : _M_val(), _M_has_value(true)
      { }

      expected(const expected&) = default;

      constexpr
      expected(const expected& __x)
      noexcept(__and_v<is_nothrow_copy_constructible<_Tp>,
		       is_nothrow_copy_constructible<_Er>>)
      requires is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Er>
      && (!is_trivially_copy_constructible_v<_Tp>
	  || !is_trivially_copy_constructible_v<_Er>)
      : _M_has_value(__x._M_has_value)
      {
	if (_M_has_value)
	  std::construct_at(__builtin_addressof(_M_val), __x._M_val);
	else
	  std::construct_at(__builtin_addressof(_M_unex), __x._M_unex);
      }

      expected(expected&&) = default;

      constexpr
      expected(expected&& __x)
      noexcept(__and_v<is_nothrow_move_constructible<_Tp>,
		       is_nothrow_move_constructible<_Er>>)
      requires is_move_constructible_v<_Tp> && is_move_constructible_v<_Er>
      && (!is_trivially_move_constructible_v<_Tp>
	  || !is_trivially_move_constructible_v<_Er>)
      : _M_has_value(__x._M_has_value)
      {
	if (_M_has_value)
	  std::construct_at(__builtin_addressof(_M_val),
			    std::move(__x)._M_val);
	else
	  std::construct_at(__builtin_addressof(_M_unex),
			    std::move(__x)._M_unex);
      }

      template<typename _Up, typename _Gr>
	requires is_constructible_v<_Tp, const _Up&>
	      && is_constructible_v<_Er, const _Gr&>
	      && (!__cons_from_expected<_Up, _Gr>)
	constexpr explicit(__explicit_conv<const _Up&, const _Gr&>)
	expected(const expected<_Up, _Gr>& __x)
	noexcept(__and_v<is_nothrow_constructible<_Tp, const _Up&>,
			 is_nothrow_constructible<_Er, const _Gr&>>)
	: _M_has_value(__x._M_has_value)
	{
	  if (_M_has_value)
	    std::construct_at(__builtin_addressof(_M_val), __x._M_val);
	  else
	    std::construct_at(__builtin_addressof(_M_unex), __x._M_unex);
	}

      template<typename _Up, typename _Gr>
	requires is_constructible_v<_Tp, _Up>
	      && is_constructible_v<_Er, _Gr>
	      && (!__cons_from_expected<_Up, _Gr>)
	constexpr explicit(__explicit_conv<_Up, _Gr>)
	expected(expected<_Up, _Gr>&& __x)
	noexcept(__and_v<is_nothrow_constructible<_Tp, _Up>,
			 is_nothrow_constructible<_Er, _Gr>>)
	: _M_has_value(__x._M_has_value)
	{
	  if (_M_has_value)
	    std::construct_at(__builtin_addressof(_M_val),
			      std::move(__x)._M_val);
	  else
	    std::construct_at(__builtin_addressof(_M_unex),
			      std::move(__x)._M_unex);
	}

      template<typename _Up = _Tp>
	requires (!is_same_v<remove_cvref_t<_Up>, expected>)
	  && (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
	  && (!is_same_v<remove_cvref_t<_Up>, unexpect_t>)
	  && is_constructible_v<_Tp, _Up>
	  && (!__expected::__is_unexpected<remove_cvref_t<_Up>>)
	  && __expected::__not_constructing_bool_from_expected<_Tp, _Up>
	constexpr explicit(!is_convertible_v<_Up, _Tp>)
	expected(_Up&& __v)
	noexcept(is_nothrow_constructible_v<_Tp, _Up>)
	: _M_val(std::forward<_Up>(__v)), _M_has_value(true)
	{ }

      template<typename _Gr = _Er>
	requires is_constructible_v<_Er, const _Gr&>
	constexpr explicit(!is_convertible_v<const _Gr&, _Er>)
	expected(const unexpected<_Gr>& __u)
	noexcept(is_nothrow_constructible_v<_Er, const _Gr&>)
	: _M_unex(__u.error()), _M_has_value(false)
	{ }

      template<typename _Gr = _Er>
	requires is_constructible_v<_Er, _Gr>
	constexpr explicit(!is_convertible_v<_Gr, _Er>)
	expected(unexpected<_Gr>&& __u)
	noexcept(is_nothrow_constructible_v<_Er, _Gr>)
	: _M_unex(std::move(__u).error()), _M_has_value(false)
	{ }

      template<typename... _Args>
	requires is_constructible_v<_Tp, _Args...>
	constexpr explicit
	expected(in_place_t, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
	: _M_val(std::forward<_Args>(__args)...), _M_has_value(true)
	{ }

      template<typename _Up, typename... _Args>
	requires is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
	constexpr explicit
	expected(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&,
					    _Args...>)
	: _M_val(__il, std::forward<_Args>(__args)...), _M_has_value(true)
	{ }

      template<typename... _Args>
	requires is_constructible_v<_Er, _Args...>
	constexpr explicit
	expected(unexpect_t, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Er, _Args...>)
	: _M_unex(std::forward<_Args>(__args)...), _M_has_value(false)
	{ }

      template<typename _Up, typename... _Args>
	requires is_constructible_v<_Er, initializer_list<_Up>&, _Args...>
	cons                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   