Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:07:38

0001 // Copyright (C) 2020 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 
0004 #include <QtCore/qstring.h>
0005 
0006 #ifndef QSTRINGBUILDER_H
0007 #define QSTRINGBUILDER_H
0008 
0009 #if 0
0010 // syncqt can not handle the templates in this file, and it doesn't need to
0011 // process them anyway because they are internal.
0012 #pragma qt_class(QStringBuilder)
0013 #pragma qt_sync_stop_processing
0014 #endif
0015 
0016 #include <QtCore/qbytearray.h>
0017 
0018 #include <string.h>
0019 
0020 QT_BEGIN_NAMESPACE
0021 
0022 
0023 struct Q_CORE_EXPORT QAbstractConcatenable
0024 {
0025 protected:
0026     static void convertFromUtf8(QByteArrayView in, QChar *&out) noexcept;
0027     static inline void convertFromAscii(char a, QChar *&out) noexcept
0028     {
0029         *out++ = QLatin1Char(a);
0030     }
0031     static void appendLatin1To(QLatin1StringView in, QChar *out) noexcept;
0032 };
0033 
0034 template <typename T> struct QConcatenable;
0035 
0036 template <typename T>
0037 using QConcatenableEx = QConcatenable<q20::remove_cvref_t<T>>;
0038 
0039 namespace QtStringBuilder {
0040     template <typename A, typename B> struct ConvertToTypeHelper
0041     { typedef A ConvertTo; };
0042     template <typename T> struct ConvertToTypeHelper<T, QString>
0043     { typedef QString ConvertTo; };
0044 
0045     template <typename T> using HasIsNull = decltype(std::declval<const T &>().isNull());
0046     template <typename T> bool isNull(const T &t)
0047     {
0048         if constexpr (qxp::is_detected_v<HasIsNull, T>)
0049             return t.isNull();
0050         else
0051             return false;
0052     }
0053 }
0054 
0055 template<typename Builder, typename T>
0056 struct QStringBuilderCommon
0057 {
0058     T toUpper() const { return resolved().toUpper(); }
0059     T toLower() const { return resolved().toLower(); }
0060 
0061 protected:
0062     T resolved() const { return *static_cast<const Builder*>(this); }
0063 };
0064 
0065 template<typename Builder, typename T>
0066 struct QStringBuilderBase : public QStringBuilderCommon<Builder, T>
0067 {
0068 };
0069 
0070 template<typename Builder>
0071 struct QStringBuilderBase<Builder, QString> : public QStringBuilderCommon<Builder, QString>
0072 {
0073     QByteArray toLatin1() const { return this->resolved().toLatin1(); }
0074     QByteArray toUtf8() const { return this->resolved().toUtf8(); }
0075     QByteArray toLocal8Bit() const { return this->resolved().toLocal8Bit(); }
0076 };
0077 
0078 template <typename A, typename B>
0079 class QStringBuilder : public QStringBuilderBase<QStringBuilder<A, B>,
0080                                                  typename QtStringBuilder::ConvertToTypeHelper<
0081                                                          typename QConcatenableEx<A>::ConvertTo,
0082                                                          typename QConcatenableEx<B>::ConvertTo
0083                                                          >::ConvertTo
0084                                                 >
0085 {
0086 public:
0087     QStringBuilder(A &&a_, B &&b_) : a(std::forward<A>(a_)), b(std::forward<B>(b_)) {}
0088 
0089     QStringBuilder(QStringBuilder &&) = default;
0090     QStringBuilder(const QStringBuilder &) = default;
0091     ~QStringBuilder() = default;
0092 
0093 private:
0094     friend class QByteArray;
0095     friend class QString;
0096     template <typename T> T convertTo() const
0097     {
0098         if (isNull()) {
0099             // appending two null strings must give back a null string,
0100             // so we're special casing this one out, QTBUG-114206
0101             return T();
0102         }
0103 
0104         const qsizetype len = Concatenable::size(*this);
0105         T s(len, Qt::Uninitialized);
0106 
0107         // Using data_ptr() here (private API) so we can bypass the
0108         // isDetached() and the replacement of a null pointer with _empty in
0109         // both QString and QByteArray's data() and constData(). The result is
0110         // the same if len != 0.
0111         auto d = reinterpret_cast<typename T::iterator>(s.data_ptr().data());
0112         const auto start = d;
0113         Concatenable::appendTo(*this, d);
0114 
0115         if constexpr (Concatenable::ExactSize) {
0116             Q_UNUSED(start)
0117         } else {
0118             if (len != d - start) {
0119                 // this resize is necessary since we allocate a bit too much
0120                 // when dealing with variable sized 8-bit encodings
0121                 s.resize(d - start);
0122             }
0123         }
0124         return s;
0125     }
0126 
0127     typedef QConcatenable<QStringBuilder<A, B> > Concatenable;
0128 public:
0129     typedef typename Concatenable::ConvertTo ConvertTo;
0130     operator ConvertTo() const { return convertTo<ConvertTo>(); }
0131 
0132     qsizetype size() const { return Concatenable::size(*this); }
0133 
0134     bool isNull() const
0135     {
0136         return QtStringBuilder::isNull(a) && QtStringBuilder::isNull(b);
0137     }
0138 
0139     A a;
0140     B b;
0141 
0142 private:
0143     QStringBuilder &operator=(QStringBuilder &&) = delete;
0144     QStringBuilder &operator=(const QStringBuilder &) = delete;
0145 };
0146 
0147 template <> struct QConcatenable<char> : private QAbstractConcatenable
0148 {
0149     typedef char type;
0150     typedef QByteArray ConvertTo;
0151     enum { ExactSize = true };
0152     static qsizetype size(const char) { return 1; }
0153 #ifndef QT_NO_CAST_FROM_ASCII
0154     QT_ASCII_CAST_WARN static inline void appendTo(const char c, QChar *&out)
0155     {
0156         QAbstractConcatenable::convertFromAscii(c, out);
0157     }
0158 #endif
0159     static inline void appendTo(const char c, char *&out)
0160     { *out++ = c; }
0161 };
0162 
0163 template <> struct QConcatenable<QByteArrayView> : private QAbstractConcatenable
0164 {
0165     typedef QByteArrayView type;
0166     typedef QByteArray ConvertTo;
0167     enum { ExactSize = true };
0168     static qsizetype size(QByteArrayView bav) { return bav.size(); }
0169 #ifndef QT_NO_CAST_FROM_ASCII
0170     QT_ASCII_CAST_WARN static inline void appendTo(QByteArrayView bav, QChar *&out)
0171     {
0172         QAbstractConcatenable::convertFromUtf8(bav, out);
0173     }
0174 #endif
0175     static inline void appendTo(QByteArrayView bav, char *&out)
0176     {
0177         qsizetype n = bav.size();
0178         if (n)
0179             memcpy(out, bav.data(), n);
0180         out += n;
0181     }
0182 };
0183 
0184 template <> struct QConcatenable<char16_t> : private QAbstractConcatenable
0185 {
0186     typedef char16_t type;
0187     typedef QString ConvertTo;
0188     enum { ExactSize = true };
0189     static constexpr qsizetype size(char16_t) { return 1; }
0190     static inline void appendTo(char16_t c, QChar *&out)
0191     { *out++ = c; }
0192 };
0193 
0194 template <> struct QConcatenable<QLatin1Char>
0195 {
0196     typedef QLatin1Char type;
0197     typedef QString ConvertTo;
0198     enum { ExactSize = true };
0199     static qsizetype size(const QLatin1Char) { return 1; }
0200     static inline void appendTo(const QLatin1Char c, QChar *&out)
0201     { *out++ = c; }
0202     static inline void appendTo(const QLatin1Char c, char *&out)
0203     { *out++ = c.toLatin1(); }
0204 };
0205 
0206 template <> struct QConcatenable<QChar> : private QAbstractConcatenable
0207 {
0208     typedef QChar type;
0209     typedef QString ConvertTo;
0210     enum { ExactSize = true };
0211     static qsizetype size(const QChar) { return 1; }
0212     static inline void appendTo(const QChar c, QChar *&out)
0213     { *out++ = c; }
0214 };
0215 
0216 template <> struct QConcatenable<QChar::SpecialCharacter> : private QAbstractConcatenable
0217 {
0218     typedef QChar::SpecialCharacter type;
0219     typedef QString ConvertTo;
0220     enum { ExactSize = true };
0221     static qsizetype size(const QChar::SpecialCharacter) { return 1; }
0222     static inline void appendTo(const QChar::SpecialCharacter c, QChar *&out)
0223     { *out++ = c; }
0224 };
0225 
0226 template <> struct QConcatenable<QLatin1StringView> : private QAbstractConcatenable
0227 {
0228     typedef QLatin1StringView type;
0229     typedef QString ConvertTo;
0230     enum { ExactSize = true };
0231     static qsizetype size(const QLatin1StringView a) { return a.size(); }
0232     static inline void appendTo(const QLatin1StringView a, QChar *&out)
0233     {
0234         appendLatin1To(a, out);
0235         out += a.size();
0236     }
0237     static inline void appendTo(const QLatin1StringView a, char *&out)
0238     {
0239         if (const char *data = a.data()) {
0240             memcpy(out, data, a.size());
0241             out += a.size();
0242         }
0243     }
0244 };
0245 
0246 template <> struct QConcatenable<QString> : private QAbstractConcatenable
0247 {
0248     typedef QString type;
0249     typedef QString ConvertTo;
0250     enum { ExactSize = true };
0251     static qsizetype size(const QString &a) { return a.size(); }
0252     static inline void appendTo(const QString &a, QChar *&out)
0253     {
0254         const qsizetype n = a.size();
0255         if (n)
0256             memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n);
0257         out += n;
0258     }
0259 };
0260 
0261 template <> struct QConcatenable<QStringView> : private QAbstractConcatenable
0262 {
0263     typedef QStringView type;
0264     typedef QString ConvertTo;
0265     enum { ExactSize = true };
0266     static qsizetype size(QStringView a) { return a.size(); }
0267     static inline void appendTo(QStringView a, QChar *&out)
0268     {
0269         const auto n = a.size();
0270         if (n)
0271             memcpy(out, a.data(), sizeof(QChar) * n);
0272         out += n;
0273     }
0274 };
0275 
0276 template <qsizetype N> struct QConcatenable<const char[N]> : private QAbstractConcatenable
0277 {
0278     typedef const char type[N];
0279     typedef QByteArray ConvertTo;
0280     enum { ExactSize = false };
0281     static qsizetype size(const char[N]) { return N - 1; }
0282 #ifndef QT_NO_CAST_FROM_ASCII
0283     QT_ASCII_CAST_WARN static inline void appendTo(const char a[N], QChar *&out)
0284     {
0285         QAbstractConcatenable::convertFromUtf8(QByteArrayView(a, N - 1), out);
0286     }
0287 #endif
0288     static inline void appendTo(const char a[N], char *&out)
0289     {
0290         while (*a)
0291             *out++ = *a++;
0292     }
0293 };
0294 
0295 template <qsizetype N> struct QConcatenable<char[N]> : QConcatenable<const char[N]>
0296 {
0297     typedef char type[N];
0298 };
0299 
0300 template <> struct QConcatenable<const char *> : private QAbstractConcatenable
0301 {
0302     typedef const char *type;
0303     typedef QByteArray ConvertTo;
0304     enum { ExactSize = false };
0305     static qsizetype size(const char *a) { return qstrlen(a); }
0306 #ifndef QT_NO_CAST_FROM_ASCII
0307     QT_ASCII_CAST_WARN static inline void appendTo(const char *a, QChar *&out)
0308     { QAbstractConcatenable::convertFromUtf8(QByteArrayView(a), out); }
0309 #endif
0310     static inline void appendTo(const char *a, char *&out)
0311     {
0312         if (!a)
0313             return;
0314         while (*a)
0315             *out++ = *a++;
0316     }
0317 };
0318 
0319 template <> struct QConcatenable<char *> : QConcatenable<const char*>
0320 {
0321     typedef char *type;
0322 };
0323 
0324 template <qsizetype N> struct QConcatenable<const char16_t[N]> : private QAbstractConcatenable
0325 {
0326     using type = const char16_t[N];
0327     using ConvertTo = QString;
0328     enum { ExactSize = true };
0329     static qsizetype size(const char16_t[N]) { return N - 1; }
0330     static void appendTo(const char16_t a[N], QChar *&out)
0331     {
0332         memcpy(static_cast<void *>(out), a, (N - 1) * sizeof(char16_t));
0333         out += N - 1;
0334     }
0335 };
0336 
0337 template <qsizetype N> struct QConcatenable<char16_t[N]> : QConcatenable<const char16_t[N]>
0338 {
0339     using type = char16_t[N];
0340 };
0341 
0342 template <> struct QConcatenable<const char16_t *> : private QAbstractConcatenable
0343 {
0344     using type = const char16_t *;
0345     using ConvertTo = QString;
0346     enum { ExactSize = true };
0347     static qsizetype size(const char16_t *a) { return QStringView(a).size(); }
0348     QT_ASCII_CAST_WARN static inline void appendTo(const char16_t *a, QChar *&out)
0349     {
0350         if (!a)
0351             return;
0352         while (*a)
0353             *out++ = *a++;
0354     }
0355 };
0356 
0357 template <> struct QConcatenable<char16_t *> : QConcatenable<const char16_t*>
0358 {
0359     typedef char16_t *type;
0360 };
0361 
0362 template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable
0363 {
0364     typedef QByteArray type;
0365     typedef QByteArray ConvertTo;
0366     enum { ExactSize = false };
0367     static qsizetype size(const QByteArray &ba) { return ba.size(); }
0368 #ifndef QT_NO_CAST_FROM_ASCII
0369     QT_ASCII_CAST_WARN static inline void appendTo(const QByteArray &ba, QChar *&out)
0370     {
0371         QAbstractConcatenable::convertFromUtf8(ba, out);
0372     }
0373 #endif
0374     static inline void appendTo(const QByteArray &ba, char *&out)
0375     {
0376         const char *a = ba.constData();
0377         const char * const end = ba.end();
0378         while (a != end)
0379             *out++ = *a++;
0380     }
0381 };
0382 
0383 
0384 template <typename A, typename B>
0385 struct QConcatenable< QStringBuilder<A, B> >
0386 {
0387     typedef QStringBuilder<A, B> type;
0388     using ConvertTo = typename QtStringBuilder::ConvertToTypeHelper<
0389                 typename QConcatenableEx<A>::ConvertTo,
0390                 typename QConcatenableEx<B>::ConvertTo
0391             >::ConvertTo;
0392     enum { ExactSize = QConcatenableEx<A>::ExactSize && QConcatenableEx<B>::ExactSize };
0393     static qsizetype size(const type &p)
0394     {
0395         return QConcatenableEx<A>::size(p.a) + QConcatenableEx<B>::size(p.b);
0396     }
0397     template<typename T> static inline void appendTo(const type &p, T *&out)
0398     {
0399         QConcatenableEx<A>::appendTo(p.a, out);
0400         QConcatenableEx<B>::appendTo(p.b, out);
0401     }
0402 };
0403 
0404 template <typename A, typename B,
0405          typename = std::void_t<typename QConcatenableEx<A>::type, typename QConcatenableEx<B>::type>>
0406 auto operator%(A &&a, B &&b)
0407 {
0408     return QStringBuilder<A, B>(std::forward<A>(a), std::forward<B>(b));
0409 }
0410 
0411 // QT_USE_FAST_OPERATOR_PLUS was introduced in 4.7, QT_USE_QSTRINGBUILDER is to be used from 4.8 onwards
0412 // QT_USE_FAST_OPERATOR_PLUS does not remove the normal operator+ for QByteArray
0413 #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
0414 template <typename A, typename B,
0415          typename = std::void_t<typename QConcatenableEx<A>::type, typename QConcatenableEx<B>::type>>
0416 auto operator+(A &&a, B &&b)
0417 {
0418     return std::forward<A>(a) % std::forward<B>(b);
0419 }
0420 #endif
0421 
0422 namespace QtStringBuilder {
0423 template <typename A, typename B>
0424 QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder<A, B> &b, char)
0425 {
0426     // append 8-bit data to a byte array
0427     qsizetype len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b);
0428     a.detach(); // a detach() in a.data() could reset a.capacity() to a.size()
0429     if (len > a.data_ptr().freeSpaceAtEnd()) // capacity() was broken when prepend()-optimization landed
0430         a.reserve(qMax(len, 2 * a.capacity()));
0431     char *it = a.data() + a.size();
0432     QConcatenable< QStringBuilder<A, B> >::appendTo(b, it);
0433     a.resize(len); //we need to resize after the appendTo for the case str+=foo+str
0434     return a;
0435 }
0436 
0437 #ifndef QT_NO_CAST_TO_ASCII
0438 template <typename A, typename B>
0439 QByteArray &appendToByteArray(QByteArray &a, const QStringBuilder<A, B> &b, QChar)
0440 {
0441     return a += QString(b).toUtf8();
0442 }
0443 #endif
0444 }
0445 
0446 template <typename A, typename B>
0447 QByteArray &operator+=(QByteArray &a, const QStringBuilder<A, B> &b)
0448 {
0449     return QtStringBuilder::appendToByteArray(a, b,
0450                                               typename QConcatenable< QStringBuilder<A, B> >::ConvertTo::value_type());
0451 }
0452 
0453 template <typename A, typename B>
0454 QString &operator+=(QString &a, const QStringBuilder<A, B> &b)
0455 {
0456     qsizetype len = a.size() + QConcatenable< QStringBuilder<A, B> >::size(b);
0457     a.detach(); // a detach() in a.data() could reset a.capacity() to a.size()
0458     if (len > a.data_ptr().freeSpaceAtEnd()) // capacity() was broken when prepend()-optimization landed
0459         a.reserve(qMax(len, 2 * a.capacity()));
0460     QChar *it = a.data() + a.size();
0461     QConcatenable< QStringBuilder<A, B> >::appendTo(b, it);
0462     // we need to resize after the appendTo for the case str+=foo+str
0463     a.resize(it - a.constData()); //may be smaller than len if there was conversion from utf8
0464     return a;
0465 }
0466 
0467 QT_END_NAMESPACE
0468 
0469 #endif // QSTRINGBUILDER_H