summaryrefslogtreecommitdiffstats
path: root/src/corelib/text
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2019-11-16 23:25:26 +0100
committerLars Knoll <lars.knoll@qt.io>2020-07-06 21:29:58 +0200
commit76004502baa118016c8e0f32895af7a822f1ba37 (patch)
tree3fb524e333cb2edf6e983c4898c76f9eebb04eb4 /src/corelib/text
parent2e51686746c45055e5bb74f58e0c159bfb6a8c13 (diff)
Get rid of shared null for QByteArray, QString and QVector
As a side effect, data() can now return a nullptr. This has the potential to cause crashes in existig code. To work around this, return an empty string from QString::data() and QByteArray::data() for now. For Qt 6 (and once all our internal issues are fixed), data() will by default return a nullptr for a null QString, but we'll offer a #define to enable backwards compatible behavior. Change-Id: I4f66d97ff1dce3eb99a239f1eab9106fa9b1741a Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/text')
-rw-r--r--src/corelib/text/qbytearray.cpp40
-rw-r--r--src/corelib/text/qbytearray.h46
-rw-r--r--src/corelib/text/qstring.cpp15
-rw-r--r--src/corelib/text/qstring.h29
-rw-r--r--src/corelib/text/qstringliteral.h15
5 files changed, 80 insertions, 65 deletions
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index 95a1f9f52c..26e3b64c9d 100644
--- a/src/corelib/text/qbytearray.cpp
+++ b/src/corelib/text/qbytearray.cpp
@@ -67,6 +67,8 @@
QT_BEGIN_NAMESPACE
+const char QByteArray::_empty = '\0';
+
// ASCII case system, used by QByteArray::to{Upper,Lower}() and qstr(n)icmp():
static constexpr inline uchar asciiUpper(uchar c)
{
@@ -364,11 +366,18 @@ int qstrnicmp(const char *str1, const char *str2, uint len)
*/
int qstrnicmp(const char *str1, qsizetype len1, const char *str2, qsizetype len2)
{
- Q_ASSERT(str1);
Q_ASSERT(len1 >= 0);
Q_ASSERT(len2 >= -1);
const uchar *s1 = reinterpret_cast<const uchar *>(str1);
const uchar *s2 = reinterpret_cast<const uchar *>(str2);
+ if (!s1 || !len1) {
+ if (len2 == 0)
+ return 0;
+ if (len2 == -1)
+ return (!s2 || !*s2) ? 0 : -1;
+ Q_ASSERT(s2);
+ return -1;
+ }
if (!s2)
return len1 == 0 ? 0 : 1;
@@ -1694,7 +1703,7 @@ void QByteArray::expand(int i)
QByteArray QByteArray::nulTerminated() const
{
// is this fromRawData?
- if (!IS_RAW_DATA(d))
+ if (d.isMutable())
return *this; // no, then we're sure we're zero terminated
QByteArray copy(*this);
@@ -1725,7 +1734,7 @@ QByteArray QByteArray::nulTerminated() const
QByteArray &QByteArray::prepend(const QByteArray &ba)
{
- if (size() == 0 && d->isStatic() && !IS_RAW_DATA(ba.d)) {
+ if (size() == 0 && d->isStatic() && ba.d.isMutable()) {
*this = ba;
} else if (ba.size() != 0) {
QByteArray tmp = *this;
@@ -1818,7 +1827,7 @@ QByteArray &QByteArray::prepend(char ch)
QByteArray &QByteArray::append(const QByteArray &ba)
{
- if (size() == 0 && d->isStatic() && !IS_RAW_DATA(ba.d)) {
+ if (size() == 0 && d->isStatic() && ba.d.isMutable()) {
*this = ba;
} else if (ba.size() != 0) {
if (d->needsDetach() || size() + ba.size() > capacity())
@@ -2507,6 +2516,8 @@ static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char
int QByteArray::lastIndexOf(const QByteArray &ba, int from) const
{
+ if (isEmpty())
+ return !ba.size() ? 0 : -1;
const int ol = ba.size();
if (ol == 1)
return lastIndexOf(ba[0], from);
@@ -2524,6 +2535,8 @@ int QByteArray::lastIndexOf(const QByteArray &ba, int from) const
*/
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);
@@ -3484,6 +3497,11 @@ T toIntegral_helper(const char *data, bool *ok, int base)
base = 10;
}
#endif
+ if (!data) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
// we select the right overload by the last, unused parameter
Int64 val = toIntegral_helper(data, ok, base, Int64());
@@ -4154,6 +4172,8 @@ QByteArray QByteArray::number(double n, char f, int prec)
}
/*!
+ \fn QByteArray QByteArray::fromRawData(const char *data, int size) constexpr
+
Constructs a QByteArray that uses the first \a size bytes of the
\a data array. The bytes are \e not copied. The QByteArray will
contain the \a data pointer. The caller guarantees that \a data
@@ -4187,18 +4207,6 @@ QByteArray QByteArray::number(double n, char f, int prec)
\sa setRawData(), data(), constData()
*/
-QByteArray QByteArray::fromRawData(const char *data, int size)
-{
- QByteArray::DataPointer x;
- if (!data) {
- } else if (!size) {
- x = DataPointer(Data::allocate(0), 0);
- } else {
- x = Data::fromRawData(data, size);
- }
- return QByteArray(x);
-}
-
/*!
\since 4.7
diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h
index 5cbcecb956..c2ec72ae76 100644
--- a/src/corelib/text/qbytearray.h
+++ b/src/corelib/text/qbytearray.h
@@ -54,6 +54,11 @@
#include <string>
#include <iterator>
+#ifndef QT5_NULL_STRINGS
+// ### Should default to 0 in Qt 6.0
+#define QT5_NULL_STRINGS 1
+#endif
+
#ifdef truncate
#error qbytearray.h must be included before any header file that defines truncate
#endif
@@ -117,16 +122,7 @@ class QDataStream;
using QByteArrayData = QArrayDataPointer<char>;
# define QByteArrayLiteral(str) \
- ([]() -> QByteArray { \
- enum { Size = sizeof(str) - 1 }; \
- static const QArrayData qbytearray_literal = { \
- Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 }; \
- QByteArrayData holder = { \
- static_cast<QTypedArrayData<char> *>(const_cast<QArrayData *>(&qbytearray_literal)), \
- const_cast<char *>(str), \
- Size }; \
- return QByteArray(holder); \
- }()) \
+ (QByteArray(QByteArrayData(nullptr, const_cast<char *>(str), sizeof(str) - 1))) \
/**/
class Q_CORE_EXPORT QByteArray
@@ -137,6 +133,7 @@ private:
typedef QTypedArrayData<char> Data;
DataPointer d;
+ static const char _empty;
public:
enum Base64Option {
@@ -158,7 +155,7 @@ public:
IllegalPadding,
};
- inline QByteArray() noexcept;
+ inline constexpr QByteArray() noexcept;
QByteArray(const char *, int size = -1);
QByteArray(int size, char c);
QByteArray(int size, Qt::Initialization);
@@ -357,7 +354,10 @@ public:
Q_REQUIRED_RESULT static QByteArray number(qlonglong, int base = 10);
Q_REQUIRED_RESULT static QByteArray number(qulonglong, int base = 10);
Q_REQUIRED_RESULT static QByteArray number(double, char f = 'g', int prec = 6);
- Q_REQUIRED_RESULT static QByteArray fromRawData(const char *, int size);
+ Q_REQUIRED_RESULT static QByteArray fromRawData(const char *data, int size)
+ {
+ return QByteArray(DataPointer(nullptr, const_cast<char *>(data), size));
+ }
class FromBase64Result;
Q_REQUIRED_RESULT static FromBase64Result fromBase64Encoding(QByteArray &&base64, Base64Options options = Base64Encoding);
@@ -449,7 +449,7 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QByteArray::Base64Options)
-inline QByteArray::QByteArray() noexcept {}
+inline constexpr QByteArray::QByteArray() noexcept {}
inline QByteArray::~QByteArray() {}
inline char QByteArray::at(int i) const
@@ -466,11 +466,21 @@ inline QByteArray::operator const void *() const
{ return data(); }
#endif
inline char *QByteArray::data()
-{ detach(); return d.data(); }
+{
+ detach();
+ Q_ASSERT(d.data());
+ return d.data();
+}
inline const char *QByteArray::data() const
-{ return d.data(); }
+{
+#if QT5_NULL_STRINGS == 1
+ return d.data() ? d.data() : &_empty;
+#else
+ return d.data();
+#endif
+}
inline const char *QByteArray::constData() const
-{ return d.data(); }
+{ return data(); }
inline void QByteArray::detach()
{ if (d->needsDetach()) reallocData(uint(size()) + 1u, d->detachFlags()); }
inline bool QByteArray::isDetached() const
@@ -486,7 +496,7 @@ inline void QByteArray::reserve(int asize)
if (d->needsDetach() || asize > capacity()) {
reallocData(qMax(uint(size()), uint(asize)) + 1u, d->detachFlags() | Data::CapacityReserved);
} else {
- d->flags() |= Data::CapacityReserved;
+ d->setFlag(Data::CapacityReserved);
}
}
@@ -497,7 +507,7 @@ inline void QByteArray::squeeze()
if (d->needsDetach() || size() < capacity()) {
reallocData(uint(size()) + 1u, d->detachFlags() & ~Data::CapacityReserved);
} else {
- d->flags() &= uint(~Data::CapacityReserved);
+ d->clearFlag(Data::CapacityReserved);
}
}
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index d327264218..af3be9ab9f 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -106,6 +106,8 @@ static constexpr bool points_into_range(const T *p, const T *b, const T *e, Cmp
return !less(p, b) && less(p, e);
}
+const char16_t QString::_empty = 0;
+
/*
* Note on the use of SIMD in qstring.cpp:
*
@@ -4549,7 +4551,7 @@ QString QString::mid(int position, int n) const
{
QPair<Data *, char16_t *> pair = Data::allocate(0);
DataPointer empty = { pair.first, pair.second, 0 };
- return QString(empty);
+ return QString(std::move(empty));
}
case QContainerImplHelper::Full:
return *this;
@@ -5066,7 +5068,7 @@ QString QString::fromLocal8Bit_helper(const char *str, int size)
if (size == 0 || (!*str && size < 0)) {
QPair<Data *, char16_t *> pair = Data::allocate(0);
QString::DataPointer empty = { pair.first, pair.second, 0 };
- return QString(empty);
+ return QString(std::move(empty));
}
QStringDecoder toUtf16(QStringDecoder::System, QStringDecoder::Flag::Stateless);
return toUtf16(str, size);
@@ -8617,14 +8619,7 @@ bool QString::isRightToLeft() const
*/
QString QString::fromRawData(const QChar *unicode, int size)
{
- QString::DataPointer x;
- if (!unicode) {
- } else if (!size) {
- x = DataPointer(Data::allocate(0), 0);
- } else {
- x = Data::fromRawData(reinterpret_cast<const char16_t *>(unicode), size);
- }
- return QString(x);
+ return QString(Data::fromRawData(const_cast<char16_t *>(reinterpret_cast<const char16_t *>(unicode)), size));
}
/*!
diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h
index 95376f79c0..da553ddde4 100644
--- a/src/corelib/text/qstring.h
+++ b/src/corelib/text/qstring.h
@@ -275,7 +275,7 @@ class Q_CORE_EXPORT QString
public:
typedef QStringPrivate DataPointer;
- inline QString() noexcept;
+ inline constexpr QString() noexcept;
explicit QString(const QChar *unicode, int size = -1);
QString(QChar c);
QString(int size, QChar c);
@@ -902,7 +902,7 @@ public:
{ return QStringView(*this).isValidUtf16(); }
QString(int size, Qt::Initialization);
- explicit QString(DataPointer dd) : d(dd) {}
+ explicit QString(DataPointer &&dd) : d(std::move(dd)) {}
private:
#if defined(QT_NO_CAST_FROM_ASCII)
@@ -915,6 +915,7 @@ private:
#endif
DataPointer d;
+ static const char16_t _empty;
friend inline bool operator==(QChar, const QString &) noexcept;
friend inline bool operator< (QChar, const QString &) noexcept;
@@ -1031,13 +1032,23 @@ inline const QChar QString::operator[](int i) const
inline bool QString::isEmpty() const
{ return d.size == 0; }
inline const QChar *QString::unicode() const
-{ return reinterpret_cast<const QChar*>(d.data()); }
+{ return data(); }
inline const QChar *QString::data() const
-{ return reinterpret_cast<const QChar*>(d.data()); }
+{
+#if QT5_NULL_STRINGS == 1
+ return reinterpret_cast<const QChar *>(d.data() ? d.data() : &_empty);
+#else
+ return reinterpret_cast<const QChar *>(d.data());
+#endif
+}
inline QChar *QString::data()
-{ detach(); return reinterpret_cast<QChar*>(d.data()); }
+{
+ detach();
+ Q_ASSERT(d.data());
+ return reinterpret_cast<QChar *>(d.data());
+}
inline const QChar *QString::constData() const
-{ return reinterpret_cast<const QChar*>(d.data()); }
+{ return data(); }
inline void QString::detach()
{ if (d->needsDetach()) reallocData(d.size + 1u); }
inline bool QString::isDetached() const
@@ -1107,7 +1118,7 @@ inline QString QString::fromWCharArray(const wchar_t *string, int size)
: fromUcs4(reinterpret_cast<const char32_t *>(string), size);
}
-inline QString::QString() noexcept {}
+inline constexpr QString::QString() noexcept {}
inline QString::~QString() {}
inline void QString::reserve(int asize)
@@ -1116,7 +1127,7 @@ inline void QString::reserve(int asize)
reallocData(uint(qMax(asize, size())) + 1u);
// we're not shared anymore, for sure
- d->flags() |= Data::CapacityReserved;
+ d->setFlag(Data::CapacityReserved);
}
inline void QString::squeeze()
@@ -1127,7 +1138,7 @@ inline void QString::squeeze()
reallocData(uint(d.size) + 1u);
// we're not shared anymore, for sure
- d->flags() &= uint(~Data::CapacityReserved);
+ d->clearFlag(Data::CapacityReserved);
}
inline QString &QString::setUtf16(const ushort *autf16, int asize)
diff --git a/src/corelib/text/qstringliteral.h b/src/corelib/text/qstringliteral.h
index a44787c7a4..4d24937eb7 100644
--- a/src/corelib/text/qstringliteral.h
+++ b/src/corelib/text/qstringliteral.h
@@ -62,18 +62,9 @@ static_assert(sizeof(qunicodechar) == 2,
#define QT_UNICODE_LITERAL(str) u"" str
#define QStringLiteral(str) \
- ([]() noexcept -> QString { \
- enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
- static const QArrayData qstring_literal = { \
- Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 \
- }; \
- QStringPrivate holder = { \
- static_cast<QTypedArrayData<char16_t> *>(const_cast<QArrayData *>(&qstring_literal)), \
- const_cast<qunicodechar *>(QT_UNICODE_LITERAL(str)), \
- Size \
- }; \
- return QString(holder); \
- }()) \
+ (QString(QStringPrivate(nullptr, \
+ reinterpret_cast<char16_t *>(const_cast<qunicodechar *>(QT_UNICODE_LITERAL(str))), \
+ sizeof(QT_UNICODE_LITERAL(str))/2 - 1))) \
/**/
using QStringPrivate = QArrayDataPointer<char16_t>;