summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Mutz <[email protected]>2025-02-11 16:34:13 +0100
committerMarc Mutz <[email protected]>2025-02-20 18:02:45 +0100
commit3070efb64a628f5c61fc5870ee4a8791942f6699 (patch)
treeffe72eb97f9e94286adacf8296691fee3f7e4a84
parent3e1dffd5ddfeeb19f33abca4e3087211401126f3 (diff)
QCbor/JsonValue: add toStringView()
This is like toString(), but returns a view on the underlying string data (which may be US-ASCII (= L1), UTF-8, or UTF-16, so the return value is QASV). Use it around the code a bit. Benchmark results on my machine (with -perf -iterations 1000): PASS : BenchmarkQtJson::iteratorKey() RESULT : BenchmarkQtJson::iteratorKey(): 78,268.426 nsecs per iteration (total: 78,268,427, iterations: 1000) 349,458.080 CPU cycles per iteration, 4,46 GHz (total: 349,458,080, iterations: 1000) 780,327.957 instructions per iteration, 2,233 instr/cycle (total: 780,327,957, iterations: 1000) 173,511.019 branch instructions per iteration, 2,22 G/sec (total: 173,511,020, iterations: 1000) PASS : BenchmarkQtJson::iteratorKeyValueView() RESULT : BenchmarkQtJson::iteratorKeyValueView(): 58,424.756 nsecs per iteration (total: 58,424,756, iterations: 1000) 267,176.603 CPU cycles per iteration, 4,57 GHz (total: 267,176,604, iterations: 1000) 614,805.388 instructions per iteration, 2,301 instr/cycle (total: 614,805,389, iterations: 1000) 140,681.105 branch instructions per iteration, 2,41 G/sec (total: 140,681,106, iterations: 1000) PASS : BenchmarkQtJson::iteratorKeyView() RESULT : BenchmarkQtJson::iteratorKeyView(): 44,060.925 nsecs per iteration (total: 44,060,925, iterations: 1000) 196,344.233 CPU cycles per iteration, 4,46 GHz (total: 196,344,233, iterations: 1000) 426,631.322 instructions per iteration, 2,173 instr/cycle (total: 426,631,323, iterations: 1000) 93,703.100 branch instructions per iteration, 2,13 G/sec (total: 93,703,101, iterations: 1000) PASS : BenchmarkQtJson::iteratorKeyViewValueView() RESULT : BenchmarkQtJson::iteratorKeyViewValueView(): 29,205.569 nsecs per iteration (total: 29,205,570, iterations: 1000) 131,089.040 CPU cycles per iteration, 4,49 GHz (total: 131,089,041, iterations: 1000) 258,529.469 instructions per iteration, 1,972 instr/cycle (total: 258,529,469, iterations: 1000) 60,875.631 branch instructions per iteration, 2,08 G/sec (total: 60,875,631, iterations: 1000) [ChangeLog][QtCore][QCborValue/QJsonValue] Add toStringView() method. Fixes: QTBUG-133688 Change-Id: I4200035e995426f1cce46a73a429921a0cd56c85 Reviewed-by: Thiago Macieira <[email protected]>
-rw-r--r--src/corelib/serialization/qcborvalue.cpp37
-rw-r--r--src/corelib/serialization/qcborvalue.h5
-rw-r--r--src/corelib/serialization/qjsonvalue.cpp31
-rw-r--r--src/corelib/serialization/qjsonvalue.h6
-rw-r--r--src/gui/opengl/qopengl.cpp4
-rw-r--r--src/platformsupport/kmsconvenience/qkmsdevice.cpp5
-rw-r--r--tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp17
-rw-r--r--tests/benchmarks/corelib/json/tst_bench_qtjson.cpp11
8 files changed, 108 insertions, 8 deletions
diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp
index e9b7d5b71b6..2e61ed7460d 100644
--- a/src/corelib/serialization/qcborvalue.cpp
+++ b/src/corelib/serialization/qcborvalue.cpp
@@ -2195,7 +2195,7 @@ QByteArray QCborValue::toByteArray(const QByteArray &defaultValue) const
Note that this function performs no conversion from other types to
QString.
- \sa isString(), isByteArray(), toByteArray()
+ \sa toStringView(), isString(), isByteArray(), toByteArray()
*/
QString QCborValue::toString(const QString &defaultValue) const
{
@@ -2206,6 +2206,33 @@ QString QCborValue::toString(const QString &defaultValue) const
return container->stringAt(n);
}
+/*!
+ \since 6.10
+
+ Returns the string value stored in this QCborValue, if it is of the string
+ type. Otherwise, it returns \a defaultValue. Since QCborValue stores
+ strings in either US-ASCII, UTF-8 or UTF-16, the returned QAnyStringView
+ may be in any of these encodings.
+
+ This function does not allocate memory. The return value is valid until the
+ next call to a non-const member function on this object. If this object goes
+ out of scope, the return value is valid until the next call to a non-const
+ member function on the parent CBOR object (map or array).
+
+ Note that this function performs no conversion from other types to
+ QString.
+
+ \sa toString(), isString(), isByteArray(), toByteArray()
+*/
+QAnyStringView QCborValue::toStringView(QAnyStringView defaultValue) const
+{
+ if (!container || !isString())
+ return defaultValue;
+
+ Q_ASSERT(n >= 0);
+ return container->anyStringViewAt(n);
+}
+
#if QT_CONFIG(datestring)
/*!
Returns the date/time value stored in this QCborValue, if it is of the
@@ -2901,6 +2928,14 @@ QString QCborValueConstRef::concreteString(QCborValueConstRef self, const QStrin
return self.d->stringAt(self.i);
}
+QAnyStringView QCborValueConstRef::concreteStringView(QCborValueConstRef self, QAnyStringView defaultValue)
+{
+ QtCbor::Element e = self.d->elements.at(self.i);
+ if (e.type != QCborValue::String)
+ return defaultValue;
+ return self.d->anyStringViewAt(self.i);
+}
+
bool
QCborValueConstRef::comparesEqual_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
{
diff --git a/src/corelib/serialization/qcborvalue.h b/src/corelib/serialization/qcborvalue.h
index 4f4349bee33..3b20ac4487b 100644
--- a/src/corelib/serialization/qcborvalue.h
+++ b/src/corelib/serialization/qcborvalue.h
@@ -198,6 +198,7 @@ public:
QByteArray toByteArray(const QByteArray &defaultValue = {}) const;
QString toString(const QString &defaultValue = {}) const;
+ QAnyStringView toStringView(QAnyStringView defaultValue = {}) const;
#if QT_CONFIG(datestring)
QDateTime toDateTime(const QDateTime &defaultValue = {}) const;
#endif
@@ -350,6 +351,8 @@ public:
{ return concrete().toByteArray(defaultValue); }
QString toString(const QString &defaultValue = {}) const
{ return concrete().toString(defaultValue); }
+ QAnyStringView toStringView(QAnyStringView defaultValue = {}) const
+ { return concreteStringView(*this, defaultValue); }
#if QT_CONFIG(datestring)
QDateTime toDateTime(const QDateTime &defaultValue = {}) const
{ return concrete().toDateTime(defaultValue); }
@@ -442,6 +445,8 @@ protected:
concreteByteArray(QCborValueConstRef that, const QByteArray &defaultValue);
static Q_CORE_EXPORT QString
concreteString(QCborValueConstRef that, const QString &defaultValue);
+ static Q_CORE_EXPORT QAnyStringView
+ concreteStringView(QCborValueConstRef that, QAnyStringView defaultValue);
constexpr QCborValueConstRef() : d(nullptr), i(0) {} // this will actually be invalid
constexpr QCborValueConstRef(QCborContainerPrivate *dd, qsizetype ii)
diff --git a/src/corelib/serialization/qjsonvalue.cpp b/src/corelib/serialization/qjsonvalue.cpp
index 80115e77b65..71934932b26 100644
--- a/src/corelib/serialization/qjsonvalue.cpp
+++ b/src/corelib/serialization/qjsonvalue.cpp
@@ -744,6 +744,8 @@ double QJsonValue::toDouble(double defaultValue) const
Converts the value to a QString and returns it.
If type() is not String, the \a defaultValue will be returned.
+
+ \sa toStringView()
*/
QString QJsonValue::toString(const QString &defaultValue) const
{
@@ -751,6 +753,26 @@ QString QJsonValue::toString(const QString &defaultValue) const
}
/*!
+ \since 6.10
+
+ Returns the string value stored in this QJsonValue, if it is of the
+ \l{String}{string} type. Otherwise, it returns \a defaultValue. Since
+ QJsonValue stores strings in either US-ASCII, UTF-8 or UTF-16, the returned
+ QAnyStringView may be in any of these encodings.
+
+ This function does not allocate memory. The return value is valid until the
+ next call to a non-const member function on this object. If this object goes
+ out of scope, the return value is valid until the next call to a non-const
+ member function on the parent JSON object or array.
+
+ \sa toString()
+*/
+QAnyStringView QJsonValue::toStringView(QAnyStringView defaultValue) const
+{
+ return value.toStringView(defaultValue);
+}
+
+/*!
Converts the value to a QString and returns it.
If type() is not String, a null QString will be returned.
@@ -1066,6 +1088,15 @@ QString QJsonValueConstRef::concreteString(QJsonValueConstRef self, const QStrin
return d->stringAt(index);
}
+QAnyStringView QJsonValueConstRef::concreteStringView(QJsonValueConstRef self, QAnyStringView defaultValue)
+{
+ const QCborContainerPrivate *d = QJsonPrivate::Value::container(self);
+ const qsizetype index = QJsonPrivate::Value::indexHelper(self);
+ if (d->elements.at(index).type != QCborValue::String)
+ return defaultValue;
+ return d->anyStringViewAt(index);
+}
+
QJsonValue QJsonValueConstRef::concrete(QJsonValueConstRef self) noexcept
{
const QCborContainerPrivate *d = QJsonPrivate::Value::container(self);
diff --git a/src/corelib/serialization/qjsonvalue.h b/src/corelib/serialization/qjsonvalue.h
index a96d57890db..cb56f38b1a4 100644
--- a/src/corelib/serialization/qjsonvalue.h
+++ b/src/corelib/serialization/qjsonvalue.h
@@ -100,6 +100,7 @@ public:
double toDouble(double defaultValue = 0) const;
QString toString() const;
QString toString(const QString &defaultValue) const;
+ QAnyStringView toStringView(QAnyStringView defaultValue = {}) const;
QJsonArray toArray() const;
QJsonArray toArray(const QJsonArray &defaultValue) const;
QJsonObject toObject() const;
@@ -165,6 +166,8 @@ public:
{ return concreteDouble(*this, defaultValue); }
QString toString(const QString &defaultValue = {}) const
{ return concreteString(*this, defaultValue); }
+ QAnyStringView toStringView(QAnyStringView defaultValue = {}) const
+ { return concreteStringView(*this, defaultValue); }
Q_CORE_EXPORT QJsonArray toArray() const;
Q_CORE_EXPORT QJsonObject toObject() const;
@@ -195,6 +198,7 @@ protected:
Q_CORE_EXPORT static double
concreteDouble(QJsonValueConstRef self, double defaultValue) noexcept Q_DECL_PURE_FUNCTION;
Q_CORE_EXPORT static QString concreteString(QJsonValueConstRef self, const QString &defaultValue);
+ Q_CORE_EXPORT static QAnyStringView concreteStringView(QJsonValueConstRef self, QAnyStringView defaultValue);
Q_CORE_EXPORT static QJsonValue concrete(QJsonValueConstRef self) noexcept;
// for iterators
@@ -287,6 +291,8 @@ public:
inline qint64 toInteger(qint64 defaultValue = 0) const { return QJsonValueConstRef::toInteger(defaultValue); }
inline double toDouble(double defaultValue = 0) const { return QJsonValueConstRef::toDouble(defaultValue); }
inline QString toString(const QString &defaultValue = {}) const { return QJsonValueConstRef::toString(defaultValue); }
+ QAnyStringView toStringView(QAnyStringView defaultValue = {}) const
+ { return QJsonValueConstRef::toStringView(defaultValue); }
QJsonArray toArray() const;
QJsonObject toObject() const;
diff --git a/src/gui/opengl/qopengl.cpp b/src/gui/opengl/qopengl.cpp
index 587975085ad..021c3964219 100644
--- a/src/gui/opengl/qopengl.cpp
+++ b/src/gui/opengl/qopengl.cpp
@@ -176,8 +176,8 @@ VersionTerm VersionTerm::fromJson(const QJsonValue &v)
if (!v.isObject())
return result;
const QJsonObject o = v.toObject();
- result.number = QVersionNumber::fromString(o.value("value"_L1).toString());
- const QString opS = o.value("op"_L1).toString();
+ result.number = QVersionNumber::fromString(o.value("value"_L1).toStringView());
+ const auto opS = o.value("op"_L1).toStringView();
for (size_t i = 0; i < sizeof(operators) / sizeof(operators[0]); ++i) {
if (opS == QLatin1StringView(operators[i])) {
result.op = static_cast<Operator>(i);
diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp
index e49022d06ec..cdd2ac2d572 100644
--- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp
+++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp
@@ -1044,14 +1044,15 @@ void QKmsScreenConfig::loadConfig()
m_devicePath = object.value("device"_L1).toString();
m_separateScreens = object.value("separateScreens"_L1).toBool(m_separateScreens);
- const QString vdOriString = object.value("virtualDesktopLayout"_L1).toString();
+ const auto vdOriString = object.value("virtualDesktopLayout"_L1).toStringView();
if (!vdOriString.isEmpty()) {
if (vdOriString == "horizontal"_L1)
m_virtualDesktopLayout = VirtualDesktopLayoutHorizontal;
else if (vdOriString == "vertical"_L1)
m_virtualDesktopLayout = VirtualDesktopLayoutVertical;
else
- qCWarning(qLcKmsDebug) << "Unknown virtualDesktopOrientation value" << vdOriString;
+ qCWarning(qLcKmsDebug, "Unknown virtualDesktopOrientation value %ls",
+ qUtf16Printable(vdOriString.toString()));
}
const QJsonArray outputs = object.value("outputs"_L1).toArray();
diff --git a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp
index 5dee0a8d4e9..90b9679309c 100644
--- a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp
+++ b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp
@@ -342,6 +342,7 @@ static void basicTypeCheck(QCborValue::Type type, const QCborValue &v, const QVa
QVERIFY(validexpr)
CMP(v.toByteArray(), QByteArray, v.toByteArray().isNull());
CMP(v.toString(), QString, v.toString().isNull());
+ CMP(v.toStringView(), QString, v.toStringView().isNull());
CMP(v.toDateTime(), QDateTime, !v.toDateTime().isValid());
CMP(v.toUrl(), QUrl, !v.toUrl().isValid());
CMP(v.toRegularExpression(), QRegularExpression, v.toRegularExpression().pattern().isNull());
@@ -886,6 +887,7 @@ void tst_QCborValue::mapSimpleInitializerList()
QCborValue v = m.value(2);
QVERIFY(v.isString());
QCOMPARE(v.toString(), "Hello");
+ QCOMPARE(v.toStringView(), u8"Hello");
QCOMPARE(vmap[2], v);
}
{
@@ -893,6 +895,7 @@ void tst_QCborValue::mapSimpleInitializerList()
QCborValue v = m.value(3);
QVERIFY(v.isString());
QCOMPARE(v.toString(), "World");
+ QCOMPARE(v.toStringView(), "World"_L1);
QCOMPARE(vmap[3], v);
}
{
@@ -934,6 +937,7 @@ void tst_QCborValue::mapSimpleInitializerList()
QCOMPARE((it + 1).key(), QCborValue(2));
QVERIFY((it + 1)->isString());
QCOMPARE((it + 1)->toString(), "Hello");
+ QCOMPARE((it + 1)->toStringView(), u8"Hello");
it += 2;
QCOMPARE(it.key(), QCborValue("Hello"));
QVERIFY(it->isInteger());
@@ -941,6 +945,7 @@ void tst_QCborValue::mapSimpleInitializerList()
QCOMPARE(it.key(), QCborValue(3));
QVERIFY(it->isString());
QCOMPARE(it.value().toString(), "World");
+ QCOMPARE(it.value().toStringView(), "World"_L1);
--end;
QCOMPARE(end.key(), QCborValue("World"));
QCOMPARE(end.value(), QCborValue(3));
@@ -1462,6 +1467,7 @@ void tst_QCborValue::arrayStringElements()
QCborValueRef r1 = a[0];
QCOMPARE(r1.toString(), "Hello");
+ QCOMPARE(r1.toStringView(), u8"Hello");
QCOMPARE(r1.operator QCborValue(), QCborValue("Hello"));
QT_TEST_EQUALITY_OPS(r1, QCborValue("Hello"), true);
@@ -1476,10 +1482,11 @@ void tst_QCborValue::arrayStringElements()
v2 = a.at(1);
QCOMPARE(v2.toString(), "World");
+ QCOMPARE(v2.toStringView(), u8"World");
QT_TEST_EQUALITY_OPS(v2, QCborValue("World"), true);
QCOMPARE(a.takeAt(1).toString(), "World");
- QCOMPARE(a.takeAt(0).toString(), "Hello");
+ QCOMPARE(a.takeAt(0).toStringView(), "Hello"_L1);
QVERIFY(a.isEmpty());
}
@@ -1492,6 +1499,7 @@ void tst_QCborValue::mapStringValues()
QCborValueRef r1 = m[0];
QCOMPARE(r1.toString(), "Hello");
+ QCOMPARE(r1.toStringView(), "Hello"_L1);
QCOMPARE(r1.operator QCborValue(), QCborValue("Hello"));
QT_TEST_EQUALITY_OPS(r1, QCborValue("Hello"), true);
@@ -1506,10 +1514,11 @@ void tst_QCborValue::mapStringValues()
v2 = (m.begin() + 1).value();
QCOMPARE(v2.toString(), "World");
+ QCOMPARE(v2.toStringView(), "World"_L1);
QCOMPARE(v2, QCborValue("World"));
QCOMPARE(m.extract(m.begin() + 1).toString(), "World");
- QCOMPARE(m.take(0).toString(), "Hello");
+ QCOMPARE(m.take(0).toStringView(), u8"Hello");
QVERIFY(m.isEmpty());
}
@@ -1530,6 +1539,7 @@ void tst_QCborValue::mapStringKeys()
QVERIFY(m2.value(QCborValue(QByteArray("foo"))).isUndefined());
QVERIFY(m.value(QCborValue(QLatin1String("foo"))).isUndefined());
QCOMPARE(m.value(QCborValue(QByteArray("foo"))).toString(), "bar");
+ QCOMPARE(m.value(QCborValue(QByteArray("foo"))).toStringView(), "bar");
m.insert(u"World"_s, QCborValue(3)); // replaces
QCOMPARE(m.size(), 3);
@@ -1796,7 +1806,7 @@ void tst_QCborValue::mapComplexKeys()
// basics_data() strings are Latin1
QByteArray latin1 = v.toString().toLatin1();
- Q_ASSERT(v.toString() == QString::fromLatin1(latin1));
+ Q_ASSERT(v.toStringView() == QString::fromLatin1(latin1));
QCOMPARE(m[QLatin1String(latin1)].toInteger(), 42);
}
@@ -3007,6 +3017,7 @@ template <typename ValueRef> static void cborValueRef_template()
QCOMPARE(ref.toDouble(47), v.toDouble(47));
QCOMPARE(ref.toByteArray("other"), v.toByteArray("other"));
QCOMPARE(ref.toString("other"), v.toString("other"));
+ QCOMPARE(ref.toStringView("other"_L1), v.toStringView("other"));
QCOMPARE(ref.toArray(otherArray), v.toArray(otherArray));
QCOMPARE(ref.toMap(otherMap), v.toMap(otherMap));
QCOMPARE(ref.toDateTime(otherDateTime), v.toDateTime(otherDateTime));
diff --git a/tests/benchmarks/corelib/json/tst_bench_qtjson.cpp b/tests/benchmarks/corelib/json/tst_bench_qtjson.cpp
index eff1b4cf91b..f6fc7a0f6f3 100644
--- a/tests/benchmarks/corelib/json/tst_bench_qtjson.cpp
+++ b/tests/benchmarks/corelib/json/tst_bench_qtjson.cpp
@@ -38,6 +38,17 @@ private Q_SLOTS:
[](auto it) { return it->toString(); });
}
+ void iteratorKeyValueView()
+ {
+ iteratorKeyImpl([](auto it) { return it.key(); },
+ [](auto it) { return it->toStringView(); });
+ }
+ void iteratorKeyViewValueView()
+ {
+ iteratorKeyImpl([](auto it) { return it.keyView(); },
+ [](auto it) { return it->toStringView(); });
+ }
+
private:
template <typename KeyFunc, typename ValueFunc>
void iteratorKeyImpl(KeyFunc key, ValueFunc val);