Skip to content

Commit 861e476

Browse files
authored
Merge pull request #531 from dtolnay/cmp
Add comparison operators for Str and String
2 parents 028d3d2 + 2ecd4fd commit 861e476

File tree

5 files changed

+106
-0
lines changed

5 files changed

+106
-0
lines changed

book/src/binding/str.md

+7
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ public:
3737
const_iterator end() const noexcept;
3838
const_iterator cbegin() const noexcept;
3939
const_iterator cend() const noexcept;
40+
41+
bool operator==(const Str &) const noexcept;
42+
bool operator!=(const Str &) const noexcept;
43+
bool operator<(const Str &) const noexcept;
44+
bool operator<=(const Str &) const noexcept;
45+
bool operator>(const Str &) const noexcept;
46+
bool operator>=(const Str &) const noexcept;
4047
};
4148
4249
std::ostream &operator<<(std::ostream &, const Str &);

book/src/binding/string.md

+7
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ public:
4242
const_iterator end() const noexcept;
4343
const_iterator cbegin() const noexcept;
4444
const_iterator cend() const noexcept;
45+
46+
bool operator==(const String &) const noexcept;
47+
bool operator!=(const String &) const noexcept;
48+
bool operator<(const String &) const noexcept;
49+
bool operator<=(const String &) const noexcept;
50+
bool operator>(const String &) const noexcept;
51+
bool operator>=(const String &) const noexcept;
4552
};
4653
4754
std::ostream &operator<<(std::ostream &, const String &);

include/cxx.h

+14
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ class String final {
5959
const_iterator cbegin() const noexcept;
6060
const_iterator cend() const noexcept;
6161

62+
bool operator==(const String &) const noexcept;
63+
bool operator!=(const String &) const noexcept;
64+
bool operator<(const String &) const noexcept;
65+
bool operator<=(const String &) const noexcept;
66+
bool operator>(const String &) const noexcept;
67+
bool operator>=(const String &) const noexcept;
68+
6269
// Internal API only intended for the cxxbridge code generator.
6370
String(unsafe_bitcopy_t, const String &) noexcept;
6471

@@ -98,6 +105,13 @@ class Str final {
98105
const_iterator cbegin() const noexcept;
99106
const_iterator cend() const noexcept;
100107

108+
bool operator==(const Str &) const noexcept;
109+
bool operator!=(const Str &) const noexcept;
110+
bool operator<(const Str &) const noexcept;
111+
bool operator<=(const Str &) const noexcept;
112+
bool operator>(const Str &) const noexcept;
113+
bool operator>=(const Str &) const noexcept;
114+
101115
private:
102116
friend impl<Str>;
103117
// Not necessarily ABI compatible with &str. Codegen will translate to

src/cxx.cc

+58
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "../include/cxx.h"
2+
#include <algorithm>
23
#include <cassert>
34
#include <cstring>
45
#include <exception>
@@ -140,6 +141,30 @@ String::const_iterator String::cend() const noexcept {
140141
return this->data() + this->size();
141142
}
142143

144+
bool String::operator==(const String &rhs) const noexcept {
145+
return rust::Str(*this) == rust::Str(rhs);
146+
}
147+
148+
bool String::operator!=(const String &rhs) const noexcept {
149+
return rust::Str(*this) != rust::Str(rhs);
150+
}
151+
152+
bool String::operator<(const String &rhs) const noexcept {
153+
return rust::Str(*this) < rust::Str(rhs);
154+
}
155+
156+
bool String::operator<=(const String &rhs) const noexcept {
157+
return rust::Str(*this) <= rust::Str(rhs);
158+
}
159+
160+
bool String::operator>(const String &rhs) const noexcept {
161+
return rust::Str(*this) > rust::Str(rhs);
162+
}
163+
164+
bool String::operator>=(const String &rhs) const noexcept {
165+
return rust::Str(*this) >= rust::Str(rhs);
166+
}
167+
143168
String::String(unsafe_bitcopy_t, const String &bits) noexcept
144169
: repr(bits.repr) {}
145170

@@ -186,6 +211,39 @@ Str::const_iterator Str::cbegin() const noexcept { return this->ptr; }
186211

187212
Str::const_iterator Str::cend() const noexcept { return this->ptr + this->len; }
188213

214+
bool Str::operator==(const Str &rhs) const noexcept {
215+
return this->len == rhs.len &&
216+
std::equal(this->begin(), this->end(), rhs.begin());
217+
}
218+
219+
bool Str::operator!=(const Str &rhs) const noexcept { return !(*this == rhs); }
220+
221+
bool Str::operator<(const Str &rhs) const noexcept {
222+
return std::lexicographical_compare(this->begin(), this->end(), rhs.begin(),
223+
rhs.end());
224+
}
225+
226+
bool Str::operator<=(const Str &rhs) const noexcept {
227+
// std::mismatch(this->begin(), this->end(), rhs.begin(), rhs.end()), except
228+
// without Undefined Behavior on C++11 if rhs is shorter than *this.
229+
const_iterator liter = this->begin(), lend = this->end(), riter = rhs.begin(),
230+
rend = rhs.end();
231+
while (liter != lend && riter != rend && *liter == *riter) {
232+
++liter, ++riter;
233+
}
234+
if (liter == lend) {
235+
return true; // equal or *this is a prefix of rhs
236+
} else if (riter == rend) {
237+
return false; // rhs is a prefix of *this
238+
} else {
239+
return *liter <= *riter;
240+
}
241+
}
242+
243+
bool Str::operator>(const Str &rhs) const noexcept { return rhs < *this; }
244+
245+
bool Str::operator>=(const Str &rhs) const noexcept { return rhs <= *this; }
246+
189247
std::ostream &operator<<(std::ostream &os, const Str &s) {
190248
os.write(s.data(), s.size());
191249
return os;

tests/ffi/tests.cc

+20
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <numeric>
77
#include <stdexcept>
88
#include <string>
9+
#include <tuple>
910

1011
extern "C" void cxx_test_suite_set_correct() noexcept;
1112
extern "C" tests::R *cxx_test_suite_get_box() noexcept;
@@ -656,6 +657,25 @@ extern "C" const char *cxx_run_test() noexcept {
656657
ASSERT(Shared{1} == Shared{1});
657658
ASSERT(Shared{1} != Shared{2});
658659

660+
rust::String first = "first", second = "second", sec = "sec";
661+
bool (rust::String::*cmp)(const rust::String &) const;
662+
bool first_first, first_second, sec_second, second_sec;
663+
for (auto test : {
664+
std::tuple<decltype(cmp), bool, bool, bool, bool>
665+
{&rust::String::operator==, true, false, false, false},
666+
{&rust::String::operator!=, false, true, true, true},
667+
{&rust::String::operator<, false, true, true, false},
668+
{&rust::String::operator<=, true, true, true, false},
669+
{&rust::String::operator>, false, false, false, true},
670+
{&rust::String::operator>=, true, false, false, true},
671+
}) {
672+
std::tie(cmp, first_first, first_second, sec_second, second_sec) = test;
673+
ASSERT((first.*cmp)(first) == first_first);
674+
ASSERT((first.*cmp)(second) == first_second);
675+
ASSERT((sec.*cmp)(second) == sec_second);
676+
ASSERT((second.*cmp)(sec) == second_sec);
677+
}
678+
659679
cxx_test_suite_set_correct();
660680
return nullptr;
661681
}

0 commit comments

Comments
 (0)