summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSona Kurazyan <sona.kurazyan@qt.io>2020-06-07 18:41:41 +0200
committerSona Kurazyan <sona.kurazyan@qt.io>2020-07-08 08:45:49 +0200
commit631127126cc14e7c01cc611532b3256b58785670 (patch)
treea89608313761f045129f6579d5c96d781d64ff31
parenta55e938fb41dfb781cdef6a4e24961a272d2dbab (diff)
Introduce QByteArrayView
Created a QByteArrayView in symmetry with QStringView. Added the basic tests symmetrical to QStringView tests. Moved the implementations of non-modifying methods of QByteArray to namespace QtPrivate, to be reused inline from both QByteArray and QByteArrayView. Changed QByteArray's counterparts of those methods to take QByteArrayView as argument instead of QByteArray. Removed QByteArray's operator QNoImplicitBoolCast(), because it was causing ambiguity when calling those methods with QByteArray argument (it was there to perevnt if(!ba)/if(ba) from compiling, but currently that would be ambiguous and won't compile anyway). [ChangeLog][QtCore][QByteArrayView] New class. Task-number: QTBUG-84321 Change-Id: I05f92e654cf65c95f2bb31b9c9018746ac110426 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r--src/corelib/CMakeLists.txt2
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_text_qbytearray.cpp4
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_text_qbytearrayview.cpp67
-rw-r--r--src/corelib/global/qglobal.h2
-rw-r--r--src/corelib/text/qbytearray.cpp388
-rw-r--r--src/corelib/text/qbytearray.h82
-rw-r--r--src/corelib/text/qbytearrayalgorithms.h76
-rw-r--r--src/corelib/text/qbytearrayview.h313
-rw-r--r--src/corelib/text/qbytearrayview.qdoc692
-rw-r--r--src/corelib/text/text.pri2
-rw-r--r--src/corelib/tools/qhash.cpp12
-rw-r--r--src/corelib/tools/qhashfunctions.h1
-rw-r--r--src/tools/moc/generator.cpp6
-rw-r--r--src/tools/uic/qclass_lib_map.h1
-rw-r--r--tests/auto/corelib/text/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/text/qbytearrayview/CMakeLists.txt10
-rw-r--r--tests/auto/corelib/text/qbytearrayview/qbytearrayview.pro4
-rw-r--r--tests/auto/corelib/text/qbytearrayview/tst_qbytearrayview.cpp595
-rw-r--r--tests/auto/corelib/text/text.pro1
19 files changed, 1960 insertions, 299 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index 9d6eb3d908..bb697f23f4 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -154,8 +154,10 @@ qt_add_module(Core
statemachine/qstate.cpp statemachine/qstate.h statemachine/qstate_p.h
statemachine/qstatemachine.cpp statemachine/qstatemachine.h statemachine/qstatemachine_p.h
text/qbytearray.cpp text/qbytearray.h text/qbytearray_p.h
+ text/qbytearrayalgorithms.h
text/qbytearraylist.cpp text/qbytearraylist.h
text/qbytearraymatcher.cpp text/qbytearraymatcher.h
+ text/qbytearrayview.h
text/qbytedata_p.h
text/qchar.h
text/qcollator.cpp text/qcollator.h text/qcollator_p.h
diff --git a/src/corelib/doc/snippets/code/src_corelib_text_qbytearray.cpp b/src/corelib/doc/snippets/code/src_corelib_text_qbytearray.cpp
index 9c07a2e92c..74f14f2a4b 100644
--- a/src/corelib/doc/snippets/code/src_corelib_text_qbytearray.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_text_qbytearray.cpp
@@ -224,7 +224,7 @@ ba.replace(QByteArray("ou"), QByteArray("o"));
//! [21]
QByteArray x("sticky question");
-QByteArray y("sti");
+QByteArrayView y("sti");
x.indexOf(y); // returns 0
x.indexOf(y, 1); // returns 10
x.indexOf(y, 10); // returns 10
@@ -243,7 +243,7 @@ ba.indexOf("X"); // returns -1
//! [23]
QByteArray x("crazy azimuths");
-QByteArray y("az");
+QByteArrayView y("az");
x.lastIndexOf(y); // returns 6
x.lastIndexOf(y, 6); // returns 6
x.lastIndexOf(y, 5); // returns 2
diff --git a/src/corelib/doc/snippets/code/src_corelib_text_qbytearrayview.cpp b/src/corelib/doc/snippets/code/src_corelib_text_qbytearrayview.cpp
new file mode 100644
index 0000000000..31a2107c62
--- /dev/null
+++ b/src/corelib/doc/snippets/code/src_corelib_text_qbytearrayview.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/qbytearrayview.h>
+
+//! [0]
+ void myfun1(QByteArrayView bv); // preferred
+ void myfun2(const QByteArrayView &bv); // compiles and works, but slower
+//! [0]
+
+//! [1]
+ void fun(QByteArrayView bv);
+ void fun(char ch) { fun(QByteArrayView(&ch, 1)); }
+//! [1]
+
+void wrapper() {
+ const char array[1] = { 0 };
+//! [2]
+ auto bv = QByteArrayView(array, std::size(array)); // using C++17 std::size()
+//! [2]
+}
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index 5065a2716f..539e3e7cda 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -598,8 +598,6 @@ using qsizetype = QIntegerForSizeof<std::size_t>::Signed;
# define QT_WIN_CALLBACK CALLBACK QT_ENSURE_STACK_ALIGNED_FOR_SSE
#endif
-typedef int QNoImplicitBoolCast;
-
/*
Utility macros and inline functions
*/
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index 375c64a90c..c498aa30a6 100644
--- a/src/corelib/text/qbytearray.cpp
+++ b/src/corelib/text/qbytearray.cpp
@@ -408,47 +408,16 @@ 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)
-{
- 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;
- }
-
- // 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;
-}
-
-/*!
- \internal
- ### Qt6: replace the QByteArray parameter with [pointer,len] pair
- */
-int qstrcmp(const QByteArray &str1, const QByteArray &str2)
+int QtPrivate::compareMemory(QByteArrayView lhs, QByteArrayView rhs)
{
- int l1 = str1.length();
- int l2 = str2.length();
- int ret = memcmp(str1.constData(), str2.constData(), qMin(l1, l2));
+ int ret = memcmp(lhs.data(), rhs.data(), qMin(lhs.size(), rhs.size()));
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 lhs.size() == rhs.size() ? 0 : lhs.size() > rhs.size() ? 1 : -1;
}
// the CRC table below is created by the following piece of code
@@ -911,7 +880,7 @@ QByteArray qUncompress(const uchar* data, int nbytes)
This issue does not apply to \l{QString}s since they represent characters
using Unicode.
- \sa QString, QBitArray
+ \sa QByteArrayView, QString, QBitArray
*/
/*!
@@ -1446,22 +1415,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
@@ -2388,61 +2350,54 @@ QByteArray QByteArray::repeated(int times) const
hashHaystack -= (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()
-*/
+static inline qsizetype findCharHelper(QByteArrayView haystack, qsizetype from, char needle) noexcept
+{
+ if (from < 0)
+ from = qMax(from + haystack.size(), qsizetype(0));
+ if (from < haystack.size()) {
+ const char *const b = haystack.data();
+ if (const auto n = static_cast<const char *>(
+ memchr(b + from, needle, static_cast<size_t>(haystack.size() - from)))) {
+ return n - b;
+ }
+ }
+ return -1;
+}
-int QByteArray::indexOf(const QByteArray &ba, int from) const
+qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept
{
- const int ol = ba.size();
+ const auto ol = needle.size();
if (ol == 0)
return from;
if (ol == 1)
- return indexOf(ba[0], from);
+ return findCharHelper(haystack, from, needle.front());
- const int l = size();
+ const auto l = haystack.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 int QByteArray::indexOf(QByteArrayView bv, int 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()
+*/
/*!
\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
@@ -2452,16 +2407,7 @@ int QByteArray::indexOf(const char *c, int from) const
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;
+ return static_cast<int>(findCharHelper(*this, from, ch));
}
static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char *needle,
@@ -2498,57 +2444,55 @@ static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char
}
-/*!
- \fn int QByteArray::lastIndexOf(const QByteArray &ba, int from) const
-
- 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.
-
- Example:
- \snippet code/src_corelib_text_qbytearray.cpp 23
-
- \sa indexOf(), contains(), count()
-*/
+static inline qsizetype lastIndexOfCharHelper(QByteArrayView haystack, qsizetype from, char needle) noexcept
+{
+ 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;
+}
-int QByteArray::lastIndexOf(const QByteArray &ba, int from) const
+qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept
{
- if (isEmpty())
- return !ba.size() ? 0 : -1;
- const int ol = ba.size();
+ if (haystack.isEmpty())
+ return !needle.size() ? 0 : -1;
+ const auto ol = needle.size();
if (ol == 1)
- return lastIndexOf(ba[0], from);
+ return lastIndexOfCharHelper(haystack, from, needle.front());
- return lastIndexOfHelper(data(), size(), ba.data(), ol, from);
+ return lastIndexOfHelper(haystack.data(), haystack.size(), needle.data(), ol, from);
}
-/*! \fn int QByteArray::lastIndexOf(const char *str, int from) const
- \overload
+/*! \fn int QByteArray::lastIndexOf(QByteArrayView bv, int from) const
+ \since 6.0
- 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.
-*/
-int QByteArray::lastIndexOf(const char *str, int from) const
-{
- if (isEmpty())
- return (str && *str) ? -1 : 0;
- const int ol = qstrlen(str);
- if (ol == 1)
- return lastIndexOf(*str, 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 index
+ position \a from. If \a from is -1 (the default), the search starts from the
+ end of the byte array. Returns -1 if no match is found.
- return lastIndexOfHelper(data(), size(), str, ol, from);
-}
+ Example:
+ \snippet code/src_corelib_text_qbytearray.cpp 23
+
+ \sa indexOf(), contains(), count()
+*/
/*!
\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
@@ -2558,53 +2502,45 @@ int QByteArray::lastIndexOf(const char *str, int from) const
int QByteArray::lastIndexOf(char ch, int from) const
{
- 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;
- }
- return -1;
+ return static_cast<int>(lastIndexOfCharHelper(*this, from, ch));
}
-/*!
- Returns the number of (potentially overlapping) occurrences of
- byte array \a ba in this byte array.
-
- \sa contains(), indexOf()
-*/
+static inline qsizetype countCharHelper(QByteArrayView haystack, char needle) noexcept
+{
+ qsizetype num = 0;
+ for (char ch : haystack) {
+ if (ch == needle)
+ ++num;
+ }
+ return num;
+}
-int QByteArray::count(const QByteArray &ba) const
+qsizetype QtPrivate::count(QByteArrayView haystack, QByteArrayView needle) noexcept
{
- int num = 0;
- int i = -1;
- if (size() > 500 && ba.size() > 5) {
- QByteArrayMatcher matcher(ba);
- while ((i = matcher.indexIn(*this, i + 1)) != -1)
+ if (needle.size() == 1)
+ return countCharHelper(haystack, needle[0]);
+
+ qsizetype num = 0;
+ qsizetype i = -1;
+ if (haystack.size() > 500 && needle.size() > 5) {
+ QByteArrayMatcher matcher(needle.data());
+ while ((i = matcher.indexIn(haystack.data(), 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 int 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
@@ -2616,13 +2552,7 @@ int QByteArray::count(const char *str) const
int 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 static_cast<int>(countCharHelper(*this, ch));
}
/*! \fn int QByteArray::count() const
@@ -2633,119 +2563,75 @@ int QByteArray::count(char ch) const
*/
/*!
- \fn int QByteArray::compare(const char *c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \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
- '\\0'-terminated string \a c. The comparison is performed according to case
- sensitivity \a cs.
-
- \sa operator==
-*/
-
-/*!
- \fn int QByteArray::compare(const QByteArray &a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \overload
- \since 5.12
+ \fn int QByteArray::compare(const 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
- QByteArray \a a. The comparison is performed according to case sensitivity
+ QByteArrayView \a bv. The comparison is performed according to case sensitivity
\a cs.
- \sa operator==
+ \sa operator==, {Character Case}
*/
-/*!
- Returns \c true if this byte array starts with byte array \a ba;
- otherwise returns \c false.
-
- Example:
- \snippet code/src_corelib_text_qbytearray.cpp 25
-
- \sa endsWith(), left()
-*/
-bool QByteArray::startsWith(const QByteArray &ba) const
+bool QtPrivate::startsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
{
- if (size() < ba.size())
+ if (haystack.size() < needle.size())
return false;
- if (data() == ba.data() || ba.size() == 0)
+ if (haystack.data() == needle.data() || needle.size() == 0)
return true;
- return memcmp(data(), ba.data(), ba.size()) == 0;
+ return memcmp(haystack.data(), needle.data(), needle.size()) == 0;
}
-/*! \overload
+/*! \fn bool QByteArray::startsWith(QByteArrayView bv) const
+ \since 6.0
+
+ Returns \c true if this byte array starts with the sequence of bytes
+ viewed by \a bv; otherwise returns \c false.
- Returns \c true if this byte array starts with '\\0'-terminated string \a
- str; otherwise returns \c false.
+ Example:
+ \snippet code/src_corelib_text_qbytearray.cpp 25
+
+ \sa endsWith(), left()
*/
-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.
-*/
-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.
diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h
index 1e0a671981..c7101716c4 100644
--- a/src/corelib/text/qbytearray.h
+++ b/src/corelib/text/qbytearray.h
@@ -46,6 +46,8 @@
#include <QtCore/qarraydata.h>
#include <QtCore/qarraydatapointer.h>
#include <QtCore/qcontainerfwd.h>
+#include <QtCore/qbytearrayalgorithms.h>
+#include <QtCore/qbytearrayview.h>
#include <stdlib.h>
#include <string.h>
@@ -94,10 +96,8 @@ Q_CORE_EXPORT char *qstrcpy(char *dst, const char *src);
Q_CORE_EXPORT char *qstrncpy(char *dst, const char *src, uint len);
Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2);
-Q_CORE_EXPORT int qstrcmp(const QByteArray &str1, const QByteArray &str2);
-Q_CORE_EXPORT int qstrcmp(const QByteArray &str1, const char *str2);
static inline int qstrcmp(const char *str1, const QByteArray &str2)
-{ return -qstrcmp(str2, str1); }
+{ return -QtPrivate::compareMemory(str2, str1); }
inline int qstrncmp(const char *str1, const char *str2, uint len)
{
@@ -202,21 +202,20 @@ public:
Q_REQUIRED_RESULT inline char &back();
int indexOf(char c, int from = 0) const;
- int indexOf(const char *c, int from = 0) const;
- int indexOf(const QByteArray &a, int from = 0) const;
+ int indexOf(QByteArrayView bv, int from = 0) const
+ { return int(QtPrivate::findByteArray(qToByteArrayViewIgnoringNull(*this), from, bv)); }
+
int lastIndexOf(char c, int from = -1) const;
- int lastIndexOf(const char *c, int from = -1) const;
- int lastIndexOf(const QByteArray &a, int from = -1) const;
+ int lastIndexOf(QByteArrayView bv, int from = -1) const
+ { return int(QtPrivate::lastIndexOf(qToByteArrayViewIgnoringNull(*this), from, bv)); }
inline bool contains(char c) const;
- inline bool contains(const char *a) const;
- inline bool contains(const QByteArray &a) const;
+ inline bool contains(QByteArrayView bv) const;
int count(char c) const;
- int count(const char *a) const;
- int count(const QByteArray &a) const;
+ int count(const QByteArrayView &bv) const
+ { return int(QtPrivate::count(qToByteArrayViewIgnoringNull(*this), bv)); }
- inline int compare(const char *c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
- inline int compare(const QByteArray &a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
+ inline int compare(const QByteArrayView &a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
Q_REQUIRED_RESULT QByteArray left(int len) const;
Q_REQUIRED_RESULT QByteArray right(int len) const;
@@ -233,13 +232,13 @@ public:
Q_REQUIRED_RESULT QByteArray chopped(int len) const
{ Q_ASSERT(len >= 0); Q_ASSERT(len <= size()); return first(size() - len); }
- bool startsWith(const QByteArray &a) const;
- bool startsWith(char c) const;
- bool startsWith(const char *c) const;
+ bool startsWith(QByteArrayView bv) const
+ { return QtPrivate::startsWith(qToByteArrayViewIgnoringNull(*this), bv); }
+ bool startsWith(char c) const { return size() > 0 && front() == c; }
- bool endsWith(const QByteArray &a) const;
- bool endsWith(char c) const;
- bool endsWith(const char *c) const;
+ bool endsWith(char c) const { return size() > 0 && back() == c; }
+ bool endsWith(QByteArrayView bv) const
+ { return QtPrivate::endsWith(qToByteArrayViewIgnoringNull(*this), bv); }
bool isUpper() const;
bool isLower() const;
@@ -429,7 +428,6 @@ public:
}
private:
- operator QNoImplicitBoolCast() const;
void reallocData(uint alloc, Data::ArrayOptions options);
void expand(int i);
QByteArray nulTerminated() const;
@@ -553,53 +551,48 @@ inline void QByteArray::push_front(const char *c)
{ prepend(c); }
inline void QByteArray::push_front(const QByteArray &a)
{ prepend(a); }
-inline bool QByteArray::contains(const QByteArray &a) const
-{ return indexOf(a) != -1; }
inline bool QByteArray::contains(char c) const
{ return indexOf(c) != -1; }
-inline int QByteArray::compare(const char *c, Qt::CaseSensitivity cs) const noexcept
-{
- return cs == Qt::CaseSensitive ? qstrcmp(*this, c) :
- qstrnicmp(data(), size(), c, -1);
-}
-inline int QByteArray::compare(const QByteArray &a, Qt::CaseSensitivity cs) const noexcept
+inline bool QByteArray::contains(QByteArrayView bv) const
+{ return indexOf(bv) != -1; }
+inline int QByteArray::compare(const QByteArrayView &a, Qt::CaseSensitivity cs) const noexcept
{
- return cs == Qt::CaseSensitive ? qstrcmp(*this, a) :
+ return cs == Qt::CaseSensitive ? QtPrivate::compareMemory(*this, a) :
qstrnicmp(data(), size(), a.data(), a.size());
}
Q_CORE_EXPORT bool operator==(const QByteArray &a1, const QByteArray &a2) noexcept;
inline bool operator==(const QByteArray &a1, const char *a2) noexcept
-{ return a2 ? qstrcmp(a1,a2) == 0 : a1.isEmpty(); }
+{ return a2 ? QtPrivate::compareMemory(a1, a2) == 0 : a1.isEmpty(); }
inline bool operator==(const char *a1, const QByteArray &a2) noexcept
{ return a1 ? qstrcmp(a1,a2) == 0 : a2.isEmpty(); }
inline bool operator!=(const QByteArray &a1, const QByteArray &a2) noexcept
{ return !(a1==a2); }
inline bool operator!=(const QByteArray &a1, const char *a2) noexcept
-{ return a2 ? qstrcmp(a1,a2) != 0 : !a1.isEmpty(); }
+{ return a2 ? QtPrivate::compareMemory(a1, a2) != 0 : !a1.isEmpty(); }
inline bool operator!=(const char *a1, const QByteArray &a2) noexcept
{ return a1 ? qstrcmp(a1,a2) != 0 : !a2.isEmpty(); }
inline bool operator<(const QByteArray &a1, const QByteArray &a2) noexcept
-{ return qstrcmp(a1, a2) < 0; }
+{ return QtPrivate::compareMemory(QByteArrayView(a1), QByteArrayView(a2)) < 0; }
inline bool operator<(const QByteArray &a1, const char *a2) noexcept
-{ return qstrcmp(a1, a2) < 0; }
+{ return QtPrivate::compareMemory(a1, a2) < 0; }
inline bool operator<(const char *a1, const QByteArray &a2) noexcept
{ return qstrcmp(a1, a2) < 0; }
inline bool operator<=(const QByteArray &a1, const QByteArray &a2) noexcept
-{ return qstrcmp(a1, a2) <= 0; }
+{ return QtPrivate::compareMemory(QByteArrayView(a1), QByteArrayView(a2)) <= 0; }
inline bool operator<=(const QByteArray &a1, const char *a2) noexcept
-{ return qstrcmp(a1, a2) <= 0; }
+{ return QtPrivate::compareMemory(a1, a2) <= 0; }
inline bool operator<=(const char *a1, const QByteArray &a2) noexcept
{ return qstrcmp(a1, a2) <= 0; }
inline bool operator>(const QByteArray &a1, const QByteArray &a2) noexcept
-{ return qstrcmp(a1, a2) > 0; }
+{ return QtPrivate::compareMemory(QByteArrayView(a1), QByteArrayView(a2)) > 0; }
inline bool operator>(const QByteArray &a1, const char *a2) noexcept
-{ return qstrcmp(a1, a2) > 0; }
+{ return QtPrivate::compareMemory(a1, a2) > 0; }
inline bool operator>(const char *a1, const QByteArray &a2) noexcept
{ return qstrcmp(a1, a2) > 0; }
inline bool operator>=(const QByteArray &a1, const QByteArray &a2) noexcept
-{ return qstrcmp(a1, a2) >= 0; }
+{ return QtPrivate::compareMemory(QByteArrayView(a1), QByteArrayView(a2)) >= 0; }
inline bool operator>=(const QByteArray &a1, const char *a2) noexcept
-{ return qstrcmp(a1, a2) >= 0; }
+{ return QtPrivate::compareMemory(a1, a2) >= 0; }
inline bool operator>=(const char *a1, const QByteArray &a2) noexcept
{ return qstrcmp(a1, a2) >= 0; }
#if !defined(QT_USE_QSTRINGBUILDER)
@@ -614,8 +607,6 @@ inline const QByteArray operator+(const char *a1, const QByteArray &a2)
inline const QByteArray operator+(char a1, const QByteArray &a2)
{ return QByteArray(&a1, 1) += a2; }
#endif // QT_USE_QSTRINGBUILDER
-inline bool QByteArray::contains(const char *c) const
-{ return indexOf(c) != -1; }
inline QByteArray &QByteArray::replace(char before, const char *c)
{ return replace(&before, 1, c, qstrlen(c)); }
inline QByteArray &QByteArray::replace(const QByteArray &before, const char *c)
@@ -704,6 +695,15 @@ inline bool operator!=(const QByteArray::FromBase64Result &lhs, const QByteArray
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QByteArray::FromBase64Result &key, size_t seed = 0) noexcept;
+//
+// QByteArrayView members that require QByteArray:
+//
+QByteArray QByteArrayView::toByteArray() const
+{
+ Q_ASSERT(size() == int(size()));
+ return QByteArray(data(), int(size()));
+}
+
QT_END_NAMESPACE
#endif // QBYTEARRAY_H
diff --git a/src/corelib/text/qbytearrayalgorithms.h b/src/corelib/text/qbytearrayalgorithms.h
new file mode 100644
index 0000000000..fdcd00a8c1
--- /dev/null
+++ b/src/corelib/text/qbytearrayalgorithms.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBYTEARRAYALGORITHMS_H
+#define QBYTEARRAYALGORITHMS_H
+
+#include <QtCore/qnamespace.h>
+
+#if 0
+#pragma qt_class(QByteArrayAlgorithms)
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QByteArrayView;
+
+namespace QtPrivate {
+
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
+bool startsWith(QByteArrayView haystack, QByteArrayView needle) noexcept;
+
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
+bool endsWith(QByteArrayView haystack, QByteArrayView needle) noexcept;
+
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
+qsizetype findByteArray(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept;
+
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
+qsizetype lastIndexOf(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept;
+
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
+qsizetype count(QByteArrayView haystack, QByteArrayView needle) noexcept;
+
+[[nodiscard]] Q_CORE_EXPORT int compareMemory(QByteArrayView lhs, QByteArrayView rhs);
+
+} // namespace QtPrivate
+
+QT_END_NAMESPACE
+
+#endif // QBYTEARRAYALGORITHMS_H
diff --git a/src/corelib/text/qbytearrayview.h b/src/corelib/text/qbytearrayview.h
new file mode 100644
index 0000000000..36764abfb4
--- /dev/null
+++ b/src/corelib/text/qbytearrayview.h
@@ -0,0 +1,313 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** 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$
+**
+****************************************************************************/
+#ifndef QBYTEARRAYVIEW_H
+#define QBYTEARRAYVIEW_H
+
+#include <QtCore/qbytearrayalgorithms.h>
+
+#include <string>
+
+QT_BEGIN_NAMESPACE
+
+class QByteArray;
+class QLatin1String;
+
+namespace QtPrivate {
+
+template <typename Byte>
+struct IsCompatibleByteTypeHelper
+ : std::integral_constant<bool,
+ std::is_same_v<Byte, char> ||
+ std::is_same_v<Byte, uchar> ||
+ std::is_same_v<Byte, signed char> ||
+ std::is_same_v<Byte, std::byte>> {};
+
+template <typename Byte>
+struct IsCompatibleByteType
+ : IsCompatibleByteTypeHelper<
+ typename std::remove_cv_t<typename std::remove_reference_t<Byte>>> {};
+
+template <typename Pointer>
+struct IsCompatibleByteArrayPointerHelper : std::false_type {};
+template <typename Byte>
+struct IsCompatibleByteArrayPointerHelper<Byte *>
+ : IsCompatibleByteType<Byte> {};
+template<typename Pointer>
+struct IsCompatibleByteArrayPointer
+ : IsCompatibleByteArrayPointerHelper<
+ typename std::remove_cv_t<typename std::remove_reference_t<Pointer>>> {};
+
+template <typename T, typename Enable = void>
+struct IsContainerCompatibleWithQByteArrayView : std::false_type {};
+
+template <typename T>
+struct IsContainerCompatibleWithQByteArrayView<T, std::enable_if_t<
+ std::conjunction_v<
+ // lacking concepts and ranges, we accept any T whose std::data yields a suitable
+ // pointer ...
+ IsCompatibleByteArrayPointer<decltype(std::data(std::declval<const T &>()))>,
+ // ... and that has a suitable size ...
+ std::is_convertible<decltype(std::size(std::declval<const T &>())), qsizetype>,
+ // ... and it's a range as it defines an iterator-like API
+ IsCompatibleByteType<typename std::iterator_traits<decltype(
+ std::begin(std::declval<const T &>()))>::value_type>,
+ std::is_convertible<decltype(std::begin(std::declval<const T &>())
+ != std::end(std::declval<const T &>())),
+ bool>,
+
+ // This needs to be treated specially due to the empty vs null distinction
+ std::negation<std::is_same<std::decay_t<T>, QByteArray>>,
+
+ // Don't make an accidental copy constructor
+ std::negation<std::is_same<std::decay_t<T>, QByteArrayView>>>>> : std::true_type {};
+
+} // namespace QtPrivate
+
+class Q_CORE_EXPORT QByteArrayView
+{
+public:
+ typedef char storage_type;
+ typedef const char value_type;
+ typedef qptrdiff difference_type;
+ typedef qsizetype size_type;
+ typedef value_type &reference;
+ typedef value_type &const_reference;
+ typedef value_type *pointer;
+ typedef value_type *const_pointer;
+
+ typedef pointer iterator;
+ typedef const_pointer const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+private:
+ template <typename Byte>
+ using if_compatible_byte =
+ typename std::enable_if_t<QtPrivate::IsCompatibleByteType<Byte>::value, bool>;
+
+ template <typename Pointer>
+ using if_compatible_pointer =
+ typename std::enable_if_t<QtPrivate::IsCompatibleByteArrayPointer<Pointer>::value,
+ bool>;
+
+ template <typename T>
+ using if_compatible_qbytearray_like =
+ typename std::enable_if_t<std::is_same_v<T, QByteArray>, bool>;
+
+ template <typename T>
+ using if_compatible_container =
+ typename std::enable_if_t<QtPrivate::IsContainerCompatibleWithQByteArrayView<T>::value,
+ bool>;
+
+ template <typename Char>
+ static constexpr qsizetype lengthHelperPointer(const Char *data) noexcept
+ {
+ return qsizetype(std::char_traits<Char>::length(data));
+ }
+
+ template <typename Container>
+ static constexpr qsizetype lengthHelperContainer(const Container &c) noexcept
+ {
+ return qsizetype(std::size(c));
+ }
+
+ template <typename Char, size_t N>
+ static constexpr qsizetype lengthHelperContainer(const Char (&)[N]) noexcept
+ {
+ return qsizetype(N - 1);
+ }
+
+ template <typename Byte>
+ static const storage_type *castHelper(const Byte *data) noexcept
+ { return reinterpret_cast<const storage_type*>(data); }
+ static Q_DECL_CONSTEXPR const storage_type *castHelper(const storage_type *data) noexcept
+ { return data; }
+
+public:
+ constexpr QByteArrayView() noexcept
+ : m_size(0), m_data(nullptr) {}
+ constexpr QByteArrayView(std::nullptr_t) noexcept
+ : QByteArrayView() {}
+
+ template <typename Byte, if_compatible_byte<Byte> = true>
+ constexpr QByteArrayView(const Byte *data, qsizetype len)
+ : m_size((Q_ASSERT(len >= 0), Q_ASSERT(data || !len), len)),
+ m_data(castHelper(data)) {}
+
+ template <typename Byte, if_compatible_byte<Byte> = true>
+ constexpr QByteArrayView(const Byte *first, const Byte *last)
+ : QByteArrayView(first, last - first) {}
+
+#ifdef Q_QDOC
+ template <typename Byte, size_t N>
+ constexpr QByteArrayView(const Byte (&array)[N]) noexcept;
+
+ template <typename Byte>
+ constexpr QByteArrayView(const Byte *data) noexcept;
+#else
+ template <typename Pointer, if_compatible_pointer<Pointer> = true>
+ constexpr QByteArrayView(const Pointer &data) noexcept
+ : QByteArrayView(
+ data, data ? lengthHelperPointer(data) : 0) {}
+#endif
+
+#ifdef Q_QDOC
+ QByteArrayView(const QByteArray &data) noexcept;
+#else
+ template <typename ByteArray, if_compatible_qbytearray_like<ByteArray> = true>
+ QByteArrayView(const ByteArray &ba) noexcept
+ : QByteArrayView(ba.isNull() ? nullptr : ba.data(), qsizetype(ba.size())) {}
+#endif
+
+ template <typename Container, if_compatible_container<Container> = true>
+ constexpr QByteArrayView(const Container &c) noexcept
+ : QByteArrayView(std::data(c), lengthHelperContainer(c)) {}
+
+ [[nodiscard]] inline QByteArray toByteArray() const; // defined in qbytearray.h
+
+ [[nodiscard]] constexpr qsizetype size() const noexcept { return m_size; }
+ [[nodiscard]] constexpr const_pointer data() const noexcept { return m_data; }
+ [[nodiscard]] constexpr const_pointer constData() const noexcept { return data(); }
+
+ [[nodiscard]] constexpr char operator[](qsizetype n) const
+ { Q_ASSERT(n >= 0); Q_ASSERT(n < size()); return m_data[n]; }
+
+ //
+ // QByteArray API
+ //
+ [[nodiscard]] constexpr char at(qsizetype n) const { return (*this)[n]; }
+
+ [[nodiscard]] constexpr QByteArrayView first(qsizetype n) const
+ { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return QByteArrayView(data(), n); }
+ [[nodiscard]] constexpr QByteArrayView last(qsizetype n) const
+ { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return QByteArrayView(data() + size() - n, n); }
+ [[nodiscard]] constexpr QByteArrayView sliced(qsizetype pos) const
+ { Q_ASSERT(pos >= 0); Q_ASSERT(pos <= size()); return QByteArrayView(data() + pos, size() - pos); }
+ [[nodiscard]] constexpr QByteArrayView sliced(qsizetype pos, qsizetype n) const
+ { Q_ASSERT(pos >= 0); Q_ASSERT(n >= 0); Q_ASSERT(size_t(pos) + size_t(n) <= size_t(size())); return QByteArrayView(data() + pos, n); }
+ [[nodiscard]] constexpr QByteArrayView chopped(qsizetype len) const
+ { Q_ASSERT(len >= 0); Q_ASSERT(len <= size()); return first(size() - len); }
+
+ constexpr void truncate(qsizetype n)
+ { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size = n; }
+ constexpr void chop(qsizetype n)
+ { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size -= n; }
+
+ [[nodiscard]] bool startsWith(QByteArrayView other) const noexcept
+ { return QtPrivate::startsWith(*this, other); }
+ [[nodiscard]] bool startsWith(char c) const noexcept
+ { return !empty() && front() == c; }
+
+ [[nodiscard]] bool endsWith(QByteArrayView other) const noexcept
+ { return QtPrivate::endsWith(*this, other); }
+ [[nodiscard]] bool endsWith(char c) const noexcept
+ { return !empty() && back() == c; }
+
+ [[nodiscard]] qsizetype indexOf(QByteArrayView a, qsizetype from = 0) const noexcept
+ { return QtPrivate::findByteArray(*this, from, a); }
+ [[nodiscard]] qsizetype indexOf(char ch, qsizetype from = 0) const noexcept
+ { return QtPrivate::findByteArray(*this, from, QByteArrayView(&ch, 1)); }
+
+ [[nodiscard]] bool contains(QByteArrayView a) const noexcept
+ { return indexOf(a) != qsizetype(-1); }
+ [[nodiscard]] bool contains(char c) const noexcept
+ { return indexOf(c) != qsizetype(-1); }
+
+ [[nodiscard]] qsizetype lastIndexOf(QByteArrayView a, qsizetype from = -1) const noexcept
+ { return QtPrivate::lastIndexOf(*this, from, a); }
+ [[nodiscard]] qsizetype lastIndexOf(char ch, qsizetype from = -1) const noexcept
+ { return QtPrivate::lastIndexOf(*this, from, QByteArrayView(&ch, 1)); }
+
+ [[nodiscard]] qsizetype count(QByteArrayView a) const noexcept
+ { return QtPrivate::count(*this, a); }
+ [[nodiscard]] qsizetype count(char ch) const noexcept
+ { return QtPrivate::count(*this, QByteArrayView(&ch, 1)); }
+
+ //
+ // STL compatibility API:
+ //
+ [[nodiscard]] constexpr const_iterator begin() const noexcept { return data(); }
+ [[nodiscard]] constexpr const_iterator end() const noexcept { return data() + size(); }
+ [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return begin(); }
+ [[nodiscard]] constexpr const_iterator cend() const noexcept { return end(); }
+ [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
+ [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
+ [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+ [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return rend(); }
+
+ [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
+ [[nodiscard]] constexpr char front() const { Q_ASSERT(!empty()); return m_data[0]; }
+ [[nodiscard]] constexpr char back() const { Q_ASSERT(!empty()); return m_data[m_size - 1]; }
+
+ //
+ // Qt compatibility API:
+ //
+ [[nodiscard]] constexpr bool isNull() const noexcept { return !m_data; }
+ [[nodiscard]] constexpr bool isEmpty() const noexcept { return empty(); }
+#if QT_DEPRECATED_SINCE(6, 0)
+ [[nodiscard]]
+ Q_DECL_DEPRECATED_X("Use size() and port callers to qsizetype.")
+ constexpr int length() const /* not nothrow! */
+ { Q_ASSERT(int(size()) == size()); return int(size()); }
+#endif
+ [[nodiscard]] constexpr char first() const { return front(); }
+ [[nodiscard]] constexpr char last() const { return back(); }
+
+private:
+ qsizetype m_size;
+ const storage_type *m_data;
+};
+Q_DECLARE_TYPEINFO(QByteArrayView, Q_PRIMITIVE_TYPE);
+
+// QByteArrayView <> QByteArrayView
+inline bool operator==(QByteArrayView lhs, QByteArrayView rhs) noexcept { return lhs.size() == rhs.size() && QtPrivate::compareMemory(lhs, rhs) == 0; }
+inline bool operator!=(QByteArrayView lhs, QByteArrayView rhs) noexcept { return !(lhs == rhs); }
+inline bool operator< (QByteArrayView lhs, QByteArrayView rhs) noexcept { return QtPrivate::compareMemory(lhs, rhs) < 0; }
+inline bool operator<=(QByteArrayView lhs, QByteArrayView rhs) noexcept { return QtPrivate::compareMemory(lhs, rhs) <= 0; }
+inline bool operator> (QByteArrayView lhs, QByteArrayView rhs) noexcept { return !(lhs <= rhs); }
+inline bool operator>=(QByteArrayView lhs, QByteArrayView rhs) noexcept { return !(lhs < rhs); }
+
+template<typename QByteArrayLike,
+ std::enable_if_t<std::is_same_v<QByteArrayLike, QByteArray>, bool> = true>
+[[nodiscard]] inline QByteArrayView qToByteArrayViewIgnoringNull(const QByteArrayLike &b) noexcept
+{ return QByteArrayView(b.data(), b.size()); }
+
+QT_END_NAMESPACE
+
+#endif // QBYTEARRAYVIEW_H
diff --git a/src/corelib/text/qbytearrayview.qdoc b/src/corelib/text/qbytearrayview.qdoc
new file mode 100644
index 0000000000..d1a9df6a1c
--- /dev/null
+++ b/src/corelib/text/qbytearrayview.qdoc
@@ -0,0 +1,692 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QByteArrayView
+ \inmodule QtCore
+ \brief The QByteArrayView class provides a view on an array of bytes with a read-only
+ subset of the QByteArray API.
+ \since 6.0
+
+ \ingroup tools
+ \ingroup shared
+ \ingroup string-processing
+
+ \reentrant
+
+ A QByteArrayView references a contiguous portion of raw bytes it does
+ not own. It acts as an interface type to all kinds of byte-array-like data,
+ without the need to construct a QByteArray first.
+
+ The byte array data may be represented as an array (or an array-compatible
+ data-structure such as QByteArray, std::basic_string, etc.) of \c char,
+ \c{signed char}, \c{unsigned char} or \c std::byte.
+
+ QByteArrayView is designed as an interface type; its main use-case is
+ as a function parameter type. When QByteArrayViews are used as automatic
+ variables or data members, care must be taken to ensure that the referenced
+ data (for example, owned by a QByteArray) outlives the QByteArrayView on all
+ code paths, lest the byte array view ends up referencing deleted data.
+
+ When used as an interface type, QByteArrayView allows a single function to accept
+ a wide variety of byte-array-like data sources. One function accepting QByteArrayView
+ thus replaces several function overloads (taking, for example, QByteArray, const char *,
+ etc.) while at the same time enabling even more byte array data sources to be passed
+ to the function.
+
+ QByteArrayView should be passed by value, not by reference-to-const:
+ \snippet code/src_corelib_text_qbytearrayview.cpp 0
+
+ If you want to give your users maximum freedom in what type of data they
+ can pass to your function, accompany the QByteArrayView overload with
+ overloads for
+
+ \list
+ \li \e char: this overload can delegate to the QByteArrayView version:
+ \snippet code/src_corelib_text_qbytearrayview.cpp 1
+ even though, for technical reasons, QByteArrayView cannot provide a
+ char constructor by itself.
+ \li \e QByteArray: if you store an unmodified copy of the byte array and
+ thus would like to take advantage of QByteArray's implicit sharing.
+ \endlist
+
+ QByteArrayView can also be used as the return value of a function. If you call a
+ function returning QByteArrayView, take extra care to not keep the QByteArrayView
+ around longer than the function promises to keep the referenced data alive.
+ If in doubt, obtain a strong reference to the data by calling toByteArray() to convert
+ the QByteArrayView into a QByteArray.
+
+ \section1 Compatible Byte Types
+
+ QByteArrayView can be constructed on any container of bytes, where the byte type
+ is one of:
+
+ \list
+ \li \c char (both signed and unsigned)
+ \li \c std::byte
+ \endlist
+
+ \sa QByteArray, QStringView
+*/
+
+/*!
+ \typedef QByteArrayView::storage_type
+
+ Alias for \c char.
+*/
+
+/*!
+ \typedef QByteArrayView::value_type
+
+ Alias for \c{const char}. Provided for compatibility with the STL.
+*/
+
+/*!
+ \typedef QByteArrayView::difference_type
+
+ Alias for \c{std::ptrdiff_t}. Provided for compatibility with the STL.
+*/
+
+/*!
+ \typedef QByteArrayView::size_type
+
+ Alias for qsizetype. Provided for compatibility with the STL.
+*/
+
+/*!
+ \typedef QByteArrayView::reference
+
+ Alias for \c{value_type &}. Provided for compatibility with the STL.
+
+ QByteArrayView does not support mutable references, so this is the same
+ as const_reference.
+*/
+
+/*!
+ \typedef QByteArrayView::const_reference
+
+ Alias for \c{value_type &}. Provided for compatibility with the STL.
+*/
+
+/*!
+ \typedef QByteArrayView::pointer
+
+ Alias for \c{value_type *}. Provided for compatibility with the STL.
+
+ QByteArrayView does not support mutable pointers, so this is the same
+ as const_pointer.
+*/
+
+/*!
+ \typedef QByteArrayView::const_pointer
+
+ Alias for \c{value_type *}. Provided for compatibility with the STL.
+*/
+
+/*!
+ \typedef QByteArrayView::iterator
+
+ This typedef provides an STL-style const iterator for QByteArrayView.
+
+ QByteArrayView does not support mutable iterators, so this is the same
+ as const_iterator.
+
+ \sa const_iterator, reverse_iterator
+*/
+
+/*!
+ \typedef QByteArrayView::const_iterator
+
+ This typedef provides an STL-style const iterator for QByteArrayView.
+
+ \sa iterator, const_reverse_iterator
+*/
+
+/*!
+ \typedef QByteArrayView::reverse_iterator
+
+ This typedef provides an STL-style const reverse iterator for QByteArrayView.
+
+ QByteArrayView does not support mutable reverse iterators, so this is the
+ same as const_reverse_iterator.
+
+ \sa const_reverse_iterator, iterator
+*/
+
+/*!
+ \typedef QByteArrayView::const_reverse_iterator
+
+ This typedef provides an STL-style const reverse iterator for QByteArrayView.
+
+ \sa reverse_iterator, const_iterator
+*/
+
+/*!
+ \fn QByteArrayView::QByteArrayView()
+
+ Constructs a null byte array view.
+
+ \sa isNull()
+*/
+
+/*!
+ \fn QByteArrayView::QByteArrayView(std::nullptr_t)
+
+ Constructs a null byte array view.
+
+ \sa isNull()
+*/
+
+/*!
+ \fn template <typename Byte> QByteArrayView::QByteArrayView(const Byte *data, qsizetype len)
+
+ Constructs a byte array view on \a data with length \a len.
+
+ The range \c{[data,len)} must remain valid for the lifetime of this QByteArrayView.
+
+ Passing \nullptr as \a data is safe if \a len is 0, too, and results in a null
+ byte array view.
+
+ The behavior is undefined if \a len is negative or, when positive, if \a data is \nullptr.
+
+ This constructor only participates in overload resolution if \c Byte is a compatible
+ byte type.
+
+ \sa {Compatible Byte Types}
+*/
+
+/*!
+ \fn template <typename Byte> QByteArrayView::QByteArrayView(const Byte *first, const Byte *last)
+
+ Constructs a byte array view on \a first with length (\a last - \a first).
+
+ The range \c{[first,last)} must remain valid for the lifetime of
+ this QByteArrayView.
+
+ Passing \c \nullptr as \a first is safe if \a last is \nullptr, too,
+ and results in a null byte array view.
+
+ The behavior is undefined if \a last precedes \a first, or \a first
+ is \nullptr and \a last is not.
+
+ This constructor only participates in overload resolution if \c Byte is
+ a compatible byte type.
+
+ \sa {Compatible Byte Types}
+*/
+
+/*!
+ \fn template <typename Byte> QByteArrayView::QByteArrayView(const Byte *data)
+
+ Constructs a byte array view on \a data. The length is determined
+ by scanning for the first \c{Byte(0)}.
+
+ \a data must remain valid for the lifetime of this byte array view object.
+
+ Passing \nullptr as \a data is safe and results in a null byte array view.
+
+ This constructor only participates in overload resolution if \a data is not
+ an array and if \c Byte is a compatible byte type.
+
+ \sa {Compatible Byte Types}
+*/
+
+/*!
+ \fn template <typename Byte, size_t N> QByteArrayView::QByteArrayView(const Byte (&data)[N])
+
+ Constructs a byte array view on the array of bytes \a data.
+ The length is set to \c{N-1}, excluding the trailing \{Byte(0)}.
+ If you need the full array, use the constructor from pointer and
+ size instead:
+
+ \snippet code/src_corelib_text_qbytearrayview.cpp 2
+
+ \a data must remain valid for the lifetime of this byte array view
+ object.
+
+ This constructor only participates in overload resolution if \a
+ data is an actual array and \c Byte is a compatible byte
+ type.
+
+ \sa {Compatible Byte Types}
+*/
+
+/*!
+ \fn QByteArrayView::QByteArrayView(const QByteArray &byteArray)
+
+ Constructs a byte array view on \a byteArray.
+
+ \c{byteArray.data()} must remain valid for the lifetime of this byte array view object.
+
+ The byte array view will be null if and only if \c{byteArray.isNull()}.
+*/
+
+/*!
+ \fn template <typename Container> QByteArrayView::QByteArrayView(const Container &c)
+
+ Constructs a byte array view on the array-like container \a c. The length and data
+ are set via \c{std::size(c)} and \c{std::data(c)} respectively.
+
+ The container's data must remain valid for the lifetime of this byte array view object.
+
+ This constructor participates in overload resolution if \a c is any contiguous
+ container container with elements of a compatible byte type.
+
+ \sa {Compatible Byte Types}
+*/
+
+/*!
+ \fn QByteArray QByteArrayView::toByteArray() const
+
+ Returns a deep copy of this byte array view's data as a QByteArray.
+
+ The return value will be a null QByteArray if and only if this byte array
+ view is null.
+
+ \warning QByteArrayView can store data with more than 2\sup{31} bytes while
+ QByteArray cannot. Calling this function on a byte array view for which size()
+ returns a value greater than \c{INT_MAX / 2} constitutes undefined behavior.
+*/
+
+/*!
+ \fn const char *QByteArrayView::data() const
+
+ Returns a const \c char pointer to the first byte in the byte array.
+
+ \note The character array represented by the return value is \e not guaranteed
+ to be null-terminated. The returned pointer is only safe to use for accessing
+ bytes at indices that are less than this byte array view's size().
+
+ \sa begin(), end()
+*/
+
+/*!
+ \fn const char *QByteArrayView::constData() const
+
+ Returns a const \c char pointer to the first byte in the byte array.
+
+ \note The character array represented by the return value is \e not guaranteed
+ to be null-terminated. The returned pointer is only safe to use for accessing
+ bytes at indices that are less than this byte array view's size().
+
+ \sa data(), begin(), end()
+*/
+
+/*!
+ \fn QByteArrayView::const_iterator QByteArrayView::begin() const
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the
+ first byte in the byte array.
+
+ This function is provided for STL compatibility.
+
+ \sa end(), cbegin(), rbegin(), data()
+*/
+
+/*!
+ \fn QByteArrayView::const_iterator QByteArrayView::cbegin() const
+
+ Same as begin().
+
+ This function is provided for STL compatibility.
+
+ \sa cend(), begin(), crbegin(), data()
+*/
+
+/*!
+ \fn QByteArrayView::const_iterator QByteArrayView::end() const
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing
+ just after the last byte in the byte array.
+
+ This function is provided for STL compatibility.
+
+ \sa begin(), cend(), rend()
+*/
+
+/*! \fn QByteArrayView::const_iterator QByteArrayView::cend() const
+
+ Same as end().
+
+ This function is provided for STL compatibility.
+
+ \sa cbegin(), end(), crend()
+*/
+
+/*!
+ \fn QByteArrayView::const_reverse_iterator QByteArrayView::rbegin() const
+
+ Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing
+ to the first byte in the byte array, in reverse order.
+
+ This function is provided for STL compatibility.
+
+ \sa rend(), crbegin(), begin()
+*/
+
+/*!
+ \fn QByteArrayView::const_reverse_iterator QByteArrayView::crbegin() const
+
+ Same as rbegin().
+
+ This function is provided for STL compatibility.
+
+ \sa crend(), rbegin(), cbegin()
+*/
+
+/*!
+ \fn QByteArrayView::const_reverse_iterator QByteArrayView::rend() const
+
+ Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
+ the last byte in the byte array, in reverse order.
+
+ This function is provided for STL compatibility.
+
+ \sa rbegin(), crend(), end()
+*/
+
+/*!
+ \fn QByteArrayView::const_reverse_iterator QByteArrayView::crend() const
+
+ Same as rend().
+
+ This function is provided for STL compatibility.
+
+ \sa crbegin(), rend(), cend()
+*/
+
+/*!
+ \fn bool QByteArrayView::empty() const
+
+ Returns \c true if this byte array view is empty - that is, \c{size() == 0}.
+
+ This function is provided for STL compatibility.
+
+ \sa isEmpty(), isNull(), size()
+*/
+
+/*!
+ \fn bool QByteArrayView::isEmpty() const
+
+ Returns \c true if this byte array view is empty - that is, \c{size() == 0}.
+
+ \sa empty(), isNull(), size()
+*/
+
+/*!
+ \fn bool QByteArrayView::isNull() const
+
+ Returns \c true if this byte array view is null - that is, \c{data() == nullptr}.
+
+ \sa empty(), isEmpty(), size()
+*/
+
+/*!
+ \fn qsizetype QByteArrayView::size() const
+
+ Returns the number of bytes in this byte array view.
+
+ \sa empty(), isEmpty(), isNull()
+*/
+
+#if QT_DEPRECATED_SINCE(6, 0)
+/*!
+ \fn int QByteArrayView::length() const
+ \obsolete
+ Use size() and port callers to qsizetype.
+
+ Same as size(), but returns the result as an \c int.
+
+ This function is provided for compatibility with other Qt containers.
+
+ \warning QByteArrayView can represent data with more than 2\sup{31} bytes.
+ Calling this function on a byte array view for which size() returns a value greater
+ than \c{INT_MAX} constitutes undefined behavior.
+
+ \sa empty(), isEmpty(), isNull(), size()
+*/
+#endif
+
+/*!
+ \fn char QByteArrayView::operator[](qsizetype n) const
+
+ Returns the character at position \a n in this byte array view.
+
+ The behavior is undefined if \a n is negative or not less than size().
+
+ \sa at(), front(), back()
+*/
+
+/*!
+ \fn char QByteArrayView::at(qsizetype n) const
+
+ Returns the character at position \a n in this byte array view.
+
+ The behavior is undefined if \a n is negative or not less than size().
+
+ \sa operator[](), front(), back()
+*/
+
+/*!
+ \fn char QByteArrayView::front() const
+
+ Returns the first byte in the byte array.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty byte array view constitutes
+ undefined behavior.
+
+ \sa back()
+*/
+
+/*!
+ \fn char QByteArrayView::back() const
+
+ Returns the last byte in the byte array.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty byte array view constitutes
+ undefined behavior.
+
+ \sa front()
+*/
+
+/*!
+ \fn QByteArrayView QByteArrayView::first(qsizetype n) const
+
+ Returns a byte array view that points to the first \a n bytes
+ of this byte array view. Equivalent to \c{sliced(0, n)}.
+
+ \note The behavior is undefined when \a n < 0 or \a n > size().
+
+ \sa last(), startsWith(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QByteArrayView QByteArrayView::last(qsizetype n) const
+
+ Returns a byte array view that points to the last \a n bytes
+ of this byte array view.
+
+ \note The behavior is undefined when \a n < 0 or \a n > size().
+
+ \sa first(), endsWith(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QByteArrayView QByteArrayView::sliced(qsizetype pos, qsizetype n) const
+
+ Returns a byte array view that points to \a n bytes of this byte array
+ view, starting at position \a pos.
+
+ \note The behavior is undefined when \a pos < 0, \a n < 0,
+ or \a pos + \a n > size().
+
+ \sa first(), last(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QByteArrayView QByteArrayView::sliced(qsizetype pos) const
+
+ Returns a byte array view starting at position \a pos in this object,
+ and extending to its end.
+
+ \note The behavior is undefined when \a pos < 0 or \a pos > size().
+
+ \sa first(), last(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QByteArrayView QByteArrayView::chopped(qsizetype length) const
+
+ Returns a copy of this byte array view that omits its last \a length bytes.
+ In other words, returns a byte array view of length size() - \a length starting
+ at the beginning of this object.
+
+ Same as \c{first(size() - length)}.
+
+ \note The behavior is undefined when \a length < 0 or \a length > size().
+
+ \sa first(), last(), sliced(), chop(), truncate()
+*/
+
+/*!
+ \fn void QByteArrayView::truncate(qsizetype length)
+
+ Truncates this byte array view to length \a length.
+
+ Same as \c{*this = first(length)}.
+
+ \note The behavior is undefined when \a length < 0 or \a length > size().
+
+ \sa first(), last(), sliced(), right(), chopped(), chop()
+*/
+
+/*!
+ \fn void QByteArrayView::chop(qsizetype length)
+
+ Truncates this byte array view by \a length characters.
+
+ Same as \c{*this = first(size() - length)}.
+
+ \note The behavior is undefined when \a length < 0 or \a length > size().
+
+ \sa sliced(), first(), last(), chopped(), truncate()
+*/
+
+/*!
+ \fn bool QByteArrayView::startsWith(QByteArrayView bv) const
+ \fn bool QByteArrayView::startsWith(char ch) const
+
+ Returns \c true if this byte array view starts with byte array view \a bv
+ or character \a ch, respectively; otherwise returns \c false.
+
+ \sa endsWith()
+*/
+
+/*!
+ \fn bool QByteArrayView::endsWith(QByteArrayView bv) const
+ \fn bool QByteArrayView::endsWith(char ch) const
+
+ Returns \c true if this byte array view ends with byte array view \a bv
+ or character \a ch, respectively; otherwise returns \c false.
+
+ \sa startsWith()
+*/
+
+/*!
+ \fn qsizetype QByteArrayView::indexOf(QByteArrayView bv, qsizetype from = 0) const
+ \fn qsizetype QByteArrayView::indexOf(char ch, qsizetype from = 0) const
+
+ Returns the index position of either the start of the first occurrence of
+ the sequence of bytes viewed by \a bv or the first occurrence of byte \a ch,
+ respectively, in this byte array view, searching forward from index position
+ \a from.Returns -1 if no match is found.
+
+ If \a from is -1, the search starts at the last character; if it is
+ -2, at the next to last character and so on.
+
+ \sa lastIndexOf(), contains()
+*/
+
+/*!
+ \fn bool QByteArrayView::contains(QByteArrayView bv) const
+ \fn bool QByteArrayView::contains(char ch) const
+
+ Returns \c true if this byte array view contains an occurrence of the sequence
+ of bytes viewed by \a bv or character \a ch, respectively; otherwise returns
+ \c false.
+
+ \sa indexOf(), lastIndexOf()
+*/
+
+/*!
+ \fn qsizetype QByteArrayView::lastIndexOf(QByteArrayView bv, qsizetype from = -1) const
+ \fn qsizetype QByteArrayView::lastIndexOf(char ch, qsizetype from = -1) const
+
+ Returns the index position of either the start of the last occurrence of
+ the sequence of bytes viewed by \a bv or the last occurrence of byte \a ch,
+ respectively, in this byte array view, searching forward from index position
+ \a from. If \a from is -1 (the default), the search starts from the end of the
+ byte array view. Returns -1 if no match is found.
+
+ \sa indexOf(), contains()
+*/
+
+/*!
+ \fn int QByteArrayView::count(QByteArrayView &bv) const
+
+ Returns the number of (potentially overlapping) occurrences of the
+ sequence of bytes viewed by \a bv in this byte array view.
+
+ \sa contains(), indexOf()
+*/
+
+/*!
+ \fn bool QByteArrayView::count(char ch) const
+ \overload
+
+ Returns the number of occurrences of byte \a ch in this byte array view.
+
+ \sa contains(), indexOf()
+*/
+
+/*!
+ \fn QByteArrayView qToByteArrayViewIgnoringNull(const QByteArray &b);
+ \internal
+
+ Convert \a b to a QByteArrayView ignoring \c{b.isNull()}.
+
+ Returns a byte array view that references \a{b}'s data, but is never null.
+
+ This is a faster way to convert a QByteArray to a QByteArrayView,
+ if null QByteArray can legitimately be treated as empty ones.
+
+ \sa QByteArray::isNull(), QByteArrayView
+*/
diff --git a/src/corelib/text/text.pri b/src/corelib/text/text.pri
index 1d83bc151b..89fbdddd83 100644
--- a/src/corelib/text/text.pri
+++ b/src/corelib/text/text.pri
@@ -3,8 +3,10 @@
HEADERS += \
text/qbytearray.h \
text/qbytearray_p.h \
+ text/qbytearrayalgorithms.h \
text/qbytearraylist.h \
text/qbytearraymatcher.h \
+ text/qbytearrayview.h \
text/qbytedata_p.h \
text/qchar.h \
text/qcollator.h \
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index f52d46a9e8..0f46e7f113 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -400,6 +400,11 @@ size_t qHash(const QByteArray &key, size_t seed) noexcept
return qHashBits(key.constData(), size_t(key.size()), seed);
}
+size_t qHash(const QByteArrayView &key, size_t seed) noexcept
+{
+ return qHashBits(key.constData(), size_t(key.size()), seed);
+}
+
size_t qHash(QStringView key, size_t seed) noexcept
{
return qHashBits(key.data(), key.size()*sizeof(QChar), seed);
@@ -886,6 +891,13 @@ size_t qHash(long double key, size_t seed) noexcept
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
+/*! \fn size_t qHash(const QByteArrayView &key, size_t seed = 0)
+ \relates QHash
+ \since 6.0
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+*/
+
/*! \fn size_t qHash(const QBitArray &key, size_t seed = 0)
\relates QHash
\since 5.0
diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h
index b48a665383..e8e93206ce 100644
--- a/src/corelib/tools/qhashfunctions.h
+++ b/src/corelib/tools/qhashfunctions.h
@@ -155,6 +155,7 @@ Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(std::nullptr_t, size_t seed
// (some) Qt types
Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(const QChar key, size_t seed = 0) noexcept { return qHash(key.unicode(), seed); }
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QByteArray &key, size_t seed = 0) noexcept;
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QByteArrayView &key, size_t seed = 0) noexcept;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QStringView key, size_t seed = 0) noexcept;
#if QT_STRINGVIEW_LEVEL < 2
inline Q_DECL_PURE_FUNCTION size_t qHash(const QString &key, size_t seed = 0) noexcept
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index 5178e90471..39640b6f68 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -164,7 +164,8 @@ bool Generator::registerableMetaType(const QByteArray &propertyType)
;
for (const QByteArray &smartPointer : smartPointers) {
- if (propertyType.startsWith(smartPointer + "<") && !propertyType.endsWith("&"))
+ QByteArray ba = smartPointer + "<";
+ if (propertyType.startsWith(ba) && !propertyType.endsWith("&"))
return knownQObjectClasses.contains(propertyType.mid(smartPointer.size() + 1, propertyType.size() - smartPointer.size() - 1 - 1));
}
@@ -174,7 +175,8 @@ bool Generator::registerableMetaType(const QByteArray &propertyType)
#undef STREAM_1ARG_TEMPLATE
;
for (const QByteArray &oneArgTemplateType : oneArgTemplates) {
- if (propertyType.startsWith(oneArgTemplateType + "<") && propertyType.endsWith(">")) {
+ QByteArray ba = oneArgTemplateType + "<";
+ if (propertyType.startsWith(ba) && propertyType.endsWith(">")) {
const int argumentSize = propertyType.size() - oneArgTemplateType.size() - 1
// The closing '>'
- 1
diff --git a/src/tools/uic/qclass_lib_map.h b/src/tools/uic/qclass_lib_map.h
index ae6fa911c5..b63b05107b 100644
--- a/src/tools/uic/qclass_lib_map.h
+++ b/src/tools/uic/qclass_lib_map.h
@@ -29,7 +29,6 @@ QT_CLASS_LIB(QIntegerForSize, QtCore, qglobal.h)
QT_CLASS_LIB(QIntegerForSize, QtCore, qglobal.h)
QT_CLASS_LIB(QIntegerForSize, QtCore, qglobal.h)
QT_CLASS_LIB(QIntegerForSize, QtCore, qglobal.h)
-QT_CLASS_LIB(QNoImplicitBoolCast, QtCore, qglobal.h)
QT_CLASS_LIB(Q_INT64, QtCore, qglobal.h)
QT_CLASS_LIB(Q_UINT64, QtCore, qglobal.h)
QT_CLASS_LIB(QSysInfo, QtCore, qglobal.h)
diff --git a/tests/auto/corelib/text/CMakeLists.txt b/tests/auto/corelib/text/CMakeLists.txt
index 1988bcc28d..0c36f1e088 100644
--- a/tests/auto/corelib/text/CMakeLists.txt
+++ b/tests/auto/corelib/text/CMakeLists.txt
@@ -4,6 +4,7 @@ add_subdirectory(qbytearray)
add_subdirectory(qbytearrayapisymmetry)
add_subdirectory(qbytearraylist)
add_subdirectory(qbytearraymatcher)
+add_subdirectory(qbytearrayview)
add_subdirectory(qbytedatabuffer)
add_subdirectory(qchar)
add_subdirectory(qcollator)
diff --git a/tests/auto/corelib/text/qbytearrayview/CMakeLists.txt b/tests/auto/corelib/text/qbytearrayview/CMakeLists.txt
new file mode 100644
index 0000000000..34476b8246
--- /dev/null
+++ b/tests/auto/corelib/text/qbytearrayview/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Generated from qbytearrayview.pro.
+
+#####################################################################
+## tst_qbytearrayview Test:
+#####################################################################
+
+qt_add_test(tst_qbytearrayview
+ SOURCES
+ tst_qbytearrayview.cpp
+)
diff --git a/tests/auto/corelib/text/qbytearrayview/qbytearrayview.pro b/tests/auto/corelib/text/qbytearrayview/qbytearrayview.pro
new file mode 100644
index 0000000000..23d0aed959
--- /dev/null
+++ b/tests/auto/corelib/text/qbytearrayview/qbytearrayview.pro
@@ -0,0 +1,4 @@
+CONFIG += testcase
+TARGET = tst_qbytearrayview
+QT = core testlib
+SOURCES += tst_qbytearrayview.cpp
diff --git a/tests/auto/corelib/text/qbytearrayview/tst_qbytearrayview.cpp b/tests/auto/corelib/text/qbytearrayview/tst_qbytearrayview.cpp
new file mode 100644
index 0000000000..c1d80b47dc
--- /dev/null
+++ b/tests/auto/corelib/text/qbytearrayview/tst_qbytearrayview.cpp
@@ -0,0 +1,595 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QByteArrayView>
+
+#include <QTest>
+
+// for negative testing (can't convert from)
+#include <deque>
+#include <list>
+
+template <typename T>
+constexpr bool CanConvert = std::is_convertible_v<T, QByteArrayView>;
+
+static_assert(!CanConvert<QString>);
+static_assert(!CanConvert<QStringView>);
+static_assert(!CanConvert<const char16_t*>);
+
+static_assert(!CanConvert<char>);
+static_assert(CanConvert<char[1]>);
+static_assert(CanConvert<const char[1]>);
+static_assert(CanConvert<char*>);
+static_assert(CanConvert<const char*>);
+
+static_assert(!CanConvert<uchar>);
+static_assert(CanConvert<uchar[1]>);
+static_assert(CanConvert<const uchar[1]>);
+static_assert(CanConvert<uchar*>);
+static_assert(CanConvert<const uchar*>);
+
+static_assert(!CanConvert<signed char>);
+static_assert(CanConvert<signed char[1]>);
+static_assert(CanConvert<const signed char[1]>);
+static_assert(CanConvert<signed char*>);
+static_assert(CanConvert<const signed char*>);
+
+static_assert(!CanConvert<std::byte>);
+static_assert(CanConvert<std::byte[1]>);
+static_assert(CanConvert<const std::byte[1]>);
+static_assert(CanConvert<std::byte*>);
+static_assert(CanConvert<const std::byte*>);
+
+static_assert(CanConvert< QByteArray >);
+static_assert(CanConvert<const QByteArray >);
+static_assert(CanConvert< QByteArray&>);
+static_assert(CanConvert<const QByteArray&>);
+
+static_assert(CanConvert< std::string >);
+static_assert(CanConvert<const std::string >);
+static_assert(CanConvert< std::string&>);
+static_assert(CanConvert<const std::string&>);
+
+static_assert(CanConvert< std::string_view >);
+static_assert(CanConvert<const std::string_view >);
+static_assert(CanConvert< std::string_view&>);
+static_assert(CanConvert<const std::string_view&>);
+
+static_assert(CanConvert< QVector<char> >);
+static_assert(CanConvert<const QVector<char> >);
+static_assert(CanConvert< QVector<char>&>);
+static_assert(CanConvert<const QVector<char>&>);
+
+static_assert(CanConvert< QVarLengthArray<char> >);
+static_assert(CanConvert<const QVarLengthArray<char> >);
+static_assert(CanConvert< QVarLengthArray<char>&>);
+static_assert(CanConvert<const QVarLengthArray<char>&>);
+
+static_assert(CanConvert< std::vector<char> >);
+static_assert(CanConvert<const std::vector<char> >);
+static_assert(CanConvert< std::vector<char>&>);
+static_assert(CanConvert<const std::vector<char>&>);
+
+static_assert(CanConvert< std::array<char, 1> >);
+static_assert(CanConvert<const std::array<char, 1> >);
+static_assert(CanConvert< std::array<char, 1>&>);
+static_assert(CanConvert<const std::array<char, 1>&>);
+
+static_assert(!CanConvert<std::deque<char>>);
+static_assert(!CanConvert<std::list<char>>);
+
+class tst_QByteArrayView : public QObject
+{
+ Q_OBJECT
+private slots:
+ void constExpr() const;
+ void basics() const;
+ void literals() const;
+ void literalsWithInternalNulls() const;
+ void at() const;
+
+ void fromQByteArray() const;
+
+ void fromCharStar() const
+ {
+ fromEmptyLiteral<char>();
+ conversionTests("Hello, World!");
+ }
+
+ void fromUCharStar() const
+ {
+ fromEmptyLiteral<uchar>();
+
+ const uchar data[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 };
+ conversionTests(data);
+ }
+
+ void fromSignedCharStar() const
+ {
+ fromEmptyLiteral<signed char>();
+
+ const signed char data[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 };
+ conversionTests(data);
+ }
+
+ void fromStdByteArray() const
+ {
+ fromEmptyLiteral<std::byte>();
+
+ const std::byte data[] = {std::byte{'H'}, std::byte{'e'}, std::byte{'l'}, std::byte{'l'},
+ std::byte{'o'}, std::byte{0}};
+ conversionTests(data);
+ }
+
+ void fromCharRange() const
+ {
+ const char data[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' };
+ fromRange(std::begin(data), std::end(data));
+ }
+
+ void fromUCharRange() const
+ {
+ const uchar data[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 };
+ fromRange(std::begin(data), std::end(data));
+ }
+
+ void fromSignedCharRange() const
+ {
+ const signed char data[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 };
+ fromRange(std::begin(data), std::end(data));
+ }
+
+ void fromStdByteRange() const
+ {
+ const std::byte data[] = {std::byte{'H'}, std::byte{'e'}, std::byte{'l'}, std::byte{'l'},
+ std::byte{'o'}, std::byte{0}};
+ fromRange(std::begin(data), std::end(data));
+ }
+
+ void fromCharContainers() const
+ {
+ fromContainers<char>();
+ }
+
+ void fromUCharContainers() const
+ {
+ fromContainers<uchar>();
+ }
+
+ void fromSignedCharContainers() const
+ {
+ fromContainers<signed char>();
+ }
+
+ void fromStdByteContainers() const
+ {
+ fromContainers<std::byte>();
+ }
+
+ void comparison() const;
+
+private:
+ template <typename Data>
+ void conversionTests(Data arg) const;
+ template <typename Char>
+ void fromEmptyLiteral() const;
+ template <typename Char>
+ void fromRange(const Char *first, const Char *last) const;
+ template <typename Char, typename Container>
+ void fromContainer() const;
+ template <typename Char>
+ void fromContainers() const;
+};
+
+void tst_QByteArrayView::constExpr() const
+{
+ // compile-time checks
+ {
+ constexpr QByteArrayView bv;
+ static_assert(bv.size() == 0);
+ static_assert(bv.isNull());
+ static_assert(bv.empty());
+ static_assert(bv.isEmpty());
+ static_assert(bv.data() == nullptr);
+
+ constexpr QByteArrayView bv2(bv.data(), bv.data() + bv.size());
+ static_assert(bv2.isNull());
+ static_assert(bv2.empty());
+ }
+ {
+ constexpr QByteArrayView bv = "";
+ static_assert(bv.size() == 0);
+ static_assert(!bv.isNull());
+ static_assert(bv.empty());
+ static_assert(bv.isEmpty());
+ static_assert(bv.data() != nullptr);
+
+ constexpr QByteArrayView bv2(bv.data(), bv.data() + bv.size());
+ static_assert(!bv2.isNull());
+ static_assert(bv2.empty());
+ }
+ {
+ static_assert(QByteArrayView("Hello").size() == 5);
+ constexpr QByteArrayView bv = "Hello";
+ static_assert(bv.size() == 5);
+ static_assert(!bv.empty());
+ static_assert(!bv.isEmpty());
+ static_assert(!bv.isNull());
+ static_assert(*bv.data() == 'H');
+ static_assert(bv[0] == 'H');
+ static_assert(bv.at(0) == 'H');
+ static_assert(bv.front() == 'H');
+ static_assert(bv.first() == 'H');
+ static_assert(bv[4] == 'o');
+ static_assert(bv.at(4) == 'o');
+ static_assert(bv.back() == 'o');
+ static_assert(bv.last() == 'o');
+
+ static_assert(*bv.begin() == 'H' );
+ static_assert(*(bv.end() - 1) == 'o' );
+ static_assert(*bv.cbegin() == 'H' );
+ static_assert(*(bv.cend() - 1) == 'o' );
+ static_assert(*bv.rbegin() == 'o' );
+ static_assert(*bv.crbegin() == 'o' );
+
+ // This is just to test that rend()/crend() are constexpr.
+ static_assert(bv.rbegin() != bv.rend());
+ static_assert(bv.crbegin() != bv.crend());
+
+ constexpr QByteArrayView bv2(bv.data(), bv.data() + bv.size());
+ static_assert(!bv2.isNull());
+ static_assert(!bv2.empty());
+ static_assert(bv2.size() == 5);
+ }
+ {
+ static constexpr char hello[] = "Hello";
+ constexpr QByteArrayView bv(hello);
+ static_assert(bv.size() == 5);
+ static_assert(!bv.empty());
+ static_assert(!bv.isEmpty());
+ static_assert(!bv.isNull());
+ static_assert(*bv.data() == 'H');
+ static_assert(bv[0] == 'H');
+ static_assert(bv.at(0) == 'H');
+ static_assert(bv.front() == 'H');
+ static_assert(bv.first() == 'H');
+ static_assert(bv[4] == 'o');
+ static_assert(bv.at(4) == 'o');
+ static_assert(bv.back() == 'o');
+ static_assert(bv.last() == 'o');
+ }
+ {
+ static constexpr char hello[] = { 'H', 'e', 'l', 'l', 'o' };
+ constexpr QByteArrayView bv(hello, std::size(hello));
+ static_assert(bv.size() == 5);
+ static_assert(!bv.empty());
+ static_assert(!bv.isEmpty());
+ static_assert(!bv.isNull());
+ static_assert(*bv.data() == 'H');
+ static_assert(bv[0] == 'H');
+ static_assert(bv.at(0) == 'H');
+ static_assert(bv.front() == 'H');
+ static_assert(bv.first() == 'H');
+ static_assert(bv[4] == 'o');
+ static_assert(bv.at(4) == 'o');
+ static_assert(bv.back() == 'o');
+ static_assert(bv.last() == 'o');
+ }
+ {
+ constexpr char *null = nullptr;
+ constexpr QByteArrayView bv(null);
+ static_assert(bv.isNull());
+ static_assert(bv.isEmpty());
+ static_assert(bv.size() == 0);
+ }
+}
+
+void tst_QByteArrayView::basics() const
+{
+ QByteArrayView bv1;
+
+ // a default-constructed QByteArrayView is null:
+ QVERIFY(bv1.isNull());
+ // which implies it's empty();
+ QVERIFY(bv1.isEmpty());
+
+ QByteArrayView bv2;
+
+ QVERIFY(bv2 == bv1);
+ QVERIFY(!(bv2 != bv1));
+}
+
+void tst_QByteArrayView::literals() const
+{
+ const char hello[] = "Hello";
+
+ QCOMPARE(QByteArrayView(hello).size(), 5);
+ QCOMPARE(QByteArrayView(hello + 0).size(), 5); // forces decay to pointer
+ QByteArrayView bv = hello;
+ QCOMPARE(bv.size(), 5);
+ QVERIFY(!bv.empty());
+ QVERIFY(!bv.isEmpty());
+ QVERIFY(!bv.isNull());
+ QCOMPARE(*bv.data(), 'H');
+ QCOMPARE(bv[0], 'H');
+ QCOMPARE(bv.at(0), 'H');
+ QCOMPARE(bv.front(), 'H');
+ QCOMPARE(bv.first(), 'H');
+ QCOMPARE(bv[4], 'o');
+ QCOMPARE(bv.at(4), 'o');
+ QCOMPARE(bv.back(), 'o');
+ QCOMPARE(bv.last(), 'o');
+
+ QByteArrayView bv2(bv.data(), bv.data() + bv.size());
+ QVERIFY(!bv2.isNull());
+ QVERIFY(!bv2.empty());
+ QCOMPARE(bv2.size(), 5);
+}
+
+void tst_QByteArrayView::literalsWithInternalNulls() const
+{
+ const char withnull[] = "a\0zzz";
+
+ // these are different results
+ QCOMPARE(size_t(QByteArrayView(withnull).size()), sizeof(withnull)/sizeof(withnull[0]) - 1);
+ QCOMPARE(QByteArrayView(withnull + 0).size(), 1);
+
+ QByteArrayView nulled(withnull);
+ QCOMPARE(nulled[1], '\0');
+ QCOMPARE(nulled.indexOf('\0'), 1);
+ QCOMPARE(nulled.indexOf('z'), 2);
+ QCOMPARE(nulled.lastIndexOf('z'), 4);
+ QCOMPARE(nulled.lastIndexOf('a'), 0);
+ QVERIFY(nulled.startsWith("a\0z"));
+ QVERIFY(!nulled.startsWith("a\0y"));
+ QVERIFY(nulled.endsWith("zz"));
+ QVERIFY(nulled.contains("z"));
+ QVERIFY(nulled.contains("\0z"));
+ QVERIFY(!nulled.contains("\0y"));
+ QCOMPARE(nulled.first(5), withnull);
+ QCOMPARE(nulled.last(5), withnull);
+ QCOMPARE(nulled.sliced(0), withnull);
+ QCOMPARE(nulled.sliced(2, 2), "zz");
+ QCOMPARE(nulled.chopped(2), "a\0z");
+ QVERIFY(nulled.chopped(2) != "a\0y");
+ QCOMPARE(nulled.count('z'), 3);
+
+ const char nullfirst[] = "\0buzz";
+ QByteArrayView fromnull(nullfirst);
+ QVERIFY(!fromnull.isEmpty());
+
+ const char nullNotEnd[] = { 'b', 'o', 'w', '\0', 'a', 'f', 't', 'z' };
+ QByteArrayView midNull(nullNotEnd);
+ QCOMPARE(midNull.back(), 't');
+}
+
+void tst_QByteArrayView::at() const
+{
+ QByteArray hello("Hello");
+ QByteArrayView bv(hello);
+ QCOMPARE(bv.at(0), 'H'); QCOMPARE(bv[0], 'H');
+ QCOMPARE(bv.at(1), 'e'); QCOMPARE(bv[1], 'e');
+ QCOMPARE(bv.at(2), 'l'); QCOMPARE(bv[2], 'l');
+ QCOMPARE(bv.at(3), 'l'); QCOMPARE(bv[3], 'l');
+ QCOMPARE(bv.at(4), 'o'); QCOMPARE(bv[4], 'o');
+}
+
+void tst_QByteArrayView::fromQByteArray() const
+{
+ QByteArray null;
+ QByteArray empty = "";
+
+ QVERIFY(QByteArrayView(null).isNull());
+ QVERIFY(!qToByteArrayViewIgnoringNull(null).isNull());
+
+ QVERIFY(QByteArrayView(null).isEmpty());
+ QVERIFY(qToByteArrayViewIgnoringNull(null).isEmpty());
+
+ QVERIFY(QByteArrayView(empty).isEmpty());
+ QVERIFY(qToByteArrayViewIgnoringNull(empty).isEmpty());
+
+ QVERIFY(!QByteArrayView(empty).isNull());
+ QVERIFY(!qToByteArrayViewIgnoringNull(empty).isNull());
+
+ conversionTests(QByteArray("Hello World!"));
+}
+
+namespace help {
+template <typename T>
+size_t size(const T &t) { return size_t(t.size()); }
+template <typename T>
+size_t size(const T *t) { return std::char_traits<T>::length(t); }
+
+template <typename T>
+decltype(auto) cbegin(const T &t) { return t.begin(); }
+template <typename T>
+const T * cbegin(const T *t) { return t; }
+
+template <typename T>
+decltype(auto) cend(const T &t) { return t.end(); }
+template <typename T>
+const T * cend(const T *t) { return t + size(t); }
+
+template <typename T>
+decltype(auto) crbegin(const T &t) { return t.rbegin(); }
+template <typename T>
+std::reverse_iterator<const T*> crbegin(const T *t) { return std::reverse_iterator<const T*>(cend(t)); }
+
+template <typename T>
+decltype(auto) crend(const T &t) { return t.rend(); }
+template <typename T>
+std::reverse_iterator<const T*> crend(const T *t) { return std::reverse_iterator<const T*>(cbegin(t)); }
+
+} // namespace help
+
+template <typename Data>
+void tst_QByteArrayView::conversionTests(Data data) const
+{
+ // copy-construct:
+ {
+ QByteArrayView bv = data;
+
+ QCOMPARE(help::size(bv), help::size(data));
+
+ const auto compare = [](auto v1, auto v2) {
+ if constexpr (std::is_same_v<decltype(v1), std::byte>)
+ return std::to_integer<char>(v1) == v2;
+ else
+ return v1 == v2;
+ };
+ QVERIFY(std::equal(help::cbegin(data), help::cend(data),
+ QT_MAKE_CHECKED_ARRAY_ITERATOR(bv.cbegin(), bv.size()), compare));
+ QVERIFY(std::equal(help::cbegin(data), help::cend(data),
+ QT_MAKE_CHECKED_ARRAY_ITERATOR(bv.begin(), bv.size()), compare));
+ QVERIFY(std::equal(help::crbegin(data), help::crend(data), bv.crbegin(), compare));
+ QVERIFY(std::equal(help::crbegin(data), help::crend(data), bv.rbegin(), compare));
+ QCOMPARE(bv, data);
+ }
+
+ QByteArrayView bv;
+
+ // copy-assign:
+ {
+ bv = data;
+
+ QCOMPARE(help::size(bv), help::size(data));
+
+ // check relational operators:
+
+ QCOMPARE(bv, data);
+ QCOMPARE(data, bv);
+
+ QVERIFY(!(bv != data));
+ QVERIFY(!(data != bv));
+
+ QVERIFY(!(bv < data));
+ QVERIFY(bv <= data);
+ QVERIFY(!(bv > data));
+ QVERIFY(bv >= data);
+
+ QVERIFY(!(data < bv));
+ QVERIFY(data <= bv);
+ QVERIFY(!(data > bv));
+ QVERIFY(data >= bv);
+ }
+
+ // copy-construct from rvalue (QByteArrayView never assumes ownership):
+ {
+ QByteArrayView bv2 = std::move(data);
+ QCOMPARE(bv2, bv);
+ QCOMPARE(bv2, data);
+ }
+
+ // copy-assign from rvalue (QByteArrayView never assumes ownership):
+ {
+ QByteArrayView bv2;
+ bv2 = std::move(data);
+ QCOMPARE(bv2, bv);
+ QCOMPARE(bv2, data);
+ }
+}
+
+template <typename Char>
+void tst_QByteArrayView::fromEmptyLiteral() const
+{
+ const Char *null = nullptr;
+ const Char empty[] = { Char{0} };
+
+ QCOMPARE(QByteArrayView(null).size(), 0);
+ QCOMPARE(QByteArrayView(null).data(), nullptr);
+ QCOMPARE(QByteArrayView(empty).size(), 0);
+ QCOMPARE(static_cast<const void*>(QByteArrayView(empty).data()),
+ static_cast<const void*>(empty));
+
+ QVERIFY(QByteArrayView(null).isNull());
+ QVERIFY(QByteArrayView(null).isEmpty());
+ QVERIFY(QByteArrayView(empty).isEmpty());
+ QVERIFY(!QByteArrayView(empty).isNull());
+}
+
+template <typename Char>
+void tst_QByteArrayView::fromRange(const Char *first, const Char *last) const
+{
+ const Char *null = nullptr;
+ QCOMPARE(QByteArrayView(null, null).size(), 0);
+ QCOMPARE(QByteArrayView(null, null).data(), nullptr);
+ QCOMPARE(QByteArrayView(first, first).size(), 0);
+ QCOMPARE(static_cast<const void*>(QByteArrayView(first, first).data()),
+ static_cast<const void*>(first));
+
+ const auto bv = QByteArrayView(first, last);
+ QCOMPARE(bv.size(), last - first);
+ QCOMPARE(static_cast<const void*>(bv.data()),
+ static_cast<const void*>(first));
+
+ QCOMPARE(static_cast<const void*>(bv.last(0).data()),
+ static_cast<const void*>(last));
+ QCOMPARE(static_cast<const void*>(bv.sliced(bv.size()).data()),
+ static_cast<const void*>(last));
+
+ // can't call conversionTests() here, as it requires a single object
+}
+
+template <typename Char, typename Container>
+void tst_QByteArrayView::fromContainer() const
+{
+ const QByteArray s = "Hello World!";
+
+ Container c;
+ // unspecified whether empty containers make null QByteArrayView
+ QVERIFY(QByteArrayView(c).isEmpty());
+
+ QCOMPARE(sizeof(Char), sizeof(char));
+
+ const auto *data = reinterpret_cast<const Char *>(s.data());
+ std::copy(data, data + s.size(), std::back_inserter(c));
+ conversionTests(std::move(c));
+}
+
+template <typename Char>
+void tst_QByteArrayView::fromContainers() const
+{
+ fromContainer<Char, QVector<Char>>();
+ fromContainer<Char, QVarLengthArray<Char>>();
+ fromContainer<Char, std::vector<Char>>();
+ fromContainer<Char, std::basic_string<Char>>();
+}
+
+void tst_QByteArrayView::comparison() const
+{
+ const QByteArrayView aa = "aa";
+ const QByteArrayView bb = "bb";
+
+ QVERIFY(aa == aa);
+ QVERIFY(aa != bb);
+ QVERIFY(aa < bb);
+ QVERIFY(bb > aa);
+}
+
+QTEST_APPLESS_MAIN(tst_QByteArrayView)
+#include "tst_qbytearrayview.moc"
diff --git a/tests/auto/corelib/text/text.pro b/tests/auto/corelib/text/text.pro
index bad5f6d61a..272bcb1013 100644
--- a/tests/auto/corelib/text/text.pro
+++ b/tests/auto/corelib/text/text.pro
@@ -5,6 +5,7 @@ SUBDIRS = \
qbytearrayapisymmetry \
qbytearraylist \
qbytearraymatcher \
+ qbytearrayview \
qbytedatabuffer \
qchar \
qcollator \