1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QSTRINGBUILDER_H
41 #define QSTRINGBUILDER_H
42 
43 #if 0
44 // syncqt can not handle the templates in this file, and it doesn't need to
45 // process them anyway because they are internal.
46 #pragma qt_class(QStringBuilder)
47 #pragma qt_sync_stop_processing
48 #endif
49 
50 #include <QtCore/qstring.h>
51 #include <QtCore/qbytearray.h>
52 
53 #include <string.h>
54 
55 QT_BEGIN_NAMESPACE
56 
57 
58 struct Q_CORE_EXPORT QAbstractConcatenable
59 {
60 protected:
61     static void convertFromAscii(const char *a, int len, QChar *&out) noexcept;
convertFromAsciiQAbstractConcatenable62     static inline void convertFromAscii(char a, QChar *&out) noexcept
63     {
64         *out++ = QLatin1Char(a);
65     }
66     static void appendLatin1To(const char *a, int len, QChar *out) noexcept;
67 };
68 
69 template <typename T> struct QConcatenable {};
70 
71 namespace QtStringBuilder {
72     template <typename A, typename B> struct ConvertToTypeHelper
73     { typedef A ConvertTo; };
74     template <typename T> struct ConvertToTypeHelper<T, QString>
75     { typedef QString ConvertTo; };
76 }
77 
78 template<typename Builder, typename T>
79 struct QStringBuilderCommon
80 {
81     T toUpper() const { return resolved().toUpper(); }
82     T toLower() const { return resolved().toLower(); }
83 
84 protected:
85     T resolved() const { return *static_cast<const Builder*>(this); }
86 };
87 
88 template<typename Builder, typename T>
89 struct QStringBuilderBase : public QStringBuilderCommon<Builder, T>
90 {
91 };
92 
93 template<typename Builder>
94 struct QStringBuilderBase<Builder, QString> : public QStringBuilderCommon<Builder, QString>
95 {
96     QByteArray toLatin1() const { return this->resolved().toLatin1(); }
97     QByteArray toUtf8() const { return this->resolved().toUtf8(); }
98     QByteArray toLocal8Bit() const { return this->resolved().toLocal8Bit(); }
99 };
100 
101 template <typename A, typename B>
102 class QStringBuilder : public QStringBuilderBase<QStringBuilder<A, B>, typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo>
103 {
104 public:
105     QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {}
106 private:
107     friend class QByteArray;
108     friend class QString;
109     template <typename T> T convertTo() const
110     {
111         const uint len = QConcatenable< QStringBuilder<A, B> >::size(*this);
112         T s(len, Qt::Uninitialized);
113 
114         // we abuse const_cast / constData here because we know we've just
115         // allocated the data and we're the only reference count
116         typename T::iterator d = const_cast<typename T::iterator>(s.constData());
117         typename T::const_iterator const start = d;
118         QConcatenable< QStringBuilder<A, B> >::appendTo(*this, d);
119 
120         if (!QConcatenable< QStringBuilder<A, B> >::ExactSize && int(len) != d - start) {
121             // this resize is necessary since we allocate a bit too much
122             // when dealing with variable sized 8-bit encodings
123             s.resize(d - start);
124         }
125         return s;
126     }
127 
128     typedef QConcatenable<QStringBuilder<A, B> > Concatenable;
129 public:
130     typedef typename Concatenable::ConvertTo ConvertTo;
131     operator ConvertTo() const { return convertTo<ConvertTo>(); }
132 
133     int size() const { return Concatenable::size(*this); }
134 
135     const A &a;
136     const B &b;
137 };
138 
139 template <>
140 class QStringBuilder <QString, QString> : public QStringBuilderBase<QStringBuilder<QString, QString>, QString>
141 {
142     public:
143         QStringBuilder(const QString &a_, const QString &b_) : a(a_), b(b_) {}
144         QStringBuilder(const QStringBuilder &other) : a(other.a), b(other.b) {}
145 
146         operator QString() const
147         { QString r(a); r += b; return r; }
148 
149         const QString &a;
150         const QString &b;
151 
152     private:
153         QStringBuilder &operator=(const QStringBuilder &) = delete;
154 };
155 
156 template <>
157 class QStringBuilder <QByteArray, QByteArray> : public QStringBuilderBase<QStringBuilder<QByteArray, QByteArray>, QByteArray>
158 {
159     public:
160         QStringBuilder(const QByteArray &a_, const QByteArray &b_) : a(a_), b(b_) {}
161         QStringBuilder(const QStringBuilder &other) : a(other.a), b(other.b) {}
162 
163         operator QByteArray() const
164         { QByteArray r(a); r += b; return r; }
165 
166         const QByteArray &a;
167         const QByteArray &b;
168 
169     private:
170         QStringBuilder &operator=(const QStringBuilder &) = delete;
171 };
172 
173 
174 template <> struct QConcatenable<char> : private QAbstractConcatenable
175 {
176     typedef char type;
177     typedef QByteArray ConvertTo;
178     enum { ExactSize = true };
179     static int size(const char) { return 1; }
180 #ifndef QT_NO_CAST_FROM_ASCII
181     static inline QT_ASCII_CAST_WARN void appendTo(const char c, QChar *&out)
182     {
183         QAbstractConcatenable::convertFromAscii(c, out);
184     }
185 #endif
186     static inline void appendTo(const char c, char *&out)
187     { *out++ = c; }
188 };
189 
190 #if defined(Q_COMPILER_UNICODE_STRINGS)
191 template <> struct QConcatenable<char16_t> : private QAbstractConcatenable
192 {
193     typedef char16_t type;
194     typedef QString ConvertTo;
195     enum { ExactSize = true };
196     static Q_DECL_CONSTEXPR int size(char16_t) { return 1; }
197     static inline void appendTo(char16_t c, QChar *&out)
198     { *out++ = c; }
199 };
200 #endif
201 
202 template <> struct QConcatenable<QLatin1Char>
203 {
204     typedef QLatin1Char type;
205     typedef QString ConvertTo;
206     enum { ExactSize = true };
207     static int size(const QLatin1Char) { return 1; }
208     static inline void appendTo(const QLatin1Char c, QChar *&out)
209     { *out++ = c; }
210     static inline void appendTo(const QLatin1Char c, char *&out)
211     { *out++ = c.toLatin1(); }
212 };
213 
214 template <> struct QConcatenable<QChar> : private QAbstractConcatenable
215 {
216     typedef QChar type;
217     typedef QString ConvertTo;
218     enum { ExactSize = true };
219     static int size(const QChar) { return 1; }
220     static inline void appendTo(const QChar c, QChar *&out)
221     { *out++ = c; }
222 };
223 
224 template <> struct QConcatenable<QChar::SpecialCharacter> : private QAbstractConcatenable
225 {
226     typedef QChar::SpecialCharacter type;
227     typedef QString ConvertTo;
228     enum { ExactSize = true };
229     static int size(const QChar::SpecialCharacter) { return 1; }
230     static inline void appendTo(const QChar::SpecialCharacter c, QChar *&out)
231     { *out++ = c; }
232 };
233 
234 template <> struct QConcatenable<QCharRef> : private QAbstractConcatenable
235 {
236     typedef QCharRef type;
237     typedef QString ConvertTo;
238     enum { ExactSize = true };
239     static int size(QCharRef) { return 1; }
240     static inline void appendTo(QCharRef c, QChar *&out)
241     { *out++ = QChar(c); }
242 };
243 
244 template <> struct QConcatenable<QLatin1String> : private QAbstractConcatenable
245 {
246     typedef QLatin1String type;
247     typedef QString ConvertTo;
248     enum { ExactSize = true };
249     static int size(const QLatin1String a) { return a.size(); }
250     static inline void appendTo(const QLatin1String a, QChar *&out)
251     {
252         appendLatin1To(a.latin1(), a.size(), out);
253         out += a.size();
254     }
255     static inline void appendTo(const QLatin1String a, char *&out)
256     {
257         if (const char *data = a.data()) {
258             memcpy(out, data, a.size());
259             out += a.size();
260         }
261     }
262 };
263 
264 template <> struct QConcatenable<QString> : private QAbstractConcatenable
265 {
266     typedef QString type;
267     typedef QString ConvertTo;
268     enum { ExactSize = true };
269     static int size(const QString &a) { return a.size(); }
270     static inline void appendTo(const QString &a, QChar *&out)
271     {
272         const int n = a.size();
273         memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n);
274         out += n;
275     }
276 };
277 
278 template <> struct QConcatenable<QStringRef> : private QAbstractConcatenable
279 {
280     typedef QStringRef type;
281     typedef QString ConvertTo;
282     enum { ExactSize = true };
283     static int size(const QStringRef &a) { return a.size(); }
284     static inline void appendTo(const QStringRef &a, QChar *&out)
285     {
286         const int n = a.size();
287         memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n);
288         out += n;
289     }
290 };
291 
292 template <> struct QConcatenable<QStringView> : private QAbstractConcatenable
293 {
294     typedef QStringView type;
295     typedef QString ConvertTo;
296     enum { ExactSize = true };
297     static int size(QStringView a) { return a.length(); }
298     static inline void appendTo(QStringView a, QChar *&out)
299     {
300         const auto n = a.size();
301         memcpy(out, a.data(), sizeof(QChar) * n);
302         out += n;
303     }
304 };
305 
306 template <int N> struct QConcatenable<const char[N]> : private QAbstractConcatenable
307 {
308     typedef const char type[N];
309     typedef QByteArray ConvertTo;
310     enum { ExactSize = false };
311     static int size(const char[N]) { return N - 1; }
312 #ifndef QT_NO_CAST_FROM_ASCII
313     static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out)
314     {
315         QAbstractConcatenable::convertFromAscii(a, N - 1, out);
316     }
317 #endif
318     static inline void appendTo(const char a[N], char *&out)
319     {
320         while (*a)
321             *out++ = *a++;
322     }
323 };
324 
325 template <int N> struct QConcatenable<char[N]> : QConcatenable<const char[N]>
326 {
327     typedef char type[N];
328 };
329 
330 template <> struct QConcatenable<const char *> : private QAbstractConcatenable
331 {
332     typedef const char *type;
333     typedef QByteArray ConvertTo;
334     enum { ExactSize = false };
335     static int size(const char *a) { return qstrlen(a); }
336 #ifndef QT_NO_CAST_FROM_ASCII
337     static inline void QT_ASCII_CAST_WARN appendTo(const char *a, QChar *&out)
338     { QAbstractConcatenable::convertFromAscii(a, -1, out); }
339 #endif
340     static inline void appendTo(const char *a, char *&out)
341     {
342         if (!a)
343             return;
344         while (*a)
345             *out++ = *a++;
346     }
347 };
348 
349 template <> struct QConcatenable<char *> : QConcatenable<const char*>
350 {
351     typedef char *type;
352 };
353 
354 #if defined(Q_COMPILER_UNICODE_STRINGS)
355 template <int N> struct QConcatenable<const char16_t[N]> : private QAbstractConcatenable
356 {
357     using type = const char16_t[N];
358     using ConvertTo = QString;
359     enum { ExactSize = true };
360     static int size(const char16_t[N]) { return N - 1; }
361     static void appendTo(const char16_t a[N], QChar *&out)
362     {
363         memcpy(out, a, (N - 1) * sizeof(char16_t));
364         out += N - 1;
365     }
366 };
367 
368 template <int N> struct QConcatenable<char16_t[N]> : QConcatenable<const char16_t[N]>
369 {
370     using type = char16_t[N];
371 };
372 
373 template <> struct QConcatenable<const char16_t *> : private QAbstractConcatenable
374 {
375     using type = const char16_t *;
376     using ConvertTo = QString;
377     enum { ExactSize = true };
378     static int size(const char16_t *a) { return QStringView(a).length(); }
379     static inline void QT_ASCII_CAST_WARN appendTo(const char16_t *a, QChar *&out)
380     {
381         if (!a)
382             return;
383         while (*a)
384             *out++ = *a++;
385     }
386 };
387 
388 template <> struct QConcatenable<char16_t *> : QConcatenable<const char16_t*>
389 {
390     typedef char16_t *type;
391 };
392 #endif // UNICODE_STRINGS
393 
394 template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable
395 {
396     typedef QByteArray type;
397     typedef QByteArray ConvertTo;
398     enum { ExactSize = false };
399     static int size(const QByteArray &ba) { return ba.size(); }
400 #ifndef QT_NO_CAST_FROM_ASCII
401     static inline QT_ASCII_CAST_WARN void appendTo(const QByteArray &ba, QChar *&out)
402     {
403         QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size(), out);
404     }
405 #endif
406     static inline void appendTo(const QByteArray &ba, char *&out)
407     {
408         const char *a = ba.constData();
409         const char * const end = ba.end();
410         while (a != end)
411             *out++ = *a++;
412     }
413 };
414 
415 
416 template <typename A, typename B>
417 struct QConcatenable< QStringBuilder<A, B> >
418 {
419     typedef QStringBuilder<A, B> type;
420     typedef typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo ConvertTo;
421     enum { ExactSize = QConcatenable<A>::ExactSize && QConcatenable<B>::ExactSize };
422     static int size(const type &p)
423     {
424         return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b);
425     }
426     template<typename T> static inline void appendTo(const type &p, T *&out)
427     {
428         QConcatenable<A>::appendTo(p.a, out);
429         QConcatenable<B>::appendTo(p.b, out);
430     }
431 };
432 
433 template <typename A, typename B>
434 QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
435 operator%(const A &a, const B &b)
436 {
437    return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b);
438 }
439 
440 // QT_USE_FAST_OPERATOR_PLUS was introduced in 4.7, QT_USE_QSTRINGBUILDER is to be used from 4.8 onwards
441 // QT_USE_FAST_OPERATOR_PLUS does not remove the normal operator+ for QByteArray
442 #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
443 template <typename A, typename B>
444 QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
445 operator+(const A &a, const B &b)
446 {
447    return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b);
448 }
449 #endif
450 
451 namespace QtStringBuilder {
452 template <typename A, typename B>
453 QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder<A, B> &b, char)
454 {
455     // append 8-bit data to a byte array
456     int len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b);
457     a.reserve(len);
458     char *it = a.data() + a.size();
459     QConcatenable< QStringBuilder<A, B> >::appendTo(b, it);
460     a.resize(len); //we need to resize after the appendTo for the case str+=foo+str
461     return a;
462 }
463 
464 #ifndef QT_NO_CAST_TO_ASCII
465 template <typename A, typename B>
466 QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder<A, B> &b, QChar)
467 {
468     return a += QString(b).toUtf8();
469 }
470 #endif
471 }
472 
473 template <typename A, typename B>
474 QByteArray &operator+=(QByteArray &a, const QStringBuilder<A, B> &b)
475 {
476     return QtStringBuilder::appendToByteArray(a, b,
477                                               typename QConcatenable< QStringBuilder<A, B> >::ConvertTo::value_type());
478 }
479 
480 template <typename A, typename B>
481 QString &operator+=(QString &a, const QStringBuilder<A, B> &b)
482 {
483     int len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b);
484     a.reserve(len);
485     QChar *it = a.data() + a.size();
486     QConcatenable< QStringBuilder<A, B> >::appendTo(b, it);
487     a.resize(int(it - a.constData())); //may be smaller than len if there was conversion from utf8
488     return a;
489 }
490 
491 
492 QT_END_NAMESPACE
493 
494 #endif // QSTRINGBUILDER_H
495