Skip to content

Commit 53a4e4a

Browse files
authored
[libc++] Specialize __lazy_synth_three_way_comparator for std::greater and friends (#157624)
This specializes `__lazy_synth_three_way_comparator` to forward to `__default_three_way_comparator` if the comparator desugars to `__greater_tag`. This is the same as the desugaring to `__less_tag` except that the sign has to be inverted.
1 parent 92dcbf4 commit 53a4e4a

File tree

5 files changed

+81
-6
lines changed

5 files changed

+81
-6
lines changed

libcxx/include/__utility/lazy_synth_three_way_comparator.h

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,11 @@ struct __eager_compare_result {
7070
};
7171

7272
template <class _Comparator, class _LHS, class _RHS>
73-
struct __lazy_synth_three_way_comparator<
74-
_Comparator,
75-
_LHS,
76-
_RHS,
77-
__enable_if_t<_And<__desugars_to<__less_tag, _Comparator, _LHS, _RHS>,
78-
__has_default_three_way_comparator<_LHS, _RHS> >::value> > {
73+
struct __lazy_synth_three_way_comparator<_Comparator,
74+
_LHS,
75+
_RHS,
76+
__enable_if_t<_And<__desugars_to<__less_tag, _Comparator, _LHS, _RHS>,
77+
__has_default_three_way_comparator<_LHS, _RHS> >::value> > {
7978
// This lifetimebound annotation is technically incorrect, but other specializations actually capture the lifetime of
8079
// the comparator.
8180
_LIBCPP_HIDE_FROM_ABI __lazy_synth_three_way_comparator(_LIBCPP_CTOR_LIFETIMEBOUND const _Comparator&) {}
@@ -87,6 +86,23 @@ struct __lazy_synth_three_way_comparator<
8786
}
8887
};
8988

89+
template <class _Comparator, class _LHS, class _RHS>
90+
struct __lazy_synth_three_way_comparator<_Comparator,
91+
_LHS,
92+
_RHS,
93+
__enable_if_t<_And<__desugars_to<__greater_tag, _Comparator, _LHS, _RHS>,
94+
__has_default_three_way_comparator<_LHS, _RHS> >::value> > {
95+
// This lifetimebound annotation is technically incorrect, but other specializations actually capture the lifetime of
96+
// the comparator.
97+
_LIBCPP_HIDE_FROM_ABI __lazy_synth_three_way_comparator(_LIBCPP_CTOR_LIFETIMEBOUND const _Comparator&) {}
98+
99+
// Same comment as above.
100+
_LIBCPP_HIDE_FROM_ABI static __eager_compare_result
101+
operator()(_LIBCPP_LIFETIMEBOUND const _LHS& __lhs, _LIBCPP_LIFETIMEBOUND const _RHS& __rhs) {
102+
return __eager_compare_result(-__default_three_way_comparator<_LHS, _RHS>()(__lhs, __rhs));
103+
}
104+
};
105+
90106
_LIBCPP_END_NAMESPACE_STD
91107

92108
#endif // _LIBCPP___UTILITY_LAZY_SYNTH_THREE_WAY_COMPARATOR_H

libcxx/test/std/containers/associative/map/map.ops/find.pass.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ int main(int, char**) {
7272
assert(r == std::next(m.begin(), 8));
7373
}
7474
}
75+
{ // Check with std::greater to ensure we're actually using the correct comparator
76+
using Pair = std::pair<const int, int>;
77+
using Map = std::map<int, int, std::greater<int> >;
78+
Pair ar[] = {Pair(5, 5), Pair(6, 6), Pair(7, 7), Pair(8, 8), Pair(9, 9), Pair(10, 10), Pair(11, 11), Pair(12, 12)};
79+
Map m(ar, ar + sizeof(ar) / sizeof(ar[0]));
80+
assert(m.find(12) == std::next(m.begin(), 0));
81+
assert(m.find(11) == std::next(m.begin(), 1));
82+
assert(m.find(10) == std::next(m.begin(), 2));
83+
assert(m.find(9) == std::next(m.begin(), 3));
84+
assert(m.find(8) == std::next(m.begin(), 4));
85+
assert(m.find(7) == std::next(m.begin(), 5));
86+
assert(m.find(6) == std::next(m.begin(), 6));
87+
assert(m.find(5) == std::next(m.begin(), 7));
88+
assert(m.find(4) == std::next(m.begin(), 8));
89+
assert(std::next(m.begin(), 8) == m.end());
90+
}
7591
#if TEST_STD_VER >= 11
7692
{
7793
typedef std::pair<const int, double> V;

libcxx/test/std/containers/associative/multimap/multimap.ops/find.pass.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,19 @@ int main(int, char**) {
6969
assert(r == m.end());
7070
}
7171
}
72+
{
73+
using Pair = std::pair<const int, int>;
74+
using Map = std::multimap<int, int, std::greater<int> >;
75+
Pair arr[] = {
76+
Pair(5, 1), Pair(5, 2), Pair(5, 3), Pair(7, 1), Pair(7, 2), Pair(7, 3), Pair(9, 1), Pair(9, 2), Pair(9, 3)};
77+
const Map m(arr, arr + sizeof(arr) / sizeof(arr[0]));
78+
assert(iter_in_range(std::next(m.begin(), 6), std::next(m.begin(), 9), m.find(5)));
79+
assert(m.find(6) == m.end());
80+
assert(iter_in_range(std::next(m.begin(), 3), std::next(m.begin(), 6), m.find(7)));
81+
assert(m.find(8) == m.end());
82+
assert(iter_in_range(std::next(m.begin(), 0), std::next(m.begin(), 3), m.find(9)));
83+
assert(m.find(10) == m.end());
84+
}
7285
#if TEST_STD_VER >= 11
7386
{
7487
typedef std::multimap<int, double, std::less<int>, min_allocator<std::pair<const int, double>>> M;

libcxx/test/std/containers/associative/multiset/find.pass.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,21 @@ int main(int, char**) {
7171
assert(r == std::next(m.begin(), 8));
7272
}
7373
}
74+
{ // Check with std::greater to ensure we're actually using the correct comparator
75+
using Set = std::multiset<int, std::greater<int> >;
76+
int ar[] = {5, 6, 7, 8, 9, 10, 11, 12};
77+
Set m(ar, ar + sizeof(ar) / sizeof(ar[0]));
78+
assert(m.find(12) == std::next(m.begin(), 0));
79+
assert(m.find(11) == std::next(m.begin(), 1));
80+
assert(m.find(10) == std::next(m.begin(), 2));
81+
assert(m.find(9) == std::next(m.begin(), 3));
82+
assert(m.find(8) == std::next(m.begin(), 4));
83+
assert(m.find(7) == std::next(m.begin(), 5));
84+
assert(m.find(6) == std::next(m.begin(), 6));
85+
assert(m.find(5) == std::next(m.begin(), 7));
86+
assert(m.find(4) == std::next(m.begin(), 8));
87+
assert(std::next(m.begin(), 8) == m.end());
88+
}
7489
#if TEST_STD_VER >= 11
7590
{
7691
typedef int V;

libcxx/test/std/containers/associative/set/find.pass.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,21 @@ int main(int, char**) {
7171
assert(r == std::next(m.begin(), 8));
7272
}
7373
}
74+
{ // Check with std::greater to ensure we're actually using the correct comparator
75+
using Set = std::set<int, std::greater<int> >;
76+
int ar[] = {5, 6, 7, 8, 9, 10, 11, 12};
77+
Set m(ar, ar + sizeof(ar) / sizeof(ar[0]));
78+
assert(m.find(12) == std::next(m.begin(), 0));
79+
assert(m.find(11) == std::next(m.begin(), 1));
80+
assert(m.find(10) == std::next(m.begin(), 2));
81+
assert(m.find(9) == std::next(m.begin(), 3));
82+
assert(m.find(8) == std::next(m.begin(), 4));
83+
assert(m.find(7) == std::next(m.begin(), 5));
84+
assert(m.find(6) == std::next(m.begin(), 6));
85+
assert(m.find(5) == std::next(m.begin(), 7));
86+
assert(m.find(4) == std::next(m.begin(), 8));
87+
assert(std::next(m.begin(), 8) == m.end());
88+
}
7489
#if TEST_STD_VER >= 11
7590
{
7691
typedef int V;

0 commit comments

Comments
 (0)