Skip to content

Commit b762611

Browse files
committed
Update compare operator
1 parent a739778 commit b762611

File tree

3 files changed

+199
-18
lines changed

3 files changed

+199
-18
lines changed

include/beman/inplace_vector/inplace_vector.hpp

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ Software.
254254
*/
255255
#include <algorithm> // for rotate...
256256
#include <array>
257+
#include <compare>
257258
#include <concepts> // for lots...
258259
#include <cstddef> // for size_t
259260
#include <cstdint> // for fixed-width integer types
@@ -309,6 +310,11 @@ concept container_compatible_range =
309310
template <typename T, std::size_t N>
310311
concept satify_constexpr = N == 0 || std::is_trivial_v<T>;
311312

313+
template <typename T>
314+
concept lessthan_comparable = requires(const T &a, const T &b) {
315+
{ a < b } -> std::convertible_to<bool>;
316+
};
317+
312318
} // namespace beman::details::inplace_vector
313319

314320
// Types implementing the `inplace_vector`'s storage
@@ -1001,27 +1007,20 @@ struct inplace_vector
10011007
insert_range(begin(), il);
10021008
}
10031009

1004-
constexpr friend int /*synth-three-way-result<T>*/
1005-
operator<=>(const inplace_vector & x, const inplace_vector & y) {
1006-
if (x.size() < y.size())
1007-
return -1;
1008-
if (x.size() > y.size())
1009-
return +1;
1010-
1011-
bool all_equal = true;
1012-
bool all_less = true;
1013-
for (size_type i = 0; i < x.size(); ++i) {
1010+
constexpr friend auto operator<=>(const inplace_vector &x,
1011+
const inplace_vector &y)
1012+
requires(std::equality_comparable<T> &&
1013+
beman::details::inplace_vector::lessthan_comparable<T>)
1014+
{
1015+
const auto sz = std::min(x.size(), y.size());
1016+
for (std::size_t i = 0; i < sz; ++i) {
10141017
if (x[i] < y[i])
1015-
all_equal = false;
1016-
if (x[i] == y[i])
1017-
all_less = false;
1018+
return std::strong_ordering::less;
1019+
if (y[i] < x[i])
1020+
return std::strong_ordering::greater;
10181021
}
10191022

1020-
if (all_equal)
1021-
return 0;
1022-
if (all_less)
1023-
return -1;
1024-
return 1;
1023+
return x.size() <=> y.size();
10251024
}
10261025
};
10271026

tests/beman/inplace_vector/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ endfunction()
3737
# Tests for official specs
3838
add_gtest(container_requirements)
3939
add_gtest(triviality)
40+
add_gtest(compare)
4041
add_gtest(constructors)
4142
add_gtest(size_n_data)
4243
add_gtest(erasure)
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
#include <beman/inplace_vector/inplace_vector.hpp>
2+
#include <gtest/gtest.h>
3+
4+
#include <compare>
5+
6+
using namespace beman;
7+
8+
template <class T>
9+
concept has_threeway = requires(const T &t) {
10+
{ t <=> t };
11+
};
12+
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;
18+
19+
T greater{4, 5, 6};
20+
T lesser{0, 0, 0};
21+
22+
T bigger{1, 2, 3, 0};
23+
T smaller{1, 2};
24+
25+
T greater_smaller{2, 2};
26+
T lesser_bigger{0, 2, 3, 0};
27+
28+
EXPECT_TRUE((base <=> copy) == 0);
29+
EXPECT_TRUE((base <=> greater) < 0);
30+
EXPECT_TRUE((base <=> lesser) > 0);
31+
32+
EXPECT_TRUE((base <=> bigger) < 0);
33+
EXPECT_TRUE((base <=> smaller) > 0);
34+
35+
EXPECT_TRUE((base <=> greater_smaller) < 0);
36+
EXPECT_TRUE((base <=> lesser_bigger) > 0);
37+
}
38+
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;
44+
45+
T greater{4.0f, 5.0f, 6.0f};
46+
T lesser{0.0f, 0.0f, 0.0f};
47+
48+
T bigger{1.0f, 2.0f, 3.0f, 0.0f};
49+
T smaller{1.0f, 2.0f};
50+
51+
T greater_smaller{2.0f, 2.0f};
52+
T lesser_bigger{0.0f, 2.0f, 3.0f, 0.0f};
53+
54+
EXPECT_TRUE((base <=> copy) == 0);
55+
56+
EXPECT_TRUE((base <=> greater) < 0);
57+
EXPECT_TRUE((base <=> lesser) > 0);
58+
59+
EXPECT_TRUE((base <=> bigger) < 0);
60+
EXPECT_TRUE((base <=> smaller) > 0);
61+
62+
EXPECT_TRUE((base <=> greater_smaller) < 0);
63+
EXPECT_TRUE((base <=> lesser_bigger) > 0);
64+
}
65+
66+
TEST(Compare, threeway_comparable1) {
67+
struct comparable1 {
68+
int a;
69+
int b;
70+
constexpr auto operator<=>(const comparable1 &) const = default;
71+
};
72+
73+
static_assert(std::three_way_comparable<comparable1>);
74+
static_assert(has_threeway<comparable1>);
75+
static_assert(std::three_way_comparable<inplace_vector<comparable1, 4>>);
76+
static_assert(has_threeway<inplace_vector<comparable1, 4>>);
77+
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);
101+
102+
EXPECT_TRUE((base <=> greater_smaller) < 0);
103+
EXPECT_TRUE((base <=> lesser_bigger) > 0);
104+
}
105+
106+
TEST(Compare, threeway_comparable2) {
107+
108+
struct comparable2 {
109+
int a;
110+
int b;
111+
constexpr bool operator==(const comparable2 &) const = default;
112+
constexpr bool operator<(const comparable2 &other) const {
113+
return a < other.a || (a == other.a && b < other.b);
114+
};
115+
};
116+
117+
static_assert(!std::three_way_comparable<comparable2>);
118+
static_assert(!has_threeway<comparable2>);
119+
static_assert(std::three_way_comparable<inplace_vector<comparable2, 4>>);
120+
static_assert(has_threeway<inplace_vector<comparable2, 4>>);
121+
122+
using T = inplace_vector<comparable2, 4>;
123+
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}};
129+
130+
T bigger{{1, 2}, {3, 4}, {5, 6}};
131+
T smaller{{1, 2}};
132+
133+
T greater_smaller{{2, 2}, {3, 3}};
134+
T lesser_bigger{{0, 2}, {3, 3}, {0, 0}};
135+
136+
EXPECT_TRUE((empty <=> empty) == 0);
137+
EXPECT_TRUE((base <=> copy) == 0);
138+
139+
EXPECT_TRUE((base <=> greater) < 0);
140+
EXPECT_TRUE((base <=> lesser) > 0);
141+
142+
EXPECT_TRUE((base <=> bigger) < 0);
143+
EXPECT_TRUE((base <=> smaller) > 0);
144+
145+
EXPECT_TRUE((base <=> greater_smaller) < 0);
146+
EXPECT_TRUE((base <=> lesser_bigger) > 0);
147+
}
148+
149+
TEST(Compare, threeway_uncomparable) {
150+
151+
struct uncomparable1 {
152+
int a;
153+
};
154+
155+
static_assert(!std::three_way_comparable<uncomparable1>);
156+
static_assert(!has_threeway<uncomparable1>);
157+
static_assert(!std::three_way_comparable<inplace_vector<uncomparable1, 4>>);
158+
static_assert(!has_threeway<inplace_vector<uncomparable1, 4>>);
159+
160+
struct uncomparable2 {
161+
int a;
162+
constexpr bool operator==(const uncomparable2 &) const = default;
163+
};
164+
165+
static_assert(!std::three_way_comparable<uncomparable2>);
166+
static_assert(!has_threeway<uncomparable2>);
167+
static_assert(!std::three_way_comparable<inplace_vector<uncomparable2, 4>>);
168+
static_assert(!has_threeway<inplace_vector<uncomparable2, 4>>);
169+
170+
struct uncomparable3 {
171+
int a;
172+
constexpr auto operator<=>(const uncomparable3 &) const {
173+
return std::partial_ordering::unordered;
174+
}
175+
};
176+
177+
static_assert(!std::three_way_comparable<uncomparable3>);
178+
static_assert(has_threeway<uncomparable3>); // has op but returns unordered
179+
static_assert(!std::three_way_comparable<inplace_vector<uncomparable3, 4>>);
180+
static_assert(!has_threeway<inplace_vector<uncomparable3, 4>>);
181+
}

0 commit comments

Comments
 (0)