/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QSTRINGBUILDER_H #define QSTRINGBUILDER_H #if 0 // syncqt can not handle the templates in this file, and it doesn't need to // process them anyway because they are internal. #pragma qt_class(QStringBuilder) #pragma qt_sync_stop_processing #endif #include #include #include QT_BEGIN_NAMESPACE struct Q_CORE_EXPORT QAbstractConcatenable { protected: static void convertFromAscii(const char *a, int len, QChar *&out); static inline void convertFromAscii(char a, QChar *&out) { *out++ = QLatin1Char(a); } static void appendLatin1To(const char *a, int len, QChar *out); }; template struct QConcatenable {}; namespace QtStringBuilder { template struct ConvertToTypeHelper { typedef A ConvertTo; }; template struct ConvertToTypeHelper { typedef QString ConvertTo; }; } template struct QStringBuilderCommon { T toUpper() const { return resolved().toUpper(); } T toLower() const { return resolved().toLower(); } protected: const T resolved() const { return *static_cast(this); } }; template struct QStringBuilderBase : public QStringBuilderCommon { }; template struct QStringBuilderBase : public QStringBuilderCommon { QByteArray toLatin1() const { return this->resolved().toLatin1(); } QByteArray toUtf8() const { return this->resolved().toUtf8(); } QByteArray toLocal8Bit() const { return this->resolved().toLocal8Bit(); } }; template class QStringBuilder : public QStringBuilderBase, typename QtStringBuilder::ConvertToTypeHelper::ConvertTo, typename QConcatenable::ConvertTo>::ConvertTo> { 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); // we abuse const_cast / constData here because we know we've just // allocated the data and we're the only reference count typename T::iterator d = const_cast(s.constData()); 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(); } int size() const { return Concatenable::size(*this); } const A &a; const B &b; }; template <> class QStringBuilder : public QStringBuilderBase, QString> { public: QStringBuilder(const QString &a_, const QString &b_) : a(a_), b(b_) {} QStringBuilder(const QStringBuilder &other) : a(other.a), b(other.b) {} operator QString() const { QString r(a); r += b; return r; } const QString &a; const QString &b; private: QStringBuilder &operator=(const QStringBuilder &) Q_DECL_EQ_DELETE; }; template <> class QStringBuilder : public QStringBuilderBase, QByteArray> { public: QStringBuilder(const QByteArray &a_, const QByteArray &b_) : a(a_), b(b_) {} QStringBuilder(const QStringBuilder &other) : a(other.a), b(other.b) {} operator QByteArray() const { QByteArray r(a); r += b; return r; } const QByteArray &a; const QByteArray &b; private: QStringBuilder &operator=(const QStringBuilder &) Q_DECL_EQ_DELETE; }; 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; } }; template <> struct QConcatenable : private QAbstractConcatenable { typedef QChar::SpecialCharacter type; typedef QString ConvertTo; enum { ExactSize = true }; static int size(const QChar::SpecialCharacter) { return 1; } static inline void appendTo(const QChar::SpecialCharacter c, QChar *&out) { *out++ = c; } }; template <> struct QConcatenable : private QAbstractConcatenable { typedef QCharRef type; typedef QString ConvertTo; enum { ExactSize = true }; static int size(QCharRef) { return 1; } static inline void appendTo(QCharRef c, QChar *&out) { *out++ = QChar(c); } }; template <> struct QConcatenable : private QAbstractConcatenable { 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) { appendLatin1To(a.latin1(), a.size(), out); out += a.size(); } static inline void appendTo(const QLatin1String a, char *&out) { if (a.data()) { 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; } }; 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; } }; 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 - 1, 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 - 1, 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 QT_ASCII_CAST_WARN void appendTo(const QByteArray &ba, QChar *&out) { QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size(), 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< 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 namespace QtStringBuilder { template QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder &b, char) { // append 8-bit data to a byte array 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; } #ifndef QT_NO_CAST_TO_ASCII template QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder &b, QChar) { return a += QString(b).toUtf8(); } #endif } template QByteArray &operator+=(QByteArray &a, const QStringBuilder &b) { return QtStringBuilder::appendToByteArray(a, b, typename QConcatenable< QStringBuilder >::ConvertTo::value_type()); } 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(int(it - a.constData())); //may be smaller than len if there was conversion from utf8 return a; } QT_END_NAMESPACE #endif // QSTRINGBUILDER_H