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