diff options
author | hjk <qtc-committer@nokia.com> | 2009-05-28 11:18:00 (GMT) |
---|---|---|
committer | hjk <qtc-committer@nokia.com> | 2009-05-28 11:38:55 (GMT) |
commit | 3331605529d2d81145259fd56d03bb59c480cac5 (patch) | |
tree | 4c716283b4fa714479a4f923019eaebd948de88a /tests | |
parent | 389ca4b5931efbf2bcac050ec80ec7971b61c857 (diff) | |
download | Qt-3331605529d2d81145259fd56d03bb59c480cac5.zip Qt-3331605529d2d81145259fd56d03bb59c480cac5.tar.gz Qt-3331605529d2d81145259fd56d03bb59c480cac5.tar.bz2 |
Introduce a new class QStringBuilder to speed up the creation of
QString objects from smaller chunks.
The QStringBuilder class:
QStringBuilder uses expression templates (using the '%' operator)
to postpone any actual concatenation until it is assigned to an
actual QString. At that time it knows the exact sizes of all chunks,
can compute the required space, allocates once a QString of
appriopriate size and then copies over the chunk data one-by-one.
In addition, QLatin1Literal is a drop-in replacement for QLatin1String
(which we can't change for compatibility reasons) that knows its
size, therefore saving a few cycles when computing the size of the
resulting string.
Some further saved cycles stem from inlining and reduced reference
counting logic (the QString created from a QStringBuilder has typically
ref count equal to 1, while QString::append() needs an extra test)
Minor changes to the existing QString class:
- Introduce QString constructor to create an uninitialized QString of a given size.
This particular constructor is used by QStringBuilder class.
- Introduce a QT_USE_FAST_CONCATENATION macro to disable the existing
overloads of operator+() and helps finding the places where they are used in code.
- Introduce QT_USE_FAST_OPERATOR_PLUS. This also disables the existing
overloads of operator+() and creates a new templated operator+() with
identical implementation of operator%(). This allows code that is compilable
QT_CAST_{TO,FROM}_ASCII to use QStringBuilder almost transparently. The only
case that is not covered is creating objects like QUrl that are implicitly
constructible from a QString from a QStringBuilder result. This needs to be
converted explicitly to a QString first, e.g. by using QUrl
url(QString(QLatin1String("http://") + hostName));
Reviewed-by: MariusSO
Diffstat (limited to 'tests')
-rw-r--r-- | tests/benchmarks/qstringbuilder/main.cpp | 304 | ||||
-rw-r--r-- | tests/benchmarks/qstringbuilder/qstringbuilder.pro | 12 |
2 files changed, 316 insertions, 0 deletions
diff --git a/tests/benchmarks/qstringbuilder/main.cpp b/tests/benchmarks/qstringbuilder/main.cpp new file mode 100644 index 0000000..cb76925 --- /dev/null +++ b/tests/benchmarks/qstringbuilder/main.cpp @@ -0,0 +1,304 @@ + +#include "qstringbuilder.h" + +#include <QDebug> +#include <QString> + +#include <qtest.h> + + +#define COMPARE(a, b) QCOMPARE(a, b) +//#define COMPARE(a, b) + +#define SEP(s) qDebug() << "\n\n-------- " s " ---------"; +#define L(s) QLatin1String(s) + +class tst_qstringbuilder : public QObject +{ + Q_OBJECT + +public: + tst_qstringbuilder() + : l1literal("some string literal"), + l1string("some string literal"), + ba("some string literal"), + string(l1string), + stringref(&string, 2, 10), + achar('c') + {} + + +public: + enum { N = 10000 }; + + int run_traditional() + { + int s = 0; + for (int i = 0; i < N; ++i) { +#if 0 + s += QString(l1string + l1string).size(); + s += QString(l1string + l1string + l1string).size(); + s += QString(l1string + l1string + l1string + l1string).size(); + s += QString(l1string + l1string + l1string + l1string + l1string).size(); +#endif + s += QString(achar + l1string + achar).size(); + } + return s; + } + + int run_builder() + { + int s = 0; + for (int i = 0; i < N; ++i) { +#if 0 + s += QString(l1literal % l1literal).size(); + s += QString(l1literal % l1literal % l1literal).size(); + s += QString(l1literal % l1literal % l1literal % l1literal).size(); + s += QString(l1literal % l1literal % l1literal % l1literal % l1literal).size(); +#endif + s += QString(achar % l1literal % achar).size(); + } + return s; + } + +private slots: + + void separator_0() { + qDebug() << "\nIn each block the QStringBuilder based result appear first, " + "QStringBased second.\n"; + } + + void separator_1() { SEP("literal + literal (builder first)"); } + + void b_2_l1literal() { + QBENCHMARK { r = l1literal % l1literal; } + COMPARE(r, l1string + l1string); + } + void s_2_l1string() { + QBENCHMARK { r = l1string + l1string; } + COMPARE(r, QString(l1literal % l1literal)); + } + + + void separator_2() { SEP("2 strings"); } + + void b_2_string() { + QBENCHMARK { r = string % string; } + COMPARE(r, string + string); + } + void s_2_string() { + QBENCHMARK { r = string + string; } + COMPARE(r, QString(string % string)); + } + + + void separator_2c() { SEP("2 string refs"); } + + void b_2_stringref() { + QBENCHMARK { r = stringref % stringref; } + COMPARE(r, stringref.toString() + stringref.toString()); + } + void s_2_stringref() { + QBENCHMARK { r = stringref.toString() + stringref.toString(); } + COMPARE(r, QString(stringref % stringref)); + } + + + void separator_2b() { SEP("3 strings"); } + + void b_3_string() { + QBENCHMARK { r = string % string % string; } + COMPARE(r, string + string + string); + } + void s_3_string() { + QBENCHMARK { r = string + string + string; } + COMPARE(r, QString(string % string % string)); + } + + + void separator_2a() { SEP("string + literal (builder first)"); } + + void b_string_l1literal() { + QBENCHMARK { r = string % l1literal; } + COMPARE(r, string + l1string); + } + void b_string_l1string() { + QBENCHMARK { r = string % l1string; } + COMPARE(r, string + l1string); + } + void s_string_l1literal() { + QBENCHMARK { r = string + l1string; } + COMPARE(r, QString(string % l1literal)); + } + void s_string_l1string() { + QBENCHMARK { r = string + l1string; } + COMPARE(r, QString(string % l1literal)); + } + + + void separator_3() { SEP("3 literals"); } + + void b_3_l1literal() { + QBENCHMARK { r = l1literal % l1literal % l1literal; } + COMPARE(r, l1string + l1string + l1string); + } + void s_3_l1string() { + QBENCHMARK { r = l1string + l1string + l1string; } + COMPARE(r, QString(l1literal % l1literal % l1literal)); + } + + + void separator_4() { SEP("4 literals"); } + + void b_4_l1literal() { + QBENCHMARK { r = l1literal % l1literal % l1literal % l1literal; } + COMPARE(r, l1string + l1string + l1string + l1string); + } + void s_4_l1string() { + QBENCHMARK { r = l1string + l1string + l1string + l1string; } + COMPARE(r, QString(l1literal % l1literal % l1literal % l1literal)); + } + + + void separator_5() { SEP("5 literals"); } + + void b_5_l1literal() { + QBENCHMARK { r = l1literal % l1literal % l1literal % l1literal %l1literal; } + COMPARE(r, l1string + l1string + l1string + l1string + l1string); + } + + void s_5_l1string() { + QBENCHMARK { r = l1string + l1string + l1string + l1string + l1string; } + COMPARE(r, QString(l1literal % l1literal % l1literal % l1literal % l1literal)); + } + + + void separator_6() { SEP("4 chars"); } + + void b_string_4_char() { + QBENCHMARK { r = string + achar + achar + achar + achar; } + COMPARE(r, QString(string % achar % achar % achar % achar)); + } + + void s_string_4_char() { + QBENCHMARK { r = string + achar + achar + achar + achar; } + COMPARE(r, QString(string % achar % achar % achar % achar)); + } + + + void separator_7() { SEP("char + string + char"); } + + void b_char_string_char() { + QBENCHMARK { r = achar + string + achar; } + COMPARE(r, QString(achar % string % achar)); + } + + void s_char_string_char() { + QBENCHMARK { r = achar + string + achar; } + COMPARE(r, QString(achar % string % achar)); + } + + void separator_8() { SEP("string.arg"); } + + void b_string_arg() { + const QString pattern = l1string + "%1" + l1string; + QBENCHMARK { r = l1literal % string % l1literal; } + COMPARE(r, l1string + string + l1string); + } + + void s_string_arg() { + const QString pattern = l1string + "%1" + l1string; + QBENCHMARK { r = pattern.arg(string); } + COMPARE(r, l1string + string + l1string); + } + + void s_bytearray_arg() { + QByteArray result; + QBENCHMARK { result = ba + ba + ba; } + } + + + void separator_9() { SEP("QString::reserve()"); } + + void b_reserve() { + QBENCHMARK { + r.clear(); + r = string % string % string % string; + } + COMPARE(r, string + string + string + string); + } + void b_reserve_lit() { + QBENCHMARK { + r.clear(); + r = string % l1literal % string % string; + } + COMPARE(r, string + string + string + string); + } + void s_reserve() { + QBENCHMARK { + r.clear(); + r.reserve(string.size() + string.size() + string.size() + string.size()); + r += string; + r += string; + r += string; + r += string; + } + COMPARE(r, string + string + string + string); + } + void s_reserve_lit() { + QBENCHMARK { + r.clear(); + //r.reserve(string.size() + qstrlen(l1string.latin1()) + // + string.size() + string.size()); + r.reserve(1024); + r += string; + r += l1string; + r += string; + r += string; + } + COMPARE(r, string + string + string + string); + } + +private: + const QLatin1Literal l1literal; + const QLatin1String l1string; + const QByteArray ba; + const QString string; + const QStringRef stringref; + const QLatin1Char achar; + + QString r; +}; + + +//void operator%(QString, int) {} + +int main(int argc, char *argv[]) +{ + //qDebug() << (QString("xx") * QLatin1String("y")).toString(); + //42 % 3; // Sanity test, should always work. + //QString("x") % 2; // Sanity test, should only compile when the + // operator%(QString, int) is visible. + + if (argc == 2 && (argv[1] == L("--run-builder") || argv[1] == L("-b"))) { + tst_qstringbuilder test; + return test.run_builder(); + } + + if (argc == 2 && (argv[1] == L("--run-traditional") || argv[1] == L("-t"))) { + tst_qstringbuilder test; + return test.run_traditional(); + } + + if (argc == 1) { + QCoreApplication app(argc, argv); + QStringList args = app.arguments(); + tst_qstringbuilder test; + return QTest::qExec(&test, argc, argv); + } + + qDebug() << "Usage: " << argv[0] << " [--run-builder|-r|--run-traditional|-t]"; +} + + +#include "main.moc" diff --git a/tests/benchmarks/qstringbuilder/qstringbuilder.pro b/tests/benchmarks/qstringbuilder/qstringbuilder.pro new file mode 100644 index 0000000..79171b4 --- /dev/null +++ b/tests/benchmarks/qstringbuilder/qstringbuilder.pro @@ -0,0 +1,12 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_qstringbuilder + +QMAKE_CXXFLAGS += -g +QMAKE_CFLAGS += -g + +QT -= gui + +CONFIG += release + +SOURCES += main.cpp |