// -*- C++ -*-
//===--------------------------- tuple ------------------------------------===//
//
// 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 _LIBCUDACXX_TUPLE
#define _LIBCUDACXX_TUPLE

/*
    tuple synopsis

namespace std
{

template <class... T>
class tuple {
public:
    explicit(see-below) constexpr tuple();
    explicit(see-below) tuple(const T&...);  // constexpr in C++14
    template <class... U>
        explicit(see-below) tuple(U&&...);  // constexpr in C++14
    tuple(const tuple&) = default;
    tuple(tuple&&) = default;
    template <class... U>
        explicit(see-below) tuple(const tuple<U...>&);  // constexpr in C++14
    template <class... U>
        explicit(see-below) tuple(tuple<U...>&&);  // constexpr in C++14
    template <class U1, class U2>
        explicit(see-below) tuple(const pair<U1, U2>&); // iff sizeof...(T) == 2
// constexpr in C++14 template <class U1, class U2> explicit(see-below)
tuple(pair<U1, U2>&&); // iff sizeof...(T) == 2  // constexpr in C++14

    // allocator-extended constructors
    template <class Alloc>
        tuple(allocator_arg_t, const Alloc& a);
    template <class Alloc>
        explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const T&...);
    template <class Alloc, class... U>
        explicit(see-below) tuple(allocator_arg_t, const Alloc& a, U&&...);
    template <class Alloc>
        tuple(allocator_arg_t, const Alloc& a, const tuple&);
    template <class Alloc>
        tuple(allocator_arg_t, const Alloc& a, tuple&&);
    template <class Alloc, class... U>
        explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const
tuple<U...>&); template <class Alloc, class... U> explicit(see-below)
tuple(allocator_arg_t, const Alloc& a, tuple<U...>&&); template <class Alloc,
class U1, class U2> explicit(see-below) tuple(allocator_arg_t, const Alloc& a,
const pair<U1, U2>&); template <class Alloc, class U1, class U2>
        explicit(see-below) tuple(allocator_arg_t, const Alloc& a, pair<U1,
U2>&&);

    tuple& operator=(const tuple&);
    tuple&
        operator=(tuple&&) noexcept(AND(is_nothrow_move_assignable<T>::value
...)); template <class... U> tuple& operator=(const tuple<U...>&); template
<class... U> tuple& operator=(tuple<U...>&&); template <class U1, class U2>
        tuple& operator=(const pair<U1, U2>&); // iff sizeof...(T) == 2
    template <class U1, class U2>
        tuple& operator=(pair<U1, U2>&&); // iff sizeof...(T) == 2

    void swap(tuple&) noexcept(AND(swap(declval<T&>(), declval<T&>())...));
};

template <class ...T>
tuple(T...) -> tuple<T...>;                                         // since
C++17 template <class T1, class T2> tuple(pair<T1, T2>) -> tuple<T1, T2>; //
since C++17 template <class Alloc, class ...T> tuple(allocator_arg_t, Alloc,
T...) -> tuple<T...>;                 // since C++17 template <class Alloc,
class T1, class T2> tuple(allocator_arg_t, Alloc, pair<T1, T2>) -> tuple<T1,
T2>;       // since C++17 template <class Alloc, class ...T>
tuple(allocator_arg_t, Alloc, tuple<T...>) -> tuple<T...>;          // since
C++17

inline constexpr unspecified ignore;

template <class... T> tuple<V...>  make_tuple(T&&...); // constexpr in C++14
template <class... T> tuple<ATypes...> forward_as_tuple(T&&...) noexcept; //
constexpr in C++14 template <class... T> tuple<T&...> tie(T&...) noexcept; //
constexpr in C++14 template <class... Tuples> tuple<CTypes...>
tuple_cat(Tuples&&... tpls); // constexpr in C++14

// [tuple.apply], calling a function with a tuple of arguments:
template <class F, class Tuple>
  constexpr decltype(auto) apply(F&& f, Tuple&& t); // C++17
template <class T, class Tuple>
  constexpr T make_from_tuple(Tuple&& t); // C++17

// 20.4.1.4, tuple helper classes:
template <class T> struct tuple_size; // undefined
template <class... T> struct tuple_size<tuple<T...>>;
template <class T>
 inline constexpr size_t tuple_size_v = tuple_size<T>::value; // C++17
template <size_t I, class T> struct tuple_element; // undefined
template <size_t I, class... T> struct tuple_element<I, tuple<T...>>;
template <size_t I, class T>
  using tuple_element_t = typename tuple_element <I, T>::type; // C++14

// 20.4.1.5, element access:
template <size_t I, class... T>
    typename tuple_element<I, tuple<T...>>::type&
    get(tuple<T...>&) noexcept; // constexpr in C++14
template <size_t I, class... T>
    const typename tuple_element<I, tuple<T...>>::type&
    get(const tuple<T...>&) noexcept; // constexpr in C++14
template <size_t I, class... T>
    typename tuple_element<I, tuple<T...>>::type&&
    get(tuple<T...>&&) noexcept; // constexpr in C++14
template <size_t I, class... T>
    const typename tuple_element<I, tuple<T...>>::type&&
    get(const tuple<T...>&&) noexcept; // constexpr in C++14

template <class T1, class... T>
    constexpr T1& get(tuple<T...>&) noexcept;  // C++14
template <class T1, class... T>
    constexpr const T1& get(const tuple<T...>&) noexcept;   // C++14
template <class T1, class... T>
    constexpr T1&& get(tuple<T...>&&) noexcept;   // C++14
template <class T1, class... T>
    constexpr const T1&& get(const tuple<T...>&&) noexcept;   // C++14

// 20.4.1.6, relational operators:
template<class... T, class... U> bool operator==(const tuple<T...>&, const
tuple<U...>&); // constexpr in C++14 template<class... T, class... U> bool
operator<(const tuple<T...>&, const tuple<U...>&);  // constexpr in C++14
template<class... T, class... U> bool operator!=(const tuple<T...>&, const
tuple<U...>&); // constexpr in C++14 template<class... T, class... U> bool
operator>(const tuple<T...>&, const tuple<U...>&);  // constexpr in C++14
template<class... T, class... U> bool operator<=(const tuple<T...>&, const
tuple<U...>&); // constexpr in C++14 template<class... T, class... U> bool
operator>=(const tuple<T...>&, const tuple<U...>&); // constexpr in C++14

template <class... Types, class Alloc>
  struct uses_allocator<tuple<Types...>, Alloc>;

template <class... Types>
  void
  swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(noexcept(x.swap(y)));

}  // std

*/

#ifndef __cuda_std__
#include <__config>
#endif // __cuda_std__

#include "__assert" // all public C++ headers provide the assertion handler
#include "__functional/unwrap_ref.h"
#include "__functional_base"
#include "__fwd/array.h"
#include "__tuple_dir/apply_cv.h"
#include "__tuple_dir/make_tuple_types.h"
#include "__tuple_dir/sfinae_helpers.h"
#include "__tuple_dir/structured_bindings.h"
#include "__tuple_dir/tuple_element.h"
#include "__tuple_dir/tuple_indices.h"
#include "__tuple_dir/tuple_like.h"
#include "__tuple_dir/tuple_size.h"
#include "__tuple_dir/tuple_types.h"
#include "__type_traits/maybe_const.h"
#include "__utility/forward.h"
#include "__utility/integer_sequence.h"
#include "__utility/move.h"
#include "__utility/pair.h"
#include "__utility/piecewise_construct.h"
#include "__utility/swap.h"
#include "climits"
#include "cstddef"
#include "cstdint"
#include "type_traits"
#include "utility"

// standard-mandated includes
#include "version"

// [tuple.syn]
#ifndef _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR
#include "compare"
#endif

#ifndef __cuda_std__
#include <__pragma_push>
#endif // __cuda_std__

#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
#  pragma GCC system_header
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
#  pragma clang system_header
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
#  pragma system_header
#endif // no system header

_LIBCUDACXX_BEGIN_NAMESPACE_STD

// __tuple_leaf
struct __tuple_leaf_default_constructor_tag {};

template <size_t _Ip, class _Hp,
          bool = _LIBCUDACXX_TRAIT(is_empty, _Hp) &&
                 !__libcpp_is_final<_Hp>::value>
class __tuple_leaf;

template <size_t _Ip, class _Hp, bool _Ep>
inline _LIBCUDACXX_INLINE_VISIBILITY void
swap(__tuple_leaf<_Ip, _Hp, _Ep> &__x,
     __tuple_leaf<_Ip, _Hp, _Ep>
         &__y) noexcept(__is_nothrow_swappable<_Hp>::value) {
  swap(__x.get(), __y.get());
}

template <size_t _Ip, class _Hp, bool> class __tuple_leaf {
  _Hp __value_;

  template <class _Tp>
  _LIBCUDACXX_INLINE_VISIBILITY static constexpr bool __can_bind_reference() {
#if __has_keyword(__reference_binds_to_temporary)
    return !__reference_binds_to_temporary(_Hp, _Tp);
#else
    return true;
#endif
  }

  _LIBCUDACXX_INLINE_VISIBILITY __tuple_leaf &operator=(const __tuple_leaf &);

public:
  _LIBCUDACXX_INLINE_VISIBILITY constexpr __tuple_leaf() noexcept(
      _LIBCUDACXX_TRAIT(is_nothrow_default_constructible, _Hp))
      : __value_() {
    static_assert(
        !_LIBCUDACXX_TRAIT(is_reference, _Hp),
        "Attempted to default construct a reference element in a tuple");
  }

  _LIBCUDACXX_INLINE_VISIBILITY constexpr __tuple_leaf(
      __tuple_leaf_default_constructor_tag) noexcept(_LIBCUDACXX_TRAIT(is_nothrow_default_constructible,
                                                                       _Hp))
      : __value_() {
    static_assert(
        !_LIBCUDACXX_TRAIT(is_reference, _Hp),
        "Attempted to default construct a reference element in a tuple");
  }

  template <class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY __tuple_leaf(integral_constant<int, 0>,
                                             const _Alloc &)
      : __value_() {
    static_assert(
        !_LIBCUDACXX_TRAIT(is_reference, _Hp),
        "Attempted to default construct a reference element in a tuple");
  }

  template <class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY __tuple_leaf(integral_constant<int, 1>,
                                             const _Alloc &__a)
      : __value_(allocator_arg_t(), __a) {
    static_assert(
        !_LIBCUDACXX_TRAIT(is_reference, _Hp),
        "Attempted to default construct a reference element in a tuple");
  }

  template <class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY __tuple_leaf(integral_constant<int, 2>,
                                             const _Alloc &__a)
      : __value_(__a) {
    static_assert(
        !_LIBCUDACXX_TRAIT(is_reference, _Hp),
        "Attempted to default construct a reference element in a tuple");
  }

  template <class _Tp>
  using __can_forward = _And<_IsNotSame<__remove_cvref_t<_Tp>, __tuple_leaf>,
                             is_constructible<_Hp, _Tp>>;

  template <class _Tp, __enable_if_t<__can_forward<_Tp>::value, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY
      _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 explicit __tuple_leaf(
          _Tp &&__t) noexcept(_LIBCUDACXX_TRAIT(is_nothrow_constructible, _Hp,
                                                _Tp))
      : __value_(_CUDA_VSTD::forward<_Tp>(__t)) {
    static_assert(__can_bind_reference<_Tp &&>(),
                  "Attempted construction of reference element binds to a "
                  "temporary whose lifetime has ended");
  }

  template <class _Tp, class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY explicit __tuple_leaf(integral_constant<int, 0>,
                                                      const _Alloc &, _Tp &&__t)
      : __value_(_CUDA_VSTD::forward<_Tp>(__t)) {
    static_assert(__can_bind_reference<_Tp &&>(),
                  "Attempted construction of reference element binds to a "
                  "temporary whose lifetime has ended");
  }

  template <class _Tp, class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY explicit __tuple_leaf(integral_constant<int, 1>,
                                                      const _Alloc &__a,
                                                      _Tp &&__t)
      : __value_(allocator_arg_t(), __a, _CUDA_VSTD::forward<_Tp>(__t)) {
    static_assert(
        !_LIBCUDACXX_TRAIT(is_reference, _Hp),
        "Attempted to uses-allocator construct a reference element in a tuple");
  }

  template <class _Tp, class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY explicit __tuple_leaf(integral_constant<int, 2>,
                                                      const _Alloc &__a,
                                                      _Tp &&__t)
      : __value_(_CUDA_VSTD::forward<_Tp>(__t), __a) {
    static_assert(
        !_LIBCUDACXX_TRAIT(is_reference, _Hp),
        "Attempted to uses-allocator construct a reference element in a tuple");
  }

  __tuple_leaf(const __tuple_leaf &__t) = default;
  __tuple_leaf(__tuple_leaf &&__t) = default;

  template <class _Tp>
  _LIBCUDACXX_INLINE_VISIBILITY __tuple_leaf &operator=(_Tp &&__t) noexcept(
      _LIBCUDACXX_TRAIT(is_nothrow_assignable, _Hp &, _Tp)) {
    __value_ = _CUDA_VSTD::forward<_Tp>(__t);
    return *this;
  }

  _LIBCUDACXX_INLINE_VISIBILITY int swap(__tuple_leaf &__t) noexcept(
      __is_nothrow_swappable<__tuple_leaf>::value) {
    _CUDA_VSTD::swap(*this, __t);
    return 0;
  }

  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 _Hp &
  get() noexcept {
    return __value_;
  }
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 const _Hp &
  get() const noexcept {
    return __value_;
  }
};

template <size_t _Ip, class _Hp>
class __tuple_leaf<_Ip, _Hp, true> : private _Hp {
  _LIBCUDACXX_INLINE_VISIBILITY __tuple_leaf &operator=(const __tuple_leaf &);

public:
  _LIBCUDACXX_INLINE_VISIBILITY constexpr __tuple_leaf() noexcept(
      is_nothrow_default_constructible<_Hp>::value) {}

  _LIBCUDACXX_INLINE_VISIBILITY constexpr __tuple_leaf(
      __tuple_leaf_default_constructor_tag) noexcept(_LIBCUDACXX_TRAIT(is_nothrow_default_constructible,
                                                                       _Hp))
      : _Hp() {}

  template <class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY __tuple_leaf(integral_constant<int, 0>,
                                             const _Alloc &) {}

  template <class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY __tuple_leaf(integral_constant<int, 1>,
                                             const _Alloc &__a)
      : _Hp(allocator_arg_t(), __a) {}

  template <class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY __tuple_leaf(integral_constant<int, 2>,
                                             const _Alloc &__a)
      : _Hp(__a) {}

  template <class _Tp>
  using __can_forward = _And<_IsNotSame<__remove_cvref_t<_Tp>, __tuple_leaf>,
                             is_constructible<_Hp, _Tp>>;

  template <class _Tp, __enable_if_t<__can_forward<_Tp>::value, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY
      _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 explicit __tuple_leaf(
          _Tp &&__t) noexcept((is_nothrow_constructible<_Hp, _Tp>::value))
      : _Hp(_CUDA_VSTD::forward<_Tp>(__t)) {}

  template <class _Tp, class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY explicit __tuple_leaf(integral_constant<int, 0>,
                                                      const _Alloc &, _Tp &&__t)
      : _Hp(_CUDA_VSTD::forward<_Tp>(__t)) {}

  template <class _Tp, class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY explicit __tuple_leaf(integral_constant<int, 1>,
                                                      const _Alloc &__a,
                                                      _Tp &&__t)
      : _Hp(allocator_arg_t(), __a, _CUDA_VSTD::forward<_Tp>(__t)) {}

  template <class _Tp, class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY explicit __tuple_leaf(integral_constant<int, 2>,
                                                      const _Alloc &__a,
                                                      _Tp &&__t)
      : _Hp(_CUDA_VSTD::forward<_Tp>(__t), __a) {}

  __tuple_leaf(__tuple_leaf const &) = default;
  __tuple_leaf(__tuple_leaf &&) = default;

  template <class _Tp>
  _LIBCUDACXX_INLINE_VISIBILITY __tuple_leaf &operator=(_Tp &&__t) noexcept(
      _LIBCUDACXX_TRAIT(is_nothrow_assignable, _Hp &, _Tp)) {
    _Hp::operator=(_CUDA_VSTD::forward<_Tp>(__t));
    return *this;
  }

  _LIBCUDACXX_INLINE_VISIBILITY int swap(__tuple_leaf &__t) noexcept(
      __is_nothrow_swappable<__tuple_leaf>::value) {
    _CUDA_VSTD::swap(*this, __t);
    return 0;
  }

  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 _Hp &
  get() noexcept {
    return static_cast<_Hp &>(*this);
  }
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 const _Hp &
  get() const noexcept {
    return static_cast<const _Hp &>(*this);
  }
};

template <class... _Tp>
_LIBCUDACXX_INLINE_VISIBILITY void __swallow(_Tp &&...) noexcept {}

template <class _Tp> struct __all_default_constructible;

template <class... _Tp>
struct __all_default_constructible<__tuple_types<_Tp...>>
    : __all<_LIBCUDACXX_TRAIT(is_default_constructible, _Tp)...> {};

struct __tuple_variadic_constructor_tag {};

// __tuple_impl

template <class _Indx, class... _Tp> struct __tuple_impl;

template <size_t... _Indx, class... _Tp>
struct _LIBCUDACXX_DECLSPEC_EMPTY_BASES
    __tuple_impl<__tuple_indices<_Indx...>, _Tp...>
    : public __tuple_leaf<_Indx, _Tp>... {
  _LIBCUDACXX_INLINE_VISIBILITY constexpr __tuple_impl() noexcept(
      __all<_LIBCUDACXX_TRAIT(is_nothrow_default_constructible,
                              _Tp)...>::value) {}

  // Handle non-allocator, full initialization
  // Old MSVC cannot handle the noexept specifier outside of template arguments
  template <class... _Up,
            __enable_if_t<sizeof...(_Up) == sizeof...(_Tp), int> = 0,
            bool __all_nothrow_constructible = __all<_LIBCUDACXX_TRAIT(
                is_nothrow_constructible, _Tp, _Up)...>::value>
  _LIBCUDACXX_INLINE_VISIBILITY
      _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 explicit __tuple_impl(
          __tuple_variadic_constructor_tag,
          _Up &&...__u) noexcept(__all_nothrow_constructible)
      : __tuple_leaf<_Indx, _Tp>(_CUDA_VSTD::forward<_Up>(__u))... {}

  // Handle non-allocator, partial default initialization
  // Recursively delegate until we have full rank
  template <class... _Up,
            __enable_if_t<sizeof...(_Up) < sizeof...(_Tp), int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 explicit __tuple_impl(
      __tuple_variadic_constructor_tag __tag,
      _Up &&...__u) noexcept(noexcept(__tuple_impl(__tag,
                                                   _CUDA_VSTD::forward<_Up>(
                                                       __u)...,
                                                   __tuple_leaf_default_constructor_tag{})))
      : __tuple_impl(__tag, _CUDA_VSTD::forward<_Up>(__u)...,
                     __tuple_leaf_default_constructor_tag{}) {}

  // Handle allocator aware, full initialization
  template <class _Alloc, class... _Up,
            __enable_if_t<sizeof...(_Up) == sizeof...(_Tp), int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY explicit __tuple_impl(
      allocator_arg_t, const _Alloc &__a, __tuple_variadic_constructor_tag,
      _Up &&...__u)
      : __tuple_leaf<_Indx, _Tp>(__uses_alloc_ctor<_Tp, _Alloc, _Up>(), __a,
                                 _CUDA_VSTD::forward<_Up>(__u))... {}

  // Handle allocator aware, full default initialization
  template <class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY explicit __tuple_impl(allocator_arg_t,
                                                      const _Alloc &__a)
      : __tuple_leaf<_Indx, _Tp>(__uses_alloc_ctor<_Tp, _Alloc>(), __a)... {}

  template <class _Tuple, size_t _Indx2>
  using __tuple_elem_at =
      __tuple_element_t<_Indx2, __make_tuple_types_t<_Tuple>>;

  template <class _Tuple,
            __enable_if_t<__tuple_constructible<_Tuple, tuple<_Tp...>>::value,
                          int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11
  __tuple_impl(_Tuple &&__t) noexcept(
      (__all<_LIBCUDACXX_TRAIT(is_nothrow_constructible, _Tp,
                               __tuple_elem_at<_Tuple, _Indx>)...>::value))
      : __tuple_leaf<_Indx, _Tp>(
            _CUDA_VSTD::forward<__tuple_elem_at<_Tuple, _Indx>>(
                _CUDA_VSTD::get<_Indx>(__t)))... {}

  template <class _Alloc, class _Tuple,
            __enable_if_t<__tuple_constructible<_Tuple, tuple<_Tp...>>::value,
                          int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY __tuple_impl(allocator_arg_t, const _Alloc &__a,
                                             _Tuple &&__t)
      : __tuple_leaf<_Indx, _Tp>(
            __uses_alloc_ctor<_Tp, _Alloc, __tuple_elem_at<_Tuple, _Indx>>(),
            __a,
            _CUDA_VSTD::forward<__tuple_elem_at<_Tuple, _Indx>>(
                _CUDA_VSTD::get<_Indx>(__t)))... {}

  template <
      class _Tuple,
      __enable_if_t<__tuple_assignable<_Tuple, tuple<_Tp...>>::value, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY __tuple_impl &operator=(_Tuple &&__t) noexcept(
      (__all<_LIBCUDACXX_TRAIT(is_nothrow_assignable, _Tp &,
                               __tuple_elem_at<_Tuple, _Indx>)...>::value)) {
    __swallow(__tuple_leaf<_Indx, _Tp>::operator=(
        _CUDA_VSTD::forward<__tuple_elem_at<_Tuple, _Indx>>(
            _CUDA_VSTD::get<_Indx>(__t)))...);
    return *this;
  }

  __tuple_impl(const __tuple_impl &) = default;
  __tuple_impl(__tuple_impl &&) = default;

  _LIBCUDACXX_INLINE_VISIBILITY __tuple_impl &
  operator=(const __tuple_impl &__t) noexcept(
      (__all<_LIBCUDACXX_TRAIT(is_nothrow_copy_assignable, _Tp)...>::value)) {
    __swallow(__tuple_leaf<_Indx, _Tp>::operator=(
        static_cast<const __tuple_leaf<_Indx, _Tp> &>(__t).get())...);
    return *this;
  }

  _LIBCUDACXX_INLINE_VISIBILITY __tuple_impl &
  operator=(__tuple_impl &&__t) noexcept(
      (__all<_LIBCUDACXX_TRAIT(is_nothrow_move_assignable, _Tp)...>::value)) {
    __swallow(__tuple_leaf<_Indx, _Tp>::operator=(_CUDA_VSTD::forward<_Tp>(
        static_cast<__tuple_leaf<_Indx, _Tp> &>(__t).get()))...);
    return *this;
  }

  _LIBCUDACXX_INLINE_VISIBILITY void swap(__tuple_impl &__t) noexcept(
      __all<__is_nothrow_swappable<_Tp>::value...>::value) {
    __swallow(__tuple_leaf<_Indx, _Tp>::swap(
        static_cast<__tuple_leaf<_Indx, _Tp> &>(__t))...);
  }
};

struct __invalid_tuple_constraints {
  static constexpr bool __implicit_constructible = false;
  static constexpr bool __explicit_constructible = false;
  static constexpr bool __nothrow_constructible = false;
};

template <class... _Tp> struct __tuple_constraints {
  static constexpr bool __implicit_default_constructible =
      __all<__is_implicitly_default_constructible<_Tp>::value...>::value;

  static constexpr bool __explicit_default_constructible =
      !__implicit_default_constructible &&
      __all<_LIBCUDACXX_TRAIT(is_default_constructible, _Tp)...>::value;

  static constexpr bool __nothrow_default_constructible =
      __all<_LIBCUDACXX_TRAIT(is_nothrow_default_constructible, _Tp)...>::value;

  static constexpr bool __implicit_variadic_copy_constructible =
      __tuple_constructible<tuple<const _Tp &...>, tuple<_Tp...>>::value &&
      __tuple_convertible<tuple<const _Tp &...>, tuple<_Tp...>>::value;

  static constexpr bool __explicit_variadic_copy_constructible =
      __tuple_constructible<tuple<const _Tp &...>, tuple<_Tp...>>::value &&
      !__tuple_convertible<tuple<const _Tp &...>, tuple<_Tp...>>::value;

  static constexpr bool __nothrow_variadic_copy_constructible =
      __all<_LIBCUDACXX_TRAIT(is_nothrow_copy_constructible, _Tp)...>::value;

  template <class... _Args> struct _PackExpandsToThisTuple : false_type {};

  template <class _Arg>
  struct _PackExpandsToThisTuple<_Arg>
      : is_same<__remove_cvref_t<_Arg>, tuple<_Tp...>> {};

  template <class... _Args> struct __variadic_constraints {
    static constexpr bool __implicit_constructible =
        __tuple_constructible<tuple<_Args...>, tuple<_Tp...>>::value &&
        __tuple_convertible<tuple<_Args...>, tuple<_Tp...>>::value;

    static constexpr bool __explicit_constructible =
        __tuple_constructible<tuple<_Args...>, tuple<_Tp...>>::value &&
        !__tuple_convertible<tuple<_Args...>, tuple<_Tp...>>::value;

    static constexpr bool __nothrow_constructible = __all<_LIBCUDACXX_TRAIT(
        is_nothrow_constructible, _Tp, _Args)...>::value;
  };

  template <class... _Args> struct __variadic_constraints_less_rank {
    static constexpr bool __implicit_constructible =
        __tuple_constructible<
            tuple<_Args...>,
            __make_tuple_types_t<tuple<_Tp...>, sizeof...(_Args)>>::value &&
        __tuple_convertible<
            tuple<_Args...>,
            __make_tuple_types_t<tuple<_Tp...>, sizeof...(_Args)>>::value &&
        __all_default_constructible<__make_tuple_types_t<
            tuple<_Tp...>, sizeof...(_Tp), sizeof...(_Args)>>::value;

    static constexpr bool __explicit_constructible =
        __tuple_constructible<
            tuple<_Args...>,
            __make_tuple_types_t<tuple<_Tp...>, sizeof...(_Args)>>::value &&
        !__tuple_convertible<
            tuple<_Args...>,
            __make_tuple_types_t<tuple<_Tp...>, sizeof...(_Args)>>::value &&
        __all_default_constructible<__make_tuple_types_t<
            tuple<_Tp...>, sizeof...(_Tp), sizeof...(_Args)>>::value;
  };

  template <class _Tuple> struct __valid_tuple_like_constraints {
    static constexpr bool __implicit_constructible =
        __tuple_constructible<_Tuple, tuple<_Tp...>>::value &&
        __tuple_convertible<_Tuple, tuple<_Tp...>>::value;

    static constexpr bool __explicit_constructible =
        __tuple_constructible<_Tuple, tuple<_Tp...>>::value &&
        !__tuple_convertible<_Tuple, tuple<_Tp...>>::value;
  };

  template <class _Tuple> struct __valid_tuple_like_constraints_rank_one {
    template <class _Tuple2>
    struct _PreferTupleLikeConstructorImpl
        : _Or<
              // Don't attempt the two checks below if the tuple we are given
              // has the same type as this tuple.
              _IsSame<__remove_cvref_t<_Tuple2>, tuple<_Tp...>>,
              _Lazy<_And, _Not<is_constructible<_Tp..., _Tuple2>>,
                    _Not<is_convertible<_Tuple2, _Tp...>>>> {};

    // This trait is used to disable the tuple-like constructor when
    // the UTypes... constructor should be selected instead.
    // See LWG issue #2549.
    template <class _Tuple2>
    using _PreferTupleLikeConstructor =
        _PreferTupleLikeConstructorImpl<_Tuple2>;

    static constexpr bool __implicit_constructible =
        __tuple_constructible<_Tuple, tuple<_Tp...>>::value &&
        __tuple_convertible<_Tuple, tuple<_Tp...>>::value &&
        _PreferTupleLikeConstructor<_Tuple>::value;

    static constexpr bool __explicit_constructible =
        __tuple_constructible<_Tuple, tuple<_Tp...>>::value &&
        !__tuple_convertible<_Tuple, tuple<_Tp...>>::value &&
        _PreferTupleLikeConstructor<_Tuple>::value;
  };

  template <class _Tuple>
  using __tuple_like_constraints =
      _If<sizeof...(_Tp) == 1, __valid_tuple_like_constraints_rank_one<_Tuple>,
          __valid_tuple_like_constraints<_Tuple>>;
};

template <class... _Tp> class _LIBCUDACXX_TEMPLATE_VIS tuple {
  typedef __tuple_impl<__make_tuple_indices_t<sizeof...(_Tp)>, _Tp...> _BaseT;

  _BaseT __base_;

  template <class... _Args> struct _PackExpandsToThisTuple : false_type {};

  template <class _Arg>
  struct _PackExpandsToThisTuple<_Arg>
      : is_same<__remove_cvref_t<_Arg>, tuple> {};

public:
  template <size_t _Ip>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 __tuple_element_t<_Ip, tuple>&
  __get_impl() & noexcept
  {
    typedef _LIBCUDACXX_NODEBUG_TYPE __tuple_element_t<_Ip, tuple> type;
    return static_cast<__tuple_leaf<_Ip, type>&>(__base_).get();
  }

  template <size_t _Ip>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 const __tuple_element_t<_Ip, tuple>&
  __get_impl() const& noexcept
  {
    typedef _LIBCUDACXX_NODEBUG_TYPE __tuple_element_t<_Ip, tuple> type;
    return static_cast<const __tuple_leaf<_Ip, type>&>(__base_).get();
  }

  template <size_t _Ip>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 __tuple_element_t<_Ip, tuple>&&
  __get_impl() && noexcept
  {
    typedef _LIBCUDACXX_NODEBUG_TYPE __tuple_element_t<_Ip, tuple> type;
    return static_cast<type&&>(static_cast<__tuple_leaf<_Ip, type>&&>(__base_).get());
  }

  template <size_t _Ip>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 const __tuple_element_t<_Ip, tuple>&&
  __get_impl() const&& noexcept
  {
    typedef _LIBCUDACXX_NODEBUG_TYPE __tuple_element_t<_Ip, tuple> type;
    return static_cast<const type&&>(static_cast<const __tuple_leaf<_Ip, type>&&>(__base_).get());
  }

  template < class _Constraints                                          = __tuple_constraints<_Tp...>,
      __enable_if_t<_Constraints::__implicit_default_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY constexpr tuple() noexcept(
      _Constraints::__nothrow_default_constructible) {}

  template <
      class _Constraints = __tuple_constraints<_Tp...>,
      __enable_if_t<_Constraints::__explicit_default_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY explicit constexpr tuple() noexcept(
      _Constraints::__nothrow_default_constructible) {}

  tuple(tuple const &) = default;
  tuple(tuple &&) = default;

  template <
      class _AllocArgT, class _Alloc,
      class _Constraints = __tuple_constraints<_Tp...>,
      __enable_if_t<_LIBCUDACXX_TRAIT(is_same, allocator_arg_t, _AllocArgT),
                    int> = 0,
      __enable_if_t<_Constraints::__implicit_default_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY tuple(_AllocArgT, _Alloc const &__a) noexcept(
      _Constraints::__nothrow_default_constructible)
      : __base_(allocator_arg_t(), __a) {}

  template <
      class _AllocArgT, class _Alloc,
      class _Constraints = __tuple_constraints<_Tp...>,
      __enable_if_t<_LIBCUDACXX_TRAIT(is_same, allocator_arg_t, _AllocArgT),
                    int> = 0,
      __enable_if_t<_Constraints::__explicit_default_constructible, int> = 0>
  explicit _LIBCUDACXX_INLINE_VISIBILITY tuple(
      _AllocArgT,
      _Alloc const &__a) noexcept(_Constraints::__nothrow_default_constructible)
      : __base_(allocator_arg_t(), __a) {}

  template <class _Constraints = __tuple_constraints<_Tp...>,
            __enable_if_t<_Constraints::__implicit_variadic_copy_constructible,
                          int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11
  tuple(const _Tp &...__t) noexcept(
      _Constraints::__nothrow_variadic_copy_constructible)
      : __base_(__tuple_variadic_constructor_tag{}, __t...) {}

  template <class _Constraints = __tuple_constraints<_Tp...>,
            __enable_if_t<_Constraints::__explicit_variadic_copy_constructible,
                          int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY
      _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 explicit tuple(
          const _Tp &...__t) noexcept(_Constraints::
                                          __nothrow_variadic_copy_constructible)
      : __base_(__tuple_variadic_constructor_tag{}, __t...) {}

  template <class _Alloc, class _Constraints = __tuple_constraints<_Tp...>,
            __enable_if_t<_Constraints::__implicit_variadic_copy_constructible,
                          int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY
  tuple(allocator_arg_t, const _Alloc &__a, const _Tp &...__t) noexcept(
      _Constraints::__nothrow_variadic_copy_constructible)
      : __base_(allocator_arg_t(), __a, __tuple_variadic_constructor_tag{},
                __t...) {}

  template <class _Alloc, class _Constraints = __tuple_constraints<_Tp...>,
            __enable_if_t<_Constraints::__explicit_variadic_copy_constructible,
                          int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY explicit tuple(
      allocator_arg_t, const _Alloc &__a,
      const _Tp
          &...__t) noexcept(_Constraints::__nothrow_variadic_copy_constructible)
      : __base_(allocator_arg_t(), __a, __tuple_variadic_constructor_tag{},
                __t...) {}

#if defined(_LIBCUDACXX_NO_TUPLE_NOEXCEPT)
  template <class... _Vp> using __base_noexcept_constructible = false_type;
#else
  template <class... _Vp>
  using __base_noexcept_constructible =
      is_nothrow_constructible<_BaseT, _Vp...>;
#endif // defined(_LIBCUDACXX_NO_TUPLE_NOEXCEPT)

  template <class... _Up>
  using __variadic_constraints =
      _If<!_PackExpandsToThisTuple<_Up...>::value &&
              sizeof...(_Up) == sizeof...(_Tp),
          typename __tuple_constraints<_Tp...>::template __variadic_constraints<
              _Up...>,
          __invalid_tuple_constraints>;

  template <class... _Up, class _Constraints = __variadic_constraints<_Up...>,
            __enable_if_t<_Constraints::__implicit_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11
  tuple(_Up &&...__u) noexcept(_Constraints::__nothrow_constructible)
      : __base_(__tuple_variadic_constructor_tag{},
                _CUDA_VSTD::forward<_Up>(__u)...) {}

  template <class... _Up, class _Constraints = __variadic_constraints<_Up...>,
            __enable_if_t<_Constraints::__explicit_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY
      _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 explicit tuple(_Up &&...__u) noexcept(
          _Constraints::__nothrow_constructible)
      : __base_(__tuple_variadic_constructor_tag{},
                _CUDA_VSTD::forward<_Up>(__u)...) {}

  template <class... _Up>
  using __variadic_constraints_less_rank =
      _If<!_PackExpandsToThisTuple<_Up...>::value,
          typename __tuple_constraints<
              _Tp...>::template __variadic_constraints_less_rank<_Up...>,
          __invalid_tuple_constraints>;

  template <class... _Up,
            class _Constraints = __variadic_constraints_less_rank<_Up...>,
            __enable_if_t<sizeof...(_Up) < sizeof...(_Tp), int> = 0,
            __enable_if_t<_Constraints::__implicit_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY
      _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 explicit tuple(_Up &&...__u) noexcept(
          __base_noexcept_constructible<__tuple_variadic_constructor_tag,
                                        _Up...>::value)
      : __base_(__tuple_variadic_constructor_tag{},
                _CUDA_VSTD::forward<_Up>(__u)...) {}

  template <class _Alloc, class... _Up,
            class _Constraints = __variadic_constraints<_Up...>,
            __enable_if_t<_Constraints::__implicit_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY
  tuple(allocator_arg_t, const _Alloc &__a,
        _Up &&...__u) noexcept(_Constraints::__nothrow_constructible)
      : __base_(allocator_arg_t(), __a, __tuple_variadic_constructor_tag{},
                _CUDA_VSTD::forward<_Up>(__u)...) {}

  template <class _Alloc, class... _Up,
            class _Constraints = __variadic_constraints<_Up...>,
            __enable_if_t<_Constraints::__explicit_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY explicit tuple(
      allocator_arg_t, const _Alloc &__a,
      _Up &&...__u) noexcept(_Constraints::__nothrow_constructible)
      : __base_(allocator_arg_t(), __a, __tuple_variadic_constructor_tag{},
                _CUDA_VSTD::forward<_Up>(__u)...) {}

  template <class _Tuple>
  using __tuple_like_constraints =
      _If<__tuple_like_with_size<_Tuple, sizeof...(_Tp)>::value,
          typename __tuple_constraints<
              _Tp...>::template __tuple_like_constraints<_Tuple>,
          __invalid_tuple_constraints>;

  template <
      class _Tuple, class _Constraints = __tuple_like_constraints<_Tuple>,
      __enable_if_t<!_PackExpandsToThisTuple<_Tuple>::value, int> = 0,
      __enable_if_t<!_LIBCUDACXX_TRAIT(is_lvalue_reference, _Tuple), int> = 0,
      __enable_if_t<_Constraints::__implicit_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11
  tuple(_Tuple &&__t) noexcept(_LIBCUDACXX_TRAIT(is_nothrow_constructible,
                                                 _BaseT, _Tuple))
      : __base_(_CUDA_VSTD::forward<_Tuple>(__t)) {}

  template <class _Tuple,
            class _Constraints = __tuple_like_constraints<const _Tuple &>,
            __enable_if_t<!_PackExpandsToThisTuple<_Tuple>::value, int> = 0,
            __enable_if_t<_Constraints::__implicit_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11
  tuple(const _Tuple &__t) noexcept(_LIBCUDACXX_TRAIT(is_nothrow_constructible,
                                                      _BaseT, const _Tuple &))
      : __base_(__t) {}

  template <
      class _Tuple, class _Constraints = __tuple_like_constraints<_Tuple>,
      __enable_if_t<!_PackExpandsToThisTuple<_Tuple>::value, int> = 0,
      __enable_if_t<!_LIBCUDACXX_TRAIT(is_lvalue_reference, _Tuple), int> = 0,
      __enable_if_t<_Constraints::__explicit_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY
      _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 explicit tuple(_Tuple &&__t) noexcept(
          _LIBCUDACXX_TRAIT(is_nothrow_constructible, _BaseT, _Tuple))
      : __base_(_CUDA_VSTD::forward<_Tuple>(__t)) {}

  template <class _Tuple,
            class _Constraints = __tuple_like_constraints<const _Tuple &>,
            __enable_if_t<!_PackExpandsToThisTuple<_Tuple>::value, int> = 0,
            __enable_if_t<_Constraints::__explicit_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY
      _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 explicit tuple(
          const _Tuple
              &__t) noexcept(_LIBCUDACXX_TRAIT(is_nothrow_constructible, _BaseT,
                                               const _Tuple &))
      : __base_(__t) {}

  template <class _Alloc, class _Tuple,
            class _Constraints = __tuple_like_constraints<_Tuple>,
            __enable_if_t<_Constraints::__implicit_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY tuple(allocator_arg_t, const _Alloc &__a,
                                      _Tuple &&__t)
      : __base_(allocator_arg_t(), __a, _CUDA_VSTD::forward<_Tuple>(__t)) {}

  template <class _Alloc, class _Tuple,
            class _Constraints = __tuple_like_constraints<_Tuple>,
            __enable_if_t<_Constraints::__explicit_constructible, int> = 0>
  _LIBCUDACXX_INLINE_VISIBILITY explicit tuple(allocator_arg_t,
                                               const _Alloc &__a, _Tuple &&__t)
      : __base_(allocator_arg_t(), __a, _CUDA_VSTD::forward<_Tuple>(__t)) {}

  using _CanCopyAssign = __all<_LIBCUDACXX_TRAIT(is_copy_assignable, _Tp)...>;
  using _CanMoveAssign = __all<_LIBCUDACXX_TRAIT(is_move_assignable, _Tp)...>;

  _LIBCUDACXX_INLINE_VISIBILITY tuple &operator=(
      __conditional_t<_CanCopyAssign::value, tuple, __nat> const
          &__t) noexcept((__all<_LIBCUDACXX_TRAIT(is_nothrow_copy_assignable,
                                                  _Tp)...>::value)) {
    __base_.operator=(__t.__base_);
    return *this;
  }

  _LIBCUDACXX_INLINE_VISIBILITY tuple &operator=(
      __conditional_t<_CanMoveAssign::value, tuple, __nat>
          &&__t) noexcept((__all<_LIBCUDACXX_TRAIT(is_nothrow_move_assignable,
                                                   _Tp)...>::value)) {
    __base_.operator=(static_cast<_BaseT &&>(__t.__base_));
    return *this;
  }

  template <
      class _Tuple,
      __enable_if_t<__tuple_assignable<_Tuple, tuple>::value, bool> = false>
  _LIBCUDACXX_INLINE_VISIBILITY tuple &operator=(_Tuple &&__t) noexcept(
      _LIBCUDACXX_TRAIT(is_nothrow_assignable, _BaseT &, _Tuple)) {
    __base_.operator=(_CUDA_VSTD::forward<_Tuple>(__t));
    return *this;
  }

  _LIBCUDACXX_INLINE_VISIBILITY void swap(tuple &__t) noexcept(
      __all<__is_nothrow_swappable<_Tp>::value...>::value) {
    __base_.swap(__t.__base_);
  }
};

template <> class _LIBCUDACXX_TEMPLATE_VIS tuple<> {
public:
  constexpr tuple() noexcept = default;
  template <class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY tuple(allocator_arg_t,
                                      const _Alloc &) noexcept {}
  template <class _Alloc>
  _LIBCUDACXX_INLINE_VISIBILITY tuple(allocator_arg_t, const _Alloc &,
                                      const tuple &) noexcept {}
  template <class _Up>
  _LIBCUDACXX_INLINE_VISIBILITY tuple(array<_Up, 0>) noexcept {}
  template <class _Alloc, class _Up>
  _LIBCUDACXX_INLINE_VISIBILITY tuple(allocator_arg_t, const _Alloc &,
                                      array<_Up, 0>) noexcept {}
  _LIBCUDACXX_INLINE_VISIBILITY void swap(tuple &) noexcept {}
};

#ifndef _LIBCUDACXX_HAS_NO_DEDUCTION_GUIDES
template <class... _Tp> _LIBCUDACXX_HOST_DEVICE tuple(_Tp...) -> tuple<_Tp...>;
template <class _Tp1, class _Tp2>
_LIBCUDACXX_HOST_DEVICE tuple(pair<_Tp1, _Tp2>) -> tuple<_Tp1, _Tp2>;
template <class _Alloc, class... _Tp>
_LIBCUDACXX_HOST_DEVICE tuple(allocator_arg_t, _Alloc, _Tp...) -> tuple<_Tp...>;
template <class _Alloc, class _Tp1, class _Tp2>
_LIBCUDACXX_HOST_DEVICE tuple(allocator_arg_t, _Alloc, pair<_Tp1, _Tp2>)
    -> tuple<_Tp1, _Tp2>;
template <class _Alloc, class... _Tp>
_LIBCUDACXX_HOST_DEVICE tuple(allocator_arg_t, _Alloc, tuple<_Tp...>)
    -> tuple<_Tp...>;
#endif // _LIBCUDACXX_HAS_NO_DEDUCTION_GUIDES

template <class... _Tp>
inline _LIBCUDACXX_INLINE_VISIBILITY
    __enable_if_t<_And<__is_swappable<_Tp>...>::value, void>
    swap(tuple<_Tp...> &__t, tuple<_Tp...> &__u) noexcept(
        __all<__is_nothrow_swappable<_Tp>::value...>::value) {
  __t.swap(__u);
}

// get
template <size_t _Ip, class... _Tp>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 __tuple_element_t<_Ip, tuple<_Tp...>>&
get(tuple<_Tp...>& __t) noexcept
{
  return __t.template __get_impl<_Ip>();
}

template <size_t _Ip, class... _Tp>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 const __tuple_element_t<_Ip, tuple<_Tp...>>&
get(const tuple<_Tp...>& __t) noexcept
{
  return __t.template __get_impl<_Ip>();
}

template <size_t _Ip, class... _Tp>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 __tuple_element_t<_Ip, tuple<_Tp...>>&&
get(tuple<_Tp...>&& __t) noexcept
{
  return _CUDA_VSTD::move(__t).template __get_impl<_Ip>();
}

template <size_t _Ip, class... _Tp>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 const __tuple_element_t<_Ip, tuple<_Tp...>>&&
get(const tuple<_Tp...>&& __t) noexcept
{
  return _CUDA_VSTD::move(__t).template __get_impl<_Ip>();
}

#if _LIBCUDACXX_STD_VER > 11

namespace __find_detail {

static constexpr size_t __not_found = ~size_t(0);
static constexpr size_t __ambiguous = __not_found - 1;

inline _LIBCUDACXX_INLINE_VISIBILITY constexpr size_t
__find_idx_return(size_t __curr_i, size_t __res, bool __matches) {
  return !__matches ? __res : (__res == __not_found ? __curr_i : __ambiguous);
}

template <size_t _Nx>
inline _LIBCUDACXX_INLINE_VISIBILITY constexpr size_t
__find_idx(size_t __i, const bool (&__matches)[_Nx]) {
  return __i == _Nx ? __not_found
                    : __find_idx_return(__i, __find_idx(__i + 1, __matches),
                                        __matches[__i]);
}

template <class _T1, class... _Args> struct __find_exactly_one_checked {
  static constexpr bool __matches[sizeof...(_Args)] = {
      is_same<_T1, _Args>::value...};
  static constexpr size_t value = __find_detail::__find_idx(0, __matches);
  static_assert(value != __not_found, "type not found in type list");
  static_assert(value != __ambiguous,
                "type occurs more than once in type list");
};

template <class _T1> struct __find_exactly_one_checked<_T1> {
  static_assert(!is_same<_T1, _T1>::value, "type not in empty type list");
};

} // namespace __find_detail

template <typename _T1, typename... _Args>
struct __find_exactly_one_t
    : public __find_detail::__find_exactly_one_checked<_T1, _Args...> {};

template <class _T1, class... _Args>
inline _LIBCUDACXX_INLINE_VISIBILITY constexpr _T1 &
get(tuple<_Args...> &__tup) noexcept {
  return _CUDA_VSTD::get<__find_exactly_one_t<_T1, _Args...>::value>(__tup);
}

template <class _T1, class... _Args>
inline _LIBCUDACXX_INLINE_VISIBILITY constexpr _T1 const &
get(tuple<_Args...> const &__tup) noexcept {
  return _CUDA_VSTD::get<__find_exactly_one_t<_T1, _Args...>::value>(__tup);
}

template <class _T1, class... _Args>
inline _LIBCUDACXX_INLINE_VISIBILITY constexpr _T1 &&
get(tuple<_Args...> &&__tup) noexcept {
  return _CUDA_VSTD::get<__find_exactly_one_t<_T1, _Args...>::value>(
      _CUDA_VSTD::move(__tup));
}

template <class _T1, class... _Args>
inline _LIBCUDACXX_INLINE_VISIBILITY constexpr _T1 const &&
get(tuple<_Args...> const &&__tup) noexcept {
  return _CUDA_VSTD::get<__find_exactly_one_t<_T1, _Args...>::value>(
      _CUDA_VSTD::move(__tup));
}

#endif

// tie

template <class... _Tp>
inline _LIBCUDACXX_INLINE_VISIBILITY
    _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 tuple<_Tp &...>
    tie(_Tp &...__t) noexcept {
  return tuple<_Tp &...>(__t...);
}

template <class _Up> struct __ignore_t {
  template <class _Tp>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 const
      __ignore_t &
      operator=(_Tp &&) const {
    return *this;
  }
};

namespace {
#ifdef __CUDA_ARCH__
static
#endif
    _LIBCUDACXX_INLINE_VAR constexpr __ignore_t<unsigned char>
        ignore = __ignore_t<unsigned char>();
} // namespace

template <class... _Tp>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11
    tuple<typename __unwrap_ref_decay<_Tp>::type...>
    make_tuple(_Tp &&...__t) {
  return tuple<typename __unwrap_ref_decay<_Tp>::type...>(
      _CUDA_VSTD::forward<_Tp>(__t)...);
}

template <class... _Tp>
inline _LIBCUDACXX_INLINE_VISIBILITY
    _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 tuple<_Tp &&...>
    forward_as_tuple(_Tp &&...__t) noexcept {
  return tuple<_Tp &&...>(_CUDA_VSTD::forward<_Tp>(__t)...);
}

template <size_t _Ip> struct __tuple_equal {
  template <class _Tp, class _Up>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 bool
  operator()(const _Tp &__x, const _Up &__y) {
    return __tuple_equal<_Ip - 1>()(__x, __y) &&
           _CUDA_VSTD::get<_Ip - 1>(__x) == _CUDA_VSTD::get<_Ip - 1>(__y);
  }
};

template <> struct __tuple_equal<0> {
  template <class _Tp, class _Up>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 bool
  operator()(const _Tp &, const _Up &) {
    return true;
  }
};

template <class... _Tp, class... _Up>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 bool
operator==(const tuple<_Tp...> &__x, const tuple<_Up...> &__y) {
  static_assert(sizeof...(_Tp) == sizeof...(_Up),
                "Can't compare tuples of different sizes");
  return __tuple_equal<sizeof...(_Tp)>()(__x, __y);
}

template <class... _Tp, class... _Up>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 bool
operator!=(const tuple<_Tp...> &__x, const tuple<_Up...> &__y) {
  return !(__x == __y);
}

template <size_t _Ip> struct __tuple_less {
  template <class _Tp, class _Up>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 bool
  operator()(const _Tp &__x, const _Up &__y) {
    const size_t __idx = tuple_size<_Tp>::value - _Ip;
    if (_CUDA_VSTD::get<__idx>(__x) < _CUDA_VSTD::get<__idx>(__y)) {
      return true;
    }
    if (_CUDA_VSTD::get<__idx>(__y) < _CUDA_VSTD::get<__idx>(__x)) {
      return false;
    }
    return __tuple_less<_Ip - 1>()(__x, __y);
  }
};

template <> struct __tuple_less<0> {
  template <class _Tp, class _Up>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 bool
  operator()(const _Tp &, const _Up &) {
    return false;
  }
};

template <class... _Tp, class... _Up>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 bool
operator<(const tuple<_Tp...> &__x, const tuple<_Up...> &__y) {
  static_assert(sizeof...(_Tp) == sizeof...(_Up),
                "Can't compare tuples of different sizes");
  return __tuple_less<sizeof...(_Tp)>()(__x, __y);
}

template <class... _Tp, class... _Up>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 bool
operator>(const tuple<_Tp...> &__x, const tuple<_Up...> &__y) {
  return __y < __x;
}

template <class... _Tp, class... _Up>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 bool
operator>=(const tuple<_Tp...> &__x, const tuple<_Up...> &__y) {
  return !(__x < __y);
}

template <class... _Tp, class... _Up>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 bool
operator<=(const tuple<_Tp...> &__x, const tuple<_Up...> &__y) {
  return !(__y < __x);
}

// tuple_cat

template <class _Tp, class _Up> struct __tuple_cat_type;

template <class... _Ttypes, class... _Utypes>
struct __tuple_cat_type<tuple<_Ttypes...>, __tuple_types<_Utypes...>> {
  typedef _LIBCUDACXX_NODEBUG_TYPE tuple<_Ttypes..., _Utypes...> type;
};

template <class _ResultTuple, bool _Is_Tuple0TupleLike, class... _Tuples>
struct __tuple_cat_return_1 {};

template <class... _Types, class _Tuple0>
struct __tuple_cat_return_1<tuple<_Types...>, true, _Tuple0> {
  typedef _LIBCUDACXX_NODEBUG_TYPE typename __tuple_cat_type<
      tuple<_Types...>, __make_tuple_types_t<__remove_cvref_t<_Tuple0>>>::type
      type;
};

template <class... _Types, class _Tuple0, class _Tuple1, class... _Tuples>
struct __tuple_cat_return_1<tuple<_Types...>, true, _Tuple0, _Tuple1,
                            _Tuples...>
    : public __tuple_cat_return_1<
          typename __tuple_cat_type<
              tuple<_Types...>,
              __make_tuple_types_t<__remove_cvref_t<_Tuple0>>>::type,
          __tuple_like<__libcpp_remove_reference_t<_Tuple1>>::value, _Tuple1,
          _Tuples...> {};

template <class... _Tuples> struct __tuple_cat_return;

template <class _Tuple0, class... _Tuples>
struct __tuple_cat_return<_Tuple0, _Tuples...>
    : public __tuple_cat_return_1<
          tuple<>, __tuple_like<__libcpp_remove_reference_t<_Tuple0>>::value,
          _Tuple0, _Tuples...> {};

template <> struct __tuple_cat_return<> {
  typedef _LIBCUDACXX_NODEBUG_TYPE tuple<> type;
};

inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 tuple<>
tuple_cat() {
  return tuple<>();
}

template <class _Rp, class _Indices, class _Tuple0, class... _Tuples>
struct __tuple_cat_return_ref_imp;

template <class... _Types, size_t... _I0, class _Tuple0>
struct __tuple_cat_return_ref_imp<tuple<_Types...>, __tuple_indices<_I0...>,
                                  _Tuple0> {
  typedef _LIBCUDACXX_NODEBUG_TYPE __libcpp_remove_reference_t<_Tuple0> _T0;
  typedef tuple<
      _Types...,
      typename __apply_cv<_Tuple0, __tuple_element_t<_I0, _T0>>::type &&...>
      type;
};

template <class... _Types, size_t... _I0, class _Tuple0, class _Tuple1,
          class... _Tuples>
struct __tuple_cat_return_ref_imp<tuple<_Types...>, __tuple_indices<_I0...>,
                                  _Tuple0, _Tuple1, _Tuples...>
    : public __tuple_cat_return_ref_imp<
          tuple<_Types...,
                typename __apply_cv<
                    _Tuple0, __tuple_element_t<_I0, __libcpp_remove_reference_t<
                                                        _Tuple0>>>::type &&...>,
          __make_tuple_indices_t<
              tuple_size<__libcpp_remove_reference_t<_Tuple1>>::value>,
          _Tuple1, _Tuples...> {};

template <class _Tuple0, class... _Tuples>
struct __tuple_cat_return_ref
    : public __tuple_cat_return_ref_imp<
          tuple<>,
          __make_tuple_indices_t<
              tuple_size<__libcpp_remove_reference_t<_Tuple0>>::value>,
          _Tuple0, _Tuples...> {};

template <class _Types, class _I0, class _J0> struct __tuple_cat;

template <class... _Types, size_t... _I0, size_t... _J0>
struct __tuple_cat<tuple<_Types...>, __tuple_indices<_I0...>,
                   __tuple_indices<_J0...>> {
  template <class _Tuple0>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11
      typename __tuple_cat_return_ref<tuple<_Types...> &&, _Tuple0 &&>::type
      operator()(tuple<_Types...> __t, _Tuple0 &&__t0) {
    (void)__t;
    return _CUDA_VSTD::forward_as_tuple(
        _CUDA_VSTD::forward<_Types>(_CUDA_VSTD::get<_I0>(__t))...,
        _CUDA_VSTD::get<_J0>(_CUDA_VSTD::forward<_Tuple0>(__t0))...);
  }

  template <class _Tuple0, class _Tuple1, class... _Tuples>
  _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11
      typename __tuple_cat_return_ref<tuple<_Types...> &&, _Tuple0 &&,
                                      _Tuple1 &&, _Tuples &&...>::type
      operator()(tuple<_Types...> __t, _Tuple0 &&__t0, _Tuple1 &&__t1,
                 _Tuples &&...__tpls) {
    (void)__t;
    typedef _LIBCUDACXX_NODEBUG_TYPE __libcpp_remove_reference_t<_Tuple0> _T0;
    typedef _LIBCUDACXX_NODEBUG_TYPE __libcpp_remove_reference_t<_Tuple1> _T1;
    return __tuple_cat<
        tuple<_Types..., typename __apply_cv<
                             _Tuple0, __tuple_element_t<_J0, _T0>>::type &&...>,
        __make_tuple_indices_t<sizeof...(_Types) + tuple_size<_T0>::value>,
        __make_tuple_indices_t<tuple_size<_T1>::value>>()(
        _CUDA_VSTD::forward_as_tuple(
            _CUDA_VSTD::forward<_Types>(_CUDA_VSTD::get<_I0>(__t))...,
            _CUDA_VSTD::get<_J0>(_CUDA_VSTD::forward<_Tuple0>(__t0))...),
        _CUDA_VSTD::forward<_Tuple1>(__t1),
        _CUDA_VSTD::forward<_Tuples>(__tpls)...);
  }
};

template <class _Tuple0, class... _Tuples>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11
    typename __tuple_cat_return<_Tuple0, _Tuples...>::type
    tuple_cat(_Tuple0 &&__t0, _Tuples &&...__tpls) {
  typedef _LIBCUDACXX_NODEBUG_TYPE __libcpp_remove_reference_t<_Tuple0> _T0;
  return __tuple_cat<tuple<>, __tuple_indices<>,
                     __make_tuple_indices_t<tuple_size<_T0>::value>>()(
      tuple<>(), _CUDA_VSTD::forward<_Tuple0>(__t0),
      _CUDA_VSTD::forward<_Tuples>(__tpls)...);
}

template <class... _Tp, class _Alloc>
struct _LIBCUDACXX_TEMPLATE_VIS uses_allocator<tuple<_Tp...>, _Alloc>
    : true_type {};

template <class _T1, class _T2, bool _IsRef>
template <class... _Args1, class... _Args2, size_t... _I1, size_t... _I2>
inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX17 __pair_base<_T1, _T2, _IsRef>::__pair_base(
  piecewise_construct_t,
  tuple<_Args1...>& __first_args,
  tuple<_Args2...>& __second_args,
  __tuple_indices<_I1...>,
  __tuple_indices<_I2...>)
    : first(_CUDA_VSTD::forward<_Args1>(_CUDA_VSTD::get<_I1>(__first_args))...)
    , second(_CUDA_VSTD::forward<_Args2>(_CUDA_VSTD::get<_I2>(__second_args))...)
{}

#if _LIBCUDACXX_STD_VER > 14
#define _LIBCUDACXX_NOEXCEPT_RETURN(...)                                       \
  noexcept(noexcept(__VA_ARGS__)) { return __VA_ARGS__; }

template <class _Fn, class _Tuple, size_t... _Id>
inline _LIBCUDACXX_INLINE_VISIBILITY constexpr decltype(auto)
__apply_tuple_impl(_Fn &&__f, _Tuple &&__t, __tuple_indices<_Id...>)
    _LIBCUDACXX_NOEXCEPT_RETURN(_CUDA_VSTD::__invoke(
        _CUDA_VSTD::forward<_Fn>(__f),
        _CUDA_VSTD::get<_Id>(_CUDA_VSTD::forward<_Tuple>(__t))...))

        template <class _Fn, class _Tuple>
        inline _LIBCUDACXX_INLINE_VISIBILITY
    constexpr decltype(auto) apply(_Fn &&__f, _Tuple &&__t)
        _LIBCUDACXX_NOEXCEPT_RETURN(_CUDA_VSTD::__apply_tuple_impl(
            _CUDA_VSTD::forward<_Fn>(__f), _CUDA_VSTD::forward<_Tuple>(__t),
            __make_tuple_indices_t<tuple_size_v<remove_reference_t<_Tuple>>>{}))

            template <class _Tp, class _Tuple, size_t... _Idx>
            inline _LIBCUDACXX_INLINE_VISIBILITY constexpr _Tp
    __make_from_tuple_impl(_Tuple &&__t, __tuple_indices<_Idx...>)
        _LIBCUDACXX_NOEXCEPT_RETURN(
            _Tp(_CUDA_VSTD::get<_Idx>(_CUDA_VSTD::forward<_Tuple>(__t))...))

            template <class _Tp, class _Tuple>
            inline _LIBCUDACXX_INLINE_VISIBILITY constexpr _Tp
    make_from_tuple(_Tuple &&__t)
        _LIBCUDACXX_NOEXCEPT_RETURN(_CUDA_VSTD::__make_from_tuple_impl<_Tp>(
            _CUDA_VSTD::forward<_Tuple>(__t),
            __make_tuple_indices_t<tuple_size_v<remove_reference_t<_Tuple>>>{}))

#undef _LIBCUDACXX_NOEXCEPT_RETURN

#endif // _LIBCUDACXX_STD_VER > 14

            _LIBCUDACXX_END_NAMESPACE_STD

#ifndef __cuda_std__
#include <__pragma_pop>
#endif //__cuda_std__

#endif // _LIBCUDACXX_TUPLE
