Merge master -> api_changes
[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 inline void convertFromAscii(char a, QChar *&out)
66     {
67         *out++ = QLatin1Char(a);
68     }
69 };
70
71 template <typename T> struct QConcatenable {};
72
73 template <typename A, typename B>
74 class QStringBuilder
75 {
76 public:
77     QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {}
78 private:
79     friend class QByteArray;
80     friend class QString;
81     template <typename T> T convertTo() const
82     {
83         const uint len = QConcatenable< QStringBuilder<A, B> >::size(*this);
84         T s(len, Qt::Uninitialized);
85
86         typename T::iterator d = s.data();
87         typename T::const_iterator const start = d;
88         QConcatenable< QStringBuilder<A, B> >::appendTo(*this, d);
89
90         if (!QConcatenable< QStringBuilder<A, B> >::ExactSize && int(len) != d - start) {
91             // this resize is necessary since we allocate a bit too much
92             // when dealing with variable sized 8-bit encodings
93             s.resize(d - start);
94         }
95         return s;
96     }
97
98     typedef QConcatenable<QStringBuilder<A, B> > Concatenable;
99     typedef typename Concatenable::ConvertTo ConvertTo;
100 public:
101     operator ConvertTo() const { return convertTo<ConvertTo>(); }
102
103     QByteArray toLatin1() const { return convertTo<QString>().toLatin1(); }
104     int size() const { return Concatenable::size(*this); }
105
106     const A &a;
107     const B &b;
108 };
109
110 template <>
111 class QStringBuilder <QString, QString>
112 {
113     public:
114         QStringBuilder(const QString &a_, const QString &b_) : a(a_), b(b_) {}
115
116         operator QString() const
117         { QString r(a); r += b; return r; }
118         QByteArray toLatin1() const { return QString(*this).toLatin1(); }
119
120         const QString &a;
121         const QString &b;
122 };
123
124 template <>
125 class QStringBuilder <QByteArray, QByteArray>
126 {
127     public:
128         QStringBuilder(const QByteArray &a_, const QByteArray &b_) : a(a_), b(b_) {}
129
130         operator QByteArray() const
131         { QByteArray r(a); r += b; return r; }
132
133         const QByteArray &a;
134         const QByteArray &b;
135 };
136
137
138 template <> struct QConcatenable<char> : private QAbstractConcatenable
139 {
140     typedef char type;
141     typedef QByteArray ConvertTo;
142     enum { ExactSize = true };
143     static int size(const char) { return 1; }
144 #ifndef QT_NO_CAST_FROM_ASCII
145     static inline QT_ASCII_CAST_WARN void appendTo(const char c, QChar *&out)
146     {
147         QAbstractConcatenable::convertFromAscii(c, out);
148     }
149 #endif
150     static inline void appendTo(const char c, char *&out)
151     { *out++ = c; }
152 };
153
154 template <> struct QConcatenable<QLatin1Char>
155 {
156     typedef QLatin1Char type;
157     typedef QString ConvertTo;
158     enum { ExactSize = true };
159     static int size(const QLatin1Char) { return 1; }
160     static inline void appendTo(const QLatin1Char c, QChar *&out)
161     { *out++ = c; }
162     static inline void appendTo(const QLatin1Char c, char *&out)
163     { *out++ = c.toLatin1(); }
164 };
165
166 template <> struct QConcatenable<QChar> : private QAbstractConcatenable
167 {
168     typedef QChar type;
169     typedef QString ConvertTo;
170     enum { ExactSize = true };
171     static int size(const QChar) { return 1; }
172     static inline void appendTo(const QChar c, QChar *&out)
173     { *out++ = c; }
174 };
175
176 template <> struct QConcatenable<QCharRef> : private QAbstractConcatenable
177 {
178     typedef QCharRef type;
179     typedef QString ConvertTo;
180     enum { ExactSize = true };
181     static int size(const QCharRef &) { return 1; }
182     static inline void appendTo(const QCharRef &c, QChar *&out)
183     { *out++ = QChar(c); }
184 };
185
186 template <> struct QConcatenable<QLatin1String>
187 {
188     typedef QLatin1String type;
189     typedef QString ConvertTo;
190     enum { ExactSize = true };
191     static int size(const QLatin1String &a) { return a.size(); }
192     static inline void appendTo(const QLatin1String &a, QChar *&out)
193     {
194         for (const char *s = a.data(); *s; )
195             *out++ = QLatin1Char(*s++);
196     }
197     static inline void appendTo(const QLatin1String &a, char *&out)
198     {
199         for (const char *s = a.data(); *s; )
200             *out++ = *s++;
201     }
202 };
203
204 template <> struct QConcatenable<QString> : private QAbstractConcatenable
205 {
206     typedef QString type;
207     typedef QString ConvertTo;
208     enum { ExactSize = true };
209     static int size(const QString &a) { return a.size(); }
210     static inline void appendTo(const QString &a, QChar *&out)
211     {
212         const int n = a.size();
213         memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n);
214         out += n;
215     }
216 };
217
218 template <int N> struct QConcatenable<QConstStringDataPtr<N> > : private QAbstractConcatenable
219 {
220     typedef QConstStringDataPtr<N> type;
221     typedef QString ConvertTo;
222     enum { ExactSize = true };
223     static int size(const type &) { return N; }
224     static inline void appendTo(const type &a, QChar *&out)
225     {
226         memcpy(out, reinterpret_cast<const char*>(a.ptr->data), sizeof(QChar) * N);
227         out += N;
228     }
229 };
230
231 template <> struct QConcatenable<QStringRef> : private QAbstractConcatenable
232 {
233     typedef QStringRef type;
234     typedef QString ConvertTo;
235     enum { ExactSize = true };
236     static int size(const QStringRef &a) { return a.size(); }
237     static inline void appendTo(const QStringRef &a, QChar *&out)
238     {
239         const int n = a.size();
240         memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n);
241         out += n;
242     }
243 };
244
245 template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable
246 {
247     typedef char type[N];
248     typedef QByteArray ConvertTo;
249     enum { ExactSize = false };
250     static int size(const char[N]) { return N - 1; }
251 #ifndef QT_NO_CAST_FROM_ASCII
252     static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out)
253     {
254         QAbstractConcatenable::convertFromAscii(a, N - 1, out);
255     }
256 #endif
257     static inline void appendTo(const char a[N], char *&out)
258     {
259         while (*a)
260             *out++ = *a++;
261     }
262 };
263
264 template <int N> struct QConcatenable<const char[N]> : private QAbstractConcatenable
265 {
266     typedef const char type[N];
267     typedef QByteArray ConvertTo;
268     enum { ExactSize = false };
269     static int size(const char[N]) { return N - 1; }
270 #ifndef QT_NO_CAST_FROM_ASCII
271     static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out)
272     {
273         QAbstractConcatenable::convertFromAscii(a, N - 1, out);
274     }
275 #endif
276     static inline void appendTo(const char a[N], char *&out)
277     {
278         while (*a)
279             *out++ = *a++;
280     }
281 };
282
283 template <> struct QConcatenable<const char *> : private QAbstractConcatenable
284 {
285     typedef char const *type;
286     typedef QByteArray ConvertTo;
287     enum { ExactSize = false };
288     static int size(const char *a) { return qstrlen(a); }
289 #ifndef QT_NO_CAST_FROM_ASCII
290     static inline void QT_ASCII_CAST_WARN appendTo(const char *a, QChar *&out)
291     { QAbstractConcatenable::convertFromAscii(a, -1, out); }
292 #endif
293     static inline void appendTo(const char *a, char *&out)
294     {
295         if (!a)
296             return;
297         while (*a)
298             *out++ = *a++;
299     }
300 };
301
302 template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable
303 {
304     typedef QByteArray type;
305     typedef QByteArray ConvertTo;
306     enum { ExactSize = false };
307     static int size(const QByteArray &ba) { return ba.size(); }
308 #ifndef QT_NO_CAST_FROM_ASCII
309     static inline QT_ASCII_CAST_WARN void appendTo(const QByteArray &ba, QChar *&out)
310     {
311         QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size(), out);
312     }
313 #endif
314     static inline void appendTo(const QByteArray &ba, char *&out)
315     {
316         const char *a = ba.constData();
317         const char * const end = ba.end();
318         while (a != end)
319             *out++ = *a++;
320     }
321 };
322
323 template <int N> struct QConcatenable<QConstByteArrayDataPtr<N> > : private QAbstractConcatenable
324 {
325     typedef QConstByteArrayDataPtr<N> type;
326     typedef QByteArray ConvertTo;
327     enum { ExactSize = false };
328     static int size(const type &) { return N; }
329 #ifndef QT_NO_CAST_FROM_ASCII
330     static inline QT_ASCII_CAST_WARN void appendTo(const type &a, QChar *&out)
331     {
332         QAbstractConcatenable::convertFromAscii(a.ptr->data, N, out);
333     }
334 #endif
335     static inline void appendTo(const type &ba, char *&out)
336     {
337         const char *a = ba.ptr->data;
338         while (*a)
339             *out++ = *a++;
340     }
341 };
342
343 namespace QtStringBuilder {
344     template <typename A, typename B> struct ConvertToTypeHelper
345     { typedef A ConvertTo; };
346     template <typename T> struct ConvertToTypeHelper<T, QString>
347     { typedef QString ConvertTo; };
348 }
349
350 template <typename A, typename B>
351 struct QConcatenable< QStringBuilder<A, B> >
352 {
353     typedef QStringBuilder<A, B> type;
354     typedef typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo ConvertTo;
355     enum { ExactSize = QConcatenable<A>::ExactSize && QConcatenable<B>::ExactSize };
356     static int size(const type &p)
357     {
358         return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b);
359     }
360     template<typename T> static inline void appendTo(const type &p, T *&out)
361     {
362         QConcatenable<A>::appendTo(p.a, out);
363         QConcatenable<B>::appendTo(p.b, out);
364     }
365 };
366
367 template <typename A, typename B>
368 QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
369 operator%(const A &a, const B &b)
370 {
371    return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b);
372 }
373
374 // QT_USE_FAST_OPERATOR_PLUS was introduced in 4.7, QT_USE_QSTRINGBUILDER is to be used from 4.8 onwards
375 // QT_USE_FAST_OPERATOR_PLUS does not remove the normal operator+ for QByteArray
376 #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
377 template <typename A, typename B>
378 QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
379 operator+(const A &a, const B &b)
380 {
381    return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b);
382 }
383 #endif
384
385 template <typename A, typename B>
386 QByteArray &operator+=(QByteArray &a, const QStringBuilder<A, B> &b)
387 {
388 #ifndef QT_NO_CAST_TO_ASCII
389     if (sizeof(typename QConcatenable< QStringBuilder<A, B> >::ConvertTo::value_type) == sizeof(QChar)) {
390         //it is not save to optimize as in utf8 it is not possible to compute the size
391         return a += QString(b);
392     }
393 #endif
394     int len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b);
395     a.reserve(len);
396     char *it = a.data() + a.size();
397     QConcatenable< QStringBuilder<A, B> >::appendTo(b, it);
398     a.resize(len); //we need to resize after the appendTo for the case str+=foo+str
399     return a;
400 }
401
402 template <typename A, typename B>
403 QString &operator+=(QString &a, const QStringBuilder<A, B> &b)
404 {
405     int len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b);
406     a.reserve(len);
407     QChar *it = a.data() + a.size();
408     QConcatenable< QStringBuilder<A, B> >::appendTo(b, it);
409     a.resize(it - a.constData()); //may be smaller than len if there was conversion from utf8
410     return a;
411 }
412
413
414 QT_END_NAMESPACE
415
416 QT_END_HEADER
417
418 #endif // QSTRINGBUILDER_H