// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef _LIBCPP_TUPLE #define _LIBCPP_TUPLE // clang-format off /* tuple synopsis namespace std { template class tuple { public: explicit(see-below) constexpr tuple(); explicit(see-below) tuple(const T&...); // constexpr in C++14 template explicit(see-below) tuple(U&&...); // constexpr in C++14 tuple(const tuple&) = default; tuple(tuple&&) = default; template constexpr explicit(see-below) tuple(tuple&); // C++23 template explicit(see-below) tuple(const tuple&); // constexpr in C++14 template explicit(see-below) tuple(tuple&&); // constexpr in C++14 template constexpr explicit(see-below) tuple(const tuple&&); // C++23 template constexpr explicit(see-below) tuple(pair&); // iff sizeof...(Types) == 2 // C++23 template explicit(see-below) tuple(const pair&); // iff sizeof...(T) == 2 // constexpr in C++14 template explicit(see-below) tuple(pair&&); // iff sizeof...(T) == 2 // constexpr in C++14 template constexpr explicit(see-below) tuple(const pair&&); // iff sizeof...(Types) == 2 // C++23 // allocator-extended constructors template tuple(allocator_arg_t, const Alloc& a); template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const T&...); // constexpr in C++20 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, U&&...); // constexpr in C++20 template tuple(allocator_arg_t, const Alloc& a, const tuple&); // constexpr in C++20 template tuple(allocator_arg_t, const Alloc& a, tuple&&); // constexpr in C++20 template constexpr explicit(see-below) tuple(allocator_arg_t, const Alloc& a, tuple&); // C++23 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const tuple&); // constexpr in C++20 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, tuple&&); // constexpr in C++20 template constexpr explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const tuple&&); // C++23 template constexpr explicit(see-below) tuple(allocator_arg_t, const Alloc& a, pair&); // C++23 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const pair&); // constexpr in C++20 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, pair&&); // constexpr in C++20 template constexpr explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const pair&&); // C++23 tuple& operator=(const tuple&); // constexpr in C++20 constexpr const tuple& operator=(const tuple&) const; // C++23 tuple& operator=(tuple&&) noexcept(is_nothrow_move_assignable_v && ...); // constexpr in C++20 constexpr const tuple& operator=(tuple&&) const; // C++23 template tuple& operator=(const tuple&); // constexpr in C++20 template constexpr const tuple& operator=(const tuple&) const; // C++23 template tuple& operator=(tuple&&); // constexpr in C++20 template constexpr const tuple& operator=(tuple&&) const; // C++23 template tuple& operator=(const pair&); // iff sizeof...(T) == 2 // constexpr in C++20 template constexpr const tuple& operator=(const pair&) const; // iff sizeof...(Types) == 2 // C++23 template tuple& operator=(pair&&); // iff sizeof...(T) == 2 // constexpr in C++20 template constexpr const tuple& operator=(pair&&) const; // iff sizeof...(Types) == 2 // C++23 template tuple& operator=(array const&) // iff sizeof...(T) == N, EXTENSION template tuple& operator=(array&&) // iff sizeof...(T) == N, EXTENSION void swap(tuple&) noexcept(AND(swap(declval(), declval())...)); // constexpr in C++20 constexpr void swap(const tuple&) const noexcept(see-below); // C++23 }; template class TQual, template class UQual> // since C++23 requires requires { typename tuple, UQual>...>; } struct basic_common_reference, tuple, TQual, UQual> { using type = tuple, UQual>...>; }; template // since C++23 requires requires { typename tuple...>; } struct common_type, tuple> { using type = tuple...>; }; template tuple(T...) -> tuple; // since C++17 template tuple(pair) -> tuple; // since C++17 template tuple(allocator_arg_t, Alloc, T...) -> tuple; // since C++17 template tuple(allocator_arg_t, Alloc, pair) -> tuple; // since C++17 template tuple(allocator_arg_t, Alloc, tuple) -> tuple; // since C++17 struct ignore-type { // exposition only // Since C++26 constexpr const ignore-type& operator=(const auto &) const noexcept { return *this; } }; inline constexpr ignore-type ignore; template tuple make_tuple(T&&...); // constexpr in C++14 template tuple forward_as_tuple(T&&...) noexcept; // constexpr in C++14 template tuple tie(T&...) noexcept; // constexpr in C++14 template tuple tuple_cat(Tuples&&... tpls); // constexpr in C++14 // [tuple.apply], calling a function with a tuple of arguments: template constexpr decltype(auto) apply(F&& f, Tuple&& t) noexcept(see below); // C++17 noexcept since C++23 template constexpr T make_from_tuple(Tuple&& t); // C++17 // 20.4.1.4, tuple helper classes: template struct tuple_size; // undefined template struct tuple_size>; template inline constexpr size_t tuple_size_v = tuple_size::value; // C++17 template struct tuple_element; // undefined template struct tuple_element>; template using tuple_element_t = typename tuple_element ::type; // C++14 // 20.4.1.5, element access: template typename tuple_element>::type& get(tuple&) noexcept; // constexpr in C++14 template const typename tuple_element>::type& get(const tuple&) noexcept; // constexpr in C++14 template typename tuple_element>::type&& get(tuple&&) noexcept; // constexpr in C++14 template const typename tuple_element>::type&& get(const tuple&&) noexcept; // constexpr in C++14 template constexpr T1& get(tuple&) noexcept; // C++14 template constexpr const T1& get(const tuple&) noexcept; // C++14 template constexpr T1&& get(tuple&&) noexcept; // C++14 template constexpr const T1&& get(const tuple&&) noexcept; // C++14 // 20.4.1.6, relational operators: template bool operator==(const tuple&, const tuple&); // constexpr in C++14 template bool operator<(const tuple&, const tuple&); // constexpr in C++14, removed in C++20 template bool operator!=(const tuple&, const tuple&); // constexpr in C++14, removed in C++20 template bool operator>(const tuple&, const tuple&); // constexpr in C++14, removed in C++20 template bool operator<=(const tuple&, const tuple&); // constexpr in C++14, removed in C++20 template bool operator>=(const tuple&, const tuple&); // constexpr in C++14, removed in C++20 template constexpr common_comparison_category_t...> operator<=>(const tuple&, const tuple&); // since C++20 template struct uses_allocator, Alloc>; template void swap(tuple& x, tuple& y) noexcept(noexcept(x.swap(y))); template constexpr void swap(const tuple& x, const tuple& y) noexcept(see-below); // C++23 } // std */ // clang-format on #include <__compare/common_comparison_category.h> #include <__compare/synth_three_way.h> #include <__config> #include <__functional/invoke.h> #include <__fwd/array.h> #include <__fwd/pair.h> #include <__fwd/tuple.h> #include <__memory/allocator_arg_t.h> #include <__memory/uses_allocator.h> #include <__tuple/find_index.h> #include <__tuple/ignore.h> #include <__tuple/make_tuple_types.h> #include <__tuple/sfinae_helpers.h> #include <__tuple/tuple_element.h> #include <__tuple/tuple_indices.h> #include <__tuple/tuple_like_ext.h> #include <__tuple/tuple_size.h> #include <__tuple/tuple_types.h> #include <__type_traits/common_reference.h> #include <__type_traits/common_type.h> #include <__type_traits/conditional.h> #include <__type_traits/conjunction.h> #include <__type_traits/copy_cvref.h> #include <__type_traits/disjunction.h> #include <__type_traits/is_arithmetic.h> #include <__type_traits/is_assignable.h> #include <__type_traits/is_constructible.h> #include <__type_traits/is_convertible.h> #include <__type_traits/is_empty.h> #include <__type_traits/is_final.h> #include <__type_traits/is_implicitly_default_constructible.h> #include <__type_traits/is_nothrow_assignable.h> #include <__type_traits/is_nothrow_constructible.h> #include <__type_traits/is_reference.h> #include <__type_traits/is_same.h> #include <__type_traits/is_swappable.h> #include <__type_traits/is_trivially_relocatable.h> #include <__type_traits/lazy.h> #include <__type_traits/maybe_const.h> #include <__type_traits/nat.h> #include <__type_traits/negation.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/remove_reference.h> #include <__type_traits/unwrap_ref.h> #include <__utility/forward.h> #include <__utility/integer_sequence.h> #include <__utility/move.h> #include <__utility/piecewise_construct.h> #include <__utility/swap.h> #include #include // standard-mandated includes // [tuple.syn] #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif _LIBCPP_PUSH_MACROS #include <__undef_macros> _LIBCPP_BEGIN_NAMESPACE_STD #ifndef _LIBCPP_CXX03_LANG // __tuple_leaf template ::value && !__libcpp_is_final<_Hp>::value > class __tuple_leaf; template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void swap(__tuple_leaf<_Ip, _Hp, _Ep>& __x, __tuple_leaf<_Ip, _Hp, _Ep>& __y) noexcept(__is_nothrow_swappable_v<_Hp>) { swap(__x.get(), __y.get()); } template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void swap(const __tuple_leaf<_Ip, _Hp, _Ep>& __x, const __tuple_leaf<_Ip, _Hp, _Ep>& __y) noexcept(__is_nothrow_swappable_v) { swap(__x.get(), __y.get()); } template class __tuple_leaf { _Hp __value_; template static _LIBCPP_HIDE_FROM_ABI constexpr bool __can_bind_reference() { # if __has_keyword(__reference_binds_to_temporary) return !__reference_binds_to_temporary(_Hp, _Tp); # else return true; # endif } public: _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_leaf& operator=(const __tuple_leaf&) = delete; _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf() noexcept(is_nothrow_default_constructible<_Hp>::value) : __value_() { static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple"); } template _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant, const _Alloc&) : __value_() { static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple"); } template _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant, const _Alloc& __a) : __value_(allocator_arg_t(), __a) { static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple"); } template _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant, const _Alloc& __a) : __value_(__a) { static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple"); } template < class _Tp, __enable_if_t<_And<_IsNotSame<__remove_cvref_t<_Tp>, __tuple_leaf>, is_constructible<_Hp, _Tp> >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(_Tp&& __t) noexcept(is_nothrow_constructible<_Hp, _Tp>::value) : __value_(std::forward<_Tp>(__t)) { static_assert(__can_bind_reference<_Tp&&>(), "Attempted construction of reference element binds to a temporary whose lifetime has ended"); } template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(integral_constant, const _Alloc&, _Tp&& __t) : __value_(std::forward<_Tp>(__t)) { static_assert(__can_bind_reference<_Tp&&>(), "Attempted construction of reference element binds to a temporary whose lifetime has ended"); } template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(integral_constant, const _Alloc& __a, _Tp&& __t) : __value_(allocator_arg_t(), __a, std::forward<_Tp>(__t)) { static_assert(!is_reference<_Hp>::value, "Attempted to uses-allocator construct a reference element in a tuple"); } template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(integral_constant, const _Alloc& __a, _Tp&& __t) : __value_(std::forward<_Tp>(__t), __a) { static_assert(!is_reference<_Hp>::value, "Attempted to uses-allocator construct a reference element in a tuple"); } _LIBCPP_HIDE_FROM_ABI __tuple_leaf(const __tuple_leaf& __t) = default; _LIBCPP_HIDE_FROM_ABI __tuple_leaf(__tuple_leaf&& __t) = default; _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int swap(__tuple_leaf& __t) noexcept(__is_nothrow_swappable_v<__tuple_leaf>) { std::swap(*this, __t); return 0; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int swap(const __tuple_leaf& __t) const noexcept(__is_nothrow_swappable_v) { std::swap(*this, __t); return 0; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Hp& get() _NOEXCEPT { return __value_; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Hp& get() const _NOEXCEPT { return __value_; } }; template class __tuple_leaf<_Ip, _Hp, true> : private _Hp { public: _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_leaf& operator=(const __tuple_leaf&) = delete; _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf() noexcept(is_nothrow_default_constructible<_Hp>::value) {} template _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant, const _Alloc&) {} template _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant, const _Alloc& __a) : _Hp(allocator_arg_t(), __a) {} template _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant, const _Alloc& __a) : _Hp(__a) {} template , __tuple_leaf>, is_constructible<_Hp, _Tp> >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(_Tp&& __t) noexcept(is_nothrow_constructible<_Hp, _Tp>::value) : _Hp(std::forward<_Tp>(__t)) {} template _LIBCPP_HIDE_FROM_ABI constexpr explicit __tuple_leaf(integral_constant, const _Alloc&, _Tp&& __t) : _Hp(std::forward<_Tp>(__t)) {} template _LIBCPP_HIDE_FROM_ABI constexpr explicit __tuple_leaf(integral_constant, const _Alloc& __a, _Tp&& __t) : _Hp(allocator_arg_t(), __a, std::forward<_Tp>(__t)) {} template _LIBCPP_HIDE_FROM_ABI constexpr explicit __tuple_leaf(integral_constant, const _Alloc& __a, _Tp&& __t) : _Hp(std::forward<_Tp>(__t), __a) {} __tuple_leaf(__tuple_leaf const&) = default; __tuple_leaf(__tuple_leaf&&) = default; _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int swap(__tuple_leaf& __t) noexcept(__is_nothrow_swappable_v<__tuple_leaf>) { std::swap(*this, __t); return 0; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int swap(const __tuple_leaf& __rhs) const noexcept(__is_nothrow_swappable_v) { std::swap(*this, __rhs); return 0; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Hp& get() _NOEXCEPT { return static_cast<_Hp&>(*this); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Hp& get() const _NOEXCEPT { return static_cast(*this); } }; template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __swallow(_Tp&&...) _NOEXCEPT {} template struct __all_default_constructible; template struct __all_default_constructible<__tuple_types<_Tp...>> : __all::value...> {}; // __tuple_impl template struct __tuple_impl; template struct _LIBCPP_DECLSPEC_EMPTY_BASES __tuple_impl<__tuple_indices<_Indx...>, _Tp...> : public __tuple_leaf<_Indx, _Tp>... { _LIBCPP_HIDE_FROM_ABI constexpr __tuple_impl() noexcept( __all::value...>::value) {} template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_impl( __tuple_indices<_Uf...>, __tuple_types<_Tf...>, __tuple_indices<_Ul...>, __tuple_types<_Tl...>, _Up&&... __u) noexcept(__all::value...>::value && __all::value...>::value) : __tuple_leaf<_Uf, _Tf>(std::forward<_Up>(__u))..., __tuple_leaf<_Ul, _Tl>()... {} template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_impl( allocator_arg_t, const _Alloc& __a, __tuple_indices<_Uf...>, __tuple_types<_Tf...>, __tuple_indices<_Ul...>, __tuple_types<_Tl...>, _Up&&... __u) : __tuple_leaf<_Uf, _Tf>(__uses_alloc_ctor<_Tf, _Alloc, _Up>(), __a, std::forward<_Up>(__u))..., __tuple_leaf<_Ul, _Tl>(__uses_alloc_ctor<_Tl, _Alloc>(), __a)... {} template >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_impl(_Tuple&& __t) noexcept( (__all::type>::type>::value...>::value)) : __tuple_leaf<_Indx, _Tp>( std::forward::type>::type>( std::get<_Indx>(__t)))... {} template >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_impl(allocator_arg_t, const _Alloc& __a, _Tuple&& __t) : __tuple_leaf<_Indx, _Tp>( __uses_alloc_ctor<_Tp, _Alloc, typename tuple_element<_Indx, typename __make_tuple_types<_Tuple>::type>::type>(), __a, std::forward::type>::type>( std::get<_Indx>(__t)))... {} __tuple_impl(const __tuple_impl&) = default; __tuple_impl(__tuple_impl&&) = default; _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void swap(__tuple_impl& __t) noexcept(__all<__is_nothrow_swappable_v<_Tp>...>::value) { std::__swallow(__tuple_leaf<_Indx, _Tp>::swap(static_cast<__tuple_leaf<_Indx, _Tp>&>(__t))...); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void swap(const __tuple_impl& __t) const noexcept(__all<__is_nothrow_swappable_v...>::value) { std::__swallow(__tuple_leaf<_Indx, _Tp>::swap(static_cast&>(__t))...); } }; template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __memberwise_copy_assign(_Dest& __dest, _Source const& __source, __tuple_indices<_Np...>) { std::__swallow(((std::get<_Np>(__dest) = std::get<_Np>(__source)), void(), 0)...); } template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __memberwise_forward_assign(_Dest& __dest, _Source&& __source, __tuple_types<_Up...>, __tuple_indices<_Np...>) { std::__swallow(((std::get<_Np>(__dest) = std::forward<_Up>(std::get<_Np>(__source))), void(), 0)...); } template class _LIBCPP_TEMPLATE_VIS tuple { typedef __tuple_impl::type, _Tp...> _BaseT; _BaseT __base_; template friend _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Jp, tuple<_Up...> >::type& get(tuple<_Up...>&) _NOEXCEPT; template friend _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Jp, tuple<_Up...> >::type& get(const tuple<_Up...>&) _NOEXCEPT; template friend _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Jp, tuple<_Up...> >::type&& get(tuple<_Up...>&&) _NOEXCEPT; template friend _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Jp, tuple<_Up...> >::type&& get(const tuple<_Up...>&&) _NOEXCEPT; public: using __trivially_relocatable = __conditional_t<_And<__libcpp_is_trivially_relocatable<_Tp>...>::value, tuple, void>; // [tuple.cnstr] // tuple() constructors (including allocator_arg_t variants) template