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; |
62 | 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 | |