// -*- 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___CXX03_OPTIONAL
#define _LIBCPP___CXX03_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

*/

#include <__cxx03/__assert>
#include <__cxx03/__compare/compare_three_way_result.h>
#include <__cxx03/__compare/three_way_comparable.h>
#include <__cxx03/__concepts/invocable.h>
#include <__cxx03/__config>
#include <__cxx03/__exception/exception.h>
#include <__cxx03/__functional/hash.h>
#include <__cxx03/__functional/invoke.h>
#include <__cxx03/__functional/unary_function.h>
#include <__cxx03/__fwd/functional.h>
#include <__cxx03/__memory/addressof.h>
#include <__cxx03/__memory/construct_at.h>
#include <__cxx03/__tuple/sfinae_helpers.h>
#include <__cxx03/__type_traits/add_pointer.h>
#include <__cxx03/__type_traits/conditional.h>
#include <__cxx03/__type_traits/conjunction.h>
#include <__cxx03/__type_traits/decay.h>
#include <__cxx03/__type_traits/disjunction.h>
#include <__cxx03/__type_traits/is_array.h>
#include <__cxx03/__type_traits/is_assignable.h>
#include <__cxx03/__type_traits/is_constructible.h>
#include <__cxx03/__type_traits/is_convertible.h>
#include <__cxx03/__type_traits/is_destructible.h>
#include <__cxx03/__type_traits/is_nothrow_assignable.h>
#include <__cxx03/__type_traits/is_nothrow_constructible.h>
#include <__cxx03/__type_traits/is_object.h>
#include <__cxx03/__type_traits/is_reference.h>
#include <__cxx03/__type_traits/is_scalar.h>
#include <__cxx03/__type_traits/is_swappable.h>
#include <__cxx03/__type_traits/is_trivially_assignable.h>
#include <__cxx03/__type_traits/is_trivially_constructible.h>
#include <__cxx03/__type_traits/is_trivially_destructible.h>
#include <__cxx03/__type_traits/is_trivially_relocatable.h>
#include <__cxx03/__type_traits/negation.h>
#include <__cxx03/__type_traits/remove_const.h>
#include <__cxx03/__type_traits/remove_cvref.h>
#include <__cxx03/__type_traits/remove_reference.h>
#include <__cxx03/__utility/declval.h>
#include <__cxx03/__utility/forward.h>
#include <__cxx03/__utility/in_place.h>
#include <__cxx03/__utility/move.h>
#include <__cxx03/__utility/swap.h>
#include <__cxx03/__verbose_abort>
#include <__cxx03/initializer_list>
#include <__cxx03/new>
#include <__cxx03/version>

// standard-mandated includes

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

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

_LIBCPP_PUSH_MACROS
#include <__cxx03/__undef_macros>

namespace std // purposefully not using versioning namespace
{

class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS 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

_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS void
__throw_bad_optional_access() {
#  ifndef _LIBCPP_HAS_NO_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_;
    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_;
    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     = __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_)
        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 = 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 =
    __sfinae_ctor_base< is_copy_constructible<_Tp>::value, is_move_constructible<_Tp>::value >;

template <class _Tp>
using __optional_sfinae_assign_base_t =
    __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 = __optional_move_assign_base<_Tp>;

public:
  using value_type = _Tp;

  using __trivially_relocatable = conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, 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 =
      _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 =
        _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 =
        _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 =
      _If< _And< _IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp> >::value,
           _CheckOptionalLikeConstructor<_QualUp>,
           __check_tuple_constructor_fail >;
  template <class _Up, class _QualUp>
  using _CheckOptionalLikeAssign =
      _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,
      class = enable_if_t< _And< _IsSame<_InPlaceT, in_place_t>, is_constructible<value_type, _Args...> >::value > >
  _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_InPlaceT, _Args&&... __args)
      : __base(in_place, std::forward<_Args>(__args)...) {}

  template <class _Up,
            class... _Args,
            class = enable_if_t< is_constructible_v<value_type, initializer_list<_Up>&, _Args...>> >
  _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,
      class     = 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> >
  _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, class = enable_if_t< is_constructible_v<value_type, _Args...> > >
  _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,
            class = enable_if_t< is_constructible_v<value_type, initializer_list<_Up>&, _Args...> > >
  _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 _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS constexpr value_type const& value() const& {
    if (!this->has_value())
      __throw_bad_optional_access();
    return this->__get();
  }

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

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

  _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS constexpr value_type const&& value() const&& {
    if (!this->has_value())
      __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 _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS 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 _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS 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 _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS 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 _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS 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 _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS 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 _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS 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 _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS 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;
};

#  if _LIBCPP_STD_VER >= 17
template <class _Tp>
optional(_Tp) -> optional<_Tp>;
#  endif

// Comparisons between optionals
template <class _Tp, class _Up>
_LIBCPP_HIDE_FROM_ABI constexpr enable_if_t<
    is_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
    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>
_LIBCPP_HIDE_FROM_ABI constexpr enable_if_t<
    is_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
    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>
_LIBCPP_HIDE_FROM_ABI constexpr enable_if_t<
    is_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
    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>
_LIBCPP_HIDE_FROM_ABI constexpr enable_if_t<
    is_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
    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>
_LIBCPP_HIDE_FROM_ABI constexpr enable_if_t<
    is_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
    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>
_LIBCPP_HIDE_FROM_ABI constexpr enable_if_t<
    is_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
    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

// Comparisons 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

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

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

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

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

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

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

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

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

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

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

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

template <class _Tp, class _Up>
_LIBCPP_HIDE_FROM_ABI constexpr enable_if_t<
    is_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
    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>
inline _LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR_SINCE_CXX20 enable_if_t< is_move_constructible_v<_Tp> && is_swappable_v<_Tp>, 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 _LIBCPP_TEMPLATE_VIS 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 <__cxx03/atomic>
#  include <__cxx03/climits>
#  include <__cxx03/concepts>
#  include <__cxx03/ctime>
#  include <__cxx03/iterator>
#  include <__cxx03/limits>
#  include <__cxx03/memory>
#  include <__cxx03/ratio>
#  include <__cxx03/stdexcept>
#  include <__cxx03/tuple>
#  include <__cxx03/type_traits>
#  include <__cxx03/typeinfo>
#  include <__cxx03/utility>
#  include <__cxx03/variant>
#endif

#endif // _LIBCPP___CXX03_OPTIONAL
