Skip to content

Commit

Permalink
Refactoring around tuple-like, pair-like, and subrange
Browse files Browse the repository at this point in the history
Effectively mirrors LLVM-85206.

In the current standard wording, the "_`pair-like`_ but not `subrange`"
pattern is used more often than plain _`pair-like`_. So it's probably
worthwhile to carve out the `_Pair_like_non_subrange` concept.
`_Tuple_like_non_subrange` seems less worthwhile, but it should be
helpful in the constructors of  `tuple`.

Moreover, with `_Pair_like_non_subrange` carved out, we can put the
definitions of `_Pair_like` in C++20 & 23 modes together in
`<xutility>`.

`_Pair_like_non_subrange` should be also helpful for extracting the key
object from pair-like construction argument via
`_In_place_key_extract_map` (since C++23). I think this can be done in
a future PR.

Other changes: Renaming the template parameter of `subrange`'s
conversion function to `_PairLike`, making the identifier `_Pair_like
 in MSVC STL always mean the concept.
  • Loading branch information
frederick-vs-ja committed Sep 26, 2024
1 parent 1e312b3 commit 15e946c
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 54 deletions.
5 changes: 0 additions & 5 deletions stl/inc/__msvc_iter_core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,11 +438,6 @@ _EXPORT_STD using ranges::get;
template <class _It, class _Se, ranges::subrange_kind _Ki>
constexpr bool _Is_subrange_v<ranges::subrange<_It, _Se, _Ki>> = true;

#if _HAS_CXX23
template <class _It, class _Se, ranges::subrange_kind _Ki>
constexpr bool _Tuple_like_impl<ranges::subrange<_It, _Se, _Ki>> = true;
#endif // _HAS_CXX23

template <class _It, class _Se, ranges::subrange_kind _Ki>
struct tuple_size<ranges::subrange<_It, _Se, _Ki>> : integral_constant<size_t, 2> {};

Expand Down
25 changes: 10 additions & 15 deletions stl/inc/tuple
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,12 @@ constexpr bool _Can_construct_values_from_tuple_like_v<tuple<_Types...>, _Other,

#ifdef __EDG__ // TRANSITION, VSO-1900279
template <class _TupleLike, class _Tuple>
concept _Can_construct_from_tuple_like =
_Different_from<_TupleLike, _Tuple> && _Tuple_like<_TupleLike> && !_Is_subrange_v<remove_cvref_t<_TupleLike>>
&& (tuple_size_v<_Tuple> == tuple_size_v<remove_cvref_t<_TupleLike>>) //
&&_Can_construct_values_from_tuple_like_v<_Tuple, _TupleLike>
&& (tuple_size_v<_Tuple> != 1
|| (!is_convertible_v<_TupleLike, tuple_element_t<0, _Tuple>>
&& !is_constructible_v<tuple_element_t<0, _Tuple>, _TupleLike>) );
concept _Can_construct_from_tuple_like = _Different_from<_TupleLike, _Tuple> && _Tuple_like_non_subrange<_TupleLike>
&& (tuple_size_v<_Tuple> == tuple_size_v<remove_cvref_t<_TupleLike>>)
&& _Can_construct_values_from_tuple_like_v<_Tuple, _TupleLike>
&& (tuple_size_v<_Tuple> != 1
|| (!is_convertible_v<_TupleLike, tuple_element_t<0, _Tuple>>
&& !is_constructible_v<tuple_element_t<0, _Tuple>, _TupleLike>) );
#endif // ^^^ workaround ^^^

template <class _TTuple, class _UTuple, class _Indices = make_index_sequence<tuple_size_v<_UTuple>>>
Expand Down Expand Up @@ -421,8 +420,7 @@ public:
template <class _Other, enable_if_t<_Can_construct_from_tuple_like<_Other, tuple>, int> = 0>
#else // ^^^ workaround / no workaround vvv
template <_Different_from<tuple> _Other>
requires _Tuple_like<_Other> && (!_Is_subrange_v<remove_cvref_t<_Other>>)
&& (1 + sizeof...(_Rest) == tuple_size_v<remove_cvref_t<_Other>>)
requires _Tuple_like_non_subrange<_Other> && (1 + sizeof...(_Rest) == tuple_size_v<remove_cvref_t<_Other>>)
&& _Can_construct_values_from_tuple_like_v<tuple, _Other>
&& (sizeof...(_Rest) != 0 || (!is_convertible_v<_Other, _This> && !is_constructible_v<_This, _Other>) )
#endif // ^^^ no workaround ^^^
Expand Down Expand Up @@ -527,8 +525,7 @@ public:
template <class _Alloc, class _Other, enable_if_t<_Can_construct_from_tuple_like<_Other, tuple>, int> = 0>
#else // ^^^ workaround / no workaround vvv
template <class _Alloc, _Different_from<tuple> _Other>
requires _Tuple_like<_Other> && (!_Is_subrange_v<remove_cvref_t<_Other>>)
&& (1 + sizeof...(_Rest) == tuple_size_v<remove_cvref_t<_Other>>)
requires _Tuple_like_non_subrange<_Other> && (1 + sizeof...(_Rest) == tuple_size_v<remove_cvref_t<_Other>>)
&& _Can_construct_values_from_tuple_like_v<tuple, _Other>
&& (sizeof...(_Rest) != 0 || (!is_convertible_v<_Other, _This> && !is_constructible_v<_This, _Other>) )
#endif // ^^^ no workaround ^^^
Expand Down Expand Up @@ -692,17 +689,15 @@ public:
}

template <_Different_from<tuple> _Other>
requires _Tuple_like<_Other> && (!_Is_subrange_v<remove_cvref_t<_Other>>)
&& (1 + sizeof...(_Rest) == tuple_size_v<remove_cvref_t<_Other>>)
requires _Tuple_like_non_subrange<_Other> && (1 + sizeof...(_Rest) == tuple_size_v<remove_cvref_t<_Other>>)
&& _Can_assign_values_from_tuple_like_v<false, _Other>
constexpr tuple& operator=(_Other&& _Right) {
_Assign_tuple_like(_STD forward<_Other>(_Right), make_index_sequence<1 + sizeof...(_Rest)>{});
return *this;
}

template <_Different_from<tuple> _Other>
requires _Tuple_like<_Other> && (!_Is_subrange_v<remove_cvref_t<_Other>>)
&& (1 + sizeof...(_Rest) == tuple_size_v<remove_cvref_t<_Other>>)
requires _Tuple_like_non_subrange<_Other> && (1 + sizeof...(_Rest) == tuple_size_v<remove_cvref_t<_Other>>)
&& _Can_assign_values_from_tuple_like_v<true, _Other>
constexpr const tuple& operator=(_Other&& _Right) const {
_Assign_tuple_like(_STD forward<_Other>(_Right), make_index_sequence<1 + sizeof...(_Rest)>{});
Expand Down
35 changes: 18 additions & 17 deletions stl/inc/utility
Original file line number Diff line number Diff line change
Expand Up @@ -205,28 +205,31 @@ constexpr bool _Is_subrange_v = false;

#if _HAS_CXX23
template <class>
constexpr bool _Tuple_like_impl = false;
constexpr bool _Tuple_like_non_subrange_impl = false;

template <class... _Types>
constexpr bool _Tuple_like_impl<tuple<_Types...>> = true;
constexpr bool _Tuple_like_non_subrange_impl<tuple<_Types...>> = true;

template <class _Ty1, class _Ty2>
constexpr bool _Tuple_like_impl<pair<_Ty1, _Ty2>> = true;
constexpr bool _Tuple_like_non_subrange_impl<pair<_Ty1, _Ty2>> = true;

template <class _Ty, size_t _Size>
constexpr bool _Tuple_like_impl<array<_Ty, _Size>> = true;
constexpr bool _Tuple_like_non_subrange_impl<array<_Ty, _Size>> = true;

template <class _Ty>
concept _Tuple_like = _Tuple_like_impl<remove_cvref_t<_Ty>>;
concept _Tuple_like_non_subrange = _Tuple_like_non_subrange_impl<remove_cvref_t<_Ty>>;

template <class _Ty>
concept _Pair_like = _Tuple_like<_Ty> && tuple_size_v<remove_cvref_t<_Ty>> == 2;
concept _Tuple_like = _Tuple_like_non_subrange<_Ty> || _Is_subrange_v<remove_cvref_t<_Ty>>;

template <class _Ty>
concept _Pair_like_non_subrange = _Tuple_like_non_subrange<_Ty> && tuple_size_v<remove_cvref_t<_Ty>> == 2;

#ifdef __EDG__ // TRANSITION, VSO-1900279
template <class _PairLike, class _Ty1, class _Ty2>
concept _Can_construct_from_pair_like = _Pair_like<_PairLike> && !_Is_subrange_v<remove_cvref_t<_PairLike>>
&& is_constructible_v<_Ty1, decltype(_STD get<0>(_STD declval<_PairLike>()))>
&& is_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_PairLike>()))>;
concept _Can_construct_from_pair_like =
_Pair_like_non_subrange<_PairLike> && is_constructible_v<_Ty1, decltype(_STD get<0>(_STD declval<_PairLike>()))>
&& is_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_PairLike>()))>;
#endif // ^^^ workaround ^^^
#endif // _HAS_CXX23
#endif // _HAS_CXX20
Expand Down Expand Up @@ -302,9 +305,8 @@ struct pair { // store a pair of values
#ifdef __EDG__ // TRANSITION, VSO-1900279
template <class _Other, enable_if_t<_Can_construct_from_pair_like<_Other, _Ty1, _Ty2>, int> = 0>
#else // ^^^ workaround / no workaround vvv
template <_Pair_like _Other>
requires conjunction_v<bool_constant<!_Is_subrange_v<remove_cvref_t<_Other>>>,
is_constructible<_Ty1, decltype(_STD get<0>(_STD declval<_Other>()))>,
template <_Pair_like_non_subrange _Other>
requires conjunction_v<is_constructible<_Ty1, decltype(_STD get<0>(_STD declval<_Other>()))>,
is_constructible<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>>
#endif // ^^^ no workaround ^^^
constexpr explicit(!conjunction_v<is_convertible<decltype(_STD get<0>(_STD declval<_Other>())), _Ty1>,
Expand Down Expand Up @@ -422,9 +424,8 @@ struct pair { // store a pair of values
return *this;
}

template <_Pair_like _Other>
requires _Different_from<_Other, pair> && (!_Is_subrange_v<remove_cvref_t<_Other>>)
&& is_assignable_v<_Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))>
template <_Pair_like_non_subrange _Other>
requires _Different_from<_Other, pair> && is_assignable_v<_Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))>
&& is_assignable_v<_Ty2&, decltype(_STD get<1>(_STD declval<_Other>()))>
constexpr pair& operator=(_Other&& _Right)
noexcept(is_nothrow_assignable_v<_Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))>
Expand All @@ -434,8 +435,8 @@ struct pair { // store a pair of values
return *this;
}

template <_Pair_like _Other>
requires _Different_from<_Other, pair> && (!_Is_subrange_v<remove_cvref_t<_Other>>)
template <_Pair_like_non_subrange _Other>
requires _Different_from<_Other, pair>
&& is_assignable_v<const _Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))>
&& is_assignable_v<const _Ty2&, decltype(_STD get<1>(_STD declval<_Other>()))>
constexpr const pair& operator=(_Other&& _Right) const noexcept(
Expand Down
2 changes: 1 addition & 1 deletion stl/inc/xmemory
Original file line number Diff line number Diff line change
Expand Up @@ -2435,7 +2435,7 @@ _NODISCARD constexpr auto uses_allocator_construction_args(
_EXPORT_STD template <_Cv_std_pair _Ty, class _Alloc, _Usable_for_pair_like_overload _Uty>
_NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty&& _Ux) noexcept {
#if _HAS_CXX23
if constexpr (_Pair_like<_Uty> && !_Is_subrange_v<remove_cvref_t<_Uty>>) {
if constexpr (_Pair_like_non_subrange<_Uty>) {
// equivalent to
// return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct,
// _STD forward_as_tuple(_STD get<0>(_STD forward<_Uty>(_Ux)),
Expand Down
35 changes: 19 additions & 16 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -3874,6 +3874,21 @@ namespace ranges {
};
} // namespace ranges

#if _HAS_CXX23
template <class _Ty>
concept _Pair_like = _Tuple_like<_Ty> && tuple_size_v<remove_cvref_t<_Ty>> == 2;
#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv
template <class _Ty>
concept _Pair_like = !is_reference_v<_Ty> && requires(_Ty __t) {
typename tuple_size<_Ty>::type;
requires derived_from<tuple_size<_Ty>, integral_constant<size_t, 2>>;
typename tuple_element_t<0, remove_const_t<_Ty>>;
typename tuple_element_t<1, remove_const_t<_Ty>>;
{ _STD get<0>(__t) } -> convertible_to<const tuple_element_t<0, _Ty>&>;
{ _STD get<1>(__t) } -> convertible_to<const tuple_element_t<1, _Ty>&>;
};
#endif // ^^^ !_HAS_CXX23 ^^^

namespace ranges {
template <class _From, class _To>
concept _Uses_nonqualification_pointer_conversion =
Expand All @@ -3884,18 +3899,6 @@ namespace ranges {
concept _Convertible_to_non_slicing =
convertible_to<_From, _To> && !_Uses_nonqualification_pointer_conversion<decay_t<_From>, decay_t<_To>>;

#if !_HAS_CXX23
template <class _Ty>
concept _Pair_like = !is_reference_v<_Ty> && requires(_Ty __t) {
typename tuple_size<_Ty>::type;
requires derived_from<tuple_size<_Ty>, integral_constant<size_t, 2>>;
typename tuple_element_t<0, remove_const_t<_Ty>>;
typename tuple_element_t<1, remove_const_t<_Ty>>;
{ _STD get<0>(__t) } -> convertible_to<const tuple_element_t<0, _Ty>&>;
{ _STD get<1>(__t) } -> convertible_to<const tuple_element_t<1, _Ty>&>;
};
#endif // !_HAS_CXX23

template <class _Ty, class _First, class _Second>
concept _Pair_like_convertible_from = !range<_Ty>
#if _HAS_CXX23
Expand Down Expand Up @@ -3989,10 +3992,10 @@ namespace ranges {
requires (_Ki == subrange_kind::sized)
: subrange{_RANGES begin(_Val), _RANGES end(_Val), _Count} {}

template <_Different_from<subrange> _Pair_like>
requires _Pair_like_convertible_from<_Pair_like, const _It&, const _Se&>
constexpr operator _Pair_like() const {
return _Pair_like(_First, _Last);
template <_Different_from<subrange> _PairLike>
requires _Pair_like_convertible_from<_PairLike, const _It&, const _Se&>
constexpr operator _PairLike() const {
return _PairLike(_First, _Last);
}

_NODISCARD constexpr _It begin() const
Expand Down

0 comments on commit 15e946c

Please sign in to comment.