Merge branch 'master' of git://scm.dev.nokia.troll.no/qt/qtbase-staging
[profile/ivi/qtbase.git] / src / corelib / tools / qstringbuilder.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
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 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         while (*a)
356             *out++ = *a++;
357     }
358 };
359
360 template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable
361 {
362     typedef QByteArray type;
363     typedef QByteArray ConvertTo;
364     enum { ExactSize = false };
365     static int size(const QByteArray &ba) { return ba.size(); }
366 #ifndef QT_NO_CAST_FROM_ASCII
367     static inline void appendTo(const QByteArray &ba, QChar *&out)
368     {
369         // adding 1 because convertFromAscii expects the size including the null-termination
370         QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size() + 1, out);
371     }
372 #endif
373     static inline void appendTo(const QByteArray &ba, char *&out)
374     {
375         const char *a = ba.constData();
376         const char * const end = ba.end();
377         while (a != end)
378             *out++ = *a++;
379     }
380 };
381
382 namespace QtStringBuilder {
383     template <typename A, typename B> struct ConvertToTypeHelper
384     { typedef A ConvertTo; };
385     template <typename T> struct ConvertToTypeHelper<T, QString>
386     { typedef QString ConvertTo; };
387 }
388
389 template <typename A, typename B>
390 struct QConcatenable< QStringBuilder<A, B> >
391 {
392     typedef QStringBuilder<A, B> type;
393     typedef typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo ConvertTo;
394     enum { ExactSize = QConcatenable<A>::ExactSize && QConcatenable<B>::ExactSize };
395     static int size(const type &p)
396     {
397         return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b);
398     }
399     template<typename T> static inline void appendTo(const type &p, T *&out)
400     {
401         QConcatenable<A>::appendTo(p.a, out);
402         QConcatenable<B>::appendTo(p.b, out);
403     }
404 };
405
406 template <typename A, typename B>
407 QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
408 operator%(const A &a, const B &b)
409 {
410    return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b);
411 }
412
413 // QT_USE_FAST_OPERATOR_PLUS was introduced in 4.7, QT_USE_QSTRINGBUILDER is to be used from 4.8 onwards
414 // QT_USE_FAST_OPERATOR_PLUS does not remove the normal operator+ for QByteArray
415 #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
416 template <typename A, typename B>
417 QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
418 operator+(const A &a, const B &b)
419 {
420    return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b);
421 }
422 #endif
423
424 template <typename A, typename B>
425 QByteArray &operator+=(QByteArray &a, const QStringBuilder<A, B> &b)
426 {
427 #ifndef QT_NO_CAST_TO_ASCII
428     if (sizeof(typename QConcatenable< QStringBuilder<A, B> >::ConvertTo::value_type) == sizeof(QChar)) {
429         //it is not save to optimize as in utf8 it is not possible to compute the size
430         return a += QString(b);
431     }
432 #endif
433     int len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b);
434     a.reserve(len);
435     char *it = a.data() + a.size();
436     QConcatenable< QStringBuilder<A, B> >::appendTo(b, it);
437     a.resize(len); //we need to resize after the appendTo for the case str+=foo+str
438     return a;
439 }
440
441 template <typename A, typename B>
442 QString &operator+=(QString &a, const QStringBuilder<A, B> &b)
443 {
444     int len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b);
445     a.reserve(len);
446     QChar *it = a.data() + a.size();
447     QConcatenable< QStringBuilder<A, B> >::appendTo(b, it);
448     a.resize(it - a.constData()); //may be smaller than len if there was conversion from utf8
449     return a;
450 }
451
452
453 QT_END_NAMESPACE
454
455 QT_END_HEADER
456
457 #endif // QSTRINGBUILDER_H