text: /// \file
  // Range v3 library
  //
  //  Copyright Casey Carter 2017
  //
  //  Use, modification and distribution is subject to the
  //  Boost Software License, Version 1.0. (See accompanying
  //  file LICENSE_1_0.txt or copy at
  //  http://www.boost.org/LICENSE_1_0.txt)
  //
  // Project home: https://github.com/ericniebler/range-v3
  //
  
  #ifndef RANGES_V3_UTILITY_OPTIONAL_HPP
  #define RANGES_V3_UTILITY_OPTIONAL_HPP
  
  #include <exception>
  #include <initializer_list>
  #include <memory>
  #include <new>
  
  #include <concepts/concepts.hpp>
  
  #include <range/v3/detail/config.hpp>
  #include <range/v3/utility/addressof.hpp>
  #include <range/v3/utility/in_place.hpp>
  #include <range/v3/utility/static_const.hpp>
  #include <range/v3/utility/swap.hpp>
  
  namespace ranges
  {
      template<typename>
      struct optional;
  
      struct bad_optional_access : std::exception
      {
          virtual const char * what() const noexcept override
          {
              return "bad optional access";
          }
      };
  
      struct nullopt_t
      {
          struct tag
          {};
          explicit constexpr nullopt_t(tag) noexcept
          {}
      };
  #if RANGES_CXX_INLINE_VARIABLES >= RANGES_CXX_INLINE_VARIABLES_17
      inline constexpr nullopt_t nullopt{nullopt_t::tag{}};
  #else
      /// \cond
      namespace detail
      {
          template<typename>
          struct nullopt_holder
          {
              static constexpr nullopt_t nullopt{nullopt_t::tag{}};
          };
          template<typename T>
          constexpr nullopt_t nullopt_holder<T>::nullopt;
      } // namespace detail
      /// \endcond
      namespace
      {
          constexpr auto & nullopt = detail::nullopt_holder<void>::nullopt;
      }
  #endif
  
      /// \cond
      namespace detail
      {
          template<typename = void>
          [[noreturn]] bool throw_bad_optional_access()
          {
              throw bad_optional_access{};
          }
  
          namespace optional_adl
          {
              template<typename T, bool = std::is_trivially_destructible<T>::value>
              struct optional_storage
              {
                  union
                  {
                      char dummy_;
                      meta::_t<std::remove_cv<T>> data_;
                  };
                  bool engaged_;
  
                  constexpr optional_storage() noexcept
                    : optional_storage(
                          tag{},
                          meta::strict_and<detail::is_trivially_default_constructible<T>,
                                           detail::is_trivially_copyable<T>>{})
                  {}
                  CPP_template(typename... Args)(         //
                      requires Constructible<T, Args...>) //
                      constexpr explicit optional_storage(in_place_t,
                                                          Args &&... args) //
                      noexcept(std::is_nothrow_constructible<T, Args...>::value)
                    : data_(static_cast<Args &&>(args)...)
                    , engaged_{true}
                  {}
  
                  constexpr void reset() noexcept
                  {
                      engaged_ = false;
                  }
  
              private:
                  struct tag
                  {};
                  constexpr optional_storage(tag, std::false_type) noexcept
                    : dummy_{}
                    , engaged_{false}
                  {}
                  constexpr optional_storage(tag, std::true_type) noexcept
                    : data_{}
                    , engaged_{false}
                  {}
              };
  
              template<typename T>
              struct optional_storage<T, false>
              {
                  union
                  {
                      char dummy_;
                      meta::_t<std::remove_cv<T>> data_;
                  };
                  bool engaged_;
  
                  ~optional_storage()
                  {
                      reset();
                  }
                  constexpr optional_storage() noexcept
                    : dummy_{}
                    , engaged_{false}
                  {}
                  CPP_template(typename... Args)(         //
                      requires Constructible<T, Args...>) //
                      constexpr explicit optional_storage(in_place_t,
                                                          Args &&... args) //
                      noexcept(std::is_nothrow_constructible<T, Args...>::value)
                    : data_(static_cast<Args &&>(args)...)
                    , engaged_{true}
                  {}
                  optional_storage(optional_storage const &) = default;
                  optional_storage(optional_storage &&) = default;
                  optional_storage & operator=(optional_storage const &) = default;
                  optional_storage & operator=(optional_storage &&) = default;
  
                  void reset() noexcept
                  {
                      if(engaged_)
                      {
                          data_.~T();
                          engaged_ = false;
                      }
                  }
              };
  
              template<typename T>
              struct optional_base : private optional_storage<T>
              {
                  using optional_storage<T>::optional_storage;
                  using optional_storage<T>::reset;
  
                  constexpr bool has_value() const noexcept
                  {
                      return engaged_;
                  }
                  constexpr T & operator*() & noexcept
                  {
                      return RANGES_EXPECT(engaged_), data_;
                  }
                  constexpr T const & operator*() const & noexcept
                  {
                      return RANGES_EXPECT(engaged_), data_;
                  }
                  constexpr T && operator*() && noexcept
                  {
                      return RANGES_EXPECT(engaged_), detail::move(data_);
                  }
                  constexpr T const && operator*() const && noexcept
                  {
                      return RANGES_EXPECT(engaged_), detail::move(data_);
                  }
                  constexpr T * operator->() noexcept
                  {
                      return RANGES_EXPECT(engaged_), detail::addressof(data_);
                  }
                  constexpr T const * operator->() const noexcept
                  {
                      return RANGES_EXPECT(engaged_), detail::addressof(data_);
                  }
                  CPP_member
                  constexpr auto swap(optional_base & that) noexcept(
                      std::is_nothrow_move_constructible<T>::value &&
                          is_nothrow_swappable<T>::value) -> CPP_ret(void)( //
                      requires MoveConstructible<T> && Swappable<T>)
                  {
                      constexpr bool can_swap_trivially =
                          !::concepts::adl_swap_detail::is_adl_swappable_v<T> &&
                          detail::is_trivially_move_constructible<T>::value &&
                          detail::is_trivially_move_assignable<T>::value;
  
                      swap_(meta::bool_<can_swap_trivially>{}, that);
                  }
  
              protected:
                  template<typename... Args>
                  auto construct_from(Args &&... args) noexcept(
                      std::is_nothrow_constructible<T, Args...>::value) -> CPP_ret(T &)( //
                      requires Constructible<T, Args...>)
                  {
                      RANGES_EXPECT(!engaged_);
                      auto const address = static_cast<void *>(std::addressof(data_));
                      ::new(address) T(static_cast<Args &&>(args)...);
                      engaged_ = true;
                      return data_;
                  }
                  template<typename U>
                  constexpr void assign_from(U && that) noexcept(
                      std::is_nothrow_constructible<T, decltype(*static_cast<U &&>(that))>::
                          value && std::is_nothrow_assignable<
                              T &, decltype(*static_cast<U &&>(that))>::value)
                  {
                      if(!that.has_value())
                          reset();
                      else if(engaged_)
                          data_ = *static_cast<U &&>(that);
                      else
                      {
                          auto const address =
                              static_cast<void *>(detail::addressof(data_));
                          ::new(address) T(*static_cast<U &&>(that));
                          engaged_ = true;
                      }
                  }
  
              private:
                  constexpr void swap_(std::true_type, optional_base & that) noexcept
                  {
                      ranges::swap(static_cast<optional_storage<T> &>(*this),
                                   static_cast<optional_storage<T> &>(that));
                  }
                  constexpr void swap_(std::false_type, optional_base & that) noexcept(
                      std::is_nothrow_move_constructible<T>::value &&
                          is_nothrow_swappable<T>::value)
                  {
                      if(that.engaged_ == engaged_)
                      {
                          if(engaged_)
                              ranges::swap(data_, that.data_);
                      }
                      else
                      {
                          auto & src = engaged_ ? *this : that;
                          auto & dst = engaged_ ? that : *this;
                          dst.construct_from(detail::move(src.data_));
                          src.reset();
                      }
                  }
  
                  using optional_storage<T>::engaged_;
                  using optional_storage<T>::data_;
              };
  
              template<typename T>
              struct optional_base<T &>
              {
                  optional_base() = default;
                  template<typename Arg>
                  constexpr explicit CPP_ctor(optional_base)(in_place_t, Arg && arg)( //
                      noexcept(true)                                                  //
                      requires Constructible<T &, Arg>)
                    : ptr_(detail::addressof(arg))
                  {}
                  constexpr bool has_value() const noexcept
                  {
                      return ptr_;
                  }
                  constexpr T & operator*() const noexcept
                  {
                      return RANGES_EXPECT(ptr_), *ptr_;
                  }
                  constexpr T * operator->() const noexcept
                  {
                      return RANGES_EXPECT(ptr_), ptr_;
                  }
                  constexpr void reset() noexcept
                  {
                      ptr_ = nullptr;
                  }
                  CPP_member
                  constexpr auto swap(optional_base & that) noexcept(
                      is_nothrow_swappable<T>::value) -> CPP_ret(void)( //
                      requires Swappable<T>)
                  {
                      if(ptr_ && that.ptr_)
                          ranges::swap(*ptr_, *that.ptr_);
                      else
                          ranges::swap(ptr_, that.ptr_);
                  }
  
              protected:
                  template<typename U>
                  constexpr auto construct_from(U && ref) noexcept -> CPP_ret(T &)( //
                      requires ConvertibleTo<U &, T &>)
                  {
                      RANGES_EXPECT(!ptr_);
                      ptr_ = detail::addressof(ref);
                      return *ptr_;
                  }
                  template<typename U>
                  constexpr void assign_from(U && that)
                  {
                      if(ptr_ && that.ptr_)
                          *ptr_ = *that.ptr_;
                      else
                          ptr_ = that.ptr_;
                  }
  
              private:
                  T * ptr_ = nullptr;
              };
  
              template<typename T>
              struct optional_copy : optional_base<T>
              {
                  optional_copy() = default;
                  optional_copy(optional_copy const & that) noexcept(
                      std::is_nothrow_copy_constructible<T>::value)
                  {
                      if(that.has_value())
                          this->construct_from(*that);
                  }
                  optional_copy(optional_copy &&) = default;
                  optional_copy & operator=(optional_copy const &) = default;
                  optional_copy & operator=(optional_copy &&) = default;
  
                  using optional_base<T>::optional_base;
              };
  
              template<typename T>
              using copy_construct_layer =
                  meta::if_c<std::is_copy_constructible<T>::value &&
                                 !detail::is_trivially_copy_constructible<T>::value,
                             optional_copy<T>, optional_base<T>>;
  
              template<typename T>
              struct optional_move : copy_construct_layer<T>
              {
                  optional_move() = default;
                  optional_move(optional_move const &) = default;
                  optional_move(optional_move && that) noexcept(
                      std::is_nothrow_move_constructible<T>::value)
                  {
                      if(that.has_value())
                          this->construct_from(std::move(*that));
                  }
                  optional_move & operator=(optional_move const &) = default;
                  optional_move & operator=(optional_move &&) = default;
  
                  using copy_construct_layer<T>::copy_construct_layer;
              };
  
              template<typename T>
              using move_construct_layer =
                  meta::if_c<std::is_move_constructible<T>::value &&
                                 !detail::is_trivially_move_constructible<T>::value,
                             optional_move<T>, copy_construct_layer<T>>;
  
              template<typename T>
              struct optional_copy_assign : move_construct_layer<T>
              {
                  optional_copy_assign() = default;
                  optional_copy_assign(optional_copy_assign const &) = default;
                  optional_copy_assign(optional_copy_assign &&) = default;
                  optional_copy_assign & operator=(optional_copy_assign const & that) //
                      noexcept(std::is_nothrow_copy_constructible<T>::value &&
                                   std::is_nothrow_copy_assignable<T>::value)
                  {
                      this->assign_from(that);
                      return *this;
                  }
                  optional_copy_assign & operator=(optional_copy_assign &&) = default;
  
                  using move_construct_layer<T>::move_construct_layer;
              };
  
              template<typename T>
              struct deleted_copy_assign : move_construct_layer<T>
              {
                  deleted_copy_assign() = default;
                  deleted_copy_assign(deleted_copy_assign const &) = default;
                  deleted_copy_assign(deleted_copy_assign &&) = default;
                  deleted_copy_assign & operator=(deleted_copy_assign const &) = delete;
                  deleted_copy_assign & operator=(deleted_copy_assign &&) = default;
  
                  using move_construct_layer<T>::move_construct_layer;
              };
  
              template<typename T>
              using copy_assign_layer = meta::if_c<
                  std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
                  meta::if_c<std::is_reference<T>::value ||
                                 !(detail::is_trivially_copy_constructible<T>::value &&
                                   detail::is_trivially_copy_assignable<T>::value),
                             optional_copy_assign<T>, move_construct_layer<T>>,
                  deleted_copy_assign<T>>;
  
              template<typename T>
              struct optional_move_assign : copy_assign_layer<T>
              {
                  optional_move_assign() = default;
                  optional_move_assign(optional_move_assign const &) = default;
                  optional_move_assign(optional_move_assign &&) = default;
                  optional_move_assign & operator=(optional_move_assign const &) = default;
                  optional_move_assign & operator=(optional_move_assign && that) noexcept(
                      std::is_nothrow_move_constructible<T>::value &&
                          std::is_nothrow_move_assignable<T>::value)
                  {
                      this->assign_from(std::move(that));
                      return *this;
                  }
  
                  using copy_assign_layer<T>::copy_assign_layer;
              };
  
              template<typename T>
              struct deleted_move_assign : copy_assign_layer<T>
              {
                  deleted_move_assign() = default;
                  deleted_move_assign(deleted_move_assign const &) = default;
                  deleted_move_assign(deleted_move_assign &&) = default;
                  deleted_move_assign & operator=(deleted_move_assign const &) = default;
                  deleted_move_assign & operator=(deleted_move_assign &&) = delete;
  
                  using copy_assign_layer<T>::copy_assign_layer;
              };
  
              template<typename T>
              using move_assign_layer = meta::if_c<
                  std::is_move_constructible<T>::value && std::is_move_assignable<T>::value,
                  meta::if_c<std::is_reference<T>::value ||
                                 !(detail::is_trivially_move_constructible<T>::value &&
                                   detail::is_trivially_move_assignable<T>::value),
                             optional_move_assign<T>, copy_assign_layer<T>>,
                  deleted_move_assign<T>>;
          } // namespace optional_adl
      }     // namespace detail
      /// \endcond
  
      // clang-format off
      CPP_def
      (
          template(typename U, typename T)
          concept OptionalShouldConvert,
              requires(int)(void()) && !(
                  Constructible<T, optional<U> &       > ||
                  Constructible<T, optional<U> &&      > ||
                  Constructible<T, optional<U> const & > ||
                  Constructible<T, optional<U> const &&> ||
                  ConvertibleTo<optional<U> &,        T> ||
                  ConvertibleTo<optional<U> &&,       T> ||
                  ConvertibleTo<optional<U> const &,  T> ||
                  ConvertibleTo<optional<U> const &&, T>
              )
      );
  
      CPP_def
      (
          template(typename U, typename T)
          concept OptionalShouldConvertAssign,
              OptionalShouldConvert<U, T> &&
              !(Assignable<T &, optional<U> &> ||
              Assignable<T &, optional<U> &&> ||
              Assignable<T &, optional<U> const &> ||
              Assignable<T &, optional<U> const &&>)
      );
      // clang-format on
  
      template<typename T>
      struct optional : detail::optional_adl::move_assign_layer<T>
      {
      private:
          using base_t = detail::optional_adl::move_assign_layer<T>;
  
      public:
          CPP_assert(Destructible<T>);
          static_assert(std::is_object<T>::value || std::is_lvalue_reference<T>::value, "");
          static_assert((bool)!Same<nullopt_t, uncvref_t<T>>, "");
          static_assert((bool)!Same<in_place_t, uncvref_t<T>>, "");
          using value_type = meta::_t<std::remove_cv<T>>;
  
          constexpr optional() noexcept
          {}
          constexpr optional(nullopt_t) noexcept
            : optional{}
          {}
          optional(optional const &) = default;
          optional(optional &&) = default;
  
          using base_t::base_t;
  
          CPP_template(typename E, typename... Args)(                         //
              requires Constructible<T, std::initializer_list<E> &, Args...>) //
              constexpr explicit optional(in_place_t, std::initializer_list<E> il,
                                          Args &&... args) //
              noexcept(std::is_nothrow_constructible<T, std::initializer_list<E> &,
                                                     Args...>::value)
            : base_t(in_place, il, static_cast<Args &&>(args)...)
          {}
  
          template<typename U = T>
          constexpr CPP_ctor(optional)(U && v)( //
              requires(!defer::Same<detail::decay_t<U>, in_place_t>) &&
              (!defer::Same<detail::decay_t<U>, optional>)&&defer::Constructible<T, U> &&
              defer::ConvertibleTo<U, T>)
            : base_t(in_place, static_cast<U &&>(v))
          {}
          template<typename U = T>
          explicit constexpr CPP_ctor(optional)(U && v)( //
              requires(!defer::Same<detail::decay_t<U>, in_place_t>) &&
              (!defer::Same<detail::decay_t<U>, optional>)&&defer::Constructible<T, U> &&
              (!defer::ConvertibleTo<U, T>))
            : base_t(in_place, static_cast<U &&>(v))
          {}
  
          template<typename U>
          CPP_ctor(optional)(optional<U> const & that)( //
              requires OptionalShouldConvert<U, T> && Constructible<T, U const &> &&
                  ConvertibleTo<U const &, T>)
          {
              if(that.has_value())
                  base_t::construct_from(*that);
          }
          template<typename U>
          explicit CPP_ctor(optional)(optional<U> const & that)( //
              requires OptionalShouldConvert<U, T> && Constructible<T, U const &> &&
              (!ConvertibleTo<U const &, T>))
          {
              if(that.has_value())
                  base_t::construct_from(*that);
          }
  
          template<typename U>
          CPP_ctor(optional)(optional<U> && that)( //
              requires OptionalShouldConvert<U, T> && Constructible<T, U> &&
                  ConvertibleTo<U, T>)
          {
              if(that.has_value())
                  base_t::construct_from(detail::move(*that));
          }
          template<typename U>
          explicit CPP_ctor(optional)(optional<U> && that)( //
              requires OptionalShouldConvert<U, T> && Constructible<T, U> &&
              (!ConvertibleTo<U, T>))
          {
              if(that.has_value())
                  base_t::construct_from(detail::move(*that));
          }
  
          constexpr optional & operator=(nullopt_t) noexcept
          {
              reset();
              return *this;
          }
  
          optional & operator=(optional const &) = default;
          optional & operator=(optional &&) = default;
  
          template<typename U = T>
          constexpr auto operator=(U && u) noexcept(
              std::is_nothrow_constructible<T, U>::value &&
                  std::is_nothrow_assignable<T &, U>::value) -> CPP_ret(optional &)( //
              requires(!defer::Same<optional, detail::decay_t<U>>) &&
              (!(defer::Satisfies<T, std::is_scalar> &&
                 defer::Same<T, detail::decay_t<U>>)) &&
              defer::Constructible<T, U> && defer::Assignable<T &, U>)
          {
              if(has_value())
                  **this = static_cast<U &&>(u);
              else
                  base_t::construct_from(static_cast<U &&>(u));
              return *this;
          }
  
          template<typename U>
          constexpr auto operator=(optional<U> const & that) -> CPP_ret(optional &)( //
              requires OptionalShouldConvertAssign<U, T> && Constructible<T, const U &> &&
                  Assignable<T &, const U &>)
          {
              base_t::assign_from(that);
              return *this;
          }
  
          template<typename U>
          constexpr auto operator=(optional<U> && that) -> CPP_ret(optional &)( //
              requires OptionalShouldConvertAssign<U, T> && Constructible<T, U> &&
                  Assignable<T &, U>)
          {
              base_t::assign_from(std::move(that));
              return *this;
          }
  
          template<typename... Args>
          auto emplace(Args &&... args) noexcept(
              std::is_nothrow_constructible<T, Args...>::value) -> CPP_ret(T &)( //
              requires Constructible<T, Args...>)
          {
              reset();
              return base_t::construct_from(static_cast<Args &&>(args)...);
          }
          template<typename E, typename... Args>
          auto emplace(std::initializer_list<E> il, Args &&... args) noexcept(
              std::is_nothrow_constructible<T, std::initializer_list<E> &, Args...>::value)
              -> CPP_ret(T &)( //
                  requires Constructible<T, std::initializer_list<E> &, Args &&...>)
          {
              reset();
              return base_t::construct_from(il, static_cast<Args &&>(args)...);
          }
  
          using base_t::swap;
          using base_t::operator->;
          using base_t::operator*;
  
          constexpr explicit operator bool() const noexcept
          {
              return has_value();
          }
          using base_t::has_value;
  
          constexpr T const & value() const &
          {
              return (has_value() || detail::throw_bad_optional_access()), **this;
          }
          constexpr T & value() &
          {
              return (has_value() || detail::throw_bad_optional_access()), **this;
          }
          constexpr T const && value() const &&
          {
              return (has_value() || detail::throw_bad_optional_access()),
                     detail::move(**this);
          }
          constexpr T && value() &&
          {
              return (has_value() || detail::throw_bad_optional_access()),
                     detail::move(**this);
          }
  
          CPP_template(typename U)(                                 //
              requires CopyConstructible<T> && ConvertibleTo<U, T>) //
              constexpr T value_or(U && u) const &
          {
              return has_value() ? **this : static_cast<T>((U &&) u);
          }
          CPP_template(typename U)(                                 //
              requires MoveConstructible<T> && ConvertibleTo<U, T>) //
              constexpr T value_or(U && u) &&
          {
              return has_value() ? detail::move(**this) : static_cast<T>((U &&) u);
          }
  
          using base_t::reset;
      };
  
      /// \cond
      namespace detail
      {
          namespace optional_adl
          {
              constexpr bool convert_bool(bool b) noexcept
              {
                  return b;
              }
  
              // Relational operators [optional.relops]
              template<typename T, typename U>
              constexpr auto operator==(optional<T> const & x, optional<U> const & y) //
                  noexcept(noexcept(convert_bool(*x == *y)))
                      -> decltype(convert_bool(*x == *y))
              {
                  return x.has_value() == y.has_value() && (!x || convert_bool(*x == *y));
              }
              template<typename T, typename U>
              constexpr auto operator!=(optional<T> const & x, optional<U> const & y) //
                  noexcept(noexcept(convert_bool(*x != *y)))
                      -> decltype(convert_bool(*x != *y))
              {
                  return x.has_value() != y.has_value() || (x && convert_bool(*x != *y));
              }
              template<typename T, typename U>
              constexpr auto operator<(optional<T> const & x, optional<U> const & y) //
                  noexcept(noexcept(convert_bool(*x < *y)))
                      -> decltype(convert_bool(*x < *y))
              {
                  return y && (!x || convert_bool(*x < *y));
              }
              template<typename T, typename U>
              constexpr auto operator>(optional<T> const & x, optional<U> const & y) //
                  noexcept(noexcept(convert_bool(*x > *y)))
                      -> decltype(convert_bool(*x > *y))
              {
                  return x && (!y || convert_bool(*x > *y));
              }
              template<typename T, typename U>
              constexpr auto operator<=(optional<T> const & x, optional<U> const & y) //
                  noexcept(noexcept(convert_bool(*x <= *y)))
                      -> decltype(convert_bool(*x <= *y))
              {
                  return !x || (y && convert_bool(*x <= *y));
              }
              template<typename T, typename U>
              constexpr auto operator>=(optional<T> const & x, optional<U> const & y) //
                  noexcept(noexcept(convert_bool(*x >= *y)))
                      -> decltype(convert_bool(*x >= *y))
              {
                  return !y || (x && convert_bool(*x >= *y));
              }
  
              // Comparisons with nullopt [optional.nullops]
              template<typename T>
              constexpr bool operator==(optional<T> const & x, nullopt_t) noexcept
              {
                  return !x;
              }
              template<typename T>
              constexpr bool operator==(nullopt_t, optional<T> const & x) noexcept
              {
                  return !x;
              }
              template<typename T>
              constexpr bool operator!=(optional<T> const & x, nullopt_t) noexcept
              {
                  return !!x;
              }
              template<typename T>
              constexpr bool operator!=(nullopt_t, optional<T> const & x) noexcept
              {
                  return !!x;
              }
              template<typename T>
              constexpr bool operator<(optional<T> const &, nullopt_t) noexcept
              {
                  return false;
              }
              template<typename T>
              constexpr bool operator<(nullopt_t, optional<T> const & x) noexcept
              {
                  return !!x;
              }
              template<typename T>
              constexpr bool operator>(optional<T> const & x, nullopt_t) noexcept
              {
                  return !!x;
              }
              template<typename T>
              constexpr bool operator>(nullopt_t, optional<T> const &) noexcept
              {
                  return false;
              }
              template<typename T>
              constexpr bool operator<=(optional<T> const & x, nullopt_t) noexcept
              {
                  return !x;
              }
              template<typename T>
              constexpr bool operator<=(nullopt_t, optional<T> const &) noexcept
              {
                  return true;
              }
              template<typename T>
              constexpr bool operator>=(optional<T> const &, nullopt_t) noexcept
              {
                  return true;
              }
              template<typename T>
              constexpr bool operator>=(nullopt_t, optional<T> const & x) noexcept
              {
                  return !x;
              }
  
              // Comparisons with T [optional.comp_with_t]
              template<typename T, typename U>
              constexpr auto operator==(optional<T> const & x, U const & y) //
                  noexcept(noexcept(convert_bool(*x == y)))                 //
                  -> decltype(convert_bool(*x == y))
              {
                  return x && convert_bool(*x == y);
              }
              template<typename T, typename U>
              constexpr auto operator==(T const & x, optional<U> const & y) //
                  noexcept(noexcept(convert_bool(x == *y)))                 //
                  -> decltype(convert_bool(x == *y))
              {
                  return y && convert_bool(x == *y);
              }
              template<typename T, typename U>
              constexpr auto operator!=(optional<T> const & x, U const & y) //
                  noexcept(noexcept(convert_bool(*x != y)))                 //
                  -> decltype(convert_bool(*x != y))
              {
                  return !x || convert_bool(*x != y);
              }
              template<typename T, typename U>
              constexpr auto operator!=(T const & x, optional<U> const & y) //
                  noexcept(noexcept(convert_bool(x != *y)))                 //
                  -> decltype(convert_bool(x != *y))
              {
                  return !y || convert_bool(x != *y);
              }
              template<typename T, typename U>
              constexpr auto operator<(optional<T> const & x, U const & y) //
                  noexcept(noexcept(convert_bool(*x < y)))                 //
                  -> decltype(convert_bool(*x < y))
              {
                  return !x || convert_bool(*x < y);
              }
              template<typename T, typename U>
              constexpr auto operator<(T const & x, optional<U> const & y) //
                  noexcept(noexcept(convert_bool(x < *y)))                 //
                  -> decltype(convert_bool(x < *y))
              {
                  return y && convert_bool(x < *y);
              }
              template<typename T, typename U>
              constexpr auto operator>(optional<T> const & x, U const & y) //
                  noexcept(noexcept(convert_bool(*x > y))) -> decltype(convert_bool(*x > y))
              {
                  return x && convert_bool(*x > y);
              }
              template<typename T, typename U>
              constexpr auto operator>(T const & x, optional<U> const & y) //
                  noexcept(noexcept(convert_bool(x > *y)))                 //
                  -> decltype(convert_bool(x > *y))
              {
                  return !y || convert_bool(x > *y);
              }
              template<typename T, typename U>
              constexpr auto operator<=(optional<T> const & x, U const & y) //
                  noexcept(noexcept(convert_bool(*x <= y)))                 //
                  -> decltype(convert_bool(*x <= y))
              {
                  return !x || convert_bool(*x <= y);
              }
              template<typename T, typename U>
              constexpr auto operator<=(T const & x, optional<U> const & y) //
                  noexcept(noexcept(convert_bool(x <= *y)))                 //
                  -> decltype(convert_bool(x <= *y))
              {
                  return y && convert_bool(x <= *y);
              }
              template<typename T, typename U>
              constexpr auto operator>=(optional<T> const & x, U const & y) //
                  noexcept(noexcept(convert_bool(*x >= y)))                 //
                  -> decltype(convert_bool(*x >= y))
              {
                  return x && convert_bool(*x >= y);
              }
              template<typename T, typename U>
              constexpr auto operator>=(T const & x, optional<U> const & y) //
                  noexcept(noexcept(convert_bool(x >= *y)))                 //
                  -> decltype(convert_bool(x >= *y))
              {
                  return !y || convert_bool(x >= *y);
              }
  
              // clang-format off
              template<typename T>
              auto CPP_auto_fun(swap)(optional<T> &x, optional<T> &y)
              (
                  return x.swap(y)
              )
              // clang-format on
          } // namespace optional_adl
      }     // namespace detail
            /// \endcond
  
      // clang-format off
      template<typename T>
      constexpr auto CPP_auto_fun(make_optional)(T &&t)
      (
          return optional<detail::decay_t<T>>{static_cast<T &&>(t)}
      )
      template<typename T, typename... Args>
      constexpr auto CPP_auto_fun(make_optional)(Args &&... args)
      (
          return optional<T>{in_place, static_cast<Args &&>(args)...}
      )
      template<typename T, typename U, typename... Args>
      constexpr auto CPP_auto_fun(make_optional)(std::initializer_list<U> il,
                                                 Args &&... args)
      (
          return optional<T>{in_place, il, static_cast<Args &&>(args)...}
      )
          // clang-format on
  
          /// \cond
          namespace detail
      {
          template<typename T, typename Tag = void, bool Enable = true>
          struct non_propagating_cache : optional<T>
          {
              non_propagating_cache() = default;
              constexpr non_propagating_cache(nullopt_t) noexcept
              {}
              constexpr non_propagating_cache(non_propagating_cache const &) noexcept
                : optional<T>{}
              {}
              constexpr non_propagating_cache(non_propagating_cache && that) noexcept
                : optional<T>{}
              {
                  that.optional<T>::reset();
              }
              constexpr non_propagating_cache & operator=(
                  non_propagating_cache const &) noexcept
              {
                  optional<T>::reset();
                  return *this;
              }
              constexpr non_propagating_cache & operator=(
                  non_propagating_cache && that) noexcept
              {
                  that.optional<T>::reset();
                  optional<T>::reset();
                  return *this;
              }
              using optional<T>::operator=;
          };
  
          template<typename T, typename Tag>
          struct non_propagating_cache<T, Tag, false>
          {};
      } // namespace detail
      /// \endcond
  } // namespace ranges
  
  #endif
  