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
55QT_BEGIN_NAMESPACE
56
57
58struct Q_CORE_EXPORT QAbstractConcatenable
59{
60protected:
61 static void convertFromAscii(const char *a, int len, QChar *&out) Q_DECL_NOTHROW;
62 static inline void convertFromAscii(char a, QChar *&out) Q_DECL_NOTHROW
63 {
64 *out++ = QLatin1Char(a);
65 }
66 static void appendLatin1To(const char *a, int len, QChar *out) Q_DECL_NOTHROW;
67};
68
69template <typename T> struct QConcatenable {};
70
71namespace 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
78template<typename Builder, typename T>
79struct QStringBuilderCommon
80{
81 T toUpper() const { return resolved().toUpper(); }
82 T toLower() const { return resolved().toLower(); }
83
84protected:
85 T resolved() const { return *static_cast<const Builder*>(this); }
86};
87
88template<typename Builder, typename T>
89struct QStringBuilderBase : public QStringBuilderCommon<Builder, T>
90{
91};
92
93template<typename Builder>
94struct 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
101template <typename A, typename B>
102class QStringBuilder : public QStringBuilderBase<QStringBuilder<A, B>, typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo>
103{
104public:
105 QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {}
106private:
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 typedef typename Concatenable::ConvertTo ConvertTo;
130public:
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
139template <>
140class 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 &) Q_DECL_EQ_DELETE;
154};
155
156template <>
157class 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 &) Q_DECL_EQ_DELETE;
171};
172
173
174template <> 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)
191template <> 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
202template <> 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
214template <> 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
224template <> 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
234template <> 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
244template <> 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
264template <> 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
278template <> 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
292template <> 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
306template <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
325template <int N> struct QConcatenable<char[N]> : QConcatenable<const char[N]>
326{
327 typedef char type[N];
328};
329
330template <> 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
349template <> struct QConcatenable<char *> : QConcatenable<const char*>
350{
351 typedef char *type;
352};
353
354#if defined(Q_COMPILER_UNICODE_STRINGS)
355template <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
368template <int N> struct QConcatenable<char16_t[N]> : QConcatenable<const char16_t[N]>
369{
370 using type = char16_t[N];
371};
372
373template <> 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
388template <> struct QConcatenable<char16_t *> : QConcatenable<const char16_t*>
389{
390 typedef char16_t *type;
391};
392#endif // UNICODE_STRINGS
393
394template <> 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
416template <typename A, typename B>
417struct 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
433template <typename A, typename B>
434QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
435operator%(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)
443template <typename A, typename B>
444QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
445operator+(const A &a, const B &b)
446{
447 return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b);
448}
449#endif
450
451namespace QtStringBuilder {
452template <typename A, typename B>
453QByteArray &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
465template <typename A, typename B>
466QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder<A, B> &b, QChar)
467{
468 return a += QString(b).toUtf8();
469}
470#endif
471}
472
473template <typename A, typename B>
474QByteArray &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
480template <typename A, typename B>
481QString &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
492QT_END_NAMESPACE
493
494#endif // QSTRINGBUILDER_H
495