1/****************************************************************************
2**
3** Copyright (C) 2020 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 convertFromUtf8(QByteArrayView in, QChar *&out) noexcept;
62 static inline void convertFromAscii(char a, QChar *&out) noexcept
63 {
64 *out++ = QLatin1Char(a);
65 }
66 static void appendLatin1To(QLatin1String in, QChar *out) noexcept;
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 qsizetype 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 && 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;
129public:
130 typedef typename Concatenable::ConvertTo ConvertTo;
131 operator ConvertTo() const { return convertTo<ConvertTo>(); }
132
133 qsizetype 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 &) = 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 &) = 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 qsizetype size(const char) { return 1; }
180#ifndef QT_NO_CAST_FROM_ASCII
181 QT_ASCII_CAST_WARN static inline 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
190template <> struct QConcatenable<char16_t> : private QAbstractConcatenable
191{
192 typedef char16_t type;
193 typedef QString ConvertTo;
194 enum { ExactSize = true };
195 static constexpr qsizetype size(char16_t) { return 1; }
196 static inline void appendTo(char16_t c, QChar *&out)
197 { *out++ = c; }
198};
199
200template <> struct QConcatenable<QLatin1Char>
201{
202 typedef QLatin1Char type;
203 typedef QString ConvertTo;
204 enum { ExactSize = true };
205 static qsizetype size(const QLatin1Char) { return 1; }
206 static inline void appendTo(const QLatin1Char c, QChar *&out)
207 { *out++ = c; }
208 static inline void appendTo(const QLatin1Char c, char *&out)
209 { *out++ = c.toLatin1(); }
210};
211
212template <> struct QConcatenable<QChar> : private QAbstractConcatenable
213{
214 typedef QChar type;
215 typedef QString ConvertTo;
216 enum { ExactSize = true };
217 static qsizetype size(const QChar) { return 1; }
218 static inline void appendTo(const QChar c, QChar *&out)
219 { *out++ = c; }
220};
221
222template <> struct QConcatenable<QChar::SpecialCharacter> : private QAbstractConcatenable
223{
224 typedef QChar::SpecialCharacter type;
225 typedef QString ConvertTo;
226 enum { ExactSize = true };
227 static qsizetype size(const QChar::SpecialCharacter) { return 1; }
228 static inline void appendTo(const QChar::SpecialCharacter c, QChar *&out)
229 { *out++ = c; }
230};
231
232template <> struct QConcatenable<QLatin1String> : private QAbstractConcatenable
233{
234 typedef QLatin1String type;
235 typedef QString ConvertTo;
236 enum { ExactSize = true };
237 static qsizetype size(const QLatin1String a) { return a.size(); }
238 static inline void appendTo(const QLatin1String a, QChar *&out)
239 {
240 appendLatin1To(a, out);
241 out += a.size();
242 }
243 static inline void appendTo(const QLatin1String a, char *&out)
244 {
245 if (const char *data = a.data()) {
246 memcpy(out, data, a.size());
247 out += a.size();
248 }
249 }
250};
251
252template <> struct QConcatenable<QString> : private QAbstractConcatenable
253{
254 typedef QString type;
255 typedef QString ConvertTo;
256 enum { ExactSize = true };
257 static qsizetype size(const QString &a) { return a.size(); }
258 static inline void appendTo(const QString &a, QChar *&out)
259 {
260 const qsizetype n = a.size();
261 if (n)
262 memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n);
263 out += n;
264 }
265};
266
267template <> struct QConcatenable<QStringView> : private QAbstractConcatenable
268{
269 typedef QStringView type;
270 typedef QString ConvertTo;
271 enum { ExactSize = true };
272 static qsizetype size(QStringView a) { return a.size(); }
273 static inline void appendTo(QStringView a, QChar *&out)
274 {
275 const auto n = a.size();
276 if (n)
277 memcpy(out, a.data(), sizeof(QChar) * n);
278 out += n;
279 }
280};
281
282template <qsizetype N> struct QConcatenable<const char[N]> : private QAbstractConcatenable
283{
284 typedef const char type[N];
285 typedef QByteArray ConvertTo;
286 enum { ExactSize = false };
287 static qsizetype size(const char[N]) { return N - 1; }
288#ifndef QT_NO_CAST_FROM_ASCII
289 QT_ASCII_CAST_WARN static inline void appendTo(const char a[N], QChar *&out)
290 {
291 QAbstractConcatenable::convertFromUtf8(QByteArrayView(a, N - 1), out);
292 }
293#endif
294 static inline void appendTo(const char a[N], char *&out)
295 {
296 while (*a)
297 *out++ = *a++;
298 }
299};
300
301template <qsizetype N> struct QConcatenable<char[N]> : QConcatenable<const char[N]>
302{
303 typedef char type[N];
304};
305
306template <> struct QConcatenable<const char *> : private QAbstractConcatenable
307{
308 typedef const char *type;
309 typedef QByteArray ConvertTo;
310 enum { ExactSize = false };
311 static qsizetype size(const char *a) { return qstrlen(a); }
312#ifndef QT_NO_CAST_FROM_ASCII
313 QT_ASCII_CAST_WARN static inline void appendTo(const char *a, QChar *&out)
314 { QAbstractConcatenable::convertFromUtf8(QByteArrayView(a), out); }
315#endif
316 static inline void appendTo(const char *a, char *&out)
317 {
318 if (!a)
319 return;
320 while (*a)
321 *out++ = *a++;
322 }
323};
324
325template <> struct QConcatenable<char *> : QConcatenable<const char*>
326{
327 typedef char *type;
328};
329
330template <qsizetype N> struct QConcatenable<const char16_t[N]> : private QAbstractConcatenable
331{
332 using type = const char16_t[N];
333 using ConvertTo = QString;
334 enum { ExactSize = true };
335 static qsizetype size(const char16_t[N]) { return N - 1; }
336 static void appendTo(const char16_t a[N], QChar *&out)
337 {
338 memcpy(out, a, (N - 1) * sizeof(char16_t));
339 out += N - 1;
340 }
341};
342
343template <qsizetype N> struct QConcatenable<char16_t[N]> : QConcatenable<const char16_t[N]>
344{
345 using type = char16_t[N];
346};
347
348template <> struct QConcatenable<const char16_t *> : private QAbstractConcatenable
349{
350 using type = const char16_t *;
351 using ConvertTo = QString;
352 enum { ExactSize = true };
353 static qsizetype size(const char16_t *a) { return QStringView(a).size(); }
354 QT_ASCII_CAST_WARN static inline void appendTo(const char16_t *a, QChar *&out)
355 {
356 if (!a)
357 return;
358 while (*a)
359 *out++ = *a++;
360 }
361};
362
363template <> struct QConcatenable<char16_t *> : QConcatenable<const char16_t*>
364{
365 typedef char16_t *type;
366};
367
368template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable
369{
370 typedef QByteArray type;
371 typedef QByteArray ConvertTo;
372 enum { ExactSize = false };
373 static qsizetype size(const QByteArray &ba) { return ba.size(); }
374#ifndef QT_NO_CAST_FROM_ASCII
375 QT_ASCII_CAST_WARN static inline void appendTo(const QByteArray &ba, QChar *&out)
376 {
377 QAbstractConcatenable::convertFromUtf8(ba, out);
378 }
379#endif
380 static inline void appendTo(const QByteArray &ba, char *&out)
381 {
382 const char *a = ba.constData();
383 const char * const end = ba.end();
384 while (a != end)
385 *out++ = *a++;
386 }
387};
388
389
390template <typename A, typename B>
391struct QConcatenable< QStringBuilder<A, B> >
392{
393 typedef QStringBuilder<A, B> type;
394 typedef typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo ConvertTo;
395 enum { ExactSize = QConcatenable<A>::ExactSize && QConcatenable<B>::ExactSize };
396 static qsizetype size(const type &p)
397 {
398 return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b);
399 }
400 template<typename T> static inline void appendTo(const type &p, T *&out)
401 {
402 QConcatenable<A>::appendTo(p.a, out);
403 QConcatenable<B>::appendTo(p.b, out);
404 }
405};
406
407template <typename A, typename B>
408QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
409operator%(const A &a, const B &b)
410{
411 return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b);
412}
413
414// QT_USE_FAST_OPERATOR_PLUS was introduced in 4.7, QT_USE_QSTRINGBUILDER is to be used from 4.8 onwards
415// QT_USE_FAST_OPERATOR_PLUS does not remove the normal operator+ for QByteArray
416#if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
417template <typename A, typename B>
418QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
419operator+(const A &a, const B &b)
420{
421 return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b);
422}
423#endif
424
425namespace QtStringBuilder {
426template <typename A, typename B>
427QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder<A, B> &b, char)
428{
429 // append 8-bit data to a byte array
430 qsizetype len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b);
431 a.reserve(len);
432 char *it = a.data() + a.size();
433 QConcatenable< QStringBuilder<A, B> >::appendTo(b, it);
434 a.resize(len); //we need to resize after the appendTo for the case str+=foo+str
435 return a;
436}
437
438#ifndef QT_NO_CAST_TO_ASCII
439template <typename A, typename B>
440QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder<A, B> &b, QChar)
441{
442 return a += QString(b).toUtf8();
443}
444#endif
445}
446
447template <typename A, typename B>
448QByteArray &operator+=(QByteArray &a, const QStringBuilder<A, B> &b)
449{
450 return QtStringBuilder::appendToByteArray(a, b,
451 typename QConcatenable< QStringBuilder<A, B> >::ConvertTo::value_type());
452}
453
454template <typename A, typename B>
455QString &operator+=(QString &a, const QStringBuilder<A, B> &b)
456{
457 qsizetype len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b);
458 a.reserve(len);
459 QChar *it = a.data() + a.size();
460 QConcatenable< QStringBuilder<A, B> >::appendTo(b, it);
461 a.resize(it - a.constData()); //may be smaller than len if there was conversion from utf8
462 return a;
463}
464
465//
466// inline QAnyStringView members requiring QStringBuilder:
467//
468
469template <typename A, typename B>
470QAnyStringView::QAnyStringView(const QStringBuilder<A, B> &expr,
471 typename QStringBuilder<A, B>::ConvertTo &&capacity)
472 : QAnyStringView(capacity = expr) {}
473
474QT_END_NAMESPACE
475
476#endif // QSTRINGBUILDER_H
477