ICU-20921 Adding find and compare to StringPiece

This commit is contained in:
Shane Carr 2019-12-11 20:46:08 -08:00 committed by Shane F. Carr
parent a3078fb8c8
commit b24538eb05
4 changed files with 137 additions and 0 deletions

View File

@ -51,6 +51,47 @@ void StringPiece::set(const char* str) {
length_ = 0;
}
int32_t StringPiece::find(StringPiece needle, int32_t offset) {
if (length() == 0 && needle.length() == 0) {
return 0;
}
// TODO: Improve to be better than O(N^2)?
for (int32_t i = offset; i < length(); i++) {
int32_t j = 0;
for (; j < needle.length(); i++, j++) {
if (data()[i] != needle.data()[j]) {
i -= j;
goto outer_end;
}
}
return i - j;
outer_end: void();
}
return -1;
}
int32_t StringPiece::compare(StringPiece other) {
int32_t i = 0;
for (; i < length(); i++) {
if (i == other.length()) {
// this is longer
return 1;
}
char a = data()[i];
char b = other.data()[i];
if (a < b) {
return -1;
} else if (a > b) {
return 1;
}
}
if (i < other.length()) {
// other is longer
return -1;
}
return 0;
}
U_EXPORT UBool U_EXPORT2
operator==(const StringPiece& x, const StringPiece& y) {
int32_t len = x.size();

View File

@ -212,6 +212,26 @@ class U_COMMON_API StringPiece : public UMemory {
}
}
#ifndef U_HIDE_DRAFT_API
/**
* Searches the StringPiece for the given search string (needle);
* @param needle The string for which to search.
* @param offset Where to start searching within this string (haystack).
* @return The offset of needle in haystack, or -1 if not found.
* @draft ICU 67
*/
int32_t find(StringPiece needle, int32_t offset);
/**
* Compares this StringPiece with the other StringPiece, with semantics
* similar to std::string::compare().
* @param other The string to compare to.
* @return below zero if this < other; above zero if this > other; 0 if this == other.
* @draft ICU 67
*/
int32_t compare(StringPiece other);
#endif // U_HIDE_DRAFT_API
/**
* Maximum integer, used as a default value for substring methods.
* @stable ICU 4.2

View File

@ -243,6 +243,7 @@ void StringTest::runIndexedTest(int32_t index, UBool exec, const char *&name, ch
TESTCASE_AUTO(TestSTLCompatibility);
TESTCASE_AUTO(TestStringPiece);
TESTCASE_AUTO(TestStringPieceComparisons);
TESTCASE_AUTO(TestStringPieceFind);
TESTCASE_AUTO(TestStringPieceOther);
#ifdef U_HAVE_STRING_VIEW
TESTCASE_AUTO(TestStringPieceStringView);
@ -407,6 +408,35 @@ StringTest::TestStringPieceComparisons() {
if(abc==abcd) {
errln("abc==abcd");
}
assertTrue("null<abc", null.compare(abc) < 0);
assertTrue("abc>null", abc.compare(null) > 0);
assertTrue("abc<abcd", abc.compare(abcd) < 0);
assertTrue("abcd>abc", abcd.compare(abc) > 0);
assertTrue("abc<abx", abc.compare(abx) < 0);
assertTrue("abx>abc", abx.compare(abc) > 0);
assertTrue("abx>abcd", abx.compare(abcd) > 0);
assertTrue("abcd<abx", abcd.compare(abx) < 0);
assertTrue("abx==abx", abx.compare(abx) == 0);
// Behavior should be the same as std::string::compare
{
std::string null("");
std::string abc("abc");
std::string abcd("abcdefg", 4);
std::string abx("abx");
assertTrue("std: null<abc", null.compare(abc) < 0);
assertTrue("std: abc>null", abc.compare(null) > 0);
assertTrue("std: abc<abcd", abc.compare(abcd) < 0);
assertTrue("std: abcd>abc", abcd.compare(abc) > 0);
assertTrue("std: abc<abx", abc.compare(abx) < 0);
assertTrue("std: abx>abc", abx.compare(abc) > 0);
assertTrue("std: abx>abcd", abx.compare(abcd) > 0);
assertTrue("std: abcd<abx", abcd.compare(abx) < 0);
assertTrue("std: abx==abx", abx.compare(abx) == 0);
}
abcd.remove_suffix(1);
if(abc!=abcd) {
errln("abc!=abcd.remove_suffix(1)");
@ -416,6 +446,51 @@ StringTest::TestStringPieceComparisons() {
}
}
void
StringTest::TestStringPieceFind() {
struct TestCase {
const char* haystack;
const char* needle;
int32_t expected;
} cases[] = {
{ "", "", 0 },
{ "", "x", -1 },
{ "x", "", 0 },
{ "x", "x", 0 },
{ "xy", "x", 0 },
{ "xy", "y", 1 },
{ "xy", "xy", 0 },
{ "xy", "xyz", -1 },
{ "qwerty", "qqw", -1 },
{ "qwerty", "qw", 0 },
{ "qwerty", "er", 2 },
{ "qwerty", "err", -1 },
{ "qwerty", "ert", 2 },
{ "qwerty", "ty", 4 },
{ "qwerty", "tyy", -1 },
{ "qwerty", "a", -1 },
{ "qwerty", "abc", -1 }
};
int32_t caseNumber = 0;
for (auto& cas : cases) {
StringPiece haystack(cas.haystack);
StringPiece needle(cas.needle);
assertEquals(Int64ToUnicodeString(caseNumber),
cas.expected, haystack.find(needle, 0));
// Should be same as std::string::find
std::string stdhaystack(cas.haystack);
std::string stdneedle(cas.needle);
assertEquals(Int64ToUnicodeString(caseNumber) + u" (std)",
cas.expected, stdhaystack.find(stdneedle, 0));
// Test offsets against std::string::find
for (int32_t offset = 0; offset < haystack.length(); offset++) {
assertEquals(Int64ToUnicodeString(caseNumber) + "u @ " + Int64ToUnicodeString(offset),
stdhaystack.find(stdneedle, offset), haystack.find(needle, offset));
}
caseNumber++;
}
}
void
StringTest::TestStringPieceOther() {
static constexpr char msg[] = "Kapow!";

View File

@ -43,6 +43,7 @@ private:
void TestLowerOrdinal();
void Test_UTF8_COUNT_TRAIL_BYTES();
void TestStringPiece();
void TestStringPieceFind();
void TestStringPieceComparisons();
void TestStringPieceOther();
#ifdef U_HAVE_STRING_VIEW