-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[libc++] Implement comparison operators for tuple
added in C++23
#148799
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
frederick-vs-ja
wants to merge
11
commits into
llvm:main
Choose a base branch
from
frederick-vs-ja:p2165r4-comparison
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+846
−425
Open
Changes from 8 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
807cd14
[libc++] Implement comparison operators for `tuple` added in C++23
frederick-vs-ja 2443610
[libc++] Set feature-test macro `__cpp_lib_constrained_equality`
frederick-vs-ja d0b9808
Potential workarounds for pre-CWG2369 Clang and module builds
frederick-vs-ja e87bfe4
Merge branch 'main' into p2165r4-comparison
frederick-vs-ja 6ec6029
Tweak implementation of `operator==`
frederick-vs-ja 1dec129
Rename `_Indices` to simpler `_Is`
frederick-vs-ja 8b7c412
Add missed synopsis comments
frederick-vs-ja 754c0c2
Unconditionally include headers in `tuple.rel/three_way.pass.cpp`
frederick-vs-ja 23a8091
Apply @ldionne's suggestions
frederick-vs-ja 2700fe8
Merge branch 'main' into p2165r4-comparison
frederick-vs-ja 2281cfc
Merge branch 'main' into p2165r4-comparison
frederick-vs-ja File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -106,6 +106,11 @@ public: | |
|
||
void swap(tuple&) noexcept(AND(swap(declval<T&>(), declval<T&>())...)); // constexpr in C++20 | ||
constexpr void swap(const tuple&) const noexcept(see-below); // C++23 | ||
|
||
template<tuple-like UTuple> | ||
friend constexpr bool operator==(const tuple& t, const UTuple& u); // C++23 | ||
template<tuple-like UTuple> | ||
friend constexpr auto operator<=>(const tuple& t, const UTuple& u); // C++23 | ||
}; | ||
|
||
|
||
|
@@ -220,7 +225,9 @@ template <class... Types> | |
# include <__config> | ||
# include <__cstddef/size_t.h> | ||
# include <__fwd/array.h> | ||
# include <__fwd/complex.h> | ||
# include <__fwd/pair.h> | ||
# include <__fwd/subrange.h> | ||
frederick-vs-ja marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# include <__fwd/tuple.h> | ||
# include <__memory/allocator_arg_t.h> | ||
# include <__memory/uses_allocator.h> | ||
|
@@ -230,6 +237,7 @@ template <class... Types> | |
# include <__tuple/sfinae_helpers.h> | ||
# include <__tuple/tuple_element.h> | ||
# include <__tuple/tuple_indices.h> | ||
# include <__tuple/tuple_like.h> | ||
# include <__tuple/tuple_like_ext.h> | ||
# include <__tuple/tuple_size.h> | ||
# include <__tuple/tuple_types.h> | ||
|
@@ -288,6 +296,66 @@ _LIBCPP_BEGIN_NAMESPACE_STD | |
|
||
# ifndef _LIBCPP_CXX03_LANG | ||
|
||
template <size_t _Ip, class _Tp, class _Up> | ||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool __tuple_compare_equal(const _Tp& __x, const _Up& __y) { | ||
if constexpr (_Ip == 0) | ||
return true; | ||
else | ||
return std::__tuple_compare_equal<_Ip - 1>(__x, __y) && std::get<_Ip - 1>(__x) == std::get<_Ip - 1>(__y); | ||
} | ||
|
||
# if _LIBCPP_STD_VER >= 26 | ||
template <class _Tp, class _Up, class _IndexSeq> | ||
inline constexpr bool __can_tuple_compare_equal_impl = false; | ||
frederick-vs-ja marked this conversation as resolved.
Show resolved
Hide resolved
|
||
template <class _Tp, class _Up, size_t... _Is> | ||
requires(tuple_size_v<_Tp> == tuple_size_v<_Up>) | ||
inline constexpr bool __can_tuple_compare_equal_impl<_Tp, _Up, index_sequence<_Is...>> = | ||
__all<requires(const tuple_element_t<_Is, _Tp>& __t, const tuple_element_t<_Is, _Up>& __u) { | ||
{ __t == __u } -> __boolean_testable; | ||
}...>::value; | ||
|
||
template <class _Tp, class _Up> | ||
inline constexpr bool __can_tuple_compare_equal = | ||
__can_tuple_compare_equal_impl<_Tp, _Up, make_index_sequence<tuple_size_v<_Tp>>>; | ||
# endif // _LIBCPP_STD_VER >= 26 | ||
|
||
# if _LIBCPP_STD_VER >= 20 | ||
template <class _Ret, class _Tp, class _Up, size_t... _Is> | ||
_LIBCPP_HIDE_FROM_ABI constexpr _Ret __tuple_compare_three_way(const _Tp& __x, const _Up& __y, index_sequence<_Is...>) { | ||
_Ret __result = strong_ordering::equal; | ||
static_cast<void>( | ||
((__result = std::__synth_three_way(std::get<_Is>(__x), std::get<_Is>(__y)), __result != 0) || ...)); | ||
return __result; | ||
} | ||
# endif // _LIBCPP_STD_VER >= 20 | ||
|
||
# if _LIBCPP_STD_VER >= 23 | ||
template <class> | ||
inline constexpr bool __is_tuple_v = false; | ||
|
||
template <class... _Tp> | ||
inline constexpr bool __is_tuple_v<tuple<_Tp...>> = true; | ||
|
||
template <class _Tp> | ||
concept __tuple_like_no_tuple = __tuple_like<_Tp> && !__is_tuple_v<_Tp>; | ||
|
||
template <class _Tp, class _Up, class _IndexSeq> | ||
struct __tuple_common_comparison_category_impl {}; | ||
template <class _Tp, class _Up, size_t... _Is> | ||
requires(tuple_size_v<_Tp> == tuple_size_v<_Up>) && requires { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
typename common_comparison_category_t< | ||
__synth_three_way_result<tuple_element_t<_Is, _Tp>, tuple_element_t<_Is, _Up>>...>; | ||
} | ||
struct __tuple_common_comparison_category_impl<_Tp, _Up, index_sequence<_Is...>> { | ||
using type _LIBCPP_NODEBUG = | ||
common_comparison_category_t<__synth_three_way_result<tuple_element_t<_Is, _Tp>, tuple_element_t<_Is, _Up>>...>; | ||
}; | ||
|
||
template <__tuple_like _Tp, __tuple_like _Up> | ||
using __tuple_common_comparison_category _LIBCPP_NODEBUG = | ||
__tuple_common_comparison_category_impl<_Tp, _Up, make_index_sequence<tuple_size_v<_Tp>>>::type; | ||
# endif // _LIBCPP_STD_VER >= 23 | ||
|
||
// __tuple_leaf | ||
|
||
template <size_t _Ip, class _Hp, bool = is_empty<_Hp>::value && !__libcpp_is_final<_Hp>::value > | ||
|
@@ -997,7 +1065,24 @@ public: | |
noexcept(__all<is_nothrow_swappable_v<const _Tp&>...>::value) { | ||
__base_.swap(__t.__base_); | ||
} | ||
# endif // _LIBCPP_STD_VER >= 23 | ||
|
||
template <__tuple_like_no_tuple _UTuple> | ||
# if _LIBCPP_STD_VER >= 26 | ||
requires __can_tuple_compare_equal<tuple, _UTuple> && (sizeof...(_Tp) == tuple_size_v<_UTuple>) | ||
# endif // _LIBCPP_STD_VER >= 26 | ||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const tuple& __x, const _UTuple& __y) { | ||
static_assert(sizeof...(_Tp) == tuple_size_v<_UTuple>, "Can't compare tuple-like values of different sizes"); | ||
return std::__tuple_compare_equal<sizeof...(_Tp)>(__x, __y); | ||
} | ||
|
||
template <__tuple_like_no_tuple _UTuple> | ||
requires(sizeof...(_Tp) == tuple_size_v<_UTuple>) | ||
_LIBCPP_HIDE_FROM_ABI friend constexpr __tuple_common_comparison_category<tuple, _UTuple> | ||
operator<=>(const tuple& __x, const _UTuple& __y) { | ||
return std::__tuple_compare_three_way<__tuple_common_comparison_category<tuple, _UTuple>>( | ||
__x, __y, index_sequence_for<_Tp...>{}); | ||
} | ||
# endif // _LIBCPP_STD_VER >= 23 | ||
}; | ||
|
||
_LIBCPP_DIAGNOSTIC_PUSH | ||
|
@@ -1019,6 +1104,21 @@ public: | |
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(tuple&) _NOEXCEPT {} | ||
# if _LIBCPP_STD_VER >= 23 | ||
_LIBCPP_HIDE_FROM_ABI constexpr void swap(const tuple&) const noexcept {} | ||
|
||
template <__tuple_like_no_tuple _UTuple> | ||
# if _LIBCPP_STD_VER >= 26 | ||
requires(tuple_size_v<_UTuple> == 0) | ||
# endif // _LIBCPP_STD_VER >= 26 | ||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const tuple&, const _UTuple&) { | ||
static_assert(tuple_size_v<_UTuple> == 0, "Can't compare tuple-like values of different sizes"); | ||
return true; | ||
} | ||
|
||
template <__tuple_like_no_tuple _UTuple> | ||
requires(tuple_size_v<_UTuple> == 0) | ||
_LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering operator<=>(const tuple&, const _UTuple&) { | ||
return strong_ordering::equal; | ||
} | ||
# endif | ||
}; | ||
_LIBCPP_DIAGNOSTIC_POP | ||
|
@@ -1137,22 +1237,6 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<_Tp&&...> forwa | |
return tuple<_Tp&&...>(std::forward<_Tp>(__t)...); | ||
} | ||
|
||
template <size_t _Ip> | ||
struct __tuple_equal { | ||
template <class _Tp, class _Up> | ||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator()(const _Tp& __x, const _Up& __y) { | ||
return __tuple_equal<_Ip - 1>()(__x, __y) && std::get<_Ip - 1>(__x) == std::get<_Ip - 1>(__y); | ||
} | ||
}; | ||
|
||
template <> | ||
struct __tuple_equal<0> { | ||
template <class _Tp, class _Up> | ||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator()(const _Tp&, const _Up&) { | ||
return true; | ||
} | ||
}; | ||
|
||
template <class... _Tp, class... _Up> | ||
# if _LIBCPP_STD_VER >= 26 | ||
requires(__all<requires(const _Tp& __t, const _Up& __u) { | ||
|
@@ -1162,27 +1246,19 @@ template <class... _Tp, class... _Up> | |
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool | ||
operator==(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) { | ||
static_assert(sizeof...(_Tp) == sizeof...(_Up), "Can't compare tuples of different sizes"); | ||
return __tuple_equal<sizeof...(_Tp)>()(__x, __y); | ||
return std::__tuple_compare_equal<sizeof...(_Tp)>(__x, __y); | ||
} | ||
|
||
# if _LIBCPP_STD_VER >= 20 | ||
|
||
// operator<=> | ||
|
||
template <class... _Tp, class... _Up, size_t... _Is> | ||
_LIBCPP_HIDE_FROM_ABI constexpr auto | ||
__tuple_compare_three_way(const tuple<_Tp...>& __x, const tuple<_Up...>& __y, index_sequence<_Is...>) { | ||
common_comparison_category_t<__synth_three_way_result<_Tp, _Up>...> __result = strong_ordering::equal; | ||
static_cast<void>( | ||
((__result = std::__synth_three_way(std::get<_Is>(__x), std::get<_Is>(__y)), __result != 0) || ...)); | ||
return __result; | ||
} | ||
|
||
template <class... _Tp, class... _Up> | ||
requires(sizeof...(_Tp) == sizeof...(_Up)) | ||
_LIBCPP_HIDE_FROM_ABI constexpr common_comparison_category_t<__synth_three_way_result<_Tp, _Up>...> | ||
operator<=>(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) { | ||
return std::__tuple_compare_three_way(__x, __y, index_sequence_for<_Tp...>{}); | ||
return std::__tuple_compare_three_way<common_comparison_category_t<__synth_three_way_result<_Tp, _Up>...>>( | ||
__x, __y, index_sequence_for<_Tp...>{}); | ||
} | ||
|
||
# else // _LIBCPP_STD_VER >= 20 | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In principle, this would need to be an update to the
BEGIN-RST-NOTES
tag on #105200. But I agree this is not ergonomic since you really want the change to be associated to this PR and blameable somehow. Perhaps this means that we should make the status pages be the canonical representation of our conformance state, or perhaps it means that the version of the notes in the status pages should be the canonical ones? As I said in #148874, I'd love to find a workflow that works and is relatively simple.