diff --git a/Source/Engine/Core/Types/String.cpp b/Source/Engine/Core/Types/String.cpp
index 7919d513d..2ea3c7dc5 100644
--- a/Source/Engine/Core/Types/String.cpp
+++ b/Source/Engine/Core/Types/String.cpp
@@ -226,7 +226,9 @@ bool String::IsANSI() const
bool String::StartsWith(const StringView& prefix, StringSearchCase searchCase) const
{
- if (prefix.IsEmpty() || prefix.Length() > Length())
+ if (prefix.IsEmpty())
+ return true;
+ if (prefix.Length() > Length())
return false;
if (searchCase == StringSearchCase::IgnoreCase)
return !StringUtils::CompareIgnoreCase(this->GetText(), *prefix, prefix.Length());
@@ -235,7 +237,9 @@ bool String::StartsWith(const StringView& prefix, StringSearchCase searchCase) c
bool String::EndsWith(const StringView& suffix, StringSearchCase searchCase) const
{
- if (suffix.IsEmpty() || suffix.Length() > Length())
+ if (suffix.IsEmpty())
+ return true;
+ if (suffix.Length() > Length())
return false;
if (searchCase == StringSearchCase::IgnoreCase)
return !StringUtils::CompareIgnoreCase(&(*this)[Length() - suffix.Length()], *suffix);
diff --git a/Source/Engine/Core/Types/String.h b/Source/Engine/Core/Types/String.h
index 0a62c516f..3485a1093 100644
--- a/Source/Engine/Core/Types/String.h
+++ b/Source/Engine/Core/Types/String.h
@@ -65,10 +65,11 @@ public:
///
/// Lexicographically tests how this string compares to the other given string.
+ /// In case sensitive mode 'A' is less than 'a'.
///
/// The another string test against.
/// The case sensitivity mode.
- /// 0 if equal, -1 if less than, 1 if greater than.
+ /// 0 if equal, negative number if less than, positive number if greater than.
int32 Compare(const StringBase& str, StringSearchCase searchCase = StringSearchCase::CaseSensitive) const
{
if (searchCase == StringSearchCase::CaseSensitive)
@@ -352,7 +353,7 @@ public:
bool StartsWith(T c, StringSearchCase searchCase = StringSearchCase::CaseSensitive) const
{
const int32 length = Length();
- if (searchCase == StringSearchCase::IgnoreCase)
+ if (searchCase == StringSearchCase::CaseSensitive)
return length > 0 && _data[0] == c;
return length > 0 && StringUtils::ToLower(_data[0]) == StringUtils::ToLower(c);
}
@@ -360,14 +361,16 @@ public:
bool EndsWith(T c, StringSearchCase searchCase = StringSearchCase::CaseSensitive) const
{
const int32 length = Length();
- if (searchCase == StringSearchCase::IgnoreCase)
+ if (searchCase == StringSearchCase::CaseSensitive)
return length > 0 && _data[length - 1] == c;
return length > 0 && StringUtils::ToLower(_data[length - 1]) == StringUtils::ToLower(c);
}
bool StartsWith(const StringBase& prefix, StringSearchCase searchCase = StringSearchCase::CaseSensitive) const
{
- if (prefix.IsEmpty() || Length() < prefix.Length())
+ if (prefix.IsEmpty())
+ return true;
+ if (Length() < prefix.Length())
return false;
if (searchCase == StringSearchCase::IgnoreCase)
return StringUtils::CompareIgnoreCase(this->GetText(), *prefix, prefix.Length()) == 0;
@@ -376,7 +379,9 @@ public:
bool EndsWith(const StringBase& suffix, StringSearchCase searchCase = StringSearchCase::CaseSensitive) const
{
- if (suffix.IsEmpty() || Length() < suffix.Length())
+ if (suffix.IsEmpty())
+ return true;
+ if (Length() < suffix.Length())
return false;
if (searchCase == StringSearchCase::IgnoreCase)
return StringUtils::CompareIgnoreCase(&(*this)[Length() - suffix.Length()], *suffix) == 0;
@@ -429,22 +434,19 @@ public:
///
/// Replaces all occurences of searchText within current string with replacementText.
///
- /// String to search for. If empty or null no replacements are done.
- /// Length of searchText.
+ /// String to search for.
+ /// Length of searchText. Must be greater than zero.
/// String to replace with. Null is treated as empty string.
/// Length of replacementText.
- /// Number of replacements made. (In case-sensitive mode if search text and replacement text are equal no replacements are done, and zero is returned.)
+ /// Number of replacements made (in other words number of occurences of searchText).
int32 Replace(const T* searchText, int32 searchTextLength, const T* replacementText, int32 replacementTextLength, StringSearchCase searchCase = StringSearchCase::CaseSensitive)
{
if (!HasChars())
return 0;
if (searchTextLength == 0)
- return 0;
-
- // If we are doing case sensitive search and replacement text is equal to search text, we do nothing.
- if ((searchCase == StringSearchCase::CaseSensitive) && (searchTextLength == replacementTextLength) && (StringUtils::Compare(searchText, replacementText) == 0))
{
+ ASSERT(false); // Empty search text never makes sense, and is always sign of a bug in calling code.
return 0;
}
diff --git a/Source/Engine/Core/Types/StringView.h b/Source/Engine/Core/Types/StringView.h
index f0d608493..74f8e398e 100644
--- a/Source/Engine/Core/Types/StringView.h
+++ b/Source/Engine/Core/Types/StringView.h
@@ -54,21 +54,23 @@ public:
///
/// Lexicographically tests how this string compares to the other given string.
+ /// In case sensitive mode 'A' is less than 'a'.
///
/// The another string test against.
/// The case sensitivity mode.
- /// 0 if equal, -1 if less than, 1 if greater than.
+ /// 0 if equal, negative number if less than, positive number if greater than.
int32 Compare(const StringViewBase& str, StringSearchCase searchCase = StringSearchCase::CaseSensitive) const
{
- const int32 lengthDiff = Length() - str.Length();
- if (lengthDiff != 0)
- return lengthDiff;
- if (Length() == 0)
+ const bool thisIsShorter = Length() < str.Length();
+ const int32 minLength = thisIsShorter ? Length() : str.Length();
+ const int32 prefixCompare = (searchCase == StringSearchCase::CaseSensitive)
+ ? StringUtils::Compare(this->GetNonTerminatedText(), str.GetNonTerminatedText(), minLength)
+ : StringUtils::CompareIgnoreCase(this->GetNonTerminatedText(), str.GetNonTerminatedText(), minLength);
+ if (prefixCompare != 0)
+ return prefixCompare;
+ if (Length() == str.Length())
return 0;
- // We know here that both this StringView and str are not empty, and therefore Get() below are valid.
- if (searchCase == StringSearchCase::CaseSensitive)
- return StringUtils::Compare(this->Get(), str.Get(), Length());
- return StringUtils::CompareIgnoreCase(this->Get(), str.Get(), Length());
+ return thisIsShorter ? -1 : 1;
}
public: