diff options
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/include/bits/ranges_util.h | 17 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/stl_iterator.h | 16 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/stl_pair.h | 182 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/utility.h | 8 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/version.def | 8 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/version.h | 10 | ||||
-rw-r--r-- | libstdc++-v3/include/std/concepts | 11 | ||||
-rw-r--r-- | libstdc++-v3/include/std/map | 1 | ||||
-rw-r--r-- | libstdc++-v3/include/std/ranges | 48 | ||||
-rw-r--r-- | libstdc++-v3/include/std/tuple | 325 | ||||
-rw-r--r-- | libstdc++-v3/include/std/unordered_map | 1 | ||||
-rw-r--r-- | libstdc++-v3/include/std/utility | 1 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/pair/p2165r4.cc | 173 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc | 335 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/ranges/zip/1.cc | 17 |
15 files changed, 1070 insertions, 83 deletions
diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h index bb04c49..9b79c3a 100644 --- a/libstdc++-v3/include/bits/ranges_util.h +++ b/libstdc++-v3/include/bits/ranges_util.h @@ -224,6 +224,10 @@ namespace ranges && !__uses_nonqualification_pointer_conversion<decay_t<_From>, decay_t<_To>>; +#if __glibcxx_tuple_like // >= C++23 + // P2165R4 version of __pair_like is defined in <bits/stl_pair.h>. +#else + // C++20 version of __pair_like from P2321R2. template<typename _Tp> concept __pair_like = !is_reference_v<_Tp> && requires(_Tp __t) @@ -235,10 +239,11 @@ namespace ranges { get<0>(__t) } -> convertible_to<const tuple_element_t<0, _Tp>&>; { get<1>(__t) } -> convertible_to<const tuple_element_t<1, _Tp>&>; }; +#endif template<typename _Tp, typename _Up, typename _Vp> concept __pair_like_convertible_from - = !range<_Tp> && __pair_like<_Tp> + = !range<_Tp> && !is_reference_v<_Vp> && __pair_like<_Tp> && constructible_from<_Tp, _Up, _Vp> && __convertible_to_non_slicing<_Up, tuple_element_t<0, _Tp>> && convertible_to<_Vp, tuple_element_t<1, _Tp>>; @@ -463,8 +468,18 @@ namespace ranges using borrowed_subrange_t = __conditional_t<borrowed_range<_Range>, subrange<iterator_t<_Range>>, dangling>; + + // __is_subrange is defined in <bits/utility.h>. + template<typename _Iter, typename _Sent, subrange_kind _Kind> + inline constexpr bool __detail::__is_subrange<subrange<_Iter, _Sent, _Kind>> = true; } // namespace ranges +#if __glibcxx_tuple_like // >= C++23 + // __is_tuple_like_v is defined in <bits/stl_pair.h>. + template<typename _It, typename _Sent, ranges::subrange_kind _Kind> + inline constexpr bool __is_tuple_like_v<ranges::subrange<_It, _Sent, _Kind>> = true; +#endif + // The following ranges algorithms are used by <ranges>, and are defined here // so that <ranges> can avoid including all of <bits/ranges_algo.h>. namespace ranges diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index d71a793..560a10a 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -78,6 +78,10 @@ # include <bits/stl_construct.h> #endif +#if __glibcxx_tuple_like // >= C++23 +# include <bits/utility.h> // for tuple_element_t +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -95,10 +99,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Cat, typename _Limit, typename _Otherwise = _Cat> using __clamp_iter_cat = __conditional_t<derived_from<_Cat, _Limit>, _Limit, _Otherwise>; - - template<typename _Tp, typename _Up> - concept __different_from - = !same_as<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>; } #endif @@ -2983,11 +2983,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // of associative containers. template<typename _InputIterator> using __iter_key_t = remove_const_t< +#if __glibcxx_tuple_like // >= C++23 + tuple_element_t<0, typename iterator_traits<_InputIterator>::value_type>>; +#else typename iterator_traits<_InputIterator>::value_type::first_type>; +#endif template<typename _InputIterator> using __iter_val_t +#if __glibcxx_tuple_like // >= C++23 + = tuple_element_t<1, typename iterator_traits<_InputIterator>::value_type>; +#else = typename iterator_traits<_InputIterator>::value_type::second_type; +#endif template<typename _T1, typename _T2> struct pair; diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index b81b479..00ec53e 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -85,12 +85,70 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @cond undocumented // Forward declarations. + template<typename _T1, typename _T2> + struct pair; + template<typename...> class tuple; + // Declarations of std::array and its std::get overloads, so that + // std::tuple_cat can use them if <tuple> is included before <array>. + // We also declare the other std::get overloads here so that they're + // visible to the P2165R4 tuple-like constructors of pair and tuple. + template<typename _Tp, size_t _Nm> + struct array; + template<size_t...> struct _Index_tuple; + template<size_t _Int, class _Tp1, class _Tp2> + constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type& + get(pair<_Tp1, _Tp2>& __in) noexcept; + + template<size_t _Int, class _Tp1, class _Tp2> + constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&& + get(pair<_Tp1, _Tp2>&& __in) noexcept; + + template<size_t _Int, class _Tp1, class _Tp2> + constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type& + get(const pair<_Tp1, _Tp2>& __in) noexcept; + + template<size_t _Int, class _Tp1, class _Tp2> + constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&& + get(const pair<_Tp1, _Tp2>&& __in) noexcept; + + template<size_t __i, typename... _Elements> + constexpr __tuple_element_t<__i, tuple<_Elements...>>& + get(tuple<_Elements...>& __t) noexcept; + + template<size_t __i, typename... _Elements> + constexpr const __tuple_element_t<__i, tuple<_Elements...>>& + get(const tuple<_Elements...>& __t) noexcept; + + template<size_t __i, typename... _Elements> + constexpr __tuple_element_t<__i, tuple<_Elements...>>&& + get(tuple<_Elements...>&& __t) noexcept; + + template<size_t __i, typename... _Elements> + constexpr const __tuple_element_t<__i, tuple<_Elements...>>&& + get(const tuple<_Elements...>&& __t) noexcept; + + template<size_t _Int, typename _Tp, size_t _Nm> + constexpr _Tp& + get(array<_Tp, _Nm>&) noexcept; + + template<size_t _Int, typename _Tp, size_t _Nm> + constexpr _Tp&& + get(array<_Tp, _Nm>&&) noexcept; + + template<size_t _Int, typename _Tp, size_t _Nm> + constexpr const _Tp& + get(const array<_Tp, _Nm>&) noexcept; + + template<size_t _Int, typename _Tp, size_t _Nm> + constexpr const _Tp&& + get(const array<_Tp, _Nm>&&) noexcept; + #if ! __cpp_lib_concepts // Concept utility functions, reused in conditionally-explicit // constructors. @@ -159,6 +217,46 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // lib concepts #endif // C++11 +#if __glibcxx_tuple_like // >= C++23 + template<typename _Tp> + inline constexpr bool __is_tuple_v = false; + + template<typename... _Ts> + inline constexpr bool __is_tuple_v<tuple<_Ts...>> = true; + + // TODO: Reuse __is_tuple_like from <type_traits>? + template<typename _Tp> + inline constexpr bool __is_tuple_like_v = false; + + template<typename... _Elements> + inline constexpr bool __is_tuple_like_v<tuple<_Elements...>> = true; + + template<typename _T1, typename _T2> + inline constexpr bool __is_tuple_like_v<pair<_T1, _T2>> = true; + + template<typename _Tp, size_t _Nm> + inline constexpr bool __is_tuple_like_v<array<_Tp, _Nm>> = true; + + // __is_tuple_like_v<subrange> is defined in <bits/ranges_util.h>. + + template<typename _Tp> + concept __tuple_like = __is_tuple_like_v<remove_cvref_t<_Tp>>; + + template<typename _Tp> + concept __pair_like = __tuple_like<_Tp> && tuple_size_v<remove_cvref_t<_Tp>> == 2; + + template<typename _Tp, typename _Tuple> + concept __eligible_tuple_like + = __detail::__different_from<_Tp, _Tuple> && __tuple_like<_Tp> + && (tuple_size_v<remove_cvref_t<_Tp>> == tuple_size_v<_Tuple>) + && !ranges::__detail::__is_subrange<remove_cvref_t<_Tp>>; + + template<typename _Tp, typename _Pair> + concept __eligible_pair_like + = __detail::__different_from<_Tp, _Pair> && __pair_like<_Tp> + && !ranges::__detail::__is_subrange<remove_cvref_t<_Tp>>; +#endif // C++23 + template<typename _U1, typename _U2> class __pair_base { #if __cplusplus >= 201103L && ! __cpp_lib_concepts @@ -295,6 +393,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return false; #endif } + +#if __glibcxx_tuple_like // >= C++23 + template<typename _UPair> + static constexpr bool + _S_constructible_from_pair_like() + { + return _S_constructible<decltype(std::get<0>(std::declval<_UPair>())), + decltype(std::get<1>(std::declval<_UPair>()))>(); + } + + template<typename _UPair> + static constexpr bool + _S_convertible_from_pair_like() + { + return _S_convertible<decltype(std::get<0>(std::declval<_UPair>())), + decltype(std::get<1>(std::declval<_UPair>()))>(); + } + + template<typename _UPair> + static constexpr bool + _S_dangles_from_pair_like() + { + return _S_dangles<decltype(std::get<0>(std::declval<_UPair>())), + decltype(std::get<1>(std::declval<_UPair>()))>(); + } +#endif // C++23 /// @endcond public: @@ -393,6 +517,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION pair(const pair<_U1, _U2>&&) = delete; #endif // C++23 +#if __glibcxx_tuple_like // >= C++23 + template<__eligible_pair_like<pair> _UPair> + requires (_S_constructible_from_pair_like<_UPair>()) + && (!_S_dangles_from_pair_like<_UPair>()) + constexpr explicit(!_S_convertible_from_pair_like<_UPair>()) + pair(_UPair&& __p) + : first(std::get<0>(std::forward<_UPair>(__p))), + second(std::get<1>(std::forward<_UPair>(__p))) + { } + + template<__eligible_pair_like<pair> _UPair> + requires (_S_constructible_from_pair_like<_UPair>()) + && (_S_dangles_from_pair_like<_UPair>()) + constexpr explicit(!_S_convertible_from_pair_like<_UPair>()) + pair(_UPair&&) = delete; +#endif // C++23 + private: /// @cond undocumented template<typename _U1, typename _U2> @@ -421,6 +562,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return is_nothrow_assignable_v<_T2&, _U2>; return false; } + +#if __glibcxx_tuple_like // >= C++23 + template<typename _UPair> + static constexpr bool + _S_assignable_from_tuple_like() + { + return _S_assignable<decltype(std::get<0>(std::declval<_UPair>())), + decltype(std::get<1>(std::declval<_UPair>()))>(); + } + + template<typename _UPair> + static constexpr bool + _S_const_assignable_from_tuple_like() + { + return _S_const_assignable<decltype(std::get<0>(std::declval<_UPair>())), + decltype(std::get<1>(std::declval<_UPair>()))>(); + } +#endif // C++23 /// @endcond public: @@ -516,6 +675,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } #endif // C++23 + +#if __glibcxx_tuple_like // >= C++23 + template<__eligible_pair_like<pair> _UPair> + requires (_S_assignable_from_tuple_like<_UPair>()) + constexpr pair& + operator=(_UPair&& __p) + { + first = std::get<0>(std::forward<_UPair>(__p)); + second = std::get<1>(std::forward<_UPair>(__p)); + return *this; + } + + template<__eligible_pair_like<pair> _UPair> + requires (_S_const_assignable_from_tuple_like<_UPair>()) + constexpr const pair& + operator=(_UPair&& __p) const + { + first = std::get<0>(std::forward<_UPair>(__p)); + second = std::get<1>(std::forward<_UPair>(__p)); + return *this; + } +#endif // C++23 + #else // !__cpp_lib_concepts // C++11/14/17 implementation using enable_if, partially constexpr. diff --git a/libstdc++-v3/include/bits/utility.h b/libstdc++-v3/include/bits/utility.h index d8a5fb9..2a741bf 100644 --- a/libstdc++-v3/include/bits/utility.h +++ b/libstdc++-v3/include/bits/utility.h @@ -266,6 +266,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif #endif +#if __glibcxx_ranges + namespace ranges::__detail + { + template<typename _Range> + inline constexpr bool __is_subrange = false; + } // namespace __detail +#endif + _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 8fb8a28..502961e 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1780,6 +1780,14 @@ ftms = { }; }; +ftms = { + name = tuple_like; + values = { + v = 202207; + cxxmin = 23; + }; +}; + // Standard test specifications. stds[97] = ">= 199711L"; stds[03] = ">= 199711L"; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index fa4e89c..7a6fbd3 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -1983,4 +1983,14 @@ #endif /* !defined(__cpp_lib_generator) && defined(__glibcxx_want_generator) */ #undef __glibcxx_want_generator +#if !defined(__cpp_lib_tuple_like) +# if (__cplusplus >= 202100L) +# define __glibcxx_tuple_like 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_tuple_like) +# define __cpp_lib_tuple_like 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_tuple_like) && defined(__glibcxx_want_tuple_like) */ +#undef __glibcxx_want_tuple_like + #undef __glibcxx_want_all diff --git a/libstdc++-v3/include/std/concepts b/libstdc++-v3/include/std/concepts index 66ed371..4f3e059 100644 --- a/libstdc++-v3/include/std/concepts +++ b/libstdc++-v3/include/std/concepts @@ -62,6 +62,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION concept same_as = __detail::__same_as<_Tp, _Up> && __detail::__same_as<_Up, _Tp>; + namespace __detail + { + template<typename _Tp, typename _Up> + concept __different_from + = !same_as<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>; + } // namespace __detail + /// [concept.derived], concept derived_from template<typename _Derived, typename _Base> concept derived_from = __is_base_of(_Base, _Derived) @@ -185,8 +192,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Up> concept __adl_swap - = (__detail::__class_or_enum<remove_reference_t<_Tp>> - || __detail::__class_or_enum<remove_reference_t<_Up>>) + = (std::__detail::__class_or_enum<remove_reference_t<_Tp>> + || std::__detail::__class_or_enum<remove_reference_t<_Up>>) && requires(_Tp&& __t, _Up&& __u) { swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }; diff --git a/libstdc++-v3/include/std/map b/libstdc++-v3/include/std/map index dcfd222..4a96e59 100644 --- a/libstdc++-v3/include/std/map +++ b/libstdc++-v3/include/std/map @@ -74,6 +74,7 @@ #define __glibcxx_want_map_try_emplace #define __glibcxx_want_node_extract #define __glibcxx_want_nonmember_container_access +#define __glibcxx_want_tuple_like #include <bits/version.h> #if __cplusplus >= 201703L diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index f2413ba..7d73985 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -2389,11 +2389,7 @@ namespace views::__adaptor inline constexpr bool __is_basic_string_view<basic_string_view<_CharT, _Traits>> = true; - template<typename _Range> - inline constexpr bool __is_subrange = false; - - template<typename _Iter, typename _Sent, subrange_kind _Kind> - inline constexpr bool __is_subrange<subrange<_Iter, _Sent, _Kind>> = true; + using ranges::__detail::__is_subrange; template<typename _Range> inline constexpr bool __is_iota_view = false; @@ -4166,6 +4162,10 @@ namespace views::__adaptor namespace __detail { +#if __cpp_lib_tuple_like // >= C++23 + template<typename _Tp, size_t _Nm> + concept __has_tuple_element = __tuple_like<_Tp> && _Nm < tuple_size_v<_Tp>; +#else template<typename _Tp, size_t _Nm> concept __has_tuple_element = requires(_Tp __t) { @@ -4175,6 +4175,7 @@ namespace views::__adaptor { std::get<_Nm>(__t) } -> convertible_to<const tuple_element_t<_Nm, _Tp>&>; }; +#endif template<typename _Tp, size_t _Nm> concept __returnable_element @@ -4559,23 +4560,12 @@ namespace views::__adaptor || (!(bidirectional_range<_Rs> && ...) && (common_range<_Rs> && ...)) || ((random_access_range<_Rs> && ...) && (sized_range<_Rs> && ...)); - template<typename... _Ts> - struct __tuple_or_pair - { using type = std::tuple<_Ts...>; }; - - template<typename _Tp, typename _Up> - struct __tuple_or_pair<_Tp, _Up> - { using type = pair<_Tp, _Up>; }; - - template<typename... _Ts> - using __tuple_or_pair_t = typename __tuple_or_pair<_Ts...>::type; - template<typename _Fp, typename _Tuple> constexpr auto __tuple_transform(_Fp&& __f, _Tuple&& __tuple) { return std::apply([&]<typename... _Ts>(_Ts&&... __elts) { - return __tuple_or_pair_t<invoke_result_t<_Fp&, _Ts>...> + return tuple<invoke_result_t<_Fp&, _Ts>...> (std::__invoke(__f, std::forward<_Ts>(__elts))...); }, std::forward<_Tuple>(__tuple)); } @@ -4696,7 +4686,7 @@ namespace views::__adaptor #ifdef __clang__ // LLVM-61763 workaround public: #endif - __detail::__tuple_or_pair_t<iterator_t<__detail::__maybe_const_t<_Const, _Vs>>...> _M_current; + tuple<iterator_t<__detail::__maybe_const_t<_Const, _Vs>>...> _M_current; constexpr explicit _Iterator(decltype(_M_current) __current) @@ -4728,7 +4718,7 @@ namespace views::__adaptor // iterator_category defined in __zip_view_iter_cat using iterator_concept = decltype(_S_iter_concept()); using value_type - = __detail::__tuple_or_pair_t<range_value_t<__detail::__maybe_const_t<_Const, _Vs>>...>; + = tuple<range_value_t<__detail::__maybe_const_t<_Const, _Vs>>...>; using difference_type = common_type_t<range_difference_t<__detail::__maybe_const_t<_Const, _Vs>>...>; @@ -4900,7 +4890,7 @@ namespace views::__adaptor template<bool _Const> class zip_view<_Vs...>::_Sentinel { - __detail::__tuple_or_pair_t<sentinel_t<__detail::__maybe_const_t<_Const, _Vs>>...> _M_end; + tuple<sentinel_t<__detail::__maybe_const_t<_Const, _Vs>>...> _M_end; constexpr explicit _Sentinel(decltype(_M_end) __end) @@ -8325,8 +8315,7 @@ namespace views::__adaptor && __detail::__cartesian_product_is_common<_First, _Vs...>) { auto __its = [this]<size_t... _Is>(index_sequence<_Is...>) { - using _Ret = __detail::__tuple_or_pair_t<iterator_t<_First>, - iterator_t<_Vs>...>; + using _Ret = tuple<iterator_t<_First>, iterator_t<_Vs>...>; bool __empty_tail = (ranges::empty(std::get<1 + _Is>(_M_bases)) || ...); auto& __first = std::get<0>(_M_bases); return _Ret{(__empty_tail @@ -8342,8 +8331,7 @@ namespace views::__adaptor end() const requires __detail::__cartesian_product_is_common<const _First, const _Vs...> { auto __its = [this]<size_t... _Is>(index_sequence<_Is...>) { - using _Ret = __detail::__tuple_or_pair_t<iterator_t<const _First>, - iterator_t<const _Vs>...>; + using _Ret = tuple<iterator_t<const _First>, iterator_t<const _Vs>...>; bool __empty_tail = (ranges::empty(std::get<1 + _Is>(_M_bases)) || ...); auto& __first = std::get<0>(_M_bases); return _Ret{(__empty_tail @@ -8416,8 +8404,8 @@ namespace views::__adaptor { using _Parent = __maybe_const_t<_Const, cartesian_product_view>; _Parent* _M_parent = nullptr; - __detail::__tuple_or_pair_t<iterator_t<__maybe_const_t<_Const, _First>>, - iterator_t<__maybe_const_t<_Const, _Vs>>...> _M_current; + tuple<iterator_t<__maybe_const_t<_Const, _First>>, + iterator_t<__maybe_const_t<_Const, _Vs>>...> _M_current; constexpr _Iterator(_Parent& __parent, decltype(_M_current) __current) @@ -8444,11 +8432,11 @@ namespace views::__adaptor using iterator_category = input_iterator_tag; using iterator_concept = decltype(_S_iter_concept()); using value_type - = __detail::__tuple_or_pair_t<range_value_t<__maybe_const_t<_Const, _First>>, - range_value_t<__maybe_const_t<_Const, _Vs>>...>; + = tuple<range_value_t<__maybe_const_t<_Const, _First>>, + range_value_t<__maybe_const_t<_Const, _Vs>>...>; using reference - = __detail::__tuple_or_pair_t<range_reference_t<__maybe_const_t<_Const, _First>>, - range_reference_t<__maybe_const_t<_Const, _Vs>>...>; + = tuple<range_reference_t<__maybe_const_t<_Const, _First>>, + range_reference_t<__maybe_const_t<_Const, _Vs>>...>; using difference_type = decltype(cartesian_product_view::_S_difference_type()); _Iterator() = default; diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index be92f1e..9c89c13 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -50,6 +50,7 @@ #define __glibcxx_want_apply #define __glibcxx_want_make_from_tuple #define __glibcxx_want_ranges_zip +#define __glibcxx_want_tuple_like #include <bits/version.h> namespace std _GLIBCXX_VISIBILITY(default) @@ -246,6 +247,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Head _M_head_impl; }; +#if __cpp_lib_tuple_like // >= C++23 + struct __tuple_like_tag_t { explicit __tuple_like_tag_t() = default; }; + + // These forward declarations are used by the operator<=> overload for + // tuple-like types. + template<typename _Cat, typename _Tp, typename _Up> + constexpr _Cat + __tuple_cmp(const _Tp&, const _Up&, index_sequence<>); + + template<typename _Cat, typename _Tp, typename _Up, + size_t _Idx0, size_t... _Idxs> + constexpr _Cat + __tuple_cmp(const _Tp& __t, const _Up& __u, + index_sequence<_Idx0, _Idxs...>); +#endif // C++23 + /** * Contains the actual implementation of the @c tuple template, stored * as a recursive inheritance hierarchy from the first element (most @@ -342,6 +359,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template<typename _UTuple, size_t... _Is> + constexpr + _Tuple_impl(__tuple_like_tag_t, _UTuple&& __u, index_sequence<_Is...>) + : _Tuple_impl(std::get<_Is>(std::forward<_UTuple>(__u))...) + { } +#endif // C++23 + template<typename _Alloc> _GLIBCXX20_CONSTEXPR _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) @@ -428,6 +453,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template<typename _Alloc, typename _UTuple, size_t... _Is> + constexpr + _Tuple_impl(__tuple_like_tag_t, allocator_arg_t __tag, const _Alloc& __a, + _UTuple&& __u, index_sequence<_Is...>) + : _Tuple_impl(__tag, __a, std::get<_Is>(std::forward<_UTuple>(__u))...) + { } +#endif // C++23 + template<typename... _UElements> _GLIBCXX20_CONSTEXPR void @@ -470,6 +504,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template<typename _UTuple> + constexpr void + _M_assign(__tuple_like_tag_t __tag, _UTuple&& __u) + { + _M_head(*this) = std::get<_Idx>(std::forward<_UTuple>(__u)); + _M_tail(*this)._M_assign(__tag, std::forward<_UTuple>(__u)); + } + + template<typename _UTuple> + constexpr void + _M_assign(__tuple_like_tag_t __tag, _UTuple&& __u) const + { + _M_head(*this) = std::get<_Idx>(std::forward<_UTuple>(__u)); + _M_tail(*this)._M_assign(__tag, std::forward<_UTuple>(__u)); + } +#endif // C++23 + protected: _GLIBCXX20_CONSTEXPR void @@ -563,6 +615,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template<typename _UTuple> + constexpr + _Tuple_impl(__tuple_like_tag_t, _UTuple&& __u, index_sequence<0>) + : _Tuple_impl(std::get<0>(std::forward<_UTuple>(__u))) + { } +#endif // C++23 + template<typename _Alloc> _GLIBCXX20_CONSTEXPR _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) @@ -633,6 +693,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template<typename _Alloc, typename _UTuple> + constexpr + _Tuple_impl(__tuple_like_tag_t, allocator_arg_t __tag, const _Alloc& __a, + _UTuple&& __u, index_sequence<0>) + : _Tuple_impl(__tag, __a, std::get<0>(std::forward<_UTuple>(__u))) + { } +#endif // C++23 + template<typename _UHead> _GLIBCXX20_CONSTEXPR void @@ -667,6 +736,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template<typename _UTuple> + constexpr void + _M_assign(__tuple_like_tag_t, _UTuple&& __u) + { _M_head(*this) = std::get<_Idx>(std::forward<_UTuple>(__u)); } + + template<typename _UTuple> + constexpr void + _M_assign(__tuple_like_tag_t, _UTuple&& __u) const + { _M_head(*this) = std::get<_Idx>(std::forward<_UTuple>(__u)); } +#endif // C++23 + protected: _GLIBCXX20_CONSTEXPR void @@ -846,6 +927,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif } +#if __cpp_lib_tuple_like // >= C++23 + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4045. tuple can create dangling references from tuple-like + template<typename _UTuple> + static consteval bool + __dangles_from_tuple_like() + { + return []<size_t... _Is>(index_sequence<_Is...>) { + return __dangles<decltype(std::get<_Is>(std::declval<_UTuple>()))...>(); + }(index_sequence_for<_Elements...>{}); + } + + template<typename _UTuple> + static consteval bool + __constructible_from_tuple_like() + { + return []<size_t... _Is>(index_sequence<_Is...>) { + return __constructible<decltype(std::get<_Is>(std::declval<_UTuple>()))...>(); + }(index_sequence_for<_Elements...>{}); + } + + template<typename _UTuple> + static consteval bool + __convertible_from_tuple_like() + { + return []<size_t... _Is>(index_sequence<_Is...>) { + return __convertible<decltype(std::get<_Is>(std::declval<_UTuple>()))...>(); + }(index_sequence_for<_Elements...>{}); + } +#endif // C++23 + public: constexpr explicit(!(__is_implicitly_default_constructible_v<_Elements> && ...)) @@ -1016,10 +1128,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION tuple(const pair<_U1, _U2>&&) = delete; #endif // C++23 -#if 0 && __cpp_lib_tuple_like // >= C++23 - template<__tuple_like _UTuple> - constexpr explicit(...) - tuple(_UTuple&& __u); +#if __cpp_lib_tuple_like // >= C++23 + template<__eligible_tuple_like<tuple> _UTuple> + requires (__constructible_from_tuple_like<_UTuple>()) + && (!__use_other_ctor<_UTuple>()) + && (!__dangles_from_tuple_like<_UTuple>()) + constexpr explicit(!__convertible_from_tuple_like<_UTuple>()) + tuple(_UTuple&& __u) + : _Inherited(__tuple_like_tag_t{}, + std::forward<_UTuple>(__u), + index_sequence_for<_Elements...>{}) + { } + + template<__eligible_tuple_like<tuple> _UTuple> + requires (__constructible_from_tuple_like<_UTuple>()) + && (!__use_other_ctor<_UTuple>()) + && (__dangles_from_tuple_like<_UTuple>()) + tuple(_UTuple&&) = delete; #endif // C++23 // Allocator-extended constructors. @@ -1202,10 +1327,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION tuple(allocator_arg_t, const _Alloc&, const pair<_U1, _U2>&&) = delete; #endif // C++23 -#if 0 && __cpp_lib_tuple_like // >= C++23 - template<typename _Alloc, __tuple_like _UTuple> - constexpr explicit(...) - tuple(allocator_arg_t __tag, const _Alloc& __a, _UTuple&& __u); +#if __cpp_lib_tuple_like // >= C++23 + template<typename _Alloc, __eligible_tuple_like<tuple> _UTuple> + requires (__constructible_from_tuple_like<_UTuple>()) + && (!__use_other_ctor<_UTuple>()) + && (!__dangles_from_tuple_like<_UTuple>()) + constexpr explicit(!__convertible_from_tuple_like<_UTuple>()) + tuple(allocator_arg_t __tag, const _Alloc& __a, _UTuple&& __u) + : _Inherited(__tuple_like_tag_t{}, + __tag, __a, std::forward<_UTuple>(__u), + index_sequence_for<_Elements...>{}) + { } + + template<typename _Alloc, __eligible_tuple_like<tuple> _UTuple> + requires (__constructible_from_tuple_like<_UTuple>()) + && (!__use_other_ctor<_UTuple>()) + && (__dangles_from_tuple_like<_UTuple>()) + tuple(allocator_arg_t, const _Alloc&, _UTuple&&) = delete; #endif // C++23 #else // !(concepts && conditional_explicit) @@ -1539,6 +1677,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif // C++23 +#if __cpp_lib_tuple_like // >= C++23 + template<typename _UTuple> + static consteval bool + __assignable_from_tuple_like() + { + return []<size_t... _Is>(index_sequence<_Is...>) { + return __assignable<decltype(std::get<_Is>(std::declval<_UTuple>()))...>(); + }(index_sequence_for<_Elements...>{}); + } + + template<typename _UTuple> + static consteval bool + __const_assignable_from_tuple_like() + { + return []<size_t... _Is>(index_sequence<_Is...>) { + return __const_assignable<decltype(std::get<_Is>(std::declval<_UTuple>()))...>(); + }(index_sequence_for<_Elements...>{}); + } +#endif // C++23 + public: tuple& operator=(const tuple& __u) = delete; @@ -1661,14 +1819,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif // C++23 -#if 0 && __cpp_lib_tuple_like // >= C++23 - template<__tuple_like _UTuple> +#if __cpp_lib_tuple_like // >= C++23 + template<__eligible_tuple_like<tuple> _UTuple> + requires (__assignable_from_tuple_like<_UTuple>()) constexpr tuple& - operator=(_UTuple&& __u); + operator=(_UTuple&& __u) + { + this->_M_assign(__tuple_like_tag_t{}, std::forward<_UTuple>(__u)); + return *this; + } + + template<__eligible_tuple_like<tuple> _UTuple> + requires (__const_assignable_from_tuple_like<_UTuple>()) + constexpr const tuple& + operator=(_UTuple&& __u) const + { + this->_M_assign(__tuple_like_tag_t{}, std::forward<_UTuple>(__u)); + return *this; + } template<__tuple_like _UTuple> - constexpr tuple& - operator=(_UTuple&& __u) const; + requires (!__is_tuple_v<_UTuple>) + friend constexpr bool + operator==(const tuple& __t, const _UTuple& __u) + { + static_assert(sizeof...(_Elements) == tuple_size_v<_UTuple>, + "tuple objects can only be compared if they have equal sizes."); + return [&]<size_t... _Is>(index_sequence<_Is...>) { + return (bool(std::get<_Is>(__t) == std::get<_Is>(__u)) + && ...); + }(index_sequence_for<_Elements...>{}); + } + + template<__tuple_like _UTuple, + typename = make_index_sequence<tuple_size_v<_UTuple>>> + struct __tuple_like_common_comparison_category; + + template<__tuple_like _UTuple, size_t... _Is> + requires requires + { typename void_t<__detail::__synth3way_t<_Elements, tuple_element_t<_Is, _UTuple>>...>; } + struct __tuple_like_common_comparison_category<_UTuple, index_sequence<_Is...>> + { + using type = common_comparison_category_t + <__detail::__synth3way_t<_Elements, tuple_element_t<_Is, _UTuple>>...>; + }; + + template<__tuple_like _UTuple> + requires (!__is_tuple_v<_UTuple>) + friend constexpr typename __tuple_like_common_comparison_category<_UTuple>::type + operator<=>(const tuple& __t, const _UTuple& __u) + { + using _Cat = typename __tuple_like_common_comparison_category<_UTuple>::type; + return std::__tuple_cmp<_Cat>(__t, __u, index_sequence_for<_Elements...>()); + } #endif // C++23 #else // ! (concepts && consteval) @@ -2433,27 +2636,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION forward_as_tuple(_Elements&&... __args) noexcept { return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); } - // Declarations of std::array and its std::get overloads, so that - // std::tuple_cat can use them if <tuple> is included before <array>. - - template<typename _Tp, size_t _Nm> struct array; - - template<size_t _Int, typename _Tp, size_t _Nm> - constexpr _Tp& - get(array<_Tp, _Nm>&) noexcept; - - template<size_t _Int, typename _Tp, size_t _Nm> - constexpr _Tp&& - get(array<_Tp, _Nm>&&) noexcept; - - template<size_t _Int, typename _Tp, size_t _Nm> - constexpr const _Tp& - get(const array<_Tp, _Nm>&) noexcept; - - template<size_t _Int, typename _Tp, size_t _Nm> - constexpr const _Tp&& - get(const array<_Tp, _Nm>&&) noexcept; - /// @cond undocumented template<size_t, typename, typename, size_t> struct __make_tuple_impl; @@ -2569,8 +2751,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @endcond /// Create a `tuple` containing all elements from multiple tuple-like objects +#if __cpp_lib_tuple_like // >= C++23 + template<__tuple_like... _Tpls> +#else template<typename... _Tpls, typename = typename enable_if<__and_<__is_tuple_like<_Tpls>...>::value>::type> +#endif constexpr auto tuple_cat(_Tpls&&... __tpls) -> typename __tuple_cat_result<_Tpls...>::__type @@ -2722,7 +2908,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::get<_Idx>(std::forward<_Tuple>(__t))...); } +#if __cpp_lib_tuple_like // >= C++23 + template <typename _Fn, __tuple_like _Tuple> +#else template <typename _Fn, typename _Tuple> +#endif constexpr decltype(auto) apply(_Fn&& __f, _Tuple&& __t) noexcept(__unpack_std_tuple<is_nothrow_invocable, _Fn, _Tuple>) @@ -2741,7 +2931,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>) { return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); } +#if __cpp_lib_tuple_like // >= C++23 + template <typename _Tp, __tuple_like _Tuple> +#else template <typename _Tp, typename _Tuple> +#endif constexpr _Tp make_from_tuple(_Tuple&& __t) noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _Tuple>) @@ -2759,17 +2953,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif -#if __cpp_lib_ranges_zip // >= C++23 - template<typename... _TTypes, typename... _UTypes, +#if __cpp_lib_tuple_like // >= C++23 + template<__tuple_like _TTuple, __tuple_like _UTuple, + template<typename> class _TQual, template<typename> class _UQual, + typename = make_index_sequence<tuple_size_v<_TTuple>>> + struct __tuple_like_common_reference; + + template<__tuple_like _TTuple, __tuple_like _UTuple, + template<typename> class _TQual, template<typename> class _UQual, + size_t... _Is> + requires requires + { typename tuple<common_reference_t<_TQual<tuple_element_t<_Is, _TTuple>>, + _UQual<tuple_element_t<_Is, _UTuple>>>...>; } + struct __tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual, index_sequence<_Is...>> + { + using type = tuple<common_reference_t<_TQual<tuple_element_t<_Is, _TTuple>>, + _UQual<tuple_element_t<_Is, _UTuple>>>...>; + }; + + template<__tuple_like _TTuple, __tuple_like _UTuple, template<typename> class _TQual, template<typename> class _UQual> - requires requires { typename tuple<common_reference_t<_TQual<_TTypes>, _UQual<_UTypes>>...>; } - struct basic_common_reference<tuple<_TTypes...>, tuple<_UTypes...>, _TQual, _UQual> - { using type = tuple<common_reference_t<_TQual<_TTypes>, _UQual<_UTypes>>...>; }; - - template<typename... _TTypes, typename... _UTypes> - requires requires { typename tuple<common_type_t<_TTypes, _UTypes>...>; } - struct common_type<tuple<_TTypes...>, tuple<_UTypes...>> - { using type = tuple<common_type_t<_TTypes, _UTypes>...>; }; + requires (__is_tuple_v<_TTuple> || __is_tuple_v<_UTuple>) + && is_same_v<_TTuple, decay_t<_TTuple>> + && is_same_v<_UTuple, decay_t<_UTuple>> + && (tuple_size_v<_TTuple> == tuple_size_v<_UTuple>) + && requires { typename __tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual>::type; } + struct basic_common_reference<_TTuple, _UTuple, _TQual, _UQual> + { + using type = typename __tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual>::type; + }; + + template<__tuple_like _TTuple, __tuple_like _UTuple, + typename = make_index_sequence<tuple_size_v<_TTuple>>> + struct __tuple_like_common_type; + + template<__tuple_like _TTuple, __tuple_like _UTuple, size_t... _Is> + requires requires + { typename tuple<common_type_t<tuple_element_t<_Is, _TTuple>, + tuple_element_t<_Is, _UTuple>>...>; } + struct __tuple_like_common_type<_TTuple, _UTuple, index_sequence<_Is...>> + { + using type = tuple<common_type_t<tuple_element_t<_Is, _TTuple>, + tuple_element_t<_Is, _UTuple>>...>; + }; + + template<__tuple_like _TTuple, __tuple_like _UTuple> + requires (__is_tuple_v<_TTuple> || __is_tuple_v<_UTuple>) + && is_same_v<_TTuple, decay_t<_TTuple>> + && is_same_v<_UTuple, decay_t<_UTuple>> + && (tuple_size_v<_TTuple> == tuple_size_v<_UTuple>) + && requires { typename __tuple_like_common_type<_TTuple, _UTuple>::type; } + struct common_type<_TTuple, _UTuple> + { + using type = typename __tuple_like_common_type<_TTuple, _UTuple>::type; + }; #endif // C++23 /// @} diff --git a/libstdc++-v3/include/std/unordered_map b/libstdc++-v3/include/std/unordered_map index efad0ce..ea6129d 100644 --- a/libstdc++-v3/include/std/unordered_map +++ b/libstdc++-v3/include/std/unordered_map @@ -51,6 +51,7 @@ #define __glibcxx_want_node_extract #define __glibcxx_want_nonmember_container_access #define __glibcxx_want_unordered_map_try_emplace +#define __glibcxx_want_tuple_like #include <bits/version.h> #if __cplusplus >= 201703L diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility index f113d572..212513f 100644 --- a/libstdc++-v3/include/std/utility +++ b/libstdc++-v3/include/std/utility @@ -92,6 +92,7 @@ #define __glibcxx_want_tuple_element_t #define __glibcxx_want_tuples_by_type #define __glibcxx_want_unreachable +#define __glibcxx_want_tuple_like #include <bits/version.h> namespace std _GLIBCXX_VISIBILITY(default) diff --git a/libstdc++-v3/testsuite/20_util/pair/p2165r4.cc b/libstdc++-v3/testsuite/20_util/pair/p2165r4.cc new file mode 100644 index 0000000..ef06df1 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/pair/p2165r4.cc @@ -0,0 +1,173 @@ +// Verify P2165R4 enhancements to std::pair. +// { dg-do run { target c++23 } } + +#include <array> +#include <tuple> +#include <utility> +#include <testsuite_hooks.h> + +using std::array; +using std::pair; +using std::tuple; + +struct A { }; + +template<template<typename> class pair_like_t> +constexpr bool +test01() +{ + struct B { + int m; + constexpr B(A&) : m(0) { } + constexpr B(A&&) : m(1) { } + constexpr B(const A&) : m(2) { } + constexpr B(const A&&) : m(3) { } + }; + + // template<pair-like UPair> + // constexpr explicit(false) pair(UPair&&); + + pair_like_t<A> pair_like; + + [&] { + pair<B, B> p2b = pair_like; + VERIFY( p2b.first.m == 0 && p2b.second.m == 0 ); + }(); + [&] { + pair<B, B> p2b = std::move(pair_like); + VERIFY( p2b.first.m == 1 && p2b.second.m == 1 ); + }(); + [&] { + pair<B, B> p2b = std::as_const(pair_like); + VERIFY( p2b.first.m == 2 && p2b.second.m == 2 ); + }(); + [&] { + pair<B, B> p2b = std::move(std::as_const(pair_like)); + VERIFY( p2b.first.m == 3 && p2b.second.m == 3 ); + }(); + + // Verify dangling checks. + static_assert( !std::is_constructible_v<pair<const int&, int>, pair_like_t<long>> ); + static_assert( !std::is_constructible_v<pair<int, const int&>, pair_like_t<long>> ); + + return true; +} + +template<template<typename> class pair_like_t> +constexpr bool +test02() +{ + struct B { + int m; + constexpr explicit B(A&) : m(0) { } + constexpr explicit B(A&&) : m(1) { } + constexpr explicit B(const A&) : m(2) { } + constexpr explicit B(const A&&) : m(3) { } + }; + + // template<pair-like UPair> + // constexpr explicit(true) pair(UPair&&); + + static_assert( !std::is_convertible_v<pair_like_t<A>, pair<B, B>> ); + + pair_like_t<A> pair_like; + + [&] { + pair<B, B> p2b{pair_like}; + VERIFY( p2b.first.m == 0 && p2b.second.m == 0 ); + }(); + [&] { + pair<B, B> p2b{std::move(pair_like)}; + VERIFY( p2b.first.m == 1 && p2b.second.m == 1 ); + }(); + [&] { + pair<B, B> p2b{std::as_const(pair_like)}; + VERIFY( p2b.first.m == 2 && p2b.second.m == 2 ); + }(); + [&] { + pair<B, B> p2b{std::move(std::as_const(pair_like))}; + VERIFY( p2b.first.m == 3 && p2b.second.m == 3 ); + }(); + + return true; +} + +template<template<typename> class pair_like_t> +constexpr bool +test03() +{ + struct B { + int m; + constexpr B& operator=(A&) { m = 0; return *this; } + constexpr B& operator=(A&&) { m = 1; return *this; } + constexpr B& operator=(const A&) { m = 2; return *this; } + constexpr B& operator=(const A&&) { m = 3; return *this; } + }; + + // template<pair-like UPair> + // constexpr pair& operator=(UPair&&); + + pair_like_t<A> pair_like; + + pair<B, B> p2b; + p2b = pair_like; + VERIFY( p2b.first.m == 0 && p2b.second.m == 0 ); + p2b = std::move(pair_like); + VERIFY( p2b.first.m == 1 && p2b.second.m == 1 ); + p2b = std::as_const(pair_like); + VERIFY( p2b.first.m == 2 && p2b.second.m == 2 ); + p2b = std::move(std::as_const(pair_like)); + VERIFY( p2b.first.m == 3 && p2b.second.m == 3 ); + + return true; +} + +template<template<typename> class pair_like_t> +constexpr bool +test04() +{ + struct B { + mutable int m; + constexpr const B& operator=(A&) const { m = 0; return *this; } + constexpr const B& operator=(A&&) const { m = 1; return *this; } + constexpr const B& operator=(const A&) const { m = 2; return *this; } + constexpr const B& operator=(const A&&) const { m = 3; return *this; } + }; + + // template<pair-like UPair> + // constexpr const pair& operator=(UPair&&) const; + + pair_like_t<A> pair_like; + + const pair<B, B> p2b; + p2b = pair_like; + VERIFY( p2b.first.m == 0 && p2b.second.m == 0 ); + p2b = std::move(pair_like); + VERIFY( p2b.first.m == 1 && p2b.second.m == 1 ); + p2b = std::as_const(pair_like); + VERIFY( p2b.first.m == 2 && p2b.second.m == 2 ); + p2b = std::move(std::as_const(pair_like)); + VERIFY( p2b.first.m == 3 && p2b.second.m == 3 ); + + return true; +} + +template<typename T> +using pair_like_array = array<T, 2>; + +template<typename T> +using pair_like_tuple = tuple<T, T>; + +int +main() +{ + static_assert( test01<pair_like_array>() ); + static_assert( test02<pair_like_array>() ); + static_assert( test03<pair_like_array>() ); + static_assert( test04<pair_like_array>() ); + + static_assert( test01<pair_like_tuple>() ); + static_assert( test02<pair_like_tuple>() ); + static_assert( test03<pair_like_tuple>() ); + static_assert( test04<pair_like_tuple>() ); +} diff --git a/libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc b/libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc new file mode 100644 index 0000000..e2437c4 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc @@ -0,0 +1,335 @@ +// Verify P2165R4 enhancements to std::tuple. +// { dg-do run { target c++23 } } + +#include <array> +#include <tuple> +#include <utility> +#include <memory> +#include <testsuite_hooks.h> + +using std::array; +using std::pair; +using std::tuple; +using std::allocator; +using std::allocator_arg_t; +using std::allocator_arg; + +namespace alloc { + struct B01; + struct B02; +} + +template<> struct std::uses_allocator<alloc::B01, allocator<int>> : std::true_type { }; +template<> struct std::uses_allocator<alloc::B02, allocator<int>> : std::true_type { }; + +struct A { }; + +template<template<typename> class tuple_like_t> +constexpr bool +test01() +{ + struct B { + int m; + constexpr B(A&) : m(0) { } + constexpr B(A&&) : m(1) { } + constexpr B(const A&) : m(2) { } + constexpr B(const A&&) : m(3) { } + }; + + // template<tuple-like UTuple> + // constexpr explicit(false) tuple(UTuple&&); + + tuple_like_t<A> tuple_like; + + [&] { + tuple<B, B, B> t3b = tuple_like; + VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 ); + }(); + [&] { + tuple<B, B, B> t3b = std::move(tuple_like); + VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 ); + }(); + [&] { + tuple<B, B, B> t3b = std::as_const(tuple_like); + VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 ); + }(); + [&] { + tuple<B, B, B> t3b = std::move(std::as_const(tuple_like)); + VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 ); + }(); + + // Verify dangling checks. + static_assert( !std::is_constructible_v<tuple<const int&, int, int>, tuple_like_t<long>> ); + static_assert( !std::is_constructible_v<tuple<int, const int&, int>, tuple_like_t<long>> ); + static_assert( !std::is_constructible_v<tuple<int, int, const int&>, tuple_like_t<long>> ); + + return true; +} + +namespace alloc +{ + struct B01 { + int m; + B01(A&); + B01(A&&); + B01(const A&); + B01(const A&&); + constexpr B01(allocator_arg_t, allocator<int>, A&) : m(0) { } + constexpr B01(allocator_arg_t, allocator<int>, A&&) : m(1) { } + constexpr B01(allocator_arg_t, allocator<int>, const A&) : m(2) { } + constexpr B01(allocator_arg_t, allocator<int>, const A&&) : m(3) { } + }; + + template<template<typename> class tuple_like_t> + constexpr bool + test01() + { + using B = B01; + + // template<tuple-like UTuple> + // constexpr explicit(false) tuple(allocator_arg_t, const Alloc&, UTuple&&); + + tuple_like_t<A> tuple_like; + + [&] { + tuple<B, B, B> t3b = {allocator_arg, allocator<int>{}, tuple_like}; + VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 ); + }(); + [&] { + tuple<B, B, B> t3b = {allocator_arg, allocator<int>{}, std::move(tuple_like)}; + VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 ); + }(); + [&] { + tuple<B, B, B> t3b = {allocator_arg, allocator<int>{}, std::as_const(tuple_like)}; + VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 ); + }(); + [&] { + tuple<B, B, B> t3b = {allocator_arg, allocator<int>{}, std::move(std::as_const(tuple_like))}; + VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 ); + }(); + + // Verify dangling checks. + static_assert( !std::is_constructible_v<tuple<const int&, int, int>, + allocator_arg_t, allocator<int>, + tuple_like_t<long>> ); + static_assert( !std::is_constructible_v<tuple<int, const int&, int>, + allocator_arg_t, allocator<int>, + tuple_like_t<long>> ); + static_assert( !std::is_constructible_v<tuple<int, int, const int&>, + allocator_arg_t, allocator<int>, + tuple_like_t<long>> ); + + return true; + } +} + +template<template<typename> class tuple_like_t> +constexpr bool +test02() +{ + struct B { + int m; + constexpr explicit B(A&) : m(0) { } + constexpr explicit B(A&&) : m(1) { } + constexpr explicit B(const A&) : m(2) { } + constexpr explicit B(const A&&) : m(3) { } + }; + + // template<tuple-like UTuple> + // constexpr explicit(true) tuple(UTuple&&); + + static_assert( !std::is_convertible_v<tuple_like_t<A>, tuple<B, B, B>> ); + + tuple_like_t<A> tuple_like; + + [&] { + tuple<B, B, B> t3b{tuple_like}; + VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 ); + }(); + [&] { + tuple<B, B, B> t3b{std::move(tuple_like)}; + VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 ); + }(); + [&] { + tuple<B, B, B> t3b{std::as_const(tuple_like)}; + VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 ); + }(); + [&] { + tuple<B, B, B> t3b{std::move(std::as_const(tuple_like))}; + VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 ); + }(); + + return true; +} + +namespace alloc +{ + struct B02 { + int m; + explicit B02(A&); + explicit B02(A&&); + explicit B02(const A&); + explicit B02(const A&&); + explicit constexpr B02(allocator_arg_t, allocator<int>, A&) : m(0) { } + explicit constexpr B02(allocator_arg_t, allocator<int>, A&&) : m(1) { } + explicit constexpr B02(allocator_arg_t, allocator<int>, const A&) : m(2) { } + explicit constexpr B02(allocator_arg_t, allocator<int>, const A&&) : m(3) { } + }; + + template<template<typename> class tuple_like_t> + constexpr bool + test02() + { + using B = B02; + + // template<tuple-like UTuple> + // constexpr explicit(true) tuple(allocator_arg_t, const Alloc&, UTuple&&); + + static_assert( !std::is_convertible_v<tuple_like_t<A>, tuple<B, B, B>> ); + + tuple_like_t<A> tuple_like; + + [&] { + tuple<B, B, B> t3b{allocator_arg, allocator<int>{}, tuple_like}; + VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 ); + }(); + [&] { + tuple<B, B, B> t3b{allocator_arg, allocator<int>{}, std::move(tuple_like)}; + VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 ); + }(); + [&] { + tuple<B, B, B> t3b{allocator_arg, allocator<int>{}, std::as_const(tuple_like)}; + VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 ); + }(); + [&] { + tuple<B, B, B> t3b{allocator_arg, allocator<int>{}, std::move(std::as_const(tuple_like))}; + VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 ); + }(); + + return true; + } +} + + +template<template<typename> class tuple_like_t> +constexpr bool +test03() +{ + struct B { + int m; + constexpr B& operator=(A&) { m = 0; return *this; } + constexpr B& operator=(A&&) { m = 1; return *this; } + constexpr B& operator=(const A&) { m = 2; return *this; } + constexpr B& operator=(const A&&) { m = 3; return *this; } + }; + + // template<tuple-like UTuple> + // constexpr tuple& operator=(UTuple&&); + + tuple_like_t<A> tuple_like; + + tuple<B, B, B> t3b; + t3b = tuple_like; + VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 ); + t3b = std::move(tuple_like); + VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 ); + t3b = std::as_const(tuple_like); + VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 ); + t3b = std::move(std::as_const(tuple_like)); + VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 ); + + return true; +} + +template<template<typename> class tuple_like_t> +constexpr bool +test04() +{ + struct B { + mutable int m; + constexpr const B& operator=(A&) const { m = 0; return *this; } + constexpr const B& operator=(A&&) const { m = 1; return *this; } + constexpr const B& operator=(const A&) const { m = 2; return *this; } + constexpr const B& operator=(const A&&) const { m = 3; return *this; } + }; + + // template<tuple-like UTuple> + // constexpr const tuple& operator=(UTuple&&) const; + + tuple_like_t<A> tuple_like; + + const tuple<B, B, B> t3b; + t3b = tuple_like; + VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 ); + t3b = std::move(tuple_like); + VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 ); + t3b = std::as_const(tuple_like); + VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 ); + t3b = std::move(std::as_const(tuple_like)); + VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 ); + + return true; +} + +template<template<typename> class tuple_like_t> +constexpr bool +test05() +{ + // template<tuple-like UTuple> + // constexpr bool operator==(const tuple&, const UTuple&); + + static_assert( tuple{1, 2, 3} == tuple_like_t{1, 2, 3} ); + static_assert( tuple{1, 2, 4} != tuple_like_t{1, 2, 3} ); + static_assert( tuple_like_t{1, 2, 3} == tuple{1, 2, 3} ); + static_assert( tuple_like_t{1, 2, 3} != tuple{1, 2, 4} ); + + // template<tuple-like UTuple> + // constexpr bool operator<=>const tuple&, const UTuple&); + + static_assert( (tuple{1, 2, 3} <=> tuple_like_t{1, 2, 3}) == std::strong_ordering::equal ); + static_assert( (tuple{1, 2, 4} <=> tuple_like_t{1, 2, 3}) == std::strong_ordering::greater ); + static_assert( (tuple_like_t{1, 2, 3} <=> tuple{1, 2, 3}) == std::strong_ordering::equal ); + static_assert( (tuple_like_t{1, 2, 3} <=> tuple{1, 2, 4}) == std::strong_ordering::less ); + + static_assert( tuple{1, 2, 4} > tuple_like_t{1, 2, 3} ); + static_assert( tuple_like_t{1, 2, 3} < tuple{1, 2, 4} ); + + // template<tuple-like TTuple, tuple-like UTuple, ...> + // struct basic_common_reference<TTuple, UTuple, ...>; + + static_assert( std::same_as<std::common_reference_t<tuple_like_t<int>, + tuple<int, long, int>>, + tuple<int, long, int>> ); + + static_assert( std::same_as<std::common_reference_t<tuple<int, long, int>, + tuple_like_t<int>>, + tuple<int, long, int>> ); + + // template<tuple-like TTuple, tuple-like UTuple> + // struct common_type<TTuple, UTuple>; + + static_assert( std::same_as<std::common_type_t<tuple_like_t<const int&>, + tuple<int, long, int>>, + tuple<int, long, int>> ); + + static_assert( std::same_as<std::common_type_t<tuple<int, long, int>, + tuple_like_t<const int&>>, + tuple<int, long, int>> ); + + return true; +} + +template<typename T> +using tuple_like_array = array<T, 3>; + +int +main() +{ + static_assert( test01<tuple_like_array>() ); + static_assert( alloc::test01<tuple_like_array>() ); + static_assert( test02<tuple_like_array>() ); + static_assert( alloc::test02<tuple_like_array>() ); + static_assert( test03<tuple_like_array>() ); + static_assert( test04<tuple_like_array>() ); + static_assert( test05<tuple_like_array>() ); +} diff --git a/libstdc++-v3/testsuite/std/ranges/zip/1.cc b/libstdc++-v3/testsuite/std/ranges/zip/1.cc index b7717ae..ea4274d 100644 --- a/libstdc++-v3/testsuite/std/ranges/zip/1.cc +++ b/libstdc++-v3/testsuite/std/ranges/zip/1.cc @@ -41,8 +41,8 @@ test01() VERIFY( i2 == z2.end() ); VERIFY( ranges::size(z2) == 2 ); VERIFY( ranges::size(std::as_const(z2)) == 2 ); - VERIFY( z2[0].first == 1 && z2[0].second == 3 ); - VERIFY( z2[1].first == 2 && z2[1].second == 4 ); + VERIFY( std::get<0>(z2[0]) == 1 && std::get<1>(z2[0]) == 3 ); + VERIFY( std::get<0>(z2[1]) == 2 && std::get<1>(z2[1]) == 4 ); for (const auto [x, y] : z2) { VERIFY( y - x == 2 ); @@ -124,6 +124,18 @@ test04() return true; } +constexpr bool +test05() +{ + // PR libstdc++/109203 + int x[] = {1, 1, 2}; + int y[] = {2, 1, 3}; + auto r = views::zip(x, y); + ranges::sort(r); + + return true; +} + int main() { @@ -131,4 +143,5 @@ main() static_assert(test02()); static_assert(test03()); static_assert(test04()); + static_assert(test05()); } |