[API CHANGE] rtl/string: Add startsWith/endsWith for a single character
A lot of places in the code are calling OUString::endsWith with a string containing a single character. Similar to lastIndexOf, this patch provides overloads to the two methods to have an optimised version for the case when there is only one character. It would be kind of nice if the compiler could handle this optimisation itself, but it’s unlikely to work because the string version of endsWith ends up calling rtl_ustr_shortenedCompare_WithLength which isn’t inline and is defined outside of a header. The main incentive to do this is to make it easier to change calls to lastIndexOf that should really be endsWith, as in tdf#171853. Change-Id: Iaba5a7db3211eb12b0a83f441c0a81e664da6eea Reviewed-on: https://gerrit.libreoffice.org/c/core/+/204363 Reviewed-by: Neil Roberts <nroberts@libreoffice.org> Tested-by: Jenkins
This commit is contained in:
@@ -1221,6 +1221,66 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Check whether this string starts with a given character.
|
||||
|
||||
@param ch the character to be compared
|
||||
|
||||
@return true if and only if the given character appears at the start of this string
|
||||
|
||||
@since LibreOffice 26.8
|
||||
*/
|
||||
bool startsWith(char ch) const
|
||||
{
|
||||
return !isEmpty() && pData->buffer[0] == ch;
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether this string starts with a given character.
|
||||
|
||||
@param str the character to be compared
|
||||
|
||||
@param rest if this function returns true, then assign a
|
||||
copy of the remainder of this string to *rest.
|
||||
|
||||
@return true if and only if the given character appears at the start of this string
|
||||
|
||||
@since LibreOffice 26.8
|
||||
*/
|
||||
bool startsWith(char ch, OString* rest) const {
|
||||
assert(rest);
|
||||
bool b = startsWith(ch);
|
||||
|
||||
if (b)
|
||||
*rest = copy(1);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
#if defined LIBO_INTERNAL_ONLY
|
||||
/**
|
||||
Check whether this string starts with a given character.
|
||||
|
||||
@param str the character to be compared
|
||||
|
||||
@param rest if this function returns true, then assign a
|
||||
copy of the remainder of this string to *rest.
|
||||
|
||||
@return true if and only if the given character appears at the start of this string
|
||||
|
||||
@since LibreOffice 26.8
|
||||
*/
|
||||
bool startsWith(char ch, std::string_view* rest) const {
|
||||
assert(rest);
|
||||
bool b = startsWith(ch);
|
||||
|
||||
if (b)
|
||||
*rest = subView(1);
|
||||
|
||||
return b;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined LIBO_INTERNAL_ONLY
|
||||
/**
|
||||
Check whether this string starts with a given string, ignoring the case of
|
||||
@@ -1595,6 +1655,66 @@ public:
|
||||
&& matchL(str, strLength, getLength() - strLength);
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether this string ends with a given character.
|
||||
|
||||
@param ch the character to be compared
|
||||
|
||||
@return true if and only if the given character appears at the end of this string
|
||||
|
||||
@since LibreOffice 26.8
|
||||
*/
|
||||
bool endsWith(char ch) const
|
||||
{
|
||||
return !isEmpty() && pData->buffer[pData->length - 1] == ch;
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether this string ends with a given character.
|
||||
|
||||
@param str the character to be compared
|
||||
|
||||
@param rest if this function returns true, then assign a
|
||||
copy of the remainder of this string to *rest.
|
||||
|
||||
@return true if and only if the given character appears at the end of this string
|
||||
|
||||
@since LibreOffice 26.8
|
||||
*/
|
||||
bool endsWith(char ch, OString* rest) const {
|
||||
assert(rest);
|
||||
bool b = endsWith(ch);
|
||||
|
||||
if (b)
|
||||
*rest = copy(0, pData->length - 1);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
#if defined LIBO_INTERNAL_ONLY
|
||||
/**
|
||||
Check whether this string ends with a given character.
|
||||
|
||||
@param str the character to be compared
|
||||
|
||||
@param rest if this function returns true, then assign a
|
||||
copy of the remainder of this string to *rest.
|
||||
|
||||
@return true if and only if the given character appears at the end of this string
|
||||
|
||||
@since LibreOffice 26.8
|
||||
*/
|
||||
bool endsWith(char ch, std::string_view* rest) const {
|
||||
assert(rest);
|
||||
bool b = endsWith(ch);
|
||||
|
||||
if (b)
|
||||
*rest = subView(0, pData->length - 1);
|
||||
|
||||
return b;
|
||||
}
|
||||
#endif
|
||||
|
||||
friend bool operator == ( const OString& rStr1, const OString& rStr2 )
|
||||
{ return rStr1.equals(rStr2); }
|
||||
friend bool operator != ( const OString& rStr1, const OString& rStr2 )
|
||||
|
||||
@@ -1618,6 +1618,66 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Check whether this string starts with a given character.
|
||||
|
||||
@param str the character to be compared
|
||||
|
||||
@return true if and only if the given character appears at the start of this string
|
||||
|
||||
@since LibreOffice 26.8
|
||||
*/
|
||||
bool startsWith(sal_Unicode ch) const
|
||||
{
|
||||
return !isEmpty() && pData->buffer[0] == ch;
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether this string starts with a given character.
|
||||
|
||||
@param str the character to be compared
|
||||
|
||||
@param rest if this function returns true, then assign a
|
||||
copy of the remainder of this string to *rest.
|
||||
|
||||
@return true if and only if the given character appears at the start of this string
|
||||
|
||||
@since LibreOffice 26.8
|
||||
*/
|
||||
bool startsWith(sal_Unicode ch, OUString* rest) const {
|
||||
assert(rest);
|
||||
bool b = startsWith(ch);
|
||||
|
||||
if (b)
|
||||
*rest = copy(1);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
#if defined LIBO_INTERNAL_ONLY
|
||||
/**
|
||||
Check whether this string starts with a given character.
|
||||
|
||||
@param str the character to be compared
|
||||
|
||||
@param rest if this function returns true, then assign a
|
||||
copy of the remainder of this string to *rest.
|
||||
|
||||
@return true if and only if the given character appears at the start of this string
|
||||
|
||||
@since LibreOffice 26.8
|
||||
*/
|
||||
bool startsWith(sal_Unicode ch, std::u16string_view* rest) const {
|
||||
assert(rest);
|
||||
bool b = startsWith(ch);
|
||||
|
||||
if (b)
|
||||
*rest = subView(1);
|
||||
|
||||
return b;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Check whether this string starts with a given string, ignoring the case of
|
||||
ASCII letters.
|
||||
@@ -1825,6 +1885,66 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Check whether this string ends with a given character.
|
||||
|
||||
@param str the character to be compared
|
||||
|
||||
@return true if and only if the given character appears at the end of this string
|
||||
|
||||
@since LibreOffice 26.8
|
||||
*/
|
||||
bool endsWith(sal_Unicode ch) const
|
||||
{
|
||||
return !isEmpty() && pData->buffer[pData->length - 1] == ch;
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether this string ends with a given character.
|
||||
|
||||
@param str the character to be compared
|
||||
|
||||
@param rest if this function returns true, then assign a
|
||||
copy of the remainder of this string to *rest.
|
||||
|
||||
@return true if and only if the given character appears at the end of this string
|
||||
|
||||
@since LibreOffice 26.8
|
||||
*/
|
||||
bool endsWith(sal_Unicode ch, OUString* rest) const {
|
||||
assert(rest);
|
||||
bool b = endsWith(ch);
|
||||
|
||||
if (b)
|
||||
*rest = copy(0, pData->length - 1);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
#if defined LIBO_INTERNAL_ONLY
|
||||
/**
|
||||
Check whether this string ends with a given character.
|
||||
|
||||
@param str the character to be compared
|
||||
|
||||
@param rest if this function returns true, then assign a
|
||||
copy of the remainder of this string to *rest.
|
||||
|
||||
@return true if and only if the given character appears at the end of this string
|
||||
|
||||
@since LibreOffice 26.8
|
||||
*/
|
||||
bool endsWith(sal_Unicode ch, std::u16string_view* rest) const {
|
||||
assert(rest);
|
||||
bool b = endsWith(ch);
|
||||
|
||||
if (b)
|
||||
*rest = subView(0, pData->length - 1);
|
||||
|
||||
return b;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined LIBO_INTERNAL_ONLY
|
||||
/**
|
||||
@overload
|
||||
|
||||
@@ -21,11 +21,15 @@ private:
|
||||
void testStartsWithIgnoreAsciiCase();
|
||||
void testCompareTo();
|
||||
void testUtf8StringLiterals();
|
||||
void testStartsWithChar();
|
||||
void testEndsWithChar();
|
||||
|
||||
CPPUNIT_TEST_SUITE(Test);
|
||||
CPPUNIT_TEST(testStartsWithIgnoreAsciiCase);
|
||||
CPPUNIT_TEST(testCompareTo);
|
||||
CPPUNIT_TEST(testUtf8StringLiterals);
|
||||
CPPUNIT_TEST(testStartsWithChar);
|
||||
CPPUNIT_TEST(testEndsWithChar);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
};
|
||||
|
||||
@@ -116,6 +120,72 @@ void Test::testUtf8StringLiterals()
|
||||
CPPUNIT_ASSERT_EQUAL(97, int(static_cast<unsigned char>(sIn[2])));
|
||||
}
|
||||
|
||||
void Test::testStartsWithChar()
|
||||
{
|
||||
CPPUNIT_ASSERT(!""_ostr.startsWith('.'));
|
||||
CPPUNIT_ASSERT("."_ostr.startsWith('.'));
|
||||
CPPUNIT_ASSERT(".foo"_ostr.startsWith('.'));
|
||||
CPPUNIT_ASSERT(!"."_ostr.startsWith('?'));
|
||||
CPPUNIT_ASSERT(!".foo"_ostr.startsWith('?'));
|
||||
|
||||
{
|
||||
OString rest = "not_changed"_ostr;
|
||||
CPPUNIT_ASSERT(!"foo"_ostr.startsWith('p', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL("not_changed"_ostr, rest);
|
||||
}
|
||||
|
||||
{
|
||||
OString rest = "must_change"_ostr;
|
||||
CPPUNIT_ASSERT("/removed_slash"_ostr.startsWith('/', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL("removed_slash"_ostr, rest);
|
||||
}
|
||||
|
||||
{
|
||||
std::string_view rest = "not_changed";
|
||||
CPPUNIT_ASSERT(!"foo"_ostr.startsWith('p', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL("not_changed"_ostr, OString(rest));
|
||||
}
|
||||
|
||||
{
|
||||
std::string_view rest = "must_change";
|
||||
CPPUNIT_ASSERT("/removed_slash"_ostr.startsWith('/', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL("removed_slash"_ostr, OString(rest));
|
||||
}
|
||||
}
|
||||
|
||||
void Test::testEndsWithChar()
|
||||
{
|
||||
CPPUNIT_ASSERT(!""_ostr.endsWith('.'));
|
||||
CPPUNIT_ASSERT("."_ostr.endsWith('.'));
|
||||
CPPUNIT_ASSERT("foo."_ostr.endsWith('.'));
|
||||
CPPUNIT_ASSERT(!"."_ostr.endsWith('?'));
|
||||
CPPUNIT_ASSERT(!"foo."_ostr.endsWith('?'));
|
||||
|
||||
{
|
||||
OString rest = "not_changed"_ostr;
|
||||
CPPUNIT_ASSERT(!"foo"_ostr.endsWith('p', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL("not_changed"_ostr, rest);
|
||||
}
|
||||
|
||||
{
|
||||
OString rest = "must_change"_ostr;
|
||||
CPPUNIT_ASSERT("removed_slash/"_ostr.endsWith('/', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL("removed_slash"_ostr, rest);
|
||||
}
|
||||
|
||||
{
|
||||
std::string_view rest = "not_changed";
|
||||
CPPUNIT_ASSERT(!"foo"_ostr.endsWith('p', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL("not_changed"_ostr, OString(rest));
|
||||
}
|
||||
|
||||
{
|
||||
std::string_view rest = "must_change";
|
||||
CPPUNIT_ASSERT("removed_slash/"_ostr.endsWith('/', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL("removed_slash"_ostr, OString(rest));
|
||||
}
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(Test);
|
||||
|
||||
}
|
||||
|
||||
@@ -33,9 +33,11 @@ class EndsWith: public CppUnit::TestFixture
|
||||
{
|
||||
private:
|
||||
void endsWith();
|
||||
void endsWithChar();
|
||||
|
||||
CPPUNIT_TEST_SUITE(EndsWith);
|
||||
CPPUNIT_TEST(endsWith);
|
||||
CPPUNIT_TEST(endsWithChar);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
};
|
||||
|
||||
@@ -107,4 +109,39 @@ void test::oustring::EndsWith::endsWith()
|
||||
}
|
||||
}
|
||||
|
||||
void test::oustring::EndsWith::endsWithChar()
|
||||
{
|
||||
CPPUNIT_ASSERT(!u""_ustr.endsWith('.'));
|
||||
CPPUNIT_ASSERT(u"."_ustr.endsWith('.'));
|
||||
CPPUNIT_ASSERT(u"foo."_ustr.endsWith('.'));
|
||||
CPPUNIT_ASSERT(u"aĥ"_ustr.endsWith(u'ĥ'));
|
||||
CPPUNIT_ASSERT(!u"."_ustr.endsWith('?'));
|
||||
CPPUNIT_ASSERT(!u"foo."_ustr.endsWith('?'));
|
||||
CPPUNIT_ASSERT(!u"aĥ"_ustr.endsWith(u'ĉ'));
|
||||
|
||||
{
|
||||
OUString rest = u"not_changed"_ustr;
|
||||
CPPUNIT_ASSERT(!u"foo"_ustr.endsWith('p', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL(u"not_changed"_ustr, rest);
|
||||
}
|
||||
|
||||
{
|
||||
OUString rest = u"must_change"_ustr;
|
||||
CPPUNIT_ASSERT(u"removed_slash/"_ustr.endsWith('/', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL(u"removed_slash"_ustr, rest);
|
||||
}
|
||||
|
||||
{
|
||||
std::u16string_view rest = u"not_changed";
|
||||
CPPUNIT_ASSERT(!u"foo"_ustr.endsWith('p', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL(u"not_changed"_ustr, OUString(rest));
|
||||
}
|
||||
|
||||
{
|
||||
std::u16string_view rest = u"must_change";
|
||||
CPPUNIT_ASSERT(u"removed_slash/"_ustr.endsWith('/', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL(u"removed_slash"_ustr, OUString(rest));
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -17,9 +17,11 @@ class StartsWith: public CppUnit::TestFixture
|
||||
{
|
||||
private:
|
||||
void startsWith();
|
||||
void startsWithChar();
|
||||
|
||||
CPPUNIT_TEST_SUITE(StartsWith);
|
||||
CPPUNIT_TEST(startsWith);
|
||||
CPPUNIT_TEST(startsWithChar);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
};
|
||||
|
||||
@@ -34,4 +36,39 @@ void test::oustring::StartsWith::startsWith()
|
||||
CPPUNIT_ASSERT( !u"foobar"_ustr.startsWith( "oo" ));
|
||||
}
|
||||
|
||||
void test::oustring::StartsWith::startsWithChar()
|
||||
{
|
||||
CPPUNIT_ASSERT(!u""_ustr.startsWith('.'));
|
||||
CPPUNIT_ASSERT(u"."_ustr.startsWith('.'));
|
||||
CPPUNIT_ASSERT(u".foo"_ustr.startsWith('.'));
|
||||
CPPUNIT_ASSERT(u"ĉu?"_ustr.startsWith(u'ĉ'));
|
||||
CPPUNIT_ASSERT(!u"."_ustr.startsWith('?'));
|
||||
CPPUNIT_ASSERT(!u".foo"_ustr.startsWith('?'));
|
||||
CPPUNIT_ASSERT(!u"ĉu?"_ustr.startsWith(u'ĥ'));
|
||||
|
||||
{
|
||||
OUString rest = u"not_changed"_ustr;
|
||||
CPPUNIT_ASSERT(!u"foo"_ustr.startsWith('p', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL(u"not_changed"_ustr, rest);
|
||||
}
|
||||
|
||||
{
|
||||
OUString rest = u"must_change"_ustr;
|
||||
CPPUNIT_ASSERT(u"/removed_slash"_ustr.startsWith('/', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL(u"removed_slash"_ustr, rest);
|
||||
}
|
||||
|
||||
{
|
||||
std::u16string_view rest = u"not_changed";
|
||||
CPPUNIT_ASSERT(!u"foo"_ustr.startsWith('p', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL(u"not_changed"_ustr, OUString(rest));
|
||||
}
|
||||
|
||||
{
|
||||
std::u16string_view rest = u"must_change";
|
||||
CPPUNIT_ASSERT(u"/removed_slash"_ustr.startsWith('/', &rest));
|
||||
CPPUNIT_ASSERT_EQUAL(u"removed_slash"_ustr, OUString(rest));
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
Reference in New Issue
Block a user