1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of the QtCore module of the Qt Toolkit. 7 ** 8 ** $QT_BEGIN_LICENSE:LGPL$ 9 ** Commercial License Usage 10 ** Licensees holding valid commercial Qt licenses may use this file in 11 ** accordance with the commercial license agreement provided with the 12 ** Software or, alternatively, in accordance with the terms contained in 13 ** a written agreement between you and The Qt Company. For licensing terms 14 ** and conditions see https://www.qt.io/terms-conditions. For further 15 ** information use the contact form at https://www.qt.io/contact-us. 16 ** 17 ** GNU Lesser General Public License Usage 18 ** Alternatively, this file may be used under the terms of the GNU Lesser 19 ** General Public License version 3 as published by the Free Software 20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 21 ** packaging of this file. Please review the following information to 22 ** ensure the GNU Lesser General Public License version 3 requirements 23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24 ** 25 ** GNU General Public License Usage 26 ** Alternatively, this file may be used under the terms of the GNU 27 ** General Public License version 2.0 or (at your option) the GNU General 28 ** Public license version 3 or any later version approved by the KDE Free 29 ** Qt Foundation. The licenses are as published by the Free Software 30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31 ** included in the packaging of this file. Please review the following 32 ** information to ensure the GNU General Public License requirements will 33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34 ** https://www.gnu.org/licenses/gpl-3.0.html. 35 ** 36 ** $QT_END_LICENSE$ 37 ** 38 ****************************************************************************/ 39 40 #ifndef QSTRINGBUILDER_H 41 #define QSTRINGBUILDER_H 42 43 #if 0 44 // syncqt can not handle the templates in this file, and it doesn't need to 45 // process them anyway because they are internal. 46 #pragma qt_class(QStringBuilder) 47 #pragma qt_sync_stop_processing 48 #endif 49 50 #include <QtCore/qstring.h> 51 #include <QtCore/qbytearray.h> 52 53 #include <string.h> 54 55 QT_BEGIN_NAMESPACE 56 57 58 struct Q_CORE_EXPORT QAbstractConcatenable 59 { 60 protected: 61 static void convertFromAscii(const char *a, int len, QChar *&out) noexcept; convertFromAsciiQAbstractConcatenable62 static inline void convertFromAscii(char a, QChar *&out) noexcept 63 { 64 *out++ = QLatin1Char(a); 65 } 66 static void appendLatin1To(const char *a, int len, QChar *out) noexcept; 67 }; 68 69 template <typename T> struct QConcatenable {}; 70 71 namespace QtStringBuilder { 72 template <typename A, typename B> struct ConvertToTypeHelper 73 { typedef A ConvertTo; }; 74 template <typename T> struct ConvertToTypeHelper<T, QString> 75 { typedef QString ConvertTo; }; 76 } 77 78 template<typename Builder, typename T> 79 struct QStringBuilderCommon 80 { 81 T toUpper() const { return resolved().toUpper(); } 82 T toLower() const { return resolved().toLower(); } 83 84 protected: 85 T resolved() const { return *static_cast<const Builder*>(this); } 86 }; 87 88 template<typename Builder, typename T> 89 struct QStringBuilderBase : public QStringBuilderCommon<Builder, T> 90 { 91 }; 92 93 template<typename Builder> 94 struct QStringBuilderBase<Builder, QString> : public QStringBuilderCommon<Builder, QString> 95 { 96 QByteArray toLatin1() const { return this->resolved().toLatin1(); } 97 QByteArray toUtf8() const { return this->resolved().toUtf8(); } 98 QByteArray toLocal8Bit() const { return this->resolved().toLocal8Bit(); } 99 }; 100 101 template <typename A, typename B> 102 class QStringBuilder : public QStringBuilderBase<QStringBuilder<A, B>, typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo> 103 { 104 public: 105 QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {} 106 private: 107 friend class QByteArray; 108 friend class QString; 109 template <typename T> T convertTo() const 110 { 111 const uint len = QConcatenable< QStringBuilder<A, B> >::size(*this); 112 T s(len, Qt::Uninitialized); 113 114 // we abuse const_cast / constData here because we know we've just 115 // allocated the data and we're the only reference count 116 typename T::iterator d = const_cast<typename T::iterator>(s.constData()); 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 public: 130 typedef typename Concatenable::ConvertTo ConvertTo; 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 QStringBuilder(const QStringBuilder &other) : a(other.a), b(other.b) {} 145 146 operator QString() const 147 { QString r(a); r += b; return r; } 148 149 const QString &a; 150 const QString &b; 151 152 private: 153 QStringBuilder &operator=(const QStringBuilder &) = delete; 154 }; 155 156 template <> 157 class QStringBuilder <QByteArray, QByteArray> : public QStringBuilderBase<QStringBuilder<QByteArray, QByteArray>, QByteArray> 158 { 159 public: 160 QStringBuilder(const QByteArray &a_, const QByteArray &b_) : a(a_), b(b_) {} 161 QStringBuilder(const QStringBuilder &other) : a(other.a), b(other.b) {} 162 163 operator QByteArray() const 164 { QByteArray r(a); r += b; return r; } 165 166 const QByteArray &a; 167 const QByteArray &b; 168 169 private: 170 QStringBuilder &operator=(const QStringBuilder &) = delete; 171 }; 172 173 174 template <> struct QConcatenable<char> : private QAbstractConcatenable 175 { 176 typedef char type; 177 typedef QByteArray ConvertTo; 178 enum { ExactSize = true }; 179 static int size(const char) { return 1; } 180 #ifndef QT_NO_CAST_FROM_ASCII 181 static inline QT_ASCII_CAST_WARN void appendTo(const char c, QChar *&out) 182 { 183 QAbstractConcatenable::convertFromAscii(c, out); 184 } 185 #endif 186 static inline void appendTo(const char c, char *&out) 187 { *out++ = c; } 188 }; 189 190 #if defined(Q_COMPILER_UNICODE_STRINGS) 191 template <> struct QConcatenable<char16_t> : private QAbstractConcatenable 192 { 193 typedef char16_t type; 194 typedef QString ConvertTo; 195 enum { ExactSize = true }; 196 static Q_DECL_CONSTEXPR int size(char16_t) { return 1; } 197 static inline void appendTo(char16_t c, QChar *&out) 198 { *out++ = c; } 199 }; 200 #endif 201 202 template <> struct QConcatenable<QLatin1Char> 203 { 204 typedef QLatin1Char type; 205 typedef QString ConvertTo; 206 enum { ExactSize = true }; 207 static int size(const QLatin1Char) { return 1; } 208 static inline void appendTo(const QLatin1Char c, QChar *&out) 209 { *out++ = c; } 210 static inline void appendTo(const QLatin1Char c, char *&out) 211 { *out++ = c.toLatin1(); } 212 }; 213 214 template <> struct QConcatenable<QChar> : private QAbstractConcatenable 215 { 216 typedef QChar type; 217 typedef QString ConvertTo; 218 enum { ExactSize = true }; 219 static int size(const QChar) { return 1; } 220 static inline void appendTo(const QChar c, QChar *&out) 221 { *out++ = c; } 222 }; 223 224 template <> struct QConcatenable<QChar::SpecialCharacter> : private QAbstractConcatenable 225 { 226 typedef QChar::SpecialCharacter type; 227 typedef QString ConvertTo; 228 enum { ExactSize = true }; 229 static int size(const QChar::SpecialCharacter) { return 1; } 230 static inline void appendTo(const QChar::SpecialCharacter c, QChar *&out) 231 { *out++ = c; } 232 }; 233 234 template <> struct QConcatenable<QCharRef> : private QAbstractConcatenable 235 { 236 typedef QCharRef type; 237 typedef QString ConvertTo; 238 enum { ExactSize = true }; 239 static int size(QCharRef) { return 1; } 240 static inline void appendTo(QCharRef c, QChar *&out) 241 { *out++ = QChar(c); } 242 }; 243 244 template <> struct QConcatenable<QLatin1String> : private QAbstractConcatenable 245 { 246 typedef QLatin1String type; 247 typedef QString ConvertTo; 248 enum { ExactSize = true }; 249 static int size(const QLatin1String a) { return a.size(); } 250 static inline void appendTo(const QLatin1String a, QChar *&out) 251 { 252 appendLatin1To(a.latin1(), a.size(), out); 253 out += a.size(); 254 } 255 static inline void appendTo(const QLatin1String a, char *&out) 256 { 257 if (const char *data = a.data()) { 258 memcpy(out, data, a.size()); 259 out += a.size(); 260 } 261 } 262 }; 263 264 template <> struct QConcatenable<QString> : private QAbstractConcatenable 265 { 266 typedef QString type; 267 typedef QString ConvertTo; 268 enum { ExactSize = true }; 269 static int size(const QString &a) { return a.size(); } 270 static inline void appendTo(const QString &a, QChar *&out) 271 { 272 const int n = a.size(); 273 memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n); 274 out += n; 275 } 276 }; 277 278 template <> struct QConcatenable<QStringRef> : private QAbstractConcatenable 279 { 280 typedef QStringRef type; 281 typedef QString ConvertTo; 282 enum { ExactSize = true }; 283 static int size(const QStringRef &a) { return a.size(); } 284 static inline void appendTo(const QStringRef &a, QChar *&out) 285 { 286 const int n = a.size(); 287 memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n); 288 out += n; 289 } 290 }; 291 292 template <> struct QConcatenable<QStringView> : private QAbstractConcatenable 293 { 294 typedef QStringView type; 295 typedef QString ConvertTo; 296 enum { ExactSize = true }; 297 static int size(QStringView a) { return a.length(); } 298 static inline void appendTo(QStringView a, QChar *&out) 299 { 300 const auto n = a.size(); 301 memcpy(out, a.data(), sizeof(QChar) * n); 302 out += n; 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 <int N> struct QConcatenable<char[N]> : QConcatenable<const char[N]> 326 { 327 typedef char type[N]; 328 }; 329 330 template <> struct QConcatenable<const char *> : private QAbstractConcatenable 331 { 332 typedef const char *type; 333 typedef QByteArray ConvertTo; 334 enum { ExactSize = false }; 335 static int size(const char *a) { return qstrlen(a); } 336 #ifndef QT_NO_CAST_FROM_ASCII 337 static inline void QT_ASCII_CAST_WARN appendTo(const char *a, QChar *&out) 338 { QAbstractConcatenable::convertFromAscii(a, -1, out); } 339 #endif 340 static inline void appendTo(const char *a, char *&out) 341 { 342 if (!a) 343 return; 344 while (*a) 345 *out++ = *a++; 346 } 347 }; 348 349 template <> struct QConcatenable<char *> : QConcatenable<const char*> 350 { 351 typedef char *type; 352 }; 353 354 #if defined(Q_COMPILER_UNICODE_STRINGS) 355 template <int N> struct QConcatenable<const char16_t[N]> : private QAbstractConcatenable 356 { 357 using type = const char16_t[N]; 358 using ConvertTo = QString; 359 enum { ExactSize = true }; 360 static int size(const char16_t[N]) { return N - 1; } 361 static void appendTo(const char16_t a[N], QChar *&out) 362 { 363 memcpy(out, a, (N - 1) * sizeof(char16_t)); 364 out += N - 1; 365 } 366 }; 367 368 template <int N> struct QConcatenable<char16_t[N]> : QConcatenable<const char16_t[N]> 369 { 370 using type = char16_t[N]; 371 }; 372 373 template <> struct QConcatenable<const char16_t *> : private QAbstractConcatenable 374 { 375 using type = const char16_t *; 376 using ConvertTo = QString; 377 enum { ExactSize = true }; 378 static int size(const char16_t *a) { return QStringView(a).length(); } 379 static inline void QT_ASCII_CAST_WARN appendTo(const char16_t *a, QChar *&out) 380 { 381 if (!a) 382 return; 383 while (*a) 384 *out++ = *a++; 385 } 386 }; 387 388 template <> struct QConcatenable<char16_t *> : QConcatenable<const char16_t*> 389 { 390 typedef char16_t *type; 391 }; 392 #endif // UNICODE_STRINGS 393 394 template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable 395 { 396 typedef QByteArray type; 397 typedef QByteArray ConvertTo; 398 enum { ExactSize = false }; 399 static int size(const QByteArray &ba) { return ba.size(); } 400 #ifndef QT_NO_CAST_FROM_ASCII 401 static inline QT_ASCII_CAST_WARN void appendTo(const QByteArray &ba, QChar *&out) 402 { 403 QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size(), out); 404 } 405 #endif 406 static inline void appendTo(const QByteArray &ba, char *&out) 407 { 408 const char *a = ba.constData(); 409 const char * const end = ba.end(); 410 while (a != end) 411 *out++ = *a++; 412 } 413 }; 414 415 416 template <typename A, typename B> 417 struct QConcatenable< QStringBuilder<A, B> > 418 { 419 typedef QStringBuilder<A, B> type; 420 typedef typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo ConvertTo; 421 enum { ExactSize = QConcatenable<A>::ExactSize && QConcatenable<B>::ExactSize }; 422 static int size(const type &p) 423 { 424 return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b); 425 } 426 template<typename T> static inline void appendTo(const type &p, T *&out) 427 { 428 QConcatenable<A>::appendTo(p.a, out); 429 QConcatenable<B>::appendTo(p.b, out); 430 } 431 }; 432 433 template <typename A, typename B> 434 QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type> 435 operator%(const A &a, const B &b) 436 { 437 return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b); 438 } 439 440 // QT_USE_FAST_OPERATOR_PLUS was introduced in 4.7, QT_USE_QSTRINGBUILDER is to be used from 4.8 onwards 441 // QT_USE_FAST_OPERATOR_PLUS does not remove the normal operator+ for QByteArray 442 #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER) 443 template <typename A, typename B> 444 QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type> 445 operator+(const A &a, const B &b) 446 { 447 return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b); 448 } 449 #endif 450 451 namespace QtStringBuilder { 452 template <typename A, typename B> 453 QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder<A, B> &b, char) 454 { 455 // append 8-bit data to a byte array 456 int len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b); 457 a.reserve(len); 458 char *it = a.data() + a.size(); 459 QConcatenable< QStringBuilder<A, B> >::appendTo(b, it); 460 a.resize(len); //we need to resize after the appendTo for the case str+=foo+str 461 return a; 462 } 463 464 #ifndef QT_NO_CAST_TO_ASCII 465 template <typename A, typename B> 466 QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder<A, B> &b, QChar) 467 { 468 return a += QString(b).toUtf8(); 469 } 470 #endif 471 } 472 473 template <typename A, typename B> 474 QByteArray &operator+=(QByteArray &a, const QStringBuilder<A, B> &b) 475 { 476 return QtStringBuilder::appendToByteArray(a, b, 477 typename QConcatenable< QStringBuilder<A, B> >::ConvertTo::value_type()); 478 } 479 480 template <typename A, typename B> 481 QString &operator+=(QString &a, const QStringBuilder<A, B> &b) 482 { 483 int len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b); 484 a.reserve(len); 485 QChar *it = a.data() + a.size(); 486 QConcatenable< QStringBuilder<A, B> >::appendTo(b, it); 487 a.resize(int(it - a.constData())); //may be smaller than len if there was conversion from utf8 488 return a; 489 } 490 491 492 QT_END_NAMESPACE 493 494 #endif // QSTRINGBUILDER_H 495