From: Phil Willoughby Date: Wed, 19 Apr 2017 12:34:26 +0000 (-0700) Subject: Improve string comparisons X-Git-Tag: v2017.04.24.00~8 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=5a122efcd603512292bd09b541c212773d2b7d55;p=folly.git Improve string comparisons Summary: Any pair of read-compatible (same type, same traits) basic_strings (`basic_fbstring` or `std::basic_string`) can now be compared to each other with the `==`, `!=`, `<`, `>`, `<=`, and `>=` operators. If you have a C++14 environment this allows you to use the heterogeneous comparison lookup methods from N3657: you can query containers which store either string type with either string type efficiently. Reviewed By: yfeldblum, ot Differential Revision: D4905697 fbshipit-source-id: 2ea976ebf40af45d64c1d8c1c08847feb3b9db68 --- diff --git a/folly/FBString.h b/folly/FBString.h index 45791e3f..91b1ab68 100644 --- a/folly/FBString.h +++ b/folly/FBString.h @@ -2725,34 +2725,90 @@ constexpr typename basic_fbstring::size_type #ifndef _LIBSTDCXX_FBSTRING // basic_string compatibility routines -template -inline -bool operator==(const basic_fbstring& lhs, - const std::string& rhs) { +template +inline bool operator==( + const basic_fbstring& lhs, + const std::basic_string& rhs) { return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) == 0; } -template -inline -bool operator==(const std::string& lhs, - const basic_fbstring& rhs) { +template +inline bool operator==( + const std::basic_string& lhs, + const basic_fbstring& rhs) { return rhs == lhs; } -template -inline -bool operator!=(const basic_fbstring& lhs, - const std::string& rhs) { +template +inline bool operator!=( + const basic_fbstring& lhs, + const std::basic_string& rhs) { return !(lhs == rhs); } -template -inline -bool operator!=(const std::string& lhs, - const basic_fbstring& rhs) { +template +inline bool operator!=( + const std::basic_string& lhs, + const basic_fbstring& rhs) { return !(lhs == rhs); } +template +inline bool operator<( + const basic_fbstring& lhs, + const std::basic_string& rhs) { + return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) < 0; +} + +template +inline bool operator>( + const basic_fbstring& lhs, + const std::basic_string& rhs) { + return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) > 0; +} + +template +inline bool operator<( + const std::basic_string& lhs, + const basic_fbstring& rhs) { + return rhs > lhs; +} + +template +inline bool operator>( + const std::basic_string& lhs, + const basic_fbstring& rhs) { + return rhs < lhs; +} + +template +inline bool operator<=( + const basic_fbstring& lhs, + const std::basic_string& rhs) { + return !(lhs > rhs); +} + +template +inline bool operator>=( + const basic_fbstring& lhs, + const std::basic_string& rhs) { + return !(lhs < rhs); +} + +template +inline bool operator<=( + const std::basic_string& lhs, + const basic_fbstring& rhs) { + return !(lhs > rhs); +} + +template +inline bool operator>=( + const std::basic_string& lhs, + const basic_fbstring& rhs) { + return !(lhs < rhs); +} + #if !defined(_LIBSTDCXX_FBSTRING) typedef basic_fbstring fbstring; #endif diff --git a/folly/test/FBStringTest.cpp b/folly/test/FBStringTest.cpp index e65f8049..518aa16c 100644 --- a/folly/test/FBStringTest.cpp +++ b/folly/test/FBStringTest.cpp @@ -1438,3 +1438,210 @@ TEST(FBStringCtorTest, NullZeroConstruction) { folly::fbstring f(p, n); EXPECT_EQ(f.size(), 0); } + +// Tests for the comparison operators. I use EXPECT_TRUE rather than EXPECT_LE +// because what's under test is the operator rather than the relation between +// the objects. + +TEST(FBString, compareToStdString) { + using folly::fbstring; + using namespace std::string_literals; + auto stdA = "a"s; + auto stdB = "b"s; + fbstring fbA("a"); + fbstring fbB("b"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +TEST(U16FBString, compareToStdU16String) { + using folly::basic_fbstring; + using namespace std::string_literals; + auto stdA = u"a"s; + auto stdB = u"b"s; + basic_fbstring fbA(u"a"); + basic_fbstring fbB(u"b"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +TEST(U32FBString, compareToStdU32String) { + using folly::basic_fbstring; + using namespace std::string_literals; + auto stdA = U"a"s; + auto stdB = U"b"s; + basic_fbstring fbA(U"a"); + basic_fbstring fbB(U"b"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +TEST(WFBString, compareToStdWString) { + using folly::basic_fbstring; + using namespace std::string_literals; + auto stdA = L"a"s; + auto stdB = L"b"s; + basic_fbstring fbA(L"a"); + basic_fbstring fbB(L"b"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +// Same again, but with a more challenging input - a common prefix and different +// lengths. + +TEST(FBString, compareToStdStringLong) { + using folly::fbstring; + using namespace std::string_literals; + auto stdA = "1234567890a"s; + auto stdB = "1234567890ab"s; + fbstring fbA("1234567890a"); + fbstring fbB("1234567890ab"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +TEST(U16FBString, compareToStdU16StringLong) { + using folly::basic_fbstring; + using namespace std::string_literals; + auto stdA = u"1234567890a"s; + auto stdB = u"1234567890ab"s; + basic_fbstring fbA(u"1234567890a"); + basic_fbstring fbB(u"1234567890ab"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +TEST(U32FBString, compareToStdU32StringLong) { + using folly::basic_fbstring; + using namespace std::string_literals; + auto stdA = U"1234567890a"s; + auto stdB = U"1234567890ab"s; + basic_fbstring fbA(U"1234567890a"); + basic_fbstring fbB(U"1234567890ab"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +TEST(WFBString, compareToStdWStringLong) { + using folly::basic_fbstring; + using namespace std::string_literals; + auto stdA = L"1234567890a"s; + auto stdB = L"1234567890ab"s; + basic_fbstring fbA(L"1234567890a"); + basic_fbstring fbB(L"1234567890ab"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +}