Skip to content

Commit 5cba529

Browse files
committed
Update threeway compare
1 parent b762611 commit 5cba529

File tree

2 files changed

+223
-82
lines changed

2 files changed

+223
-82
lines changed

include/beman/inplace_vector/inplace_vector.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,7 @@ struct inplace_vector
10091009

10101010
constexpr friend auto operator<=>(const inplace_vector &x,
10111011
const inplace_vector &y)
1012-
requires(std::equality_comparable<T> &&
1012+
requires(!std::three_way_comparable<T> && std::equality_comparable<T> &&
10131013
beman::details::inplace_vector::lessthan_comparable<T>)
10141014
{
10151015
const auto sz = std::min(x.size(), y.size());
@@ -1022,6 +1022,14 @@ struct inplace_vector
10221022

10231023
return x.size() <=> y.size();
10241024
}
1025+
1026+
constexpr friend auto operator<=>(const inplace_vector &x,
1027+
const inplace_vector &y)
1028+
requires(std::three_way_comparable<T>)
1029+
{
1030+
return std::lexicographical_compare_three_way(x.begin(), x.end(), y.begin(),
1031+
y.end());
1032+
}
10251033
};
10261034

10271035
template <typename T, std::size_t N, typename U = T>
Lines changed: 214 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <beman/inplace_vector/inplace_vector.hpp>
22
#include <gtest/gtest.h>
33

4+
#include <cmath>
45
#include <compare>
56

67
using namespace beman;
@@ -10,57 +11,96 @@ concept has_threeway = requires(const T &t) {
1011
{ t <=> t };
1112
};
1213

13-
TEST(Compare, threeway_int) {
14-
using T = inplace_vector<int, 4>;
15-
T empty{};
16-
T base{1, 2, 3};
17-
T copy = base;
14+
template <typename T> struct vec_list {
15+
T empty;
16+
T base; // base
17+
T copy; // identical to base
18+
T greater; // greater number of elements
19+
T lesser; // lesser number of elements
20+
T bigger; // bigger value of the elements
21+
T smaller; // smaller value of the elements
22+
T greater_smaller; // greater number of elements but smaller values
23+
T lesser_bigger; // lesser number of elements but bigger values
24+
};
1825

19-
T greater{4, 5, 6};
20-
T lesser{0, 0, 0};
26+
template <typename T> static void runtests(vec_list<T> &list) {
2127

22-
T bigger{1, 2, 3, 0};
23-
T smaller{1, 2};
28+
static_assert(std::three_way_comparable<T>);
2429

25-
T greater_smaller{2, 2};
26-
T lesser_bigger{0, 2, 3, 0};
30+
// if T::value_type is threewaycomparable with ordering X then T must also
31+
// be comparable with ordering X
2732

28-
EXPECT_TRUE((base <=> copy) == 0);
29-
EXPECT_TRUE((base <=> greater) < 0);
30-
EXPECT_TRUE((base <=> lesser) > 0);
33+
using VT = typename T::value_type;
3134

32-
EXPECT_TRUE((base <=> bigger) < 0);
33-
EXPECT_TRUE((base <=> smaller) > 0);
35+
if constexpr (std::three_way_comparable<VT, std::strong_ordering>)
36+
static_assert(std::three_way_comparable<T, std::strong_ordering>);
3437

35-
EXPECT_TRUE((base <=> greater_smaller) < 0);
36-
EXPECT_TRUE((base <=> lesser_bigger) > 0);
37-
}
38+
if constexpr (std::three_way_comparable<VT, std::weak_ordering>)
39+
static_assert(std::three_way_comparable<T, std::weak_ordering>);
40+
41+
if constexpr (std::three_way_comparable<VT, std::partial_ordering>)
42+
static_assert(std::three_way_comparable<T, std::partial_ordering>);
43+
44+
EXPECT_TRUE(list.empty == list.empty);
45+
EXPECT_TRUE(list.empty != list.base);
46+
47+
EXPECT_TRUE((list.base <=> list.copy) == 0);
48+
EXPECT_TRUE((list.base <=> list.greater) < 0);
49+
EXPECT_TRUE((list.base <=> list.lesser) > 0);
3850

39-
TEST(COmpare, threeway_float) {
40-
using T = inplace_vector<float, 4>;
41-
T empty{};
42-
T base{1.0f, 2.0f, 3.0f};
43-
T copy = base;
51+
EXPECT_TRUE((list.base <=> list.bigger) < 0);
52+
EXPECT_TRUE((list.base <=> list.smaller) > 0);
4453

45-
T greater{4.0f, 5.0f, 6.0f};
46-
T lesser{0.0f, 0.0f, 0.0f};
54+
EXPECT_TRUE((list.base <=> list.greater_smaller) < 0);
55+
EXPECT_TRUE((list.base <=> list.lesser_bigger) > 0);
4756

48-
T bigger{1.0f, 2.0f, 3.0f, 0.0f};
49-
T smaller{1.0f, 2.0f};
57+
EXPECT_TRUE(list.base == list.copy);
58+
EXPECT_TRUE(list.base <= list.copy);
59+
EXPECT_TRUE(list.base >= list.copy);
60+
EXPECT_TRUE(list.base < list.greater);
61+
EXPECT_TRUE(list.base <= list.greater);
62+
EXPECT_TRUE(list.base > list.lesser);
63+
EXPECT_TRUE(list.base >= list.lesser);
5064

51-
T greater_smaller{2.0f, 2.0f};
52-
T lesser_bigger{0.0f, 2.0f, 3.0f, 0.0f};
65+
EXPECT_TRUE(list.copy == list.base);
66+
EXPECT_TRUE(list.copy <= list.base);
67+
EXPECT_TRUE(list.copy >= list.base);
68+
EXPECT_TRUE(list.greater > list.base);
69+
EXPECT_TRUE(list.greater >= list.base);
70+
EXPECT_TRUE(list.lesser < list.base);
71+
EXPECT_TRUE(list.lesser <= list.base);
72+
};
5373

54-
EXPECT_TRUE((base <=> copy) == 0);
74+
TEST(Compare, threeway_int) {
75+
vec_list<inplace_vector<int, 4>> list{
76+
.empty{},
77+
.base{1, 2, 3},
78+
.copy{1, 2, 3},
79+
.greater{4, 5, 6},
80+
.lesser{0, 0, 0},
81+
.bigger{1, 2, 3, 0},
82+
.smaller{1, 2},
83+
.greater_smaller{2, 2},
84+
.lesser_bigger{0, 2, 3, 4},
85+
};
5586

56-
EXPECT_TRUE((base <=> greater) < 0);
57-
EXPECT_TRUE((base <=> lesser) > 0);
87+
runtests(list);
88+
}
5889

59-
EXPECT_TRUE((base <=> bigger) < 0);
60-
EXPECT_TRUE((base <=> smaller) > 0);
90+
TEST(Compare, threeway_float) {
91+
vec_list<inplace_vector<float, 4>> list{
92+
.empty{},
93+
.base{1.0f, 2.0f, 3.0f},
94+
.copy{1.0f, 2.0f, 3.0f},
95+
.greater{4.0f, 5.0f, 6.0f},
96+
.lesser{0.0f, 0.0f, 0.0f},
97+
.bigger{1.0f, 2.0f, 3.0f, 0.0f},
98+
.smaller{1.0f, 2.0f},
99+
.greater_smaller{2.0f, 2.0f},
100+
.lesser_bigger{0.0f, 2.0f, 3.0f, 4.0f},
101+
};
61102

62-
EXPECT_TRUE((base <=> greater_smaller) < 0);
63-
EXPECT_TRUE((base <=> lesser_bigger) > 0);
103+
runtests(list);
64104
}
65105

66106
TEST(Compare, threeway_comparable1) {
@@ -75,32 +115,19 @@ TEST(Compare, threeway_comparable1) {
75115
static_assert(std::three_way_comparable<inplace_vector<comparable1, 4>>);
76116
static_assert(has_threeway<inplace_vector<comparable1, 4>>);
77117

78-
using T = inplace_vector<comparable1, 4>;
79-
80-
T empty{};
81-
82-
T base{{1, 2}, {3, 4}};
83-
T copy = base;
84-
T greater{{5, 6}, {7, 8}};
85-
T lesser{{0, 0}, {0, 0}};
86-
87-
T bigger{{1, 2}, {3, 4}, {5, 6}};
88-
T smaller{{1, 2}};
89-
90-
T greater_smaller{{2, 2}, {3, 3}};
91-
T lesser_bigger{{0, 2}, {3, 3}, {0, 0}};
92-
93-
EXPECT_TRUE((empty <=> empty) == 0);
94-
EXPECT_TRUE((base <=> copy) == 0);
95-
96-
EXPECT_TRUE((base <=> greater) < 0);
97-
EXPECT_TRUE((base <=> lesser) > 0);
98-
99-
EXPECT_TRUE((base <=> bigger) < 0);
100-
EXPECT_TRUE((base <=> smaller) > 0);
118+
vec_list<inplace_vector<comparable1, 4>> list{
119+
.empty{},
120+
.base{{1, 2}, {3, 4}},
121+
.copy{{1, 2}, {3, 4}},
122+
.greater{{5, 6}, {7, 8}},
123+
.lesser{{0, 0}, {0, 0}},
124+
.bigger{{1, 2}, {3, 4}, {5, 6}},
125+
.smaller{{1, 2}},
126+
.greater_smaller{{2, 2}, {3, 3}},
127+
.lesser_bigger{{0, 2}, {3, 3}, {4, 4}},
128+
};
101129

102-
EXPECT_TRUE((base <=> greater_smaller) < 0);
103-
EXPECT_TRUE((base <=> lesser_bigger) > 0);
130+
runtests(list);
104131
}
105132

106133
TEST(Compare, threeway_comparable2) {
@@ -119,31 +146,136 @@ TEST(Compare, threeway_comparable2) {
119146
static_assert(std::three_way_comparable<inplace_vector<comparable2, 4>>);
120147
static_assert(has_threeway<inplace_vector<comparable2, 4>>);
121148

122-
using T = inplace_vector<comparable2, 4>;
149+
vec_list<inplace_vector<comparable2, 4>> list{
150+
.empty{},
151+
.base{{1, 2}, {3, 4}},
152+
.copy{{1, 2}, {3, 4}},
153+
.greater{{5, 6}, {7, 8}},
154+
.lesser{{0, 0}, {0, 0}},
155+
.bigger{{1, 2}, {3, 4}, {5, 6}},
156+
.smaller{{1, 2}},
157+
.greater_smaller{{2, 2}, {3, 3}},
158+
.lesser_bigger{{0, 2}, {3, 3}, {4, 4}},
159+
};
160+
161+
runtests(list);
162+
163+
// compare unorderable values
164+
165+
EXPECT_EQ(std::nanf("") <=> std::nanf(""), std::partial_ordering::unordered);
166+
EXPECT_FALSE(std::nanf("") == std::nanf(""));
167+
EXPECT_FALSE(std::nanf("") < std::nanf(""));
168+
EXPECT_FALSE(std::nanf("") > std::nanf(""));
169+
EXPECT_FALSE(std::nanf("") >= std::nanf(""));
170+
EXPECT_FALSE(std::nanf("") <= std::nanf(""));
171+
172+
inplace_vector<float, 4> vnan{std::nanf("")};
173+
inplace_vector<float, 4> vnan2{std::nanf("")};
123174

124-
T empty{};
125-
T base{{1, 2}, {3, 4}};
126-
T copy = base;
127-
T greater{{5, 6}, {7, 8}};
128-
T lesser{{0, 0}, {0, 0}};
175+
EXPECT_EQ(vnan <=> vnan2, std::partial_ordering::unordered);
176+
EXPECT_FALSE(vnan == vnan2);
177+
EXPECT_FALSE(vnan < vnan2);
178+
EXPECT_FALSE(vnan > vnan2);
179+
EXPECT_FALSE(vnan >= vnan2);
180+
EXPECT_FALSE(vnan <= vnan2);
181+
}
182+
183+
TEST(Compare, threeway_strong_ordering) {
184+
185+
struct weaktype {
186+
int a;
187+
constexpr std::strong_ordering
188+
operator<=>(const weaktype &other) const = default;
189+
};
190+
191+
using T = weaktype;
192+
193+
vec_list<inplace_vector<weaktype, 4>> list{
194+
.empty{},
195+
.base{T{1}, T{2}, T{3}},
196+
.copy{T{1}, T{2}, T{3}},
197+
.greater{T{4}, T{5}, T{6}},
198+
.lesser{T{0}, T{0}, T{0}},
199+
.bigger{T{1}, T{2}, T{3}, T{0}},
200+
.smaller{T{1}, T{2}},
201+
.greater_smaller{T{2}, T{2}},
202+
.lesser_bigger{T{0}, T{2}, T{3}, T{4}},
203+
};
204+
205+
runtests(list);
206+
}
207+
208+
TEST(Compare, threeway_weak_ordering) {
209+
210+
struct weaktype {
211+
int a;
212+
constexpr std::weak_ordering
213+
operator<=>(const weaktype &other) const = default;
214+
};
215+
216+
using T = weaktype;
217+
218+
vec_list<inplace_vector<weaktype, 4>> list{
219+
.empty{},
220+
.base{T{1}, T{2}, T{3}},
221+
.copy{T{1}, T{2}, T{3}},
222+
.greater{T{4}, T{5}, T{6}},
223+
.lesser{T{0}, T{0}, T{0}},
224+
.bigger{T{1}, T{2}, T{3}, T{0}},
225+
.smaller{T{1}, T{2}},
226+
.greater_smaller{T{2}, T{2}},
227+
.lesser_bigger{T{0}, T{2}, T{3}, T{4}},
228+
};
229+
230+
runtests(list);
231+
}
232+
233+
TEST(Compare, threeway_partial_ordering) {
129234

130-
T bigger{{1, 2}, {3, 4}, {5, 6}};
131-
T smaller{{1, 2}};
235+
struct custom {
236+
int a;
237+
constexpr auto operator<=>(const custom &other) const {
238+
if (a == -1 && other.a == -1)
239+
return std::partial_ordering::unordered;
240+
return std::partial_ordering(a <=> other.a);
241+
}
242+
243+
constexpr bool operator==(const custom &other) const {
244+
if (a == -1 && other.a == -1)
245+
return false;
246+
return a == other.a;
247+
}
248+
};
132249

133-
T greater_smaller{{2, 2}, {3, 3}};
134-
T lesser_bigger{{0, 2}, {3, 3}, {0, 0}};
250+
using T = custom;
251+
252+
vec_list<inplace_vector<custom, 4>> list{
253+
.empty{},
254+
.base{T{1}, T{2}, T{3}},
255+
.copy{T{1}, T{2}, T{3}},
256+
.greater{T{4}, T{5}, T{6}},
257+
.lesser{T{0}, T{0}, T{0}},
258+
.bigger{T{1}, T{2}, T{3}, T{0}},
259+
.smaller{T{1}, T{2}},
260+
.greater_smaller{T{2}, T{2}},
261+
.lesser_bigger{T{0}, T{2}, T{3}, T{4}},
262+
};
135263

136-
EXPECT_TRUE((empty <=> empty) == 0);
137-
EXPECT_TRUE((base <=> copy) == 0);
264+
runtests(list);
138265

139-
EXPECT_TRUE((base <=> greater) < 0);
140-
EXPECT_TRUE((base <=> lesser) > 0);
266+
T t1{-1};
267+
T t2 = t1;
268+
EXPECT_EQ(t1 <=> t2, std::partial_ordering::unordered);
141269

142-
EXPECT_TRUE((base <=> bigger) < 0);
143-
EXPECT_TRUE((base <=> smaller) > 0);
270+
inplace_vector<T, 4> v1{t1};
271+
inplace_vector<T, 4> v2{t2};
144272

145-
EXPECT_TRUE((base <=> greater_smaller) < 0);
146-
EXPECT_TRUE((base <=> lesser_bigger) > 0);
273+
EXPECT_EQ(v1 <=> v2, std::partial_ordering::unordered);
274+
EXPECT_FALSE(v1 == v2);
275+
EXPECT_FALSE(v1 < v2);
276+
EXPECT_FALSE(v1 > v2);
277+
EXPECT_FALSE(v1 >= v2);
278+
EXPECT_FALSE(v1 <= v2);
147279
}
148280

149281
TEST(Compare, threeway_uncomparable) {
@@ -172,10 +304,11 @@ TEST(Compare, threeway_uncomparable) {
172304
constexpr auto operator<=>(const uncomparable3 &) const {
173305
return std::partial_ordering::unordered;
174306
}
307+
constexpr bool operator==(const uncomparable3 &) const = delete;
175308
};
176309

177310
static_assert(!std::three_way_comparable<uncomparable3>);
178-
static_assert(has_threeway<uncomparable3>); // has op but returns unordered
311+
static_assert(has_threeway<uncomparable3>); // has <=> but no == operator
179312
static_assert(!std::three_way_comparable<inplace_vector<uncomparable3, 4>>);
180313
static_assert(!has_threeway<inplace_vector<uncomparable3, 4>>);
181314
}

0 commit comments

Comments
 (0)