summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/text/qstringbuilder.h56
-rw-r--r--tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp149
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;