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.cpp2285
1 files changed, 1365 insertions, 920 deletions
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index 46902bdec8..e6387e4bed 100644
--- a/src/corelib/text/qbytearray.cpp
+++ b/src/corelib/text/qbytearray.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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,30 +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>
-QT_BEGIN_NAMESPACE
+#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
-template <typename T, typename Cmp = std::less<>>
-static constexpr bool points_into_range(const T *p, const T *b, const T *e, Cmp less = {}) noexcept
-{
- return !less(p, b) && less(p, e);
-}
+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)
@@ -149,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)
@@ -212,7 +181,8 @@ char *qstrncpy(char *dst, const char *src, size_t len)
\nullptr, it is treated as less than the other (even if the other is an
empty string).
- \sa qstrncmp(), qstricmp(), qstrnicmp(), {Character Case}, QByteArray::compare()
+ \sa qstrncmp(), qstricmp(), qstrnicmp(), {Character Case},
+ QByteArray::compare()
*/
int qstrcmp(const char *str1, const char *str2)
{
@@ -236,7 +206,8 @@ int qstrcmp(const char *str1, const char *str2)
\nullptr, it is treated as less than the other (even if the other is an
empty string or \a len is 0).
- \sa qstrcmp(), qstricmp(), qstrnicmp(), {Character Case}, QByteArray::compare()
+ \sa qstrcmp(), qstricmp(), qstrnicmp(), {Character Case},
+ QByteArray::compare()
*/
/*! \relates QByteArray
@@ -254,7 +225,8 @@ int qstrcmp(const char *str1, const char *str2)
\nullptr, it is treated as less than the other (even if the other is an
empty string).
- \sa qstrcmp(), qstrncmp(), qstrnicmp(), {Character Case}, QByteArray::compare()
+ \sa qstrcmp(), qstrncmp(), qstrnicmp(), {Character Case},
+ QByteArray::compare()
*/
int qstricmp(const char *str1, const char *str2)
@@ -272,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;
@@ -298,7 +270,7 @@ int qstricmp(const char *str1, const char *str2)
__m128i a = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s1 + offset));
__m128i b = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s2 + offset));
- // compare the two against each oher
+ // compare the two against each other
__m128i cmp = _mm_cmpeq_epi8(a, b);
// find NUL terminators too
@@ -311,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;
@@ -343,7 +315,8 @@ int qstricmp(const char *str1, const char *str2)
\nullptr, it is treated as less than the other (even if the other is an
empty string or \a len is 0).
- \sa qstrcmp(), qstrncmp(), qstricmp(), {Character Case}, QByteArray::compare()
+ \sa qstrcmp(), qstrncmp(), qstricmp(), {Character Case},
+ QByteArray::compare()
*/
int qstrnicmp(const char *str1, const char *str2, size_t len)
@@ -354,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;
@@ -395,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;
@@ -403,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)
@@ -428,6 +401,14 @@ int QtPrivate::compareMemory(QByteArrayView lhs, QByteArrayView rhs)
return lhs.size() == rhs.size() ? 0 : lhs.size() > rhs.size() ? 1 : -1;
}
+/*!
+ \internal
+*/
+bool QtPrivate::isValidUtf8(QByteArrayView s) noexcept
+{
+ return QUtf8::isValidUtf8(s).isValidUtf8;
+}
+
// the CRC table below is created by the following piece of code
#if 0
static void createCRC16Table() // build CRC16 lookup table
@@ -532,10 +513,12 @@ quint16 qChecksum(QByteArrayView data, Qt::ChecksumType standard)
The default value is -1, which specifies zlib's default
compression.
- \sa qUncompress()
+ \sa qUncompress(const QByteArray &data)
*/
-/*! \relates QByteArray
+/*!
+ \fn QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
+ \relates QByteArray
\overload
@@ -544,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
@@ -603,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
@@ -624,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);
- QByteArray::DataPointer d(QByteArray::Data::allocate(len));
- if (Q_UNLIKELY(d.data() == nullptr))
+ if (nbytes < 0)
+ return lengthIsNegative(ZLibOp::Decompression);
+
+ 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, QByteArray::Data::GrowsForward);
- 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
@@ -696,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
@@ -743,7 +864,7 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
at() can be faster than operator[](), because it never causes a
\l{deep copy} to occur.
- To extract many bytes at a time, use left(), right(), or mid().
+ To extract many bytes at a time, use first(), last(), or sliced().
A QByteArray can embed '\\0' bytes. The size() function always
returns the size of the whole array, including embedded '\\0'
@@ -772,16 +893,48 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
\snippet code/src_corelib_text_qbytearray.cpp 3
- The replace() and remove() functions' first two arguments are the
- position from which to start erasing and the number of bytes that
- should be erased.
+ In the above example the replace() function's first two arguments are the
+ position from which to start replacing and the number of bytes that
+ should be replaced.
- When you append() data to a non-empty array, the array will be
- reallocated and the new data copied to it. You can avoid this
- behavior by calling reserve(), which preallocates a certain amount
+ When data-modifying functions increase the size of the array,
+ they may lead to reallocation of memory for the QByteArray object. When
+ this happens, QByteArray expands by more than it immediately needs so as
+ to have space for further expansion without reallocation until the size
+ of the array has greatly increased.
+
+ The insert(), remove() and, when replacing a sub-array with one of
+ different size, replace() functions can be slow (\l{linear time}) for
+ large arrays, because they require moving many bytes in the array by
+ at least one position in memory.
+
+ If you are building a QByteArray gradually and know in advance
+ approximately how many bytes the QByteArray will contain, you
+ can call reserve(), asking QByteArray to preallocate a certain amount
of memory. You can also call capacity() to find out how much
- memory QByteArray actually allocated. Data appended to an empty
- array is not copied.
+ memory the QByteArray actually has allocated.
+
+ Note that using non-const operators and functions can cause
+ QByteArray to do a deep copy of the data, due to \l{implicit sharing}.
+
+ QByteArray provides \l{STL-style iterators} (QByteArray::const_iterator and
+ QByteArray::iterator). In practice, iterators are handy when working with
+ generic algorithms provided by the C++ standard library.
+
+ \note Iterators and references to individual QByteArray elements are subject
+ to stability issues. They are often invalidated when a QByteArray-modifying
+ operation (e.g. insert() or remove()) is called. When stability and
+ iterator-like functionality is required, you should use indexes instead of
+ iterators as they are not tied to QByteArray's internal state and thus do
+ not get invalidated.
+
+ \note Iterators over a QByteArray, and references to individual bytes
+ within one, cannot be relied on to remain valid when any non-const method
+ of the QByteArray is called. Accessing such an iterator or reference after
+ the call to a non-const method leads to undefined behavior. When stability
+ for iterator-like functionality is required, you should use indexes instead
+ of iterators as they are not tied to QByteArray's internal state and thus do
+ not get invalidated.
If you want to find all occurrences of a particular byte or sequence of
bytes in a QByteArray, use indexOf() or lastIndexOf(). The former searches
@@ -823,9 +976,19 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
\section1 Maximum size and out-of-memory conditions
- In case memory allocation fails, QByteArray will throw a \c std::bad_alloc
- exception. Out of memory conditions in the Qt containers are the only case
- where Qt will throw exceptions.
+ The maximum size of QByteArray depends on the architecture. Most 64-bit
+ systems can allocate more than 2 GB of memory, with a typical limit
+ of 2^63 bytes. The actual value also depends on the overhead required for
+ managing the data block. As a result, you can expect the maximum size
+ of 2 GB minus overhead on 32-bit platforms, and 2^63 bytes minus overhead
+ on 64-bit platforms. The number of elements that can be stored in a
+ QByteArray is this maximum size.
+
+ When memory allocation fails, QByteArray throws a \c std::bad_alloc
+ exception if the application is being compiled with exception support.
+ Out of memory conditions in Qt containers are the only case where Qt
+ will throw exceptions. If exceptions are disabled, then running out of
+ memory is undefined behavior.
Note that the operating system may impose further limits on applications
holding a lot of allocated memory, especially large, contiguous blocks.
@@ -848,14 +1011,6 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
such a pointer, without a length, will interpret it as this sequence of
bytes. Such a sequence, by construction, cannot contain a '\\0' byte.
- Take care when passing fixed size C arrays to QByteArray methods that accept
- a QByteArrayView: the length of the data on which the method will operate is
- determined by array size. A \c{char [N]} array will be handled as a view of
- size \c{N-1}, on the expectation that the array is a string literal with a '\\0'
- at index \c{N-1}. For example:
-
- \snippet code/src_corelib_text_qbytearray.cpp 54
-
Other overloads accept a start-pointer and a byte-count; these use the given
number of bytes, following the start address, regardless of whether any of
them happen to be '\\0' bytes. In some cases, where there is no overload
@@ -867,17 +1022,18 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
\section2 Spacing Characters
A frequent requirement is to remove spacing characters from a byte array
- ('\\n', '\\t', ' ', etc.). If you want to remove spacing from both ends of a
- QByteArray, use trimmed(). If you want to also replace each run of spacing
- characters with a single space character within the byte array, use
+ (\c{'\n'}, \c{'\t'}, \c{' '}, etc.). If you want to remove spacing from both
+ ends of a QByteArray, use trimmed(). If you want to also replace each run of
+ spacing characters with a single space character within the byte array, use
simplified(). Only ASCII spacing characters are recognized for these
purposes.
\section2 Number-String Conversions
- Functions that perform conversions between numeric data types and strings
- are performed in the C locale, regardless of the user's locale settings. Use
- QLocale to perform locale-aware conversions between numbers and strings.
+ Functions that perform conversions between numeric data types and string
+ representations are performed in the C locale, regardless of the user's
+ locale settings. Use QLocale to perform locale-aware conversions between
+ numbers and strings.
\section2 Character Case
@@ -885,13 +1041,13 @@ 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.
- \sa QByteArrayView, QString, QBitArray
+ \sa QByteArrayView, QString, QBitArray
*/
/*!
@@ -1003,8 +1159,8 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
/*! \fn QByteArray::reverse_iterator QByteArray::rbegin()
\since 5.6
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- byte in the byte-array, in reverse order.
+ Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to
+ the first byte in the byte-array, in reverse order.
\include qbytearray.cpp iterator-invalidation-func-desc
@@ -1019,8 +1175,8 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
/*! \fn QByteArray::const_reverse_iterator QByteArray::crbegin() const
\since 5.6
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- byte in the byte-array, in reverse order.
+ Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing
+ to the first byte in the byte-array, in reverse order.
\include qbytearray.cpp iterator-invalidation-func-desc
@@ -1030,8 +1186,8 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
/*! \fn QByteArray::reverse_iterator QByteArray::rend()
\since 5.6
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
- the last byte in the byte-array, in reverse order.
+ Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing just
+ after the last byte in the byte-array, in reverse order.
\include qbytearray.cpp iterator-invalidation-func-desc
@@ -1046,8 +1202,8 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
/*! \fn QByteArray::const_reverse_iterator QByteArray::crend() const
\since 5.6
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to one
- past the last byte in the byte-array, in reverse order.
+ Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing
+ just after the last byte in the byte-array, in reverse order.
\include qbytearray.cpp iterator-invalidation-func-desc
@@ -1115,6 +1271,37 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
squeeze().
*/
+/*!
+ \since 6.1
+
+ Removes from the byte array the characters in the half-open range
+ [ \a first , \a last ). Returns an iterator to the character
+ referred to by \a last before the erase.
+*/
+QByteArray::iterator QByteArray::erase(QByteArray::const_iterator first, QByteArray::const_iterator last)
+{
+ const auto start = std::distance(cbegin(), first);
+ const auto len = std::distance(first, last);
+ remove(start, len);
+ 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.
@@ -1162,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)
@@ -1171,13 +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() || size_t(len) > capacityAtEnd
- || (len < size() && size_t(len) < (capacityAtEnd >> 1)))
- reallocData(len, d->detachFlags());
- memcpy(d.data(), str, len + 1); // include null terminator
- d.size = len;
+ assign(str);
}
return *this;
}
@@ -1206,7 +1390,7 @@ QByteArray &QByteArray::operator=(const char *str)
you can use the return value of data() and constData() as arguments to
functions that expect '\\0'-terminated strings. If the QByteArray object was
created from a \l{fromRawData()}{raw data} that didn't include the trailing
- '\\0'-termination byte, then QByteArray doesn't add it automaticall unless a
+ '\\0'-termination byte, then QByteArray doesn't add it automatically unless a
\l{deep copy} is created.
Example:
@@ -1215,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.
@@ -1247,16 +1440,27 @@ QByteArray &QByteArray::operator=(const char *str)
/*! \fn void QByteArray::reserve(qsizetype size)
- Attempts to allocate memory for at least \a size bytes. If you
- know in advance how large the byte array will be, you can call
+ Attempts to allocate memory for at least \a size bytes.
+
+ If you know in advance how large the byte array will be, you can call
this function, and if you call resize() often you are likely to
- get better performance. If \a size is an underestimate, the worst
- that will happen is that the QByteArray will be a bit slower.
+ get better performance.
+
+ If in doubt about how much space shall be needed, it is usually better to
+ use an upper bound as \a size, or a high estimate of the most likely size,
+ if a strict upper bound would be much bigger than this. If \a size is an
+ underestimate, the array will grow as needed once the reserved size is
+ exceeded, which may lead to a larger allocation than your best overestimate
+ would have and will slow the operation that triggers it.
+
+ \warning reserve() reserves memory but does not change the size of the byte
+ array. Accessing data beyond the end of the byte array is undefined
+ behavior. If you need to access memory beyond the current end of the array,
+ use resize().
The sole purpose of this function is to provide a means of fine
tuning QByteArray's memory usage. In general, you will rarely
- ever need to call this function. If you want to change the size
- of the byte array, call resize().
+ ever need to call this function.
\sa squeeze(), capacity()
*/
@@ -1275,7 +1479,7 @@ QByteArray &QByteArray::operator=(const char *str)
/*! \fn QByteArray::operator const char *() const
\fn QByteArray::operator const void *() const
- \obsolete Use constData() instead.
+ \note Use constData() instead in new code.
Returns a pointer to the data stored in the byte array. The
pointer can be used to access the bytes that compose the array.
@@ -1351,8 +1555,8 @@ QByteArray &QByteArray::operator=(const char *str)
/*! \fn const char *QByteArray::constData() const
- Returns a pointer to the data stored in the byte array. The pointer can be
- used to access the bytes that compose the array. The data is
+ Returns a pointer to the const data stored in the byte array. The pointer
+ can be used to access the bytes that compose the array. The data is
'\\0'-terminated unless the QByteArray object was created from raw data.
\include qbytearray.cpp pointer-invalidation-desc
@@ -1498,7 +1702,7 @@ QByteArray &QByteArray::operator=(const char *str)
Example:
\snippet code/src_corelib_text_qbytearray.cpp 10
- \sa chop(), resize(), left()
+ \sa chop(), resize(), first()
*/
void QByteArray::truncate(qsizetype pos)
{
@@ -1516,7 +1720,7 @@ void QByteArray::truncate(qsizetype pos)
Example:
\snippet code/src_corelib_text_qbytearray.cpp 11
- \sa truncate(), resize(), left()
+ \sa truncate(), resize(), first()
*/
void QByteArray::chop(qsizetype n)
@@ -1617,7 +1821,8 @@ 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';
}
@@ -1635,15 +1840,14 @@ 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';
}
}
/*!
- \internal
-
Constructs a byte array of size \a size with uninitialized contents.
*/
@@ -1652,7 +1856,8 @@ 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';
}
}
@@ -1664,10 +1869,13 @@ QByteArray::QByteArray(qsizetype size, Qt::Initialization)
extended to make it \a size bytes with the extra bytes added to
the end. The new bytes are uninitialized.
- If \a size is less than the current size, bytes are removed from
- the end.
+ If \a size is less than the current size, bytes beyond position
+ \a size 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()
+ \sa size(), truncate(), squeeze()
*/
void QByteArray::resize(qsizetype size)
{
@@ -1676,13 +1884,53 @@ void QByteArray::resize(qsizetype size)
const auto capacityAtEnd = capacity() - d.freeSpaceAtBegin();
if (d->needsDetach() || size > capacityAtEnd)
- reallocData(size, d->detachFlags() | Data::GrowsForward);
+ reallocData(size, QArrayData::Grow);
d.size = size;
if (d->allocatedCapacity())
d.data()[size] = 0;
}
/*!
+ \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.
@@ -1700,42 +1948,42 @@ QByteArray &QByteArray::fill(char ch, qsizetype size)
return *this;
}
-void QByteArray::reallocData(qsizetype alloc, Data::ArrayOptions options)
+void QByteArray::reallocData(qsizetype alloc, QArrayData::AllocationOption option)
{
if (!alloc) {
d = DataPointer::fromRawData(&_empty, 0);
return;
}
- // there's a case of slow reallocate path where we need to memmove the data
- // before a call to ::realloc(), meaning that there's an extra "heavy"
- // operation. just prefer ::malloc() branch in this case
- const bool slowReallocatePath = d.freeSpaceAtBegin() > 0;
+ // don't use reallocate path when reducing capacity and there's free space
+ // at the beginning: might shift data pointer outside of allocated space
+ const bool cannotUseReallocate = d.freeSpaceAtBegin() > 0;
- if (d->needsDetach() || slowReallocatePath) {
- DataPointer dd(Data::allocate(alloc, options), qMin(alloc, d.size));
+ if (d->needsDetach() || cannotUseReallocate) {
+ DataPointer dd(alloc, qMin(alloc, d.size), option);
+ Q_CHECK_PTR(dd.data());
if (dd.size > 0)
::memcpy(dd.data(), d.data(), dd.size);
dd.data()[dd.size] = 0;
d = dd;
} else {
- d->reallocate(alloc, options);
+ d->reallocate(alloc, option);
}
}
-void QByteArray::reallocGrowData(qsizetype alloc, Data::ArrayOptions options)
+void QByteArray::reallocGrowData(qsizetype n)
{
- if (!alloc) // expected to always allocate
- alloc = 1;
+ if (!n) // expected to always allocate
+ n = 1;
if (d->needsDetach()) {
- const auto newSize = qMin(alloc, d.size);
- DataPointer dd(DataPointer::allocateGrow(d, alloc, newSize, options));
- dd->copyAppend(d.data(), d.data() + newSize);
+ DataPointer dd(DataPointer::allocateGrow(d, n, QArrayData::GrowsAtEnd));
+ Q_CHECK_PTR(dd.data());
+ dd->copyAppend(d.data(), d.data() + d.size);
dd.data()[dd.size] = 0;
d = dd;
} else {
- d->reallocate(alloc, options);
+ d->reallocate(d.constAllocatedCapacity() + n, QArrayData::Grow);
}
}
@@ -1745,31 +1993,15 @@ 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
reference to this byte array.
+ This operation is typically very fast (\l{constant time}), because
+ QByteArray preallocates extra space at the beginning of the data,
+ so it can grow without reallocating the entire array each time.
+
Example:
\snippet code/src_corelib_text_qbytearray.cpp 15
@@ -1784,6 +2016,12 @@ QByteArray QByteArray::nulTerminated() const
Prepends \a ba to this byte array.
*/
+QByteArray &QByteArray::prepend(const QByteArray &ba)
+{
+ if (size() == 0 && ba.size() > d.constAllocatedCapacity() && ba.d.isMutable())
+ return (*this = ba);
+ return prepend(QByteArrayView(ba));
+}
/*!
\fn QByteArray &QByteArray::prepend(const char *str)
@@ -1833,18 +2071,26 @@ QByteArray QByteArray::nulTerminated() const
If the byte array being appended to is not empty, a deep copy of the
data is performed, taking \l{linear time}.
- This operation typically does not suffer from allocation overhead,
- because QByteArray preallocates extra space at the end of the data
- so that it may grow without reallocating for each append operation.
+ The append() function is typically very fast (\l{constant time}),
+ because QByteArray preallocates extra space at the end of the data,
+ so it can grow without reallocating the entire array each time.
\sa operator+=(), prepend(), insert()
*/
QByteArray &QByteArray::append(const QByteArray &ba)
{
- if (size() == 0 && 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;
}
/*!
@@ -1896,15 +2142,80 @@ QByteArray &QByteArray::append(const QByteArray &ba)
QByteArray& QByteArray::append(char ch)
{
- const bool shouldGrow = d->shouldGrowBeforeInsert(d.end(), 1);
- if (d->needsDetach() || size() + 1 > capacity() || shouldGrow)
- reallocGrowData(size() + 1, d->detachFlags() | Data::GrowsForward);
+ d.detachAndGrow(QArrayData::GrowsAtEnd, 1, nullptr, nullptr);
d->copyAppend(1, ch);
d.data()[d.size] = '\0';
return *this;
}
/*!
+ \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.
@@ -1912,41 +2223,73 @@ QByteArray& QByteArray::append(char ch)
\snippet code/src_corelib_text_qbytearray.cpp 17
\since 6.0
+ For large byte arrays, this operation can be slow (\l{linear time}),
+ because it requires moving all the bytes at indexes \a i and
+ above by at least one position further in memory.
+
+//! [array-grow-at-insertion]
+ This array grows to accommodate the insertion. If \a i is beyond
+ the end of the array, the array is first extended with space characters
+ to reach this \a i.
+//! [array-grow-at-insertion]
+
\sa append(), prepend(), replace(), remove()
*/
QByteArray &QByteArray::insert(qsizetype i, QByteArrayView data)
{
const char *str = data.data();
- qsizetype len = data.size();
- if (i < 0 || str == nullptr || len <= 0)
+ qsizetype size = data.size();
+ if (i < 0 || size <= 0)
return *this;
- if (points_into_range(str, d.data(), d.data() + d.size)) {
- QVarLengthArray a(str, str + len);
- return insert(i, a);
+ // handle this specially, as QArrayDataOps::insert() doesn't handle out of
+ // bounds positions
+ if (i >= d->size) {
+ // In case when data points into the range or is == *this, we need to
+ // defer a call to free() so that it comes after we copied the data from
+ // the old memory:
+ DataPointer detached{}; // construction is free
+ d.detachAndGrow(Data::GrowsAtEnd, (i - d.size) + size, &str, &detached);
+ Q_CHECK_PTR(d.data());
+ d->copyAppend(i - d->size, ' ');
+ d->copyAppend(str, str + size);
+ d.data()[d.size] = '\0';
+ return *this;
}
- const auto oldSize = size();
- const auto newSize = qMax(i, oldSize) + len;
- const bool shouldGrow = d->shouldGrowBeforeInsert(d.begin() + qMin(i, oldSize), len);
-
- // ### optimize me
- if (d->needsDetach() || newSize > capacity() || shouldGrow) {
- auto flags = d->detachFlags() | Data::GrowsForward;
- if (oldSize != 0 && i <= oldSize / 4) // using QList's policy
- flags |= Data::GrowsBackwards;
- reallocGrowData(newSize, flags);
+ if (!d->needsDetach() && QtPrivate::q_points_into_range(str, d)) {
+ QVarLengthArray a(str, str + size);
+ return insert(i, a);
}
- if (i > oldSize) // set spaces in the uninitialized gap
- d->copyAppend(i - oldSize, 0x20);
-
- d->insert(d.begin() + i, str, str + len);
+ d->insert(i, str, size);
d.data()[d.size] = '\0';
return *this;
}
/*!
+ \fn QByteArray &QByteArray::insert(qsizetype i, const QByteArray &data)
+ Inserts \a data at index position \a i and returns a
+ reference to this byte array.
+
+ \include qbytearray.cpp array-grow-at-insertion
+
+ \sa append(), prepend(), replace(), remove()
+*/
+
+/*!
+ \fn QByteArray &QByteArray::insert(qsizetype i, const char *s)
+ Inserts \a s at index position \a i and returns a
+ reference to this byte array.
+
+ \include qbytearray.cpp array-grow-at-insertion
+
+ The function is equivalent to \c{insert(i, QByteArrayView(s))}
+
+ \sa append(), prepend(), replace(), remove()
+*/
+
+/*!
\fn QByteArray &QByteArray::insert(qsizetype i, const char *data, qsizetype len)
\overload
\since 4.6
@@ -1954,16 +2297,16 @@ QByteArray &QByteArray::insert(qsizetype i, QByteArrayView data)
Inserts \a len bytes, starting at \a data, at position \a i in the byte
array.
- If \a i is greater than size(), the array is first extended using
- resize().
+ \include qbytearray.cpp array-grow-at-insertion
*/
/*!
\fn QByteArray &QByteArray::insert(qsizetype i, char ch)
\overload
- Inserts byte \a ch at index position \a i in the byte array. If \a i is
- greater than size(), the array is first extended using resize().
+ Inserts byte \a ch at index position \a i in the byte array.
+
+ \include qbytearray.cpp array-grow-at-insertion
*/
/*! \fn QByteArray &QByteArray::insert(qsizetype i, qsizetype count, char ch)
@@ -1974,7 +2317,7 @@ QByteArray &QByteArray::insert(qsizetype i, QByteArrayView data)
Inserts \a count copies of byte \a ch at index position \a i in the byte
array.
- If \a i is greater than size(), the array is first extended using resize().
+ \include qbytearray.cpp array-grow-at-insertion
*/
QByteArray &QByteArray::insert(qsizetype i, qsizetype count, char ch)
@@ -1982,22 +2325,17 @@ QByteArray &QByteArray::insert(qsizetype i, qsizetype count, char ch)
if (i < 0 || count <= 0)
return *this;
- const auto oldSize = size();
- const auto newSize = qMax(i, oldSize) + count;
- const bool shouldGrow = d->shouldGrowBeforeInsert(d.begin() + qMin(i, oldSize), count);
-
- // ### optimize me
- if (d->needsDetach() || newSize > capacity() || shouldGrow) {
- auto flags = d->detachFlags() | Data::GrowsForward;
- if (oldSize != 0 && i <= oldSize / 4) // using QList's policy
- flags |= Data::GrowsBackwards;
- reallocGrowData(newSize, flags);
+ if (i >= d->size) {
+ // handle this specially, as QArrayDataOps::insert() doesn't handle out of bounds positions
+ d.detachAndGrow(Data::GrowsAtEnd, (i - d.size) + count, nullptr, nullptr);
+ Q_CHECK_PTR(d.data());
+ d->copyAppend(i - d->size, ' ');
+ d->copyAppend(count, ch);
+ d.data()[d.size] = '\0';
+ return *this;
}
- if (i > oldSize) // set spaces in the uninitialized gap
- d->copyAppend(i - oldSize, 0x20);
-
- d->insert(d.begin() + i, count, ch);
+ d->insert(i, count, ch);
d.data()[d.size] = '\0';
return *this;
}
@@ -2013,20 +2351,77 @@ QByteArray &QByteArray::insert(qsizetype i, qsizetype count, char ch)
Example:
\snippet code/src_corelib_text_qbytearray.cpp 18
- \sa insert(), replace()
+ Element removal will preserve the array's capacity and not reduce the
+ amount of allocated memory. To shed extra capacity and free as much memory
+ as possible, call squeeze() after the last change to the array's size.
+
+ \sa insert(), replace(), squeeze()
*/
QByteArray &QByteArray::remove(qsizetype pos, qsizetype len)
{
if (len <= 0 || pos < 0 || size_t(pos) >= size_t(size()))
return *this;
- detach();
- d->erase(d.begin() + pos, d.begin() + qMin(pos + len, size()));
- d.data()[d.size] = '\0';
+ if (pos + len > d->size)
+ len = d->size - pos;
+
+ 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
+
+ Removes all bytes for which the predicate \a pred returns true
+ from the byte array. Returns a reference to the byte array.
+
+ \sa remove()
+*/
+
+/*!
Replaces \a len bytes from index position \a pos with the byte
array \a after, and returns a reference to this byte array.
@@ -2038,13 +2433,16 @@ QByteArray &QByteArray::remove(qsizetype pos, qsizetype len)
QByteArray &QByteArray::replace(qsizetype pos, qsizetype len, QByteArrayView after)
{
- if (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
@@ -2095,11 +2493,11 @@ QByteArray &QByteArray::replace(QByteArrayView before, QByteArrayView after)
return *this;
// protect against before or after being part of this
- if (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 (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);
}
@@ -2191,23 +2589,6 @@ QByteArray &QByteArray::replace(QByteArrayView before, QByteArrayView after)
return *this;
}
-
-/*!
- \fn QByteArray &QByteArray::replace(const QByteArray &before, const char *after)
- \overload
-
- Replaces every occurrence of the byte in \a before with the '\\0'-terminated
- string \a after.
-*/
-
-/*! \fn QByteArray &QByteArray::replace(const char *before, const char *after)
-
- \overload
-
- Replaces every occurrence of the '\\0'-terminated string \a before with the
- '\\0'-terminated string \a after.
-*/
-
/*!
\fn QByteArray &QByteArray::replace(char before, QByteArrayView after)
\overload
@@ -2224,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;
}
@@ -2302,32 +2682,23 @@ QByteArray QByteArray::repeated(qsizetype times) const
#define REHASH(a) \
if (ol_minus_1 < sizeof(std::size_t) * CHAR_BIT) \
- hashHaystack -= (a) << ol_minus_1; \
+ 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();
- if (ol == 0)
- return from;
+ const auto l = haystack.size();
+ if (ol == 0) {
+ if (from < 0)
+ return qMax(from + l, 0);
+ else
+ return from > l ? -1 : from;
+ }
+
if (ol == 1)
- return findCharHelper(haystack, from, needle.front());
+ return findByteArray(haystack, from, needle.front());
- const auto l = haystack.size();
if (from > l || ol + from > l)
return -1;
@@ -2348,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
@@ -2360,11 +2732,6 @@ qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByt
\sa lastIndexOf(), contains()
*/
-qsizetype QByteArray::indexOf(char ch, qsizetype from) const
-{
- return static_cast<int>(findCharHelper(*this, from, ch));
-}
-
static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char *needle,
qsizetype ol, qsizetype from)
{
@@ -2401,6 +2768,8 @@ static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char
static inline qsizetype lastIndexOfCharHelper(QByteArrayView haystack, qsizetype from, char needle) noexcept
{
+ if (haystack.size() == 0)
+ return -1;
if (from < 0)
from += haystack.size();
else if (from > haystack.size())
@@ -2416,10 +2785,18 @@ 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())
- return !needle.size() ? 0 : -1;
+ if (haystack.isEmpty()) {
+ if (needle.isEmpty() && from == 0)
+ return 0;
+ return -1;
+ }
const auto ol = needle.size();
if (ol == 1)
return lastIndexOfCharHelper(haystack, from, needle.front());
@@ -2430,10 +2807,34 @@ qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteA
/*! \fn qsizetype QByteArray::lastIndexOf(QByteArrayView bv, qsizetype from) const
\since 6.0
- 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 default), the search starts from the
- end of the byte array. Returns -1 if no match is found.
+ 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.
+
+ \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
+
+ \note When searching for a 0-length \a bv, the match at the end of
+ the data is excluded from the search by a negative \a from, even
+ though \c{-1} is normally thought of as searching from the end of
+ the byte array: the match at the end is \e after the last character, so
+ it is excluded. To include such a final empty match, either give a
+ positive value for \a from or omit the \a from parameter entirely.
+
+ \sa indexOf(), contains(), count()
+*/
+
+/*! \fn qsizetype QByteArray::lastIndexOf(QByteArrayView bv) const
+ \since 6.2
+ \overload
+
+ 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 the end of the byte array. Returns -1 if no match is found.
Example:
\snippet code/src_corelib_text_qbytearray.cpp 23
@@ -2442,12 +2843,13 @@ 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 in
- this byte array, searching backward from index position \a from. If \a from is -1
- (the default), the search starts at the last byte (at index size() - 1). Returns
- -1 if no match is found.
+ Returns the index position of the start of the last occurrence of byte \a ch
+ in this byte array, searching backward from index position \a from.
+ If \a from is -1 (the default), the search starts at the last byte
+ (at index size() - 1). Returns -1 if no match is found.
Example:
\snippet code/src_corelib_text_qbytearray.cpp 24
@@ -2455,11 +2857,6 @@ qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteA
\sa indexOf(), contains()
*/
-qsizetype QByteArray::lastIndexOf(char ch, qsizetype from) const
-{
- return static_cast<int>(lastIndexOfCharHelper(*this, from, ch));
-}
-
static inline qsizetype countCharHelper(QByteArrayView haystack, char needle) noexcept
{
qsizetype num = 0;
@@ -2472,14 +2869,17 @@ static inline qsizetype countCharHelper(QByteArrayView haystack, char needle) no
qsizetype QtPrivate::count(QByteArrayView haystack, QByteArrayView needle) noexcept
{
+ if (needle.size() == 0)
+ return haystack.size() + 1;
+
if (needle.size() == 1)
return countCharHelper(haystack, needle[0]);
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)
@@ -2507,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
@@ -2523,8 +2925,8 @@ qsizetype QByteArray::count(char ch) const
Returns an integer less than, equal to, or greater than zero depending on
whether this QByteArray sorts before, at the same position as, or after the
- QByteArrayView \a bv. The comparison is performed according to case sensitivity
- \a cs.
+ QByteArrayView \a bv. The comparison is performed according to case
+ sensitivity \a cs.
\sa operator==, {Character Case}
*/
@@ -2547,7 +2949,7 @@ bool QtPrivate::startsWith(QByteArrayView haystack, QByteArrayView needle) noexc
Example:
\snippet code/src_corelib_text_qbytearray.cpp 25
- \sa endsWith(), left()
+ \sa endsWith(), first()
*/
/*!
@@ -2577,7 +2979,7 @@ bool QtPrivate::endsWith(QByteArrayView haystack, QByteArrayView needle) noexcep
Example:
\snippet code/src_corelib_text_qbytearray.cpp 26
- \sa startsWith(), right()
+ \sa startsWith(), last()
*/
/*!
@@ -2596,125 +2998,108 @@ 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;
+ return std::none_of(begin(), end(), isUpperCaseAscii);
+}
- const char *d = data();
+/*!
+ \fn QByteArray::isValidUtf8() const
- for (qsizetype i = 0, max = size(); i < max; ++i) {
- if (!isLowerCaseAscii(d[i]))
- return false;
- }
+ Returns \c true if this byte array contains valid UTF-8 encoded data,
+ or \c false otherwise.
- return true;
-}
+ \since 6.3
+*/
/*!
+ \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.
- \obsolete Use first() instead in new code.
+ If you know that \a len cannot be out of bounds, use first() instead in new
+ code, because it is faster.
The entire byte array is returned if \a len is greater than
size().
Returns an empty QByteArray if \a len is smaller than 0.
- Example:
- \snippet code/src_corelib_text_qbytearray.cpp 27
-
\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.
- \obsolete Use last() instead in new code.
+ If you know that \a len cannot be out of bounds, use last() instead in new
+ code, because it is faster.
The entire byte array is returned if \a len is greater than
size().
Returns an empty QByteArray if \a len is smaller than 0.
- Example:
- \snippet code/src_corelib_text_qbytearray.cpp 28
-
- \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.
- \obsolete Use sliced() instead in new code.
+ If you know that \a pos and \a len cannot be out of bounds, use sliced()
+ instead in new code, because it is faster.
If \a len is -1 (the default), or \a pos + \a len >= size(),
returns a byte array containing all bytes starting at position \a
pos until the end of the byte array.
- Example:
- \snippet code/src_corelib_text_qbytearray.cpp 29
-
- \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;
@@ -2729,36 +3114,63 @@ 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.
\note The behavior is undefined when \a n < 0 or \a n > size().
- \sa last(), sliced(), startsWith(), chopped(), chop(), truncate()
+ Example:
+ \snippet code/src_corelib_text_qbytearray.cpp 27
+
+ \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.
\note The behavior is undefined when \a n < 0 or \a n > size().
- \sa first(), sliced(), endsWith(), chopped(), chop(), truncate()
+ Example:
+ \snippet code/src_corelib_text_qbytearray.cpp 28
+
+ \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
@@ -2767,11 +3179,23 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
\note The behavior is undefined when \a pos < 0, \a n < 0,
or \a pos + \a n > size().
- \sa first(), last(), chopped(), chop(), truncate()
+ Example:
+ \snippet code/src_corelib_text_qbytearray.cpp 29
+
+ \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
@@ -2780,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::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::chopped(qsizetype len) const
+ \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
@@ -2792,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(), left(), right(), mid(), chop(), truncate()
+ \sa endsWith(), first(), last(), sliced(), chop(), truncate(), slice()
*/
/*!
@@ -2807,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
@@ -2882,7 +3332,7 @@ void QByteArray::clear()
d.clear();
}
-#if !defined(QT_NO_DATASTREAM) || (defined(QT_BOOTSTRAPPED) && !defined(QT_BUILD_QMAKE))
+#if !defined(QT_NO_DATASTREAM)
/*! \relates QByteArray
@@ -2895,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());
@@ -2912,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);
@@ -2935,289 +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 operator==(const QByteArray &a1, const QByteArray &a2)
- \relates QByteArray
-
+/*! \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 operator==(const QByteArray &a1, const char *a2)
- \relates QByteArray
-
+/*! \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 operator==(const char *a1, const QByteArray &a2)
- \relates QByteArray
-
+/*! \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 operator!=(const QByteArray &a1, const QByteArray &a2)
- \relates QByteArray
-
+/*! \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 operator!=(const QByteArray &a1, const char *a2)
- \relates QByteArray
-
+/*! \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 operator!=(const char *a1, const QByteArray &a2)
- \relates QByteArray
-
+/*! \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 operator<(const QByteArray &a1, const QByteArray &a2)
- \relates QByteArray
-
+/*! \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 inline bool operator<(const QByteArray &a1, const char *a2)
- \relates QByteArray
-
+/*! \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 operator<(const char *a1, const QByteArray &a2)
- \relates QByteArray
-
+/*! \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 operator<=(const QByteArray &a1, const QByteArray &a2)
- \relates QByteArray
-
+/*! \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 operator<=(const QByteArray &a1, const char *a2)
- \relates QByteArray
-
+/*! \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 operator<=(const char *a1, const QByteArray &a2)
- \relates QByteArray
-
+/*! \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 operator>(const QByteArray &a1, const QByteArray &a2)
- \relates QByteArray
-
+/*! \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 operator>(const QByteArray &a1, const char *a2)
- \relates QByteArray
-
+/*! \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 operator>(const char *a1, const QByteArray &a2)
- \relates QByteArray
-
+/*! \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 operator>=(const QByteArray &a1, const QByteArray &a2)
- \relates QByteArray
-
+/*! \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 operator>=(const QByteArray &a1, const char *a2)
- \relates QByteArray
-
+/*! \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 operator>=(const char *a1, const QByteArray &a2)
- \relates QByteArray
-
+/*! \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
@@ -3226,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
@@ -3235,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
@@ -3244,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
@@ -3253,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
@@ -3318,6 +3656,11 @@ QByteArray QByteArray::trimmed_helper(QByteArray &a)
return QStringAlgorithms<QByteArray>::trimmed_helper(a);
}
+QByteArrayView QtPrivate::trimmed(QByteArrayView view) noexcept
+{
+ const auto [start, stop] = QStringAlgorithms<QByteArrayView>::trimmed_helper_positions(view);
+ return QByteArrayView(start, stop);
+}
/*!
Returns a byte array of size \a width that contains this byte array padded
@@ -3393,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(const char *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(const char *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(const char *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) {
- 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 {};
}
/*!
@@ -3442,8 +3777,9 @@ T toIntegral_helper(const char *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.
@@ -3454,12 +3790,14 @@ T toIntegral_helper(const char *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>(nulTerminated().constData(), ok, base);
+ return QtPrivate::toIntegral<qlonglong>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3469,8 +3807,9 @@ qlonglong QByteArray::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.
@@ -3481,12 +3820,14 @@ qlonglong QByteArray::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>(nulTerminated().constData(), ok, base);
+ return QtPrivate::toIntegral<qulonglong>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3496,8 +3837,9 @@ qulonglong QByteArray::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.
@@ -3510,12 +3852,14 @@ qulonglong QByteArray::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>(nulTerminated().constData(), ok, base);
+ return QtPrivate::toIntegral<int>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3525,8 +3869,9 @@ int QByteArray::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.
@@ -3537,12 +3882,14 @@ int QByteArray::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>(nulTerminated().constData(), ok, base);
+ return QtPrivate::toIntegral<uint>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3554,8 +3901,9 @@ uint QByteArray::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.
@@ -3568,11 +3916,13 @@ uint QByteArray::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>(nulTerminated().constData(), ok, base);
+ return QtPrivate::toIntegral<long>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3584,8 +3934,9 @@ long QByteArray::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.
@@ -3596,11 +3947,13 @@ long QByteArray::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>(nulTerminated().constData(), ok, base);
+ return QtPrivate::toIntegral<ulong>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3609,9 +3962,10 @@ ulong QByteArray::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.
@@ -3622,12 +3976,14 @@ ulong QByteArray::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>(nulTerminated().constData(), ok, base);
+ return QtPrivate::toIntegral<short>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
/*!
@@ -3636,9 +3992,10 @@ short QByteArray::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.
@@ -3649,15 +4006,16 @@ short QByteArray::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>(nulTerminated().constData(), ok, base);
+ return QtPrivate::toIntegral<ushort>(qToByteArrayViewIgnoringNull(*this), ok, base);
}
-
/*!
Returns the byte array converted to a \c double value.
@@ -3685,13 +4043,16 @@ ushort QByteArray::toUShort(bool *ok, int base) const
double QByteArray::toDouble(bool *ok) const
{
- bool nonNullOk = false;
- int processed = 0;
- double d = qt_asciiToDouble(constData(), size(),
- nonNullOk, processed, WhitespacesAllowed);
- if (ok)
- *ok = nonNullOk;
- return d;
+ return QByteArrayView(*this).toDouble(ok);
+}
+
+auto QtPrivate::toDouble(QByteArrayView a) noexcept -> ParsedNumber<double>
+{
+ auto r = qt_asciiToDouble(a.data(), a.size(), WhitespacesAllowed);
+ if (r.ok())
+ return ParsedNumber{r.result};
+ else
+ return {};
}
/*!
@@ -3724,6 +4085,17 @@ float QByteArray::toFloat(bool *ok) const
return QLocaleData::convertDoubleToFloat(toDouble(ok), ok);
}
+auto QtPrivate::toFloat(QByteArrayView a) noexcept -> ParsedNumber<float>
+{
+ if (const auto r = toDouble(a)) {
+ bool ok = true;
+ const auto f = QLocaleData::convertDoubleToFloat(*r, &ok);
+ if (ok)
+ return ParsedNumber(f);
+ }
+ return {};
+}
+
/*!
\since 5.2
@@ -3737,27 +4109,29 @@ float QByteArray::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++]));
@@ -3792,10 +4166,12 @@ QByteArray QByteArray::toBase64(Base64Options options) const
/*!
\fn QByteArray &QByteArray::setNum(int n, int base)
- Sets the byte array to the printed value of \a n in base \a base (ten by
- default) and returns a reference to the byte array. Bases 2 through 36 are
+ Represent the whole number \a n as text.
+
+ Sets this byte array to a string representing \a n in base \a base (ten by
+ default) and returns a reference to this byte array. Bases 2 through 36 are
supported, using letters for digits beyond 9; A is ten, B is eleven and so
- on. For bases other than ten, n is treated as an unsigned integer.
+ on.
Example:
\snippet code/src_corelib_text_qbytearray.cpp 40
@@ -3850,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;
@@ -3867,11 +4243,12 @@ 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;
- if (n < 0 && base == 10) {
+ if (n < 0) {
+ // Take care to avoid overflow on negating min value:
p = qulltoa2(buff + buffsize, qulonglong(-(1 + n)) + 1, base);
*--p = '-';
} else {
@@ -3891,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);
@@ -3903,82 +4280,39 @@ QByteArray &QByteArray::setNum(qulonglong n, int base)
/*!
\overload
- Sets the byte array to the printed value of \a n, formatted in format
- \a f with precision \a prec, and returns a reference to the
- byte array.
-
- The format \a f can be any of the following:
-
- \table
- \header \li Format \li Meaning
- \row \li \c e \li format as [-]9.9e[+|-]999
- \row \li \c E \li format as [-]9.9E[+|-]999
- \row \li \c f \li format as [-]9.9
- \row \li \c g \li use \c e or \c f format, whichever is the most concise
- \row \li \c G \li use \c E or \c f format, whichever is the most concise
- \endtable
+ Represent the floating-point number \a n as text.
- With 'e', 'E', and 'f', \a prec is the number of digits after the
- decimal point. With 'g' and 'G', \a prec is the maximum number of
- significant digits (trailing zeroes are omitted).
+ Sets this byte array to a string representing \a n, with a given \a format
+ and \a precision (with the same meanings as for \l {QString::number(double,
+ char, int)}), and returns a reference to this byte array.
- \note The format of the number is not localized; the default C locale is
- used regardless of the user's locale. Use QLocale to perform locale-aware
- conversions between numbers and strings.
-
- \sa toDouble()
+ \sa toDouble(), QLocale::FloatingPointPrecisionOption
*/
-QByteArray &QByteArray::setNum(double n, char f, int prec)
+QByteArray &QByteArray::setNum(double n, char format, int precision)
{
- QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
- uint flags = QLocaleData::ZeroPadExponent;
-
- char lower = asciiLower(uchar(f));
- if (f != lower)
- flags |= QLocaleData::CapitalEorX;
- f = lower;
-
- switch (f) {
- case 'f':
- form = QLocaleData::DFDecimal;
- break;
- case 'e':
- form = QLocaleData::DFExponent;
- break;
- case 'g':
- form = QLocaleData::DFSignificantDigits;
- break;
- default:
-#if defined(QT_CHECK_RANGE)
- qWarning("QByteArray::setNum: Invalid format char '%c'", f);
-#endif
- break;
- }
-
- *this = QLocaleData::c()->doubleToString(n, prec, form, -1, flags).toUtf8();
- return *this;
+ return *this = QByteArray::number(n, format, precision);
}
/*!
- \fn QByteArray &QByteArray::setNum(float n, char f, int prec)
+ \fn QByteArray &QByteArray::setNum(float n, char format, int precision)
\overload
- Sets the byte array to the printed value of \a n, formatted in format
- \a f with precision \a prec, and returns a reference to the
- byte array.
+ Represent the floating-point number \a n as text.
- \note The format of the number is not localized; the default C locale is
- used regardless of the user's locale. Use QLocale to perform locale-aware
- conversions between numbers and strings.
+ Sets this byte array to a string representing \a n, with a given \a format
+ and \a precision (with the same meanings as for \l {QString::number(double,
+ char, int)}), and returns a reference to this byte array.
\sa toFloat()
*/
/*!
- Returns a byte array containing the printed value of the number \a n to base
- \a base (ten by default). Bases 2 through 36 are supported, using letters
- for digits beyond 9: A is ten, B is eleven and so on.
+ Returns a byte-array representing the whole number \a n as text.
+
+ Returns a byte array containing a string representing \a n, using the
+ specified \a base (ten by default). Bases 2 through 36 are supported, using
+ letters for digits beyond 9: A is ten, B is eleven and so on.
Example:
\snippet code/src_corelib_text_qbytearray.cpp 41
@@ -4058,39 +4392,38 @@ QByteArray QByteArray::number(qulonglong n, int base)
/*!
\overload
+ Returns a byte-array representing the floating-point number \a n as text.
- Returns a byte array that contains the printed value of \a n,
- formatted in format \a f with precision \a prec.
-
- Argument \a n is formatted according to the \a f format specified,
- which is \c g by default, and can be any of the following:
-
- \table
- \header \li Format \li Meaning
- \row \li \c e \li format as [-]9.9e[+|-]999
- \row \li \c E \li format as [-]9.9E[+|-]999
- \row \li \c f \li format as [-]9.9
- \row \li \c g \li use \c e or \c f format, whichever is the most concise
- \row \li \c G \li use \c E or \c f format, whichever is the most concise
- \endtable
-
- With 'e', 'E', and 'f', \a prec is the number of digits after the
- decimal point. With 'g' and 'G', \a prec is the maximum number of
- significant digits (trailing zeroes are omitted).
+ Returns a byte array containing a string representing \a n, with a given \a
+ format and \a precision, with the same meanings as for \l
+ {QString::number(double, char, int)}. For example:
\snippet code/src_corelib_text_qbytearray.cpp 42
- \note The format of the number is not localized; the default C locale is
- used regardless of the user's locale. Use QLocale to perform locale-aware
- conversions between numbers and strings.
-
- \sa toDouble()
+ \sa toDouble(), QLocale::FloatingPointPrecisionOption
*/
-QByteArray QByteArray::number(double n, char f, int prec)
+QByteArray QByteArray::number(double n, char format, int precision)
{
- QByteArray s;
- s.setNum(n, f, prec);
- return s;
+ QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
+
+ switch (QtMiscUtils::toAsciiLower(format)) {
+ case 'f':
+ form = QLocaleData::DFDecimal;
+ break;
+ case 'e':
+ form = QLocaleData::DFExponent;
+ break;
+ case 'g':
+ form = QLocaleData::DFSignificantDigits;
+ break;
+ default:
+#if defined(QT_CHECK_RANGE)
+ qWarning("QByteArray::setNum: Invalid format char '%c'", format);
+#endif
+ break;
+ }
+
+ return qdtoAscii(n, form, precision, isUpperCaseAscii(format));
}
/*!
@@ -4263,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 };
}
@@ -4279,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 };
}
@@ -4315,9 +4648,9 @@ QByteArray QByteArray::fromBase64(const QByteArray &base64, Base64Options option
}
/*!
- Returns a decoded copy of the hex encoded array \a hexEncoded. Input is not checked
- for validity; invalid characters in the input are skipped, enabling the
- decoding process to continue with subsequent characters.
+ Returns a decoded copy of the hex encoded array \a hexEncoded. Input is not
+ checked for validity; invalid characters in the input are skipped, enabling
+ the decoding process to continue with subsequent characters.
For example:
@@ -4350,10 +4683,13 @@ QByteArray QByteArray::fromHex(const QByteArray &hexEncoded)
return res;
}
-/*! Returns a hex encoded copy of the byte array. The hex encoding uses the numbers 0-9 and
- the letters a-f.
+/*!
+ Returns a hex encoded copy of the byte array.
+
+ The hex encoding uses the numbers 0-9 and the letters a-f.
- If \a separator is not '\0', the separator character is inserted between the hex bytes.
+ If \a separator is not '\0', the separator character is inserted between
+ the hex bytes.
Example:
\snippet code/src_corelib_text_qbytearray.cpp 50
@@ -4389,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;
@@ -4420,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
@@ -4441,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
@@ -4460,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
@@ -4473,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()));
}
/*!
@@ -4569,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
*/
@@ -4682,6 +5054,57 @@ 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.
+
+ 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
+ auto str = "hello"_qba;
+ \endcode
+
+ \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
\inmodule QtCore
@@ -4734,8 +5157,7 @@ QByteArray QByteArray::toPercentEncoding(const QByteArray &exclude, const QByteA
*/
/*!
- \fn bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
- \relates QByteArray::FromBase64Result
+ \fn bool QByteArray::FromBase64Result::operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
Returns \c true if \a lhs and \a rhs are equal, otherwise returns \c false.
@@ -4745,10 +5167,10 @@ QByteArray QByteArray::toPercentEncoding(const QByteArray &exclude, const QByteA
*/
/*!
- \fn bool operator!=(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
- \relates QByteArray::FromBase64Result
+ \fn bool QByteArray::FromBase64Result::operator!=(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
- Returns \c true if \a lhs and \a rhs are different, otherwise returns \c false.
+ Returns \c true if \a lhs and \a rhs are different, otherwise
+ returns \c false.
*/
/*!
@@ -4762,4 +5184,27 @@ size_t qHash(const QByteArray::FromBase64Result &key, size_t seed) noexcept
return qHashMulti(seed, key.decoded, static_cast<int>(key.decodingStatus));
}
+/*! \fn template <typename T> qsizetype erase(QByteArray &ba, const T &t)
+ \relates QByteArray
+ \since 6.1
+
+ Removes all elements that compare equal to \a t from the
+ byte array \a ba. Returns the number of elements removed, if any.
+
+ \sa erase_if
+*/
+
+/*! \fn template <typename Predicate> qsizetype erase_if(QByteArray &ba, Predicate pred)
+ \relates QByteArray
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the byte array \a ba. Returns the number of elements removed, if
+ any.
+
+ \sa erase
+*/
+
QT_END_NAMESPACE
+
+#undef REHASH