/**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** 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.1, 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. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QSTRINGBUILDER_H #define QSTRINGBUILDER_H #include #include #if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 0) # include # endif #endif #include QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Core) struct Q_CORE_EXPORT QAbstractConcatenable { protected: static void convertFromAscii(const char *a, int len, QChar *&out); static void convertToAscii(const QChar *a, int len, char *&out); static inline void convertFromAscii(char a, QChar *&out) { #ifndef QT_NO_TEXTCODEC if (QString::codecForCStrings) *out++ = QChar::fromAscii(a); else #endif *out++ = QLatin1Char(a); } static inline void convertToAscii(QChar a, char *&out) { #ifndef QT_NO_TEXTCODEC if (QString::codecForCStrings) *out++ = a.toAscii(); //### else #endif convertToLatin1(a, out); } static inline void convertToLatin1(QChar a, char *&out) { *out++ = a.unicode() > 0xff ? '?' : char(a.unicode()); } }; template struct QConcatenable {}; template class QStringBuilder { public: QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {} private: friend class QByteArray; friend class QString; template T convertTo() const { const uint len = QConcatenable< QStringBuilder >::size(*this); T s(len, Qt::Uninitialized); typename T::iterator d = s.data(); typename T::const_iterator const start = d; QConcatenable< QStringBuilder >::appendTo(*this, d); if (!QConcatenable< QStringBuilder >::ExactSize && int(len) != d - start) { // this resize is necessary since we allocate a bit too much // when dealing with variable sized 8-bit encodings s.resize(d - start); } return s; } typedef QConcatenable > Concatenable; typedef typename Concatenable::ConvertTo ConvertTo; public: operator ConvertTo() const { return convertTo(); } QByteArray toLatin1() const { return convertTo().toLatin1(); } int size() const { return Concatenable::size(*this); } const A &a; const B &b; }; template <> class QStringBuilder { public: QStringBuilder(const QString &a_, const QString &b_) : a(a_), b(b_) {} operator QString() const { QString r(a); r += b; return r; } QByteArray toLatin1() const { return QString(*this).toLatin1(); } const QString &a; const QString &b; }; template <> class QStringBuilder { public: QStringBuilder(const QByteArray &a_, const QByteArray &b_) : a(a_), b(b_) {} operator QByteArray() const { QByteArray r(a); r += b; return r; } const QByteArray &a; const QByteArray &b; }; template <> struct QConcatenable : private QAbstractConcatenable { typedef char type; typedef QByteArray ConvertTo; enum { ExactSize = true }; static int size(const char) { return 1; } #ifndef QT_NO_CAST_FROM_ASCII static inline QT_ASCII_CAST_WARN void appendTo(const char c, QChar *&out) { QAbstractConcatenable::convertFromAscii(c, out); } #endif static inline void appendTo(const char c, char *&out) { *out++ = c; } }; template <> struct QConcatenable { typedef QLatin1Char type; typedef QString ConvertTo; enum { ExactSize = true }; static int size(const QLatin1Char) { return 1; } static inline void appendTo(const QLatin1Char c, QChar *&out) { *out++ = c; } static inline void appendTo(const QLatin1Char c, char *&out) { *out++ = c.toLatin1(); } }; template <> struct QConcatenable : private QAbstractConcatenable { typedef QChar type; typedef QString ConvertTo; enum { ExactSize = true }; static int size(const QChar) { return 1; } static inline void appendTo(const QChar c, QChar *&out) { *out++ = c; } #ifndef QT_NO_CAST_TO_ASCII static inline QT_ASCII_CAST_WARN void appendTo(const QChar c, char *&out) { convertToAscii(c, out); } #endif }; template <> struct QConcatenable : private QAbstractConcatenable { typedef QCharRef type; typedef QString ConvertTo; enum { ExactSize = true }; static int size(const QCharRef &) { return 1; } static inline void appendTo(const QCharRef &c, QChar *&out) { *out++ = QChar(c); } #ifndef QT_NO_CAST_TO_ASCII static inline QT_ASCII_CAST_WARN void appendTo(const QCharRef &c, char *&out) { convertToAscii(c, out); } #endif }; template <> struct QConcatenable { typedef QLatin1String type; typedef QString ConvertTo; enum { ExactSize = true }; static int size(const QLatin1String &a) { return a.size(); } static inline void appendTo(const QLatin1String &a, QChar *&out) { for (const char *s = a.data(); *s; ) *out++ = QLatin1Char(*s++); } static inline void appendTo(const QLatin1String &a, char *&out) { for (const char *s = a.data(); *s; ) *out++ = *s++; } }; template <> struct QConcatenable : private QAbstractConcatenable { typedef QString type; typedef QString ConvertTo; enum { ExactSize = true }; static int size(const QString &a) { return a.size(); } static inline void appendTo(const QString &a, QChar *&out) { const int n = a.size(); memcpy(out, reinterpret_cast(a.constData()), sizeof(QChar) * n); out += n; } #ifndef QT_NO_CAST_TO_ASCII static inline QT_ASCII_CAST_WARN void appendTo(const QString &a, char *&out) { convertToAscii(a.constData(), a.length(), out); } #endif }; template struct QConcatenable > : private QAbstractConcatenable { typedef QConstStringDataPtr type; typedef QString ConvertTo; enum { ExactSize = true }; static int size(const type &) { return N; } static inline void appendTo(const type &a, QChar *&out) { memcpy(out, reinterpret_cast(a.ptr->data), sizeof(QChar) * N); out += N; } #ifndef QT_NO_CAST_TO_ASCII static inline QT_ASCII_CAST_WARN void appendTo(const type &a, char *&out) { convertToAscii(a.ptr->data, N, out); } #endif }; template <> struct QConcatenable : private QAbstractConcatenable { typedef QStringRef type; typedef QString ConvertTo; enum { ExactSize = true }; static int size(const QStringRef &a) { return a.size(); } static inline void appendTo(const QStringRef &a, QChar *&out) { const int n = a.size(); memcpy(out, reinterpret_cast(a.constData()), sizeof(QChar) * n); out += n; } #ifndef QT_NO_CAST_TO_ASCII static inline QT_ASCII_CAST_WARN void appendTo(const QStringRef &a, char *&out) { convertToAscii(a.constData(), a.length(), out); } #endif }; template struct QConcatenable : private QAbstractConcatenable { typedef char type[N]; typedef QByteArray ConvertTo; enum { ExactSize = false }; static int size(const char[N]) { return N - 1; } #ifndef QT_NO_CAST_FROM_ASCII static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out) { QAbstractConcatenable::convertFromAscii(a, N, out); } #endif static inline void appendTo(const char a[N], char *&out) { while (*a) *out++ = *a++; } }; template struct QConcatenable : private QAbstractConcatenable { typedef const char type[N]; typedef QByteArray ConvertTo; enum { ExactSize = false }; static int size(const char[N]) { return N - 1; } #ifndef QT_NO_CAST_FROM_ASCII static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out) { QAbstractConcatenable::convertFromAscii(a, N, out); } #endif static inline void appendTo(const char a[N], char *&out) { while (*a) *out++ = *a++; } }; template <> struct QConcatenable : private QAbstractConcatenable { typedef char const *type; typedef QByteArray ConvertTo; enum { ExactSize = false }; static int size(const char *a) { return qstrlen(a); } #ifndef QT_NO_CAST_FROM_ASCII static inline void QT_ASCII_CAST_WARN appendTo(const char *a, QChar *&out) { QAbstractConcatenable::convertFromAscii(a, -1, out); } #endif static inline void appendTo(const char *a, char *&out) { if (!a) return; while (*a) *out++ = *a++; } }; template <> struct QConcatenable : private QAbstractConcatenable { typedef QByteArray type; typedef QByteArray ConvertTo; enum { ExactSize = false }; static int size(const QByteArray &ba) { return ba.size(); } #ifndef QT_NO_CAST_FROM_ASCII static inline void appendTo(const QByteArray &ba, QChar *&out) { // adding 1 because convertFromAscii expects the size including the null-termination QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size() + 1, out); } #endif static inline void appendTo(const QByteArray &ba, char *&out) { const char *a = ba.constData(); const char * const end = ba.end(); while (a != end) *out++ = *a++; } }; template struct QConcatenable > : private QAbstractConcatenable { typedef QConstByteArrayDataPtr type; typedef QByteArray ConvertTo; enum { ExactSize = false }; static int size(const type &) { return N; } #ifndef QT_NO_CAST_FROM_ASCII static inline QT_ASCII_CAST_WARN void appendTo(const type &a, QChar *&out) { // adding 1 because convertFromAscii expects the size including the null-termination QAbstractConcatenable::convertFromAscii(a.ptr->data, N + 1, out); } #endif static inline void appendTo(const type &ba, char *&out) { const char *a = ba.ptr->data; while (*a) *out++ = *a++; } }; namespace QtStringBuilder { template struct ConvertToTypeHelper { typedef A ConvertTo; }; template struct ConvertToTypeHelper { typedef QString ConvertTo; }; } template struct QConcatenable< QStringBuilder > { typedef QStringBuilder type; typedef typename QtStringBuilder::ConvertToTypeHelper::ConvertTo, typename QConcatenable::ConvertTo>::ConvertTo ConvertTo; enum { ExactSize = QConcatenable::ExactSize && QConcatenable::ExactSize }; static int size(const type &p) { return QConcatenable::size(p.a) + QConcatenable::size(p.b); } template static inline void appendTo(const type &p, T *&out) { QConcatenable::appendTo(p.a, out); QConcatenable::appendTo(p.b, out); } }; template QStringBuilder::type, typename QConcatenable::type> operator%(const A &a, const B &b) { return QStringBuilder::type, typename QConcatenable::type>(a, b); } // QT_USE_FAST_OPERATOR_PLUS was introduced in 4.7, QT_USE_QSTRINGBUILDER is to be used from 4.8 onwards // QT_USE_FAST_OPERATOR_PLUS does not remove the normal operator+ for QByteArray #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER) template QStringBuilder::type, typename QConcatenable::type> operator+(const A &a, const B &b) { return QStringBuilder::type, typename QConcatenable::type>(a, b); } #endif template QByteArray &operator+=(QByteArray &a, const QStringBuilder &b) { #ifndef QT_NO_CAST_TO_ASCII if (sizeof(typename QConcatenable< QStringBuilder >::ConvertTo::value_type) == sizeof(QChar)) { //it is not save to optimize as in utf8 it is not possible to compute the size return a += QString(b); } #endif int len = a.size() + QConcatenable< QStringBuilder >::size(b); a.reserve(len); char *it = a.data() + a.size(); QConcatenable< QStringBuilder >::appendTo(b, it); a.resize(len); //we need to resize after the appendTo for the case str+=foo+str return a; } template QString &operator+=(QString &a, const QStringBuilder &b) { int len = a.size() + QConcatenable< QStringBuilder >::size(b); a.reserve(len); QChar *it = a.data() + a.size(); QConcatenable< QStringBuilder >::appendTo(b, it); a.resize(it - a.constData()); //may be smaller than len if there was conversion from utf8 return a; } QT_END_NAMESPACE QT_END_HEADER #endif // QSTRINGBUILDER_H