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 | |
55 | QT_BEGIN_NAMESPACE |
56 | |
57 | |
58 | struct Q_CORE_EXPORT QAbstractConcatenable |
59 | { |
60 | protected: |
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 | |
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(int(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 | qsizetype 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 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 | |
190 | template <> 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 | |
200 | template <> 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 | |
212 | template <> 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 | |
222 | template <> 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 | |
232 | template <> 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 | |
252 | template <> 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 int n = a.size(); |
261 | if (n) |
262 | memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n); |
263 | out += n; |
264 | } |
265 | }; |
266 | |
267 | template <> 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 | |
282 | template <int 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 | |
301 | template <int N> struct QConcatenable<char[N]> : QConcatenable<const char[N]> |
302 | { |
303 | typedef char type[N]; |
304 | }; |
305 | |
306 | template <> 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 | |
325 | template <> struct QConcatenable<char *> : QConcatenable<const char*> |
326 | { |
327 | typedef char *type; |
328 | }; |
329 | |
330 | template <int 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 | |
343 | template <int N> struct QConcatenable<char16_t[N]> : QConcatenable<const char16_t[N]> |
344 | { |
345 | using type = char16_t[N]; |
346 | }; |
347 | |
348 | template <> 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 | |
363 | template <> struct QConcatenable<char16_t *> : QConcatenable<const char16_t*> |
364 | { |
365 | typedef char16_t *type; |
366 | }; |
367 | |
368 | template <> 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 | |
390 | template <typename A, typename B> |
391 | struct 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 | |
407 | template <typename A, typename B> |
408 | QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type> |
409 | operator%(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) |
417 | template <typename A, typename B> |
418 | QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type> |
419 | operator+(const A &a, const B &b) |
420 | { |
421 | return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b); |
422 | } |
423 | #endif |
424 | |
425 | namespace QtStringBuilder { |
426 | template <typename A, typename B> |
427 | QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder<A, B> &b, char) |
428 | { |
429 | // append 8-bit data to a byte array |
430 | int 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 |
439 | template <typename A, typename B> |
440 | QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder<A, B> &b, QChar) |
441 | { |
442 | return a += QString(b).toUtf8(); |
443 | } |
444 | #endif |
445 | } |
446 | |
447 | template <typename A, typename B> |
448 | QByteArray &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 | |
454 | template <typename A, typename B> |
455 | QString &operator+=(QString &a, const QStringBuilder<A, B> &b) |
456 | { |
457 | int 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(int(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 | |
469 | template <typename A, typename B> |
470 | QAnyStringView::QAnyStringView(const QStringBuilder<A, B> &expr, |
471 | typename QStringBuilder<A, B>::ConvertTo &&capacity) |
472 | : QAnyStringView(capacity = expr) {} |
473 | |
474 | QT_END_NAMESPACE |
475 | |
476 | #endif // QSTRINGBUILDER_H |
477 | |