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.cpp2998
1 files changed, 1684 insertions, 1314 deletions
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index 95a1f9f52c..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,23 +14,37 @@
#include "private/qsimd_p.h"
#include "qstringalgorithms_p.h"
#include "qscopedpointer.h"
-#include "qbytearray_p.h"
+#include "qstringconverter_p.h"
#include <qdatastream.h>
#include <qmath.h>
+#if defined(Q_OS_WASM)
+#include "private/qstdweb_p.h"
+#endif
#ifndef QT_NO_COMPRESS
#include <zconf.h>
#include <zlib.h>
+#include <qxpfunctional.h>
#endif
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
-#define IS_RAW_DATA(d) ((d)->flags() & QArrayData::RawDataType)
+#include <algorithm>
+
+#ifdef Q_OS_WIN
+# if !defined(QT_BOOTSTRAPPED) && (defined(QT_NO_CAST_FROM_ASCII) || defined(QT_NO_CAST_FROM_BYTEARRAY))
+// MSVC requires this, but let's apply it to MinGW compilers too, just in case
+# error "This file cannot be compiled with QT_NO_CAST_{TO,FROM}_ASCII, " \
+ "otherwise some QByteArray functions will not get exported."
+# endif
+#endif
QT_BEGIN_NAMESPACE
+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)
{
@@ -125,7 +103,7 @@ char *qstrcpy(char *dst, const char *src)
if (!src)
return nullptr;
#ifdef Q_CC_MSVC
- const int len = int(strlen(src));
+ const size_t len = strlen(src);
// This is actually not secure!!! It will be fixed
// properly in a later release!
if (len >= 0 && strcpy_s(dst, len+1, src) == 0)
@@ -141,34 +119,33 @@ 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, uint len)
+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 uint qstrlen(const char *str)
+/*! \fn size_t qstrlen(const char *str)
\relates QByteArray
A safe \c strlen() function.
@@ -179,7 +156,7 @@ char *qstrncpy(char *dst, const char *src, uint len)
\sa qstrnlen()
*/
-/*! \fn uint qstrnlen(const char *str, uint maxlen)
+/*! \fn size_t qstrnlen(const char *str, size_t maxlen)
\relates QByteArray
\since 4.2
@@ -204,7 +181,8 @@ char *qstrncpy(char *dst, const char *src, uint 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)
{
@@ -212,7 +190,7 @@ int qstrcmp(const char *str1, const char *str2)
: (str1 ? 1 : (str2 ? -1 : 0));
}
-/*! \fn int qstrncmp(const char *str1, const char *str2, uint len);
+/*! \fn int qstrncmp(const char *str1, const char *str2, size_t len);
\relates QByteArray
@@ -228,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
@@ -246,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)
@@ -264,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;
@@ -282,7 +262,7 @@ int qstricmp(const char *str1, const char *str2)
// very quick.
quintptr u1 = quintptr(s1 + offset);
quintptr u2 = quintptr(s2 + offset);
- uint n = PageSize - ((u1 | u2) & PageMask);
+ size_t n = PageSize - ((u1 | u2) & PageMask);
qptrdiff maxoffset = offset + n;
for ( ; offset + 16 <= maxoffset; offset += sizeof(__m128i)) {
@@ -290,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
@@ -303,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;
@@ -335,10 +315,11 @@ 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, uint len)
+int qstrnicmp(const char *str1, const char *str2, size_t len)
{
const uchar *s1 = reinterpret_cast<const uchar *>(str1);
const uchar *s2 = reinterpret_cast<const uchar *>(str2);
@@ -346,7 +327,7 @@ int qstrnicmp(const char *str1, const char *str2, uint 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;
@@ -364,11 +345,18 @@ int qstrnicmp(const char *str1, const char *str2, uint len)
*/
int qstrnicmp(const char *str1, qsizetype len1, const char *str2, qsizetype len2)
{
- Q_ASSERT(str1);
Q_ASSERT(len1 >= 0);
Q_ASSERT(len2 >= -1);
const uchar *s1 = reinterpret_cast<const uchar *>(str1);
const uchar *s2 = reinterpret_cast<const uchar *>(str2);
+ if (!s1 || !len1) {
+ if (len2 == 0)
+ return 0;
+ if (len2 == -1)
+ return (!s2 || !*s2) ? 0 : -1;
+ Q_ASSERT(s2);
+ return -1;
+ }
if (!s2)
return len1 == 0 ? 0 : 1;
@@ -380,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;
@@ -388,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)
@@ -399,47 +387,26 @@ int qstrnicmp(const char *str1, qsizetype len1, const char *str2, qsizetype len2
/*!
\internal
- ### Qt6: replace the QByteArray parameter with [pointer,len] pair
*/
-int qstrcmp(const QByteArray &str1, const char *str2)
+int QtPrivate::compareMemory(QByteArrayView lhs, QByteArrayView rhs)
{
- if (!str2)
- return str1.isEmpty() ? 0 : +1;
-
- const char *str1data = str1.constData();
- const char *str1end = str1data + str1.length();
- for ( ; str1data < str1end && *str2; ++str1data, ++str2) {
- int diff = int(uchar(*str1data)) - uchar(*str2);
- if (diff)
- // found a difference
- return diff;
+ if (!lhs.isNull() && !rhs.isNull()) {
+ int ret = memcmp(lhs.data(), rhs.data(), qMin(lhs.size(), rhs.size()));
+ if (ret != 0)
+ return ret;
}
- // Why did we stop?
- if (*str2 != '\0')
- // not the null, so we stopped because str1 is shorter
- return -1;
- if (str1data < str1end)
- // we haven't reached the end, so str1 must be longer
- return +1;
- return 0;
+ // they matched qMin(l1, l2) bytes
+ // so the longer one is lexically after the shorter one
+ return lhs.size() == rhs.size() ? 0 : lhs.size() > rhs.size() ? 1 : -1;
}
/*!
\internal
- ### Qt6: replace the QByteArray parameter with [pointer,len] pair
- */
-int qstrcmp(const QByteArray &str1, const QByteArray &str2)
+*/
+bool QtPrivate::isValidUtf8(QByteArrayView s) noexcept
{
- int l1 = str1.length();
- int l2 = str2.length();
- int ret = memcmp(str1.constData(), str2.constData(), qMin(l1, l2));
- if (ret != 0)
- return ret;
-
- // they matched qMin(l1, l2) bytes
- // so the longer one is lexically after the shorter one
- return l1 - l2;
+ return QUtf8::isValidUtf8(s).isValidUtf8;
}
// the CRC table below is created by the following piece of code
@@ -490,7 +457,7 @@ static const quint16 crc_tbl[16] = {
\relates QByteArray
\since 5.9
- Returns the CRC-16 checksum of the first \a len bytes of \a data.
+ Returns the CRC-16 checksum of \a data.
The checksum is independent of the byte order (endianness) and will
be calculated accorded to the algorithm published in \a standard.
@@ -499,7 +466,7 @@ static const quint16 crc_tbl[16] = {
\note This function is a 16-bit cache conserving (16 entry table)
implementation of the CRC-16-CCITT algorithm.
*/
-quint16 qChecksum(const char *data, uint len, Qt::ChecksumType standard)
+quint16 qChecksum(QByteArrayView data, Qt::ChecksumType standard)
{
quint16 crc = 0x0000;
switch (standard) {
@@ -511,7 +478,8 @@ quint16 qChecksum(const char *data, uint len, Qt::ChecksumType standard)
break;
}
uchar c;
- const uchar *p = reinterpret_cast<const uchar *>(data);
+ const uchar *p = reinterpret_cast<const uchar *>(data.data());
+ qsizetype len = data.size();
while (len--) {
c = *p++;
crc = ((crc >> 4) & 0x0fff) ^ crc_tbl[((crc ^ c) & 15)];
@@ -545,10 +513,12 @@ quint16 qChecksum(const char *data, uint len, 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
@@ -557,44 +527,196 @@ quint16 qChecksum(const char *data, uint len, Qt::ChecksumType standard)
*/
#ifndef QT_NO_COMPRESS
-QByteArray qCompress(const uchar* data, int nbytes, int compressionLevel)
+using CompressSizeHint_t = quint32; // 32-bit BE, historically
+
+enum class ZLibOp : bool { Compression, Decompression };
+
+Q_DECL_COLD_FUNCTION
+static const char *zlibOpAsString(ZLibOp op)
{
- if (nbytes == 0) {
- return QByteArray(4, '\0');
+ switch (op) {
+ case ZLibOp::Compression: return "qCompress";
+ case ZLibOp::Decompression: return "qUncompress";
}
- if (!data) {
- qWarning("qCompress: Data is null");
- return QByteArray();
+ 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(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
@@ -616,18 +738,21 @@ QByteArray qCompress(const uchar* data, int 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
@@ -635,66 +760,41 @@ static QByteArray invalidCompressedData()
Uncompresses the first \a nbytes of \a data and returns a new byte
array with the uncompressed data.
*/
-QByteArray qUncompress(const uchar* data, int nbytes)
+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();
- }
- ulong expectedSize = uint((data[0] << 24) | (data[1] << 16) |
- (data[2] << 8) | (data[3] ));
- ulong len = qMax(expectedSize, 1ul);
- const ulong 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(expectedSize + 1));
- 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 {
- ulong alloc = len;
- int res = ::uncompress((uchar*)d.data(), &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
@@ -709,6 +809,14 @@ QByteArray qUncompress(const uchar* data, int 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
@@ -756,7 +864,7 @@ QByteArray qUncompress(const uchar* data, int 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'
@@ -785,16 +893,48 @@ QByteArray qUncompress(const uchar* data, int 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 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.
- 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
+ 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
@@ -836,15 +976,19 @@ QByteArray qUncompress(const uchar* data, int nbytes)
\section1 Maximum size and out-of-memory conditions
- The current version of QByteArray is limited to just under 2 GB (2^31
- bytes) in size. The exact value is architecture-dependent, since it depends
- on the overhead required for managing the data block, but is no more than
- 32 bytes. Raw data blocks are also limited by the use of \c int type in the
- current version to 2 GB minus 1 byte.
+ 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.
- 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.
+ 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.
@@ -878,17 +1022,18 @@ QByteArray qUncompress(const uchar* data, int 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
@@ -896,13 +1041,13 @@ QByteArray qUncompress(const uchar* data, int 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 QString, QBitArray
+ \sa QByteArrayView, QString, QBitArray
*/
/*!
@@ -941,6 +1086,11 @@ QByteArray qUncompress(const uchar* data, int nbytes)
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first
byte in the byte-array.
+//! [iterator-invalidation-func-desc]
+ \warning The returned iterator is invalidated on detachment or when the
+ QByteArray is modified.
+//! [iterator-invalidation-func-desc]
+
\sa constBegin(), end()
*/
@@ -955,6 +1105,8 @@ QByteArray qUncompress(const uchar* data, int nbytes)
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the
first byte in the byte-array.
+ \include qbytearray.cpp iterator-invalidation-func-desc
+
\sa begin(), cend()
*/
@@ -963,6 +1115,8 @@ QByteArray qUncompress(const uchar* data, int nbytes)
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the
first byte in the byte-array.
+ \include qbytearray.cpp iterator-invalidation-func-desc
+
\sa begin(), constEnd()
*/
@@ -971,6 +1125,8 @@ QByteArray qUncompress(const uchar* data, int nbytes)
Returns an \l{STL-style iterators}{STL-style iterator} pointing just after
the last byte in the byte-array.
+ \include qbytearray.cpp iterator-invalidation-func-desc
+
\sa begin(), constEnd()
*/
@@ -985,6 +1141,8 @@ QByteArray qUncompress(const uchar* data, int nbytes)
Returns a const \l{STL-style iterators}{STL-style iterator} pointing just
after the last byte in the byte-array.
+ \include qbytearray.cpp iterator-invalidation-func-desc
+
\sa cbegin(), end()
*/
@@ -993,14 +1151,18 @@ QByteArray qUncompress(const uchar* data, int nbytes)
Returns a const \l{STL-style iterators}{STL-style iterator} pointing just
after the last byte in the byte-array.
+ \include qbytearray.cpp iterator-invalidation-func-desc
+
\sa constBegin(), end()
*/
/*! \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
\sa begin(), crbegin(), rend()
*/
@@ -1013,8 +1175,10 @@ QByteArray qUncompress(const uchar* data, int 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
\sa begin(), rbegin(), rend()
*/
@@ -1022,8 +1186,10 @@ QByteArray qUncompress(const uchar* data, int 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
\sa end(), crend(), rbegin()
*/
@@ -1036,8 +1202,10 @@ QByteArray qUncompress(const uchar* data, int 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
\sa end(), rend(), rbegin()
*/
@@ -1048,6 +1216,13 @@ QByteArray qUncompress(const uchar* data, int nbytes)
to append(\a other).
*/
+/*! \fn void QByteArray::push_back(QByteArrayView str)
+ \since 6.0
+ \overload
+
+ Same as append(\a str).
+*/
+
/*! \fn void QByteArray::push_back(const char *str)
\overload
@@ -1068,6 +1243,13 @@ QByteArray qUncompress(const uchar* data, int nbytes)
to prepend(\a other).
*/
+/*! \fn void QByteArray::push_front(QByteArrayView str)
+ \since 6.0
+ \overload
+
+ Same as prepend(\a str).
+*/
+
/*! \fn void QByteArray::push_front(const char *str)
\overload
@@ -1089,6 +1271,37 @@ QByteArray qUncompress(const uchar* data, int 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.
@@ -1136,24 +1349,19 @@ 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)
{
- if (!str || !*str) {
- if (!str) {
- d.clear();
- } else {
- d = QByteArrayData(Data::allocate(0), 0);
- }
+ if (!str) {
+ d.clear();
+ } else if (!*str) {
+ d = DataPointer::fromRawData(&_empty, 0);
} else {
- const int len = int(strlen(str));
- const uint fullLen = uint(len) + 1;
- if (d->needsDetach() || fullLen > d->allocatedCapacity()
- || (len < size() && fullLen < (d->allocatedCapacity() >> 1)))
- reallocData(fullLen, d->detachFlags());
- memcpy(d.data(), str, fullLen); // include null terminator
- d.size = len;
+ assign(str);
}
return *this;
}
@@ -1173,7 +1381,7 @@ QByteArray &QByteArray::operator=(const char *str)
fast and never fails.
*/
-/*! \fn int QByteArray::size() const
+/*! \fn qsizetype QByteArray::size() const
Returns the number of bytes in this byte array.
@@ -1182,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:
@@ -1191,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.
@@ -1201,7 +1418,7 @@ QByteArray &QByteArray::operator=(const char *str)
\sa size()
*/
-/*! \fn int QByteArray::capacity() const
+/*! \fn qsizetype QByteArray::capacity() const
Returns the maximum number of bytes that can be stored in the
byte array without forcing a reallocation.
@@ -1214,21 +1431,36 @@ QByteArray &QByteArray::operator=(const char *str)
\note a statically allocated byte array will report a capacity of 0,
even if it's not empty.
+ \note The free space position in the allocated memory block is undefined. In
+ other words, one should not assume that the free memory is always located
+ after the initialized elements.
+
\sa reserve(), squeeze()
*/
-/*! \fn void QByteArray::reserve(int size)
+/*! \fn void QByteArray::reserve(qsizetype size)
+
+ Attempts to allocate memory for at least \a size bytes.
- 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
+ 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()
*/
@@ -1247,12 +1479,16 @@ 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.
- The data is '\\0'-terminated. The pointer remains valid as long
- as the array isn't reallocated or destroyed.
+ The data is '\\0'-terminated.
+
+//! [pointer-invalidation-desc]
+ The pointer remains valid as long as no detach happens and the QByteArray
+ is not modified.
+//! [pointer-invalidation-desc]
This operator is mostly useful to pass a byte array to a function
that accepts a \c{const char *}.
@@ -1287,9 +1523,10 @@ QByteArray &QByteArray::operator=(const char *str)
Example:
\snippet code/src_corelib_text_qbytearray.cpp 8
- The pointer remains valid as long as the byte array isn't
- reallocated or destroyed. For read-only access, constData() is
- faster because it never causes a \l{deep copy} to occur.
+ \include qbytearray.cpp pointer-invalidation-desc
+
+ For read-only access, constData() is faster because it never
+ causes a \l{deep copy} to occur.
This function is mostly useful to pass a byte array to a function
that accepts a \c{const char *}.
@@ -1318,11 +1555,11 @@ 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.
- The pointer remains valid as long as the byte array isn't reallocated or
- destroyed.
+
+ \include qbytearray.cpp pointer-invalidation-desc
This function is mostly useful to pass a byte array to a function
that accepts a \c{const char *}.
@@ -1349,7 +1586,7 @@ QByteArray &QByteArray::operator=(const char *str)
\internal
*/
-/*! \fn char QByteArray::at(int i) const
+/*! \fn char QByteArray::at(qsizetype i) const
Returns the byte at index position \a i in the byte array.
@@ -1359,7 +1596,7 @@ QByteArray &QByteArray::operator=(const char *str)
\sa operator[]()
*/
-/*! \fn char &QByteArray::operator[](int i)
+/*! \fn char &QByteArray::operator[](qsizetype i)
Returns the byte at index position \a i as a modifiable reference.
@@ -1372,7 +1609,7 @@ QByteArray &QByteArray::operator=(const char *str)
\sa at()
*/
-/*! \fn char QByteArray::operator[](int i) const
+/*! \fn char QByteArray::operator[](qsizetype i) const
\overload
@@ -1439,22 +1676,15 @@ QByteArray &QByteArray::operator=(const char *str)
\sa front(), at(), operator[]()
*/
-/*! \fn bool QByteArray::contains(const QByteArray &ba) const
+/*! \fn bool QByteArray::contains(QByteArrayView bv) const
+ \since 6.0
- Returns \c true if the byte array contains an occurrence of the byte
- array \a ba; otherwise returns \c false.
+ Returns \c true if this byte array contains an occurrence of the
+ sequence of bytes viewed by \a bv; otherwise returns \c false.
\sa indexOf(), count()
*/
-/*! \fn bool QByteArray::contains(const char *str) const
-
- \overload
-
- Returns \c true if the byte array contains the '\\0'-terminated string \a
- str; otherwise returns \c false.
-*/
-
/*! \fn bool QByteArray::contains(char ch) const
\overload
@@ -1472,9 +1702,9 @@ 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(int pos)
+void QByteArray::truncate(qsizetype pos)
{
if (pos < size())
resize(pos);
@@ -1490,10 +1720,10 @@ void QByteArray::truncate(int pos)
Example:
\snippet code/src_corelib_text_qbytearray.cpp 11
- \sa truncate(), resize(), left()
+ \sa truncate(), resize(), first()
*/
-void QByteArray::chop(int n)
+void QByteArray::chop(qsizetype n)
{
if (n > 0)
resize(size() - n);
@@ -1540,7 +1770,7 @@ void QByteArray::chop(int n)
reference to this byte array.
*/
-/*! \fn int QByteArray::length() const
+/*! \fn qsizetype QByteArray::length() const
Same as size().
*/
@@ -1581,16 +1811,21 @@ void QByteArray::chop(int n)
\sa fromRawData()
*/
-QByteArray::QByteArray(const char *data, int size)
+QByteArray::QByteArray(const char *data, qsizetype size)
{
if (!data) {
d = DataPointer();
} else {
if (size < 0)
- size = int(strlen(data));
- d = DataPointer(Data::allocate(uint(size) + 1u), size);
- memcpy(d.data(), data, size);
- d.data()[size] = '\0';
+ size = qstrlen(data);
+ if (!size) {
+ d = DataPointer::fromRawData(&_empty, 0);
+ } else {
+ d = DataPointer(size, size);
+ Q_CHECK_PTR(d.data());
+ memcpy(d.data(), data, size);
+ d.data()[size] = '\0';
+ }
}
}
@@ -1600,27 +1835,31 @@ QByteArray::QByteArray(const char *data, int size)
\sa fill()
*/
-QByteArray::QByteArray(int size, char ch)
+QByteArray::QByteArray(qsizetype size, char ch)
{
if (size <= 0) {
- d = DataPointer(Data::allocate(0), 0);
+ d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(uint(size) + 1u), 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.
*/
-QByteArray::QByteArray(int size, Qt::Initialization)
+QByteArray::QByteArray(qsizetype size, Qt::Initialization)
{
- d = DataPointer(Data::allocate(uint(size) + 1u), size);
- d.data()[size] = '\0';
+ if (size <= 0) {
+ d = DataPointer::fromRawData(&_empty, 0);
+ } else {
+ d = DataPointer(size, size);
+ Q_CHECK_PTR(d.data());
+ d.data()[size] = '\0';
+ }
}
/*!
@@ -1630,24 +1869,68 @@ QByteArray::QByteArray(int 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(int size)
+void QByteArray::resize(qsizetype size)
{
if (size < 0)
size = 0;
- if (d->needsDetach() || size > capacity())
- reallocData(uint(size) + 1u, d->detachFlags() | Data::GrowsForward);
+ const auto capacityAtEnd = capacity() - d.freeSpaceAtBegin();
+ if (d->needsDetach() || size > capacityAtEnd)
+ 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.
@@ -1657,7 +1940,7 @@ void QByteArray::resize(int size)
\sa resize()
*/
-QByteArray &QByteArray::fill(char ch, int size)
+QByteArray &QByteArray::fill(char ch, qsizetype size)
{
resize(size < 0 ? this->size() : size);
if (this->size())
@@ -1665,88 +1948,90 @@ QByteArray &QByteArray::fill(char ch, int size)
return *this;
}
-void QByteArray::reallocData(uint alloc, Data::ArrayOptions options)
+void QByteArray::reallocData(qsizetype alloc, QArrayData::AllocationOption option)
{
- if (d->needsDetach()) {
- DataPointer dd(Data::allocate(alloc, options), qMin(int(alloc) - 1, d.size));
- ::memcpy(dd.data(), d.data(), dd.size);
+ if (!alloc) {
+ d = DataPointer::fromRawData(&_empty, 0);
+ return;
+ }
+
+ // 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() || 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::expand(int i)
+void QByteArray::reallocGrowData(qsizetype n)
{
- resize(qMax(i + 1, size()));
-}
+ if (!n) // expected to always allocate
+ n = 1;
-/*!
- \internal
- Return a QByteArray that is sure to be '\\0'-terminated.
+ if (d->needsDetach()) {
+ 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(d.constAllocatedCapacity() + n, QArrayData::Grow);
+ }
+}
- 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
+void QByteArray::expand(qsizetype i)
{
- // is this fromRawData?
- if (!IS_RAW_DATA(d))
- return *this; // no, then we're sure we're zero terminated
-
- QByteArray copy(*this);
- copy.detach();
- return copy;
+ resize(qMax(i + 1, size()));
}
/*!
- Prepends the byte array \a ba to this byte array and returns a
+ \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
This is the same as insert(0, \a ba).
- Note: QByteArray is an \l{implicitly shared} class. Consequently,
- if you prepend to an empty byte array, then the byte array will just
- share the data held in \a ba. In this case, no copying of data is done,
- taking \l{constant time}. If a shared instance is modified, it will
- be copied (copy-on-write), taking \l{linear time}.
-
- If the byte array being prepended to is not empty, a deep copy of the
- data is performed, taking \l{linear time}.
-
\sa append(), insert()
*/
+/*!
+ \fn QByteArray &QByteArray::prepend(const QByteArray &ba)
+ \overload
+
+ Prepends \a ba to this byte array.
+*/
QByteArray &QByteArray::prepend(const QByteArray &ba)
{
- if (size() == 0 && d->isStatic() && !IS_RAW_DATA(ba.d)) {
- *this = ba;
- } else if (ba.size() != 0) {
- QByteArray tmp = *this;
- *this = ba;
- append(tmp);
- }
- return *this;
+ if (size() == 0 && ba.size() > d.constAllocatedCapacity() && ba.d.isMutable())
+ return (*this = ba);
+ return prepend(QByteArrayView(ba));
}
/*!
+ \fn QByteArray &QByteArray::prepend(const char *str)
\overload
Prepends the '\\0'-terminated string \a str to this byte array.
*/
-QByteArray &QByteArray::prepend(const char *str)
-{
- return prepend(str, qstrlen(str));
-}
-
/*!
+ \fn QByteArray &QByteArray::prepend(const char *str, qsizetype len)
\overload
\since 4.6
@@ -1754,20 +2039,7 @@ QByteArray &QByteArray::prepend(const char *str)
The bytes prepended may include '\\0' bytes.
*/
-QByteArray &QByteArray::prepend(const char *str, int len)
-{
- if (str) {
- if (d->needsDetach() || size() + len > capacity())
- reallocData(uint(size() + len) + 1u, d->detachFlags() | Data::GrowsForward);
- memmove(d.data()+len, d.data(), d.size);
- memcpy(d.data(), str, len);
- d.size += len;
- d.data()[d.size] = '\0';
- }
- return *this;
-}
-
-/*! \fn QByteArray &QByteArray::prepend(int count, char ch)
+/*! \fn QByteArray &QByteArray::prepend(qsizetype count, char ch)
\overload
\since 5.7
@@ -1776,22 +2048,12 @@ QByteArray &QByteArray::prepend(const char *str, int len)
*/
/*!
+ \fn QByteArray &QByteArray::prepend(char ch)
\overload
Prepends the byte \a ch to this byte array.
*/
-QByteArray &QByteArray::prepend(char ch)
-{
- if (d->needsDetach() || size() + 1 > capacity())
- reallocData(uint(size()) + 2u, d->detachFlags() | Data::GrowsForward);
- memmove(d.data()+1, d.data(), d.size);
- d.data()[0] = ch;
- ++d.size;
- d.data()[d.size] = '\0';
- return *this;
-}
-
/*!
Appends the byte array \a ba onto the end of this byte array.
@@ -1809,47 +2071,45 @@ QByteArray &QByteArray::prepend(char ch)
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 && d->isStatic() && !IS_RAW_DATA(ba.d)) {
- *this = ba;
- } else if (ba.size() != 0) {
- if (d->needsDetach() || size() + ba.size() > capacity())
- reallocData(uint(size() + ba.size()) + 1u, d->detachFlags() | Data::GrowsForward);
- memcpy(d.data() + d.size, ba.data(), ba.size());
- d.size += ba.size();
- d.data()[d.size] = '\0';
+ 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;
}
/*!
+ \fn QByteArray &QByteArray::append(QByteArrayView data)
\overload
- Appends the '\\0'-terminated string \a str to this byte array.
+ Appends \a data to this byte array.
*/
-QByteArray& QByteArray::append(const char *str)
-{
- if (str) {
- const int len = int(strlen(str));
- if (d->needsDetach() || size() + len > capacity())
- reallocData(uint(size() + len) + 1u, d->detachFlags() | Data::GrowsForward);
- memcpy(d.data() + d.size, str, len + 1); // include null terminator
- d.size += len;
- }
- return *this;
-}
+/*!
+ \fn QByteArray& QByteArray::append(const char *str)
+ \overload
+
+ Appends the '\\0'-terminated string \a str to this byte array.
+*/
/*!
- \overload append()
+ \fn QByteArray &QByteArray::append(const char *str, qsizetype len)
+ \overload
Appends the first \a len bytes starting at \a str to this byte array and
returns a reference to this byte array. The bytes appended may include '\\0'
@@ -1863,21 +2123,7 @@ QByteArray& QByteArray::append(const char *str)
array. Ensure that \a len is \e not longer than \a str.
*/
-QByteArray &QByteArray::append(const char *str, int len)
-{
- if (len < 0)
- len = qstrlen(str);
- if (str && len) {
- if (d->needsDetach() || size() + len > capacity())
- reallocData(uint(size() + len) + 1u, d->detachFlags() | Data::GrowsForward);
- memcpy(d.data() + d.size, str, len);
- d.size += len;
- d.data()[d.size] = '\0';
- }
- return *this;
-}
-
-/*! \fn QByteArray &QByteArray::append(int count, char ch)
+/*! \fn QByteArray &QByteArray::append(qsizetype count, char ch)
\overload
\since 5.7
@@ -1896,95 +2142,174 @@ QByteArray &QByteArray::append(const char *str, int len)
QByteArray& QByteArray::append(char ch)
{
- if (d->needsDetach() || size() + 1 > capacity())
- reallocData(uint(size()) + 2u, d->detachFlags() | Data::GrowsForward);
- d.data()[d.size++] = ch;
+ d.detachAndGrow(QArrayData::GrowsAtEnd, 1, nullptr, nullptr);
+ d->copyAppend(1, ch);
d.data()[d.size] = '\0';
return *this;
}
/*!
- \internal
- Inserts \a len bytes from the array \a arr at position \a pos and returns a
- reference the modified byte array.
+ \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.
*/
-static inline QByteArray &qbytearray_insert(QByteArray *ba,
- int pos, const char *arr, int len)
+
+/*!
+ \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)
{
- if (pos < 0 || len <= 0 || arr == nullptr)
- return *ba;
-
- int oldsize = ba->size();
- ba->resize(qMax(pos, oldsize) + len);
- char *dst = ba->data();
- if (pos > oldsize)
- ::memset(dst + oldsize, 0x20, pos - oldsize);
- else
- ::memmove(dst + pos + len, dst + pos, oldsize - pos);
- memcpy(dst + pos, arr, len);
- return *ba;
+ 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 the byte array \a ba at index position \a i and returns a
+ Inserts \a data at index position \a i and returns a
reference to this byte array.
Example:
\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(int i, const QByteArray &ba)
+QByteArray &QByteArray::insert(qsizetype i, QByteArrayView data)
{
- QByteArray copy(ba);
- return qbytearray_insert(this, i, copy.constData(), copy.size());
+ const char *str = data.data();
+ qsizetype size = data.size();
+ if (i < 0 || size <= 0)
+ return *this;
+
+ // 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;
+ }
+
+ if (!d->needsDetach() && QtPrivate::q_points_into_range(str, d)) {
+ QVarLengthArray a(str, str + size);
+ return insert(i, a);
+ }
+
+ d->insert(i, str, size);
+ d.data()[d.size] = '\0';
+ return *this;
}
/*!
- \overload
+ \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.
- Inserts the '\\0'-terminated string \a str at position \a i in the byte
- array.
+ \include qbytearray.cpp array-grow-at-insertion
- If \a i is greater than size(), the array is first extended using
- resize().
+ \sa append(), prepend(), replace(), remove()
*/
-QByteArray &QByteArray::insert(int i, const char *str)
-{
- return qbytearray_insert(this, i, str, qstrlen(str));
-}
+/*!
+ \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
- Inserts \a len bytes, starting at \a str, at position \a i in the byte
+ 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
*/
-QByteArray &QByteArray::insert(int i, const char *str, int len)
-{
- return qbytearray_insert(this, i, str, len);
-}
-
/*!
+ \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.
-QByteArray &QByteArray::insert(int i, char ch)
-{
- return qbytearray_insert(this, i, &ch, 1);
-}
+ \include qbytearray.cpp array-grow-at-insertion
+*/
-/*! \fn QByteArray &QByteArray::insert(int i, int count, char ch)
+/*! \fn QByteArray &QByteArray::insert(qsizetype i, qsizetype count, char ch)
\overload
\since 5.7
@@ -1992,22 +2317,26 @@ QByteArray &QByteArray::insert(int i, char ch)
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(int i, int count, char ch)
+QByteArray &QByteArray::insert(qsizetype i, qsizetype count, char ch)
{
if (i < 0 || count <= 0)
return *this;
- int oldsize = size();
- resize(qMax(i, oldsize) + count);
- char *dst = d.data();
- if (i > oldsize)
- ::memset(dst + oldsize, 0x20, i - oldsize);
- else if (i < oldsize)
- ::memmove(dst + i + count, dst + i, oldsize - i);
- ::memset(dst + i, ch, count);
+ 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;
+ }
+
+ d->insert(i, count, ch);
+ d.data()[d.size] = '\0';
return *this;
}
@@ -2022,24 +2351,77 @@ QByteArray &QByteArray::insert(int i, int 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(int pos, int len)
+QByteArray &QByteArray::remove(qsizetype pos, qsizetype len)
{
- if (len <= 0 || uint(pos) >= uint(size()))
+ if (len <= 0 || pos < 0 || size_t(pos) >= size_t(size()))
return *this;
- detach();
- if (len >= size() - pos) {
- resize(pos);
+ 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 {
- memmove(d.data() + pos, d.data() + pos + len, size() - pos - len);
- resize(size() - len);
+ 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.
@@ -2049,35 +2431,27 @@ QByteArray &QByteArray::remove(int pos, int len)
\sa insert(), remove()
*/
-QByteArray &QByteArray::replace(int pos, int len, const QByteArray &after)
+QByteArray &QByteArray::replace(qsizetype pos, qsizetype len, QByteArrayView after)
{
+ 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 {
- QByteArray copy(after);
// ### optimize me
remove(pos, len);
- return insert(pos, copy);
+ return insert(pos, after);
}
}
-/*! \fn QByteArray &QByteArray::replace(int pos, int len, const char *after)
-
- \overload
-
- Replaces \a len bytes from index position \a pos with the
- '\\0'-terminated string \a after.
-
- Notice: this can change the length of the byte array.
-*/
-QByteArray &QByteArray::replace(int pos, int len, const char *after)
-{
- return replace(pos,len,after,qstrlen(after));
-}
-
-/*! \fn QByteArray &QByteArray::replace(int pos, int len, const char *after, int alen)
+/*! \fn QByteArray &QByteArray::replace(qsizetype pos, qsizetype len, const char *after, qsizetype alen)
\overload
@@ -2086,83 +2460,51 @@ QByteArray &QByteArray::replace(int pos, int len, const char *after)
\since 4.7
*/
-QByteArray &QByteArray::replace(int pos, int len, const char *after, int alen)
-{
- if (len == alen && (pos + len <= size())) {
- detach();
- memcpy(d.data() + pos, after, len*sizeof(char));
- return *this;
- } else {
- remove(pos, len);
- return qbytearray_insert(this, pos, after, alen);
- }
-}
-
-// ### optimize all other replace method, by offering
-// QByteArray::replace(const char *before, int blen, const char *after, int alen)
/*!
+ \fn QByteArray &QByteArray::replace(const char *before, qsizetype bsize, const char *after, qsizetype asize)
\overload
- Replaces every occurrence of the byte array \a before with the
- byte array \a after.
-
- Example:
- \snippet code/src_corelib_text_qbytearray.cpp 20
+ Replaces every occurrence of the \a bsize bytes starting at \a before with
+ the \a asize bytes starting at \a after. Since the sizes of the strings are
+ given by \a bsize and \a asize, they may contain '\\0' bytes and do not need
+ to be '\\0'-terminated.
*/
-QByteArray &QByteArray::replace(const QByteArray &before, const QByteArray &after)
-{
- return replace(before.constData(), before.size(), after.constData(), after.size());
-}
-
/*!
- \fn QByteArray &QByteArray::replace(const char *before, const QByteArray &after)
\overload
+ \since 6.0
- Replaces every occurrence of the '\\0'-terminated string \a before with the
+ Replaces every occurrence of the byte array \a before with the
byte array \a after.
-*/
-
-QByteArray &QByteArray::replace(const char *c, const QByteArray &after)
-{
- return replace(c, qstrlen(c), after.constData(), after.size());
-}
-/*!
- \fn QByteArray &QByteArray::replace(const char *before, int bsize, const char *after, int asize)
- \overload
-
- Replaces every occurrence of the \a bsize bytes starting at \a before with
- the \asize bytes starting at \a after. Since the sizes of the strings are
- given by \a bsize and \a asize, they may contain '\\0' bytes and do not need
- to be '\\0'-terminated.
+ Example:
+ \snippet code/src_corelib_text_qbytearray.cpp 20
*/
-QByteArray &QByteArray::replace(const char *before, int bsize, const char *after, int asize)
+QByteArray &QByteArray::replace(QByteArrayView before, QByteArrayView after)
{
- if (isNull() || (before == after && bsize == asize))
+ const char *b = before.data();
+ qsizetype bsize = before.size();
+ const char *a = after.data();
+ qsizetype asize = after.size();
+
+ if (isNull() || (b == a && bsize == asize))
return *this;
// protect against before or after being part of this
- const char *a = after;
- const char *b = before;
- if (after >= constBegin() && after < constEnd()) {
- char *copy = (char *)malloc(asize);
- Q_CHECK_PTR(copy);
- memcpy(copy, after, asize);
- a = copy;
+ if (QtPrivate::q_points_into_range(a, d)) {
+ QVarLengthArray copy(a, a + asize);
+ return replace(before, QByteArrayView{copy});
}
- if (before >= constBegin() && before < constEnd()) {
- char *copy = (char *)malloc(bsize);
- Q_CHECK_PTR(copy);
- memcpy(copy, before, bsize);
- b = copy;
+ if (QtPrivate::q_points_into_range(b, d)) {
+ QVarLengthArray copy(b, b + bsize);
+ return replace(QByteArrayView{copy}, after);
}
- QByteArrayMatcher matcher(before, bsize);
- int index = 0;
- int len = size();
+ QByteArrayMatcher matcher(b, bsize);
+ qsizetype index = 0;
+ qsizetype len = size();
char *d = data(); // detaches
if (bsize == asize) {
@@ -2173,12 +2515,12 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after
}
}
} else if (asize < bsize) {
- uint to = 0;
- uint movestart = 0;
- uint num = 0;
+ size_t to = 0;
+ size_t movestart = 0;
+ size_t num = 0;
while ((index = matcher.indexIn(*this, index)) != -1) {
if (num) {
- int msize = index - movestart;
+ qsizetype msize = index - movestart;
if (msize > 0) {
memmove(d + to, d + movestart, msize);
to += msize;
@@ -2195,7 +2537,7 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after
num++;
}
if (num) {
- int msize = len - movestart;
+ qsizetype msize = len - movestart;
if (msize > 0)
memmove(d + to, d + movestart, msize);
resize(len - num*(bsize-asize));
@@ -2204,8 +2546,8 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after
// the most complex case. We don't want to lose performance by doing repeated
// copies and reallocs of the data.
while (index != -1) {
- uint indices[4096];
- uint pos = 0;
+ size_t indices[4096];
+ size_t pos = 0;
while(pos < 4095) {
index = matcher.indexIn(*this, index);
if (index == -1)
@@ -2220,12 +2562,12 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after
break;
// we have a table of replacement positions, use them for fast replacing
- int adjust = pos*(asize-bsize);
+ qsizetype adjust = pos*(asize-bsize);
// index has to be adjusted in case we get back into the loop above.
if (index != -1)
index += adjust;
- int newlen = len + adjust;
- int moveend = len;
+ qsizetype newlen = len + adjust;
+ qsizetype moveend = len;
if (newlen > len) {
resize(newlen);
len = newlen;
@@ -2234,9 +2576,9 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after
while(pos) {
pos--;
- int movestart = indices[pos] + bsize;
- int insertstart = indices[pos] + pos*(asize-bsize);
- int moveto = insertstart + asize;
+ qsizetype movestart = indices[pos] + bsize;
+ qsizetype insertstart = indices[pos] + pos*(asize-bsize);
+ qsizetype moveto = insertstart + asize;
memmove(d + moveto, d + movestart, (moveend - movestart));
if (asize)
memcpy(d + insertstart, a, asize);
@@ -2244,54 +2586,17 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after
}
}
}
-
- if (a != after)
- ::free(const_cast<char *>(a));
- if (b != before)
- ::free(const_cast<char *>(b));
-
-
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
Replaces every occurrence of the byte \a before with the byte array \a
after.
*/
-QByteArray &QByteArray::replace(char before, const QByteArray &after)
-{
- char b[2] = { before, '\0' };
- return replace(b, 1, after.constData(), after.size());
-}
-
-/*! \fn QByteArray &QByteArray::replace(char before, const char *after)
-
- \overload
-
- Replaces every occurrence of the byte \a before with the '\\0'-terminated
- string \a after.
-*/
-
/*!
\overload
@@ -2300,12 +2605,11 @@ QByteArray &QByteArray::replace(char before, const QByteArray &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;
}
@@ -2320,8 +2624,8 @@ QByteArray &QByteArray::replace(char before, char after)
QList<QByteArray> QByteArray::split(char sep) const
{
QList<QByteArray> list;
- int start = 0;
- int end;
+ qsizetype start = 0;
+ qsizetype end;
while ((end = indexOf(sep, start)) != -1) {
list.append(mid(start, end - start));
start = end + 1;
@@ -2341,7 +2645,7 @@ QList<QByteArray> QByteArray::split(char sep) const
\snippet code/src_corelib_text_qbytearray.cpp 49
*/
-QByteArray QByteArray::repeated(int times) const
+QByteArray QByteArray::repeated(qsizetype times) const
{
if (isEmpty())
return *this;
@@ -2352,7 +2656,7 @@ QByteArray QByteArray::repeated(int times) const
return QByteArray();
}
- const int resultSize = times * size();
+ const qsizetype resultSize = times * size();
QByteArray result;
result.reserve(resultSize);
@@ -2361,10 +2665,10 @@ QByteArray QByteArray::repeated(int times) const
memcpy(result.d.data(), data(), size());
- int sizeSoFar = size();
+ qsizetype sizeSoFar = size();
char *end = result.d.data() + sizeSoFar;
- const int halfResultSize = resultSize >> 1;
+ const qsizetype halfResultSize = resultSize >> 1;
while (sizeSoFar <= halfResultSize) {
memcpy(end, result.d.data(), sizeSoFar);
end += sizeSoFar;
@@ -2378,64 +2682,49 @@ QByteArray QByteArray::repeated(int 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
-/*!
- Returns the index position of the first occurrence of the byte
- array \a ba in this byte array, searching forward from index
- position \a from. Returns -1 if \a ba could not be found.
-
- Example:
- \snippet code/src_corelib_text_qbytearray.cpp 21
-
- \sa lastIndexOf(), contains(), count()
-*/
-
-int QByteArray::indexOf(const QByteArray &ba, int from) const
+qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept
{
- const int ol = ba.size();
- if (ol == 0)
- return from;
+ const auto ol = needle.size();
+ 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 indexOf(ba[0], from);
+ return findByteArray(haystack, from, needle.front());
- const int l = size();
if (from > l || ol + from > l)
return -1;
- return static_cast<int>(qFindByteArray(data(), size(), from, ba.data(), ol));
+ return qFindByteArray(haystack.data(), haystack.size(), from, needle.data(), ol);
}
-/*! \fn int QByteArray::indexOf(const char *str, int from) const
-
- \overload
+/*! \fn qsizetype QByteArray::indexOf(QByteArrayView bv, qsizetype from) const
+ \since 6.0
- Returns the index position of the first occurrence of the '\\0'-terminated
- string \a str in the byte array, searching forward from index position \a
- from. Returns -1 if \a str could not be found.
-*/
-int QByteArray::indexOf(const char *c, int from) const
-{
- const int ol = qstrlen(c);
- if (ol == 1)
- return indexOf(*c, from);
+ Returns the index position of the start of the first occurrence of the
+ sequence of bytes viewed by \a bv in this byte array, searching forward
+ from index position \a from. Returns -1 if no match is found.
- const int l = size();
- if (from > l || ol + from > l)
- return -1;
- if (ol == 0)
- return from;
+ Example:
+ \snippet code/src_corelib_text_qbytearray.cpp 21
- return static_cast<int>(qFindByteArray(data(), size(), from, c, ol));
-}
+ \sa lastIndexOf(), contains(), count()
+*/
/*!
+ \fn qsizetype QByteArray::indexOf(char ch, qsizetype from) const
\overload
- Returns the index position of the first occurrence of the byte \a ch in the
- byte array, searching forward from index position \a from. Returns -1 if \a
- ch could not be found.
+ Returns the index position of the start of the first occurrence of the
+ byte \a ch in this byte array, searching forward from index position \a from.
+ Returns -1 if no match is found.
Example:
\snippet code/src_corelib_text_qbytearray.cpp 22
@@ -2443,20 +2732,6 @@ int QByteArray::indexOf(const char *c, int from) const
\sa lastIndexOf(), contains()
*/
-int QByteArray::indexOf(char ch, int from) const
-{
- if (from < 0)
- from = qMax(from + size(), 0);
- if (from < size()) {
- const char *n = data() + from - 1;
- const char *e = end();
- while (++n != e)
- if (*n == ch)
- return n - data();
- }
- return -1;
-}
-
static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char *needle,
qsizetype ol, qsizetype from)
{
@@ -2491,53 +2766,90 @@ static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char
}
-/*!
- \fn int QByteArray::lastIndexOf(const QByteArray &ba, int from) const
+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())
+ from = haystack.size() - 1;
+ if (from >= 0) {
+ const char *b = haystack.data();
+ const char *n = b + from + 1;
+ while (n-- != b) {
+ if (*n == needle)
+ return n - b;
+ }
+ }
+ return -1;
+}
- Returns the index position of the last occurrence of the byte array \a ba 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 \a ba could not be found.
+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()) {
+ if (needle.isEmpty() && from == 0)
+ return 0;
+ return -1;
+ }
+ const auto ol = needle.size();
+ if (ol == 1)
+ return lastIndexOfCharHelper(haystack, from, needle.front());
+
+ return lastIndexOfHelper(haystack.data(), haystack.size(), needle.data(), ol, from);
+}
+
+/*! \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.
+
+ \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()
*/
-int QByteArray::lastIndexOf(const QByteArray &ba, int from) const
-{
- const int ol = ba.size();
- if (ol == 1)
- return lastIndexOf(ba[0], from);
+/*! \fn qsizetype QByteArray::lastIndexOf(QByteArrayView bv) const
+ \since 6.2
+ \overload
- return lastIndexOfHelper(data(), size(), ba.data(), ol, from);
-}
+ 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.
-/*! \fn int QByteArray::lastIndexOf(const char *str, int from) const
- \overload
+ Example:
+ \snippet code/src_corelib_text_qbytearray.cpp 23
- Returns the index position of the last occurrence of the '\\0'-terminated
- string \a str in the 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 \a str could not be found.
+ \sa indexOf(), contains(), count()
*/
-int QByteArray::lastIndexOf(const char *str, int from) const
-{
- const int ol = qstrlen(str);
- if (ol == 1)
- return lastIndexOf(*str, from);
-
- return lastIndexOfHelper(data(), size(), str, ol, from);
-}
/*!
+ \fn qsizetype QByteArray::lastIndexOf(char ch, qsizetype from) const
\overload
- Returns the index position of the last occurrence of byte \a ch in the 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 \a ch could not be 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
@@ -2545,55 +2857,45 @@ int QByteArray::lastIndexOf(const char *str, int from) const
\sa indexOf(), contains()
*/
-int QByteArray::lastIndexOf(char ch, int from) const
+static inline qsizetype countCharHelper(QByteArrayView haystack, char needle) noexcept
{
- if (from < 0)
- from += size();
- else if (from > size())
- from = size()-1;
- if (from >= 0) {
- const char *b = data();
- const char *n = b + from + 1;
- while (n-- != b)
- if (*n == ch)
- return n - b;
+ qsizetype num = 0;
+ for (char ch : haystack) {
+ if (ch == needle)
+ ++num;
}
- return -1;
+ return num;
}
-/*!
- Returns the number of (potentially overlapping) occurrences of
- byte array \a ba in this byte array.
+qsizetype QtPrivate::count(QByteArrayView haystack, QByteArrayView needle) noexcept
+{
+ if (needle.size() == 0)
+ return haystack.size() + 1;
- \sa contains(), indexOf()
-*/
+ if (needle.size() == 1)
+ return countCharHelper(haystack, needle[0]);
-int QByteArray::count(const QByteArray &ba) const
-{
- int num = 0;
- int i = -1;
- if (size() > 500 && ba.size() > 5) {
- QByteArrayMatcher matcher(ba);
- while ((i = matcher.indexIn(*this, i + 1)) != -1)
+ qsizetype num = 0;
+ qsizetype i = -1;
+ if (haystack.size() > 500 && needle.size() > 5) {
+ QByteArrayMatcher matcher(needle);
+ while ((i = matcher.indexIn(haystack, i + 1)) != -1)
++num;
} else {
- while ((i = indexOf(ba, i + 1)) != -1)
+ while ((i = haystack.indexOf(needle, i + 1)) != -1)
++num;
}
return num;
}
-/*!
- \overload
+/*! \fn qsizetype QByteArray::count(QByteArrayView bv) const
+ \since 6.0
- Returns the number of (potentially overlapping) occurrences of
- '\\0'-terminated string \a str in the byte array.
-*/
+ Returns the number of (potentially overlapping) occurrences of the
+ sequence of bytes viewed by \a bv in this byte array.
-int QByteArray::count(const char *str) const
-{
- return count(fromRawData(str, qstrlen(str)));
-}
+ \sa contains(), indexOf()
+*/
/*!
\overload
@@ -2603,138 +2905,90 @@ int QByteArray::count(const char *str) const
\sa contains(), indexOf()
*/
-int QByteArray::count(char ch) const
+qsizetype QByteArray::count(char ch) const
{
- int num = 0;
- const char *i = end();
- const char *b = begin();
- while (i != b)
- if (*--i == ch)
- ++num;
- return num;
+ return countCharHelper(*this, ch);
}
-/*! \fn int QByteArray::count() const
-
+#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(const char *c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \since 5.12
+ \fn int QByteArray::compare(QByteArrayView bv, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ \since 6.0
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
- '\\0'-terminated string \a c. The comparison is performed according to case
+ QByteArrayView \a bv. The comparison is performed according to case
sensitivity \a cs.
- \sa operator==
+ \sa operator==, {Character Case}
*/
-/*!
- \fn int QByteArray::compare(const QByteArray &a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \overload
- \since 5.12
-
- 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
- QByteArray \a a. The comparison is performed according to case sensitivity
- \a cs.
+bool QtPrivate::startsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
+{
+ if (haystack.size() < needle.size())
+ return false;
+ if (haystack.data() == needle.data() || needle.size() == 0)
+ return true;
+ return memcmp(haystack.data(), needle.data(), needle.size()) == 0;
+}
- \sa operator==
-*/
+/*! \fn bool QByteArray::startsWith(QByteArrayView bv) const
+ \since 6.0
-/*!
- Returns \c true if this byte array starts with byte array \a ba;
- otherwise returns \c false.
+ Returns \c true if this byte array starts with the sequence of bytes
+ viewed by \a bv; otherwise returns \c false.
Example:
\snippet code/src_corelib_text_qbytearray.cpp 25
- \sa endsWith(), left()
+ \sa endsWith(), first()
*/
-bool QByteArray::startsWith(const QByteArray &ba) const
-{
- if (size() < ba.size())
- return false;
- if (data() == ba.data() || ba.size() == 0)
- return true;
- return memcmp(data(), ba.data(), ba.size()) == 0;
-}
-/*! \overload
-
- Returns \c true if this byte array starts with '\\0'-terminated string \a
- str; otherwise returns \c false.
-*/
-bool QByteArray::startsWith(const char *str) const
-{
- if (!str || !*str)
- return true;
- const int len = int(strlen(str));
- if (size() < len)
- return false;
- return qstrncmp(data(), str, len) == 0;
-}
-
-/*! \overload
+/*!
+ \fn bool QByteArray::startsWith(char ch) const
+ \overload
Returns \c true if this byte array starts with byte \a ch; otherwise returns
\c false.
*/
-bool QByteArray::startsWith(char ch) const
+
+bool QtPrivate::endsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
{
- if (size() == 0)
+ if (haystack.size() < needle.size())
return false;
- return data()[0] == ch;
+ if (haystack.end() == needle.end() || needle.size() == 0)
+ return true;
+ return memcmp(haystack.end() - needle.size(), needle.data(), needle.size()) == 0;
}
/*!
- Returns \c true if this byte array ends with byte array \a ba;
- otherwise returns \c false.
+ \fn bool QByteArray::endsWith(QByteArrayView bv) const
+ \since 6.0
+
+ Returns \c true if this byte array ends with the sequence of bytes
+ viewed by \a bv; otherwise returns \c false.
Example:
\snippet code/src_corelib_text_qbytearray.cpp 26
- \sa startsWith(), right()
-*/
-bool QByteArray::endsWith(const QByteArray &ba) const
-{
- if (size() < ba.size())
- return false;
- if (end() == ba.end() || ba.size() == 0)
- return true;
- return memcmp(end() - ba.size(), ba.data(), ba.size()) == 0;
-}
-
-/*! \overload
-
- Returns \c true if this byte array ends with '\\0'-terminated string \a str;
- otherwise returns \c false.
+ \sa startsWith(), last()
*/
-bool QByteArray::endsWith(const char *str) const
-{
- if (!str || !*str)
- return true;
- const int len = int(strlen(str));
- if (size() < len)
- return false;
- return qstrncmp(end() - len, str, len) == 0;
-}
-/*! \overload
+/*!
+ \fn bool QByteArray::endsWith(char ch) const
+ \overload
Returns \c true if this byte array ends with byte \a ch;
otherwise returns \c false.
*/
-bool QByteArray::endsWith(char ch) const
-{
- if (size() == 0)
- return false;
- return data()[size() - 1] == ch;
-}
/*
Returns true if \a c is an uppercase ASCII letter.
@@ -2744,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 (int 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 (int 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(int 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(int 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(int pos, int len) const
+QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const &
{
qsizetype p = pos;
qsizetype l = len;
@@ -2872,43 +3109,68 @@ QByteArray QByteArray::mid(int pos, int len) const
return QByteArray();
case QContainerImplHelper::Empty:
{
- auto alloc = Data::allocate(0);
- QByteArray::DataPointer empty = { alloc.first, alloc.second, 0 };
- return QByteArray(empty);
+ return QByteArray(DataPointer::fromRawData(&_empty, 0));
}
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(), from(), 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(), from(), 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
@@ -2917,23 +3179,66 @@ QByteArray QByteArray::mid(int pos, int len) const
\note The behavior is undefined when \a pos < 0, \a n < 0,
or \a pos + \a n > size().
- \sa first(), last(), from(), 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::from(qsizetype pos) const
+ \fn QByteArray QByteArray::sliced(qsizetype pos) const &
+ \fn QByteArray QByteArray::sliced(qsizetype pos) &&
\since 6.0
+ \overload
Returns a byte array containing the bytes starting at position \a pos
in this object, and extending to the end of this object.
\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::chopped(int len) const
+ \fn QByteArray &QByteArray::slice(qsizetype pos)
+ \since 6.8
+ \overload
+
+ Modifies this byte array to start at position \a pos, extending to its
+ end, and returns a reference to this byte array.
+
+ \note The behavior is undefined if \a pos < 0 or \a pos > size().
+
+ \sa sliced(), first(), last(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QByteArray QByteArray::chopped(qsizetype len) const &
+ \fn QByteArray QByteArray::chopped(qsizetype len) &&
\since 5.10
Returns a byte array that contains the leftmost size() - \a len bytes of
@@ -2941,7 +3246,7 @@ QByteArray QByteArray::mid(int pos, int 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()
*/
/*!
@@ -2956,11 +3261,7 @@ QByteArray QByteArray::mid(int pos, int 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
@@ -3031,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
@@ -3044,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());
@@ -3061,16 +3362,24 @@ 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 {
- int blockSize = qMin(Step, len - allocated);
+ qsizetype blockSize = qMin(Step, len - allocated);
ba.resize(allocated + blockSize);
if (in.readRawData(ba.data() + allocated, blockSize) != blockSize) {
ba.clear();
@@ -3084,205 +3393,169 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
}
#endif // QT_NO_DATASTREAM
-/*! \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
@@ -3291,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
@@ -3300,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
@@ -3309,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
@@ -3318,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
@@ -3383,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
@@ -3402,11 +3680,11 @@ QByteArray QByteArray::trimmed_helper(QByteArray &a)
\sa rightJustified()
*/
-QByteArray QByteArray::leftJustified(int width, char fill, bool truncate) const
+QByteArray QByteArray::leftJustified(qsizetype width, char fill, bool truncate) const
{
QByteArray result;
- int len = size();
- int padlen = width - len;
+ qsizetype len = size();
+ qsizetype padlen = width - len;
if (padlen > 0) {
result.resize(len+padlen);
if (len)
@@ -3439,11 +3717,11 @@ QByteArray QByteArray::leftJustified(int width, char fill, bool truncate) const
\sa leftJustified()
*/
-QByteArray QByteArray::rightJustified(int width, char fill, bool truncate) const
+QByteArray QByteArray::rightJustified(qsizetype width, char fill, bool truncate) const
{
QByteArray result;
- int len = size();
- int padlen = width - len;
+ qsizetype len = size();
+ qsizetype padlen = width - len;
if (padlen > 0) {
result.resize(len+padlen);
if (len)
@@ -3458,41 +3736,38 @@ QByteArray QByteArray::rightJustified(int width, char fill, bool truncate) const
return result;
}
-bool QByteArray::isNull() const
+auto QtPrivate::toSignedInteger(QByteArrayView data, int base) -> ParsedNumber<qlonglong>
{
- return d->isNull();
-}
-
-static qlonglong toIntegral_helper(const char *data, bool *ok, int base, 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.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 {};
}
/*!
@@ -3502,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.
@@ -3514,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);
}
/*!
@@ -3529,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.
@@ -3541,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);
}
/*!
@@ -3556,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.
@@ -3570,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);
}
/*!
@@ -3585,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.
@@ -3597,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);
}
/*!
@@ -3614,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.
@@ -3628,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);
}
/*!
@@ -3644,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.
@@ -3656,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);
}
/*!
@@ -3669,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.
@@ -3682,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);
}
/*!
@@ -3696,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.
@@ -3709,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.
@@ -3745,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 {};
}
/*!
@@ -3784,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
@@ -3797,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 = '=';
- int padlen = 0;
+ constexpr char padchar = '=';
+ qsizetype padlen = 0;
- QByteArray tmp((size() + 2) / 3 * 4, Qt::Uninitialized);
+ const qsizetype sz = size();
- int i = 0;
+ 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++]));
@@ -3852,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
@@ -3910,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;
@@ -3927,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 {
@@ -3951,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);
@@ -3963,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
@@ -4118,42 +4392,43 @@ 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));
}
/*!
+ \fn QByteArray QByteArray::fromRawData(const char *data, qsizetype size) constexpr
+
Constructs a QByteArray that uses the first \a size bytes of the
\a data array. The bytes are \e not copied. The QByteArray will
contain the \a data pointer. The caller guarantees that \a data
@@ -4187,18 +4462,6 @@ QByteArray QByteArray::number(double n, char f, int prec)
\sa setRawData(), data(), constData()
*/
-QByteArray QByteArray::fromRawData(const char *data, int size)
-{
- QByteArray::DataPointer x;
- if (!data) {
- } else if (!size) {
- x = DataPointer(Data::allocate(0), 0);
- } else {
- x = Data::fromRawData(data, size);
- }
- return QByteArray(x);
-}
-
/*!
\since 4.7
@@ -4213,17 +4476,12 @@ QByteArray QByteArray::fromRawData(const char *data, int size)
\sa fromRawData(), data(), constData()
*/
-QByteArray &QByteArray::setRawData(const char *data, uint size)
+QByteArray &QByteArray::setRawData(const char *data, qsizetype size)
{
- if (!data || !size) {
+ if (!data || !size)
clear();
- }
-// else if (d->isShared() || (d->flags() & Data::RawDataType) == 0) {
+ else
*this = fromRawData(data, size);
-// } else {
-// d.size = size;
-// d.data() = const_cast<char *>(data);
-// }
return *this;
}
@@ -4338,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 };
}
@@ -4354,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 };
}
@@ -4390,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:
@@ -4406,7 +4664,7 @@ QByteArray QByteArray::fromHex(const QByteArray &hexEncoded)
uchar *result = (uchar *)res.data() + res.size();
bool odd_digit = true;
- for (int i = hexEncoded.size() - 1; i >= 0; --i) {
+ for (qsizetype i = hexEncoded.size() - 1; i >= 0; --i) {
uchar ch = uchar(hexEncoded.at(i));
int tmp = QtMiscUtils::fromHex(ch);
if (tmp == -1)
@@ -4425,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
@@ -4441,11 +4702,11 @@ QByteArray QByteArray::toHex(char separator) const
if (isEmpty())
return QByteArray();
- const int length = separator ? (size() * 3 - 1) : (size() * 2);
+ const qsizetype length = separator ? (size() * 3 - 1) : (size() * 2);
QByteArray hex(length, Qt::Uninitialized);
char *hexData = hex.data();
const uchar *data = (const uchar *)this->data();
- for (int i = 0, o = 0; i < size(); ++i) {
+ for (qsizetype i = 0, o = 0; i < size(); ++i) {
hexData[o++] = QtMiscUtils::toHexLower(data[i] >> 4);
hexData[o++] = QtMiscUtils::toHexLower(data[i] & 0xf);
@@ -4463,9 +4724,9 @@ static void q_fromPercentEncoding(QByteArray *ba, char percent)
char *data = ba->data();
const char *inputPtr = data;
- int i = 0;
- int len = ba->count();
- int outlen = 0;
+ qsizetype i = 0;
+ qsizetype len = ba->size();
+ qsizetype outlen = 0;
int a, b;
char c;
while (i < len) {
@@ -4495,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
@@ -4516,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
@@ -4535,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
@@ -4548,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;
- int len = input.count();
- const char *inputData = input.constData();
- char *output = nullptr;
- int length = 0;
-
- for (int 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()));
}
/*!
@@ -4644,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
*/
@@ -4757,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
@@ -4809,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.
@@ -4820,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.
*/
/*!
@@ -4837,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