From af8f9a2a6e3dbc865470f8d7f09b533ccea4f353 Mon Sep 17 00:00:00 2001 From: Vladimir Belyavsky Date: Fri, 19 May 2023 14:58:50 +0300 Subject: QStringBuilder: allow to be used with 'auto' keyword The idea is to store a concatenable in a QStringBuilder object by value or by reference, depending on how it was originally passed into the concatenation operator. So if it was passed by r-value, we treat it as a temporary object and hold it by value (and use move-semantic if available), otherwise we hold it by reference (as before). To achieve this we first change concatenation operators '%' and '+' to take their arguments by universal reference. Next we instantiate QStringBuilder object with deduced types of the arguments, which will be a "value type" or a "reference type" according to "universal reference deduction rules". Further we use perfect forwarding to pass arguments to QStringBuilder's constructor. Thus arguments, initially passed by r-value reference and which are move-constructible, will be "moved" to corresponding QStringBuilder member variables. So, to summarize: 1. Arguments passed by l-value reference - stored in QStringBuilder object by reference (as before). 2. Temporary objects passed by r-value reference - stored in QStringBuilder object by value. If a type is move-constructible (QSting, QByteArray, etc), the object will be "moved" accordingly. Special thanks to Giuseppe D'Angelo for the tests. Fixes: QTBUG-99291 Fixes: QTBUG-87603 Fixes: QTBUG-47066 Task-number: QTBUG-74873 Task-number: QTBUG-103090 Task-number: QTBUG-104354 Change-Id: I64f417be0de0815ec5ae7e35a1cc6cef6d887933 Reviewed-by: Volker Hilsheimer Reviewed-by: Qt CI Bot Reviewed-by: Vladimir Belyavsky Reviewed-by: Thiago Macieira Reviewed-by: Marc Mutz --- .../qstringbuilder1/stringbuilder.cpp | 149 +++++++++++++++++++++ 1 file changed, 149 insertions(+) (limited to 'tests/auto/corelib/text/qstringbuilder') 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 struct Helper; + +// These specializations forward to the non-const ones, and add const on top. +template struct Helper +{ + static const T create() { return Helper::create(); } + static const T createNull() { return Helper::createNull(); } +}; +template struct Helper +{ + static const T &create() { return Helper::create(); } + static const T &createNull() { return Helper::createNull(); } +}; + +template <> struct Helper +{ + static QString create() { return QString::fromUtf8("QString rvalue"); } + static QString createNull() { return QString(); } +}; + +template <> struct Helper +{ + static QString &create() { static QString s = QString::fromUtf8("QString lvalue"); return s; } + static QString &createNull() { static QString s; return s; } +}; + +template <> struct Helper +{ + static QStringView create() { return QStringView(u"QStringView rvalue"); } + static QStringView createNull() { return QStringView(); } +}; + +template <> struct Helper +{ + static QStringView &create() { static QStringView s = u"QStringView lvalue"; return s; } + static QStringView &createNull() { static QStringView s; return s; } +}; + +template <> struct Helper +{ + static QByteArray create() { return QByteArray("QByteArray rvalue"); } + static QByteArray createNull() { return QByteArray(); } +}; + +template <> struct Helper +{ + static QByteArray &create() { static QByteArray ba = QByteArray("QByteArray lvalue"); return ba; } + static QByteArray &createNull() { static QByteArray ba; return ba; } +}; + +template <> struct Helper +{ + static QByteArrayView create() { return QByteArrayView("QByteArrayView rvalue"); } + static QByteArrayView createNull() { return QByteArrayView(); } +}; + +template <> struct Helper +{ + static QByteArrayView &create() { static QByteArrayView ba = "QByteArrayView lvalue"; return ba; } + static QByteArrayView &createNull() { static QByteArrayView ba; return ba; } +}; + +template <> struct Helper +{ + static const char *create() { return "const char * rvalue"; } + static const char *createNull() { return ""; } +}; + +template <> struct Helper +{ + static const char *&create() { static const char *s = "const char * lvalue"; return s; } + static const char *&createNull() { static const char *s = ""; return s; } +}; + +template +void checkAutoImpl3() +{ + { + auto result = Helper::create() P Helper::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper::create() P Helper::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper::create() P Helper::create() P Helper::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper::create() P Helper::create() P Helper::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper::createNull() P Helper::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper::createNull() P Helper::createNull(); + Result expected = result; + QCOMPARE(result, expected); + } +} + +template +void checkAutoImpl2() +{ + checkAutoImpl3(); + checkAutoImpl3(); + checkAutoImpl3(); + checkAutoImpl3(); +} + +template +void checkAutoImpl() +{ + checkAutoImpl2< String1, String2, Result>(); + checkAutoImpl2(); + checkAutoImpl2< String1, const String2, Result>(); + checkAutoImpl2(); +} + +} // namespace CheckAuto + +void checkAuto() +{ + CheckAuto::checkAutoImpl(); + CheckAuto::checkAutoImpl(); + + CheckAuto::checkAutoImpl(); + CheckAuto::checkAutoImpl(); + CheckAuto::checkAutoImpl(); + +#ifndef QT_NO_CAST_FROM_ASCII + CheckAuto::checkAutoImpl(); + CheckAuto::checkAutoImpl(); +#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; -- cgit v1.2.3