Skip to content
This repository
Browse code

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 authored September 18, 2013
6  xbmc/Application.cpp
@@ -1586,7 +1586,7 @@ void CApplication::OnSettingChanged(const CSetting *setting)
1586 1586
   }
1587 1587
   else if (settingId == "lookandfeel.skinzoom")
1588 1588
     g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_WINDOW_RESIZE);
1589  
-  else if (StringUtils::StartsWith(settingId, "audiooutput."))
  1589
+  else if (StringUtils::StartsWithNoCase(settingId, "audiooutput."))
1590 1590
   {
1591 1591
     if (settingId == "audiooutput.guisoundmode")
1592 1592
     {
@@ -2225,13 +2225,13 @@ bool CApplication::OnKey(const CKey& key)
2225 2225
   m_idleTimer.StartZero();
2226 2226
   bool processKey = AlwaysProcess(action);
2227 2227
 
2228  
-  if (StringUtils::StartsWith(action.GetName(),"CECToggleState") || StringUtils::StartsWith(action.GetName(),"CECStandby"))
  2228
+  if (StringUtils::StartsWithNoCase(action.GetName(),"CECToggleState") || StringUtils::StartsWithNoCase(action.GetName(),"CECStandby"))
2229 2229
   {
2230 2230
     bool ret = true;
2231 2231
 
2232 2232
     CLog::Log(LOGDEBUG, "%s: action %s [%d], toggling state of playing device", __FUNCTION__, action.GetName().c_str(), action.GetID());
2233 2233
     // do not wake up the screensaver right after switching off the playing device
2234  
-    if (StringUtils::StartsWith(action.GetName(),"CECToggleState"))
  2234
+    if (StringUtils::StartsWithNoCase(action.GetName(),"CECToggleState"))
2235 2235
       ret = CApplicationMessenger::Get().CECToggleState();
2236 2236
     else
2237 2237
       ret = CApplicationMessenger::Get().CECStandby();
24  xbmc/CueDocument.cpp
@@ -103,7 +103,7 @@ bool CCueDocument::Parse(const CStdString &strFile)
103 103
   {
104 104
     if (!ReadNextLine(strLine))
105 105
       break;
106  
-    if (StringUtils::StartsWith(strLine,"INDEX 01"))
  106
+    if (StringUtils::StartsWithNoCase(strLine,"INDEX 01"))
107 107
     {
108 108
       if (bCurrentFileChanged)
109 109
       {
@@ -124,7 +124,7 @@ bool CCueDocument::Parse(const CStdString &strFile)
124 124
       if (m_iTotalTracks >= 0)
125 125
         m_Track[m_iTotalTracks].iStartTime = time; // start time of the next track
126 126
     }
127  
-    else if (StringUtils::StartsWith(strLine,"TITLE"))
  127
+    else if (StringUtils::StartsWithNoCase(strLine,"TITLE"))
128 128
     {
129 129
       if (m_iTotalTracks == -1) // No tracks yet
130 130
         ExtractQuoteInfo(strLine, m_strAlbum);
@@ -140,14 +140,14 @@ bool CCueDocument::Parse(const CStdString &strFile)
140 140
         }
141 141
       }
142 142
     }
143  
-    else if (StringUtils::StartsWith(strLine,"PERFORMER"))
  143
+    else if (StringUtils::StartsWithNoCase(strLine,"PERFORMER"))
144 144
     {
145 145
       if (m_iTotalTracks == -1) // No tracks yet
146 146
         ExtractQuoteInfo(strLine, m_strArtist);
147 147
       else // New Artist for this track
148 148
         ExtractQuoteInfo(strLine, m_Track[m_iTotalTracks].strArtist);
149 149
     }
150  
-    else if (StringUtils::StartsWith(strLine,"TRACK"))
  150
+    else if (StringUtils::StartsWithNoCase(strLine,"TRACK"))
151 151
     {
152 152
       int iTrackNumber = ExtractNumericInfo(strLine.Mid(5));
153 153
 
@@ -164,13 +164,13 @@ bool CCueDocument::Parse(const CStdString &strFile)
164 164
 
165 165
       bCurrentFileChanged = false;
166 166
     }
167  
-    else if (StringUtils::StartsWith(strLine,"REM DISCNUMBER"))
  167
+    else if (StringUtils::StartsWithNoCase(strLine,"REM DISCNUMBER"))
168 168
     {
169 169
       int iDiscNumber = ExtractNumericInfo(strLine.Mid(14));
170 170
       if (iDiscNumber > 0)
171 171
         m_iDiscNumber = iDiscNumber;
172 172
     }
173  
-    else if (StringUtils::StartsWith(strLine,"FILE"))
  173
+    else if (StringUtils::StartsWithNoCase(strLine,"FILE"))
174 174
     {
175 175
       // already a file name? then the time computation will be changed
176 176
       if(strCurrentFile.size() > 0)
@@ -182,13 +182,13 @@ bool CCueDocument::Parse(const CStdString &strFile)
182 182
       if (strCurrentFile.length() > 0)
183 183
         ResolvePath(strCurrentFile, strFile);
184 184
     }
185  
-    else if (StringUtils::StartsWith(strLine,"REM DATE"))
  185
+    else if (StringUtils::StartsWithNoCase(strLine,"REM DATE"))
186 186
     {
187 187
       int iYear = ExtractNumericInfo(strLine.Mid(8));
188 188
       if (iYear > 0)
189 189
         m_iYear = iYear;
190 190
     }
191  
-    else if (StringUtils::StartsWith(strLine,"REM GENRE"))
  191
+    else if (StringUtils::StartsWithNoCase(strLine,"REM GENRE"))
192 192
     {
193 193
       if (!ExtractQuoteInfo(strLine, m_strGenre))
194 194
       {
@@ -201,13 +201,13 @@ bool CCueDocument::Parse(const CStdString &strFile)
201 201
         }
202 202
       }
203 203
     }
204  
-    else if (StringUtils::StartsWith(strLine,"REM REPLAYGAIN_ALBUM_GAIN"))
  204
+    else if (StringUtils::StartsWithNoCase(strLine,"REM REPLAYGAIN_ALBUM_GAIN"))
205 205
       m_replayGainAlbumGain = (float)atof(strLine.Mid(26));
206  
-    else if (StringUtils::StartsWith(strLine,"REM REPLAYGAIN_ALBUM_PEAK"))
  206
+    else if (StringUtils::StartsWithNoCase(strLine,"REM REPLAYGAIN_ALBUM_PEAK"))
207 207
       m_replayGainAlbumPeak = (float)atof(strLine.Mid(26));
208  
-    else if (StringUtils::StartsWith(strLine,"REM REPLAYGAIN_TRACK_GAIN") && m_iTotalTracks >= 0)
  208
+    else if (StringUtils::StartsWithNoCase(strLine,"REM REPLAYGAIN_TRACK_GAIN") && m_iTotalTracks >= 0)
209 209
       m_Track[m_iTotalTracks].replayGainTrackGain = (float)atof(strLine.Mid(26));
210  
-    else if (StringUtils::StartsWith(strLine,"REM REPLAYGAIN_TRACK_PEAK") && m_iTotalTracks >= 0)
  210
+    else if (StringUtils::StartsWithNoCase(strLine,"REM REPLAYGAIN_TRACK_PEAK") && m_iTotalTracks >= 0)
211 211
       m_Track[m_iTotalTracks].replayGainTrackPeak = (float)atof(strLine.Mid(26));
212 212
   }
213 213
 
2  xbmc/addons/Addon.cpp
@@ -314,7 +314,7 @@ bool CAddon::MeetsVersion(const AddonVersion &version) const
314 314
   // if the addon is one of xbmc's extension point definitions (addonid starts with "xbmc.")
315 315
   // and the minversion is "0.0.0" i.e. no <backwards-compatibility> tag has been specified
316 316
   // we need to assume that the current version is not backwards-compatible and therefore check against the actual version
317  
-  if (StringUtils::StartsWith(m_props.id, "xbmc.") &&
  317
+  if (StringUtils::StartsWithNoCase(m_props.id, "xbmc.") &&
318 318
      (strlen(m_props.minversion.c_str()) == 0 || StringUtils::EqualsNoCase(m_props.minversion.c_str(), "0.0.0")))
319 319
     return m_props.version == version;
320 320
 
2  xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp
@@ -149,7 +149,7 @@ bool CAESinkDirectSound::Initialize(AEAudioFormat &format, std::string &device)
149 149
   std::string deviceFriendlyName;
150 150
   DirectSoundEnumerate(DSEnumCallback, &DSDeviceList);
151 151
 
152  
-  if(StringUtils::EndsWith(device, std::string("default")))
  152
+  if(StringUtils::EndsWithNoCase(device, std::string("default")))
153 153
     strDeviceGUID = GetDefaultDevice();
154 154
 
155 155
   for (std::list<DSDevice>::iterator itt = DSDeviceList.begin(); itt != DSDeviceList.end(); ++itt)
2  xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
@@ -231,7 +231,7 @@ bool CAESinkWASAPI::Initialize(AEAudioFormat &format, std::string &device)
231 231
   hr = pEnumDevices->GetCount(&uiCount);
232 232
   EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
233 233
 
234  
-  if(StringUtils::EndsWith(device, std::string("default")))
  234
+  if(StringUtils::EndsWithNoCase(device, std::string("default")))
235 235
     bdefault = true;
236 236
 
237 237
   if(!bdefault)
20  xbmc/filesystem/test/TestRarFile.cpp
@@ -210,7 +210,7 @@ TEST(TestRarFile, StoredRAR)
210 210
    * an uncompressed RAR archive. See TestRarFile.Read test case.
211 211
    */
212 212
   strpathinrar = itemlist[1]->GetPath();
213  
-  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/reffile.txt", true));
  213
+  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/reffile.txt"));
214 214
   EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
215 215
   EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFREG);
216 216
 
@@ -255,7 +255,7 @@ TEST(TestRarFile, StoredRAR)
255 255
 
256 256
   /* /testsymlink -> testdir/reffile.txt */
257 257
   strpathinrar = itemlist[2]->GetPath();
258  
-  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlink", true));
  258
+  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlink"));
259 259
   EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
260 260
   EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFLNK);
261 261
 
@@ -270,7 +270,7 @@ TEST(TestRarFile, StoredRAR)
270 270
 
271 271
   /* /testsymlinksubdir -> testdir/testsubdir/reffile.txt */
272 272
   strpathinrar = itemlist[3]->GetPath();
273  
-  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlinksubdir", true));
  273
+  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlinksubdir"));
274 274
   EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
275 275
   EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFLNK);
276 276
 
@@ -280,7 +280,7 @@ TEST(TestRarFile, StoredRAR)
280 280
 
281 281
   /* /testdir/ */
282 282
   strpathinrar = itemlist[0]->GetPath();
283  
-  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/", true));
  283
+  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/"));
284 284
   EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
285 285
   EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFDIR);
286 286
 
@@ -345,7 +345,7 @@ TEST(TestRarFile, StoredRAR)
345 345
 
346 346
   /* FIXME: This directory appears a second time as a file */
347 347
   strpathinrar = itemlist[3]->GetPath();
348  
-  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/testsubdir", true));
  348
+  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/testsubdir"));
349 349
 
350 350
   /* /testdir/testsymlink -> testsubdir/reffile.txt */
351 351
   strpathinrar = itemlist[4]->GetPath();
@@ -432,7 +432,7 @@ TEST(TestRarFile, NormalRAR)
432 432
 
433 433
   /* /reffile.txt */
434 434
   strpathinrar = itemlist[1]->GetPath();
435  
-  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/reffile.txt", true));
  435
+  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/reffile.txt"));
436 436
   EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
437 437
   EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFREG);
438 438
 
@@ -477,7 +477,7 @@ TEST(TestRarFile, NormalRAR)
477 477
 
478 478
   /* /testsymlink -> testdir/reffile.txt */
479 479
   strpathinrar = itemlist[2]->GetPath();
480  
-  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlink", true));
  480
+  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlink"));
481 481
   EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
482 482
   EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFLNK);
483 483
 
@@ -492,7 +492,7 @@ TEST(TestRarFile, NormalRAR)
492 492
 
493 493
   /* /testsymlinksubdir -> testdir/testsubdir/reffile.txt */
494 494
   strpathinrar = itemlist[3]->GetPath();
495  
-  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlinksubdir", true));
  495
+  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testsymlinksubdir"));
496 496
   EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
497 497
   EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFLNK);
498 498
 
@@ -502,7 +502,7 @@ TEST(TestRarFile, NormalRAR)
502 502
 
503 503
   /* /testdir/ */
504 504
   strpathinrar = itemlist[0]->GetPath();
505  
-  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/", true));
  505
+  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/"));
506 506
   EXPECT_EQ(0, XFILE::CFile::Stat(strpathinrar, &stat_buffer));
507 507
   EXPECT_TRUE((stat_buffer.st_mode & S_IFMT) | S_IFDIR);
508 508
 
@@ -567,7 +567,7 @@ TEST(TestRarFile, NormalRAR)
567 567
 
568 568
   /* FIXME: This directory appears a second time as a file */
569 569
   strpathinrar = itemlist[3]->GetPath();
570  
-  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/testsubdir", true));
  570
+  ASSERT_TRUE(StringUtils::EndsWith(strpathinrar, "/testdir/testsubdir"));
571 571
 
572 572
   /* /testdir/testsymlink -> testsubdir/reffile.txt */
573 573
   strpathinrar = itemlist[4]->GetPath();
2  xbmc/interfaces/generic/ScriptInvocationManager.cpp
@@ -122,7 +122,7 @@ void CScriptInvocationManager::RegisterLanguageInvocationHandler(ILanguageInvoca
122 122
 
123 123
   string ext = extension;
124 124
   StringUtils::ToLower(ext);
125  
-  if (!StringUtils::StartsWith(ext, "."))
  125
+  if (!StringUtils::StartsWithNoCase(ext, "."))
126 126
     ext = "." + ext;
127 127
 
128 128
   CSingleLock lock(m_critSection);
2  xbmc/music/windows/GUIWindowMusicBase.cpp
@@ -1154,7 +1154,7 @@ bool CGUIWindowMusicBase::CheckFilterAdvanced(CFileItemList &items) const
1154 1154
 
1155 1155
 bool CGUIWindowMusicBase::CanContainFilter(const CStdString &strDirectory) const
1156 1156
 {
1157  
-  return StringUtils::StartsWith(strDirectory, "musicdb://");
  1157
+  return StringUtils::StartsWithNoCase(strDirectory, "musicdb://");
1158 1158
 }
1159 1159
 
1160 1160
 void CGUIWindowMusicBase::OnInitWindow()
6  xbmc/music/windows/GUIWindowMusicNav.cpp
@@ -447,7 +447,7 @@ void CGUIWindowMusicNav::GetContextButtons(int itemNumber, CContextButtons &butt
447 447
     {
448 448
       if (!item->m_bIsFolder) // music video
449 449
        buttons.Add(CONTEXT_BUTTON_INFO, 20393);
450  
-      if (StringUtils::StartsWith(item->GetPath(), "videodb://musicvideos/artist/") && item->m_bIsFolder)
  450
+      if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/artist/") && item->m_bIsFolder)
451 451
       {
452 452
         long idArtist = m_musicdatabase.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
453 453
         if (idArtist > - 1)
@@ -565,7 +565,7 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
565 565
         return CGUIWindowMusicBase::OnContextButton(itemNumber,button);
566 566
 
567 567
       // music videos - artists
568  
-      if (StringUtils::StartsWith(item->GetPath(), "videodb://musicvideos/artists/"))
  568
+      if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/artists/"))
569 569
       {
570 570
         long idArtist = m_musicdatabase.GetArtistByName(item->GetLabel());
571 571
         if (idArtist == -1)
@@ -582,7 +582,7 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
582 582
       }
583 583
 
584 584
       // music videos - albums
585  
-      if (StringUtils::StartsWith(item->GetPath(), "videodb://musicvideos/albums/"))
  585
+      if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/albums/"))
586 586
       {
587 587
         long idAlbum = m_musicdatabase.GetAlbumByName(item->GetLabel());
588 588
         if (idAlbum == -1)
2  xbmc/network/WebServer.cpp
@@ -965,7 +965,7 @@ int64_t CWebServer::ParseRangeHeader(const std::string &rangeHeaderValue, int64_
965 965
   firstPosition = 0;
966 966
   lastPosition = totalLength - 1;
967 967
 
968  
-  if (rangeHeaderValue.empty() || !StringUtils::StartsWith(rangeHeaderValue, "bytes="))
  968
+  if (rangeHeaderValue.empty() || !StringUtils::StartsWithNoCase(rangeHeaderValue, "bytes="))
969 969
     return totalLength;
970 970
 
971 971
   int64_t rangesLength = 0;
18  xbmc/network/upnp/UPnPServer.cpp
@@ -547,7 +547,7 @@ CUPnPServer::OnBrowseMetadata(PLT_ActionReference&          action,
547 547
 
548 548
         // attempt to determine the parent of this item
549 549
         CStdString parent;
550  
-        if (URIUtils::IsVideoDb((const char*)id) || URIUtils::IsMusicDb((const char*)id) || StringUtils::StartsWith((const char*)id, "library://video/")) {
  550
+        if (URIUtils::IsVideoDb((const char*)id) || URIUtils::IsMusicDb((const char*)id) || StringUtils::StartsWithNoCase((const char*)id, "library://video/")) {
551 551
             if (!URIUtils::GetParentPath((const char*)id, parent)) {
552 552
                 parent = "0";
553 553
             }
@@ -560,11 +560,11 @@ CUPnPServer::OnBrowseMetadata(PLT_ActionReference&          action,
560 560
             // however this is quicker to implement and subsequently purge when a
561 561
             // better solution presents itself
562 562
             CStdString child_id((const char*)id);
563  
-            if      (StringUtils::StartsWith(child_id, "special://musicplaylists/"))          parent = "musicdb://";
564  
-            else if (StringUtils::StartsWith(child_id, "special://videoplaylists/"))          parent = "library://video/";
565  
-            else if (StringUtils::StartsWith(child_id, "sources://video/"))                   parent = "library://video/";
566  
-            else if (StringUtils::StartsWith(child_id, "special://profile/playlists/music/")) parent = "special://musicplaylists/";
567  
-            else if (StringUtils::StartsWith(child_id, "special://profile/playlists/video/")) parent = "special://videoplaylists/";
  563
+            if      (StringUtils::StartsWithNoCase(child_id, "special://musicplaylists/"))          parent = "musicdb://";
  564
+            else if (StringUtils::StartsWithNoCase(child_id, "special://videoplaylists/"))          parent = "library://video/";
  565
+            else if (StringUtils::StartsWithNoCase(child_id, "sources://video/"))                   parent = "library://video/";
  566
+            else if (StringUtils::StartsWithNoCase(child_id, "special://profile/playlists/music/")) parent = "special://musicplaylists/";
  567
+            else if (StringUtils::StartsWithNoCase(child_id, "special://profile/playlists/video/")) parent = "special://videoplaylists/";
568 568
             else parent = "sources://video/"; // this can only match video sources
569 569
         }
570 570
 
@@ -729,13 +729,13 @@ CUPnPServer::BuildResponse(PLT_ActionReference&          action,
729 729
     NPT_Reference<CThumbLoader> thumb_loader;
730 730
 
731 731
     if (URIUtils::IsVideoDb(items.GetPath()) ||
732  
-        StringUtils::StartsWith(items.GetPath(), "library://video/") ||
733  
-        StringUtils::StartsWith(items.GetPath(), "special://profile/playlists/video/")) {
  732
+        StringUtils::StartsWithNoCase(items.GetPath(), "library://video/") ||
  733
+        StringUtils::StartsWithNoCase(items.GetPath(), "special://profile/playlists/video/")) {
734 734
 
735 735
         thumb_loader = NPT_Reference<CThumbLoader>(new CVideoThumbLoader());
736 736
     }
737 737
     else if (URIUtils::IsMusicDb(items.GetPath()) ||
738  
-        StringUtils::StartsWith(items.GetPath(), "special://profile/playlists/music/")) {
  738
+        StringUtils::StartsWithNoCase(items.GetPath(), "special://profile/playlists/music/")) {
739 739
 
740 740
         thumb_loader = NPT_Reference<CThumbLoader>(new CMusicThumbLoader());
741 741
     }
4  xbmc/settings/SettingDependency.cpp
@@ -131,12 +131,12 @@ bool CSettingDependencyCondition::setTarget(const std::string &target)
131 131
 bool CSettingDependencyCondition::setOperator(const std::string &op)
132 132
 {
133 133
   size_t length = 0;
134  
-  if (StringUtils::EndsWith(op, "is"))
  134
+  if (StringUtils::EndsWithNoCase(op, "is"))
135 135
   {
136 136
     m_operator = SettingDependencyOperatorEquals;
137 137
     length = 2;
138 138
   }
139  
-  else if (StringUtils::EndsWith(op, "contains"))
  139
+  else if (StringUtils::EndsWithNoCase(op, "contains"))
140 140
   {
141 141
     m_operator = SettingDependencyOperatorContains;
142 142
     length = 8;
2  xbmc/settings/SettingsManager.cpp
@@ -476,7 +476,7 @@ bool CSettingsManager::GetBool(const std::string &id) const
476 476
   if (setting == NULL || setting->GetType() != SettingTypeBool)
477 477
   {
478 478
     // Backward compatibility (skins use this setting)
479  
-    if (setting == NULL && StringUtils::EqualsNoCase(id.c_str(), "lookandfeel.enablemouse"))
  479
+    if (setting == NULL && StringUtils::EqualsNoCase(id, "lookandfeel.enablemouse"))
480 480
       return GetBool("input.enablemouse");
481 481
 
482 482
     return false;
4  xbmc/settings/SkinSettings.cpp
@@ -175,13 +175,13 @@ void CSkinSettings::Reset()
175 175
   // clear all the settings and strings from this skin.
176 176
   for (map<int, CSkinBool>::iterator it = m_bools.begin(); it != m_bools.end(); ++it)
177 177
   {
178  
-    if (StringUtils::StartsWith(it->second.name, currentSkin))
  178
+    if (StringUtils::StartsWithNoCase(it->second.name, currentSkin))
179 179
       it->second.value = false;
180 180
   }
181 181
 
182 182
   for (map<int, CSkinString>::iterator it = m_strings.begin(); it != m_strings.end(); ++it)
183 183
   {
184  
-    if (StringUtils::StartsWith(it->second.name, currentSkin))
  184
+    if (StringUtils::StartsWithNoCase(it->second.name, currentSkin))
185 185
       it->second.value.clear();
186 186
   }
187 187
 
22  xbmc/utils/FileUtils.cpp
@@ -116,27 +116,27 @@ bool CFileUtils::RemoteAccessAllowed(const CStdString &strPath)
116 116
   while (URIUtils::IsInArchive(realPath))
117 117
     realPath = CURL(realPath).GetHostName();
118 118
 
119  
-  if (StringUtils::StartsWith(realPath, "virtualpath://upnproot/"))
  119
+  if (StringUtils::StartsWithNoCase(realPath, "virtualpath://upnproot/"))
120 120
     return true;
121  
-  else if (StringUtils::StartsWith(realPath, "musicdb://"))
  121
+  else if (StringUtils::StartsWithNoCase(realPath, "musicdb://"))
122 122
     return true;
123  
-  else if (StringUtils::StartsWith(realPath, "videodb://"))
  123
+  else if (StringUtils::StartsWithNoCase(realPath, "videodb://"))
124 124
     return true;
125  
-  else if (StringUtils::StartsWith(realPath, "library://video"))
  125
+  else if (StringUtils::StartsWithNoCase(realPath, "library://video"))
126 126
     return true;
127  
-  else if (StringUtils::StartsWith(realPath, "sources://video"))
  127
+  else if (StringUtils::StartsWithNoCase(realPath, "sources://video"))
128 128
     return true;
129  
-  else if (StringUtils::StartsWith(realPath, "special://musicplaylists"))
  129
+  else if (StringUtils::StartsWithNoCase(realPath, "special://musicplaylists"))
130 130
     return true;
131  
-  else if (StringUtils::StartsWith(realPath, "special://profile/playlists"))
  131
+  else if (StringUtils::StartsWithNoCase(realPath, "special://profile/playlists"))
132 132
     return true;
133  
-  else if (StringUtils::StartsWith(realPath, "special://videoplaylists"))
  133
+  else if (StringUtils::StartsWithNoCase(realPath, "special://videoplaylists"))
134 134
     return true;
135  
-  else if (StringUtils::StartsWith(realPath, "addons://sources"))
  135
+  else if (StringUtils::StartsWithNoCase(realPath, "addons://sources"))
136 136
     return true;
137  
-  else if (StringUtils::StartsWith(realPath, "upnp://"))
  137
+  else if (StringUtils::StartsWithNoCase(realPath, "upnp://"))
138 138
     return true;
139  
-  else if (StringUtils::StartsWith(realPath, "plugin://"))
  139
+  else if (StringUtils::StartsWithNoCase(realPath, "plugin://"))
140 140
     return true;
141 141
   bool isSource;
142 142
   for (unsigned int index = 0; index < SourcesSize; index++)
2  xbmc/utils/LegacyPathTranslation.cpp
@@ -95,7 +95,7 @@ std::string CLegacyPathTranslation::TranslatePath(const std::string &legacyPath,
95 95
   std::string newPath = legacyPath;
96 96
   for (size_t index = 0; index < translationMapSize; index++)
97 97
   {
98  
-    if (StringUtils::StartsWith(newPath, translationMap[index].legacyPath))
  98
+    if (StringUtils::StartsWithNoCase(newPath, translationMap[index].legacyPath))
99 99
     {
100 100
       StringUtils::Replace(newPath, translationMap[index].legacyPath, translationMap[index].newPath);
101 101
       break;
121  xbmc/utils/StringUtils.cpp
@@ -114,12 +114,26 @@ void StringUtils::ToLower(string &str)
114 114
 
115 115
 bool StringUtils::EqualsNoCase(const std::string &str1, const std::string &str2)
116 116
 {
117  
-  string tmp1 = str1;
118  
-  string tmp2 = str2;
119  
-  ToLower(tmp1);
120  
-  ToLower(tmp2);
121  
-  
122  
-  return tmp1.compare(tmp2) == 0;
  117
+  return EqualsNoCase(str1.c_str(), str2.c_str());
  118
+}
  119
+
  120
+bool StringUtils::EqualsNoCase(const std::string &str1, const char *s2)
  121
+{
  122
+  return EqualsNoCase(str1.c_str(), s2);
  123
+}
  124
+
  125
+bool StringUtils::EqualsNoCase(const char *s1, const char *s2)
  126
+{
  127
+  int c1, c2; // Yes, because the return type of tolower() is int.
  128
+              // To make these chars would be to introduce an unnecesary extra bitmask/zero-extend (effectively caller-narowing) into the binary.
  129
+  do
  130
+  {
  131
+    c1 = ::tolower(*s1++);
  132
+    c2 = ::tolower(*s2++);
  133
+    if (c1 != c2) // This includes the possibility that one of the characters is the null-terminator, which implies a string mismatch.
  134
+      return false;
  135
+  } while (c2 != '\0'); // At this point, we know c1 == c2, so there's no need to test them both.
  136
+  return true;
123 137
 }
124 138
 
125 139
 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:
225 239
   return replacedChars;
226 240
 }
227 241
 
228  
-bool StringUtils::StartsWith(const std::string &str, const std::string &str2, bool useCase /* = false */)
  242
+bool StringUtils::StartsWith(const std::string &str1, const std::string &str2)
229 243
 {
230  
-  std::string left = StringUtils::Left(str, str2.size());
231  
-  
232  
-  if (useCase)
233  
-    return left.compare(str2) == 0;
  244
+  return str1.compare(0, str2.size(), str2) == 0;
  245
+}
234 246
 
235  
-  return StringUtils::EqualsNoCase(left, str2);
  247
+bool StringUtils::StartsWith(const std::string &str1, const char *s2)
  248
+{
  249
+  return StartsWith(str1.c_str(), s2);
236 250
 }
237 251
 
238  
-bool StringUtils::EndsWith(const std::string &str, const std::string &str2, bool useCase /* = false */)
  252
+bool StringUtils::StartsWith(const char *s1, const char *s2)
239 253
 {
240  
-  std::string right = StringUtils::Right(str, str2.size());
241  
-  
242  
-  if (useCase)
243  
-    return right.compare(str2) == 0;
  254
+  while (*s2 != '\0')
  255
+  {
  256
+    if (*s1 != *s2)
  257
+      return false;
  258
+    s1++;
  259
+    s2++;
  260
+  }
  261
+  return true;
  262
+}
244 263
 
245  
-  return StringUtils::EqualsNoCase(right, str2);
  264
+bool StringUtils::StartsWithNoCase(const std::string &str1, const std::string &str2)
  265
+{
  266
+  return StartsWithNoCase(str1.c_str(), str2.c_str());
  267
+}
  268
+
  269
+bool StringUtils::StartsWithNoCase(const std::string &str1, const char *s2)
  270
+{
  271
+  return StartsWithNoCase(str1.c_str(), s2);
  272
+}
  273
+
  274
+bool StringUtils::StartsWithNoCase(const char *s1, const char *s2)
  275
+{
  276
+  while (*s2 != '\0')
  277
+  {
  278
+    if (::tolower(*s1) != ::tolower(*s2))
  279
+      return false;
  280
+    s1++;
  281
+    s2++;
  282
+  }
  283
+  return true;
  284
+}
  285
+
  286
+bool StringUtils::EndsWith(const std::string &str1, const std::string &str2)
  287
+{
  288
+  if (str1.size() < str2.size())
  289
+    return false;
  290
+  return str1.compare(str1.size() - str2.size(), str2.size(), str2) == 0;
  291
+}
  292
+
  293
+bool StringUtils::EndsWith(const std::string &str1, const char *s2)
  294
+{
  295
+  size_t len2 = strlen(s2);
  296
+  if (str1.size() < len2)
  297
+    return false;
  298
+  return str1.compare(str1.size() - len2, len2, s2) == 0;
  299
+}
  300
+
  301
+bool StringUtils::EndsWithNoCase(const std::string &str1, const std::string &str2)
  302
+{
  303
+  if (str1.size() < str2.size())
  304
+    return false;
  305
+  const char *s1 = str1.c_str() + str1.size() - str2.size();
  306
+  const char *s2 = str2.c_str();
  307
+  while (*s2 != '\0')
  308
+  {
  309
+    if (::tolower(*s1) != ::tolower(*s2))
  310
+      return false;
  311
+    s1++;
  312
+    s2++;
  313
+  }
  314
+  return true;
  315
+}
  316
+
  317
+bool StringUtils::EndsWithNoCase(const std::string &str1, const char *s2)
  318
+{
  319
+  size_t len2 = strlen(s2);
  320
+  if (str1.size() < len2)
  321
+    return false;
  322
+  const char *s1 = str1.c_str() + str1.size() - len2;
  323
+  while (*s2 != '\0')
  324
+  {
  325
+    if (::tolower(*s1) != ::tolower(*s2))
  326
+      return false;
  327
+    s1++;
  328
+    s2++;
  329
+  }
  330
+  return true;
246 331
 }
247 332
 
248 333
 void StringUtils::JoinString(const CStdStringArray &strings, const CStdString& delimiter, CStdString& result)
14  xbmc/utils/StringUtils.h
@@ -55,6 +55,8 @@ class StringUtils
55 55
   static void ToUpper(std::string &str);
56 56
   static void ToLower(std::string &str);
57 57
   static bool EqualsNoCase(const std::string &str1, const std::string &str2);
  58
+  static bool EqualsNoCase(const std::string &str1, const char *s2);
  59
+  static bool EqualsNoCase(const char *s1, const char *s2);
58 60
   static std::string Left(const std::string &str, size_t count);
59 61
   static std::string Mid(const std::string &str, size_t first, size_t count = std::string::npos);
60 62
   static std::string Right(const std::string &str, size_t count);
@@ -64,8 +66,16 @@ class StringUtils
64 66
   static std::string& RemoveDuplicatedSpacesAndTabs(std::string& str);
65 67
   static int Replace(std::string &str, char oldChar, char newChar);
66 68
   static int Replace(std::string &str, const std::string &oldStr, const std::string &newStr);
67  
-  static bool StartsWith(const std::string &str, const std::string &str2, bool useCase = false);
68  
-  static bool EndsWith(const std::string &str, const std::string &str2, bool useCase = false);
  69
+  static bool StartsWith(const std::string &str1, const std::string &str2);
  70
+  static bool StartsWith(const std::string &str1, const char *s2);
  71
+  static bool StartsWith(const char *s1, const char *s2);
  72
+  static bool StartsWithNoCase(const std::string &str1, const std::string &str2);
  73
+  static bool StartsWithNoCase(const std::string &str1, const char *s2);
  74
+  static bool StartsWithNoCase(const char *s1, const char *s2);
  75
+  static bool EndsWith(const std::string &str1, const std::string &str2);
  76
+  static bool EndsWith(const std::string &str1, const char *s2);
  77
+  static bool EndsWithNoCase(const std::string &str1, const std::string &str2);
  78
+  static bool EndsWithNoCase(const std::string &str1, const char *s2);
69 79
 
70 80
   static void JoinString(const CStdStringArray &strings, const CStdString& delimiter, CStdString& result);
71 81
   static CStdString JoinString(const CStdStringArray &strings, const CStdString& delimiter);
2  xbmc/utils/StringValidation.cpp
@@ -37,7 +37,7 @@ bool StringValidation::IsTime(const std::string &input, void *data)
37 37
   std::string strTime = input;
38 38
   StringUtils::Trim(strTime);
39 39
 
40  
-  if (StringUtils::EndsWith(strTime, " min"))
  40
+  if (StringUtils::EndsWithNoCase(strTime, " min"))
41 41
   {
42 42
     strTime = StringUtils::Left(strTime, strTime.size() - 4);
43 43
     StringUtils::TrimRight(strTime);
24  xbmc/utils/test/TestStringUtils.cpp
@@ -175,28 +175,28 @@ TEST(TestStringUtils, StartsWith)
175 175
 {
176 176
   std::string refstr = "test";
177 177
   
178  
-  EXPECT_FALSE(StringUtils::StartsWith(refstr, "x"));
  178
+  EXPECT_FALSE(StringUtils::StartsWithNoCase(refstr, "x"));
179 179
   
180  
-  EXPECT_TRUE(StringUtils::StartsWith(refstr, "te", true));
181  
-  EXPECT_TRUE(StringUtils::StartsWith(refstr, "test", true));
182  
-  EXPECT_FALSE(StringUtils::StartsWith(refstr, "Te", true));
  180
+  EXPECT_TRUE(StringUtils::StartsWith(refstr, "te"));
  181
+  EXPECT_TRUE(StringUtils::StartsWith(refstr, "test"));
  182
+  EXPECT_FALSE(StringUtils::StartsWith(refstr, "Te"));
183 183
   
184  
-  EXPECT_TRUE(StringUtils::StartsWith(refstr, "Te", false));
185  
-  EXPECT_TRUE(StringUtils::StartsWith(refstr, "TesT", false));
  184
+  EXPECT_TRUE(StringUtils::StartsWithNoCase(refstr, "Te"));
  185
+  EXPECT_TRUE(StringUtils::StartsWithNoCase(refstr, "TesT"));
186 186
 }
187 187
 
188 188
 TEST(TestStringUtils, EndsWith)
189 189
 {
190 190
   std::string refstr = "test";
191 191
   
192  
-  EXPECT_FALSE(StringUtils::EndsWith(refstr, "x"));
  192
+  EXPECT_FALSE(StringUtils::EndsWithNoCase(refstr, "x"));
193 193
   
194  
-  EXPECT_TRUE(StringUtils::EndsWith(refstr, "st", true));
195  
-  EXPECT_TRUE(StringUtils::EndsWith(refstr, "test", true));
196  
-  EXPECT_FALSE(StringUtils::EndsWith(refstr, "sT", true));
  194
+  EXPECT_TRUE(StringUtils::EndsWith(refstr, "st"));
  195
+  EXPECT_TRUE(StringUtils::EndsWith(refstr, "test"));
  196
+  EXPECT_FALSE(StringUtils::EndsWith(refstr, "sT"));
197 197
   
198  
-  EXPECT_TRUE(StringUtils::EndsWith(refstr, "sT", false));
199  
-  EXPECT_TRUE(StringUtils::EndsWith(refstr, "TesT", false));
  198
+  EXPECT_TRUE(StringUtils::EndsWithNoCase(refstr, "sT"));
  199
+  EXPECT_TRUE(StringUtils::EndsWithNoCase(refstr, "TesT"));
200 200
 }
201 201
 
202 202
 TEST(TestStringUtils, JoinString)
2  xbmc/video/windows/GUIWindowVideoBase.cpp
@@ -1791,7 +1791,7 @@ bool CGUIWindowVideoBase::CheckFilterAdvanced(CFileItemList &items) const
1791 1791
 
1792 1792
 bool CGUIWindowVideoBase::CanContainFilter(const CStdString &strDirectory) const
1793 1793
 {
1794  
-  return StringUtils::StartsWith(strDirectory, "videodb://");
  1794
+  return StringUtils::StartsWithNoCase(strDirectory, "videodb://");
1795 1795
 }
1796 1796
 
1797 1797
 void CGUIWindowVideoBase::AddToDatabase(int iItem)
6  xbmc/video/windows/GUIWindowVideoNav.cpp
@@ -674,7 +674,7 @@ void CGUIWindowVideoNav::OnDeleteItem(CFileItemPtr pItem)
674 674
         !pItem->GetPath().Left(9).Equals("newtag://"))
675 675
       CGUIWindowVideoBase::OnDeleteItem(pItem);
676 676
   }
677  
-  else if (StringUtils::StartsWith(pItem->GetPath(), "videodb://movies/sets/") &&
  677
+  else if (StringUtils::StartsWithNoCase(pItem->GetPath(), "videodb://movies/sets/") &&
678 678
            pItem->GetPath().size() > 22 && pItem->m_bIsFolder)
679 679
   {
680 680
     CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
@@ -967,7 +967,7 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt
967 967
         if (node == NODE_TYPE_SEASONS && item->m_bIsFolder)
968 968
           buttons.Add(CONTEXT_BUTTON_SET_SEASON_ART, 13511);
969 969
 
970  
-        if (StringUtils::StartsWith(item->GetPath(), "videodb://movies/sets/") && item->GetPath().size() > 22 && item->m_bIsFolder) // sets
  970
+        if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://movies/sets/") && item->GetPath().size() > 22 && item->m_bIsFolder) // sets
971 971
         {
972 972
           buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_ART, 13511);
973 973
           buttons.Add(CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS, 20465);
@@ -991,7 +991,7 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt
991 991
 
992 992
         if (node == NODE_TYPE_ACTOR && !dir.IsAllItem(item->GetPath()) && item->m_bIsFolder)
993 993
         {
994  
-          if (StringUtils::StartsWith(m_vecItems->GetPath(), "videodb://musicvideos")) // mvids
  994
+          if (StringUtils::StartsWithNoCase(m_vecItems->GetPath(), "videodb://musicvideos")) // mvids
995 995
             buttons.Add(CONTEXT_BUTTON_SET_ARTIST_THUMB, 13359);
996 996
           else
997 997
             buttons.Add(CONTEXT_BUTTON_SET_ACTOR_THUMB, 20403);
4  xbmc/view/ViewDatabase.cpp
@@ -93,9 +93,9 @@ bool CViewDatabase::UpdateOldVersion(int version)
93 93
       {
94 94
         std::string originalPath = m_pDS->fv(1).get_asString();
95 95
         std::string path = originalPath;
96  
-        if (StringUtils::StartsWith(path, "musicdb://"))
  96
+        if (StringUtils::StartsWithNoCase(path, "musicdb://"))
97 97
           path = CLegacyPathTranslation::TranslateMusicDbPath(path);
98  
-        else if (StringUtils::StartsWith(path, "videodb://"))
  98
+        else if (StringUtils::StartsWithNoCase(path, "videodb://"))
99 99
           path = CLegacyPathTranslation::TranslateVideoDbPath(path);
100 100
 
101 101
         if (!StringUtils::EqualsNoCase(path, originalPath))

0 notes on commit 02fd1ab

Please sign in to comment.
Something went wrong with that request. Please try again.