summaryrefslogtreecommitdiffstats
path: root/src/corelib/text/qbytearray.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/text/qbytearray.cpp')
-rw-r--r--src/corelib/text/qbytearray.cpp1595
1 files changed, 930 insertions, 665 deletions
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index 03fbe2b139..e6387e4bed 100644
--- a/src/corelib/text/qbytearray.cpp
+++ b/src/corelib/text/qbytearray.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbytearray.h"
#include "qbytearraymatcher.h"
@@ -50,25 +14,36 @@
#include "private/qsimd_p.h"
#include "qstringalgorithms_p.h"
#include "qscopedpointer.h"
-#include "qbytearray_p.h"
#include "qstringconverter_p.h"
#include <qdatastream.h>
#include <qmath.h>
+#if defined(Q_OS_WASM)
+#include "private/qstdweb_p.h"
+#endif
#ifndef QT_NO_COMPRESS
#include <zconf.h>
#include <zlib.h>
+#include <qxpfunctional.h>
#endif
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
-#define IS_RAW_DATA(d) ((d)->flags() & QArrayData::RawDataType)
+#include <algorithm>
+
+#ifdef Q_OS_WIN
+# if !defined(QT_BOOTSTRAPPED) && (defined(QT_NO_CAST_FROM_ASCII) || defined(QT_NO_CAST_FROM_BYTEARRAY))
+// MSVC requires this, but let's apply it to MinGW compilers too, just in case
+# error "This file cannot be compiled with QT_NO_CAST_{TO,FROM}_ASCII, " \
+ "otherwise some QByteArray functions will not get exported."
+# endif
+#endif
QT_BEGIN_NAMESPACE
-const char QByteArray::_empty = '\0';
+Q_CONSTINIT const char QByteArray::_empty = '\0';
// ASCII case system, used by QByteArray::to{Upper,Lower}() and qstr(n)icmp():
static constexpr inline uchar asciiUpper(uchar c)
@@ -144,31 +119,30 @@ char *qstrcpy(char *dst, const char *src)
A safe \c strncpy() function.
Copies at most \a len bytes from \a src (stopping at \a len or the
- terminating '\\0' whichever comes first) into \a dst and returns a
- pointer to \a dst. Guarantees that \a dst is '\\0'-terminated. If
- \a src or \a dst is \nullptr, returns \nullptr immediately.
+ terminating '\\0' whichever comes first) into \a dst. Guarantees that \a
+ dst is '\\0'-terminated, except when \a dst is \nullptr or \a len is 0. If
+ \a src is \nullptr, returns \nullptr, otherwise returns \a dst.
This function assumes that \a dst is at least \a len characters
long.
\note If \a dst and \a src overlap, the behavior is undefined.
+ \note Unlike strncpy(), this function does \e not write '\\0' to all \a
+ len bytes of \a dst, but stops after the terminating '\\0'. In this sense,
+ it's similar to C11's strncpy_s().
+
\sa qstrcpy()
*/
char *qstrncpy(char *dst, const char *src, size_t len)
{
- if (!src || !dst)
- return nullptr;
- if (len > 0) {
-#ifdef Q_CC_MSVC
- strncpy_s(dst, len, src, len - 1);
-#else
- strncpy(dst, src, len);
-#endif
- dst[len-1] = '\0';
+ if (dst && len > 0) {
+ *dst = '\0';
+ if (src)
+ std::strncat(dst, src, len - 1);
}
- return dst;
+ return src ? dst : nullptr;
}
/*! \fn size_t qstrlen(const char *str)
@@ -270,7 +244,7 @@ int qstricmp(const char *str1, const char *str2)
max += offset;
do {
uchar c = s1[offset];
- if (int res = asciiLower(c) - asciiLower(s2[offset]))
+ if (int res = QtMiscUtils::caseCompareAscii(c, s2[offset]))
return res;
if (!c)
return 0;
@@ -309,7 +283,7 @@ int qstricmp(const char *str1, const char *str2)
// yes, find out where
uint start = qCountTrailingZeroBits(mask);
uint end = sizeof(mask) * 8 - qCountLeadingZeroBits(mask);
- Q_ASSUME(end >= start);
+ Q_ASSERT(end >= start);
offset += start;
n = end - start;
break;
@@ -353,7 +327,7 @@ int qstrnicmp(const char *str1, const char *str2, size_t len)
return s1 ? 1 : (s2 ? -1 : 0);
for (; len--; ++s1, ++s2) {
const uchar c = *s1;
- if (int res = asciiLower(c) - asciiLower(*s2))
+ if (int res = QtMiscUtils::caseCompareAscii(c, *s2))
return res;
if (!c) // strings are equal
break;
@@ -394,7 +368,7 @@ int qstrnicmp(const char *str1, qsizetype len1, const char *str2, qsizetype len2
if (!c)
return 1;
- if (int res = asciiLower(s1[i]) - asciiLower(c))
+ if (int res = QtMiscUtils::caseCompareAscii(s1[i], c))
return res;
}
return s2[i] ? -1 : 0;
@@ -402,7 +376,7 @@ int qstrnicmp(const char *str1, qsizetype len1, const char *str2, qsizetype len2
// not null-terminated
const qsizetype len = qMin(len1, len2);
for (qsizetype i = 0; i < len; ++i) {
- if (int res = asciiLower(s1[i]) - asciiLower(s2[i]))
+ if (int res = QtMiscUtils::caseCompareAscii(s1[i], s2[i]))
return res;
}
if (len1 == len2)
@@ -542,7 +516,9 @@ quint16 qChecksum(QByteArrayView data, Qt::ChecksumType standard)
\sa qUncompress(const QByteArray &data)
*/
-/*! \relates QByteArray
+/*!
+ \fn QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
+ \relates QByteArray
\overload
@@ -551,44 +527,196 @@ quint16 qChecksum(QByteArrayView data, Qt::ChecksumType standard)
*/
#ifndef QT_NO_COMPRESS
+using CompressSizeHint_t = quint32; // 32-bit BE, historically
+
+enum class ZLibOp : bool { Compression, Decompression };
+
+Q_DECL_COLD_FUNCTION
+static const char *zlibOpAsString(ZLibOp op)
+{
+ switch (op) {
+ case ZLibOp::Compression: return "qCompress";
+ case ZLibOp::Decompression: return "qUncompress";
+ }
+ Q_UNREACHABLE_RETURN(nullptr);
+}
+
+Q_DECL_COLD_FUNCTION
+static QByteArray zlibError(ZLibOp op, const char *what)
+{
+ qWarning("%s: %s", zlibOpAsString(op), what);
+ return QByteArray();
+}
+
+Q_DECL_COLD_FUNCTION
+static QByteArray dataIsNull(ZLibOp op)
+{
+ return zlibError(op, "Data is null");
+}
+
+Q_DECL_COLD_FUNCTION
+static QByteArray lengthIsNegative(ZLibOp op)
+{
+ return zlibError(op, "Input length is negative");
+}
+
+Q_DECL_COLD_FUNCTION
+static QByteArray tooMuchData(ZLibOp op)
+{
+ return zlibError(op, "Not enough memory");
+}
+
+Q_DECL_COLD_FUNCTION
+static QByteArray invalidCompressedData()
+{
+ return zlibError(ZLibOp::Decompression, "Input data is corrupted");
+}
+
+Q_DECL_COLD_FUNCTION
+static QByteArray unexpectedZlibError(ZLibOp op, int err, const char *msg)
+{
+ qWarning("%s unexpected zlib error: %s (%d)",
+ zlibOpAsString(op),
+ msg ? msg : "",
+ err);
+ return QByteArray();
+}
+
+static QByteArray xxflate(ZLibOp op, QArrayDataPointer<char> out, QByteArrayView input,
+ qxp::function_ref<int(z_stream *) const> init,
+ qxp::function_ref<int(z_stream *, size_t) const> processChunk,
+ qxp::function_ref<void(z_stream *) const> deinit)
+{
+ if (out.data() == nullptr) // allocation failed
+ return tooMuchData(op);
+ qsizetype capacity = out.allocatedCapacity();
+
+ const auto initalSize = out.size;
+
+ z_stream zs = {};
+ zs.next_in = reinterpret_cast<uchar *>(const_cast<char *>(input.data())); // 1980s C API...
+ if (const int err = init(&zs); err != Z_OK)
+ return unexpectedZlibError(op, err, zs.msg);
+ const auto sg = qScopeGuard([&] { deinit(&zs); });
+
+ using ZlibChunkSize_t = decltype(zs.avail_in);
+ static_assert(!std::is_signed_v<ZlibChunkSize_t>);
+ static_assert(std::is_same_v<ZlibChunkSize_t, decltype(zs.avail_out)>);
+ constexpr auto MaxChunkSize = std::numeric_limits<ZlibChunkSize_t>::max();
+ [[maybe_unused]]
+ constexpr auto MaxStatisticsSize = std::numeric_limits<decltype(zs.total_out)>::max();
+
+ size_t inputLeft = size_t(input.size());
+
+ int res;
+ do {
+ Q_ASSERT(out.freeSpaceAtBegin() == 0); // ensure prepend optimization stays out of the way
+ Q_ASSERT(capacity == out.allocatedCapacity());
+
+ if (zs.avail_out == 0) {
+ Q_ASSERT(size_t(out.size) - initalSize > MaxStatisticsSize || // total_out overflow
+ size_t(out.size) - initalSize == zs.total_out);
+ Q_ASSERT(out.size <= capacity);
+
+ qsizetype avail_out = capacity - out.size;
+ if (avail_out == 0) {
+ out->reallocateAndGrow(QArrayData::GrowsAtEnd, 1); // grow to next natural capacity
+ if (out.data() == nullptr) // reallocation failed
+ return tooMuchData(op);
+ capacity = out.allocatedCapacity();
+ avail_out = capacity - out.size;
+ }
+ zs.next_out = reinterpret_cast<uchar *>(out.data()) + out.size;
+ zs.avail_out = size_t(avail_out) > size_t(MaxChunkSize) ? MaxChunkSize
+ : ZlibChunkSize_t(avail_out);
+ out.size += zs.avail_out;
+
+ Q_ASSERT(zs.avail_out > 0);
+ }
+
+ if (zs.avail_in == 0) {
+ // zs.next_in is kept up-to-date by processChunk(), so nothing to do
+ zs.avail_in = inputLeft > MaxChunkSize ? MaxChunkSize : ZlibChunkSize_t(inputLeft);
+ inputLeft -= zs.avail_in;
+ }
+
+ res = processChunk(&zs, inputLeft);
+ } while (res == Z_OK);
+
+ switch (res) {
+ case Z_STREAM_END:
+ out.size -= zs.avail_out;
+ Q_ASSERT(size_t(out.size) - initalSize > MaxStatisticsSize || // total_out overflow
+ size_t(out.size) - initalSize == zs.total_out);
+ Q_ASSERT(out.size <= out.allocatedCapacity());
+ out.data()[out.size] = '\0';
+ return QByteArray(std::move(out));
+
+ case Z_MEM_ERROR:
+ return tooMuchData(op);
+
+ case Z_BUF_ERROR:
+ Q_UNREACHABLE(); // cannot happen - we supply a buffer that can hold the result,
+ // or else error out early
+
+ case Z_DATA_ERROR: // can only happen on decompression
+ Q_ASSERT(op == ZLibOp::Decompression);
+ return invalidCompressedData();
+
+ default:
+ return unexpectedZlibError(op, res, zs.msg);
+ }
+}
+
QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
{
+ constexpr qsizetype HeaderSize = sizeof(CompressSizeHint_t);
if (nbytes == 0) {
- return QByteArray(4, '\0');
- }
- if (!data) {
- qWarning("qCompress: Data is null");
- return QByteArray();
+ return QByteArray(HeaderSize, '\0');
}
+ if (!data)
+ return dataIsNull(ZLibOp::Compression);
+
+ if (nbytes < 0)
+ return lengthIsNegative(ZLibOp::Compression);
+
if (compressionLevel < -1 || compressionLevel > 9)
compressionLevel = -1;
- ulong len = nbytes + nbytes / 100 + 13;
- QByteArray bazip;
- int res;
- do {
- bazip.resize(len + 4);
- res = ::compress2((uchar*)bazip.data()+4, &len, data, nbytes, compressionLevel);
-
- switch (res) {
- case Z_OK:
- bazip.resize(len + 4);
- bazip[0] = (nbytes & 0xff000000) >> 24;
- bazip[1] = (nbytes & 0x00ff0000) >> 16;
- bazip[2] = (nbytes & 0x0000ff00) >> 8;
- bazip[3] = (nbytes & 0x000000ff);
- break;
- case Z_MEM_ERROR:
- qWarning("qCompress: Z_MEM_ERROR: Not enough memory");
- bazip.resize(0);
- break;
- case Z_BUF_ERROR:
- len *= 2;
- break;
+ QArrayDataPointer out = [&] {
+ constexpr qsizetype SingleAllocLimit = 256 * 1024; // the maximum size for which we use
+ // zlib's compressBound() to guarantee
+ // the output buffer size is sufficient
+ // to hold result
+ qsizetype capacity = HeaderSize;
+ if (nbytes < SingleAllocLimit) {
+ // use maximum size
+ capacity += compressBound(uLong(nbytes)); // cannot overflow (both times)!
+ return QArrayDataPointer<char>(capacity);
}
- } while (res == Z_BUF_ERROR);
- return bazip;
+ // for larger buffers, assume it compresses optimally, and
+ // grow geometrically from there:
+ constexpr qsizetype MaxCompressionFactor = 1024; // max theoretical factor is 1032
+ // cf. http://www.zlib.org/zlib_tech.html,
+ // but use a nearby power-of-two (faster)
+ capacity += std::max(qsizetype(compressBound(uLong(SingleAllocLimit))),
+ nbytes / MaxCompressionFactor);
+ return QArrayDataPointer<char>(capacity, 0, QArrayData::Grow);
+ }();
+
+ if (out.data() == nullptr) // allocation failed
+ return tooMuchData(ZLibOp::Compression);
+
+ qToBigEndian(qt_saturate<CompressSizeHint_t>(nbytes), out.data());
+ out.size = HeaderSize;
+
+ return xxflate(ZLibOp::Compression, std::move(out), {data, nbytes},
+ [=] (z_stream *zs) { return deflateInit(zs, compressionLevel); },
+ [] (z_stream *zs, size_t inputLeft) {
+ return deflate(zs, inputLeft ? Z_NO_FLUSH : Z_FINISH);
+ },
+ [] (z_stream *zs) { deflateEnd(zs); });
}
#endif
@@ -610,18 +738,21 @@ QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
data that was compressed using zlib, you first need to prepend a four
byte header to the byte array containing the data. The header must
contain the expected length (in bytes) of the uncompressed data,
- expressed as an unsigned, big-endian, 32-bit integer.
+ expressed as an unsigned, big-endian, 32-bit integer. This number is
+ just a hint for the initial size of the output buffer size,
+ though. If the indicated size is too small to hold the result, the
+ output buffer size will still be increased until either the output
+ fits or the system runs out of memory. So, despite the 32-bit
+ header, this function, on 64-bit platforms, can produce more than
+ 4GiB of output.
+
+ \note In Qt versions prior to Qt 6.5, more than 2GiB of data
+ worked unreliably; in Qt versions prior to Qt 6.0, not at all.
\sa qCompress()
*/
#ifndef QT_NO_COMPRESS
-static QByteArray invalidCompressedData()
-{
- qWarning("qUncompress: Input data is corrupted");
- return QByteArray();
-}
-
/*! \relates QByteArray
\overload
@@ -631,64 +762,39 @@ static QByteArray invalidCompressedData()
*/
QByteArray qUncompress(const uchar* data, qsizetype nbytes)
{
- if (!data) {
- qWarning("qUncompress: Data is null");
- return QByteArray();
- }
- if (nbytes <= 4) {
- if (nbytes < 4 || (data[0]!=0 || data[1]!=0 || data[2]!=0 || data[3]!=0))
- qWarning("qUncompress: Input data is corrupted");
- return QByteArray();
- }
- size_t expectedSize = size_t((data[0] << 24) | (data[1] << 16) |
- (data[2] << 8) | (data[3] ));
- size_t len = qMax(expectedSize, 1ul);
- const size_t maxPossibleSize = MaxAllocSize - sizeof(QByteArray::Data);
- if (Q_UNLIKELY(len >= maxPossibleSize)) {
- // QByteArray does not support that huge size anyway.
- return invalidCompressedData();
- }
+ if (!data)
+ return dataIsNull(ZLibOp::Decompression);
+
+ if (nbytes < 0)
+ return lengthIsNegative(ZLibOp::Decompression);
- QByteArray::DataPointer d(QByteArray::Data::allocate(len));
- if (Q_UNLIKELY(d.data() == nullptr))
+ constexpr qsizetype HeaderSize = sizeof(CompressSizeHint_t);
+ if (nbytes < HeaderSize)
return invalidCompressedData();
- forever {
- const auto alloc = len;
- int res = ::uncompress((uchar*)d.data(), reinterpret_cast<uLongf*>(&len),
- data+4, nbytes-4);
-
- switch (res) {
- case Z_OK: {
- Q_ASSERT(len <= alloc);
- Q_UNUSED(alloc);
- d.data()[len] = '\0';
- d.size = len;
- return QByteArray(d);
- }
+ const auto expectedSize = qFromBigEndian<CompressSizeHint_t>(data);
+ if (nbytes == HeaderSize) {
+ if (expectedSize != 0)
+ return invalidCompressedData();
+ return QByteArray();
+ }
- case Z_MEM_ERROR:
- qWarning("qUncompress: Z_MEM_ERROR: Not enough memory");
- return QByteArray();
+ constexpr auto MaxDecompressedSize = size_t(QByteArray::max_size());
+ if constexpr (MaxDecompressedSize < std::numeric_limits<CompressSizeHint_t>::max()) {
+ if (expectedSize > MaxDecompressedSize)
+ return tooMuchData(ZLibOp::Decompression);
+ }
- case Z_BUF_ERROR:
- len *= 2;
- if (Q_UNLIKELY(len >= maxPossibleSize)) {
- // QByteArray does not support that huge size anyway.
- return invalidCompressedData();
- } else {
- // grow the block
- d->reallocate(d->allocatedCapacity()*2, QArrayData::Grow);
- if (Q_UNLIKELY(d.data() == nullptr))
- return invalidCompressedData();
- }
- continue;
+ // expectedSize may be truncated, so always use at least nbytes
+ // (larger by at most 1%, according to zlib docs)
+ qsizetype capacity = std::max(qsizetype(expectedSize), // cannot overflow!
+ nbytes);
- case Z_DATA_ERROR:
- qWarning("qUncompress: Z_DATA_ERROR: Input data is corrupted");
- return QByteArray();
- }
- }
+ QArrayDataPointer<char> d(capacity);
+ return xxflate(ZLibOp::Decompression, std::move(d), {data + HeaderSize, nbytes - HeaderSize},
+ [] (z_stream *zs) { return inflateInit(zs); },
+ [] (z_stream *zs, size_t) { return inflate(zs, Z_NO_FLUSH); },
+ [] (z_stream *zs) { inflateEnd(zs); });
}
#endif
@@ -703,6 +809,14 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
\reentrant
+ \compares strong
+ \compareswith strong {const char *} QByteArrayView
+ \endcompareswith
+ \compareswith strong QChar char16_t QString QStringView QLatin1StringView \
+ QUtf8StringView
+ When comparing with string types, the content is interpreted as utf-8.
+ \endcompareswith
+
QByteArray can be used to store both raw bytes (including '\\0's)
and traditional 8-bit '\\0'-terminated strings. Using QByteArray
is much more convenient than using \c{const char *}. Behind the
@@ -927,8 +1041,8 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
comparison is limited to ASCII. Non-ASCII characters are treated as
caseless, since their case depends on encoding. This affects functions that
support a case insensitive option or that change the case of their
- arguments. Functions that this affects include contains(), indexOf(),
- lastIndexOf(), isLower(), isUpper(), toLower() and toUpper().
+ arguments. Functions that this affects include compare(), isLower(),
+ isUpper(), toLower() and toUpper().
This issue does not apply to \l{QString}s since they represent characters
using Unicode.
@@ -1172,6 +1286,22 @@ QByteArray::iterator QByteArray::erase(QByteArray::const_iterator first, QByteAr
return begin() + start;
}
+/*!
+ \fn QByteArray::iterator QByteArray::erase(QByteArray::const_iterator it)
+
+ \overload
+ \since 6.5
+
+ Removes the character denoted by \c it from the byte array.
+ Returns an iterator to the character immediately after the
+ erased character.
+
+ \code
+ QByteArray ba = "abcdefg";
+ auto it = ba.erase(ba.cbegin()); // ba is now "bcdefg" and it points to "b"
+ \endcode
+*/
+
/*! \fn QByteArray::QByteArray(const QByteArray &other)
Constructs a copy of \a other.
@@ -1219,6 +1349,9 @@ QByteArray &QByteArray::operator=(const QByteArray & other) noexcept
\overload
Assigns \a str to this byte array.
+
+ \a str is assumed to point to a null-terminated string, and its length is
+ determined dynamically.
*/
QByteArray &QByteArray::operator=(const char *str)
@@ -1228,14 +1361,7 @@ QByteArray &QByteArray::operator=(const char *str)
} else if (!*str) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- const qsizetype len = qsizetype(strlen(str));
- const auto capacityAtEnd = d->allocatedCapacity() - d.freeSpaceAtBegin();
- if (d->needsDetach() || len > capacityAtEnd
- || (len < size() && len < (capacityAtEnd >> 1)))
- // ### inefficient! reallocData() does copy the old data and we then overwrite it in the next line
- reallocData(len, QArrayData::KeepSize);
- memcpy(d.data(), str, len + 1); // include null terminator
- d.size = len;
+ assign(str);
}
return *this;
}
@@ -1273,6 +1399,15 @@ QByteArray &QByteArray::operator=(const char *str)
\sa isEmpty(), resize()
*/
+/*! \fn qsizetype QByteArray::max_size()
+ \since 6.8
+
+ This function is provided for STL compatibility.
+ It returns the maximum number of elements that the byte array can
+ theoretically hold. In practice, the number can be much smaller,
+ limited by the amount of memory available to the system.
+*/
+
/*! \fn bool QByteArray::isEmpty() const
Returns \c true if the byte array has size 0; otherwise returns \c false.
@@ -1686,7 +1821,7 @@ QByteArray::QByteArray(const char *data, qsizetype size)
if (!size) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size), size);
+ d = DataPointer(size, size);
Q_CHECK_PTR(d.data());
memcpy(d.data(), data, size);
d.data()[size] = '\0';
@@ -1705,7 +1840,7 @@ QByteArray::QByteArray(qsizetype size, char ch)
if (size <= 0) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size), size);
+ d = DataPointer(size, size);
Q_CHECK_PTR(d.data());
memset(d.data(), ch, size);
d.data()[size] = '\0';
@@ -1713,8 +1848,6 @@ QByteArray::QByteArray(qsizetype size, char ch)
}
/*!
- \internal
-
Constructs a byte array of size \a size with uninitialized contents.
*/
@@ -1723,7 +1856,7 @@ QByteArray::QByteArray(qsizetype size, Qt::Initialization)
if (size <= 0) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size), size);
+ d = DataPointer(size, size);
Q_CHECK_PTR(d.data());
d.data()[size] = '\0';
}
@@ -1758,6 +1891,46 @@ void QByteArray::resize(qsizetype size)
}
/*!
+ \since 6.4
+
+ Sets the size of the byte array to \a newSize bytes.
+
+ If \a newSize is greater than the current size, the byte array is
+ extended to make it \a newSize bytes with the extra bytes added to
+ the end. The new bytes are initialized to \a c.
+
+ If \a newSize is less than the current size, bytes beyond position
+ \a newSize are excluded from the byte array.
+
+ \note While resize() will grow the capacity if needed, it never shrinks
+ capacity. To shed excess capacity, use squeeze().
+
+ \sa size(), truncate(), squeeze()
+*/
+void QByteArray::resize(qsizetype newSize, char c)
+{
+ const auto old = d.size;
+ resize(newSize);
+ if (old < d.size)
+ memset(d.data() + old, c, d.size - old);
+}
+
+/*!
+ \since 6.8
+
+ Resizes the byte array to \a size bytes. If the size of the
+ byte array grows, the new bytes are uninitialized.
+
+ The behavior is identical to \c{resize(size)}.
+
+ \sa resize()
+*/
+void QByteArray::resizeForOverwrite(qsizetype size)
+{
+ resize(size);
+}
+
+/*!
Sets every byte in the byte array to \a ch. If \a size is different from -1
(the default), the byte array is resized to size \a size beforehand.
@@ -1787,7 +1960,7 @@ void QByteArray::reallocData(qsizetype alloc, QArrayData::AllocationOption optio
const bool cannotUseReallocate = d.freeSpaceAtBegin() > 0;
if (d->needsDetach() || cannotUseReallocate) {
- DataPointer dd(Data::allocate(alloc, option), qMin(alloc, d.size));
+ DataPointer dd(alloc, qMin(alloc, d.size), option);
Q_CHECK_PTR(dd.data());
if (dd.size > 0)
::memcpy(dd.data(), d.data(), dd.size);
@@ -1820,26 +1993,6 @@ void QByteArray::expand(qsizetype i)
}
/*!
- \internal
- Return a QByteArray that is sure to be '\\0'-terminated.
-
- By default, all QByteArray have an extra NUL at the end,
- guaranteeing that assumption. However, if QByteArray::fromRawData
- is used, then the NUL is there only if the user put it there. We
- can't be sure.
-*/
-QByteArray QByteArray::nulTerminated() const
-{
- // is this fromRawData?
- if (d.isMutable())
- return *this; // no, then we're sure we're zero terminated
-
- QByteArray copy(*this);
- copy.detach();
- return copy;
-}
-
-/*!
\fn QByteArray &QByteArray::prepend(QByteArrayView ba)
Prepends the byte array view \a ba to this byte array and returns a
@@ -1927,9 +2080,17 @@ QByteArray &QByteArray::prepend(const QByteArray &ba)
QByteArray &QByteArray::append(const QByteArray &ba)
{
- if (size() == 0 && ba.size() > d->freeSpaceAtEnd() && ba.d.isMutable())
- return (*this = ba);
- return append(QByteArrayView(ba));
+ if (!ba.isNull()) {
+ if (isNull()) {
+ if (Q_UNLIKELY(!ba.d.isMutable()))
+ assign(ba); // fromRawData, so we do a deep copy
+ else
+ operator=(ba);
+ } else if (ba.size()) {
+ append(QByteArrayView(ba));
+ }
+ }
+ return *this;
}
/*!
@@ -1988,6 +2149,73 @@ QByteArray& QByteArray::append(char ch)
}
/*!
+ \fn QByteArray &QByteArray::assign(QByteArrayView v)
+ \since 6.6
+
+ Replaces the contents of this byte array with a copy of \a v and returns a
+ reference to this byte array.
+
+ The size of this byte array will be equal to the size of \a v.
+
+ This function only allocates memory if the size of \a v exceeds the capacity
+ of this byte array or this byte array is shared.
+*/
+
+/*!
+ \fn QByteArray &QByteArray::assign(qsizetype n, char c)
+ \since 6.6
+
+ Replaces the contents of this byte array with \a n copies of \a c and
+ returns a reference to this byte array.
+
+ The size of this byte array will be equal to \a n, which has to be non-negative.
+
+ This function will only allocate memory if \a n exceeds the capacity of this
+ byte array or this byte array is shared.
+
+ \sa fill()
+*/
+
+/*!
+ \fn template <typename InputIterator, QByteArray::if_input_iterator<InputIterator>> QByteArray &QByteArray::assign(InputIterator first, InputIterator last)
+ \since 6.6
+
+ Replaces the contents of this byte array with a copy of the elements in the
+ iterator range [\a first, \a last) and returns a reference to this
+ byte array.
+
+ The size of this byte array will be equal to the number of elements in the
+ range [\a first, \a last).
+
+ This function will only allocate memory if the number of elements in the
+ range exceeds the capacity of this byte array or this byte array is shared.
+
+ \note This function overload only participates in overload resolution if
+ \c InputIterator meets the requirements of a
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}.
+
+ \note The behavior is undefined if either argument is an iterator into *this or
+ [\a first, \a last) is not a valid range.
+*/
+
+QByteArray &QByteArray::assign(QByteArrayView v)
+{
+ const auto len = v.size();
+
+ if (len <= capacity() && isDetached()) {
+ const auto offset = d.freeSpaceAtBegin();
+ if (offset)
+ d.setBegin(d.begin() - offset);
+ std::memcpy(d.begin(), v.data(), len);
+ d.size = len;
+ d.data()[d.size] = '\0';
+ } else {
+ *this = v.toByteArray();
+ }
+ return *this;
+}
+
+/*!
Inserts \a data at index position \a i and returns a
reference to this byte array.
@@ -2029,7 +2257,7 @@ QByteArray &QByteArray::insert(qsizetype i, QByteArrayView data)
return *this;
}
- if (!d->needsDetach() && QtPrivate::q_points_into_range(str, d.data(), d.data() + d.size)) {
+ if (!d->needsDetach() && QtPrivate::q_points_into_range(str, d)) {
QVarLengthArray a(str, str + size);
return insert(i, a);
}
@@ -2134,15 +2362,56 @@ QByteArray &QByteArray::remove(qsizetype pos, qsizetype len)
{
if (len <= 0 || pos < 0 || size_t(pos) >= size_t(size()))
return *this;
- detach();
if (pos + len > d->size)
len = d->size - pos;
- d->erase(d.begin() + pos, len);
- d.data()[d.size] = '\0';
+
+ auto begin = d.begin();
+ if (!d->isShared()) {
+ d->erase(begin + pos, len);
+ d.data()[d.size] = '\0';
+ } else {
+ QByteArray copy{size() - len, Qt::Uninitialized};
+ const auto toRemove_start = d.begin() + pos;
+ copy.d->copyRanges({{d.begin(), toRemove_start},
+ {toRemove_start + len, d.end()}});
+ swap(copy);
+ }
return *this;
}
/*!
+ \fn QByteArray &QByteArray::removeAt(qsizetype pos)
+
+ \since 6.5
+
+ Removes the character at index \a pos. If \a pos is out of bounds
+ (i.e. \a pos >= size()) this function does nothing.
+
+ \sa remove()
+*/
+
+/*!
+ \fn QByteArray &QByteArray::removeFirst()
+
+ \since 6.5
+
+ Removes the first character in this byte array. If the byte array is empty,
+ this function does nothing.
+
+ \sa remove()
+*/
+/*!
+ \fn QByteArray &QByteArray::removeLast()
+
+ \since 6.5
+
+ Removes the last character in this byte array. If the byte array is empty,
+ this function does nothing.
+
+ \sa remove()
+*/
+
+/*!
\fn template <typename Predicate> QByteArray &QByteArray::removeIf(Predicate pred)
\since 6.1
@@ -2164,13 +2433,16 @@ QByteArray &QByteArray::remove(qsizetype pos, qsizetype len)
QByteArray &QByteArray::replace(qsizetype pos, qsizetype len, QByteArrayView after)
{
- if (QtPrivate::q_points_into_range(after.data(), d.data(), d.data() + d.size)) {
+ if (QtPrivate::q_points_into_range(after.data(), d)) {
QVarLengthArray copy(after.data(), after.data() + after.size());
return replace(pos, len, QByteArrayView{copy});
}
if (len == after.size() && (pos + len <= size())) {
- detach();
- memmove(d.data() + pos, after.data(), len*sizeof(char));
+ // same size: in-place replacement possible
+ if (len > 0) {
+ detach();
+ memcpy(d.data() + pos, after.data(), len*sizeof(char));
+ }
return *this;
} else {
// ### optimize me
@@ -2221,11 +2493,11 @@ QByteArray &QByteArray::replace(QByteArrayView before, QByteArrayView after)
return *this;
// protect against before or after being part of this
- if (QtPrivate::q_points_into_range(a, d.data(), d.data() + d.size)) {
+ if (QtPrivate::q_points_into_range(a, d)) {
QVarLengthArray copy(a, a + asize);
return replace(before, QByteArrayView{copy});
}
- if (QtPrivate::q_points_into_range(b, d.data(), d.data() + d.size)) {
+ if (QtPrivate::q_points_into_range(b, d)) {
QVarLengthArray copy(b, b + bsize);
return replace(QByteArrayView{copy}, after);
}
@@ -2333,12 +2605,11 @@ QByteArray &QByteArray::replace(QByteArrayView before, QByteArrayView after)
QByteArray &QByteArray::replace(char before, char after)
{
- if (!isEmpty()) {
- char *i = data();
- char *e = i + size();
- for (; i != e; ++i)
- if (*i == before)
- * i = after;
+ if (before != after) {
+ if (const auto pos = indexOf(before); pos >= 0) {
+ const auto detachedData = data();
+ std::replace(detachedData + pos, detachedData + size(), before, after);
+ }
}
return *this;
}
@@ -2414,20 +2685,6 @@ QByteArray QByteArray::repeated(qsizetype times) const
hashHaystack -= std::size_t(a) << ol_minus_1; \
hashHaystack <<= 1
-static inline qsizetype findCharHelper(QByteArrayView haystack, qsizetype from, char needle) noexcept
-{
- if (from < 0)
- from = qMax(from + haystack.size(), qsizetype(0));
- if (from < haystack.size()) {
- const char *const b = haystack.data();
- if (const auto n = static_cast<const char *>(
- memchr(b + from, needle, static_cast<size_t>(haystack.size() - from)))) {
- return n - b;
- }
- }
- return -1;
-}
-
qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept
{
const auto ol = needle.size();
@@ -2440,7 +2697,7 @@ qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByt
}
if (ol == 1)
- return findCharHelper(haystack, from, needle.front());
+ return findByteArray(haystack, from, needle.front());
if (from > l || ol + from > l)
return -1;
@@ -2462,6 +2719,7 @@ qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByt
*/
/*!
+ \fn qsizetype QByteArray::indexOf(char ch, qsizetype from) const
\overload
Returns the index position of the start of the first occurrence of the
@@ -2474,11 +2732,6 @@ qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByt
\sa lastIndexOf(), contains()
*/
-qsizetype QByteArray::indexOf(char ch, qsizetype from) const
-{
- return qToByteArrayViewIgnoringNull(*this).indexOf(ch, from);
-}
-
static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char *needle,
qsizetype ol, qsizetype from)
{
@@ -2532,6 +2785,11 @@ static inline qsizetype lastIndexOfCharHelper(QByteArrayView haystack, qsizetype
return -1;
}
+qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, char needle) noexcept
+{
+ return lastIndexOfCharHelper(haystack, from, needle);
+}
+
qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept
{
if (haystack.isEmpty()) {
@@ -2551,9 +2809,11 @@ qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteA
Returns the index position of the start of the last occurrence of the
sequence of bytes viewed by \a bv in this byte array, searching backward
- from index position \a from. If \a from is -1, the search starts at
- the last character; if \a from is -2, at the next to last character
- and so on. Returns -1 if no match is found.
+ from index position \a from.
+
+ \include qstring.qdocinc negative-index-start-search-from-end
+
+ Returns -1 if no match is found.
Example:
\snippet code/src_corelib_text_qbytearray.cpp 23
@@ -2583,6 +2843,7 @@ qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteA
*/
/*!
+ \fn qsizetype QByteArray::lastIndexOf(char ch, qsizetype from) const
\overload
Returns the index position of the start of the last occurrence of byte \a ch
@@ -2596,11 +2857,6 @@ qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteA
\sa indexOf(), contains()
*/
-qsizetype QByteArray::lastIndexOf(char ch, qsizetype from) const
-{
- return qToByteArrayViewIgnoringNull(*this).lastIndexOf(ch, from);
-}
-
static inline qsizetype countCharHelper(QByteArrayView haystack, char needle) noexcept
{
qsizetype num = 0;
@@ -2622,8 +2878,8 @@ qsizetype QtPrivate::count(QByteArrayView haystack, QByteArrayView needle) noexc
qsizetype num = 0;
qsizetype i = -1;
if (haystack.size() > 500 && needle.size() > 5) {
- QByteArrayMatcher matcher(needle.data(), needle.size());
- while ((i = matcher.indexIn(haystack.data(), haystack.size(), i + 1)) != -1)
+ QByteArrayMatcher matcher(needle);
+ while ((i = matcher.indexIn(haystack, i + 1)) != -1)
++num;
} else {
while ((i = haystack.indexOf(needle, i + 1)) != -1)
@@ -2651,15 +2907,17 @@ qsizetype QtPrivate::count(QByteArrayView haystack, QByteArrayView needle) noexc
qsizetype QByteArray::count(char ch) const
{
- return static_cast<int>(countCharHelper(*this, ch));
+ return countCharHelper(*this, ch);
}
+#if QT_DEPRECATED_SINCE(6, 4)
/*! \fn qsizetype QByteArray::count() const
-
+ \deprecated [6.4] Use size() or length() instead.
\overload
Same as size().
*/
+#endif
/*!
\fn int QByteArray::compare(QByteArrayView bv, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
@@ -2740,56 +2998,44 @@ static constexpr inline bool isUpperCaseAscii(char c)
return c >= 'A' && c <= 'Z';
}
+/*
+ Returns true if \a c is an lowercase ASCII letter.
+ */
+static constexpr inline bool isLowerCaseAscii(char c)
+{
+ return c >= 'a' && c <= 'z';
+}
+
/*!
- Returns \c true if this byte array contains only ASCII uppercase letters,
- otherwise returns \c false.
+ Returns \c true if this byte array is uppercase, that is, if
+ it's identical to its toUpper() folding.
+
+ Note that this does \e not mean that the byte array only contains
+ uppercase letters; only that it contains no ASCII lowercase letters.
+
\since 5.12
\sa isLower(), toUpper()
*/
bool QByteArray::isUpper() const
{
- if (isEmpty())
- return false;
-
- const char *d = data();
-
- for (qsizetype i = 0, max = size(); i < max; ++i) {
- if (!isUpperCaseAscii(d[i]))
- return false;
- }
-
- return true;
-}
-
-/*
- Returns true if \a c is an lowercase ASCII letter.
- */
-static constexpr inline bool isLowerCaseAscii(char c)
-{
- return c >= 'a' && c <= 'z';
+ return std::none_of(begin(), end(), isLowerCaseAscii);
}
/*!
- Returns \c true if this byte array contains only lowercase ASCII letters,
- otherwise returns \c false.
+ Returns \c true if this byte array is lowercase, that is, if
+ it's identical to its toLower() folding.
+
+ Note that this does \e not mean that the byte array only contains
+ lowercase letters; only that it contains no ASCII uppercase letters.
+
\since 5.12
\sa isUpper(), toLower()
*/
bool QByteArray::isLower() const
{
- if (isEmpty())
- return false;
-
- const char *d = data();
-
- for (qsizetype i = 0, max = size(); i < max; ++i) {
- if (!isLowerCaseAscii(d[i]))
- return false;
- }
-
- return true;
+ return std::none_of(begin(), end(), isUpperCaseAscii);
}
/*!
@@ -2802,6 +3048,9 @@ bool QByteArray::isLower() const
*/
/*!
+ \fn QByteArray QByteArray::left(qsizetype len) const &
+ \fn QByteArray QByteArray::left(qsizetype len) &&
+
Returns a byte array that contains the first \a len bytes of this byte
array.
@@ -2816,16 +3065,10 @@ bool QByteArray::isLower() const
\sa first(), last(), startsWith(), chopped(), chop(), truncate()
*/
-QByteArray QByteArray::left(qsizetype len) const
-{
- if (len >= size())
- return *this;
- if (len < 0)
- len = 0;
- return QByteArray(data(), len);
-}
-
/*!
+ \fn QByteArray QByteArray::right(qsizetype len) const &
+ \fn QByteArray QByteArray::right(qsizetype len) &&
+
Returns a byte array that contains the last \a len bytes of this byte array.
If you know that \a len cannot be out of bounds, use last() instead in new
@@ -2836,18 +3079,13 @@ QByteArray QByteArray::left(qsizetype len) const
Returns an empty QByteArray if \a len is smaller than 0.
- \sa endsWith(), last(), first(), sliced(), chopped(), chop(), truncate()
+ \sa endsWith(), last(), first(), sliced(), chopped(), chop(), truncate(), slice()
*/
-QByteArray QByteArray::right(qsizetype len) const
-{
- if (len >= size())
- return *this;
- if (len < 0)
- len = 0;
- return QByteArray(end() - len, len);
-}
/*!
+ \fn QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const &
+ \fn QByteArray QByteArray::mid(qsizetype pos, qsizetype len) &&
+
Returns a byte array containing \a len bytes from this byte array,
starting at position \a pos.
@@ -2858,10 +3096,10 @@ QByteArray QByteArray::right(qsizetype len) const
returns a byte array containing all bytes starting at position \a
pos until the end of the byte array.
- \sa first(), last(), sliced(), chopped(), chop(), truncate()
+ \sa first(), last(), sliced(), chopped(), chop(), truncate(), slice()
*/
-QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
+QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const &
{
qsizetype p = pos;
qsizetype l = len;
@@ -2876,14 +3114,33 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
case QContainerImplHelper::Full:
return *this;
case QContainerImplHelper::Subset:
- return QByteArray(d.data() + p, l);
+ return sliced(p, l);
}
- Q_UNREACHABLE();
- return QByteArray();
+ Q_UNREACHABLE_RETURN(QByteArray());
+}
+
+QByteArray QByteArray::mid(qsizetype pos, qsizetype len) &&
+{
+ qsizetype p = pos;
+ qsizetype l = len;
+ using namespace QtPrivate;
+ switch (QContainerImplHelper::mid(size(), &p, &l)) {
+ case QContainerImplHelper::Null:
+ return QByteArray();
+ case QContainerImplHelper::Empty:
+ resize(0); // keep capacity if we've reserve()d
+ [[fallthrough]];
+ case QContainerImplHelper::Full:
+ return std::move(*this);
+ case QContainerImplHelper::Subset:
+ return std::move(*this).sliced(p, l);
+ }
+ Q_UNREACHABLE_RETURN(QByteArray());
}
/*!
- \fn QByteArray QByteArray::first(qsizetype n) const
+ \fn QByteArray QByteArray::first(qsizetype n) const &
+ \fn QByteArray QByteArray::first(qsizetype n) &&
\since 6.0
Returns the first \a n bytes of the byte array.
@@ -2893,11 +3150,12 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
Example:
\snippet code/src_corelib_text_qbytearray.cpp 27
- \sa last(), sliced(), startsWith(), chopped(), chop(), truncate()
+ \sa last(), sliced(), startsWith(), chopped(), chop(), truncate(), slice()
*/
/*!
- \fn QByteArray QByteArray::last(qsizetype n) const
+ \fn QByteArray QByteArray::last(qsizetype n) const &
+ \fn QByteArray QByteArray::last(qsizetype n) &&
\since 6.0
Returns the last \a n bytes of the byte array.
@@ -2907,11 +3165,12 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
Example:
\snippet code/src_corelib_text_qbytearray.cpp 28
- \sa first(), sliced(), endsWith(), chopped(), chop(), truncate()
+ \sa first(), sliced(), endsWith(), chopped(), chop(), truncate(), slice()
*/
/*!
- \fn QByteArray QByteArray::sliced(qsizetype pos, qsizetype n) const
+ \fn QByteArray QByteArray::sliced(qsizetype pos, qsizetype n) const &
+ \fn QByteArray QByteArray::sliced(qsizetype pos, qsizetype n) &&
\since 6.0
Returns a byte array containing the \a n bytes of this object starting
@@ -2923,11 +3182,20 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
Example:
\snippet code/src_corelib_text_qbytearray.cpp 29
- \sa first(), last(), chopped(), chop(), truncate()
+ \sa first(), last(), chopped(), chop(), truncate(), slice()
*/
+QByteArray QByteArray::sliced_helper(QByteArray &a, qsizetype pos, qsizetype n)
+{
+ if (n == 0)
+ return fromRawData(&_empty, 0);
+ DataPointer d = std::move(a.d).sliced(pos, n);
+ d.data()[n] = 0;
+ return QByteArray(std::move(d));
+}
/*!
- \fn QByteArray QByteArray::sliced(qsizetype pos) const
+ \fn QByteArray QByteArray::sliced(qsizetype pos) const &
+ \fn QByteArray QByteArray::sliced(qsizetype pos) &&
\since 6.0
\overload
@@ -2936,11 +3204,41 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
\note The behavior is undefined when \a pos < 0 or \a pos > size().
- \sa first(), last(), sliced(), chopped(), chop(), truncate()
+ \sa first(), last(), chopped(), chop(), truncate(), slice()
*/
/*!
- \fn QByteArray QByteArray::chopped(qsizetype len) const
+ \fn QByteArray &QByteArray::slice(qsizetype pos, qsizetype n)
+ \since 6.8
+
+ Modifies this byte array to start at position \a pos, extending for \a n
+ bytes, and returns a reference to this byte array.
+
+ \note The behavior is undefined if \a pos < 0, \a n < 0,
+ or \a pos + \a n > size().
+
+ Example:
+ \snippet code/src_corelib_text_qbytearray.cpp 57
+
+ \sa sliced(), first(), last(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QByteArray &QByteArray::slice(qsizetype pos)
+ \since 6.8
+ \overload
+
+ Modifies this byte array to start at position \a pos, extending to its
+ end, and returns a reference to this byte array.
+
+ \note The behavior is undefined if \a pos < 0 or \a pos > size().
+
+ \sa sliced(), first(), last(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QByteArray QByteArray::chopped(qsizetype len) const &
+ \fn QByteArray QByteArray::chopped(qsizetype len) &&
\since 5.10
Returns a byte array that contains the leftmost size() - \a len bytes of
@@ -2948,7 +3246,7 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
\note The behavior is undefined if \a len is negative or greater than size().
- \sa endsWith(), first(), last(), sliced(), chop(), truncate()
+ \sa endsWith(), first(), last(), sliced(), chop(), truncate(), slice()
*/
/*!
@@ -2963,11 +3261,7 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
\sa isLower(), toUpper(), {Character Case}
*/
-// prevent the compiler from inlining the function in each of
-// toLower and toUpper when the only difference is the table being used
-// (even with constant propagation, there's no gain in performance).
template <typename T>
-Q_NEVER_INLINE
static QByteArray toCase_template(T &input, uchar (*lookup)(uchar))
{
// find the first bad character in input
@@ -3038,7 +3332,7 @@ void QByteArray::clear()
d.clear();
}
-#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
+#if !defined(QT_NO_DATASTREAM)
/*! \relates QByteArray
@@ -3051,7 +3345,7 @@ void QByteArray::clear()
QDataStream &operator<<(QDataStream &out, const QByteArray &ba)
{
if (ba.isNull() && out.version() >= 6) {
- out << (quint32)0xffffffff;
+ QDataStream::writeQSizeType(out, -1);
return out;
}
return out.writeBytes(ba.constData(), ba.size());
@@ -3068,13 +3362,21 @@ QDataStream &operator<<(QDataStream &out, const QByteArray &ba)
QDataStream &operator>>(QDataStream &in, QByteArray &ba)
{
ba.clear();
- quint32 len;
- in >> len;
- if (len == 0xffffffff)
+
+ qint64 size = QDataStream::readQSizeType(in);
+ qsizetype len = size;
+ if (size != len || size < -1) {
+ ba.clear();
+ in.setStatus(QDataStream::SizeLimitExceeded);
+ return in;
+ }
+ if (len == -1) { // null byte-array
+ ba = QByteArray();
return in;
+ }
- const quint32 Step = 1024 * 1024;
- quint32 allocated = 0;
+ constexpr qsizetype Step = 1024 * 1024;
+ qsizetype allocated = 0;
do {
qsizetype blockSize = qMin(Step, len - allocated);
@@ -3091,253 +3393,169 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
}
#endif // QT_NO_DATASTREAM
-/*! \fn bool QByteArray::operator==(const QString &str) const
-
- Returns \c true if this byte array is equal to the UTF-8 encoding of \a str;
- otherwise returns \c false.
-
- The comparison is case sensitive.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. You
- then need to call QString::fromUtf8(), QString::fromLatin1(),
- or QString::fromLocal8Bit() explicitly if you want to convert the byte
- array to a QString before doing the comparison.
-*/
-
-/*! \fn bool QByteArray::operator!=(const QString &str) const
-
- Returns \c true if this byte array is not equal to the UTF-8 encoding of \a
- str; otherwise returns \c false.
-
- The comparison is case sensitive.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. You
- then need to call QString::fromUtf8(), QString::fromLatin1(),
- or QString::fromLocal8Bit() explicitly if you want to convert the byte
- array to a QString before doing the comparison.
-*/
-
-/*! \fn bool QByteArray::operator<(const QString &str) const
-
- Returns \c true if this byte array is lexically less than the UTF-8 encoding
- of \a str; otherwise returns \c false.
-
- The comparison is case sensitive.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. You
- then need to call QString::fromUtf8(), QString::fromLatin1(),
- or QString::fromLocal8Bit() explicitly if you want to convert the byte
- array to a QString before doing the comparison.
-*/
-
-/*! \fn bool QByteArray::operator>(const QString &str) const
-
- Returns \c true if this byte array is lexically greater than the UTF-8
- encoding of \a str; otherwise returns \c false.
-
- The comparison is case sensitive.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. You
- then need to call QString::fromUtf8(), QString::fromLatin1(),
- or QString::fromLocal8Bit() explicitly if you want to convert the byte
- array to a QString before doing the comparison.
-*/
-
-/*! \fn bool QByteArray::operator<=(const QString &str) const
-
- Returns \c true if this byte array is lexically less than or equal to the
- UTF-8 encoding of \a str; otherwise returns \c false.
-
- The comparison is case sensitive.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. You
- then need to call QString::fromUtf8(), QString::fromLatin1(),
- or QString::fromLocal8Bit() explicitly if you want to convert the byte
- array to a QString before doing the comparison.
-*/
-
-/*! \fn bool QByteArray::operator>=(const QString &str) const
-
- Returns \c true if this byte array is greater than or equal to the UTF-8
- encoding of \a str; otherwise returns \c false.
-
- The comparison is case sensitive.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. You
- then need to call QString::fromUtf8(), QString::fromLatin1(),
- or QString::fromLocal8Bit() explicitly if you want to convert the byte
- array to a QString before doing the comparison.
-*/
-
-/*! \fn bool QByteArray::operator==(const QByteArray &a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator==(const QByteArray &lhs, const QByteArray &rhs)
\overload
- Returns \c true if byte array \a a1 is equal to byte array \a a2;
+ Returns \c true if byte array \a lhs is equal to byte array \a rhs;
otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator==(const QByteArray &a1, const char *a2)
+/*! \fn bool QByteArray::operator==(const QByteArray &lhs, const char * const &rhs)
\overload
- Returns \c true if byte array \a a1 is equal to the '\\0'-terminated string
- \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is equal to the '\\0'-terminated string
+ \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator==(const char *a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator==(const char * const &lhs, const QByteArray &rhs)
\overload
- Returns \c true if '\\0'-terminated string \a a1 is equal to byte array \a
- a2; otherwise returns \c false.
+ Returns \c true if '\\0'-terminated string \a lhs is equal to byte array \a
+ rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator!=(const QByteArray &a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator!=(const QByteArray &lhs, const QByteArray &rhs)
\overload
- Returns \c true if byte array \a a1 is not equal to byte array \a a2;
+ Returns \c true if byte array \a lhs is not equal to byte array \a rhs;
otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator!=(const QByteArray &a1, const char *a2)
+/*! \fn bool QByteArray::operator!=(const QByteArray &lhs, const char * const &rhs)
\overload
- Returns \c true if byte array \a a1 is not equal to the '\\0'-terminated
- string \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is not equal to the '\\0'-terminated
+ string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator!=(const char *a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator!=(const char * const &lhs, const QByteArray &rhs)
\overload
- Returns \c true if '\\0'-terminated string \a a1 is not equal to byte array
- \a a2; otherwise returns \c false.
+ Returns \c true if '\\0'-terminated string \a lhs is not equal to byte array
+ \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator<(const QByteArray &a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator<(const QByteArray &lhs, const QByteArray &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically less than byte array
- \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically less than byte array
+ \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator<(const QByteArray &a1, const char *a2)
+/*! \fn bool QByteArray::operator<(const QByteArray &lhs, const char * const &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically less than the
- '\\0'-terminated string \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically less than the
+ '\\0'-terminated string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator<(const char *a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator<(const char * const &lhs, const QByteArray &rhs)
\overload
- Returns \c true if '\\0'-terminated string \a a1 is lexically less than byte
- array \a a2; otherwise returns \c false.
+ Returns \c true if '\\0'-terminated string \a lhs is lexically less than byte
+ array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator<=(const QByteArray &a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator<=(const QByteArray &lhs, const QByteArray &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically less than or equal
- to byte array \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically less than or equal
+ to byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator<=(const QByteArray &a1, const char *a2)
+/*! \fn bool QByteArray::operator<=(const QByteArray &lhs, const char * const &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically less than or equal to the
- '\\0'-terminated string \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically less than or equal to the
+ '\\0'-terminated string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator<=(const char *a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator<=(const char * const &lhs, const QByteArray &rhs)
\overload
- Returns \c true if '\\0'-terminated string \a a1 is lexically less than or
- equal to byte array \a a2; otherwise returns \c false.
+ Returns \c true if '\\0'-terminated string \a lhs is lexically less than or
+ equal to byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator>(const QByteArray &a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator>(const QByteArray &lhs, const QByteArray &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically greater than byte
- array \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically greater than byte
+ array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator>(const QByteArray &a1, const char *a2)
+/*! \fn bool QByteArray::operator>(const QByteArray &lhs, const char * const &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically greater than the
- '\\0'-terminated string \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically greater than the
+ '\\0'-terminated string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator>(const char *a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator>(const char * const &lhs, const QByteArray &rhs)
\overload
- Returns \c true if '\\0'-terminated string \a a1 is lexically greater than
- byte array \a a2; otherwise returns \c false.
+ Returns \c true if '\\0'-terminated string \a lhs is lexically greater than
+ byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator>=(const QByteArray &a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator>=(const QByteArray &lhs, const QByteArray &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically greater than or
- equal to byte array \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically greater than or
+ equal to byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator>=(const QByteArray &a1, const char *a2)
+/*! \fn bool QByteArray::operator>=(const QByteArray &lhs, const char * const &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically greater than or equal to
- the '\\0'-terminated string \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically greater than or equal to
+ the '\\0'-terminated string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator>=(const char *a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator>=(const char * const &lhs, const QByteArray &rhs)
\overload
- Returns \c true if '\\0'-terminated string \a a1 is lexically greater than
- or equal to byte array \a a2; otherwise returns \c false.
+ Returns \c true if '\\0'-terminated string \a lhs is lexically greater than
+ or equal to byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn const QByteArray operator+(const QByteArray &a1, const QByteArray &a2)
+/*! \fn QByteArray operator+(const QByteArray &a1, const QByteArray &a2)
\relates QByteArray
Returns a byte array that is the result of concatenating byte
@@ -3346,7 +3564,7 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
\sa QByteArray::operator+=()
*/
-/*! \fn const QByteArray operator+(const QByteArray &a1, const char *a2)
+/*! \fn QByteArray operator+(const QByteArray &a1, const char *a2)
\relates QByteArray
\overload
@@ -3355,7 +3573,7 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
and '\\0'-terminated string \a a2.
*/
-/*! \fn const QByteArray operator+(const QByteArray &a1, char a2)
+/*! \fn QByteArray operator+(const QByteArray &a1, char a2)
\relates QByteArray
\overload
@@ -3364,7 +3582,7 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
array \a a1 and byte \a a2.
*/
-/*! \fn const QByteArray operator+(const char *a1, const QByteArray &a2)
+/*! \fn QByteArray operator+(const char *a1, const QByteArray &a2)
\relates QByteArray
\overload
@@ -3373,7 +3591,7 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
string \a a1 and byte array \a a2.
*/
-/*! \fn const QByteArray operator+(char a1, const QByteArray &a2)
+/*! \fn QByteArray operator+(char a1, const QByteArray &a2)
\relates QByteArray
\overload
@@ -3440,9 +3658,7 @@ QByteArray QByteArray::trimmed_helper(QByteArray &a)
QByteArrayView QtPrivate::trimmed(QByteArrayView view) noexcept
{
- auto start = view.begin();
- auto stop = view.end();
- QStringAlgorithms<QByteArrayView>::trimmed_helper_positions(start, stop);
+ const auto [start, stop] = QStringAlgorithms<QByteArrayView>::trimmed_helper_positions(view);
return QByteArrayView(start, stop);
}
@@ -3520,46 +3736,38 @@ QByteArray QByteArray::rightJustified(qsizetype width, char fill, bool truncate)
return result;
}
-bool QByteArray::isNull() const
-{
- return d->isNull();
-}
-
-static qlonglong toIntegral_helper(QByteArrayView data, bool *ok, int base, qlonglong)
+auto QtPrivate::toSignedInteger(QByteArrayView data, int base) -> ParsedNumber<qlonglong>
{
- return QLocaleData::bytearrayToLongLong(data, base, ok);
-}
+#if defined(QT_CHECK_RANGE)
+ if (base != 0 && (base < 2 || base > 36)) {
+ qWarning("QByteArray::toIntegral: Invalid base %d", base);
+ base = 10;
+ }
+#endif
+ if (data.isEmpty())
+ return {};
-static qulonglong toIntegral_helper(QByteArrayView data, bool *ok, int base, qulonglong)
-{
- return QLocaleData::bytearrayToUnsLongLong(data, base, ok);
+ const QSimpleParsedNumber r = QLocaleData::bytearrayToLongLong(data, base);
+ if (r.ok())
+ return ParsedNumber(r.result);
+ return {};
}
-template <typename T> static inline
-T toIntegral_helper(QByteArrayView data, bool *ok, int base)
+auto QtPrivate::toUnsignedInteger(QByteArrayView data, int base) -> ParsedNumber<qulonglong>
{
- using Int64 = typename std::conditional<std::is_unsigned<T>::value, qulonglong, qlonglong>::type;
-
#if defined(QT_CHECK_RANGE)
if (base != 0 && (base < 2 || base > 36)) {
qWarning("QByteArray::toIntegral: Invalid base %d", base);
base = 10;
}
#endif
- if (data.isEmpty()) {
- if (ok)
- *ok = false;
- return 0;
- }
+ if (data.isEmpty())
+ return {};
- // we select the right overload by the last, unused parameter
- Int64 val = toIntegral_helper(data, ok, base, Int64());
- if (T(val) != val) {
- if (ok)
- *ok = false;
- val = 0;
- }
- return T(val);
+ const QSimpleParsedNumber r = QLocaleData::bytearrayToUnsLongLong(data, base);
+ if (r.ok())
+ return ParsedNumber(r.result);
+ return {};
}
/*!
@@ -3569,8 +3777,9 @@ T toIntegral_helper(QByteArrayView data, bool *ok, int base)
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
- (base 16); otherwise, if it begins with "0", it is assumed to be octal (base
- 8); otherwise it is assumed to be decimal.
+ (base 16); otherwise, if it begins with "0b", it is assumed to be binary
+ (base 2); otherwise, if it begins with "0", it is assumed to be octal
+ (base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@@ -3581,17 +3790,14 @@ T toIntegral_helper(QByteArrayView data, bool *ok, int base)
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number()
*/
qlonglong QByteArray::toLongLong(bool *ok, int base) const
{
- return toIntegral_helper<qlonglong>(*this, ok, base);
-}
-
-qlonglong QByteArrayView::toLongLong(bool *ok, int base) const
-{
- return toIntegral_helper<qlonglong>(*this, ok, base);
+ return QtPrivate::toIntegral<qlonglong>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3601,8 +3807,9 @@ qlonglong QByteArrayView::toLongLong(bool *ok, int base) const
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
- (base 16); otherwise, if it begins with "0", it is assumed to be octal (base
- 8); otherwise it is assumed to be decimal.
+ (base 16); otherwise, if it begins with "0b", it is assumed to be binary
+ (base 2); otherwise, if it begins with "0", it is assumed to be octal
+ (base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@@ -3613,17 +3820,14 @@ qlonglong QByteArrayView::toLongLong(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number()
*/
qulonglong QByteArray::toULongLong(bool *ok, int base) const
{
- return toIntegral_helper<qulonglong>(*this, ok, base);
-}
-
-qulonglong QByteArrayView::toULongLong(bool *ok, int base) const
-{
- return toIntegral_helper<qulonglong>(*this, ok, base);
+ return QtPrivate::toIntegral<qulonglong>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3633,8 +3837,9 @@ qulonglong QByteArrayView::toULongLong(bool *ok, int base) const
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
- (base 16); otherwise, if it begins with "0", it is assumed to be octal (base
- 8); otherwise it is assumed to be decimal.
+ (base 16); otherwise, if it begins with "0b", it is assumed to be binary
+ (base 2); otherwise, if it begins with "0", it is assumed to be octal
+ (base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@@ -3647,17 +3852,14 @@ qulonglong QByteArrayView::toULongLong(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number()
*/
int QByteArray::toInt(bool *ok, int base) const
{
- return toIntegral_helper<int>(*this, ok, base);
-}
-
-int QByteArrayView::toInt(bool *ok, int base) const
-{
- return toIntegral_helper<int>(*this, ok, base);
+ return QtPrivate::toIntegral<int>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3667,8 +3869,9 @@ int QByteArrayView::toInt(bool *ok, int base) const
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
- (base 16); otherwise, if it begins with "0", it is assumed to be octal (base
- 8); otherwise it is assumed to be decimal.
+ (base 16); otherwise, if it begins with "0b", it is assumed to be binary
+ (base 2); otherwise, if it begins with "0", it is assumed to be octal
+ (base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@@ -3679,17 +3882,14 @@ int QByteArrayView::toInt(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number()
*/
uint QByteArray::toUInt(bool *ok, int base) const
{
- return toIntegral_helper<uint>(*this, ok, base);
-}
-
-uint QByteArrayView::toUInt(bool *ok, int base) const
-{
- return toIntegral_helper<uint>(*this, ok, base);
+ return QtPrivate::toIntegral<uint>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3701,8 +3901,9 @@ uint QByteArrayView::toUInt(bool *ok, int base) const
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
- (base 16); otherwise, if it begins with "0", it is assumed to be octal (base
- 8); otherwise it is assumed to be decimal.
+ (base 16); otherwise, if it begins with "0b", it is assumed to be binary
+ (base 2); otherwise, if it begins with "0", it is assumed to be octal
+ (base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@@ -3715,16 +3916,13 @@ uint QByteArrayView::toUInt(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number()
*/
long QByteArray::toLong(bool *ok, int base) const
{
- return toIntegral_helper<long>(*this, ok, base);
-}
-
-long QByteArrayView::toLong(bool *ok, int base) const
-{
- return toIntegral_helper<long>(*this, ok, base);
+ return QtPrivate::toIntegral<long>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3736,8 +3934,9 @@ long QByteArrayView::toLong(bool *ok, int base) const
If \a base is 0, the base is determined automatically using the following
rules: If the byte array begins with "0x", it is assumed to be hexadecimal
- (base 16); otherwise, if it begins with "0", it is assumed to be octal (base
- 8); otherwise it is assumed to be decimal.
+ (base 16); otherwise, if it begins with "0b", it is assumed to be binary
+ (base 2); otherwise, if it begins with "0", it is assumed to be octal
+ (base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@@ -3748,16 +3947,13 @@ long QByteArrayView::toLong(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number()
*/
ulong QByteArray::toULong(bool *ok, int base) const
{
- return toIntegral_helper<ulong>(*this, ok, base);
-}
-
-ulong QByteArrayView::toULong(bool *ok, int base) const
-{
- return toIntegral_helper<ulong>(*this, ok, base);
+ return QtPrivate::toIntegral<ulong>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3766,9 +3962,10 @@ ulong QByteArrayView::toULong(bool *ok, int base) const
digits beyond 9; A is ten, B is eleven and so on.
If \a base is 0, the base is determined automatically using the following
- rules: If the byte array begins with "0x", it is assumed to be hexadecimal;
- otherwise, if it begins with "0", it is assumed to be octal; otherwise it is
- assumed to be decimal.
+ rules: If the byte array begins with "0x", it is assumed to be hexadecimal
+ (base 16); otherwise, if it begins with "0b", it is assumed to be binary
+ (base 2); otherwise, if it begins with "0", it is assumed to be octal
+ (base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@@ -3779,17 +3976,14 @@ ulong QByteArrayView::toULong(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number()
*/
short QByteArray::toShort(bool *ok, int base) const
{
- return toIntegral_helper<short>(*this, ok, base);
-}
-
-short QByteArrayView::toShort(bool *ok, int base) const
-{
- return toIntegral_helper<short>(*this, ok, base);
+ return QtPrivate::toIntegral<short>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3798,9 +3992,10 @@ short QByteArrayView::toShort(bool *ok, int base) const
letters for digits beyond 9; A is ten, B is eleven and so on.
If \a base is 0, the base is determined automatically using the following
- rules: If the byte array begins with "0x", it is assumed to be hexadecimal;
- otherwise, if it begins with "0", it is assumed to be octal; otherwise it is
- assumed to be decimal.
+ rules: If the byte array begins with "0x", it is assumed to be hexadecimal
+ (base 16); otherwise, if it begins with "0b", it is assumed to be binary
+ (base 2); otherwise, if it begins with "0", it is assumed to be octal
+ (base 8); otherwise it is assumed to be decimal.
Returns 0 if the conversion fails.
@@ -3811,17 +4006,14 @@ short QByteArrayView::toShort(bool *ok, int base) const
regardless of the user's locale. Use QLocale to perform locale-aware
conversions between numbers and strings.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number()
*/
ushort QByteArray::toUShort(bool *ok, int base) const
{
- return toIntegral_helper<ushort>(*this, ok, base);
-}
-
-ushort QByteArrayView::toUShort(bool *ok, int base) const
-{
- return toIntegral_helper<ushort>(*this, ok, base);
+ return QtPrivate::toIntegral<ushort>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3854,14 +4046,13 @@ double QByteArray::toDouble(bool *ok) const
return QByteArrayView(*this).toDouble(ok);
}
-double QByteArrayView::toDouble(bool *ok) const
+auto QtPrivate::toDouble(QByteArrayView a) noexcept -> ParsedNumber<double>
{
- bool nonNullOk = false;
- int processed = 0;
- double d = qt_asciiToDouble(data(), size(), nonNullOk, processed, WhitespacesAllowed);
- if (ok)
- *ok = nonNullOk;
- return d;
+ auto r = qt_asciiToDouble(a.data(), a.size(), WhitespacesAllowed);
+ if (r.ok())
+ return ParsedNumber{r.result};
+ else
+ return {};
}
/*!
@@ -3894,9 +4085,15 @@ float QByteArray::toFloat(bool *ok) const
return QLocaleData::convertDoubleToFloat(toDouble(ok), ok);
}
-float QByteArrayView::toFloat(bool *ok) const
+auto QtPrivate::toFloat(QByteArrayView a) noexcept -> ParsedNumber<float>
{
- return QLocaleData::convertDoubleToFloat(toDouble(ok), ok);
+ if (const auto r = toDouble(a)) {
+ bool ok = true;
+ const auto f = QLocaleData::convertDoubleToFloat(*r, &ok);
+ if (ok)
+ return ParsedNumber(f);
+ }
+ return {};
}
/*!
@@ -3912,27 +4109,29 @@ float QByteArrayView::toFloat(bool *ok) const
*/
QByteArray QByteArray::toBase64(Base64Options options) const
{
- const char alphabet_base64[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
- "ghijklmn" "opqrstuv" "wxyz0123" "456789+/";
- const char alphabet_base64url[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
- "ghijklmn" "opqrstuv" "wxyz0123" "456789-_";
+ constexpr char alphabet_base64[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
+ "ghijklmn" "opqrstuv" "wxyz0123" "456789+/";
+ constexpr char alphabet_base64url[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
+ "ghijklmn" "opqrstuv" "wxyz0123" "456789-_";
const char *const alphabet = options & Base64UrlEncoding ? alphabet_base64url : alphabet_base64;
- const char padchar = '=';
+ constexpr char padchar = '=';
qsizetype padlen = 0;
- QByteArray tmp((size() + 2) / 3 * 4, Qt::Uninitialized);
+ const qsizetype sz = size();
+
+ QByteArray tmp((sz + 2) / 3 * 4, Qt::Uninitialized);
qsizetype i = 0;
char *out = tmp.data();
- while (i < size()) {
+ while (i < sz) {
// encode 3 bytes at a time
int chunk = 0;
chunk |= int(uchar(data()[i++])) << 16;
- if (i == size()) {
+ if (i == sz) {
padlen = 2;
} else {
chunk |= int(uchar(data()[i++])) << 8;
- if (i == size())
+ if (i == sz)
padlen = 1;
else
chunk |= int(uchar(data()[i++]));
@@ -4027,7 +4226,7 @@ static char *qulltoa2(char *p, qulonglong n, int base)
base = 10;
}
#endif
- const char b = 'a' - 10;
+ constexpr char b = 'a' - 10;
do {
const int c = n % base;
n /= base;
@@ -4044,7 +4243,7 @@ static char *qulltoa2(char *p, qulonglong n, int base)
*/
QByteArray &QByteArray::setNum(qlonglong n, int base)
{
- const int buffsize = 66; // big enough for MAX_ULLONG in base 2
+ constexpr int buffsize = 66; // big enough for MAX_ULLONG in base 2
char buff[buffsize];
char *p;
@@ -4069,7 +4268,7 @@ QByteArray &QByteArray::setNum(qlonglong n, int base)
QByteArray &QByteArray::setNum(qulonglong n, int base)
{
- const int buffsize = 66; // big enough for MAX_ULLONG in base 2
+ constexpr int buffsize = 66; // big enough for MAX_ULLONG in base 2
char buff[buffsize];
char *p = qulltoa2(buff + buffsize, n, base);
@@ -4207,7 +4406,7 @@ QByteArray QByteArray::number(double n, char format, int precision)
{
QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
- switch (asciiLower(format)) {
+ switch (QtMiscUtils::toAsciiLower(format)) {
case 'f':
form = QLocaleData::DFDecimal;
break;
@@ -4397,7 +4596,7 @@ QByteArray::FromBase64Result QByteArray::fromBase64Encoding(QByteArray &&base64,
base64.size(),
base64.data(), // in-place
options);
- base64.truncate(int(base64result.decodedLength));
+ base64.truncate(base64result.decodedLength);
return { std::move(base64), base64result.status };
}
@@ -4413,7 +4612,7 @@ QByteArray::FromBase64Result QByteArray::fromBase64Encoding(const QByteArray &ba
base64Size,
const_cast<char *>(result.constData()),
options);
- result.truncate(int(base64result.decodedLength));
+ result.truncate(base64result.decodedLength);
return { std::move(result), base64result.status };
}
@@ -4526,7 +4725,7 @@ static void q_fromPercentEncoding(QByteArray *ba, char percent)
const char *inputPtr = data;
qsizetype i = 0;
- qsizetype len = ba->count();
+ qsizetype len = ba->size();
qsizetype outlen = 0;
int a, b;
char c;
@@ -4557,20 +4756,17 @@ static void q_fromPercentEncoding(QByteArray *ba, char percent)
ba->truncate(outlen);
}
-void q_fromPercentEncoding(QByteArray *ba)
-{
- q_fromPercentEncoding(ba, '%');
-}
-
/*!
- \since 4.4
+ \since 6.4
- Returns a decoded copy of the URI/URL-style percent-encoded \a input.
- The \a percent parameter allows you to replace the '%' character for
- another (for instance, '_' or '=').
+ Decodes URI/URL-style percent-encoding.
+
+ Returns a byte array containing the decoded text. The \a percent parameter
+ allows use of a different character than '%' (for instance, '_' or '=') as
+ the escape character.
For example:
- \snippet code/src_corelib_text_qbytearray.cpp 51
+ \snippet code/src_corelib_text_qbytearray.cpp 54
\note Given invalid input (such as a string containing the sequence "%G5",
which is not a valid hexadecimal number) the output will be invalid as
@@ -4578,18 +4774,35 @@ void q_fromPercentEncoding(QByteArray *ba)
\sa toPercentEncoding(), QUrl::fromPercentEncoding()
*/
-QByteArray QByteArray::fromPercentEncoding(const QByteArray &input, char percent)
+QByteArray QByteArray::percentDecoded(char percent) const
{
- if (input.isNull())
- return QByteArray(); // preserve null
- if (input.isEmpty())
- return QByteArray(input.data(), 0);
+ if (isEmpty())
+ return *this; // Preserves isNull().
- QByteArray tmp = input;
+ QByteArray tmp = *this;
q_fromPercentEncoding(&tmp, percent);
return tmp;
}
+/*!
+ \since 4.4
+
+ Decodes \a input from URI/URL-style percent-encoding.
+
+ Returns a byte array containing the decoded text. The \a percent parameter
+ allows use of a different character than '%' (for instance, '_' or '=') as
+ the escape character. Equivalent to input.percentDecoded(percent).
+
+ For example:
+ \snippet code/src_corelib_text_qbytearray.cpp 51
+
+ \sa percentDecoded()
+*/
+QByteArray QByteArray::fromPercentEncoding(const QByteArray &input, char percent)
+{
+ return input.percentDecoded(percent);
+}
+
/*! \fn QByteArray QByteArray::fromStdString(const std::string &str)
\since 5.4
@@ -4597,6 +4810,10 @@ QByteArray QByteArray::fromPercentEncoding(const QByteArray &input, char percent
\sa toStdString(), QString::fromStdString()
*/
+QByteArray QByteArray::fromStdString(const std::string &s)
+{
+ return QByteArray(s.data(), qsizetype(s.size()));
+}
/*!
\fn std::string QByteArray::toStdString() const
@@ -4610,68 +4827,9 @@ QByteArray QByteArray::fromPercentEncoding(const QByteArray &input, char percent
\sa fromStdString(), QString::toStdString()
*/
-
-static inline bool q_strchr(const char str[], char chr)
+std::string QByteArray::toStdString() const
{
- if (!str) return false;
-
- const char *ptr = str;
- char c;
- while ((c = *ptr++))
- if (c == chr)
- return true;
- return false;
-}
-
-static void q_toPercentEncoding(QByteArray *ba, const char *dontEncode, const char *alsoEncode, char percent)
-{
- if (ba->isEmpty())
- return;
-
- QByteArray input = *ba;
- qsizetype len = input.count();
- const char *inputData = input.constData();
- char *output = nullptr;
- qsizetype length = 0;
-
- for (qsizetype i = 0; i < len; ++i) {
- unsigned char c = *inputData++;
- if (((c >= 0x61 && c <= 0x7A) // ALPHA
- || (c >= 0x41 && c <= 0x5A) // ALPHA
- || (c >= 0x30 && c <= 0x39) // DIGIT
- || c == 0x2D // -
- || c == 0x2E // .
- || c == 0x5F // _
- || c == 0x7E // ~
- || q_strchr(dontEncode, c))
- && !q_strchr(alsoEncode, c)) {
- if (output)
- output[length] = c;
- ++length;
- } else {
- if (!output) {
- // detach now
- ba->resize(len*3); // worst case
- output = ba->data();
- }
- output[length++] = percent;
- output[length++] = QtMiscUtils::toHexUpper((c & 0xf0) >> 4);
- output[length++] = QtMiscUtils::toHexUpper(c & 0xf);
- }
- }
- if (output)
- ba->truncate(length);
-}
-
-void q_toPercentEncoding(QByteArray *ba, const char *exclude, const char *include)
-{
- q_toPercentEncoding(ba, exclude, include, '%');
-}
-
-void q_normalizePercentEncoding(QByteArray *ba, const char *exclude)
-{
- q_fromPercentEncoding(ba, '%');
- q_toPercentEncoding(ba, exclude, nullptr, '%');
+ return std::string(data(), size_t(size()));
}
/*!
@@ -4706,23 +4864,100 @@ QByteArray QByteArray::toPercentEncoding(const QByteArray &exclude, const QByteA
if (isEmpty())
return QByteArray(data(), 0);
- QByteArray include2 = include;
- if (percent != '%') // the default
- if ((percent >= 0x61 && percent <= 0x7A) // ALPHA
- || (percent >= 0x41 && percent <= 0x5A) // ALPHA
- || (percent >= 0x30 && percent <= 0x39) // DIGIT
- || percent == 0x2D // -
- || percent == 0x2E // .
- || percent == 0x5F // _
- || percent == 0x7E) // ~
- include2 += percent;
+ const auto contains = [](const QByteArray &view, char c) {
+ // As view.contains(c), but optimised to bypass a lot of overhead:
+ return view.size() > 0 && memchr(view.data(), c, view.size()) != nullptr;
+ };
QByteArray result = *this;
- q_toPercentEncoding(&result, exclude.nulTerminated().constData(), include2.nulTerminated().constData(), percent);
+ char *output = nullptr;
+ qsizetype length = 0;
+
+ for (unsigned char c : *this) {
+ if (char(c) != percent
+ && ((c >= 0x61 && c <= 0x7A) // ALPHA
+ || (c >= 0x41 && c <= 0x5A) // ALPHA
+ || (c >= 0x30 && c <= 0x39) // DIGIT
+ || c == 0x2D // -
+ || c == 0x2E // .
+ || c == 0x5F // _
+ || c == 0x7E // ~
+ || contains(exclude, c))
+ && !contains(include, c)) {
+ if (output)
+ output[length] = c;
+ ++length;
+ } else {
+ if (!output) {
+ // detach now
+ result.resize(size() * 3); // worst case
+ output = result.data();
+ }
+ output[length++] = percent;
+ output[length++] = QtMiscUtils::toHexUpper((c & 0xf0) >> 4);
+ output[length++] = QtMiscUtils::toHexUpper(c & 0xf);
+ }
+ }
+ if (output)
+ result.truncate(length);
return result;
}
+#if defined(Q_OS_WASM) || defined(Q_QDOC)
+
+/*!
+ Constructs a new QByteArray containing a copy of the Uint8Array \a uint8array.
+
+ This function transfers data from a JavaScript data buffer - which
+ is not addressable from C++ code - to heap memory owned by a QByteArray.
+ The Uint8Array can be released once this function returns and a copy
+ has been made.
+
+ The \a uint8array argument must an emscripten::val referencing an Uint8Array
+ object, e.g. obtained from a global JavaScript variable:
+
+ \snippet code/src_corelib_text_qbytearray.cpp 55
+
+ This function returns a null QByteArray if the size of the Uint8Array
+ exceeds the maximum capacity of QByteArray, or if the \a uint8array
+ argument is not of the Uint8Array type.
+
+ \since 6.5
+ \ingroup platform-type-conversions
+
+ \sa toEcmaUint8Array()
+*/
+
+QByteArray QByteArray::fromEcmaUint8Array(emscripten::val uint8array)
+{
+ return qstdweb::Uint8Array(uint8array).copyToQByteArray();
+}
+
+/*!
+ Creates a Uint8Array from a QByteArray.
+
+ This function transfers data from heap memory owned by a QByteArray
+ to a JavaScript data buffer. The function allocates and copies into an
+ ArrayBuffer, and returns a Uint8Array view to that buffer.
+
+ The JavaScript objects own a copy of the data, and this
+ QByteArray can be safely deleted after the copy has been made.
+
+ \snippet code/src_corelib_text_qbytearray.cpp 56
+
+ \since 6.5
+ \ingroup platform-type-conversions
+
+ \sa toEcmaUint8Array()
+*/
+emscripten::val QByteArray::toEcmaUint8Array()
+{
+ return qstdweb::Uint8Array::copyFrom(*this).val();
+}
+
+#endif
+
/*! \typedef QByteArray::ConstIterator
\internal
*/
@@ -4819,11 +5054,13 @@ QByteArray QByteArray::toPercentEncoding(const QByteArray &exclude, const QByteA
\sa QStringLiteral
*/
+#if QT_DEPRECATED_SINCE(6, 8)
/*!
\fn QtLiterals::operator""_qba(const char *str, size_t size)
\relates QByteArray
\since 6.2
+ \deprecated [6.8] Use \c _ba from Qt::StringLiterals namespace instead.
Literal operator that creates a QByteArray out of the first \a size characters
in the char string literal \a str.
@@ -4841,6 +5078,32 @@ QByteArray QByteArray::toPercentEncoding(const QByteArray &exclude, const QByteA
\sa QByteArrayLiteral, QtLiterals::operator""_qs(const char16_t *str, size_t size)
*/
+#endif // QT_DEPRECATED_SINCE(6, 8)
+
+/*!
+ \fn Qt::Literals::StringLiterals::operator""_ba(const char *str, size_t size)
+
+ \relates QByteArray
+ \since 6.4
+
+ Literal operator that creates a QByteArray out of the first \a size characters
+ in the char string literal \a str.
+
+ The QByteArray is created at compile time, and the generated string data is stored
+ in the read-only segment of the compiled object file. Duplicate literals may share
+ the same read-only memory. This functionality is interchangeable with
+ QByteArrayLiteral, but saves typing when many string literals are present in the
+ code.
+
+ The following code creates a QByteArray:
+ \code
+ using namespace Qt::Literals::StringLiterals;
+
+ auto str = "hello"_ba;
+ \endcode
+
+ \sa Qt::Literals::StringLiterals
+*/
/*!
\class QByteArray::FromBase64Result
@@ -4943,3 +5206,5 @@ size_t qHash(const QByteArray::FromBase64Result &key, size_t seed) noexcept
*/
QT_END_NAMESPACE
+
+#undef REHASH