Skip to content

Commit 3ac64fa

Browse files
committed
Rather than having comparison algorithms behave differently depending on the number of iterators you pass to them, just have functions equal_assume_same_size and lexicographical_compare_assume_same_size. Remove all iterator overloads of these functions since they operate on ranges. Rename lexicographical_compare_3way to lexicographical_compare since we're fine being different from the standard.
1 parent 00ea6b7 commit 3ac64fa

File tree

6 files changed

+102
-154
lines changed

6 files changed

+102
-154
lines changed

dependencies/Catch2

dependencies/std_module

source/containers/algorithms/compare.cpp

Lines changed: 75 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55

66
module;
77

8+
#include <bounded/assert.hpp>
89
#include <operators/forward.hpp>
910

1011
export module containers.algorithms.compare;
1112

1213
import containers.begin_end;
1314
import containers.iterator;
1415
import containers.range;
16+
import containers.range_reference_t;
1517
import containers.sentinel_for;
1618
import containers.size;
1719
import containers.sized_range;
@@ -21,126 +23,84 @@ import std_module;
2123

2224
namespace containers {
2325

24-
export template<iterator InputIterator1, iterator InputIterator2>
25-
constexpr auto lexicographical_compare_3way(InputIterator1 first1, sentinel_for<InputIterator1> auto const last1, InputIterator2 first2, sentinel_for<InputIterator2> auto const last2, auto cmp) -> decltype(cmp(*first1, *first2)) {
26-
for (; first1 != last1 and first2 != last2; ++first1, ++first2) {
26+
template<typename Range1, typename Range2>
27+
using comparison_result = std::compare_three_way_result_t<
28+
containers::range_reference_t<Range1>,
29+
containers::range_reference_t<Range2>
30+
>;
31+
32+
export template<range Range1, range Range2, typename Compare = std::compare_three_way>
33+
constexpr auto lexicographical_compare_assume_same_size(
34+
Range1 && range1,
35+
Range2 && range2,
36+
Compare cmp = std::compare_three_way()
37+
) -> comparison_result<Range1, Range2> {
38+
if constexpr (sized_range<Range1> and sized_range<Range2>) {
39+
BOUNDED_ASSERT(::containers::size(range1) == ::containers::size(range2));
40+
}
41+
auto const last1 = containers::end(OPERATORS_FORWARD(range1));
42+
auto first1 = containers::begin(OPERATORS_FORWARD(range1));
43+
auto first2 = containers::begin(OPERATORS_FORWARD(range2));
44+
for (; first1 != last1; ++first1, ++first2) {
2745
if (auto const result = cmp(*first1, *first2); result != 0) {
2846
return result;
2947
}
3048
}
31-
return
32-
(first1 != last1) ? std::strong_ordering::greater :
33-
(first2 != last2) ? std::strong_ordering::less :
34-
std::strong_ordering::equal;
35-
}
36-
37-
export constexpr auto lexicographical_compare_3way(range auto && range1, range auto && range2, auto cmp) {
38-
return ::containers::lexicographical_compare_3way(
39-
containers::begin(OPERATORS_FORWARD(range1)),
40-
containers::end(OPERATORS_FORWARD(range1)),
41-
containers::begin(OPERATORS_FORWARD(range2)),
42-
containers::end(OPERATORS_FORWARD(range2)),
43-
std::move(cmp)
44-
);
45-
}
46-
47-
48-
export template<iterator InputIterator1, iterator InputIterator2>
49-
constexpr auto lexicographical_compare_3way(InputIterator1 first1, sentinel_for<InputIterator1> auto last1, InputIterator2 first2, sentinel_for<InputIterator2> auto last2) {
50-
return ::containers::lexicographical_compare_3way(
51-
std::move(first1),
52-
std::move(last1),
53-
std::move(first2),
54-
std::move(last2),
55-
std::compare_three_way()
56-
);
57-
}
58-
59-
export constexpr auto lexicographical_compare_3way(range auto && range1, range auto && range2) {
60-
return ::containers::lexicographical_compare_3way(
61-
OPERATORS_FORWARD(range1),
62-
OPERATORS_FORWARD(range2),
63-
std::compare_three_way()
64-
);
49+
return std::strong_ordering::equal;
6550
}
6651

67-
68-
export template<iterator InputIterator1, iterator InputIterator2>
69-
constexpr auto lexicographical_compare_3way(InputIterator1 first1, sentinel_for<InputIterator1> auto const last1, InputIterator2 first2, auto cmp) requires(!sentinel_for<decltype(cmp), InputIterator2>) {
70-
for (; first1 != last1; ++first1, ++first2) {
52+
export template<range Range1, range Range2, typename Compare = std::compare_three_way>
53+
constexpr auto lexicographical_compare(
54+
Range1 && range1,
55+
Range2 && range2,
56+
Compare cmp = std::compare_three_way()
57+
) -> comparison_result<Range1, Range2> {
58+
auto const last1 = containers::end(OPERATORS_FORWARD(range1));
59+
auto first1 = containers::begin(OPERATORS_FORWARD(range1));
60+
auto const last2 = containers::end(OPERATORS_FORWARD(range2));
61+
auto first2 = containers::begin(OPERATORS_FORWARD(range2));
62+
for (; first1 != last1 and first2 != last2; ++first1, ++first2) {
7163
if (auto const result = cmp(*first1, *first2); result != 0) {
7264
return result;
7365
}
7466
}
75-
return std::strong_ordering::equal;
76-
}
77-
78-
export template<iterator InputIterator1>
79-
constexpr auto lexicographical_compare_3way(InputIterator1 first1, sentinel_for<InputIterator1> auto last1, iterator auto first2) {
80-
return ::containers::lexicographical_compare_3way(
81-
std::move(first1),
82-
std::move(last1),
83-
std::move(first2),
84-
std::compare_three_way()
85-
);
67+
return
68+
(first1 != last1) ? std::strong_ordering::greater :
69+
(first2 != last2) ? std::strong_ordering::less :
70+
std::strong_ordering::equal;
8671
}
8772

88-
89-
9073
// Shorter ranges compare less than longer ranges. Ranges of the same length
9174
// compare lexicographically.
92-
export constexpr auto shortlex_compare(sized_range auto && range1, sized_range auto && range2, auto cmp) {
75+
export template<sized_range Range1, sized_range Range2, typename Compare = std::compare_three_way>
76+
constexpr auto shortlex_compare(
77+
Range1 && range1,
78+
Range2 && range2,
79+
Compare cmp = std::compare_three_way()
80+
) -> comparison_result<Range1, Range2> {
9381
if (auto const result = ::containers::size(range1) <=> ::containers::size(range2); result != 0) {
9482
return result;
9583
}
96-
return ::containers::lexicographical_compare_3way(
97-
::containers::begin(OPERATORS_FORWARD(range1)),
98-
::containers::end(OPERATORS_FORWARD(range1)),
99-
::containers::begin(OPERATORS_FORWARD(range2)),
100-
std::move(cmp)
101-
);
102-
}
103-
104-
export constexpr auto shortlex_compare(sized_range auto && range1, sized_range auto && range2) {
105-
return ::containers::shortlex_compare(
84+
return ::containers::lexicographical_compare_assume_same_size(
10685
OPERATORS_FORWARD(range1),
10786
OPERATORS_FORWARD(range2),
108-
std::compare_three_way()
87+
std::move(cmp)
10988
);
11089
}
11190

11291

113-
114-
115-
116-
117-
118-
119-
120-
export template<iterator InputIterator1, iterator InputIterator2>
121-
constexpr auto equal(InputIterator1 first1, sentinel_for<InputIterator1> auto const last1, InputIterator2 first2, sentinel_for<InputIterator2> auto const last2, auto cmp) {
122-
for (; first1 != last1 and first2 != last2; ++first1, ++first2) {
123-
if (!cmp(*first1, *first2)) {
124-
return false;
125-
}
92+
export template<range Range1, range Range2, typename Compare = std::equal_to<>>
93+
constexpr auto equal_assume_same_size(
94+
Range1 && range1,
95+
Range2 && range2,
96+
Compare cmp = std::equal_to()
97+
) -> bool {
98+
if constexpr (sized_range<Range1> and sized_range<Range2>) {
99+
BOUNDED_ASSERT(::containers::size(range1) == ::containers::size(range2));
126100
}
127-
return first1 == last1 and first2 == last2;
128-
}
129-
130-
131-
export template<iterator InputIterator1, iterator InputIterator2>
132-
constexpr auto equal(InputIterator1 first1, sentinel_for<InputIterator1> auto last1, InputIterator2 first2, sentinel_for<InputIterator2> auto last2) {
133-
return ::containers::equal(
134-
std::move(first1),
135-
std::move(last1),
136-
std::move(first2),
137-
std::move(last2),
138-
bounded::equal_to()
139-
);
140-
}
141-
142-
export template<iterator InputIterator1, iterator InputIterator2>
143-
constexpr auto equal(InputIterator1 first1, sentinel_for<InputIterator1> auto const last1, InputIterator2 first2, auto cmp) requires(!sentinel_for<decltype(cmp), InputIterator2>) {
101+
auto const last1 = containers::end(OPERATORS_FORWARD(range1));
102+
auto first1 = containers::begin(OPERATORS_FORWARD(range1));
103+
auto first2 = containers::begin(OPERATORS_FORWARD(range2));
144104
for (; first1 != last1; ++first1, ++first2) {
145105
if (!cmp(*first1, *first2)) {
146106
return false;
@@ -149,45 +109,33 @@ constexpr auto equal(InputIterator1 first1, sentinel_for<InputIterator1> auto co
149109
return true;
150110
}
151111

152-
export template<iterator InputIterator1, iterator InputIterator2>
153-
constexpr auto equal(InputIterator1 first1, sentinel_for<InputIterator1> auto last1, InputIterator2 first2) {
154-
return ::containers::equal(
155-
std::move(first1),
156-
std::move(last1),
157-
std::move(first2),
158-
bounded::equal_to()
159-
);
160-
}
161112

162-
export template<range Range1, range Range2>
163-
constexpr auto equal(Range1 && range1, Range2 && range2, auto cmp) {
113+
export template<range Range1, range Range2, typename Compare = std::equal_to<>>
114+
constexpr auto equal(
115+
Range1 && range1,
116+
Range2 && range2,
117+
Compare cmp = std::equal_to()
118+
) -> bool {
164119
if constexpr (sized_range<Range1> and sized_range<Range2>) {
165120
return
166121
::containers::size(range1) == ::containers::size(range2) and
167-
::containers::equal(
168-
containers::begin(OPERATORS_FORWARD(range1)),
169-
containers::end(OPERATORS_FORWARD(range1)),
170-
containers::begin(OPERATORS_FORWARD(range2)),
122+
::containers::equal_assume_same_size(
123+
OPERATORS_FORWARD(range1),
124+
OPERATORS_FORWARD(range2),
171125
std::move(cmp)
172126
);
173127
} else {
174-
return ::containers::equal(
175-
containers::begin(OPERATORS_FORWARD(range1)),
176-
containers::end(OPERATORS_FORWARD(range1)),
177-
containers::begin(OPERATORS_FORWARD(range2)),
178-
containers::end(OPERATORS_FORWARD(range2)),
179-
std::move(cmp)
180-
);
128+
auto const last1 = containers::end(OPERATORS_FORWARD(range1));
129+
auto first1 = containers::begin(OPERATORS_FORWARD(range1));
130+
auto const last2 = containers::end(OPERATORS_FORWARD(range2));
131+
auto first2 = containers::begin(OPERATORS_FORWARD(range2));
132+
for (; first1 != last1 and first2 != last2; ++first1, ++first2) {
133+
if (!cmp(*first1, *first2)) {
134+
return false;
135+
}
136+
}
137+
return first1 == last1 and first2 == last2;
181138
}
182139
}
183140

184-
export template<range Range1, range Range2>
185-
constexpr auto equal(Range1 && range1, Range2 && range2) {
186-
return ::containers::equal(
187-
OPERATORS_FORWARD(range1),
188-
OPERATORS_FORWARD(range2),
189-
bounded::equal_to()
190-
);
191-
}
192-
193141
} // namespace containers

source/containers/compare_container.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ namespace lexicographical_comparison {
3232
export struct base {
3333
template<range T> requires bounded::ordered<range_value_t<T>>
3434
friend constexpr auto operator<=>(T const & lhs, T const & rhs) {
35-
return ::containers::lexicographical_compare_3way(lhs, rhs);
35+
return ::containers::lexicographical_compare(lhs, rhs);
3636
}
3737
template<range T> requires bounded::equality_comparable<range_value_t<T>>
3838
friend constexpr auto operator==(T const & lhs, T const & rhs) -> bool {

source/containers/string.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export struct string : private small_buffer_optimized_vector<char, 0> {
6868
}
6969

7070
friend constexpr auto operator<=>(string const & lhs, std::string_view const rhs) {
71-
return ::containers::lexicographical_compare_3way(lhs, rhs);
71+
return ::containers::lexicographical_compare(lhs, rhs);
7272
}
7373
friend constexpr auto operator==(string const & lhs, std::string_view const rhs) -> bool {
7474
return ::containers::equal(lhs, rhs);

source/containers/test/algorithms/compare.cpp

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,19 @@ using namespace bounded::literal;
1414

1515
constexpr auto empty = containers::array<int, 0_bi>();
1616

17-
static_assert(containers::lexicographical_compare_3way(empty, empty) == 0);
17+
static_assert(containers::lexicographical_compare(empty, empty) == 0);
1818
static_assert(containers::equal(empty, empty));
1919

2020
constexpr auto one_one = containers::array({1});
2121
constexpr auto one_two = containers::array({2});
2222

23-
static_assert(containers::lexicographical_compare_3way(empty, one_one) < 0);
24-
static_assert(containers::lexicographical_compare_3way(one_one, empty) > 0);
23+
static_assert(containers::lexicographical_compare(empty, one_one) < 0);
24+
static_assert(containers::lexicographical_compare(one_one, empty) > 0);
2525
static_assert(!containers::equal(empty, one_one));
2626
static_assert(!containers::equal(one_one, empty));
2727

28-
static_assert(containers::lexicographical_compare_3way(one_one, one_two) < 0);
29-
static_assert(containers::lexicographical_compare_3way(one_two, one_one) > 0);
28+
static_assert(containers::lexicographical_compare(one_one, one_two) < 0);
29+
static_assert(containers::lexicographical_compare(one_two, one_one) > 0);
3030
static_assert(!containers::equal(one_one, one_two));
3131
static_assert(!containers::equal(one_two, one_one));
3232

@@ -36,23 +36,23 @@ static_assert(containers::equal(one_two, one_two));
3636
constexpr auto two_forward = containers::array({1, 2});
3737
constexpr auto two_reversed = containers::array({2, 1});
3838

39-
static_assert(containers::lexicographical_compare_3way(empty, two_forward) < 0);
40-
static_assert(containers::lexicographical_compare_3way(two_forward, empty) > 0);
39+
static_assert(containers::lexicographical_compare(empty, two_forward) < 0);
40+
static_assert(containers::lexicographical_compare(two_forward, empty) > 0);
4141
static_assert(!containers::equal(empty, two_forward));
4242
static_assert(!containers::equal(two_forward, empty));
4343

44-
static_assert(containers::lexicographical_compare_3way(one_one, two_forward) < 0);
45-
static_assert(containers::lexicographical_compare_3way(two_forward, one_one) > 0);
44+
static_assert(containers::lexicographical_compare(one_one, two_forward) < 0);
45+
static_assert(containers::lexicographical_compare(two_forward, one_one) > 0);
4646
static_assert(!containers::equal(one_one, two_forward));
4747
static_assert(!containers::equal(two_forward, one_one));
4848

49-
static_assert(containers::lexicographical_compare_3way(one_two, two_forward) > 0);
50-
static_assert(containers::lexicographical_compare_3way(two_forward, one_two) < 0);
49+
static_assert(containers::lexicographical_compare(one_two, two_forward) > 0);
50+
static_assert(containers::lexicographical_compare(two_forward, one_two) < 0);
5151
static_assert(!containers::equal(one_two, two_forward));
5252
static_assert(!containers::equal(two_forward, one_two));
5353

54-
static_assert(containers::lexicographical_compare_3way(two_forward, two_reversed) < 0);
55-
static_assert(containers::lexicographical_compare_3way(two_reversed, two_forward) > 0);
54+
static_assert(containers::lexicographical_compare(two_forward, two_reversed) < 0);
55+
static_assert(containers::lexicographical_compare(two_reversed, two_forward) > 0);
5656
static_assert(!containers::equal(two_forward, two_reversed));
5757
static_assert(!containers::equal(two_reversed, two_forward));
5858

@@ -62,28 +62,28 @@ static_assert(containers::equal(two_reversed, two_reversed));
6262
constexpr auto nine = containers::array({1, 2, 3, 4, 5, 6, 7, 8, 9});
6363
constexpr auto ten = containers::array({1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
6464

65-
static_assert(containers::lexicographical_compare_3way(empty, nine) < 0);
66-
static_assert(containers::lexicographical_compare_3way(nine, empty) > 0);
65+
static_assert(containers::lexicographical_compare(empty, nine) < 0);
66+
static_assert(containers::lexicographical_compare(nine, empty) > 0);
6767
static_assert(!containers::equal(empty, nine));
6868
static_assert(!containers::equal(nine, empty));
6969

70-
static_assert(containers::lexicographical_compare_3way(one_one, nine) < 0);
71-
static_assert(containers::lexicographical_compare_3way(nine, one_one) > 0);
70+
static_assert(containers::lexicographical_compare(one_one, nine) < 0);
71+
static_assert(containers::lexicographical_compare(nine, one_one) > 0);
7272
static_assert(!containers::equal(one_one, nine));
7373
static_assert(!containers::equal(nine, one_one));
7474

75-
static_assert(containers::lexicographical_compare_3way(one_two, nine) > 0);
76-
static_assert(containers::lexicographical_compare_3way(nine, one_two) < 0);
75+
static_assert(containers::lexicographical_compare(one_two, nine) > 0);
76+
static_assert(containers::lexicographical_compare(nine, one_two) < 0);
7777
static_assert(!containers::equal(one_two, nine));
7878
static_assert(!containers::equal(nine, one_two));
7979

80-
static_assert(containers::lexicographical_compare_3way(nine, two_reversed) < 0);
81-
static_assert(containers::lexicographical_compare_3way(two_reversed, nine) > 0);
80+
static_assert(containers::lexicographical_compare(nine, two_reversed) < 0);
81+
static_assert(containers::lexicographical_compare(two_reversed, nine) > 0);
8282
static_assert(!containers::equal(nine, two_reversed));
8383
static_assert(!containers::equal(two_reversed, nine));
8484

85-
static_assert(containers::lexicographical_compare_3way(nine, ten) < 0);
86-
static_assert(containers::lexicographical_compare_3way(ten, nine) > 0);
85+
static_assert(containers::lexicographical_compare(nine, ten) < 0);
86+
static_assert(containers::lexicographical_compare(ten, nine) > 0);
8787
static_assert(!containers::equal(nine, ten));
8888
static_assert(!containers::equal(ten, nine));
8989

0 commit comments

Comments
 (0)