diff options
-rw-r--r-- | src/corelib/text/qstringbuilder.h | 56 | ||||
-rw-r--r-- | tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp | 149 |
2 files changed, 187 insertions, 18 deletions
diff --git a/src/corelib/text/qstringbuilder.h b/src/corelib/text/qstringbuilder.h index a5a6505628..fb44a56633 100644 --- a/src/corelib/text/qstringbuilder.h +++ b/src/corelib/text/qstringbuilder.h @@ -30,7 +30,10 @@ protected: static void appendLatin1To(QLatin1StringView in, QChar *out) noexcept; }; -template <typename T> struct QConcatenable {}; +template <typename T> struct QConcatenable; + +template <typename T> +using QConcatenableEx = QConcatenable<q20::remove_cvref_t<T>>; namespace QtStringBuilder { template <typename A, typename B> struct ConvertToTypeHelper @@ -72,10 +75,20 @@ struct QStringBuilderBase<Builder, QString> : public QStringBuilderCommon<Builde }; template <typename A, typename B> -class QStringBuilder : public QStringBuilderBase<QStringBuilder<A, B>, typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo> +class QStringBuilder : public QStringBuilderBase<QStringBuilder<A, B>, + typename QtStringBuilder::ConvertToTypeHelper< + typename QConcatenableEx<A>::ConvertTo, + typename QConcatenableEx<B>::ConvertTo + >::ConvertTo + > { public: - QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {} + QStringBuilder(A &&a_, B &&b_) : a(std::forward<A>(a_)), b(std::forward<B>(b_)) {} + + QStringBuilder(QStringBuilder &&) = default; + QStringBuilder(const QStringBuilder &) = default; + ~QStringBuilder() = default; + private: friend class QByteArray; friend class QString; @@ -116,8 +129,12 @@ public: return QtStringBuilder::isNull(a) && QtStringBuilder::isNull(b); } - const A &a; - const B &b; + A a; + B b; + +private: + QStringBuilder &operator=(QStringBuilder &&) = delete; + QStringBuilder &operator=(const QStringBuilder &) = delete; }; template <> struct QConcatenable<char> : private QAbstractConcatenable @@ -361,34 +378,37 @@ template <typename A, typename B> struct QConcatenable< QStringBuilder<A, B> > { typedef QStringBuilder<A, B> type; - typedef typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo ConvertTo; - enum { ExactSize = QConcatenable<A>::ExactSize && QConcatenable<B>::ExactSize }; + using ConvertTo = typename QtStringBuilder::ConvertToTypeHelper< + typename QConcatenableEx<A>::ConvertTo, + typename QConcatenableEx<B>::ConvertTo + >::ConvertTo; + enum { ExactSize = QConcatenableEx<A>::ExactSize && QConcatenableEx<B>::ExactSize }; static qsizetype size(const type &p) { - return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b); + return QConcatenableEx<A>::size(p.a) + QConcatenableEx<B>::size(p.b); } template<typename T> static inline void appendTo(const type &p, T *&out) { - QConcatenable<A>::appendTo(p.a, out); - QConcatenable<B>::appendTo(p.b, out); + QConcatenableEx<A>::appendTo(p.a, out); + QConcatenableEx<B>::appendTo(p.b, out); } }; -template <typename A, typename B> -QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type> -operator%(const A &a, const B &b) +template <typename A, typename B, + typename = std::void_t<typename QConcatenableEx<A>::type, typename QConcatenableEx<B>::type>> +auto operator%(A &&a, B &&b) { - return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b); + return QStringBuilder<A, B>(std::forward<A>(a), std::forward<B>(b)); } // QT_USE_FAST_OPERATOR_PLUS was introduced in 4.7, QT_USE_QSTRINGBUILDER is to be used from 4.8 onwards // QT_USE_FAST_OPERATOR_PLUS does not remove the normal operator+ for QByteArray #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER) -template <typename A, typename B> -QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type> -operator+(const A &a, const B &b) +template <typename A, typename B, + typename = std::void_t<typename QConcatenableEx<A>::type, typename QConcatenableEx<B>::type>> +auto operator+(A &&a, B &&b) { - return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b); + return std::forward<A>(a) % std::forward<B>(b); } #endif diff --git a/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp b/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp index a547205460..06dc1ec5a5 100644 --- a/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp @@ -98,6 +98,152 @@ void checkNullVsEmpty(const String &empty) QVERIFY(result.isNull()); } +namespace CheckAuto { +// T is cvref-qualified, using universal reference deduction rules. +template <typename T> struct Helper; + +// These specializations forward to the non-const ones, and add const on top. +template <typename T> struct Helper<const T> +{ + static const T create() { return Helper<T>::create(); } + static const T createNull() { return Helper<T>::createNull(); } +}; +template <typename T> struct Helper<const T &> +{ + static const T &create() { return Helper<T &>::create(); } + static const T &createNull() { return Helper<T &>::createNull(); } +}; + +template <> struct Helper<QString> +{ + static QString create() { return QString::fromUtf8("QString rvalue"); } + static QString createNull() { return QString(); } +}; + +template <> struct Helper<QString &> +{ + static QString &create() { static QString s = QString::fromUtf8("QString lvalue"); return s; } + static QString &createNull() { static QString s; return s; } +}; + +template <> struct Helper<QStringView> +{ + static QStringView create() { return QStringView(u"QStringView rvalue"); } + static QStringView createNull() { return QStringView(); } +}; + +template <> struct Helper<QStringView &> +{ + static QStringView &create() { static QStringView s = u"QStringView lvalue"; return s; } + static QStringView &createNull() { static QStringView s; return s; } +}; + +template <> struct Helper<QByteArray> +{ + static QByteArray create() { return QByteArray("QByteArray rvalue"); } + static QByteArray createNull() { return QByteArray(); } +}; + +template <> struct Helper<QByteArray &> +{ + static QByteArray &create() { static QByteArray ba = QByteArray("QByteArray lvalue"); return ba; } + static QByteArray &createNull() { static QByteArray ba; return ba; } +}; + +template <> struct Helper<QByteArrayView> +{ + static QByteArrayView create() { return QByteArrayView("QByteArrayView rvalue"); } + static QByteArrayView createNull() { return QByteArrayView(); } +}; + +template <> struct Helper<QByteArrayView &> +{ + static QByteArrayView &create() { static QByteArrayView ba = "QByteArrayView lvalue"; return ba; } + static QByteArrayView &createNull() { static QByteArrayView ba; return ba; } +}; + +template <> struct Helper<const char *> +{ + static const char *create() { return "const char * rvalue"; } + static const char *createNull() { return ""; } +}; + +template <> struct Helper<const char *&> +{ + static const char *&create() { static const char *s = "const char * lvalue"; return s; } + static const char *&createNull() { static const char *s = ""; return s; } +}; + +template <typename String1, typename String2, typename Result> +void checkAutoImpl3() +{ + { + auto result = Helper<String1>::create() P Helper<String2>::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper<String2>::create() P Helper<String1>::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper<String1>::create() P Helper<String2>::create() P Helper<String1>::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper<String2>::create() P Helper<String1>::create() P Helper<String2>::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper<String1>::createNull() P Helper<String2>::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper<String1>::createNull() P Helper<String2>::createNull(); + Result expected = result; + QCOMPARE(result, expected); + } +} + +template <typename String1, typename String2, typename Result> +void checkAutoImpl2() +{ + checkAutoImpl3<String1 , String2 , Result>(); + checkAutoImpl3<String1 &, String2 , Result>(); + checkAutoImpl3<String1 , String2 &, Result>(); + checkAutoImpl3<String1 &, String2 &, Result>(); +} + +template <typename String1, typename String2, typename Result> +void checkAutoImpl() +{ + checkAutoImpl2< String1, String2, Result>(); + checkAutoImpl2<const String1, String2, Result>(); + checkAutoImpl2< String1, const String2, Result>(); + checkAutoImpl2<const String1, const String2, Result>(); +} + +} // namespace CheckAuto + +void checkAuto() +{ + CheckAuto::checkAutoImpl<QString, QString, QString>(); + CheckAuto::checkAutoImpl<QString, QStringView, QString>(); + + CheckAuto::checkAutoImpl<QByteArray, QByteArray, QByteArray>(); + CheckAuto::checkAutoImpl<QByteArray, const char *, QByteArray>(); + CheckAuto::checkAutoImpl<QByteArray, QByteArrayView, QByteArray>(); + +#ifndef QT_NO_CAST_FROM_ASCII + CheckAuto::checkAutoImpl<QString, const char *, QString>(); + CheckAuto::checkAutoImpl<QString, QByteArray, QString>(); +#endif +} + void runScenario() { // this code is latin1. TODO: replace it with the utf8 block below, once @@ -381,6 +527,9 @@ void runScenario() checkNullVsEmpty(QStringLiteral("")); checkNullVsEmpty(QByteArrayLiteral("")); + // auto + checkAuto(); + checkItWorksWithFreeSpaceAtBegin(QByteArray(UTF8_LITERAL), "1234"); if (QTest::currentTestFailed()) return; |