This is a combination of running clang-tidy with modernize-use-nullptr check for some ports (GTK, X11, OSX) and manual changes to the ports for which it couldn't be used easily (MSW, DFB) and also manually updating the docs. Also replace NULL with null or nullptr in the comments as this is more consistent with the use of nullptr in the code and makes it simpler to grep for the remaining occurrences of NULL itself. And also use null in the assert messages. Only a few occurrences of "NULL" are still left in non-C files, mostly corresponding to unclear comments or string output which it might not be safe to change.
455 lines
11 KiB
C++
455 lines
11 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: tests/benchmarks/strings.cpp
|
|
// Purpose: String-related benchmarks
|
|
// Author: Vadim Zeitlin
|
|
// Created: 2008-07-19
|
|
// Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "wx/string.h"
|
|
#include "wx/ffile.h"
|
|
|
|
#include "bench.h"
|
|
#include "htmlparser/htmlpars.h"
|
|
|
|
static const char asciistr[] =
|
|
"This is just the first line of a very long 7 bit ASCII string"
|
|
"This is just the second line of a very long 7 bit ASCII string"
|
|
"This is just the third line of a very long 7 bit ASCII string"
|
|
"This is just the fourth line of a very long 7 bit ASCII string"
|
|
"This is just the fifth line of a very long 7 bit ASCII string"
|
|
"This is just the sixth line of a very long 7 bit ASCII string"
|
|
"This is just the seventh line of a very long 7 bit ASCII string"
|
|
"This is just the eighth line of a very long 7 bit ASCII string"
|
|
"This is just the ninth line of a very long 7 bit ASCII string"
|
|
"This is just the tenth line of a very long 7 bit ASCII string"
|
|
;
|
|
|
|
static const char utf8str[] =
|
|
"\xD0\xA6\xD0\xB5\xD0\xBB\xD0\xBE\xD0\xB5 \xD1\x87\xD0\xB8\xD1\x81\xD0\xBB\xD0\xBE 0"
|
|
"\xD0\xA6\xD0\xB5\xD0\xBB\xD0\xBE\xD0\xB5 \xD1\x87\xD0\xB8\xD1\x81\xD0\xBB\xD0\xBE 1"
|
|
"\xD0\xA6\xD0\xB5\xD0\xBB\xD0\xBE\xD0\xB5 \xD1\x87\xD0\xB8\xD1\x81\xD0\xBB\xD0\xBE 2"
|
|
"\xD0\xA6\xD0\xB5\xD0\xBB\xD0\xBE\xD0\xB5 \xD1\x87\xD0\xB8\xD1\x81\xD0\xBB\xD0\xBE 3"
|
|
"\xD0\xA6\xD0\xB5\xD0\xBB\xD0\xBE\xD0\xB5 \xD1\x87\xD0\xB8\xD1\x81\xD0\xBB\xD0\xBE 4"
|
|
"\xD0\xA6\xD0\xB5\xD0\xBB\xD0\xBE\xD0\xB5 \xD1\x87\xD0\xB8\xD1\x81\xD0\xBB\xD0\xBE 5"
|
|
"\xD0\xA6\xD0\xB5\xD0\xBB\xD0\xBE\xD0\xB5 \xD1\x87\xD0\xB8\xD1\x81\xD0\xBB\xD0\xBE 6"
|
|
"\xD0\xA6\xD0\xB5\xD0\xBB\xD0\xBE\xD0\xB5 \xD1\x87\xD0\xB8\xD1\x81\xD0\xBB\xD0\xBE 7"
|
|
"\xD0\xA6\xD0\xB5\xD0\xBB\xD0\xBE\xD0\xB5 \xD1\x87\xD0\xB8\xD1\x81\xD0\xBB\xD0\xBE 8"
|
|
"\xD0\xA6\xD0\xB5\xD0\xBB\xD0\xBE\xD0\xB5 \xD1\x87\xD0\xB8\xD1\x81\xD0\xBB\xD0\xBE 9"
|
|
;
|
|
|
|
namespace
|
|
{
|
|
|
|
const wxString& GetTestAsciiString()
|
|
{
|
|
static wxString testString;
|
|
if ( testString.empty() )
|
|
{
|
|
long num = Bench::GetNumericParameter();
|
|
if ( !num )
|
|
num = 1;
|
|
|
|
for ( long n = 0; n < num; n++ )
|
|
testString += wxString::FromAscii(asciistr);
|
|
}
|
|
|
|
return testString;
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
// this is just a baseline
|
|
BENCHMARK_FUNC(Strlen)
|
|
{
|
|
if ( strlen(utf8str) != WXSIZEOF(utf8str) - 1 )
|
|
return false;
|
|
|
|
if ( strlen(asciistr) != WXSIZEOF(asciistr) - 1 )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// FromUTF8() benchmarks
|
|
// ----------------------------------------------------------------------------
|
|
|
|
BENCHMARK_FUNC(FromUTF8)
|
|
{
|
|
wxString s = wxString::FromUTF8(utf8str);
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
s = wxString::FromUTF8(asciistr);
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
BENCHMARK_FUNC(FromUTF8WithNpos)
|
|
{
|
|
wxString s = wxString::FromUTF8(utf8str, wxString::npos);
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
s = wxString::FromUTF8(asciistr, wxString::npos);
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
BENCHMARK_FUNC(FromUTF8WithLen)
|
|
{
|
|
wxString s = wxString::FromUTF8(utf8str, WXSIZEOF(utf8str));
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
s = wxString::FromUTF8(asciistr, WXSIZEOF(asciistr));
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// FromUTF8Unchecked() benchmarks
|
|
// ----------------------------------------------------------------------------
|
|
|
|
BENCHMARK_FUNC(FromUTF8Unchecked)
|
|
{
|
|
wxString s = wxString::FromUTF8Unchecked(utf8str);
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
s = wxString::FromUTF8Unchecked(asciistr);
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
BENCHMARK_FUNC(FromUTF8UncheckedWithNpos)
|
|
{
|
|
wxString s = wxString::FromUTF8Unchecked(utf8str, wxString::npos);
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
s = wxString::FromUTF8Unchecked(asciistr, wxString::npos);
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
BENCHMARK_FUNC(FromUTF8UncheckedWithLen)
|
|
{
|
|
wxString s = wxString::FromUTF8Unchecked(utf8str, WXSIZEOF(utf8str));
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
s = wxString::FromUTF8Unchecked(asciistr, WXSIZEOF(asciistr));
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// FromAscii() benchmarks
|
|
// ----------------------------------------------------------------------------
|
|
|
|
BENCHMARK_FUNC(FromAscii)
|
|
{
|
|
wxString s = wxString::FromAscii(asciistr);
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
BENCHMARK_FUNC(FromAsciiWithNpos)
|
|
{
|
|
wxString s = wxString::FromAscii(asciistr);
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
BENCHMARK_FUNC(FromAsciiWithLen)
|
|
{
|
|
wxString s = wxString::FromAscii(asciistr, WXSIZEOF(asciistr));
|
|
if ( s.empty() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// simple string iteration
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// baseline
|
|
BENCHMARK_FUNC(ForCString)
|
|
{
|
|
for ( size_t n = 0; n < WXSIZEOF(asciistr); n++ )
|
|
{
|
|
if ( asciistr[n] == '~' )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
BENCHMARK_FUNC(ForStringIndex)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
const size_t len = s.length();
|
|
for ( size_t n = 0; n < len; n++ )
|
|
{
|
|
if ( s[n] == '~' )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
BENCHMARK_FUNC(ForStringIter)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
const wxString::const_iterator end = s.end();
|
|
for ( wxString::const_iterator i = s.begin(); i != end; ++i )
|
|
{
|
|
if ( *i == '~' )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
BENCHMARK_FUNC(ForStringRIter)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
const wxString::const_reverse_iterator rend = s.rend();
|
|
for ( wxString::const_reverse_iterator i = s.rbegin(); i != rend; ++i )
|
|
{
|
|
if ( *i == '~' )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxString::Replace()
|
|
// ----------------------------------------------------------------------------
|
|
|
|
const size_t ASCIISTR_LEN = strlen(asciistr);
|
|
|
|
BENCHMARK_FUNC(ReplaceLoop)
|
|
{
|
|
wxString str('x', ASCIISTR_LEN);
|
|
for ( size_t n = 0; n < ASCIISTR_LEN; n++ )
|
|
{
|
|
if ( str[n] == 'a' )
|
|
str[n] = 'z';
|
|
}
|
|
|
|
return str.length() != 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(ReplaceNone)
|
|
{
|
|
wxString str('x', ASCIISTR_LEN);
|
|
return str.Replace("a", "z") == 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(ReplaceSome)
|
|
{
|
|
wxString str(asciistr);
|
|
return str.Replace("7", "8") != 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(ReplaceAll)
|
|
{
|
|
wxString str('x', ASCIISTR_LEN);
|
|
return str.Replace("x", "y") != 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(ReplaceLonger)
|
|
{
|
|
wxString str('x', ASCIISTR_LEN);
|
|
return str.Replace("x", "yy") != 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(ReplaceShorter)
|
|
{
|
|
wxString str('x', ASCIISTR_LEN);
|
|
return str.Replace("xx", "y") != 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// string case conversion
|
|
// ----------------------------------------------------------------------------
|
|
|
|
BENCHMARK_FUNC(Lower)
|
|
{
|
|
return GetTestAsciiString().Lower().length() > 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(Upper)
|
|
{
|
|
return GetTestAsciiString().Upper().length() > 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// string comparison
|
|
// ----------------------------------------------------------------------------
|
|
|
|
BENCHMARK_FUNC(StrcmpA)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
|
|
return wxCRT_StrcmpA(s.c_str(), s.c_str()) == 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(StrcmpW)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
|
|
return wxCRT_StrcmpW(s.wc_str(), s.wc_str()) == 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(StricmpA)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
|
|
return wxCRT_StricmpA(s.c_str(), s.c_str()) == 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(StricmpW)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
|
|
return wxCRT_StricmpW(s.wc_str(), s.wc_str()) == 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(StringCmp)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
|
|
return s.Cmp(s) == 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(StringCmpNoCase)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
|
|
return s.CmpNoCase(s) == 0;
|
|
}
|
|
|
|
// Also benchmark various native functions under MSW. Surprisingly/annoyingly
|
|
// they sometimes have vastly better performance than alternatives, especially
|
|
// for case-sensitive comparison (see #10375).
|
|
#ifdef __WINDOWS__
|
|
|
|
#include "wx/msw/wrapwin.h"
|
|
|
|
BENCHMARK_FUNC(MSWlstrcmp)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
|
|
return lstrcmp(s.t_str(), s.t_str()) == 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(MSWlstrcmpi)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
|
|
return lstrcmpi(s.t_str(), s.t_str()) == 0;
|
|
}
|
|
|
|
BENCHMARK_FUNC(MSWCompareString)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
|
|
return ::CompareString
|
|
(
|
|
LOCALE_USER_DEFAULT,
|
|
0,
|
|
s.t_str(), s.length(),
|
|
s.t_str(), s.length()
|
|
) == CSTR_EQUAL;
|
|
}
|
|
|
|
BENCHMARK_FUNC(MSWCompareStringIgnoreCase)
|
|
{
|
|
const wxString& s = GetTestAsciiString();
|
|
|
|
return ::CompareString
|
|
(
|
|
LOCALE_USER_DEFAULT,
|
|
NORM_IGNORECASE,
|
|
s.t_str(), s.length(),
|
|
s.t_str(), s.length()
|
|
) == CSTR_EQUAL;
|
|
}
|
|
|
|
#endif // __WINDOWS__
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// string buffers: wx[W]CharBuffer
|
|
// ----------------------------------------------------------------------------
|
|
|
|
BENCHMARK_FUNC(CharBuffer)
|
|
{
|
|
wxString str(asciistr);
|
|
|
|
// NB: wxStrlen() is here to simulate some use of the returned buffer.
|
|
// Both mb_str() and wc_str() are used so that this code does something
|
|
// nontrivial in any build.
|
|
return wxStrlen(str.mb_str()) == ASCIISTR_LEN &&
|
|
wxStrlen(str.wc_str()) == ASCIISTR_LEN;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxString::operator[] - parse large HTML page
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class DummyParser : public wx28HtmlParser
|
|
{
|
|
public:
|
|
virtual wxObject* GetProduct() { return nullptr; }
|
|
virtual void AddText(const wxChar*) {}
|
|
};
|
|
|
|
|
|
BENCHMARK_FUNC(ParseHTML)
|
|
{
|
|
// static so that construction time is not counted
|
|
static DummyParser parser;
|
|
static wxString html;
|
|
if ( html.empty() )
|
|
{
|
|
wxString html1;
|
|
wxFFile("htmltest.html").ReadAll(&html1, wxConvUTF8);
|
|
|
|
// this is going to make for some invalid HTML, of course, but it
|
|
// doesn't really matter
|
|
long num = Bench::GetNumericParameter();
|
|
if ( !num )
|
|
num = 1;
|
|
|
|
for ( long n = 0; n < num; n++ )
|
|
html += html1;
|
|
}
|
|
|
|
parser.Parse(html);
|
|
|
|
return true;
|
|
}
|