Merge remote-tracking branch 'gerrit/master' into containers
[profile/ivi/qtbase.git] / src / corelib / tools / qstringbuilder.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
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
61 struct Q_CORE_EXPORT QAbstractConcatenable
62 {
63 protected:
64     static void convertFromAscii(const char *a, int len, QChar *&out);
65     static void convertToAscii(const QChar *a, int len, char *&out);
66     static inline void convertFromAscii(char a, QChar *&out)
67     {
68 #ifndef QT_NO_TEXTCODEC
69         if (QString::codecForCStrings)
70             *out++ = QChar::fromAscii(a);
71         else
72 #endif
73             *out++ = QLatin1Char(a);
74     }
75
76     static inline void convertToAscii(QChar a, char *&out)
77     {
78 #ifndef QT_NO_TEXTCODEC
79         if (QString::codecForCStrings)
80             *out++ = a.toAscii(); //###
81         else
82 #endif
83             convertToLatin1(a, out);
84     }
85
86     static inline void convertToLatin1(QChar a, char *&out)
87     {
88         *out++ = a.unicode() > 0xff ? '?' : char(a.unicode());
89     }
90 };
91
92 template <typename T> struct QConcatenable {};
93
94 template <typename A, typename B>
95 class QStringBuilder
96 {
97 public:
98     QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {}
99 private:
100     friend class QByteArray;
101     friend class QString;
102     template <typename T> T convertTo() const
103     {
104         const uint len = QConcatenable< QStringBuilder<A, B> >::size(*this);
105         T s(len, Qt::Uninitialized);
106
107         typename T::iterator d = s.data();
108         typename T::const_iterator const start = d;
109         QConcatenable< QStringBuilder<A, B> >::appendTo(*this, d);
110
111         if (!QConcatenable< QStringBuilder<A, B> >::ExactSize && int(len) != d - start) {
112             // this resize is necessary since we allocate a bit too much
113             // when dealing with variable sized 8-bit encodings
114             s.resize(d - start);
115         }
116         return s;
117     }
118
119     typedef QConcatenable<QStringBuilder<A, B> > Concatenable;
120     typedef typename Concatenable::ConvertTo ConvertTo;
121 public:
122     operator ConvertTo() const { return convertTo<ConvertTo>(); }
123
124     QByteArray toLatin1() const { return convertTo<QString>().toLatin1(); }
125     int size() const { return Concatenable::size(*this); }
126
127     const A &a;
128     const B &b;
129 };
130
131 template <>
132 class QStringBuilder <QString, QString>
133 {
134     public:
135         QStringBuilder(const QString &a_, const QString &b_) : a(a_), b(b_) {}
136
137         operator QString() const
138         { QString r(a); r += b; return r; }
139         QByteArray toLatin1() const { return QString(*this).toLatin1(); }
140
141         const QString &a;
142         const QString &b;
143 };
144
145 template <>
146 class QStringBuilder <QByteArray, QByteArray>
147 {
148     public:
149         QStringBuilder(const QByteArray &a_, const QByteArray &b_) : a(a_), b(b_) {}
150
151         operator QByteArray() const
152         { QByteArray r(a); r += b; return r; }
153
154         const QByteArray &a;
155         const QByteArray &b;
156 };
157
158
159 template <> struct QConcatenable<char> : private QAbstractConcatenable
160 {
161     typedef char type;
162     typedef QByteArray ConvertTo;
163     enum { ExactSize = true };
164     static int size(const char) { return 1; }
165 #ifndef QT_NO_CAST_FROM_ASCII
166     static inline QT_ASCII_CAST_WARN void appendTo(const char c, QChar *&out)
167     {
168         QAbstractConcatenable::convertFromAscii(c, out);
169     }
170 #endif
171     static inline void appendTo(const char c, char *&out)
172     { *out++ = c; }
173 };
174
175 template <> struct QConcatenable<QLatin1Char>
176 {
177     typedef QLatin1Char type;
178     typedef QString ConvertTo;
179     enum { ExactSize = true };
180     static int size(const QLatin1Char) { return 1; }
181     static inline void appendTo(const QLatin1Char c, QChar *&out)
182     { *out++ = c; }
183     static inline void appendTo(const QLatin1Char c, char *&out)
184     { *out++ = c.toLatin1(); }
185 };
186
187 template <> struct QConcatenable<QChar> : private QAbstractConcatenable
188 {
189     typedef QChar type;
190     typedef QString ConvertTo;
191     enum { ExactSize = true };
192     static int size(const QChar) { return 1; }
193     static inline void appendTo(const QChar c, QChar *&out)
194     { *out++ = c; }
195 #ifndef QT_NO_CAST_TO_ASCII
196     static inline QT_ASCII_CAST_WARN void appendTo(const QChar c, char *&out)
197     { convertToAscii(c, out); }
198 #endif
199 };
200
201 template <> struct QConcatenable<QCharRef> : private QAbstractConcatenable
202 {
203     typedef QCharRef type;
204     typedef QString ConvertTo;
205     enum { ExactSize = true };
206     static int size(const QCharRef &) { return 1; }
207     static inline void appendTo(const QCharRef &c, QChar *&out)
208     { *out++ = QChar(c); }
209 #ifndef QT_NO_CAST_TO_ASCII
210     static inline QT_ASCII_CAST_WARN void appendTo(const QCharRef &c, char *&out)
211     { convertToAscii(c, out); }
212 #endif
213 };
214
215 template <> struct QConcatenable<QLatin1String>
216 {
217     typedef QLatin1String type;
218     typedef QString ConvertTo;
219     enum { ExactSize = true };
220     static int size(const QLatin1String &a) { return a.size(); }
221     static inline void appendTo(const QLatin1String &a, QChar *&out)
222     {
223         for (const char *s = a.data(); *s; )
224             *out++ = QLatin1Char(*s++);
225     }
226     static inline void appendTo(const QLatin1String &a, char *&out)
227     {
228         for (const char *s = a.data(); *s; )
229             *out++ = *s++;
230     }
231 };
232
233 template <> struct QConcatenable<QString> : private QAbstractConcatenable
234 {
235     typedef QString type;
236     typedef QString ConvertTo;
237     enum { ExactSize = true };
238     static int size(const QString &a) { return a.size(); }
239     static inline void appendTo(const QString &a, QChar *&out)
240     {
241         const int n = a.size();
242         memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n);
243         out += n;
244     }
245 #ifndef QT_NO_CAST_TO_ASCII
246     static inline QT_ASCII_CAST_WARN void appendTo(const QString &a, char *&out)
247     { convertToAscii(a.constData(), a.length(), out); }
248 #endif
249 };
250
251 template <int N> struct QConcatenable<QStaticStringDataPtr<N> > : private QAbstractConcatenable
252 {
253     typedef QStaticStringDataPtr<N> type;
254     typedef QString ConvertTo;
255     enum { ExactSize = true };
256     static int size(const type &) { return N; }
257     static inline void appendTo(const type &a, QChar *&out)
258     {
259         memcpy(out, reinterpret_cast<const char*>(a.ptr->data), sizeof(QChar) * N);
260         out += N;
261     }
262 #ifndef QT_NO_CAST_TO_ASCII
263     static inline QT_ASCII_CAST_WARN void appendTo(const type &a, char *&out)
264     { convertToAscii(a.ptr->data, N, out); }
265 #endif
266 };
267
268 template <> struct QConcatenable<QStringRef> : private QAbstractConcatenable
269 {
270     typedef QStringRef type;
271     typedef QString ConvertTo;
272     enum { ExactSize = true };
273     static int size(const QStringRef &a) { return a.size(); }
274     static inline void appendTo(const QStringRef &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 QStringRef &a, char *&out)
282     { convertToAscii(a.constData(), a.length(), out); }
283 #endif
284
285 };
286
287 template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable
288 {
289     typedef char type[N];
290     typedef QByteArray ConvertTo;
291     enum { ExactSize = false };
292     static int size(const char[N]) { return N - 1; }
293 #ifndef QT_NO_CAST_FROM_ASCII
294     static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out)
295     {
296         QAbstractConcatenable::convertFromAscii(a, N - 1, out);
297     }
298 #endif
299     static inline void appendTo(const char a[N], char *&out)
300     {
301         while (*a)
302             *out++ = *a++;
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 <> struct QConcatenable<const char *> : private QAbstractConcatenable
326 {
327     typedef char const *type;
328     typedef QByteArray ConvertTo;
329     enum { ExactSize = false };
330     static int size(const char *a) { return qstrlen(a); }
331 #ifndef QT_NO_CAST_FROM_ASCII
332     static inline void QT_ASCII_CAST_WARN appendTo(const char *a, QChar *&out)
333     { QAbstractConcatenable::convertFromAscii(a, -1, out); }
334 #endif
335     static inline void appendTo(const char *a, char *&out)
336     {
337         if (!a)
338             return;
339         while (*a)
340             *out++ = *a++;
341     }
342 };
343
344 template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable
345 {
346     typedef QByteArray type;
347     typedef QByteArray ConvertTo;
348     enum { ExactSize = false };
349     static int size(const QByteArray &ba) { return ba.size(); }
350 #ifndef QT_NO_CAST_FROM_ASCII
351     static inline QT_ASCII_CAST_WARN void appendTo(const QByteArray &ba, QChar *&out)
352     {
353         QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size(), out);
354     }
355 #endif
356     static inline void appendTo(const QByteArray &ba, char *&out)
357     {
358         const char *a = ba.constData();
359         const char * const end = ba.end();
360         while (a != end)
361             *out++ = *a++;
362     }
363 };
364
365 template <int N> struct QConcatenable<QStaticByteArrayDataPtr<N> > : private QAbstractConcatenable
366 {
367     typedef QStaticByteArrayDataPtr<N> type;
368     typedef QByteArray ConvertTo;
369     enum { ExactSize = false };
370     static int size(const type &) { return N; }
371 #ifndef QT_NO_CAST_FROM_ASCII
372     static inline QT_ASCII_CAST_WARN void appendTo(const type &a, QChar *&out)
373     {
374         QAbstractConcatenable::convertFromAscii(a.ptr->data, N, out);
375     }
376 #endif
377     static inline void appendTo(const type &ba, char *&out)
378     {
379         ::memcpy(out, ba.ptr->data, N);
380         out += N;
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