Merge remote-tracking branch 'origin/master' into 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 #if 0
46 // syncqt can not handle the templates in this file, and it doesn't need to
47 // process them anyway because they are internal.
48 #pragma qt_class(QStringBuilder)
49 #pragma qt_sync_stop_processing
50 #endif
51
52 #include <QtCore/qstring.h>
53 #include <QtCore/qbytearray.h>
54
55 #include <string.h>
56
57 QT_BEGIN_HEADER
58
59 QT_BEGIN_NAMESPACE
60
61
62 struct Q_CORE_EXPORT QAbstractConcatenable
63 {
64 protected:
65     static void convertFromAscii(const char *a, int len, QChar *&out);
66     static inline void convertFromAscii(char a, QChar *&out)
67     {
68         *out++ = QLatin1Char(a);
69     }
70 };
71
72 template <typename T> struct QConcatenable {};
73
74 namespace QtStringBuilder {
75     template <typename A, typename B> struct ConvertToTypeHelper
76     { typedef A ConvertTo; };
77     template <typename T> struct ConvertToTypeHelper<T, QString>
78     { typedef QString ConvertTo; };
79 }
80
81 template<typename Builder, typename T>
82 struct QStringBuilderCommon
83 {
84     T toUpper() const { return resolved().toUpper(); }
85     T toLower() const { return resolved().toLower(); }
86
87 protected:
88     const T resolved() const { return *static_cast<const Builder*>(this); }
89 };
90
91 template<typename Builder, typename T>
92 struct QStringBuilderBase : public QStringBuilderCommon<Builder, T>
93 {
94 };
95
96 template<typename Builder>
97 struct QStringBuilderBase<Builder, QString> : public QStringBuilderCommon<Builder, QString>
98 {
99     QByteArray toLatin1() const { return this->resolved().toLatin1(); }
100     QByteArray toLocal8Bit() const { return this->resolved().toLocal8Bit(); }
101 };
102
103 template <typename A, typename B>
104 class QStringBuilder : public QStringBuilderBase<QStringBuilder<A, B>, typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo>
105 {
106 public:
107     QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {}
108 private:
109     friend class QByteArray;
110     friend class QString;
111     template <typename T> T convertTo() const
112     {
113         const uint len = QConcatenable< QStringBuilder<A, B> >::size(*this);
114         T s(len, Qt::Uninitialized);
115
116         typename T::iterator d = s.data();
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(d - start);
124         }
125         return s;
126     }
127
128     typedef QConcatenable<QStringBuilder<A, B> > Concatenable;
129     typedef typename Concatenable::ConvertTo ConvertTo;
130 public:
131     operator ConvertTo() const { return convertTo<ConvertTo>(); }
132
133     int 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
145         operator QString() const
146         { QString r(a); r += b; return r; }
147
148         const QString &a;
149         const QString &b;
150 };
151
152 template <>
153 class QStringBuilder <QByteArray, QByteArray> : public QStringBuilderBase<QStringBuilder<QByteArray, QByteArray>, QByteArray>
154 {
155     public:
156         QStringBuilder(const QByteArray &a_, const QByteArray &b_) : a(a_), b(b_) {}
157
158         operator QByteArray() const
159         { QByteArray r(a); r += b; return r; }
160
161         const QByteArray &a;
162         const QByteArray &b;
163 };
164
165
166 template <> struct QConcatenable<char> : private QAbstractConcatenable
167 {
168     typedef char type;
169     typedef QByteArray ConvertTo;
170     enum { ExactSize = true };
171     static int size(const char) { return 1; }
172 #ifndef QT_NO_CAST_FROM_ASCII
173     static inline QT_ASCII_CAST_WARN void appendTo(const char c, QChar *&out)
174     {
175         QAbstractConcatenable::convertFromAscii(c, out);
176     }
177 #endif
178     static inline void appendTo(const char c, char *&out)
179     { *out++ = c; }
180 };
181
182 template <> struct QConcatenable<QLatin1Char>
183 {
184     typedef QLatin1Char type;
185     typedef QString ConvertTo;
186     enum { ExactSize = true };
187     static int size(const QLatin1Char) { return 1; }
188     static inline void appendTo(const QLatin1Char c, QChar *&out)
189     { *out++ = c; }
190     static inline void appendTo(const QLatin1Char c, char *&out)
191     { *out++ = c.toLatin1(); }
192 };
193
194 template <> struct QConcatenable<QChar> : private QAbstractConcatenable
195 {
196     typedef QChar type;
197     typedef QString ConvertTo;
198     enum { ExactSize = true };
199     static int size(const QChar) { return 1; }
200     static inline void appendTo(const QChar c, QChar *&out)
201     { *out++ = c; }
202 };
203
204 template <> struct QConcatenable<QChar::SpecialCharacter> : private QAbstractConcatenable
205 {
206     typedef QChar::SpecialCharacter type;
207     typedef QString ConvertTo;
208     enum { ExactSize = true };
209     static int size(const QChar::SpecialCharacter) { return 1; }
210     static inline void appendTo(const QChar::SpecialCharacter c, QChar *&out)
211     { *out++ = c; }
212 };
213
214 template <> struct QConcatenable<QCharRef> : private QAbstractConcatenable
215 {
216     typedef QCharRef type;
217     typedef QString ConvertTo;
218     enum { ExactSize = true };
219     static int size(const QCharRef &) { return 1; }
220     static inline void appendTo(const QCharRef &c, QChar *&out)
221     { *out++ = QChar(c); }
222 };
223
224 template <> struct QConcatenable<QLatin1String>
225 {
226     typedef QLatin1String type;
227     typedef QString ConvertTo;
228     enum { ExactSize = true };
229     static int size(const QLatin1String &a) { return a.size(); }
230     static inline void appendTo(const QLatin1String &a, QChar *&out)
231     {
232         for (const char *s = a.data(); *s; )
233             *out++ = QLatin1Char(*s++);
234     }
235     static inline void appendTo(const QLatin1String &a, char *&out)
236     {
237         for (const char *s = a.data(); *s; )
238             *out++ = *s++;
239     }
240 };
241
242 template <> struct QConcatenable<QString> : private QAbstractConcatenable
243 {
244     typedef QString type;
245     typedef QString ConvertTo;
246     enum { ExactSize = true };
247     static int size(const QString &a) { return a.size(); }
248     static inline void appendTo(const QString &a, QChar *&out)
249     {
250         const int n = a.size();
251         memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n);
252         out += n;
253     }
254 };
255
256 template <> struct QConcatenable<QStringDataPtr> : private QAbstractConcatenable
257 {
258     typedef QStringDataPtr type;
259     typedef QString ConvertTo;
260     enum { ExactSize = true };
261     static int size(const type &a) { return a.ptr->size; }
262     static inline void appendTo(const type &a, QChar *&out)
263     {
264         memcpy(out, reinterpret_cast<const char*>(a.ptr->data()), sizeof(QChar) * a.ptr->size);
265         out += a.ptr->size;
266     }
267 };
268
269 template <> struct QConcatenable<QStringRef> : private QAbstractConcatenable
270 {
271     typedef QStringRef type;
272     typedef QString ConvertTo;
273     enum { ExactSize = true };
274     static int size(const QStringRef &a) { return a.size(); }
275     static inline void appendTo(const QStringRef &a, QChar *&out)
276     {
277         const int n = a.size();
278         memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n);
279         out += n;
280     }
281 };
282
283 template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable
284 {
285     typedef char type[N];
286     typedef QByteArray ConvertTo;
287     enum { ExactSize = false };
288     static int size(const char[N]) { return N - 1; }
289 #ifndef QT_NO_CAST_FROM_ASCII
290     static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out)
291     {
292         QAbstractConcatenable::convertFromAscii(a, N - 1, out);
293     }
294 #endif
295     static inline void appendTo(const char a[N], char *&out)
296     {
297         while (*a)
298             *out++ = *a++;
299     }
300 };
301
302 template <int N> struct QConcatenable<const char[N]> : private QAbstractConcatenable
303 {
304     typedef const char type[N];
305     typedef QByteArray ConvertTo;
306     enum { ExactSize = false };
307     static int size(const char[N]) { return N - 1; }
308 #ifndef QT_NO_CAST_FROM_ASCII
309     static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out)
310     {
311         QAbstractConcatenable::convertFromAscii(a, N - 1, out);
312     }
313 #endif
314     static inline void appendTo(const char a[N], char *&out)
315     {
316         while (*a)
317             *out++ = *a++;
318     }
319 };
320
321 template <> struct QConcatenable<const char *> : private QAbstractConcatenable
322 {
323     typedef char const *type;
324     typedef QByteArray ConvertTo;
325     enum { ExactSize = false };
326     static int size(const char *a) { return qstrlen(a); }
327 #ifndef QT_NO_CAST_FROM_ASCII
328     static inline void QT_ASCII_CAST_WARN appendTo(const char *a, QChar *&out)
329     { QAbstractConcatenable::convertFromAscii(a, -1, out); }
330 #endif
331     static inline void appendTo(const char *a, char *&out)
332     {
333         if (!a)
334             return;
335         while (*a)
336             *out++ = *a++;
337     }
338 };
339
340 template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable
341 {
342     typedef QByteArray type;
343     typedef QByteArray ConvertTo;
344     enum { ExactSize = false };
345     static int size(const QByteArray &ba) { return ba.size(); }
346 #ifndef QT_NO_CAST_FROM_ASCII
347     static inline QT_ASCII_CAST_WARN void appendTo(const QByteArray &ba, QChar *&out)
348     {
349         QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size(), out);
350     }
351 #endif
352     static inline void appendTo(const QByteArray &ba, char *&out)
353     {
354         const char *a = ba.constData();
355         const char * const end = ba.end();
356         while (a != end)
357             *out++ = *a++;
358     }
359 };
360
361 template <> struct QConcatenable<QByteArrayDataPtr> : private QAbstractConcatenable
362 {
363     typedef QByteArrayDataPtr type;
364     typedef QByteArray ConvertTo;
365     enum { ExactSize = false };
366     static int size(const type &ba) { return ba.ptr->size; }
367 #ifndef QT_NO_CAST_FROM_ASCII
368     static inline QT_ASCII_CAST_WARN void appendTo(const type &a, QChar *&out)
369     {
370         QAbstractConcatenable::convertFromAscii(a.ptr->data(), a.ptr->size, out);
371     }
372 #endif
373     static inline void appendTo(const type &ba, char *&out)
374     {
375         ::memcpy(out, ba.ptr->data(), ba.ptr->size);
376         out += ba.ptr->size;
377     }
378 };
379
380 template <typename A, typename B>
381 struct QConcatenable< QStringBuilder<A, B> >
382 {
383     typedef QStringBuilder<A, B> type;
384     typedef typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo ConvertTo;
385     enum { ExactSize = QConcatenable<A>::ExactSize && QConcatenable<B>::ExactSize };
386     static int size(const type &p)
387     {
388         return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b);
389     }
390     template<typename T> static inline void appendTo(const type &p, T *&out)
391     {
392         QConcatenable<A>::appendTo(p.a, out);
393         QConcatenable<B>::appendTo(p.b, out);
394     }
395 };
396
397 template <typename A, typename B>
398 QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
399 operator%(const A &a, const B &b)
400 {
401    return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b);
402 }
403
404 // QT_USE_FAST_OPERATOR_PLUS was introduced in 4.7, QT_USE_QSTRINGBUILDER is to be used from 4.8 onwards
405 // QT_USE_FAST_OPERATOR_PLUS does not remove the normal operator+ for QByteArray
406 #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
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 #endif
414
415 template <typename A, typename B>
416 QByteArray &operator+=(QByteArray &a, const QStringBuilder<A, B> &b)
417 {
418 #ifndef QT_NO_CAST_TO_ASCII
419     if (sizeof(typename QConcatenable< QStringBuilder<A, B> >::ConvertTo::value_type) == sizeof(QChar)) {
420         //it is not save to optimize as in utf8 it is not possible to compute the size
421         return a += QString(b);
422     }
423 #endif
424     int len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b);
425     a.reserve(len);
426     char *it = a.data() + a.size();
427     QConcatenable< QStringBuilder<A, B> >::appendTo(b, it);
428     a.resize(len); //we need to resize after the appendTo for the case str+=foo+str
429     return a;
430 }
431
432 template <typename A, typename B>
433 QString &operator+=(QString &a, const QStringBuilder<A, B> &b)
434 {
435     int len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b);
436     a.reserve(len);
437     QChar *it = a.data() + a.size();
438     QConcatenable< QStringBuilder<A, B> >::appendTo(b, it);
439     a.resize(it - a.constData()); //may be smaller than len if there was conversion from utf8
440     return a;
441 }
442
443
444 QT_END_NAMESPACE
445
446 QT_END_HEADER
447
448 #endif // QSTRINGBUILDER_H