diff options
author | Lars Knoll <lars.knoll@qt.io> | 2020-07-09 16:55:47 +0200 |
---|---|---|
committer | Mårten Nordheim <marten.nordheim@qt.io> | 2020-09-03 14:15:52 +0200 |
commit | 8897aa071a668563a53a4c2e6909572f1762b1e7 (patch) | |
tree | 5c6ee5d4eb68361ad02b83cc735726c3a51f4af2 /src/corelib/text/qbytearray.cpp | |
parent | 8eef75f0b52519f15078c29dfde5354ca7cccbdb (diff) |
Clean up the QByteArray API and implementation
Add overloads using a QByteArrayView where it makes sense, and
call those inline from the other overloads. Remove overloads
that are not required anymore (due to implicit conversion of
a const char * to a QByteArrayView).
Guard all implementations against passing this object to them.
Change-Id: I930156f8b05ce72c32cb8201c70513f2e6e19d3e
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src/corelib/text/qbytearray.cpp')
-rw-r--r-- | src/corelib/text/qbytearray.cpp | 323 |
1 files changed, 89 insertions, 234 deletions
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index 27986baeae..9b58136c0d 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -67,6 +67,12 @@ QT_BEGIN_NAMESPACE +template <typename T, typename Cmp = std::less<>> +static constexpr bool points_into_range(const T *p, const T *b, const T *e, Cmp less = {}) noexcept +{ + return !less(p, b) && less(p, e); +} + const char QByteArray::_empty = '\0'; // ASCII case system, used by QByteArray::to{Upper,Lower}() and qstr(n)icmp(): @@ -470,7 +476,7 @@ static const quint16 crc_tbl[16] = { \relates QByteArray \since 5.9 - Returns the CRC-16 checksum of the first \a len bytes of \a data. + Returns the CRC-16 checksum of \a data. The checksum is independent of the byte order (endianness) and will be calculated accorded to the algorithm published in \a standard. @@ -479,7 +485,7 @@ static const quint16 crc_tbl[16] = { \note This function is a 16-bit cache conserving (16 entry table) implementation of the CRC-16-CCITT algorithm. */ -quint16 qChecksum(const char *data, qsizetype len, Qt::ChecksumType standard) +quint16 qChecksum(QByteArrayView data, Qt::ChecksumType standard) { quint16 crc = 0x0000; switch (standard) { @@ -491,7 +497,8 @@ quint16 qChecksum(const char *data, qsizetype len, Qt::ChecksumType standard) break; } uchar c; - const uchar *p = reinterpret_cast<const uchar *>(data); + const uchar *p = reinterpret_cast<const uchar *>(data.data()); + qsizetype len = data.size(); while (len--) { c = *p++; crc = ((crc >> 4) & 0x0fff) ^ crc_tbl[((crc ^ c) & 15)]; @@ -1697,7 +1704,9 @@ QByteArray QByteArray::nulTerminated() const } /*! - Prepends the byte array \a ba to this byte array and returns a + \fn QByteArray &QByteArray::prepend(QByteArrayView ba) + + Prepends the byte array view \a ba to this byte array and returns a reference to this byte array. Example: @@ -1705,42 +1714,25 @@ QByteArray QByteArray::nulTerminated() const This is the same as insert(0, \a ba). - Note: QByteArray is an \l{implicitly shared} class. Consequently, - if you prepend to an empty byte array, then the byte array will just - share the data held in \a ba. In this case, no copying of data is done, - taking \l{constant time}. If a shared instance is modified, it will - be copied (copy-on-write), taking \l{linear time}. - - If the byte array being prepended to is not empty, a deep copy of the - data is performed, taking \l{linear time}. - \sa append(), insert() */ -QByteArray &QByteArray::prepend(const QByteArray &ba) -{ - if (size() == 0 && ba.d.isMutable()) { - *this = ba; - } else if (ba.size() != 0) { - QByteArray tmp = *this; - *this = ba; - append(tmp); - } - return *this; -} +/*! + \fn QByteArray &QByteArray::prepend(const QByteArray &ba) + \overload + + Prepends \a ba to this byte array. +*/ /*! + \fn QByteArray &QByteArray::prepend(const char *str) \overload Prepends the '\\0'-terminated string \a str to this byte array. */ -QByteArray &QByteArray::prepend(const char *str) -{ - return prepend(str, qstrlen(str)); -} - /*! + \fn QByteArray &QByteArray::prepend(const char *str, qsizetype len) \overload \since 4.6 @@ -1748,18 +1740,6 @@ QByteArray &QByteArray::prepend(const char *str) The bytes prepended may include '\\0' bytes. */ -QByteArray &QByteArray::prepend(const char *str, qsizetype len) -{ - if (str) { - const bool shouldGrow = d->shouldGrowBeforeInsert(d.begin(), len); - if (d->needsDetach() || size() + len > capacity() || shouldGrow) - reallocGrowData(size_t(size() + len) + 1u, d->detachFlags() | Data::GrowsBackwards); - d->insert(d.begin(), str, str + len); - d.data()[d.size] = '\0'; - } - return *this; -} - /*! \fn QByteArray &QByteArray::prepend(qsizetype count, char ch) \overload @@ -1769,21 +1749,12 @@ QByteArray &QByteArray::prepend(const char *str, qsizetype len) */ /*! + \fn QByteArray &QByteArray::prepend(char ch) \overload Prepends the byte \a ch to this byte array. */ -QByteArray &QByteArray::prepend(char ch) -{ - const bool shouldGrow = d->shouldGrowBeforeInsert(d.begin(), 1); - if (d->needsDetach() || size() + 1 > capacity() || shouldGrow) - reallocGrowData(size_t(size()) + 2u, d->detachFlags() | Data::GrowsBackwards); - d->insert(d.begin(), 1, ch); - d.data()[d.size] = '\0'; - return *this; -} - /*! Appends the byte array \a ba onto the end of this byte array. @@ -1810,39 +1781,28 @@ QByteArray &QByteArray::prepend(char ch) QByteArray &QByteArray::append(const QByteArray &ba) { - if (size() == 0 && ba.d.isMutable()) { - *this = ba; - } else if (ba.size() != 0) { - const bool shouldGrow = d->shouldGrowBeforeInsert(d.end(), ba.size()); - if (d->needsDetach() || size() + ba.size() > capacity() || shouldGrow) - reallocGrowData(size_t(size() + ba.size()) + 1u, d->detachFlags() | Data::GrowsForward); - d->copyAppend(ba.data(), ba.data() + ba.size()); - d.data()[d.size] = '\0'; - } - return *this; + if (size() == 0 && ba.d.isMutable()) + return (*this = ba); + return append(QByteArrayView(ba)); } /*! + \fn QByteArray &QByteArray::append(QByteArrayView data) \overload - Appends the '\\0'-terminated string \a str to this byte array. + Appends \a data to this byte array. */ -QByteArray& QByteArray::append(const char *str) -{ - if (str) { - const qsizetype len = qsizetype(strlen(str)); - const bool shouldGrow = d->shouldGrowBeforeInsert(d.end(), len); - if (d->needsDetach() || size() + len > capacity() || shouldGrow) - reallocGrowData(size_t(size() + len) + 1u, d->detachFlags() | Data::GrowsForward); - d->copyAppend(str, str + len); - d.data()[d.size] = '\0'; - } - return *this; -} +/*! + \fn QByteArray& QByteArray::append(const char *str) + \overload + + Appends the '\\0'-terminated string \a str to this byte array. +*/ /*! - \overload append() + \fn QByteArray &QByteArray::append(const char *str, qsizetype len) + \overload Appends the first \a len bytes starting at \a str to this byte array and returns a reference to this byte array. The bytes appended may include '\\0' @@ -1856,20 +1816,6 @@ QByteArray& QByteArray::append(const char *str) array. Ensure that \a len is \e not longer than \a str. */ -QByteArray &QByteArray::append(const char *str, qsizetype len) -{ - if (len < 0) - len = qstrlen(str); - if (str && len) { - const bool shouldGrow = d->shouldGrowBeforeInsert(d.end(), len); - if (d->needsDetach() || size() + len > capacity() || shouldGrow) - reallocGrowData(size_t(size() + len) + 1u, d->detachFlags() | Data::GrowsForward); - d->copyAppend(str, str + len); - d.data()[d.size] = '\0'; - } - return *this; -} - /*! \fn QByteArray &QByteArray::append(qsizetype count, char ch) \overload @@ -1898,63 +1844,27 @@ QByteArray& QByteArray::append(char ch) } /*! - \internal - Inserts \a len bytes from the array \a arr at position \a pos and returns a - reference the modified byte array. -*/ -static inline QByteArray &qbytearray_insert(QByteArray *ba, - qsizetype pos, const char *arr, qsizetype len) -{ - return ba->insert(pos, arr, len); -} - -/*! - Inserts the byte array \a ba at index position \a i and returns a + Inserts \a data at index position \a i and returns a reference to this byte array. Example: \snippet code/src_corelib_text_qbytearray.cpp 17 + \since 6.0 \sa append(), prepend(), replace(), remove() */ - -QByteArray &QByteArray::insert(qsizetype i, const QByteArray &ba) -{ - QByteArray copy(ba); - return qbytearray_insert(this, i, copy.constData(), copy.size()); -} - -/*! - \overload - - Inserts the '\\0'-terminated string \a str at position \a i in the byte - array. - - If \a i is greater than size(), the array is first extended using - resize(). -*/ - -QByteArray &QByteArray::insert(qsizetype i, const char *str) -{ - return qbytearray_insert(this, i, str, qstrlen(str)); -} - -/*! - \overload - \since 4.6 - - Inserts \a len bytes, starting at \a str, at position \a i in the byte - array. - - If \a i is greater than size(), the array is first extended using - resize(). -*/ - -QByteArray &QByteArray::insert(qsizetype i, const char *str, qsizetype len) +QByteArray &QByteArray::insert(qsizetype i, QByteArrayView data) { + const char *str = data.data(); + qsizetype len = data.size(); if (i < 0 || str == nullptr || len <= 0) return *this; + if (points_into_range(str, d.data(), d.data() + d.size)) { + QVarLengthArray a(str, str + len); + return insert(i, a); + } + const auto oldSize = size(); const auto newSize = qMax(i, oldSize) + len; const bool shouldGrow = d->shouldGrowBeforeInsert(d.begin() + qMin(i, oldSize), len); @@ -1962,7 +1872,7 @@ QByteArray &QByteArray::insert(qsizetype i, const char *str, qsizetype len) // ### optimize me if (d->needsDetach() || newSize > capacity() || shouldGrow) { auto flags = d->detachFlags() | Data::GrowsForward; - if (i <= oldSize / 4) // using QList's policy + if (oldSize != 0 && i <= oldSize / 4) // using QList's policy flags |= Data::GrowsBackwards; reallocGrowData(newSize + 1, flags); } @@ -1976,17 +1886,25 @@ QByteArray &QByteArray::insert(qsizetype i, const char *str, qsizetype len) } /*! + \fn QByteArray &QByteArray::insert(qsizetype i, const char *data, qsizetype len) + \overload + \since 4.6 + + Inserts \a len bytes, starting at \a data, at position \a i in the byte + array. + + If \a i is greater than size(), the array is first extended using + resize(). +*/ + +/*! + \fn QByteArray &QByteArray::insert(qsizetype i, char ch) \overload Inserts byte \a ch at index position \a i in the byte array. If \a i is greater than size(), the array is first extended using resize(). */ -QByteArray &QByteArray::insert(qsizetype i, char ch) -{ - return qbytearray_insert(this, i, &ch, 1); -} - /*! \fn QByteArray &QByteArray::insert(qsizetype i, qsizetype count, char ch) \overload @@ -2057,34 +1975,23 @@ QByteArray &QByteArray::remove(qsizetype pos, qsizetype len) \sa insert(), remove() */ -QByteArray &QByteArray::replace(qsizetype pos, qsizetype len, const QByteArray &after) +QByteArray &QByteArray::replace(qsizetype pos, qsizetype len, QByteArrayView after) { + if (points_into_range(after.data(), d.data(), d.data() + d.size)) { + QVarLengthArray copy(after.data(), after.data() + after.size()); + return replace(pos, len, QByteArrayView{copy}); + } if (len == after.size() && (pos + len <= size())) { detach(); memmove(d.data() + pos, after.data(), len*sizeof(char)); return *this; } else { - QByteArray copy(after); // ### optimize me remove(pos, len); - return insert(pos, copy); + return insert(pos, after); } } -/*! \fn QByteArray &QByteArray::replace(qsizetype pos, qsizetype len, const char *after) - - \overload - - Replaces \a len bytes from index position \a pos with the - '\\0'-terminated string \a after. - - Notice: this can change the length of the byte array. -*/ -QByteArray &QByteArray::replace(qsizetype pos, qsizetype len, const char *after) -{ - return replace(pos,len,after,qstrlen(after)); -} - /*! \fn QByteArray &QByteArray::replace(qsizetype pos, qsizetype len, const char *after, qsizetype alen) \overload @@ -2094,81 +2001,49 @@ QByteArray &QByteArray::replace(qsizetype pos, qsizetype len, const char *after) \since 4.7 */ -QByteArray &QByteArray::replace(qsizetype pos, qsizetype len, const char *after, qsizetype alen) -{ - if (len == alen && (pos + len <= size())) { - detach(); - memcpy(d.data() + pos, after, len*sizeof(char)); - return *this; - } else { - remove(pos, len); - return qbytearray_insert(this, pos, after, alen); - } -} - -// ### optimize all other replace method, by offering -// QByteArray::replace(const char *before, qsizetype blen, const char *after, qsizetype alen) /*! + \fn QByteArray &QByteArray::replace(const char *before, qsizetype bsize, const char *after, qsizetype asize) \overload - Replaces every occurrence of the byte array \a before with the - byte array \a after. - - Example: - \snippet code/src_corelib_text_qbytearray.cpp 20 + Replaces every occurrence of the \a bsize bytes starting at \a before with + the \a asize bytes starting at \a after. Since the sizes of the strings are + given by \a bsize and \a asize, they may contain '\\0' bytes and do not need + to be '\\0'-terminated. */ -QByteArray &QByteArray::replace(const QByteArray &before, const QByteArray &after) -{ - return replace(before.constData(), before.size(), after.constData(), after.size()); -} - /*! - \fn QByteArray &QByteArray::replace(const char *before, const QByteArray &after) \overload + \since 6.0 - Replaces every occurrence of the '\\0'-terminated string \a before with the + Replaces every occurrence of the byte array \a before with the byte array \a after. -*/ - -QByteArray &QByteArray::replace(const char *c, const QByteArray &after) -{ - return replace(c, qstrlen(c), after.constData(), after.size()); -} - -/*! - \fn QByteArray &QByteArray::replace(const char *before, qsizetype bsize, const char *after, qsizetype asize) - \overload - Replaces every occurrence of the \a bsize bytes starting at \a before with - the \a size bytes starting at \a after. Since the sizes of the strings are - given by \a bsize and \a asize, they may contain '\\0' bytes and do not need - to be '\\0'-terminated. + Example: + \snippet code/src_corelib_text_qbytearray.cpp 20 */ -QByteArray &QByteArray::replace(const char *before, qsizetype bsize, const char *after, qsizetype asize) +QByteArray &QByteArray::replace(QByteArrayView before, QByteArrayView after) { - if (isNull() || (before == after && bsize == asize)) + const char *b = before.data(); + qsizetype bsize = before.size(); + const char *a = after.data(); + qsizetype asize = after.size(); + + if (isNull() || (b == a && bsize == asize)) return *this; // protect against before or after being part of this - const char *a = after; - const char *b = before; - if (after >= constBegin() && after < constEnd()) { - char *copy = (char *)malloc(asize); - Q_CHECK_PTR(copy); - memcpy(copy, after, asize); - a = copy; + if (points_into_range(a, d.data(), d.data() + d.size)) { + QVarLengthArray copy(a, a + asize); + return replace(before, QByteArrayView{copy}); } - if (before >= constBegin() && before < constEnd()) { - char *copy = (char *)malloc(bsize); - Q_CHECK_PTR(copy); - memcpy(copy, before, bsize); - b = copy; + if (points_into_range(b, d.data(), d.data() + d.size)) { + QVarLengthArray copy(b, b + bsize); + return replace(QByteArrayView{copy}, after); } - QByteArrayMatcher matcher(before, bsize); + QByteArrayMatcher matcher(b, bsize); qsizetype index = 0; qsizetype len = size(); char *d = data(); // detaches @@ -2252,13 +2127,6 @@ QByteArray &QByteArray::replace(const char *before, qsizetype bsize, const char } } } - - if (a != after) - ::free(const_cast<char *>(a)); - if (b != before) - ::free(const_cast<char *>(b)); - - return *this; } @@ -2280,26 +2148,13 @@ QByteArray &QByteArray::replace(const char *before, qsizetype bsize, const char */ /*! + \fn QByteArray &QByteArray::replace(char before, QByteArrayView after) \overload Replaces every occurrence of the byte \a before with the byte array \a after. */ -QByteArray &QByteArray::replace(char before, const QByteArray &after) -{ - char b[2] = { before, '\0' }; - return replace(b, 1, after.constData(), after.size()); -} - -/*! \fn QByteArray &QByteArray::replace(char before, const char *after) - - \overload - - Replaces every occurrence of the byte \a before with the '\\0'-terminated - string \a after. -*/ - /*! \overload |