Skip to content

Commit 1679b27

Browse files
authored
[libc++] Refactor __tuple_like and __pair_like (#85206)
The exposition-only type trait `pair-like` includes `ranges::subrange`, but in every single case excludes `ranges::subrange` from the list. This patch introduces two new traits `__tuple_like_no_subrange` and `__pair_like_no_subrange`, which exclude `ranges::subrange` from the possible matches. `__pair_like` is no longer required, and thus removed. `__tuple_like` is implemented as `__tuple_like_no_subrange` or a `ranges::subrange` specialization.
1 parent c7954ca commit 1679b27

File tree

14 files changed

+108
-104
lines changed

14 files changed

+108
-104
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,12 +709,12 @@ set(files
709709
__tree
710710
__tuple/find_index.h
711711
__tuple/make_tuple_types.h
712-
__tuple/pair_like.h
713712
__tuple/sfinae_helpers.h
714713
__tuple/tuple_element.h
715714
__tuple/tuple_indices.h
716715
__tuple/tuple_like.h
717716
__tuple/tuple_like_ext.h
717+
__tuple/tuple_like_no_subrange.h
718718
__tuple/tuple_size.h
719719
__tuple/tuple_types.h
720720
__type_traits/add_const.h

libcxx/include/__algorithm/mismatch.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
#include <__type_traits/invoke.h>
1919
#include <__type_traits/is_constant_evaluated.h>
2020
#include <__type_traits/is_equality_comparable.h>
21+
#include <__type_traits/is_integral.h>
2122
#include <__type_traits/operation_traits.h>
2223
#include <__utility/move.h>
2324
#include <__utility/pair.h>
2425
#include <__utility/unreachable.h>
26+
#include <cstddef>
2527

2628
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2729
# pragma GCC system_header

libcxx/include/__memory/uses_allocator_construction.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#include <__config>
1313
#include <__memory/construct_at.h>
1414
#include <__memory/uses_allocator.h>
15-
#include <__tuple/pair_like.h>
15+
#include <__tuple/tuple_like_no_subrange.h>
1616
#include <__type_traits/enable_if.h>
1717
#include <__type_traits/is_same.h>
1818
#include <__type_traits/remove_cv.h>
@@ -128,11 +128,7 @@ __uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>&&
128128
std::forward_as_tuple(std::get<1>(std::move(__pair))));
129129
}
130130

131-
template < class _Pair,
132-
class _Alloc,
133-
__pair_like _PairLike,
134-
__enable_if_t<__is_cv_std_pair<_Pair> && !__is_specialization_of_subrange<remove_cvref_t<_PairLike>>::value,
135-
int> = 0>
131+
template <class _Pair, class _Alloc, __pair_like_no_subrange _PairLike, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
136132
_LIBCPP_HIDE_FROM_ABI constexpr auto
137133
__uses_allocator_construction_args(const _Alloc& __alloc, _PairLike&& __p) noexcept {
138134
return std::__uses_allocator_construction_args<_Pair>(
@@ -161,9 +157,7 @@ inline constexpr bool __convertible_to_const_pair_ref =
161157
# if _LIBCPP_STD_VER >= 23
162158
template <class _Tp, class _Up>
163159
inline constexpr bool __uses_allocator_constraints =
164-
__is_cv_std_pair<_Tp> &&
165-
(__is_specialization_of_subrange<remove_cvref_t<_Up>>::value ||
166-
(!__pair_like<_Up> && !__convertible_to_const_pair_ref<_Up>));
160+
__is_cv_std_pair<_Tp> && !__pair_like_no_subrange<_Up> && !__convertible_to_const_pair_ref<_Up>;
167161
# else
168162
template <class _Tp, class _Up>
169163
inline constexpr bool __uses_allocator_constraints = __is_cv_std_pair<_Tp> && !__convertible_to_const_pair_ref<_Up>;

libcxx/include/__memory_resource/polymorphic_allocator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <__assert>
1313
#include <__availability>
1414
#include <__config>
15+
#include <__fwd/pair.h>
1516
#include <__memory_resource/memory_resource.h>
1617
#include <__utility/exception_guard.h>
1718
#include <cstddef>

libcxx/include/__ranges/subrange.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
#include <__ranges/enable_borrowed_range.h>
2929
#include <__ranges/size.h>
3030
#include <__ranges/view_interface.h>
31-
#include <__tuple/pair_like.h>
3231
#include <__tuple/tuple_element.h>
32+
#include <__tuple/tuple_like_no_subrange.h>
3333
#include <__tuple/tuple_size.h>
3434
#include <__type_traits/conditional.h>
3535
#include <__type_traits/decay.h>
@@ -64,7 +64,7 @@ concept __convertible_to_non_slicing =
6464

6565
template <class _Pair, class _Iter, class _Sent>
6666
concept __pair_like_convertible_from =
67-
!range<_Pair> && __pair_like<_Pair> && constructible_from<_Pair, _Iter, _Sent> &&
67+
!range<_Pair> && __pair_like_no_subrange<_Pair> && constructible_from<_Pair, _Iter, _Sent> &&
6868
__convertible_to_non_slicing<_Iter, tuple_element_t<0, _Pair>> && convertible_to<_Sent, tuple_element_t<1, _Pair>>;
6969

7070
template <input_or_output_iterator _Iter,
@@ -125,8 +125,7 @@ class _LIBCPP_TEMPLATE_VIS subrange : public view_interface<subrange<_Iter, _Sen
125125
requires(_Kind == subrange_kind::sized)
126126
: subrange(ranges::begin(__range), ranges::end(__range), __n) {}
127127

128-
template <__different_from<subrange> _Pair>
129-
requires __pair_like_convertible_from<_Pair, const _Iter&, const _Sent&>
128+
template <__pair_like_convertible_from<const _Iter&, const _Sent&> _Pair>
130129
_LIBCPP_HIDE_FROM_ABI constexpr operator _Pair() const {
131130
return _Pair(__begin_, __end_);
132131
}

libcxx/include/__tuple/pair_like.h

Lines changed: 0 additions & 32 deletions
This file was deleted.

libcxx/include/__tuple/tuple_like.h

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@
1010
#define _LIBCPP___TUPLE_TUPLE_LIKE_H
1111

1212
#include <__config>
13-
#include <__fwd/array.h>
14-
#include <__fwd/complex.h>
15-
#include <__fwd/pair.h>
1613
#include <__fwd/subrange.h>
17-
#include <__fwd/tuple.h>
18-
#include <__type_traits/integral_constant.h>
14+
#include <__tuple/tuple_like_no_subrange.h>
15+
#include <__tuple/tuple_size.h>
1916
#include <__type_traits/remove_cvref.h>
2017

2118
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -27,29 +24,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2724
#if _LIBCPP_STD_VER >= 20
2825

2926
template <class _Tp>
30-
struct __tuple_like_impl : false_type {};
27+
inline constexpr bool __is_ranges_subrange_v = false;
3128

32-
template <class... _Tp>
33-
struct __tuple_like_impl<tuple<_Tp...> > : true_type {};
34-
35-
template <class _T1, class _T2>
36-
struct __tuple_like_impl<pair<_T1, _T2> > : true_type {};
37-
38-
template <class _Tp, size_t _Size>
39-
struct __tuple_like_impl<array<_Tp, _Size> > : true_type {};
40-
41-
template <class _Ip, class _Sp, ranges::subrange_kind _Kp>
42-
struct __tuple_like_impl<ranges::subrange<_Ip, _Sp, _Kp> > : true_type {};
43-
44-
# if _LIBCPP_STD_VER >= 26
29+
template <class _Iter, class _Sent, ranges::subrange_kind _Kind>
30+
inline constexpr bool __is_ranges_subrange_v<ranges::subrange<_Iter, _Sent, _Kind>> = true;
4531

4632
template <class _Tp>
47-
struct __tuple_like_impl<complex<_Tp>> : true_type {};
48-
49-
# endif
33+
concept __tuple_like = __tuple_like_no_subrange<_Tp> || __is_ranges_subrange_v<remove_cvref_t<_Tp>>;
5034

51-
template <class _Tp>
52-
concept __tuple_like = __tuple_like_impl<remove_cvref_t<_Tp>>::value;
35+
// As of writing this comment every use of `pair-like` in the standard excludes `ranges::subrange`, so
36+
// you most likely want to use `__pair_like_no_subrange` if you're looking for `pair-like`.
5337

5438
#endif // _LIBCPP_STD_VER >= 20
5539

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___TUPLE_TUPLE_LIKE_NO_SUBRANGE_H
10+
#define _LIBCPP___TUPLE_TUPLE_LIKE_NO_SUBRANGE_H
11+
12+
#include <__config>
13+
#include <__fwd/array.h>
14+
#include <__fwd/complex.h>
15+
#include <__fwd/pair.h>
16+
#include <__fwd/tuple.h>
17+
#include <__tuple/tuple_size.h>
18+
#include <__type_traits/remove_cvref.h>
19+
#include <cstddef>
20+
21+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
22+
# pragma GCC system_header
23+
#endif
24+
25+
_LIBCPP_BEGIN_NAMESPACE_STD
26+
27+
#if _LIBCPP_STD_VER >= 20
28+
29+
template <class _Tp>
30+
inline constexpr bool __tuple_like_no_subrange_impl = false;
31+
32+
template <class... _Tp>
33+
inline constexpr bool __tuple_like_no_subrange_impl<tuple<_Tp...>> = true;
34+
35+
template <class _T1, class _T2>
36+
inline constexpr bool __tuple_like_no_subrange_impl<pair<_T1, _T2>> = true;
37+
38+
template <class _Tp, size_t _Size>
39+
inline constexpr bool __tuple_like_no_subrange_impl<array<_Tp, _Size>> = true;
40+
41+
# if _LIBCPP_STD_VER >= 26
42+
43+
template <class _Tp>
44+
inline constexpr bool __tuple_like_no_subrange_impl<complex<_Tp>> = true;
45+
46+
# endif
47+
48+
template <class _Tp>
49+
concept __tuple_like_no_subrange = __tuple_like_no_subrange_impl<remove_cvref_t<_Tp>>;
50+
51+
// This is equivalent to the exposition-only type trait `pair-like`, except that it is false for specializations of
52+
// `ranges::subrange`. This is more useful than the pair-like concept in the standard because every use of `pair-like`
53+
// excludes `ranges::subrange`.
54+
template <class _Tp>
55+
concept __pair_like_no_subrange = __tuple_like_no_subrange<_Tp> && tuple_size<remove_cvref_t<_Tp>>::value == 2;
56+
57+
#endif // _LIBCPP_STD_VER >= 20
58+
59+
_LIBCPP_END_NAMESPACE_STD
60+
61+
#endif // _LIBCPP___TUPLE_TUPLE_LIKE_NO_SUBRANGE_H

libcxx/include/__utility/pair.h

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@
1515
#include <__config>
1616
#include <__fwd/array.h>
1717
#include <__fwd/pair.h>
18-
#include <__fwd/subrange.h>
1918
#include <__fwd/tuple.h>
20-
#include <__tuple/pair_like.h>
2119
#include <__tuple/sfinae_helpers.h>
2220
#include <__tuple/tuple_element.h>
2321
#include <__tuple/tuple_indices.h>
22+
#include <__tuple/tuple_like_no_subrange.h>
2423
#include <__tuple/tuple_size.h>
2524
#include <__type_traits/common_reference.h>
2625
#include <__type_traits/common_type.h>
@@ -60,14 +59,6 @@ struct __non_trivially_copyable_base {
6059
__non_trivially_copyable_base(__non_trivially_copyable_base const&) _NOEXCEPT {}
6160
};
6261

63-
#if _LIBCPP_STD_VER >= 23
64-
template <class _Tp>
65-
struct __is_specialization_of_subrange : false_type {};
66-
67-
template <class _Iter, class _Sent, ranges::subrange_kind _Kind>
68-
struct __is_specialization_of_subrange<ranges::subrange<_Iter, _Sent, _Kind>> : true_type {};
69-
#endif
70-
7162
template <class _T1, class _T2>
7263
struct _LIBCPP_TEMPLATE_VIS pair
7364
#if defined(_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR)
@@ -201,19 +192,19 @@ struct _LIBCPP_TEMPLATE_VIS pair
201192
# endif
202193

203194
# if _LIBCPP_STD_VER >= 23
195+
// TODO: Remove this workaround in LLVM 20. The bug got fixed in Clang 18.
204196
// This is a workaround for http://llvm.org/PR60710. We should be able to remove it once Clang is fixed.
205197
template <class _PairLike>
206198
_LIBCPP_HIDE_FROM_ABI static constexpr bool __pair_like_explicit_wknd() {
207-
if constexpr (__pair_like<_PairLike>) {
199+
if constexpr (__pair_like_no_subrange<_PairLike>) {
208200
return !is_convertible_v<decltype(std::get<0>(std::declval<_PairLike&&>())), first_type> ||
209201
!is_convertible_v<decltype(std::get<1>(std::declval<_PairLike&&>())), second_type>;
210202
}
211203
return false;
212204
}
213205

214-
template <__pair_like _PairLike>
215-
requires(!__is_specialization_of_subrange<remove_cvref_t<_PairLike>>::value &&
216-
is_constructible_v<first_type, decltype(std::get<0>(std::declval<_PairLike &&>()))> &&
206+
template <__pair_like_no_subrange _PairLike>
207+
requires(is_constructible_v<first_type, decltype(std::get<0>(std::declval<_PairLike &&>()))> &&
217208
is_constructible_v<second_type, decltype(std::get<1>(std::declval<_PairLike &&>()))>)
218209
_LIBCPP_HIDE_FROM_ABI constexpr explicit(__pair_like_explicit_wknd<_PairLike>()) pair(_PairLike&& __p)
219210
: first(std::get<0>(std::forward<_PairLike>(__p))), second(std::get<1>(std::forward<_PairLike>(__p))) {}
@@ -306,8 +297,8 @@ struct _LIBCPP_TEMPLATE_VIS pair
306297
return *this;
307298
}
308299

309-
template <__pair_like _PairLike>
310-
requires(__different_from<_PairLike, pair> && !__is_specialization_of_subrange<remove_cvref_t<_PairLike>>::value &&
300+
template <__pair_like_no_subrange _PairLike>
301+
requires(__different_from<_PairLike, pair> &&
311302
is_assignable_v<first_type&, decltype(std::get<0>(std::declval<_PairLike>()))> &&
312303
is_assignable_v<second_type&, decltype(std::get<1>(std::declval<_PairLike>()))>)
313304
_LIBCPP_HIDE_FROM_ABI constexpr pair& operator=(_PairLike&& __p) {
@@ -316,8 +307,8 @@ struct _LIBCPP_TEMPLATE_VIS pair
316307
return *this;
317308
}
318309

319-
template <__pair_like _PairLike>
320-
requires(__different_from<_PairLike, pair> && !__is_specialization_of_subrange<remove_cvref_t<_PairLike>>::value &&
310+
template <__pair_like_no_subrange _PairLike>
311+
requires(__different_from<_PairLike, pair> &&
321312
is_assignable_v<first_type const&, decltype(std::get<0>(std::declval<_PairLike>()))> &&
322313
is_assignable_v<second_type const&, decltype(std::get<1>(std::declval<_PairLike>()))>)
323314
_LIBCPP_HIDE_FROM_ABI constexpr pair const& operator=(_PairLike&& __p) const {

libcxx/include/libcxx.imp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,12 +705,12 @@
705705
{ include: [ "<__thread/timed_backoff_policy.h>", "private", "<thread>", "public" ] },
706706
{ include: [ "<__tuple/find_index.h>", "private", "<tuple>", "public" ] },
707707
{ include: [ "<__tuple/make_tuple_types.h>", "private", "<tuple>", "public" ] },
708-
{ include: [ "<__tuple/pair_like.h>", "private", "<tuple>", "public" ] },
709708
{ include: [ "<__tuple/sfinae_helpers.h>", "private", "<tuple>", "public" ] },
710709
{ include: [ "<__tuple/tuple_element.h>", "private", "<tuple>", "public" ] },
711710
{ include: [ "<__tuple/tuple_indices.h>", "private", "<tuple>", "public" ] },
712711
{ include: [ "<__tuple/tuple_like.h>", "private", "<tuple>", "public" ] },
713712
{ include: [ "<__tuple/tuple_like_ext.h>", "private", "<tuple>", "public" ] },
713+
{ include: [ "<__tuple/tuple_like_no_subrange.h>", "private", "<tuple>", "public" ] },
714714
{ include: [ "<__tuple/tuple_size.h>", "private", "<tuple>", "public" ] },
715715
{ include: [ "<__tuple/tuple_types.h>", "private", "<tuple>", "public" ] },
716716
{ include: [ "<__type_traits/add_const.h>", "private", "<type_traits>", "public" ] },

libcxx/include/module.modulemap

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,20 +1810,22 @@ module std_private_thread_thread [system] {
18101810
}
18111811
module std_private_thread_timed_backoff_policy [system] { header "__thread/timed_backoff_policy.h" }
18121812

1813-
module std_private_tuple_find_index [system] { header "__tuple/find_index.h" }
1814-
module std_private_tuple_make_tuple_types [system] { header "__tuple/make_tuple_types.h" }
1815-
module std_private_tuple_pair_like [system] {
1816-
header "__tuple/pair_like.h"
1817-
export std_private_tuple_tuple_like
1818-
}
1819-
module std_private_tuple_sfinae_helpers [system] { header "__tuple/sfinae_helpers.h" }
1820-
module std_private_tuple_tuple_element [system] { header "__tuple/tuple_element.h" }
1821-
module std_private_tuple_tuple_fwd [system] { header "__fwd/tuple.h" }
1822-
module std_private_tuple_tuple_indices [system] { header "__tuple/tuple_indices.h" }
1823-
module std_private_tuple_tuple_like [system] { header "__tuple/tuple_like.h" }
1824-
module std_private_tuple_tuple_like_ext [system] { header "__tuple/tuple_like_ext.h" }
1825-
module std_private_tuple_tuple_size [system] { header "__tuple/tuple_size.h" }
1826-
module std_private_tuple_tuple_types [system] { header "__tuple/tuple_types.h" }
1813+
module std_private_tuple_find_index [system] { header "__tuple/find_index.h" }
1814+
module std_private_tuple_make_tuple_types [system] { header "__tuple/make_tuple_types.h" }
1815+
module std_private_tuple_tuple_like_no_subrange [system] {
1816+
header "__tuple/tuple_like_no_subrange.h"
1817+
}
1818+
module std_private_tuple_sfinae_helpers [system] { header "__tuple/sfinae_helpers.h" }
1819+
module std_private_tuple_tuple_element [system] { header "__tuple/tuple_element.h" }
1820+
module std_private_tuple_tuple_fwd [system] { header "__fwd/tuple.h" }
1821+
module std_private_tuple_tuple_indices [system] { header "__tuple/tuple_indices.h" }
1822+
module std_private_tuple_tuple_like [system] {
1823+
header "__tuple/tuple_like.h"
1824+
export *
1825+
}
1826+
module std_private_tuple_tuple_like_ext [system] { header "__tuple/tuple_like_ext.h" }
1827+
module std_private_tuple_tuple_size [system] { header "__tuple/tuple_size.h" }
1828+
module std_private_tuple_tuple_types [system] { header "__tuple/tuple_types.h" }
18271829

18281830
module std_private_type_traits_add_const [system] { header "__type_traits/add_const.h" }
18291831
module std_private_type_traits_add_cv [system] { header "__type_traits/add_cv.h" }

libcxx/include/variant

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,13 @@ namespace std {
235235
#include <__type_traits/is_destructible.h>
236236
#include <__type_traits/is_nothrow_assignable.h>
237237
#include <__type_traits/is_nothrow_constructible.h>
238+
#include <__type_traits/is_reference.h>
238239
#include <__type_traits/is_trivially_assignable.h>
239240
#include <__type_traits/is_trivially_constructible.h>
240241
#include <__type_traits/is_trivially_destructible.h>
241242
#include <__type_traits/is_void.h>
242243
#include <__type_traits/remove_const.h>
244+
#include <__type_traits/remove_cvref.h>
243245
#include <__type_traits/type_identity.h>
244246
#include <__type_traits/void_t.h>
245247
#include <__utility/declval.h>

libcxx/test/libcxx/utilities/tuple/__tuple_like.compile.pass.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// template<class T>
1616
// concept tuple-like; // exposition only
1717

18+
#include <__tuple/tuple_like.h>
1819
#include <array>
1920
#include <complex>
2021
#include <ranges>

libcxx/test/std/ranges/range.adaptors/range.elements/range.concept.compile.pass.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ static_assert(!std::ranges::input_range<Range<cpp20_output_iterator<std::tuple<i
5252
static_assert(!HasElementsView<Range<cpp20_output_iterator<std::tuple<int>*>>, 0>);
5353

5454
// !tuple-like
55-
LIBCPP_STATIC_ASSERT(!std::__tuple_like<int>);
5655
static_assert(!HasElementsView<Range<int*>, 1>);
5756

5857
// !(N < tuple_size_v<T>)

0 commit comments

Comments
 (0)