// -*- 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_OPTIONAL
#define _LIBCPP_OPTIONAL

/*
    optional synopsis

// C++1z

namespace std {
  // [optional.optional], class template optional
  template <class T>
    class optional;

  template<class T>
    concept is-derived-from-optional = requires(const T& t) {       // exposition only
      []<class U>(const optional<U>&){ }(t);
    };

  // [optional.nullopt], no-value state indicator
  struct nullopt_t{see below };
  inline constexpr nullopt_t nullopt(unspecified );

  // [optional.bad.access], class bad_optional_access
  class bad_optional_access;

  // [optional.relops], relational operators
  template <class T, class U>
    constexpr bool operator==(const optional<T>&, const optional<U>&);
  template <class T, class U>
    constexpr bool operator!=(const optional<T>&, const optional<U>&);
  template <class T, class U>
    constexpr bool operator<(const optional<T>&, const optional<U>&);
  template <class T, class U>
    constexpr bool operator>(const optional<T>&, const optional<U>&);
  template <class T, class U>
    constexpr bool operator<=(const optional<T>&, const optional<U>&);
  template <class T, class U>
    constexpr bool operator>=(const optional<T>&, const optional<U>&);
  template<class T, three_way_comparable_with<T> U>
    constexpr compare_three_way_result_t<T, U>
      operator<=>(const optional<T>&, const optional<U>&); // since C++20

  // [optional.nullops], comparison with nullopt
  template<class T> constexpr bool operator==(const optional<T>&, nullopt_t) noexcept;
  template<class T> constexpr bool operator==(nullopt_t, const optional<T>&) noexcept; // until C++17
  template<class T> constexpr bool operator!=(const optional<T>&, nullopt_t) noexcept; // until C++17
  template<class T> constexpr bool operator!=(nullopt_t, const optional<T>&) noexcept; // until C++17
  template<class T> constexpr bool operator<(const optional<T>&, nullopt_t) noexcept;  // until C++17
  template<class T> constexpr bool operator<(nullopt_t, const optional<T>&) noexcept;  // until C++17
  template<class T> constexpr bool operator<=(const optional<T>&, nullopt_t) noexcept; // until C++17
  template<class T> constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept; // until C++17
  template<class T> constexpr bool operator>(const optional<T>&, nullopt_t) noexcept;  // until C++17
  template<class T> constexpr bool operator>(nullopt_t, const optional<T>&) noexcept;  // until C++17
  template<class T> constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept; // until C++17
  template<class T> constexpr bool operator>=(nullopt_t, const optional<T>&) noexcept; // until C++17
  template<class T>
    constexpr strong_ordering operator<=>(const optional<T>&, nullopt_t) noexcept;     // since C++20

  // [optional.comp.with.t], comparison with T
  template<class T, class U> constexpr bool operator==(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator==(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator!=(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator!=(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator<(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator<(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator<=(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator<=(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator>(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator>(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator>=(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator>=(const T&, const optional<U>&);
  template<class T, class U>
      requires (!is-derived-from-optional<U>) && three_way_comparable_with<T, U>
    constexpr compare_three_way_result_t<T, U>
      operator<=>(const optional<T>&, const U&);                                       // since C++20

  // [optional.specalg], specialized algorithms
  template<class T>
    void swap(optional<T>&, optional<T>&) noexcept(see below ); // constexpr in C++20

  template<class T>
    constexpr optional<see below > make_optional(T&&);
  template<class T, class... Args>
    constexpr optional<T> make_optional(Args&&... args);
  template<class T, class U, class... Args>
    constexpr optional<T> make_optional(initializer_list<U> il, Args&&... args);

  // [optional.hash], hash support
  template<class T> struct hash;
  template<class T> struct hash<optional<T>>;

  template<class T>
  class optional {
  public:
    using value_type = T;

    // [optional.ctor], constructors
    constexpr optional() noexcept;
    constexpr optional(nullopt_t) noexcept;
    constexpr optional(const optional &);
    constexpr optional(optional &&) noexcept(see below);
    template<class... Args>
      constexpr explicit optional(in_place_t, Args &&...);
    template<class U, class... Args>
      constexpr explicit optional(in_place_t, initializer_list<U>, Args &&...);
    template<class U = T>
      constexpr explicit(see-below) optional(U &&);
    template<class U>
      explicit(see-below) optional(const optional<U> &);                          // constexpr in C++20
    template<class U>
      explicit(see-below) optional(optional<U> &&);                               // constexpr in C++20

    // [optional.dtor], destructor
    ~optional(); // constexpr in C++20

    // [optional.assign], assignment
    optional &operator=(nullopt_t) noexcept;                                      // constexpr in C++20
    constexpr optional &operator=(const optional &);
    constexpr optional &operator=(optional &&) noexcept(see below);
    template<class U = T> optional &operator=(U &&);                              // constexpr in C++20
    template<class U> optional &operator=(const optional<U> &);                   // constexpr in C++20
    template<class U> optional &operator=(optional<U> &&);                        // constexpr in C++20
    template<class... Args> T& emplace(Args &&...);                               // constexpr in C++20
    template<class U, class... Args> T& emplace(initializer_list<U>, Args &&...); // constexpr in C++20

    // [optional.swap], swap
    void swap(optional &) noexcept(see below ); // constexpr in C++20

    // [optional.observe], observers
    constexpr T const *operator->() const noexcept;
    constexpr T *operator->() noexcept;
    constexpr T const &operator*() const & noexcept;
    constexpr T &operator*() & noexcept;
    constexpr T &&operator*() && noexcept;
    constexpr const T &&operator*() const && noexcept;
    constexpr explicit operator bool() const noexcept;
    constexpr bool has_value() const noexcept;
    constexpr T const &value() const &;
    constexpr T &value() &;
    constexpr T &&value() &&;
    constexpr const T &&value() const &&;
    template<class U> constexpr T value_or(U &&) const &;
    template<class U> constexpr T value_or(U &&) &&;

    // [optional.monadic], monadic operations
    template<class F> constexpr auto and_then(F&& f) &;         // since C++23
    template<class F> constexpr auto and_then(F&& f) &&;        // since C++23
    template<class F> constexpr auto and_then(F&& f) const&;    // since C++23
    template<class F> constexpr auto and_then(F&& f) const&&;   // since C++23
    template<class F> constexpr auto transform(F&& f) &;        // since C++23
    template<class F> constexpr auto transform(F&& f) &&;       // since C++23
    template<class F> constexpr auto transform(F&& f) const&;   // since C++23
    template<class F> constexpr auto transform(F&& f) const&&;  // since C++23
    template<class F> constexpr optional or_else(F&& f) &&;     // since C++23
    template<class F> constexpr optional or_else(F&& f) const&; // since C++23

    // [optional.mod], modifiers
    void reset() noexcept;                                      // constexpr in C++20

  private:
    T *val;         // exposition only
  };

  template<class T>
    optional(T) -> optional<T>;

} // namespace std

*/

#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
#  include <__cxx03/__config>
#else
#  include <__assert>
#  include <__compare/compare_three_way_result.h>
#  include <__compare/ordering.h>
#  include <__compare/three_way_comparable.h>
#  include <__concepts/invocable.h>
#  include <__config>
#  include <__exception/exception.h>
#  include <__functional/hash.h>
#  include <__functional/invoke.h>
#  include <__functional/unary_function.h>
#  include <__fwd/functional.h>
#  include <__memory/addressof.h>
#  include <__memory/construct_at.h>
#  include <__tuple/sfinae_helpers.h>
#  include <__type_traits/add_pointer.h>
#  include <__type_traits/conditional.h>
#  include <__type_traits/conjunction.h>
#  include <__type_traits/decay.h>
#  include <__type_traits/disjunction.h>
#  include <__type_traits/enable_if.h>
#  include <__type_traits/invoke.h>
#  include <__type_traits/is_array.h>
#  include <__type_traits/is_assignable.h>
#  include <__type_traits/is_constructible.h>
#  include <__type_traits/is_convertible.h>
#  include <__type_traits/is_core_convertible.h>
#  include <__type_traits/is_destructible.h>
#  include <__type_traits/is_nothrow_assignable.h>
#  include <__type_traits/is_nothrow_constructible.h>
#  include <__type_traits/is_object.h>
#  include <__type_traits/is_reference.h>
#  include <__type_traits/is_replaceable.h>
#  include <__type_traits/is_same.h>
#  include <__type_traits/is_scalar.h>
#  include <__type_traits/is_swappable.h>
#  include <__type_traits/is_trivially_assignable.h>
#  include <__type_traits/is_trivially_constructible.h>
#  include <__type_traits/is_trivially_destructible.h>
#  include <__type_traits/is_trivially_relocatable.h>
#  include <__type_traits/negation.h>
#  include <__type_traits/remove_const.h>
#  include <__type_traits/remove_cv.h>
#  include <__type_traits/remove_cvref.h>
#  include <__type_traits/remove_reference.h>
#  include <__utility/declval.h>
#  include <__utility/forward.h>
#  include <__utility/in_place.h>
#  include <__utility/move.h>
#  include <__utility/swap.h>
#  include <__verbose_abort>
#  include <initializer_list>
#  include <version>

// standard-mandated includes

// [optional.syn]
#  include <compare>

#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#    pragma GCC system_header
#  endif

_LIBCPP_PUSH_MACROS
#  include <__undef_macros>

namespace std // purposefully not using versioning namespace
{

class _LIBCPP_EXPORTED_FROM_ABI bad_optional_access : public exception {
public:
  _LIBCPP_HIDE_FROM_ABI bad_optional_access() _NOEXCEPT                                      = default;
  _LIBCPP_HIDE_FROM_ABI bad_optional_access(const bad_optional_access&) _NOEXCEPT            = default;
  _LIBCPP_HIDE_FROM_ABI bad_optional_access& operator=(const bad_optional_access&) _NOEXCEPT = default;
  // Get the key function ~bad_optional_access() into the dylib
  ~bad_optional_access() _NOEXCEPT override;
  const char* what() const _NOEXCEPT override;
};

} // namespace std

#  if _LIBCPP_STD_VER >= 17

_LIBCPP_BEGIN_NAMESPACE_STD

[[noreturn]] inline _LIBCPP_HIDE_FROM_ABI void __throw_bad_optional_access() {
#    if _LIBCPP_HAS_EXCEPTIONS
  throw bad_optional_access();
#    else
  _LIBCPP_VERBOSE_ABORT("bad_optional_access was thrown in -fno-exceptions mode");
#    endif
}

struct nullopt_t {
  struct __secret_tag {
    explicit __secret_tag() = default;
  };
  _LIBCPP_HIDE_FROM_ABI constexpr explicit nullopt_t(__secret_tag, __secret_tag) noexcept {}
};

inline constexpr nullopt_t nullopt{nullopt_t::__secret_tag{}, nullopt_t::__secret_tag{}};

struct __optional_construct_from_invoke_tag {};

template <class _Tp, bool = is_trivially_destructible<_Tp>::value>
struct __optional_destruct_base;

template <class _Tp>
struct __optional_destruct_base<_Tp, false> {
  typedef _Tp value_type;
  static_assert(is_object_v<value_type>, "instantiation of optional with a non-object type is undefined behavior");
  union {
    char __null_state_;
    remove_cv_t<value_type> __val_;
  };
  bool __engaged_;

  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__optional_destruct_base() {
    if (__engaged_)
      __val_.~value_type();
  }

  _LIBCPP_HIDE_FROM_ABI constexpr __optional_destruct_base() noexcept : __null_state_(), __engaged_(false) {}

  template <class... _Args>
  _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_destruct_base(in_place_t, _Args&&... __args)
      : __val_(std::forward<_Args>(__args)...), __engaged_(true) {}

#    if _LIBCPP_STD_VER >= 23
  template <class _Fp, class... _Args>
  _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_destruct_base(
      __optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args)
      : __val_(std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)), __engaged_(true) {}
#    endif

  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept {
    if (__engaged_) {
      __val_.~value_type();
      __engaged_ = false;
    }
  }
};

template <class _Tp>
struct __optional_destruct_base<_Tp, true> {
  typedef _Tp value_type;
  static_assert(is_object_v<value_type>, "instantiation of optional with a non-object type is undefined behavior");
  union {
    char __null_state_;
    remove_cv_t<value_type> __val_;
  };
  bool __engaged_;

  _LIBCPP_HIDE_FROM_ABI constexpr __optional_destruct_base() noexcept : __null_state_(), __engaged_(false) {}

  template <class... _Args>
  _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_destruct_base(in_place_t, _Args&&... __args)
      : __val_(std::forward<_Args>(__args)...), __engaged_(true) {}

#    if _LIBCPP_STD_VER >= 23
  template <class _Fp, class... _Args>
  _LIBCPP_HIDE_FROM_ABI constexpr __optional_destruct_base(
      __optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args)
      : __val_(std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)), __engaged_(true) {}
#    endif

  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept {
    if (__engaged_) {
      __engaged_ = false;
    }
  }
};

template <class _Tp, bool = is_reference<_Tp>::value>
struct __optional_storage_base : __optional_destruct_base<_Tp> {
  using __base _LIBCPP_NODEBUG = __optional_destruct_base<_Tp>;
  using value_type             = _Tp;
  using __base::__base;

  _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__engaged_; }

  _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() & noexcept { return this->__val_; }
  _LIBCPP_HIDE_FROM_ABI constexpr const value_type& __get() const& noexcept { return this->__val_; }
  _LIBCPP_HIDE_FROM_ABI constexpr value_type&& __get() && noexcept { return std::move(this->__val_); }
  _LIBCPP_HIDE_FROM_ABI constexpr const value_type&& __get() const&& noexcept { return std::move(this->__val_); }

  template <class... _Args>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_Args&&... __args) {
    _LIBCPP_ASSERT_INTERNAL(!has_value(), "__construct called for engaged __optional_storage");
    std::__construct_at(std::addressof(this->__val_), std::forward<_Args>(__args)...);
    this->__engaged_ = true;
  }

  template <class _That>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_from(_That&& __opt) {
    if (__opt.has_value())
      __construct(std::forward<_That>(__opt).__get());
  }

  template <class _That>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from(_That&& __opt) {
    if (this->__engaged_ == __opt.has_value()) {
      if (this->__engaged_)
        static_cast<_Tp&>(this->__val_) = std::forward<_That>(__opt).__get();
    } else {
      if (this->__engaged_)
        this->reset();
      else
        __construct(std::forward<_That>(__opt).__get());
    }
  }
};

// optional<T&> is currently required to be ill-formed. However, it may
// be allowed in the future. For this reason, it has already been implemented
// to ensure we can make the change in an ABI-compatible manner.
template <class _Tp>
struct __optional_storage_base<_Tp, true> {
  using value_type                 = _Tp;
  using __raw_type _LIBCPP_NODEBUG = remove_reference_t<_Tp>;
  __raw_type* __value_;

  template <class _Up>
  static _LIBCPP_HIDE_FROM_ABI constexpr bool __can_bind_reference() {
    using _RawUp = __libcpp_remove_reference_t<_Up>;
    using _UpPtr = _RawUp*;
    using _RawTp = __libcpp_remove_reference_t<_Tp>;
    using _TpPtr = _RawTp*;
    using _CheckLValueArg =
        integral_constant<bool,
                          (is_lvalue_reference<_Up>::value && is_convertible<_UpPtr, _TpPtr>::value) ||
                              is_same<_RawUp, reference_wrapper<_RawTp>>::value ||
                              is_same<_RawUp, reference_wrapper<__remove_const_t<_RawTp>>>::value >;
    return (is_lvalue_reference<_Tp>::value && _CheckLValueArg::value) ||
           (is_rvalue_reference<_Tp>::value && !is_lvalue_reference<_Up>::value &&
            is_convertible<_UpPtr, _TpPtr>::value);
  }

  _LIBCPP_HIDE_FROM_ABI constexpr __optional_storage_base() noexcept : __value_(nullptr) {}

  template <class _UArg>
  _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_storage_base(in_place_t, _UArg&& __uarg)
      : __value_(std::addressof(__uarg)) {
    static_assert(__can_bind_reference<_UArg>(),
                  "Attempted to construct a reference element in tuple from a "
                  "possible temporary");
  }

  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { __value_ = nullptr; }

  _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __value_ != nullptr; }

  _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() const& noexcept { return *__value_; }

  _LIBCPP_HIDE_FROM_ABI constexpr value_type&& __get() const&& noexcept { return std::forward<value_type>(*__value_); }

  template <class _UArg>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_UArg&& __val) {
    _LIBCPP_ASSERT_INTERNAL(!has_value(), "__construct called for engaged __optional_storage");
    static_assert(__can_bind_reference<_UArg>(),
                  "Attempted to construct a reference element in tuple from a "
                  "possible temporary");
    __value_ = std::addressof(__val);
  }

  template <class _That>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_from(_That&& __opt) {
    if (__opt.has_value())
      __construct(std::forward<_That>(__opt).__get());
  }

  template <class _That>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from(_That&& __opt) {
    if (has_value() == __opt.has_value()) {
      if (has_value())
        *__value_ = std::forward<_That>(__opt).__get();
    } else {
      if (has_value())
        reset();
      else
        __construct(std::forward<_That>(__opt).__get());
    }
  }
};

template <class _Tp, bool = is_trivially_copy_constructible<_Tp>::value>
struct __optional_copy_base : __optional_storage_base<_Tp> {
  using __optional_storage_base<_Tp>::__optional_storage_base;
};

template <class _Tp>
struct __optional_copy_base<_Tp, false> : __optional_storage_base<_Tp> {
  using __optional_storage_base<_Tp>::__optional_storage_base;

  _LIBCPP_HIDE_FROM_ABI __optional_copy_base() = default;

  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __optional_copy_base(const __optional_copy_base& __opt) {
    this->__construct_from(__opt);
  }

  _LIBCPP_HIDE_FROM_ABI __optional_copy_base(__optional_copy_base&&)                 = default;
  _LIBCPP_HIDE_FROM_ABI __optional_copy_base& operator=(const __optional_copy_base&) = default;
  _LIBCPP_HIDE_FROM_ABI __optional_copy_base& operator=(__optional_copy_base&&)      = default;
};

template <class _Tp, bool = is_trivially_move_constructible<_Tp>::value>
struct __optional_move_base : __optional_copy_base<_Tp> {
  using __optional_copy_base<_Tp>::__optional_copy_base;
};

template <class _Tp>
struct __optional_move_base<_Tp, false> : __optional_copy_base<_Tp> {
  using value_type = _Tp;
  using __optional_copy_base<_Tp>::__optional_copy_base;

  _LIBCPP_HIDE_FROM_ABI __optional_move_base()                            = default;
  _LIBCPP_HIDE_FROM_ABI __optional_move_base(const __optional_move_base&) = default;

  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
  __optional_move_base(__optional_move_base&& __opt) noexcept(is_nothrow_move_constructible_v<value_type>) {
    this->__construct_from(std::move(__opt));
  }

  _LIBCPP_HIDE_FROM_ABI __optional_move_base& operator=(const __optional_move_base&) = default;
  _LIBCPP_HIDE_FROM_ABI __optional_move_base& operator=(__optional_move_base&&)      = default;
};

template <class _Tp,
          bool = is_trivially_destructible<_Tp>::value && is_trivially_copy_constructible<_Tp>::value &&
                 is_trivially_copy_assignable<_Tp>::value>
struct __optional_copy_assign_base : __optional_move_base<_Tp> {
  using __optional_move_base<_Tp>::__optional_move_base;
};

template <class _Tp>
struct __optional_copy_assign_base<_Tp, false> : __optional_move_base<_Tp> {
  using __optional_move_base<_Tp>::__optional_move_base;

  _LIBCPP_HIDE_FROM_ABI __optional_copy_assign_base()                                   = default;
  _LIBCPP_HIDE_FROM_ABI __optional_copy_assign_base(const __optional_copy_assign_base&) = default;
  _LIBCPP_HIDE_FROM_ABI __optional_copy_assign_base(__optional_copy_assign_base&&)      = default;

  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __optional_copy_assign_base&
  operator=(const __optional_copy_assign_base& __opt) {
    this->__assign_from(__opt);
    return *this;
  }

  _LIBCPP_HIDE_FROM_ABI __optional_copy_assign_base& operator=(__optional_copy_assign_base&&) = default;
};

template <class _Tp,
          bool = is_trivially_destructible<_Tp>::value && is_trivially_move_constructible<_Tp>::value &&
                 is_trivially_move_assignable<_Tp>::value>
struct __optional_move_assign_base : __optional_copy_assign_base<_Tp> {
  using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;
};

template <class _Tp>
struct __optional_move_assign_base<_Tp, false> : __optional_copy_assign_base<_Tp> {
  using value_type = _Tp;
  using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;

  _LIBCPP_HIDE_FROM_ABI __optional_move_assign_base()                                              = default;
  _LIBCPP_HIDE_FROM_ABI __optional_move_assign_base(const __optional_move_assign_base& __opt)      = default;
  _LIBCPP_HIDE_FROM_ABI __optional_move_assign_base(__optional_move_assign_base&&)                 = default;
  _LIBCPP_HIDE_FROM_ABI __optional_move_assign_base& operator=(const __optional_move_assign_base&) = default;

  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __optional_move_assign_base&
  operator=(__optional_move_assign_base&& __opt) noexcept(
      is_nothrow_move_assignable_v<value_type> && is_nothrow_move_constructible_v<value_type>) {
    this->__assign_from(std::move(__opt));
    return *this;
  }
};

template <class _Tp>
using __optional_sfinae_ctor_base_t _LIBCPP_NODEBUG =
    __sfinae_ctor_base< is_copy_constructible<_Tp>::value, is_move_constructible<_Tp>::value >;

template <class _Tp>
using __optional_sfinae_assign_base_t _LIBCPP_NODEBUG =
    __sfinae_assign_base< (is_copy_constructible<_Tp>::value && is_copy_assignable<_Tp>::value),
                          (is_move_constructible<_Tp>::value && is_move_assignable<_Tp>::value) >;

template <class _Tp>
class optional;

#    if _LIBCPP_STD_VER >= 20

template <class _Tp>
concept __is_derived_from_optional = requires(const _Tp& __t) { []<class _Up>(const optional<_Up>&) {}(__t); };

#    endif // _LIBCPP_STD_VER >= 20

template <class _Tp>
struct __is_std_optional : false_type {};
template <class _Tp>
struct __is_std_optional<optional<_Tp>> : true_type {};

template <class _Tp>
class _LIBCPP_DECLSPEC_EMPTY_BASES optional
    : private __optional_move_assign_base<_Tp>,
      private __optional_sfinae_ctor_base_t<_Tp>,
      private __optional_sfinae_assign_base_t<_Tp> {
  using __base _LIBCPP_NODEBUG = __optional_move_assign_base<_Tp>;

public:
  using value_type = _Tp;

  using __trivially_relocatable _LIBCPP_NODEBUG =
      conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, optional, void>;
  using __replaceable _LIBCPP_NODEBUG = conditional_t<__is_replaceable_v<_Tp>, optional, void>;

private:
  // Disable the reference extension using this static assert.
  static_assert(!is_same_v<__remove_cvref_t<value_type>, in_place_t>,
                "instantiation of optional with in_place_t is ill-formed");
  static_assert(!is_same_v<__remove_cvref_t<value_type>, nullopt_t>,
                "instantiation of optional with nullopt_t is ill-formed");
  static_assert(!is_reference_v<value_type>, "instantiation of optional with a reference type is ill-formed");
  static_assert(is_destructible_v<value_type>, "instantiation of optional with a non-destructible type is ill-formed");
  static_assert(!is_array_v<value_type>, "instantiation of optional with an array type is ill-formed");

  // LWG2756: conditionally explicit conversion from _Up
  struct _CheckOptionalArgsConstructor {
    template <class _Up>
    _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_implicit() {
      return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>;
    }

    template <class _Up>
    _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_explicit() {
      return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>;
    }
  };
  template <class _Up>
  using _CheckOptionalArgsCtor _LIBCPP_NODEBUG =
      _If< _IsNotSame<__remove_cvref_t<_Up>, in_place_t>::value && _IsNotSame<__remove_cvref_t<_Up>, optional>::value &&
               (!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_optional<__remove_cvref_t<_Up>>::value),
           _CheckOptionalArgsConstructor,
           __check_tuple_constructor_fail >;
  template <class _QualUp>
  struct _CheckOptionalLikeConstructor {
    template <class _Up, class _Opt = optional<_Up>>
    using __check_constructible_from_opt _LIBCPP_NODEBUG =
        _Or< is_constructible<_Tp, _Opt&>,
             is_constructible<_Tp, _Opt const&>,
             is_constructible<_Tp, _Opt&&>,
             is_constructible<_Tp, _Opt const&&>,
             is_convertible<_Opt&, _Tp>,
             is_convertible<_Opt const&, _Tp>,
             is_convertible<_Opt&&, _Tp>,
             is_convertible<_Opt const&&, _Tp> >;
    template <class _Up, class _Opt = optional<_Up>>
    using __check_assignable_from_opt _LIBCPP_NODEBUG =
        _Or< is_assignable<_Tp&, _Opt&>,
             is_assignable<_Tp&, _Opt const&>,
             is_assignable<_Tp&, _Opt&&>,
             is_assignable<_Tp&, _Opt const&&> >;
    template <class _Up, class _QUp = _QualUp>
    _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_implicit() {
      return is_convertible<_QUp, _Tp>::value &&
             (is_same_v<remove_cv_t<_Tp>, bool> || !__check_constructible_from_opt<_Up>::value);
    }
    template <class _Up, class _QUp = _QualUp>
    _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_explicit() {
      return !is_convertible<_QUp, _Tp>::value &&
             (is_same_v<remove_cv_t<_Tp>, bool> || !__check_constructible_from_opt<_Up>::value);
    }
    template <class _Up, class _QUp = _QualUp>
    _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_assign() {
      // Construction and assignability of _QUp to _Tp has already been
      // checked.
      return !__check_constructible_from_opt<_Up>::value && !__check_assignable_from_opt<_Up>::value;
    }
  };

  template <class _Up, class _QualUp>
  using _CheckOptionalLikeCtor _LIBCPP_NODEBUG =
      _If< _And< _IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp> >::value,
           _CheckOptionalLikeConstructor<_QualUp>,
           __check_tuple_constructor_fail >;
  template <class _Up, class _QualUp>
  using _CheckOptionalLikeAssign _LIBCPP_NODEBUG =
      _If< _And< _IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>, is_assignable<_Tp&, _QualUp> >::value,
           _CheckOptionalLikeConstructor<_QualUp>,
           __check_tuple_constructor_fail >;

public:
  _LIBCPP_HIDE_FROM_ABI constexpr optional() noexcept {}
  _LIBCPP_HIDE_FROM_ABI constexpr optional(const optional&) = default;
  _LIBCPP_HIDE_FROM_ABI constexpr optional(optional&&)      = default;
  _LIBCPP_HIDE_FROM_ABI constexpr optional(nullopt_t) noexcept {}

  template <class _InPlaceT,
            class... _Args,
            enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>, is_constructible<value_type, _Args...>>::value, int> = 0>
  _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_InPlaceT, _Args&&... __args)
      : __base(in_place, std::forward<_Args>(__args)...) {}

  template <class _Up,
            class... _Args,
            enable_if_t<is_constructible_v<value_type, initializer_list<_Up>&, _Args...>, int> = 0>
  _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
      : __base(in_place, __il, std::forward<_Args>(__args)...) {}

  template <class _Up                                                                        = value_type,
            enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), int> = 0>
  _LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v) : __base(in_place, std::forward<_Up>(__v)) {}

  template <class _Up, enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), int> = 0>
  _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Up&& __v) : __base(in_place, std::forward<_Up>(__v)) {}

  // LWG2756: conditionally explicit conversion from const optional<_Up>&
  template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_implicit<_Up>(), int> = 0>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>& __v) {
    this->__construct_from(__v);
  }
  template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_explicit<_Up>(), int> = 0>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(const optional<_Up>& __v) {
    this->__construct_from(__v);
  }

  // LWG2756: conditionally explicit conversion from optional<_Up>&&
  template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_implicit<_Up>(), int> = 0>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(optional<_Up>&& __v) {
    this->__construct_from(std::move(__v));
  }
  template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_explicit<_Up>(), int> = 0>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(optional<_Up>&& __v) {
    this->__construct_from(std::move(__v));
  }

#    if _LIBCPP_STD_VER >= 23
  template <class _Tag,
            class _Fp,
            class... _Args,
            enable_if_t<_IsSame<_Tag, __optional_construct_from_invoke_tag>::value, int> = 0>
  _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Tag, _Fp&& __f, _Args&&... __args)
      : __base(__optional_construct_from_invoke_tag{}, std::forward<_Fp>(__f), std::forward<_Args>(__args)...) {}
#    endif

  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(nullopt_t) noexcept {
    reset();
    return *this;
  }

  _LIBCPP_HIDE_FROM_ABI constexpr optional& operator=(const optional&) = default;
  _LIBCPP_HIDE_FROM_ABI constexpr optional& operator=(optional&&)      = default;

  // LWG2756
  template <class _Up        = value_type,
            enable_if_t<_And<_IsNotSame<__remove_cvref_t<_Up>, optional>,
                             _Or<_IsNotSame<__remove_cvref_t<_Up>, value_type>, _Not<is_scalar<value_type>>>,
                             is_constructible<value_type, _Up>,
                             is_assignable<value_type&, _Up>>::value,
                        int> = 0>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(_Up&& __v) {
    if (this->has_value())
      this->__get() = std::forward<_Up>(__v);
    else
      this->__construct(std::forward<_Up>(__v));
    return *this;
  }

  // LWG2756
  template <class _Up, enable_if_t<_CheckOptionalLikeAssign<_Up, _Up const&>::template __enable_assign<_Up>(), int> = 0>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(const optional<_Up>& __v) {
    this->__assign_from(__v);
    return *this;
  }

  // LWG2756
  template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_assign<_Up>(), int> = 0>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(optional<_Up>&& __v) {
    this->__assign_from(std::move(__v));
    return *this;
  }

  template <class... _Args, enable_if_t<is_constructible_v<value_type, _Args...>, int> = 0>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(_Args&&... __args) {
    reset();
    this->__construct(std::forward<_Args>(__args)...);
    return this->__get();
  }

  template <class _Up,
            class... _Args,
            enable_if_t<is_constructible_v<value_type, initializer_list<_Up>&, _Args...>, int> = 0>
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) {
    reset();
    this->__construct(__il, std::forward<_Args>(__args)...);
    return this->__get();
  }

  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
  swap(optional& __opt) noexcept(is_nothrow_move_constructible_v<value_type> && is_nothrow_swappable_v<value_type>) {
    if (this->has_value() == __opt.has_value()) {
      using std::swap;
      if (this->has_value())
        swap(this->__get(), __opt.__get());
    } else {
      if (this->has_value()) {
        __opt.__construct(std::move(this->__get()));
        reset();
      } else {
        this->__construct(std::move(__opt.__get()));
        __opt.reset();
      }
    }
  }

  _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<value_type const> operator->() const noexcept {
    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
    return std::addressof(this->__get());
  }

  _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<value_type> operator->() noexcept {
    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
    return std::addressof(this->__get());
  }

  _LIBCPP_HIDE_FROM_ABI constexpr const value_type& operator*() const& noexcept {
    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
    return this->__get();
  }

  _LIBCPP_HIDE_FROM_ABI constexpr value_type& operator*() & noexcept {
    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
    return this->__get();
  }

  _LIBCPP_HIDE_FROM_ABI constexpr value_type&& operator*() && noexcept {
    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
    return std::move(this->__get());
  }

  _LIBCPP_HIDE_FROM_ABI constexpr const value_type&& operator*() const&& noexcept {
    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
    return std::move(this->__get());
  }

  _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return has_value(); }

  using __base::__get;
  using __base::has_value;

  _LIBCPP_HIDE_FROM_ABI constexpr value_type const& value() const& {
    if (!this->has_value())
      std::__throw_bad_optional_access();
    return this->__get();
  }

  _LIBCPP_HIDE_FROM_ABI constexpr value_type& value() & {
    if (!this->has_value())
      std::__throw_bad_optional_access();
    return this->__get();
  }

  _LIBCPP_HIDE_FROM_ABI constexpr value_type&& value() && {
    if (!this->has_value())
      std::__throw_bad_optional_access();
    return std::move(this->__get());
  }

  _LIBCPP_HIDE_FROM_ABI constexpr value_type const&& value() const&& {
    if (!this->has_value())
      std::__throw_bad_optional_access();
    return std::move(this->__get());
  }

  template <class _Up>
  _LIBCPP_HIDE_FROM_ABI constexpr value_type value_or(_Up&& __v) const& {
    static_assert(is_copy_constructible_v<value_type>, "optional<T>::value_or: T must be copy constructible");
    static_assert(is_convertible_v<_Up, value_type>, "optional<T>::value_or: U must be convertible to T");
    return this->has_value() ? this->__get() : static_cast<value_type>(std::forward<_Up>(__v));
  }

  template <class _Up>
  _LIBCPP_HIDE_FROM_ABI constexpr value_type value_or(_Up&& __v) && {
    static_assert(is_move_constructible_v<value_type>, "optional<T>::value_or: T must be move constructible");
    static_assert(is_convertible_v<_Up, value_type>, "optional<T>::value_or: U must be convertible to T");
    return this->has_value() ? std::move(this->__get()) : static_cast<value_type>(std::forward<_Up>(__v));
  }

#    if _LIBCPP_STD_VER >= 23
  template <class _Func>
  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
    using _Up = invoke_result_t<_Func, value_type&>;
    static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
                  "Result of f(value()) must be a specialization of std::optional");
    if (*this)
      return std::invoke(std::forward<_Func>(__f), value());
    return remove_cvref_t<_Up>();
  }

  template <class _Func>
  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& {
    using _Up = invoke_result_t<_Func, const value_type&>;
    static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
                  "Result of f(value()) must be a specialization of std::optional");
    if (*this)
      return std::invoke(std::forward<_Func>(__f), value());
    return remove_cvref_t<_Up>();
  }

  template <class _Func>
  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
    using _Up = invoke_result_t<_Func, value_type&&>;
    static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
                  "Result of f(std::move(value())) must be a specialization of std::optional");
    if (*this)
      return std::invoke(std::forward<_Func>(__f), std::move(value()));
    return remove_cvref_t<_Up>();
  }

  template <class _Func>
  _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& {
    using _Up = invoke_result_t<_Func, const value_type&&>;
    static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
                  "Result of f(std::move(value())) must be a specialization of std::optional");
    if (*this)
      return std::invoke(std::forward<_Func>(__f), std::move(value()));
    return remove_cvref_t<_Up>();
  }

  template <class _Func>
  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & {
    using _Up = remove_cv_t<invoke_result_t<_Func, value_type&>>;
    static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array");
    static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t");
    static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t");
    static_assert(is_object_v<_Up>, "Result of f(value()) should be an object type");
    if (*this)
      return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), value());
    return optional<_Up>();
  }

  template <class _Func>
  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& {
    using _Up = remove_cv_t<invoke_result_t<_Func, const value_type&>>;
    static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array");
    static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t");
    static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t");
    static_assert(is_object_v<_Up>, "Result of f(value()) should be an object type");
    if (*this)
      return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), value());
    return optional<_Up>();
  }

  template <class _Func>
  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && {
    using _Up = remove_cv_t<invoke_result_t<_Func, value_type&&>>;
    static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array");
    static_assert(!is_same_v<_Up, in_place_t>, "Result of f(std::move(value())) should not be std::in_place_t");
    static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(std::move(value())) should not be std::nullopt_t");
    static_assert(is_object_v<_Up>, "Result of f(std::move(value())) should be an object type");
    if (*this)
      return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), std::move(value()));
    return optional<_Up>();
  }

  template <class _Func>
  _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& {
    using _Up = remove_cvref_t<invoke_result_t<_Func, const value_type&&>>;
    static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array");
    static_assert(!is_same_v<_Up, in_place_t>, "Result of f(std::move(value())) should not be std::in_place_t");
    static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(std::move(value())) should not be std::nullopt_t");
    static_assert(is_object_v<_Up>, "Result of f(std::move(value())) should be an object type");
    if (*this)
      return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), std::move(value()));
    return optional<_Up>();
  }

  template <invocable _Func>
  _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) const&
    requires is_copy_constructible_v<value_type>
  {
    static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>,
                  "Result of f() should be the same type as this optional");
    if (*this)
      return *this;
    return std::forward<_Func>(__f)();
  }

  template <invocable _Func>
  _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) &&
    requires is_move_constructible_v<value_type>
  {
    static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>,
                  "Result of f() should be the same type as this optional");
    if (*this)
      return std::move(*this);
    return std::forward<_Func>(__f)();
  }
#    endif // _LIBCPP_STD_VER >= 23

  using __base::reset;
};

template <class _Tp>
optional(_Tp) -> optional<_Tp>;

// [optional.relops] Relational operators

template <
    class _Tp,
    class _Up,
    enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
                int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const optional<_Up>& __y) {
  if (static_cast<bool>(__x) != static_cast<bool>(__y))
    return false;
  if (!static_cast<bool>(__x))
    return true;
  return *__x == *__y;
}

template <
    class _Tp,
    class _Up,
    enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
                int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const optional<_Up>& __y) {
  if (static_cast<bool>(__x) != static_cast<bool>(__y))
    return true;
  if (!static_cast<bool>(__x))
    return false;
  return *__x != *__y;
}

template < class _Tp,
           class _Up,
           enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
                       int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const optional<_Up>& __y) {
  if (!static_cast<bool>(__y))
    return false;
  if (!static_cast<bool>(__x))
    return true;
  return *__x < *__y;
}

template < class _Tp,
           class _Up,
           enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
                       int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const optional<_Up>& __y) {
  if (!static_cast<bool>(__x))
    return false;
  if (!static_cast<bool>(__y))
    return true;
  return *__x > *__y;
}

template <
    class _Tp,
    class _Up,
    enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
                int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const optional<_Up>& __y) {
  if (!static_cast<bool>(__x))
    return true;
  if (!static_cast<bool>(__y))
    return false;
  return *__x <= *__y;
}

template <
    class _Tp,
    class _Up,
    enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
                int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const optional<_Up>& __y) {
  if (!static_cast<bool>(__y))
    return true;
  if (!static_cast<bool>(__x))
    return false;
  return *__x >= *__y;
}

#    if _LIBCPP_STD_VER >= 20

template <class _Tp, three_way_comparable_with<_Tp> _Up>
_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Tp, _Up>
operator<=>(const optional<_Tp>& __x, const optional<_Up>& __y) {
  if (__x && __y)
    return *__x <=> *__y;
  return __x.has_value() <=> __y.has_value();
}

#    endif // _LIBCPP_STD_VER >= 20

// [optional.nullops] Comparison with nullopt

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, nullopt_t) noexcept {
  return !static_cast<bool>(__x);
}

#    if _LIBCPP_STD_VER <= 17

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(nullopt_t, const optional<_Tp>& __x) noexcept {
  return !static_cast<bool>(__x);
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, nullopt_t) noexcept {
  return static_cast<bool>(__x);
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(nullopt_t, const optional<_Tp>& __x) noexcept {
  return static_cast<bool>(__x);
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>&, nullopt_t) noexcept {
  return false;
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(nullopt_t, const optional<_Tp>& __x) noexcept {
  return static_cast<bool>(__x);
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, nullopt_t) noexcept {
  return !static_cast<bool>(__x);
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(nullopt_t, const optional<_Tp>&) noexcept {
  return true;
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, nullopt_t) noexcept {
  return static_cast<bool>(__x);
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(nullopt_t, const optional<_Tp>&) noexcept {
  return false;
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>&, nullopt_t) noexcept {
  return true;
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(nullopt_t, const optional<_Tp>& __x) noexcept {
  return !static_cast<bool>(__x);
}

#    else // _LIBCPP_STD_VER <= 17

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept {
  return __x.has_value() <=> false;
}

#    endif // _LIBCPP_STD_VER <= 17

// [optional.comp.with.t] Comparison with T

template <
    class _Tp,
    class _Up,
    enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
                int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const _Up& __v) {
  return static_cast<bool>(__x) ? *__x == __v : false;
}

template <
    class _Tp,
    class _Up,
    enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
                int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __v, const optional<_Up>& __x) {
  return static_cast<bool>(__x) ? __v == *__x : false;
}

template <
    class _Tp,
    class _Up,
    enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
                int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const _Up& __v) {
  return static_cast<bool>(__x) ? *__x != __v : true;
}

template <
    class _Tp,
    class _Up,
    enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
                int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const _Tp& __v, const optional<_Up>& __x) {
  return static_cast<bool>(__x) ? __v != *__x : true;
}

template < class _Tp,
           class _Up,
           enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
                       int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const _Up& __v) {
  return static_cast<bool>(__x) ? *__x < __v : true;
}

template < class _Tp,
           class _Up,
           enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
                       int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __v, const optional<_Up>& __x) {
  return static_cast<bool>(__x) ? __v < *__x : false;
}

template <
    class _Tp,
    class _Up,
    enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
                int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const _Up& __v) {
  return static_cast<bool>(__x) ? *__x <= __v : true;
}

template <
    class _Tp,
    class _Up,
    enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
                int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Tp& __v, const optional<_Up>& __x) {
  return static_cast<bool>(__x) ? __v <= *__x : false;
}

template < class _Tp,
           class _Up,
           enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
                       int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const _Up& __v) {
  return static_cast<bool>(__x) ? *__x > __v : false;
}

template < class _Tp,
           class _Up,
           enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
                       int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __v, const optional<_Up>& __x) {
  return static_cast<bool>(__x) ? __v > *__x : true;
}

template <
    class _Tp,
    class _Up,
    enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
                int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const _Up& __v) {
  return static_cast<bool>(__x) ? *__x >= __v : false;
}

template <
    class _Tp,
    class _Up,
    enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
                int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Tp& __v, const optional<_Up>& __x) {
  return static_cast<bool>(__x) ? __v >= *__x : true;
}

#    if _LIBCPP_STD_VER >= 20

template <class _Tp, class _Up>
  requires(!__is_derived_from_optional<_Up>) && three_way_comparable_with<_Tp, _Up>
_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Tp, _Up>
operator<=>(const optional<_Tp>& __x, const _Up& __v) {
  return __x.has_value() ? *__x <=> __v : strong_ordering::less;
}

#    endif // _LIBCPP_STD_VER >= 20

template <class _Tp, enable_if_t< is_move_constructible_v<_Tp> && is_swappable_v<_Tp>, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
swap(optional<_Tp>& __x, optional<_Tp>& __y) noexcept(noexcept(__x.swap(__y))) {
  __x.swap(__y);
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr optional<decay_t<_Tp>> make_optional(_Tp&& __v) {
  return optional<decay_t<_Tp>>(std::forward<_Tp>(__v));
}

template <class _Tp, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> make_optional(_Args&&... __args) {
  return optional<_Tp>(in_place, std::forward<_Args>(__args)...);
}

template <class _Tp, class _Up, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> make_optional(initializer_list<_Up> __il, _Args&&... __args) {
  return optional<_Tp>(in_place, __il, std::forward<_Args>(__args)...);
}

template <class _Tp>
struct hash< __enable_hash_helper<optional<_Tp>, remove_const_t<_Tp>> > {
#    if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS)
  _LIBCPP_DEPRECATED_IN_CXX17 typedef optional<_Tp> argument_type;
  _LIBCPP_DEPRECATED_IN_CXX17 typedef size_t result_type;
#    endif

  _LIBCPP_HIDE_FROM_ABI size_t operator()(const optional<_Tp>& __opt) const {
    return static_cast<bool>(__opt) ? hash<remove_const_t<_Tp>>()(*__opt) : 0;
  }
};

_LIBCPP_END_NAMESPACE_STD

#  endif // _LIBCPP_STD_VER >= 17

_LIBCPP_POP_MACROS

#  if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
#    include <atomic>
#    include <climits>
#    include <concepts>
#    include <ctime>
#    include <iterator>
#    include <limits>
#    include <memory>
#    include <ratio>
#    include <stdexcept>
#    include <tuple>
#    include <type_traits>
#    include <typeinfo>
#    include <utility>
#    include <variant>
#  endif
#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)

#endif // _LIBCPP_OPTIONAL
