xbmc/xbmc — pull request #3290 by bavison (2013-09-18 12:34:12+00:00)
Title: Faster substring comparisons

There were nearly 200 places in the code where testing for a substring was
being performed using a construct of the form
CStdString::Left(len).Equals("string")
or the related CStdString methods Mid or Right. These are bad for performance
because they involve allocating a heap block for the duration of the
expression evaluation, for the purpose of holding the substring, and then
freeing it again.

Aware that CStdString is being phased out (PR #3225), I have replaced these
where possible with calls to std::string::compare - this amounted to cases
where comparison was against a string literal containing no alphabetic
characters. In theory, calls of CStdString::Equals with the optional bUseCase
parameter set true would have been other candidates for this, but there were
none (at least not in conjunction with Left(), Mid() or Right()).

The remaining cases need to be case-insenitive comparisons, for
compatibility's sake. std::string doesn't have case-insensitive comparisons,
so I have added a couple of extra methods to StringUtils:

* SubstringEqualsNoCase(), similar to the existing EqualsNoCase() but
specifying an offset and length into the first string.

* ToLowerSubstringEquals(), used in by far the most common case, where the
second string was a string literal. This uses a C string parameter to avoid
having to construct a std::string in order to call it. It also assumes that
the string literal is already in lower case, to halve the number of
tolower() calls needed. This was already true of the majority of string
literals, and I have changed the remainder to match.

I noted that StringUtils::EqualsNoCase would benefit from being reimplemented
in a similar way to SubstringEqualsNoCase to avoid unnecessary heap
operations, but that is not part of this commit.

The majority of the changes here were achieved using a sophisticated search
and replace, which will hopefully minimise any bugs introduced in the
conversion.

This patch is expected to have wide-reaching performance benefits. One
benchmark (that can't pretend to exercise all ~200 improvements) is the time
to open the songs library: on a Raspberry Pi, this patch improves this time
- specificaly, in CGUIMediaWindow::Update - from 11.7 to 10.4 seconds (that's
a 13% speedup) with a library of 4100 songs. (The standard deviation on those
measurements is 0.1 seconds).