diff options
-rw-r--r-- | src/corelib/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/corelib/doc/snippets/code/src_corelib_text_qbytearray.cpp | 4 | ||||
-rw-r--r-- | src/corelib/doc/snippets/code/src_corelib_text_qbytearrayview.cpp | 67 | ||||
-rw-r--r-- | src/corelib/global/qglobal.h | 2 | ||||
-rw-r--r-- | src/corelib/text/qbytearray.cpp | 388 | ||||
-rw-r--r-- | src/corelib/text/qbytearray.h | 82 | ||||
-rw-r--r-- | src/corelib/text/qbytearrayalgorithms.h | 76 | ||||
-rw-r--r-- | src/corelib/text/qbytearrayview.h | 313 | ||||
-rw-r--r-- | src/corelib/text/qbytearrayview.qdoc | 692 | ||||
-rw-r--r-- | src/corelib/text/text.pri | 2 | ||||
-rw-r--r-- | src/corelib/tools/qhash.cpp | 12 | ||||
-rw-r--r-- | src/corelib/tools/qhashfunctions.h | 1 | ||||
-rw-r--r-- | src/tools/moc/generator.cpp | 6 | ||||
-rw-r--r-- | src/tools/uic/qclass_lib_map.h | 1 | ||||
-rw-r--r-- | tests/auto/corelib/text/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/corelib/text/qbytearrayview/CMakeLists.txt | 10 | ||||
-rw-r--r-- | tests/auto/corelib/text/qbytearrayview/qbytearrayview.pro | 4 | ||||
-rw-r--r-- | tests/auto/corelib/text/qbytearrayview/tst_qbytearrayview.cpp | 595 | ||||
-rw-r--r-- | tests/auto/corelib/text/text.pro | 1 |
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 \ |