QDebug: Support standard strings and string views directly

[ChangeLog][QtCore][QDebug] QDebug now supports printing
std::strings and std::string_views (and their wide, u16, and
u32 variants) directly.

Task-number: QTBUG-96878
Change-Id: I7baf4fe688bfff50580b1cee9417af13949374cc
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Ville Voutilainen 2022-09-21 00:08:45 +03:00
parent 9a23a3d1b4
commit e08f05ac6e
3 changed files with 356 additions and 1 deletions

View File

@ -763,6 +763,79 @@ QDebug &QDebug::resetFormat()
\internal
*/
/*!
\since 6.5
\fn QDebug &QDebug::operator<<(const std::string &s)
Converts \a s to a QUtf8StringView,
writes the result to the stream and returns
a reference to the stream.
*/
/*!
\since 6.5
\fn QDebug &QDebug::operator<<(std::string_view s)
Converts \a s to a QUtf8StringView,
writes the result to the stream and returns
a reference to the stream.
*/
/*!
\since 6.5
\fn QDebug &QDebug::operator<<(const std::wstring &s)
Converts \a s to a QString via QString::fromStdWString(),
writes the result to the stream and returns
a reference to the stream.
*/
/*!
\since 6.5
\fn QDebug &QDebug::operator<<(std::wstring_view s)
Converts \a s to a QString via QString::fromWCharArray(),
writes the result to the stream and returns
a reference to the stream.
*/
/*!
\since 6.5
\fn QDebug &QDebug::operator<<(const std::u16string &s)
Converts \a s to a QStringView,
writes the result to the stream and returns
a reference to the stream.
*/
/*!
\since 6.5
\fn QDebug &QDebug::operator<<(std::u16string_view s)
Converts \a s to a QStringView,
writes the result to the stream and returns
a reference to the stream.
*/
/*!
\since 6.5
\fn QDebug &QDebug::operator<<(const std::u32string &s)
Converts \a s to a QString via QString::fromUcs4(),
writes the result to the stream and returns
a reference to the stream.
*/
/*!
\since 6.5
\fn QDebug &QDebug::operator<<(std::u32string_view s)
Converts \a s to a QString via QString::fromUcs4(),
writes the result to the stream and returns
a reference to the stream.
*/
/*!
\fn template <class T> QString QDebug::toString(T &&object)
\since 6.0

View File

@ -16,10 +16,12 @@
#include <QtCore/qsharedpointer.h>
// all these have already been included by various headers above, but don't rely on indirect includes:
#include <vector>
#include <list>
#include <map>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 1
# include <QtCore/qlist.h>
@ -126,6 +128,30 @@ public:
inline QDebug &operator<<(QTextStreamManipulator m)
{ stream->ts << m; return *this; }
inline QDebug &operator<<(const std::string &s)
{ return *this << QUtf8StringView(s); }
inline QDebug &operator<<(std::string_view s)
{ return *this << QUtf8StringView(s); }
inline QDebug &operator<<(const std::wstring &s)
{ return *this << QString::fromStdWString(s); }
inline QDebug &operator<<(std::wstring_view s)
{ return *this << QString::fromWCharArray(s.data(), s.size()); }
inline QDebug &operator<<(const std::u16string &s)
{ return *this << QStringView(s); }
inline QDebug &operator<<(std::u16string_view s)
{ return *this << QStringView(s); }
inline QDebug &operator<<(const std::u32string &s)
{ return *this << QString::fromUcs4(s.data(), s.size()); }
inline QDebug &operator<<(std::u32string_view s)
{ return *this << QString::fromUcs4(s.data(), s.size()); }
template <typename T>
static QString toString(T &&object)
{

View File

@ -63,6 +63,14 @@ private slots:
void qDebugQStringView() const;
void qDebugQUtf8StringView() const;
void qDebugQLatin1String() const;
void qDebugStdString() const;
void qDebugStdStringView() const;
void qDebugStdWString() const;
void qDebugStdWStringView() const;
void qDebugStdU16String() const;
void qDebugStdU16StringView() const;
void qDebugStdU32String() const;
void qDebugStdU32StringView() const;
void qDebugQByteArray() const;
void qDebugQByteArrayView() const;
void qDebugQFlags() const;
@ -648,6 +656,254 @@ void tst_QDebug::qDebugQLatin1String() const
QCOMPARE(s_msg, QString("\"\\nSm\\u00F8rg\\u00E5sbord\\\\\""));
}
void tst_QDebug::qDebugStdString() const
{
QString file, function;
int line = 0;
MessageHandlerSetter mhs(myMessageHandler);
{
QDebug d = qDebug();
d << std::string("foo") << std::string("") << std::string("barbaz", 3);
d.nospace().noquote() << std::string("baz");
}
#ifndef QT_NO_MESSAGELOGCONTEXT
file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
#endif
QCOMPARE(s_msgType, QtDebugMsg);
QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz"));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
/* simpler tests from now on */
std::string string("\"Hello\"");
qDebug() << string;
QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
qDebug().noquote().nospace() << string;
QCOMPARE(s_msg, QString::fromStdString(string));
qDebug().noquote().nospace() << qSetFieldWidth(8) << string;
QCOMPARE(s_msg, " " + QString::fromStdString(string));
}
void tst_QDebug::qDebugStdStringView() const
{
QString file, function;
int line = 0;
MessageHandlerSetter mhs(myMessageHandler);
{
QDebug d = qDebug();
d << std::string_view("foo") << std::string_view("") << std::string_view("barbaz", 3);
d.nospace().noquote() << std::string_view("baz");
}
#ifndef QT_NO_MESSAGELOGCONTEXT
file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
#endif
QCOMPARE(s_msgType, QtDebugMsg);
QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz"));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
/* simpler tests from now on */
std::string_view string("\"Hello\"");
qDebug() << string;
QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
qDebug().noquote().nospace() << string;
QCOMPARE(s_msg, QString::fromStdString(std::string(string)));
qDebug().noquote().nospace() << qSetFieldWidth(8) << string;
QCOMPARE(s_msg, " " + QString::fromStdString(std::string(string)));
}
void tst_QDebug::qDebugStdWString() const
{
QString file, function;
int line = 0;
MessageHandlerSetter mhs(myMessageHandler);
{
QDebug d = qDebug();
d << std::wstring(L"foo") << std::wstring(L"") << std::wstring(L"barbaz", 3);
d.nospace().noquote() << std::wstring(L"baz");
}
#ifndef QT_NO_MESSAGELOGCONTEXT
file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
#endif
QCOMPARE(s_msgType, QtDebugMsg);
QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz"));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
/* simpler tests from now on */
std::wstring string(L"\"Hello\"");
qDebug() << string;
QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
qDebug().noquote().nospace() << string;
QCOMPARE(s_msg, QString::fromStdWString(string));
qDebug().noquote().nospace() << qSetFieldWidth(8) << string;
QCOMPARE(s_msg, " " + QString::fromStdWString(string));
}
void tst_QDebug::qDebugStdWStringView() const
{
QString file, function;
int line = 0;
MessageHandlerSetter mhs(myMessageHandler);
{
QDebug d = qDebug();
d << std::wstring_view(L"foo") << std::wstring_view(L"") << std::wstring_view(L"barbaz", 3);
d.nospace().noquote() << std::wstring_view(L"baz");
}
#ifndef QT_NO_MESSAGELOGCONTEXT
file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
#endif
QCOMPARE(s_msgType, QtDebugMsg);
QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz"));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
/* simpler tests from now on */
std::wstring_view string(L"\"Hello\"");
qDebug() << string;
QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
qDebug().noquote().nospace() << string;
QCOMPARE(s_msg, QString::fromStdWString(std::wstring(string)));
qDebug().noquote().nospace() << qSetFieldWidth(8) << string;
QCOMPARE(s_msg, " " + QString::fromStdWString(std::wstring(string)));
}
void tst_QDebug::qDebugStdU16String() const
{
QString file, function;
int line = 0;
MessageHandlerSetter mhs(myMessageHandler);
{
QDebug d = qDebug();
d << std::u16string(u"foo") << std::u16string(u"") << std::u16string(u"barbaz", 3);
d.nospace().noquote() << std::u16string(u"baz");
}
#ifndef QT_NO_MESSAGELOGCONTEXT
file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
#endif
QCOMPARE(s_msgType, QtDebugMsg);
QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz"));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
/* simpler tests from now on */
std::u16string string(u"\"Hello\"");
qDebug() << string;
QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
qDebug().noquote().nospace() << string;
QCOMPARE(s_msg, QString::fromStdU16String(string));
qDebug().noquote().nospace() << qSetFieldWidth(8) << string;
QCOMPARE(s_msg, " " + QString::fromStdU16String(string));
}
void tst_QDebug::qDebugStdU16StringView() const
{
QString file, function;
int line = 0;
MessageHandlerSetter mhs(myMessageHandler);
{
QDebug d = qDebug();
d << std::u16string_view(u"foo") << std::u16string_view(u"") << std::u16string_view(u"barbaz", 3);
d.nospace().noquote() << std::u16string_view(u"baz");
}
#ifndef QT_NO_MESSAGELOGCONTEXT
file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
#endif
QCOMPARE(s_msgType, QtDebugMsg);
QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz"));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
/* simpler tests from now on */
std::u16string_view string(u"\"Hello\"");
qDebug() << string;
QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
qDebug().noquote().nospace() << string;
QCOMPARE(s_msg, QString::fromStdU16String(std::u16string(string)));
qDebug().noquote().nospace() << qSetFieldWidth(8) << string;
QCOMPARE(s_msg, " " + QString::fromStdU16String(std::u16string(string)));
}
void tst_QDebug::qDebugStdU32String() const
{
QString file, function;
int line = 0;
MessageHandlerSetter mhs(myMessageHandler);
{
QDebug d = qDebug();
d << std::u32string(U"foo") << std::u32string(U"") << std::u32string(U"barbaz", 3);
d.nospace().noquote() << std::u32string(U"baz");
}
#ifndef QT_NO_MESSAGELOGCONTEXT
file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
#endif
QCOMPARE(s_msgType, QtDebugMsg);
QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz"));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
/* simpler tests from now on */
std::u32string string(U"\"Hello\"");
qDebug() << string;
QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
qDebug().noquote().nospace() << string;
QCOMPARE(s_msg, QString::fromStdU32String(string));
qDebug().noquote().nospace() << qSetFieldWidth(8) << string;
QCOMPARE(s_msg, " " + QString::fromStdU32String(string));
}
void tst_QDebug::qDebugStdU32StringView() const
{
QString file, function;
int line = 0;
MessageHandlerSetter mhs(myMessageHandler);
{
QDebug d = qDebug();
d << std::u32string_view(U"foo") << std::u32string_view(U"") << std::u32string_view(U"barbaz", 3);
d.nospace().noquote() << std::u32string_view(U"baz");
}
#ifndef QT_NO_MESSAGELOGCONTEXT
file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
#endif
QCOMPARE(s_msgType, QtDebugMsg);
QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz"));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
/* simpler tests from now on */
std::u32string_view string(U"\"Hello\"");
qDebug() << string;
QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
qDebug().noquote().nospace() << string;
QCOMPARE(s_msg, QString::fromStdU32String(std::u32string(string)));
qDebug().noquote().nospace() << qSetFieldWidth(8) << string;
QCOMPARE(s_msg, " " + QString::fromStdU32String(std::u32string(string)));
}
void tst_QDebug::qDebugQByteArray() const
{
QString file, function;