1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
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 Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #ifndef QSTRINGBUILDER_H |
43 | #define QSTRINGBUILDER_H |
44 | |
45 | #include <QtCore/qstring.h> |
46 | #include <QtCore/qbytearray.h> |
47 | |
48 | #if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) |
49 | # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 0) |
50 | # include <QtCore/qmap.h> |
51 | # endif |
52 | #endif |
53 | |
54 | #include <string.h> |
55 | |
56 | QT_BEGIN_HEADER |
57 | |
58 | QT_BEGIN_NAMESPACE |
59 | |
60 | QT_MODULE(Core) |
61 | |
62 | // ### Qt 5: merge with QLatin1String |
63 | class QLatin1Literal |
64 | { |
65 | public: |
66 | int size() const { return m_size; } |
67 | const char *data() const { return m_data; } |
68 | |
69 | template <int N> |
70 | QLatin1Literal(const char (&str)[N]) |
71 | : m_size(N - 1), m_data(str) {} |
72 | |
73 | private: |
74 | const int m_size; |
75 | const char * const m_data; |
76 | }; |
77 | |
78 | struct Q_CORE_EXPORT QAbstractConcatenable |
79 | { |
80 | protected: |
81 | static void convertFromAscii(const char *a, int len, QChar *&out); |
82 | static void convertToAscii(const QChar *a, int len, char *&out); |
83 | static inline void convertFromAscii(char a, QChar *&out) |
84 | { |
85 | #ifndef QT_NO_TEXTCODEC |
86 | if (QString::codecForCStrings) |
87 | *out++ = QChar::fromAscii(a); |
88 | else |
89 | #endif |
90 | *out++ = QLatin1Char(a); |
91 | } |
92 | |
93 | static inline void convertToAscii(QChar a, char *&out) |
94 | { |
95 | #ifndef QT_NO_TEXTCODEC |
96 | if (QString::codecForCStrings) |
97 | *out++ = a.toAscii(); //### |
98 | else |
99 | #endif |
100 | convertToLatin1(a, out); |
101 | } |
102 | |
103 | static inline void convertToLatin1(QChar a, char *&out) |
104 | { |
105 | *out++ = a.unicode() > 0xff ? '?' : char(a.unicode()); |
106 | } |
107 | }; |
108 | |
109 | template <typename T> struct QConcatenable {}; |
110 | |
111 | template <typename A, typename B> |
112 | class QStringBuilder |
113 | { |
114 | public: |
115 | QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {} |
116 | private: |
117 | friend class QByteArray; |
118 | friend class QString; |
119 | template <typename T> T convertTo() const |
120 | { |
121 | const uint len = QConcatenable< QStringBuilder<A, B> >::size(*this); |
122 | T s(len, Qt::Uninitialized); |
123 | |
124 | typename T::iterator d = s.data(); |
125 | typename T::const_iterator const start = d; |
126 | QConcatenable< QStringBuilder<A, B> >::appendTo(*this, d); |
127 | |
128 | if (!QConcatenable< QStringBuilder<A, B> >::ExactSize && int(len) != d - start) { |
129 | // this resize is necessary since we allocate a bit too much |
130 | // when dealing with variable sized 8-bit encodings |
131 | s.resize(d - start); |
132 | } |
133 | return s; |
134 | } |
135 | |
136 | typedef QConcatenable<QStringBuilder<A, B> > Concatenable; |
137 | typedef typename Concatenable::ConvertTo ConvertTo; |
138 | public: |
139 | operator ConvertTo() const { return convertTo<ConvertTo>(); } |
140 | |
141 | QByteArray toLatin1() const { return convertTo<QString>().toLatin1(); } |
142 | int size() const { return Concatenable::size(*this); } |
143 | |
144 | const A &a; |
145 | const B &b; |
146 | }; |
147 | |
148 | template <> |
149 | class QStringBuilder <QString, QString> |
150 | { |
151 | public: |
152 | QStringBuilder(const QString &a_, const QString &b_) : a(a_), b(b_) {} |
153 | |
154 | operator QString() const |
155 | { QString r(a); r += b; return r; } |
156 | QByteArray toLatin1() const { return QString(*this).toLatin1(); } |
157 | |
158 | const QString &a; |
159 | const QString &b; |
160 | }; |
161 | |
162 | template <> |
163 | class QStringBuilder <QByteArray, QByteArray> |
164 | { |
165 | public: |
166 | QStringBuilder(const QByteArray &a_, const QByteArray &b_) : a(a_), b(b_) {} |
167 | |
168 | operator QByteArray() const |
169 | { QByteArray r(a); r += b; return r; } |
170 | |
171 | const QByteArray &a; |
172 | const QByteArray &b; |
173 | }; |
174 | |
175 | |
176 | template <> struct QConcatenable<char> : private QAbstractConcatenable |
177 | { |
178 | typedef char type; |
179 | typedef QByteArray ConvertTo; |
180 | enum { ExactSize = true }; |
181 | static int size(const char) { return 1; } |
182 | #ifndef QT_NO_CAST_FROM_ASCII |
183 | static inline QT_ASCII_CAST_WARN void appendTo(const char c, QChar *&out) |
184 | { |
185 | QAbstractConcatenable::convertFromAscii(c, out); |
186 | } |
187 | #endif |
188 | static inline void appendTo(const char c, char *&out) |
189 | { *out++ = c; } |
190 | }; |
191 | |
192 | template <> struct QConcatenable<QLatin1Char> |
193 | { |
194 | typedef QLatin1Char type; |
195 | typedef QString ConvertTo; |
196 | enum { ExactSize = true }; |
197 | static int size(const QLatin1Char) { return 1; } |
198 | static inline void appendTo(const QLatin1Char c, QChar *&out) |
199 | { *out++ = c; } |
200 | static inline void appendTo(const QLatin1Char c, char *&out) |
201 | { *out++ = c.toLatin1(); } |
202 | }; |
203 | |
204 | template <> struct QConcatenable<QChar> : private QAbstractConcatenable |
205 | { |
206 | typedef QChar type; |
207 | typedef QString ConvertTo; |
208 | enum { ExactSize = true }; |
209 | static int size(const QChar) { return 1; } |
210 | static inline void appendTo(const QChar c, QChar *&out) |
211 | { *out++ = c; } |
212 | #ifndef QT_NO_CAST_TO_ASCII |
213 | static inline QT_ASCII_CAST_WARN void appendTo(const QChar c, char *&out) |
214 | { convertToAscii(c, out); } |
215 | #endif |
216 | }; |
217 | |
218 | template <> struct QConcatenable<QCharRef> : private QAbstractConcatenable |
219 | { |
220 | typedef QCharRef type; |
221 | typedef QString ConvertTo; |
222 | enum { ExactSize = true }; |
223 | static int size(const QCharRef &) { return 1; } |
224 | static inline void appendTo(const QCharRef &c, QChar *&out) |
225 | { *out++ = QChar(c); } |
226 | #ifndef QT_NO_CAST_TO_ASCII |
227 | static inline QT_ASCII_CAST_WARN void appendTo(const QCharRef &c, char *&out) |
228 | { convertToAscii(c, out); } |
229 | #endif |
230 | }; |
231 | |
232 | template <> struct QConcatenable<QLatin1String> |
233 | { |
234 | typedef QLatin1String type; |
235 | typedef QString ConvertTo; |
236 | enum { ExactSize = true }; |
237 | static int size(const QLatin1String &a) { return qstrlen(a.latin1()); } |
238 | static inline void appendTo(const QLatin1String &a, QChar *&out) |
239 | { |
240 | for (const char *s = a.latin1(); *s; ) |
241 | *out++ = QLatin1Char(*s++); |
242 | } |
243 | static inline void appendTo(const QLatin1String &a, char *&out) |
244 | { |
245 | for (const char *s = a.latin1(); *s; ) |
246 | *out++ = *s++; |
247 | } |
248 | }; |
249 | |
250 | template <> struct QConcatenable<QLatin1Literal> |
251 | { |
252 | typedef QLatin1Literal type; |
253 | typedef QString ConvertTo; |
254 | enum { ExactSize = true }; |
255 | static int size(const QLatin1Literal &a) { return a.size(); } |
256 | static inline void appendTo(const QLatin1Literal &a, QChar *&out) |
257 | { |
258 | for (const char *s = a.data(); *s; ) |
259 | *out++ = QLatin1Char(*s++); |
260 | } |
261 | static inline void appendTo(const QLatin1Literal &a, char *&out) |
262 | { |
263 | for (const char *s = a.data(); *s; ) |
264 | *out++ = *s++; |
265 | } |
266 | }; |
267 | |
268 | template <> struct QConcatenable<QString> : private QAbstractConcatenable |
269 | { |
270 | typedef QString type; |
271 | typedef QString ConvertTo; |
272 | enum { ExactSize = true }; |
273 | static int size(const QString &a) { return a.size(); } |
274 | static inline void appendTo(const QString &a, QChar *&out) |
275 | { |
276 | const int n = a.size(); |
277 | memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n); |
278 | out += n; |
279 | } |
280 | #ifndef QT_NO_CAST_TO_ASCII |
281 | static inline QT_ASCII_CAST_WARN void appendTo(const QString &a, char *&out) |
282 | { convertToAscii(a.constData(), a.length(), out); } |
283 | #endif |
284 | }; |
285 | |
286 | template <> struct QConcatenable<QStringRef> : private QAbstractConcatenable |
287 | { |
288 | typedef QStringRef type; |
289 | typedef QString ConvertTo; |
290 | enum { ExactSize = true }; |
291 | static int size(const QStringRef &a) { return a.size(); } |
292 | static inline void appendTo(const QStringRef &a, QChar *&out) |
293 | { |
294 | const int n = a.size(); |
295 | memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n); |
296 | out += n; |
297 | } |
298 | #ifndef QT_NO_CAST_TO_ASCII |
299 | static inline QT_ASCII_CAST_WARN void appendTo(const QStringRef &a, char *&out) |
300 | { convertToAscii(a.constData(), a.length(), out); } |
301 | #endif |
302 | |
303 | }; |
304 | |
305 | template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable |
306 | { |
307 | typedef char type[N]; |
308 | typedef QByteArray ConvertTo; |
309 | enum { ExactSize = false }; |
310 | static int size(const char[N]) { return N - 1; } |
311 | #ifndef QT_NO_CAST_FROM_ASCII |
312 | static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out) |
313 | { |
314 | QAbstractConcatenable::convertFromAscii(a, N, out); |
315 | } |
316 | #endif |
317 | static inline void appendTo(const char a[N], char *&out) |
318 | { |
319 | while (*a) |
320 | *out++ = *a++; |
321 | } |
322 | }; |
323 | |
324 | template <int N> struct QConcatenable<const char[N]> : private QAbstractConcatenable |
325 | { |
326 | typedef const char type[N]; |
327 | typedef QByteArray ConvertTo; |
328 | enum { ExactSize = false }; |
329 | static int size(const char[N]) { return N - 1; } |
330 | #ifndef QT_NO_CAST_FROM_ASCII |
331 | static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out) |
332 | { |
333 | QAbstractConcatenable::convertFromAscii(a, N, out); |
334 | } |
335 | #endif |
336 | static inline void appendTo(const char a[N], char *&out) |
337 | { |
338 | while (*a) |
339 | *out++ = *a++; |
340 | } |
341 | }; |
342 | |
343 | template <> struct QConcatenable<const char *> : private QAbstractConcatenable |
344 | { |
345 | typedef char const *type; |
346 | typedef QByteArray ConvertTo; |
347 | enum { ExactSize = false }; |
348 | static int size(const char *a) { return qstrlen(a); } |
349 | #ifndef QT_NO_CAST_FROM_ASCII |
350 | static inline void QT_ASCII_CAST_WARN appendTo(const char *a, QChar *&out) |
351 | { QAbstractConcatenable::convertFromAscii(a, -1, out); } |
352 | #endif |
353 | static inline void appendTo(const char *a, char *&out) |
354 | { |
355 | if (!a) |
356 | return; |
357 | while (*a) |
358 | *out++ = *a++; |
359 | } |
360 | }; |
361 | |
362 | template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable |
363 | { |
364 | typedef QByteArray type; |
365 | typedef QByteArray ConvertTo; |
366 | enum { ExactSize = false }; |
367 | static int size(const QByteArray &ba) { return ba.size(); } |
368 | #ifndef QT_NO_CAST_FROM_ASCII |
369 | static inline void appendTo(const QByteArray &ba, QChar *&out) |
370 | { |
371 | // adding 1 because convertFromAscii expects the size including the null-termination |
372 | QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size() + 1, out); |
373 | } |
374 | #endif |
375 | static inline void appendTo(const QByteArray &ba, char *&out) |
376 | { |
377 | const char *a = ba.constData(); |
378 | const char * const end = ba.end(); |
379 | while (a != end) |
380 | *out++ = *a++; |
381 | } |
382 | }; |
383 | |
384 | namespace QtStringBuilder { |
385 | template <typename A, typename B> struct ConvertToTypeHelper |
386 | { typedef A ConvertTo; }; |
387 | template <typename T> struct ConvertToTypeHelper<T, QString> |
388 | { typedef QString ConvertTo; }; |
389 | } |
390 | |
391 | template <typename A, typename B> |
392 | struct QConcatenable< QStringBuilder<A, B> > |
393 | { |
394 | typedef QStringBuilder<A, B> type; |
395 | typedef typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo ConvertTo; |
396 | enum { ExactSize = QConcatenable<A>::ExactSize && QConcatenable<B>::ExactSize }; |
397 | static int size(const type &p) |
398 | { |
399 | return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b); |
400 | } |
401 | template<typename T> static inline void appendTo(const type &p, T *&out) |
402 | { |
403 | QConcatenable<A>::appendTo(p.a, out); |
404 | QConcatenable<B>::appendTo(p.b, out); |
405 | } |
406 | }; |
407 | |
408 | template <typename A, typename B> |
409 | QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type> |
410 | operator%(const A &a, const B &b) |
411 | { |
412 | return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b); |
413 | } |
414 | |
415 | // QT_USE_FAST_OPERATOR_PLUS was introduced in 4.7, QT_USE_QSTRINGBUILDER is to be used from 4.8 onwards |
416 | // QT_USE_FAST_OPERATOR_PLUS does not remove the normal operator+ for QByteArray |
417 | #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER) |
418 | template <typename A, typename B> |
419 | QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type> |
420 | operator+(const A &a, const B &b) |
421 | { |
422 | return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b); |
423 | } |
424 | #endif |
425 | |
426 | template <typename A, typename B> |
427 | QByteArray &operator+=(QByteArray &a, const QStringBuilder<A, B> &b) |
428 | { |
429 | #ifndef QT_NO_CAST_TO_ASCII |
430 | if (sizeof(typename QConcatenable< QStringBuilder<A, B> >::ConvertTo::value_type) == sizeof(QChar)) { |
431 | //it is not save to optimize as in utf8 it is not possible to compute the size |
432 | return a += QString(b); |
433 | } |
434 | #endif |
435 | int len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b); |
436 | a.reserve(len); |
437 | char *it = a.data() + a.size(); |
438 | QConcatenable< QStringBuilder<A, B> >::appendTo(b, it); |
439 | a.resize(len); //we need to resize after the appendTo for the case str+=foo+str |
440 | return a; |
441 | } |
442 | |
443 | template <typename A, typename B> |
444 | QString &operator+=(QString &a, const QStringBuilder<A, B> &b) |
445 | { |
446 | int len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b); |
447 | a.reserve(len); |
448 | QChar *it = a.data() + a.size(); |
449 | QConcatenable< QStringBuilder<A, B> >::appendTo(b, it); |
450 | a.resize(it - a.constData()); //may be smaller than len if there was conversion from utf8 |
451 | return a; |
452 | } |
453 | |
454 | |
455 | QT_END_NAMESPACE |
456 | |
457 | QT_END_HEADER |
458 | |
459 | #endif // QSTRINGBUILDER_H |
460 | |