Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Faster string comparison functions in StringUtils

The methods EqualsNoCase(), StartsWith() and EndsWith() required quite a lot
of unncessary creation and destruction of std::strings, whether it be the
creation of a temporary copy that could be forced to lower-case, a temporary
copy that was a substring of one of the inputs, or just marshalling a
string literal argument into a std::string.

These functions don't appear to be used all that much at the moment; when I
profiled opening the songs library, I saw only a 1% improvement, which was
within the sampling noise threshold. But with PR #3225 and PR #3290 coming
along, that looks set to change. Once the functions are being called millions
of times, those heap operations really start to get noticeable.

Also, split StartsWith() and EndsWith() into multiple separately-named
functions, according to case sensitivity. Formerly, there was an optional
parameter (default off) to indicate that these operations were
case-*sensitive*, which is actually computationally simpler to perform. Now
the naming convention is consistent with EqualsNoCase:
  StartsWith       - case-sensitive
  EndsWith         - case-sensitive
  StartsWithNoCase - case-insensitive
  EndsWithNoCase   - case-insensitive

With the case-sensitive versions now easier to type, it will hopefully
encourage future developers to use them in preference.
  • Loading branch information...
commit 02fd1ab143bfa35d77ace5ee557ac344c1cd6b25 1 parent 92169a6
@bavison bavison authored
View
6 xbmc/Application.cpp
@@ -1586,7 +1586,7 @@ void CApplication::OnSettingChanged(const CSetting *setting)
}
else if (settingId == "lookandfeel.skinzoom")
g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_WINDOW_RESIZE);
- else if (StringUtils::StartsWith(settingId, "audiooutput."))
+ else if (StringUtils::StartsWithNoCase(settingId, "audiooutput."))
{
if (settingId == "audiooutput.guisoundmode")
{
@@ -2225,13 +2225,13 @@ bool CApplication::OnKey(const CKey& key)
m_idleTimer.StartZero();
bool processKey = AlwaysProcess(action);
- if (StringUtils::StartsWith(action.GetName(),"CECToggleState") || StringUtils::StartsWith(action.GetName(),"CECStandby"))
+ if (StringUtils::StartsWithNoCase(action.GetName(),"CECToggleState") || StringUtils::StartsWithNoCase(action.GetName(),"CECStandby"))
{
bool ret = true;
CLog::Log(LOGDEBUG, "%s: action %s [%d], toggling state of playing device", __FUNCTION__, action.GetName().c_str(), action.GetID());
// do not wake up the screensaver right after switching off the playing device
- if (StringUtils::StartsWith(action.GetName(),"CECToggleState"))
+ if (StringUtils::StartsWithNoCase(action.GetName(),"CECToggleState"))
ret = CApplicationMessenger::Get().CECToggleState();
else
ret = CApplicationMessenger::Get().CECStandby();
View
24 xbmc/CueDocument.cpp
@@ -103,7 +103,7 @@ bool CCueDocument::Parse(const CStdString &strFile)
{
if (!ReadNextLine(strLine))
break;
- if (StringUtils::StartsWith(strLine,"INDEX 01"))
+ if (StringUtils::StartsWithNoCase(strLine,"INDEX 01"))
{
if (bCurrentFileChanged)
{
@@ -124,7 +124,7 @@ bool CCueDocument::Parse(const CStdString &strFile)
if (m_iTotalTracks >= 0)
m_Track[m_iTotalTracks].iStartTime = time; // start time of the next track
}
- else if (StringUtils::StartsWith(strLine,"TITLE"))
+ else if (StringUtils::StartsWithNoCase(strLine,"TITLE"))
{
if (m_iTotalTracks == -1) // No tracks yet
ExtractQuoteInfo(strLine, m_strAlbum);
@@ -140,14 +140,14 @@ bool CCueDocument::Parse(const CStdString &strFile)
}
}
}
- else if (StringUtils::StartsWith(strLine,"PERFORMER"))
+ else if (StringUtils::StartsWithNoCase(strLine,"PERFORMER"))
{
if (m_iTotalTracks == -1) // No tracks yet
ExtractQuoteInfo(strLine, m_strArtist);
else // New Artist for this track
ExtractQuoteInfo(strLine, m_Track[m_iTotalTracks].strArtist);
}
- else if (StringUtils::StartsWith(strLine,"TRACK"))
+ else if (StringUtils::StartsWithNoCase(strLine,"TRACK"))
{
int iTrackNumber = ExtractNumericInfo(strLine.Mid(5));
@@ -164,13 +164,13 @@ bool CCueDocument::Parse(const CStdString &strFile)
bCurrentFileChanged = false;
}
- else if (StringUtils::StartsWith(strLine,"REM DISCNUMBER"))
+ else if (StringUtils::StartsWithNoCase(strLine,"REM DISCNUMBER"))
{
int iDiscNumber = ExtractNumericInfo(strLine.Mid(14));
if (iDiscNumber > 0)
m_iDiscNumber = iDiscNumber;
}
- else if (StringUtils::StartsWith(strLine,"FILE"))
+ else if (StringUtils::StartsWithNoCase(strLine,"FILE"))
{
// already a file name? then the time computation will be changed
if(strCurrentFile.size() > 0)
@@ -182,13 +182,13 @@ bool CCueDocument::Parse(const CStdString &strFile)
if (strCurrentFile.length() > 0)
ResolvePath(strCurrentFile, strFile);
}
- else if (StringUtils::StartsWith(strLine,"REM DATE"))
+ else if (StringUtils::StartsWithNoCase(strLine,"REM DATE"))
{
int iYear = ExtractNumericInfo(strLine.Mid(8));
if (iYear > 0)
m_iYear = iYear;
}
- else if (StringUtils::StartsWith(strLine,"REM GENRE"))
+ else if (StringUtils::StartsWithNoCase(strLine,"REM GENRE"))
{
if (!ExtractQuoteInfo(strLine, m_strGenre))
{
@@ -201,13 +201,13 @@ bool CCueDocument::Parse(const CStdString &strFile)
}
}
}
- else if (StringUtils::StartsWith(strLine,"REM REPLAYGAIN_ALBUM_GAIN"))
+ else if (StringUtils::StartsWithNoCase(strLine,"REM REPLAYGAIN_ALBUM_GAIN"))
m_replayGainAlbumGain = (float)atof(strLine.Mid(26));
- else if (StringUtils::StartsWith(strLine,"REM REPLAYGAIN_ALBUM_PEAK"))
+ else if (StringUtils::StartsWithNoCase(strLine,"REM REPLAYGAIN_ALBUM_PEAK"))
m_replayGainAlbumPeak = (float)atof(strLine.Mid(26));
- else if (StringUtils::StartsWith(strLine,"REM REPLAYGAIN_TRACK_GAIN") && m_iTotalTracks >= 0)
+ else if (StringUtils::StartsWithNoCase(strLine,"REM REPLAYGAIN_TRACK_GAIN") && m_iTotalTracks >= 0)
m_Track[m_iTotalTracks].replayGainTrackGain = (float)atof(strLine.Mid(26));
- else if (StringUtils::StartsWith(strLine,"REM REPLAYGAIN_TRACK_PEAK") && m_iTotalTracks >= 0)
+ else if (StringUtils::StartsWithNoCase(strLine,"REM REPLAYGAIN_TRACK_PEAK") && m_iTotalTracks >= 0)
m_Track[m_iTotalTracks].replayGainTrackPeak = (float)atof(strLine.Mid(26));
}
View
2  xbmc/addons/Addon.cpp
@@ -314,7 +314,7 @@ bool CAddon::MeetsVersion(const AddonVersion &version) const
// if the addon is one of xbmc's extension point definitions (addonid starts with "xbmc.")
// and the minversion is "0.0.0" i.e. no <backwards-compatibility> tag has been specified
// we need to assume that the current version is not backwards-compatible and therefore check against the actual version
- if (StringUtils::StartsWith(m_props.id, "xbmc.") &&
+ if (StringUtils::StartsWithNoCase(m_props.id, "xbmc.") &&
(strlen(m_props.minversion.c_str()) == 0 || StringUtils::EqualsNoCase(m_props.minversion.c_str(), "0.0.0")))
return m_props.version == version;
View
2  xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp
@@ -149,7 +149,7 @@ bool CAESinkDirectSound::Initialize(AEAudioFormat &format, std::string &device)
std::string deviceFriendlyName;
DirectSoundEnumerate(DSEnumCallback, &DSDeviceList);
- if(StringUtils::EndsWith(device, std::string("default")))
+ if(StringUtils::EndsWithNoCase(device, std::string("default")))
strDeviceGUID = GetDefaultDevice();
for (std::list<DSDevice>::iterator itt = DSDeviceList.begin(); itt != DSDeviceList.end(); ++itt)
View
2  xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
@@ -231,7 +231,7 @@ bool CAESinkWASAPI::Initialize(AEAudioFormat &format, std::string &device)
hr = pEnumDevices->GetCount(&uiCount);
EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
- if(StringUtils::EndsWith(device, std::string("default")))
+ if(StringUtils::EndsWithNoCase(device, std::string("default")))
bdefault = true;
if(!bdefault)
View
20 xbmc/filesystem/test/TestRarFile.cpp
@@ -210,7 +210,7 @@ TEST(TestRarFile, StoredRAR)
* an uncompressed RAR archive. See TestRarFile.Read test case.
*/
strpathinrar = itemlist[1]->GetPath();
- ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/reffile.txt", true));
+ ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/reffile.txt"));
EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFREG);
@@ -255,7 +255,7 @@ TEST(TestRarFile, StoredRAR)
/* /testsymlink -> testdir/reffile.txt */
strpathinrar = itemlist[2]->GetPath();
- ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlink", true));
+ ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlink"));
EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFLNK);
@@ -270,7 +270,7 @@ TEST(TestRarFile, StoredRAR)
/* /testsymlinksubdir -> testdir/testsubdir/reffile.txt */
strpathinrar = itemlist[3]->GetPath();
- ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlinksubdir", true));
+ ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlinksubdir"));
EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFLNK);
@@ -280,7 +280,7 @@ TEST(TestRarFile, StoredRAR)
/* /testdir/ */
strpathinrar = itemlist[0]->GetPath();
- ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/", true));
+ ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/"));
EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFDIR);
@@ -345,7 +345,7 @@ TEST(TestRarFile, StoredRAR)
/* FIXME: This directory appears a second time as a file */
strpathinrar = itemlist[3]->GetPath();
- ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/testsubdir", true));
+ ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/testsubdir"));
/* /testdir/testsymlink -> testsubdir/reffile.txt */
strpathinrar = itemlist[4]->GetPath();
@@ -432,7 +432,7 @@ TEST(TestRarFile, NormalRAR)
/* /reffile.txt */
strpathinrar = itemlist[1]->GetPath();
- ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/reffile.txt", true));
+ ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/reffile.txt"));
EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFREG);
@@ -477,7 +477,7 @@ TEST(TestRarFile, NormalRAR)
/* /testsymlink -> testdir/reffile.txt */
strpathinrar = itemlist[2]->GetPath();
- ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlink", true));
+ ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlink"));
EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFLNK);
@@ -492,7 +492,7 @@ TEST(TestRarFile, NormalRAR)
/* /testsymlinksubdir -> testdir/testsubdir/reffile.txt */
strpathinrar = itemlist[3]->GetPath();
- ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlinksubdir", true));
+ ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlinksubdir"));
EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFLNK);
@@ -502,7 +502,7 @@ TEST(TestRarFile, NormalRAR)
/* /testdir/ */
strpathinrar = itemlist[0]->GetPath();
- ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/", true));
+ ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/"));
EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFDIR);
@@ -567,7 +567,7 @@ TEST(TestRarFile, NormalRAR)
/* FIXME: This directory appears a second time as a file */
strpathinrar = itemlist[3]->GetPath();
- ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/testsubdir", true));
+ ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/testsubdir"));
/* /testdir/testsymlink -> testsubdir/reffile.txt */
strpathinrar = itemlist[4]->GetPath();
View
2  xbmc/interfaces/generic/ScriptInvocationManager.cpp
@@ -122,7 +122,7 @@ void CScriptInvocationManager::RegisterLanguageInvocationHandler(ILanguageInvoca
string ext = extension;
StringUtils::ToLower(ext);
- if (!StringUtils::StartsWith(ext, "."))
+ if (!StringUtils::StartsWithNoCase(ext, "."))
ext = "." + ext;
CSingleLock lock(m_critSection);
View
2  xbmc/music/windows/GUIWindowMusicBase.cpp
@@ -1154,7 +1154,7 @@ bool CGUIWindowMusicBase::CheckFilterAdvanced(CFileItemList &items) const
bool CGUIWindowMusicBase::CanContainFilter(const CStdString &strDirectory) const
{
- return StringUtils::StartsWith(strDirectory, "musicdb://");
+ return StringUtils::StartsWithNoCase(strDirectory, "musicdb://");
}
void CGUIWindowMusicBase::OnInitWindow()
View
6 xbmc/music/windows/GUIWindowMusicNav.cpp
@@ -447,7 +447,7 @@ void CGUIWindowMusicNav::GetContextButtons(int itemNumber, CContextButtons &butt
{
if (!item->m_bIsFolder) // music video
buttons.Add(CONTEXT_BUTTON_INFO, 20393);
- if (StringUtils::StartsWith(item->GetPath(), "videodb://musicvideos/artist/") && item->m_bIsFolder)
+ if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/artist/") && item->m_bIsFolder)
{
long idArtist = m_musicdatabase.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
if (idArtist > - 1)
@@ -565,7 +565,7 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
return CGUIWindowMusicBase::OnContextButton(itemNumber,button);
// music videos - artists
- if (StringUtils::StartsWith(item->GetPath(), "videodb://musicvideos/artists/"))
+ if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/artists/"))
{
long idArtist = m_musicdatabase.GetArtistByName(item->GetLabel());
if (idArtist == -1)
@@ -582,7 +582,7 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
}
// music videos - albums
- if (StringUtils::StartsWith(item->GetPath(), "videodb://musicvideos/albums/"))
+ if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/albums/"))
{
long idAlbum = m_musicdatabase.GetAlbumByName(item->GetLabel());
if (idAlbum == -1)
View
2  xbmc/network/WebServer.cpp
@@ -965,7 +965,7 @@ int64_t CWebServer::ParseRangeHeader(const std::string &rangeHeaderValue, int64_
firstPosition = 0;
lastPosition = totalLength - 1;
- if (rangeHeaderValue.empty() || !StringUtils::StartsWith(rangeHeaderValue, "bytes="))
+ if (rangeHeaderValue.empty() || !StringUtils::StartsWithNoCase(rangeHeaderValue, "bytes="))
return totalLength;
int64_t rangesLength = 0;
View
18 xbmc/network/upnp/UPnPServer.cpp
@@ -547,7 +547,7 @@ CUPnPServer::OnBrowseMetadata(PLT_ActionReference& action,
// attempt to determine the parent of this item
CStdString parent;
- if (URIUtils::IsVideoDb((const char*)id) || URIUtils::IsMusicDb((const char*)id) || StringUtils::StartsWith((const char*)id, "library://video/")) {
+ if (URIUtils::IsVideoDb((const char*)id) || URIUtils::IsMusicDb((const char*)id) || StringUtils::StartsWithNoCase((const char*)id, "library://video/")) {
if (!URIUtils::GetParentPath((const char*)id, parent)) {
parent = "0";
}
@@ -560,11 +560,11 @@ CUPnPServer::OnBrowseMetadata(PLT_ActionReference& action,
// however this is quicker to implement and subsequently purge when a
// better solution presents itself
CStdString child_id((const char*)id);
- if (StringUtils::StartsWith(child_id, "special://musicplaylists/")) parent = "musicdb://";
- else if (StringUtils::StartsWith(child_id, "special://videoplaylists/")) parent = "library://video/";
- else if (StringUtils::StartsWith(child_id, "sources://video/")) parent = "library://video/";
- else if (StringUtils::StartsWith(child_id, "special://profile/playlists/music/")) parent = "special://musicplaylists/";
- else if (StringUtils::StartsWith(child_id, "special://profile/playlists/video/")) parent = "special://videoplaylists/";
+ if (StringUtils::StartsWithNoCase(child_id, "special://musicplaylists/")) parent = "musicdb://";
+ else if (StringUtils::StartsWithNoCase(child_id, "special://videoplaylists/")) parent = "library://video/";
+ else if (StringUtils::StartsWithNoCase(child_id, "sources://video/")) parent = "library://video/";
+ else if (StringUtils::StartsWithNoCase(child_id, "special://profile/playlists/music/")) parent = "special://musicplaylists/";
+ else if (StringUtils::StartsWithNoCase(child_id, "special://profile/playlists/video/")) parent = "special://videoplaylists/";
else parent = "sources://video/"; // this can only match video sources
}
@@ -729,13 +729,13 @@ CUPnPServer::BuildResponse(PLT_ActionReference& action,
NPT_Reference<CThumbLoader> thumb_loader;
if (URIUtils::IsVideoDb(items.GetPath()) ||
- StringUtils::StartsWith(items.GetPath(), "library://video/") ||
- StringUtils::StartsWith(items.GetPath(), "special://profile/playlists/video/")) {
+ StringUtils::StartsWithNoCase(items.GetPath(), "library://video/") ||
+ StringUtils::StartsWithNoCase(items.GetPath(), "special://profile/playlists/video/")) {
thumb_loader = NPT_Reference<CThumbLoader>(new CVideoThumbLoader());
}
else if (URIUtils::IsMusicDb(items.GetPath()) ||
- StringUtils::StartsWith(items.GetPath(), "special://profile/playlists/music/")) {
+ StringUtils::StartsWithNoCase(items.GetPath(), "special://profile/playlists/music/")) {
thumb_loader = NPT_Reference<CThumbLoader>(new CMusicThumbLoader());
}
View
4 xbmc/settings/SettingDependency.cpp
@@ -131,12 +131,12 @@ bool CSettingDependencyCondition::setTarget(const std::string &target)
bool CSettingDependencyCondition::setOperator(const std::string &op)
{
size_t length = 0;
- if (StringUtils::EndsWith(op, "is"))
+ if (StringUtils::EndsWithNoCase(op, "is"))
{
m_operator = SettingDependencyOperatorEquals;
length = 2;
}
- else if (StringUtils::EndsWith(op, "contains"))
+ else if (StringUtils::EndsWithNoCase(op, "contains"))
{
m_operator = SettingDependencyOperatorContains;
length = 8;
View
2  xbmc/settings/SettingsManager.cpp
@@ -476,7 +476,7 @@ bool CSettingsManager::GetBool(const std::string &id) const
if (setting == NULL || setting->GetType() != SettingTypeBool)
{
// Backward compatibility (skins use this setting)
- if (setting == NULL && StringUtils::EqualsNoCase(id.c_str(), "lookandfeel.enablemouse"))
+ if (setting == NULL && StringUtils::EqualsNoCase(id, "lookandfeel.enablemouse"))
return GetBool("input.enablemouse");
return false;
View
4 xbmc/settings/SkinSettings.cpp
@@ -175,13 +175,13 @@ void CSkinSettings::Reset()
// clear all the settings and strings from this skin.
for (map<int, CSkinBool>::iterator it = m_bools.begin(); it != m_bools.end(); ++it)
{
- if (StringUtils::StartsWith(it->second.name, currentSkin))
+ if (StringUtils::StartsWithNoCase(it->second.name, currentSkin))
it->second.value = false;
}
for (map<int, CSkinString>::iterator it = m_strings.begin(); it != m_strings.end(); ++it)
{
- if (StringUtils::StartsWith(it->second.name, currentSkin))
+ if (StringUtils::StartsWithNoCase(it->second.name, currentSkin))
it->second.value.clear();
}
View
22 xbmc/utils/FileUtils.cpp
@@ -116,27 +116,27 @@ bool CFileUtils::RemoteAccessAllowed(const CStdString &strPath)
while (URIUtils::IsInArchive(realPath))
realPath = CURL(realPath).GetHostName();
- if (StringUtils::StartsWith(realPath, "virtualpath://upnproot/"))
+ if (StringUtils::StartsWithNoCase(realPath, "virtualpath://upnproot/"))
return true;
- else if (StringUtils::StartsWith(realPath, "musicdb://"))
+ else if (StringUtils::StartsWithNoCase(realPath, "musicdb://"))
return true;
- else if (StringUtils::StartsWith(realPath, "videodb://"))
+ else if (StringUtils::StartsWithNoCase(realPath, "videodb://"))
return true;
- else if (StringUtils::StartsWith(realPath, "library://video"))
+ else if (StringUtils::StartsWithNoCase(realPath, "library://video"))
return true;
- else if (StringUtils::StartsWith(realPath, "sources://video"))
+ else if (StringUtils::StartsWithNoCase(realPath, "sources://video"))
return true;
- else if (StringUtils::StartsWith(realPath, "special://musicplaylists"))
+ else if (StringUtils::StartsWithNoCase(realPath, "special://musicplaylists"))
return true;
- else if (StringUtils::StartsWith(realPath, "special://profile/playlists"))
+ else if (StringUtils::StartsWithNoCase(realPath, "special://profile/playlists"))
return true;
- else if (StringUtils::StartsWith(realPath, "special://videoplaylists"))
+ else if (StringUtils::StartsWithNoCase(realPath, "special://videoplaylists"))
return true;
- else if (StringUtils::StartsWith(realPath, "addons://sources"))
+ else if (StringUtils::StartsWithNoCase(realPath, "addons://sources"))
return true;
- else if (StringUtils::StartsWith(realPath, "upnp://"))
+ else if (StringUtils::StartsWithNoCase(realPath, "upnp://"))
return true;
- else if (StringUtils::StartsWith(realPath, "plugin://"))
+ else if (StringUtils::StartsWithNoCase(realPath, "plugin://"))
return true;
bool isSource;
for (unsigned int index = 0; index < SourcesSize; index++)
View
2  xbmc/utils/LegacyPathTranslation.cpp
@@ -95,7 +95,7 @@ std::string CLegacyPathTranslation::TranslatePath(const std::string &legacyPath,
std::string newPath = legacyPath;
for (size_t index = 0; index < translationMapSize; index++)
{
- if (StringUtils::StartsWith(newPath, translationMap[index].legacyPath))
+ if (StringUtils::StartsWithNoCase(newPath, translationMap[index].legacyPath))
{
StringUtils::Replace(newPath, translationMap[index].legacyPath, translationMap[index].newPath);
break;
View
121 xbmc/utils/StringUtils.cpp
@@ -114,12 +114,26 @@ void StringUtils::ToLower(string &str)
bool StringUtils::EqualsNoCase(const std::string &str1, const std::string &str2)
{
- string tmp1 = str1;
- string tmp2 = str2;
- ToLower(tmp1);
- ToLower(tmp2);
-
- return tmp1.compare(tmp2) == 0;
+ return EqualsNoCase(str1.c_str(), str2.c_str());
+}
+
+bool StringUtils::EqualsNoCase(const std::string &str1, const char *s2)
+{
+ return EqualsNoCase(str1.c_str(), s2);
+}
+
+bool StringUtils::EqualsNoCase(const char *s1, const char *s2)
+{
+ int c1, c2; // Yes, because the return type of tolower() is int.
+ // To make these chars would be to introduce an unnecesary extra bitmask/zero-extend (effectively caller-narowing) into the binary.
+ do
+ {
+ c1 = ::tolower(*s1++);
+ c2 = ::tolower(*s2++);
+ if (c1 != c2) // This includes the possibility that one of the characters is the null-terminator, which implies a string mismatch.
+ return false;
+ } while (c2 != '\0'); // At this point, we know c1 == c2, so there's no need to test them both.
+ return true;
}
string StringUtils::Left(const string &str, size_t count)
@@ -225,24 +239,95 @@ int StringUtils::Replace(std::string &str, const std::string &oldStr, const std:
return replacedChars;
}
-bool StringUtils::StartsWith(const std::string &str, const std::string &str2, bool useCase /* = false */)
+bool StringUtils::StartsWith(const std::string &str1, const std::string &str2)
{
- std::string left = StringUtils::Left(str, str2.size());
-
- if (useCase)
- return left.compare(str2) == 0;
+ return str1.compare(0, str2.size(), str2) == 0;
+}
- return StringUtils::EqualsNoCase(left, str2);
+bool StringUtils::StartsWith(const std::string &str1, const char *s2)
+{
+ return StartsWith(str1.c_str(), s2);
}
-bool StringUtils::EndsWith(const std::string &str, const std::string &str2, bool useCase /* = false */)
+bool StringUtils::StartsWith(const char *s1, const char *s2)
{
- std::string right = StringUtils::Right(str, str2.size());
-
- if (useCase)
- return right.compare(str2) == 0;
+ while (*s2 != '\0')
+ {
+ if (*s1 != *s2)
+ return false;
+ s1++;
+ s2++;
+ }
+ return true;
+}
- return StringUtils::EqualsNoCase(right, str2);
+bool StringUtils::StartsWithNoCase(const std::string &str1, const std::string &str2)
+{
+ return StartsWithNoCase(str1.c_str(), str2.c_str());
+}
+
+bool StringUtils::StartsWithNoCase(const std::string &str1, const char *s2)
+{
+ return StartsWithNoCase(str1.c_str(), s2);
+}
+
+bool StringUtils::StartsWithNoCase(const char *s1, const char *s2)
+{
+ while (*s2 != '\0')
+ {
+ if (::tolower(*s1) != ::tolower(*s2))
+ return false;
+ s1++;
+ s2++;
+ }
+ return true;
+}
+
+bool StringUtils::EndsWith(const std::string &str1, const std::string &str2)
+{
+ if (str1.size() < str2.size())
+ return false;
+ return str1.compare(str1.size() - str2.size(), str2.size(), str2) == 0;
+}
+
+bool StringUtils::EndsWith(const std::string &str1, const char *s2)
+{
+ size_t len2 = strlen(s2);
+ if (str1.size() < len2)
+ return false;
+ return str1.compare(str1.size() - len2, len2, s2) == 0;
+}
+
+bool StringUtils::EndsWithNoCase(const std::string &str1, const std::string &str2)
+{
+ if (str1.size() < str2.size())
+ return false;
+ const char *s1 = str1.c_str() + str1.size() - str2.size();
+ const char *s2 = str2.c_str();
+ while (*s2 != '\0')
+ {
+ if (::tolower(*s1) != ::tolower(*s2))
+ return false;
+ s1++;
+ s2++;
+ }
+ return true;
+}
+
+bool StringUtils::EndsWithNoCase(const std::string &str1, const char *s2)
+{
+ size_t len2 = strlen(s2);
+ if (str1.size() < len2)
+ return false;
+ const char *s1 = str1.c_str() + str1.size() - len2;
+ while (*s2 != '\0')
+ {
+ if (::tolower(*s1) != ::tolower(*s2))
+ return false;
+ s1++;
+ s2++;
+ }
+ return true;
}
void StringUtils::JoinString(const CStdStringArray &strings, const CStdString& delimiter, CStdString& result)
View
14 xbmc/utils/StringUtils.h
@@ -55,6 +55,8 @@ class StringUtils
static void ToUpper(std::string &str);
static void ToLower(std::string &str);
static bool EqualsNoCase(const std::string &str1, const std::string &str2);
+ static bool EqualsNoCase(const std::string &str1, const char *s2);
+ static bool EqualsNoCase(const char *s1, const char *s2);
static std::string Left(const std::string &str, size_t count);
static std::string Mid(const std::string &str, size_t first, size_t count = std::string::npos);
static std::string Right(const std::string &str, size_t count);
@@ -64,8 +66,16 @@ class StringUtils
static std::string& RemoveDuplicatedSpacesAndTabs(std::string& str);
static int Replace(std::string &str, char oldChar, char newChar);
static int Replace(std::string &str, const std::string &oldStr, const std::string &newStr);
- static bool StartsWith(const std::string &str, const std::string &str2, bool useCase = false);
- static bool EndsWith(const std::string &str, const std::string &str2, bool useCase = false);
+ static bool StartsWith(const std::string &str1, const std::string &str2);
+ static bool StartsWith(const std::string &str1, const char *s2);
+ static bool StartsWith(const char *s1, const char *s2);
+ static bool StartsWithNoCase(const std::string &str1, const std::string &str2);
+ static bool StartsWithNoCase(const std::string &str1, const char *s2);
+ static bool StartsWithNoCase(const char *s1, const char *s2);
+ static bool EndsWith(const std::string &str1, const std::string &str2);
+ static bool EndsWith(const std::string &str1, const char *s2);
+ static bool EndsWithNoCase(const std::string &str1, const std::string &str2);
+ static bool EndsWithNoCase(const std::string &str1, const char *s2);
static void JoinString(const CStdStringArray &strings, const CStdString& delimiter, CStdString& result);
static CStdString JoinString(const CStdStringArray &strings, const CStdString& delimiter);
View
2  xbmc/utils/StringValidation.cpp
@@ -37,7 +37,7 @@ bool StringValidation::IsTime(const std::string &input, void *data)
std::string strTime = input;
StringUtils::Trim(strTime);
- if (StringUtils::EndsWith(strTime, " min"))
+ if (StringUtils::EndsWithNoCase(strTime, " min"))
{
strTime = StringUtils::Left(strTime, strTime.size() - 4);
StringUtils::TrimRight(strTime);
View
24 xbmc/utils/test/TestStringUtils.cpp
@@ -175,28 +175,28 @@ TEST(TestStringUtils, StartsWith)
{
std::string refstr = "test";
- EXPECT_FALSE(StringUtils::StartsWith(refstr, "x"));
+ EXPECT_FALSE(StringUtils::StartsWithNoCase(refstr, "x"));
- EXPECT_TRUE(StringUtils::StartsWith(refstr, "te", true));
- EXPECT_TRUE(StringUtils::StartsWith(refstr, "test", true));
- EXPECT_FALSE(StringUtils::StartsWith(refstr, "Te", true));
+ EXPECT_TRUE(StringUtils::StartsWith(refstr, "te"));
+ EXPECT_TRUE(StringUtils::StartsWith(refstr, "test"));
+ EXPECT_FALSE(StringUtils::StartsWith(refstr, "Te"));
- EXPECT_TRUE(StringUtils::StartsWith(refstr, "Te", false));
- EXPECT_TRUE(StringUtils::StartsWith(refstr, "TesT", false));
+ EXPECT_TRUE(StringUtils::StartsWithNoCase(refstr, "Te"));
+ EXPECT_TRUE(StringUtils::StartsWithNoCase(refstr, "TesT"));
}
TEST(TestStringUtils, EndsWith)
{
std::string refstr = "test";
- EXPECT_FALSE(StringUtils::EndsWith(refstr, "x"));
+ EXPECT_FALSE(StringUtils::EndsWithNoCase(refstr, "x"));
- EXPECT_TRUE(StringUtils::EndsWith(refstr, "st", true));
- EXPECT_TRUE(StringUtils::EndsWith(refstr, "test", true));
- EXPECT_FALSE(StringUtils::EndsWith(refstr, "sT", true));
+ EXPECT_TRUE(StringUtils::EndsWith(refstr, "st"));
+ EXPECT_TRUE(StringUtils::EndsWith(refstr, "test"));
+ EXPECT_FALSE(StringUtils::EndsWith(refstr, "sT"));
- EXPECT_TRUE(StringUtils::EndsWith(refstr, "sT", false));
- EXPECT_TRUE(StringUtils::EndsWith(refstr, "TesT", false));
+ EXPECT_TRUE(StringUtils::EndsWithNoCase(refstr, "sT"));
+ EXPECT_TRUE(StringUtils::EndsWithNoCase(refstr, "TesT"));
}
TEST(TestStringUtils, JoinString)
View
2  xbmc/video/windows/GUIWindowVideoBase.cpp
@@ -1791,7 +1791,7 @@ bool CGUIWindowVideoBase::CheckFilterAdvanced(CFileItemList &items) const
bool CGUIWindowVideoBase::CanContainFilter(const CStdString &strDirectory) const
{
- return StringUtils::StartsWith(strDirectory, "videodb://");
+ return StringUtils::StartsWithNoCase(strDirectory, "videodb://");
}
void CGUIWindowVideoBase::AddToDatabase(int iItem)
View
6 xbmc/video/windows/GUIWindowVideoNav.cpp
@@ -674,7 +674,7 @@ void CGUIWindowVideoNav::OnDeleteItem(CFileItemPtr pItem)
!pItem->GetPath().Left(9).Equals("newtag://"))
CGUIWindowVideoBase::OnDeleteItem(pItem);
}
- else if (StringUtils::StartsWith(pItem->GetPath(), "videodb://movies/sets/") &&
+ else if (StringUtils::StartsWithNoCase(pItem->GetPath(), "videodb://movies/sets/") &&
pItem->GetPath().size() > 22 && pItem->m_bIsFolder)
{
CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
@@ -967,7 +967,7 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt
if (node == NODE_TYPE_SEASONS && item->m_bIsFolder)
buttons.Add(CONTEXT_BUTTON_SET_SEASON_ART, 13511);
- if (StringUtils::StartsWith(item->GetPath(), "videodb://movies/sets/") && item->GetPath().size() > 22 && item->m_bIsFolder) // sets
+ if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://movies/sets/") && item->GetPath().size() > 22 && item->m_bIsFolder) // sets
{
buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_ART, 13511);
buttons.Add(CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS, 20465);
@@ -991,7 +991,7 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt
if (node == NODE_TYPE_ACTOR && !dir.IsAllItem(item->GetPath()) && item->m_bIsFolder)
{
- if (StringUtils::StartsWith(m_vecItems->GetPath(), "videodb://musicvideos")) // mvids
+ if (StringUtils::StartsWithNoCase(m_vecItems->GetPath(), "videodb://musicvideos")) // mvids
buttons.Add(CONTEXT_BUTTON_SET_ARTIST_THUMB, 13359);
else
buttons.Add(CONTEXT_BUTTON_SET_ACTOR_THUMB, 20403);
View
4 xbmc/view/ViewDatabase.cpp
@@ -93,9 +93,9 @@ bool CViewDatabase::UpdateOldVersion(int version)
{
std::string originalPath = m_pDS->fv(1).get_asString();
std::string path = originalPath;
- if (StringUtils::StartsWith(path, "musicdb://"))
+ if (StringUtils::StartsWithNoCase(path, "musicdb://"))
path = CLegacyPathTranslation::TranslateMusicDbPath(path);
- else if (StringUtils::StartsWith(path, "videodb://"))
+ else if (StringUtils::StartsWithNoCase(path, "videodb://"))
path = CLegacyPathTranslation::TranslateVideoDbPath(path);
if (!StringUtils::EqualsNoCase(path, originalPath))
Please sign in to comment.
Something went wrong with that request. Please try again.