summaryrefslogtreecommitdiffstats
path: root/tests/benchmarks/qstringbuilder
diff options
context:
space:
mode:
authorhjk <qtc-committer@nokia.com>2009-05-28 11:18:00 (GMT)
committerhjk <qtc-committer@nokia.com>2009-05-28 11:38:55 (GMT)
commit3331605529d2d81145259fd56d03bb59c480cac5 (patch)
tree4c716283b4fa714479a4f923019eaebd948de88a /tests/benchmarks/qstringbuilder
parent389ca4b5931efbf2bcac050ec80ec7971b61c857 (diff)
downloadQt-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/benchmarks/qstringbuilder')
-rw-r--r--tests/benchmarks/qstringbuilder/main.cpp304
-rw-r--r--tests/benchmarks/qstringbuilder/qstringbuilder.pro12
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