QHttpHeaders: make default ctor non-allocating

... by allowing d == nullptr to mean the empty state.

Needed to add a few guards and specialize QESDP::detach() to be able
to detach from nullptr.

This also gets rid of the partially-formed moved-from state. It's now
guaranteed to be empty.

Change-Id: If874d7c69d91eb4babe667ae577f261610d52fd3
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
(cherry picked from commit 61130d73d47249fb1106ed86f8da908c96fe11c7)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2024-01-25 11:10:48 +01:00 committed by Qt Cherry-pick Bot
parent 55b2011bcd
commit 44b6b3870a
2 changed files with 36 additions and 15 deletions

View File

@ -94,6 +94,15 @@ public:
}; };
QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QHttpHeadersPrivate) QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QHttpHeadersPrivate)
template <> void QExplicitlySharedDataPointer<QHttpHeadersPrivate>::detach()
{
if (!d) {
d = new QHttpHeadersPrivate();
d->ref.ref();
} else if (d->ref.loadRelaxed() != 1) {
detach_helper();
}
}
// This list is from IANA HTTP Field Name Registry // This list is from IANA HTTP Field Name Registry
// https://www.iana.org/assignments/http-fields // https://www.iana.org/assignments/http-fields
@ -472,7 +481,7 @@ static constexpr auto headerNames = qOffsetStringArray(
/*! /*!
Creates a new QHttpHeaders object. Creates a new QHttpHeaders object.
*/ */
QHttpHeaders::QHttpHeaders() : d(new QHttpHeadersPrivate) QHttpHeaders::QHttpHeaders() noexcept : d()
{ {
} }
@ -542,11 +551,8 @@ QHttpHeaders &QHttpHeaders::operator=(const QHttpHeaders &other)
/*! /*!
\fn QHttpHeaders::QHttpHeaders(QHttpHeaders &&other) noexcept \fn QHttpHeaders::QHttpHeaders(QHttpHeaders &&other) noexcept
Move-constructs the object from \a other. Move-constructs the object from \a other, which will be left
\l{isEmpty()}{empty}.
\note The moved-from object \a other is placed in a
partially-formed state, in which the only valid operations are
destruction and assignment of a new value.
*/ */
/*! /*!
@ -554,9 +560,7 @@ QHttpHeaders &QHttpHeaders::operator=(const QHttpHeaders &other)
Move-assigns \a other and returns a reference to this object. Move-assigns \a other and returns a reference to this object.
\note The moved-from object \a other is placed in a \a other will be left \l{isEmpty()}{empty}.
partially-formed state, in which the only valid operations are
destruction and assignment of a new value.
*/ */
/*! /*!
@ -578,12 +582,15 @@ QDebug operator<<(QDebug debug, const QHttpHeaders &headers)
const QDebugStateSaver saver(debug); const QDebugStateSaver saver(debug);
debug.resetFormat().nospace(); debug.resetFormat().nospace();
debug << "QHttpHeaders(headers = "; debug << "QHttpHeaders(";
if (headers.d) {
debug << "headers = ";
const char *separator = ""; const char *separator = "";
for (const auto &h : headers.d->headers) { for (const auto &h : headers.d->headers) {
debug << separator << h.name << ':' << h.value; debug << separator << h.name << ':' << h.value;
separator = " | "; separator = " | ";
} }
}
debug << ")"; debug << ")";
return debug; return debug;
} }
@ -867,6 +874,8 @@ bool QHttpHeaders::replace(qsizetype i, WellKnownHeader name, QAnyStringView new
*/ */
bool QHttpHeaders::contains(QAnyStringView name) const bool QHttpHeaders::contains(QAnyStringView name) const
{ {
if (!d)
return false;
return std::any_of(d->headers.cbegin(), d->headers.cend(), return std::any_of(d->headers.cbegin(), d->headers.cend(),
[&name](const Header &header) { return headerNameIs(header, name); }); [&name](const Header &header) { return headerNameIs(header, name); });
} }
@ -924,6 +933,8 @@ void QHttpHeaders::removeAt(qsizetype i)
*/ */
QByteArrayView QHttpHeaders::value(QAnyStringView name, QByteArrayView defaultValue) const noexcept QByteArrayView QHttpHeaders::value(QAnyStringView name, QByteArrayView defaultValue) const noexcept
{ {
if (!d)
return defaultValue;
for (const auto &h : std::as_const(d->headers)) { for (const auto &h : std::as_const(d->headers)) {
if (headerNameIs(h, name)) if (headerNameIs(h, name))
return h.value; return h.value;
@ -948,6 +959,8 @@ QByteArrayView QHttpHeaders::value(WellKnownHeader name, QByteArrayView defaultV
QList<QByteArray> QHttpHeaders::values(QAnyStringView name) const QList<QByteArray> QHttpHeaders::values(QAnyStringView name) const
{ {
QList<QByteArray> values; QList<QByteArray> values;
if (!d)
return values;
for (const auto &h : std::as_const(d->headers)) { for (const auto &h : std::as_const(d->headers)) {
if (headerNameIs(h, name)) if (headerNameIs(h, name))
values.append(h.value); values.append(h.value);
@ -1028,6 +1041,8 @@ QByteArray QHttpHeaders::combinedValue(WellKnownHeader name) const
*/ */
qsizetype QHttpHeaders::size() const noexcept qsizetype QHttpHeaders::size() const noexcept
{ {
if (!d)
return 0;
return d->headers.size(); return d->headers.size();
} }
@ -1059,6 +1074,8 @@ QByteArrayView QHttpHeaders::wellKnownHeaderName(WellKnownHeader name) noexcept
QList<std::pair<QByteArray, QByteArray>> QHttpHeaders::toListOfPairs() const QList<std::pair<QByteArray, QByteArray>> QHttpHeaders::toListOfPairs() const
{ {
QList<std::pair<QByteArray, QByteArray>> list; QList<std::pair<QByteArray, QByteArray>> list;
if (!d)
return list;
list.reserve(size()); list.reserve(size());
for (const auto & h : std::as_const(d->headers)) for (const auto & h : std::as_const(d->headers))
list.append({h.name, h.value}); list.append({h.name, h.value});
@ -1072,6 +1089,8 @@ QList<std::pair<QByteArray, QByteArray>> QHttpHeaders::toListOfPairs() const
QMultiMap<QByteArray, QByteArray> QHttpHeaders::toMultiMap() const QMultiMap<QByteArray, QByteArray> QHttpHeaders::toMultiMap() const
{ {
QMultiMap<QByteArray, QByteArray> map; QMultiMap<QByteArray, QByteArray> map;
if (!d)
return map;
for (const auto &h : std::as_const(d->headers)) for (const auto &h : std::as_const(d->headers))
map.insert(h.name, h.value); map.insert(h.name, h.value);
return map; return map;
@ -1084,6 +1103,8 @@ QMultiMap<QByteArray, QByteArray> QHttpHeaders::toMultiMap() const
QMultiHash<QByteArray, QByteArray> QHttpHeaders::toMultiHash() const QMultiHash<QByteArray, QByteArray> QHttpHeaders::toMultiHash() const
{ {
QMultiHash<QByteArray, QByteArray> hash; QMultiHash<QByteArray, QByteArray> hash;
if (!d)
return hash;
hash.reserve(size()); hash.reserve(size());
for (const auto &h : std::as_const(d->headers)) for (const auto &h : std::as_const(d->headers))
hash.insert(h.name, h.value); hash.insert(h.name, h.value);

View File

@ -201,7 +201,7 @@ public:
}; };
Q_ENUM(WellKnownHeader) Q_ENUM(WellKnownHeader)
Q_NETWORK_EXPORT QHttpHeaders(); Q_NETWORK_EXPORT QHttpHeaders() noexcept;
Q_NETWORK_EXPORT ~QHttpHeaders(); Q_NETWORK_EXPORT ~QHttpHeaders();
Q_NETWORK_EXPORT QHttpHeaders(const QHttpHeaders &other); Q_NETWORK_EXPORT QHttpHeaders(const QHttpHeaders &other);