diff --git a/src/libs/utils/qstringbuilder.cpp b/src/libs/utils/qstringbuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f3925e56b5e62bc0c81c554c17b68b67ff476ad9 --- /dev/null +++ b/src/libs/utils/qstringbuilder.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstringbuilder.h" + +/*! + \class QLatin1Literal + \reentrant + + \brief The QLatin1Literal class provides a thin wrapper of string literal + used in source codes. + + The main use of \c QLatin1Literal is in conjunction with \c QStringBuilder + to reduce the number of reallocations needed to build up a string from + smaller chunks. + + Contrary to \c QLatin1String, a \c QLatin1Literal can retrieve its size + int \i{O(1)}. + + \ingroup tools + \ingroup shared + \ingroup text + \mainclass + + \sa QStringBuilder, QLatin1String, QString + +*/ + +/*! \fn QLatin1Literal::QLatin1Literal(const char(&literal)[]) + + The only constructor of the class. +*/ + +/*! \fn int QLatin1Literal::size() const + + Returns the number of characters in the literal \i{not} including + the trailing NUL char. +*/ + +/*! \fn char *QLatin1Literal::size() const + + Returns a pointer to the first character of the string literal. + The string literal is terminated by a NUL character. +*/ + +/*! \fn QLatin1Literal::operator QString() const + + Converts the \c QLatin1Literal into a \c QString object. +*/ + + +/*! + \class QStringBuilderPair + \reentrant + + \brief QStringBuilderPair is a helper class template for building + QStringBuilder objects wrapping two smaller QStringBuilder object. +*/ + + +/*! + \class QStringBuilder + \reentrant + + \brief QStringBuilder is a template class providing a facility to build + up QStrings from smaller chunks. + + \ingroup tools + \ingroup shared + \ingroup text + \mainclass + + When creating strings from smaller chunks, typically \c QString::operator+() + is used, resulting \i{n - 1} reallocations when operating on \i{n} chunks. + + QStringBuilder uses expression + templates to collect the individual parts, compute the total size, + allocate memory for the resulting QString object, and copy the contents + of the chunks into the result. + + Using \c QStringBuilder::operator%() yield generally better performance then + using \c QString::operator+() on the same chunks if there are three or + more of them, and equal performance otherwise. + + \sa QLatin1Literal, QString +*/ + +/* !fn template <class A, class B> QStringBuilder< QStringBuilderPair<A, B> > operator%(const A &a, const B &b) + + Creates a helper object containing both parameters. + + This is the main function to build up +*/ diff --git a/src/libs/utils/qstringbuilder.h b/src/libs/utils/qstringbuilder.h new file mode 100644 index 0000000000000000000000000000000000000000..cbe0d44353139cda10e61530f903632010dbd58a --- /dev/null +++ b/src/libs/utils/qstringbuilder.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTRINGBUILDER_H +#define QSTRINGBUILDER_H + +#include <QtCore/qstring.h> + +#include <string.h> + +class QLatin1Literal +{ +public: + template <int N> + QLatin1Literal(const char (&str)[N]) : m_size(N - 1), m_data(str) {} + + int size() const { return m_size; } + const char *data() const { return m_data; } + + void append(QChar *&out) const + { + const char *s = m_data; + for (int i = m_size; --i >= 0;) + *out++ = *s++; + } + + operator QString() const + { + QString s; + s.resize(m_size); + QChar *d = s.data(); + append(d); + return s; + } + +private: + const int m_size; + const char *m_data; +}; + +template <class A> +class QStringBuilder : public A +{ +public: + QStringBuilder(A a_) : A(a_) {} + + operator QString() const + { + QString s; + s.resize(this->size()); + QChar *d = s.data(); + this->append(d); + return s; + } + +}; + +template <> +class QStringBuilder<QString> +{ +public: + QStringBuilder(const QString &a_) : a(&a_) {} + + inline int size() const { return a->size(); } + + inline void append(QChar *&out) const + { + const int n = a->size(); + memcpy(out, (char*)a->constData(), sizeof(QChar) * n); + out += n; + } + + inline operator QString() const { return *a; } + +private: + const QString *a; +}; + +template <class A, class B> +class QStringBuilderPair +{ +public: + QStringBuilderPair(A a_, B b_) : a(a_), b(b_) {} + inline int size() const { return a.size() + b.size(); } + inline void append(QChar *&out) const { a.append(out); b.append(out); } +private: + A a; + B b; +}; + + +template <class A, class B> +QStringBuilder< QStringBuilderPair<A, B> > +operator%(const A &a, const B &b) +{ + return QStringBuilderPair<A, B> (a, b); +} + +template <class A> +inline QStringBuilder< QStringBuilderPair<A, QStringBuilder<QString> > > +operator%(const A &a, const QString &b) +{ + return QStringBuilderPair<A, QStringBuilder<QString> > (a, b); +} + +template <class B> +inline QStringBuilder< QStringBuilderPair<QStringBuilder<QString>, B> > +operator%(const QString &a, const B &b) +{ + return QStringBuilderPair<QStringBuilder<QString>, B> (a, b); +} + + +inline QStringBuilder< + QStringBuilderPair<QStringBuilder<QString>, + QStringBuilder<QString> > +> +operator%(const QString &a, const QString &b) +{ + return QStringBuilderPair< QStringBuilder<QString>, + QStringBuilder<QString> > (a, b); +} + +#endif // QSTRINGBUILDER_H diff --git a/tests/auto/qstringbuilder/qstringbuilder.pro b/tests/auto/qstringbuilder/qstringbuilder.pro new file mode 100644 index 0000000000000000000000000000000000000000..5416ca413ab313bea694286ce9a4c72d84466e2d --- /dev/null +++ b/tests/auto/qstringbuilder/qstringbuilder.pro @@ -0,0 +1,11 @@ +load(qttest_p4) +SOURCES += tst_qstringbuilder.cpp + +QT -= gui + +QT = core + +DEFINES += QT_NO_CAST_TO_ASCII + + + diff --git a/tests/auto/qstringbuilder/tst_qstringbuilder.cpp b/tests/auto/qstringbuilder/tst_qstringbuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e58d1252aa3386a58335948a6457c99401a6982 --- /dev/null +++ b/tests/auto/qstringbuilder/tst_qstringbuilder.cpp @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include "../../../src/libs/utils/qstringbuilder.h" + +//TESTED_CLASS=QStringBuilder +//TESTED_FILES=qstringbuilder.h + +class tst_QStringBuilder : public QObject +{ + Q_OBJECT + +public: + tst_QStringBuilder(); + ~tst_QStringBuilder() {} + +public slots: + void init() {} + void cleanup() {} + +private slots: + void operator_percent(); +}; + + +tst_QStringBuilder::tst_QStringBuilder() +{ + //QTextCodec::setCodecForLocale(QTextCodec::codecForName("ISO 8859-1")); +} + +void tst_QStringBuilder::operator_percent() +{ + QLatin1Literal l1literal("a literal"); + QLatin1String l1string("a literal"); + QLatin1Char l1char('c'); + QChar qchar(l1char); + + QCOMPARE(QString(l1literal % l1literal), QString(l1string + l1string)); +} + +QTEST_APPLESS_MAIN(tst_QStringBuilder) + +#include "tst_qstringbuilder.moc" diff --git a/tests/benchmarks/qstringbuilder/main.cpp b/tests/benchmarks/qstringbuilder/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b2bc99a7cd0dd71ac1f3ed22f41293f5ca2f508 --- /dev/null +++ b/tests/benchmarks/qstringbuilder/main.cpp @@ -0,0 +1,84 @@ + +#include <QDebug> +#include <QString> + +#include "../../../src/libs/utils/qstringbuilder.h" + +#include <qtest.h> + + +class tst_qstringbuilder : public QObject +{ + Q_OBJECT + +public: + tst_qstringbuilder(); + +private slots: + // QStringBuilder based + void builderbased_l1literal_l1literal(); + void builderbased_l1literal_l1literal_l1literal(); + void builderbased_l1literal_l1literal_l1literal_l1literal(); + + // QString based for comparison + void stringbased_l1string_l1string(); + void stringbased_l1string_l1string_l1string(); + void stringbased_l1string_l1string_l1string_l1string(); + +private: + const QLatin1Literal l1literal; + const QLatin1String l1string; +}; + + +tst_qstringbuilder::tst_qstringbuilder() + : l1literal("some literal"), l1string("some literal") +{} + +void tst_qstringbuilder::builderbased_l1literal_l1literal() +{ + QString result; + QBENCHMARK { result = l1literal % l1literal; } + QCOMPARE(result, l1string + l1string); +} + +void tst_qstringbuilder::builderbased_l1literal_l1literal_l1literal() +{ + QString result; + QBENCHMARK { result = l1literal % l1literal % l1literal; } + QCOMPARE(result, l1string + l1string + l1string); +} + +void tst_qstringbuilder::builderbased_l1literal_l1literal_l1literal_l1literal() +{ + QString result; + QBENCHMARK { result = l1literal % l1literal % l1literal % l1literal; } + QCOMPARE(result, l1string + l1string + l1string + l1string); +} + + + +void tst_qstringbuilder::stringbased_l1string_l1string() +{ + QString result; + QBENCHMARK { result = l1string + l1string; } + QCOMPARE(result, QString(l1literal % l1literal)); +} + +void tst_qstringbuilder::stringbased_l1string_l1string_l1string() +{ + QString result; + QBENCHMARK { result = l1string + l1string + l1string; } + QCOMPARE(result, QString(l1literal % l1literal % l1literal)); +} + +void tst_qstringbuilder::stringbased_l1string_l1string_l1string_l1string() +{ + QString result; + QBENCHMARK { result = l1string + l1string + l1string + l1string; } + QCOMPARE(result, QString(l1literal % l1literal % l1literal % l1literal)); +} + +QTEST_MAIN(tst_qstringbuilder) + +#include "main.moc" diff --git a/tests/benchmarks/qstringbuilder/qstringbuilder.pro b/tests/benchmarks/qstringbuilder/qstringbuilder.pro new file mode 100644 index 0000000000000000000000000000000000000000..81c42bc565d2fa4183dad8022d125f26fc4f4f31 --- /dev/null +++ b/tests/benchmarks/qstringbuilder/qstringbuilder.pro @@ -0,0 +1,12 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_qstringbuilder +DEPENDPATH += . +INCLUDEPATH += . + +QT -= gui + +CONFIG += release + +# Input +SOURCES += main.cpp