Skip to content

Commit fcad677

Browse files
Centimoevgeniy.efimov
authored andcommitted
Simplify Tuple::operator<=> and add comprehensive tests
Rewrite three-way comparison to use common_comparison_category_t for correct return type and a cleaner fold expression with early exit. Add tests for single/multi-element tuples, lexicographic order, and mixed types.
1 parent 179392d commit fcad677

2 files changed

Lines changed: 107 additions & 17 deletions

File tree

include/rfl/Tuple.hpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,17 +102,19 @@ class Tuple {
102102
static_assert(sizeof...(Types) == sizeof...(OtherTypes),
103103
"The size of the two tuples must be the same.");
104104

105-
const auto compare = [&]<int _i>(std::strong_ordering* _ordering,
106-
std::integral_constant<int, _i>) {
107-
if (*_ordering == std::strong_ordering::equivalent &&
108-
this->get<_i>() != _other.template get<_i>()) {
109-
*_ordering = (this->get<_i>() <=> _other.template get<_i>());
110-
}
105+
using OrderingType = std::common_comparison_category_t<
106+
decltype(std::declval<Types>() <=> std::declval<OtherTypes>())...>;
107+
108+
auto ordering = OrderingType::equivalent;
109+
110+
const auto compare = [&]<int _i>(std::integral_constant<int, _i>) {
111+
ordering = static_cast<OrderingType>(
112+
this->get<_i>() <=> _other.template get<_i>());
113+
return ordering != 0;
111114
};
112115

113116
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
114-
auto ordering = std::strong_ordering::equivalent;
115-
(compare(&ordering, std::integral_constant<int, _is>{}), ...);
117+
(compare(std::integral_constant<int, _is>{}) || ...);
116118
return ordering;
117119
}(std::make_integer_sequence<int, sizeof...(Types)>());
118120
}

tests/generic/test_tuple.cpp

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,111 @@
11
#include <gtest/gtest.h>
22

33
#include <compare>
4+
#include <limits>
5+
#include <string>
46

57
#include <rfl.hpp>
68

79
namespace test_tuple_spaceship {
810

9-
TEST(regression, tuple_spaceship_not_always_equivalent) {
11+
TEST(Tuple, spaceship_single_less) {
1012
const auto a = rfl::Tuple<int>(1);
1113
const auto b = rfl::Tuple<int>(2);
12-
EXPECT_NE(a <=> b, std::strong_ordering::equivalent)
13-
<< "Tuple<int>(1) <=> Tuple<int>(2) should not be equivalent";
14+
EXPECT_EQ(a <=> b, std::strong_ordering::less);
1415
}
1516

16-
TEST(regression, tuple_spaceship_less) {
17-
const auto a = rfl::Tuple<int>(1);
18-
const auto b = rfl::Tuple<int>(2);
19-
EXPECT_EQ(a <=> b, std::strong_ordering::less)
20-
<< "Tuple<int>(1) <=> Tuple<int>(2) should be less";
17+
TEST(Tuple, spaceship_single_greater) {
18+
const auto a = rfl::Tuple<int>(3);
19+
const auto b = rfl::Tuple<int>(1);
20+
EXPECT_EQ(a <=> b, std::strong_ordering::greater);
21+
}
22+
23+
TEST(Tuple, spaceship_single_equivalent) {
24+
const auto a = rfl::Tuple<int>(5);
25+
const auto b = rfl::Tuple<int>(5);
26+
EXPECT_EQ(a <=> b, std::strong_ordering::equivalent);
27+
}
28+
29+
TEST(Tuple, spaceship_multi_first_differs) {
30+
const auto a = rfl::Tuple<int, int, int>(1, 10, 10);
31+
const auto b = rfl::Tuple<int, int, int>(2, 10, 10);
32+
EXPECT_EQ(a <=> b, std::strong_ordering::less);
33+
}
34+
35+
TEST(Tuple, spaceship_multi_second_differs) {
36+
const auto a = rfl::Tuple<int, int, int>(1, 2, 10);
37+
const auto b = rfl::Tuple<int, int, int>(1, 3, 10);
38+
EXPECT_EQ(a <=> b, std::strong_ordering::less);
39+
}
40+
41+
TEST(Tuple, spaceship_multi_last_differs) {
42+
const auto a = rfl::Tuple<int, int, int>(1, 2, 3);
43+
const auto b = rfl::Tuple<int, int, int>(1, 2, 4);
44+
EXPECT_EQ(a <=> b, std::strong_ordering::less);
45+
}
46+
47+
TEST(Tuple, spaceship_multi_all_equivalent) {
48+
const auto a = rfl::Tuple<int, int, int>(1, 2, 3);
49+
const auto b = rfl::Tuple<int, int, int>(1, 2, 3);
50+
EXPECT_EQ(a <=> b, std::strong_ordering::equivalent);
51+
}
52+
53+
TEST(Tuple, spaceship_multi_greater_first_decides) {
54+
const auto a = rfl::Tuple<int, int>(5, 1);
55+
const auto b = rfl::Tuple<int, int>(3, 9);
56+
EXPECT_EQ(a <=> b, std::strong_ordering::greater);
57+
}
58+
59+
TEST(Tuple, spaceship_multi_greater_later_element) {
60+
const auto a = rfl::Tuple<int, int, int>(1, 2, 5);
61+
const auto b = rfl::Tuple<int, int, int>(1, 2, 3);
62+
EXPECT_EQ(a <=> b, std::strong_ordering::greater);
63+
}
64+
65+
TEST(Tuple, spaceship_partial_ordering) {
66+
const auto a = rfl::Tuple<double>(1.0);
67+
const auto b = rfl::Tuple<double>(2.0);
68+
EXPECT_EQ(a <=> b, std::partial_ordering::less);
69+
}
70+
71+
TEST(Tuple, spaceship_nan_unordered) {
72+
const auto a = rfl::Tuple<double>(std::numeric_limits<double>::quiet_NaN());
73+
const auto b = rfl::Tuple<double>(1.0);
74+
EXPECT_EQ(a <=> b, std::partial_ordering::unordered);
75+
}
76+
77+
TEST(Tuple, spaceship_lexicographic_order) {
78+
// First element decides, even if later elements disagree.
79+
const auto a = rfl::Tuple<int, int>(1, 100);
80+
const auto b = rfl::Tuple<int, int>(2, 0);
81+
EXPECT_EQ(a <=> b, std::strong_ordering::less);
82+
}
83+
84+
TEST(Tuple, spaceship_mixed_types) {
85+
const auto a = rfl::Tuple<int, std::string>(1, "abc");
86+
const auto b = rfl::Tuple<int, std::string>(1, "abd");
87+
EXPECT_EQ(a <=> b, std::strong_ordering::less);
88+
}
89+
90+
TEST(Tuple, spaceship_mixed_types_first_decides) {
91+
const auto a = rfl::Tuple<int, std::string>(2, "aaa");
92+
const auto b = rfl::Tuple<int, std::string>(1, "zzz");
93+
EXPECT_EQ(a <=> b, std::strong_ordering::greater);
94+
}
95+
96+
TEST(Tuple, equality_single) {
97+
const auto a = rfl::Tuple<int>(42);
98+
const auto b = rfl::Tuple<int>(42);
99+
EXPECT_TRUE(a == b);
100+
EXPECT_FALSE(a == rfl::Tuple<int>(43));
101+
}
102+
103+
TEST(Tuple, equality_multi) {
104+
const auto a = rfl::Tuple<int, std::string>(1, "hello");
105+
const auto b = rfl::Tuple<int, std::string>(1, "hello");
106+
const auto c = rfl::Tuple<int, std::string>(1, "world");
107+
EXPECT_TRUE(a == b);
108+
EXPECT_FALSE(a == c);
21109
}
22110

23-
} // namespace test_tuple_spaceship
111+
} // namespace test_tuple_spaceship

0 commit comments

Comments
 (0)