diff options
Diffstat (limited to 'src/corelib/tools')
44 files changed, 849 insertions, 380 deletions
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index 88d8b8244d..234a44f6b6 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -215,7 +215,7 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, headerSize += (alignment - Q_ALIGNOF(QArrayData)); if (headerSize > size_t(MaxAllocSize)) - return 0; + return nullptr; size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options); QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize)); @@ -224,9 +224,9 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, & ~(alignment - 1); #if !defined(QT_NO_UNSHARABLE_CONTAINERS) - header->ref.atomic.store(bool(!(options & Unsharable))); + header->ref.atomic.storeRelaxed(bool(!(options & Unsharable))); #else - header->ref.atomic.store(1); + header->ref.atomic.storeRelaxed(1); #endif header->size = 0; header->alloc = capacity; diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index 7e3f8c9dbd..dcd95924c1 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -323,11 +323,17 @@ struct QArrayDataPointerRef }()) \ /**/ +#ifdef Q_COMPILER_CONSTEXPR +#define Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type) Q_STATIC_ASSERT(std::is_literal_type<Type>::value) +#else +#define Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type) do {} while (0) +#endif + #define Q_ARRAY_LITERAL_IMPL(Type, ...) \ - union { Type type_must_be_POD; } dummy; Q_UNUSED(dummy) \ + Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type); \ \ /* Portable compile-time array size computation */ \ - Type data[] = { __VA_ARGS__ }; Q_UNUSED(data) \ + Q_CONSTEXPR Type data[] = { __VA_ARGS__ }; Q_UNUSED(data); \ enum { Size = sizeof(data) / sizeof(data[0]) }; \ \ static const QStaticArrayData<Type, Size> literal = { \ diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 7e1b43f9b1..8e19525f07 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -106,7 +106,7 @@ struct QPodArrayOps void destroyAll() // Call from destructors, ONLY! { Q_ASSERT(this->isMutable()); - Q_ASSERT(this->ref.atomic.load() == 0); + Q_ASSERT(this->ref.atomic.loadRelaxed() == 0); // As this is to be called only from destructor, it doesn't need to be // exception safe; size not updated. @@ -204,7 +204,7 @@ struct QGenericArrayOps // As this is to be called only from destructor, it doesn't need to be // exception safe; size not updated. - Q_ASSERT(this->ref.atomic.load() == 0); + Q_ASSERT(this->ref.atomic.loadRelaxed() == 0); const T *const b = this->begin(); const T *i = this->end(); diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 9526350126..ecbb4743af 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -943,6 +943,23 @@ QByteArray qUncompress(const uchar* data, int nbytes) and QByteArray() compares equal to QByteArray(""). We recommend that you always use isEmpty() and avoid isNull(). + \section1 Maximum size and out-of-memory conditions + + The current version of QByteArray is limited to just under 2 GB (2^31 + bytes) in size. The exact value is architecture-dependent, since it depends + on the overhead required for managing the data block, but is no more than + 32 bytes. Raw data blocks are also limited by the use of \c int type in the + current version to 2 GB minus 1 byte. + + In case memory allocation fails, QByteArray will throw a \c std::bad_alloc + exception. Out of memory conditions in the Qt containers are the only case + where Qt will throw exceptions. + + Note that the operating system may impose further limits on applications + holding a lot of allocated memory, especially large, contiguous blocks. + Such considerations, the configuration of such behavior or any mitigation + are outside the scope of the QByteArray API. + \section1 Notes on Locale \section2 Number-String Conversions @@ -2072,7 +2089,7 @@ static inline QByteArray &qbytearray_insert(QByteArray *ba, { Q_ASSERT(pos >= 0); - if (pos < 0 || len <= 0 || arr == 0) + if (pos < 0 || len <= 0 || arr == nullptr) return *ba; int oldsize = ba->size(); @@ -4775,7 +4792,7 @@ static void q_toPercentEncoding(QByteArray *ba, const char *dontEncode, const ch QByteArray input = *ba; int len = input.count(); const char *inputData = input.constData(); - char *output = 0; + char *output = nullptr; int length = 0; for (int i = 0; i < len; ++i) { @@ -4815,7 +4832,7 @@ void q_toPercentEncoding(QByteArray *ba, const char *exclude, const char *includ void q_normalizePercentEncoding(QByteArray *ba, const char *exclude) { q_fromPercentEncoding(ba, '%'); - q_toPercentEncoding(ba, exclude, 0, '%'); + q_toPercentEncoding(ba, exclude, nullptr, '%'); } /*! diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index a81051d309..7c571706d8 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -548,7 +548,7 @@ class #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) Q_CORE_EXPORT #endif -QByteRef { +QByteRef { // ### Qt 7: remove QByteArray &a; int i; inline QByteRef(QByteArray &array, int idx) diff --git a/src/corelib/tools/qbytearraylist.h b/src/corelib/tools/qbytearraylist.h index 1261e1757c..0250b649b8 100644 --- a/src/corelib/tools/qbytearraylist.h +++ b/src/corelib/tools/qbytearraylist.h @@ -48,8 +48,11 @@ QT_BEGIN_NAMESPACE +#if !defined(QT_NO_JAVA_STYLE_ITERATORS) typedef QListIterator<QByteArray> QByteArrayListIterator; typedef QMutableListIterator<QByteArray> QMutableByteArrayListIterator; +#endif + #ifndef Q_CLANG_QDOC typedef QList<QByteArray> QByteArrayList; diff --git a/src/corelib/tools/qbytearraymatcher.cpp b/src/corelib/tools/qbytearraymatcher.cpp index d2eb4e0e3c..72e09226af 100644 --- a/src/corelib/tools/qbytearraymatcher.cpp +++ b/src/corelib/tools/qbytearraymatcher.cpp @@ -116,9 +116,9 @@ static inline int bm_find(const uchar *cc, int l, int index, const uchar *puc, u Call setPattern() to give it a pattern to match. */ QByteArrayMatcher::QByteArrayMatcher() - : d(0) + : d(nullptr) { - p.p = 0; + p.p = nullptr; p.l = 0; memset(p.q_skiptable, 0, sizeof(p.q_skiptable)); } @@ -129,7 +129,7 @@ QByteArrayMatcher::QByteArrayMatcher() the destructor does not delete \a pattern. */ QByteArrayMatcher::QByteArrayMatcher(const char *pattern, int length) - : d(0) + : d(nullptr) { p.p = reinterpret_cast<const uchar *>(pattern); p.l = length; @@ -141,7 +141,7 @@ QByteArrayMatcher::QByteArrayMatcher(const char *pattern, int length) Call indexIn() to perform a search. */ QByteArrayMatcher::QByteArrayMatcher(const QByteArray &pattern) - : d(0), q_pattern(pattern) + : d(nullptr), q_pattern(pattern) { p.p = reinterpret_cast<const uchar *>(pattern.constData()); p.l = pattern.size(); @@ -152,7 +152,7 @@ QByteArrayMatcher::QByteArrayMatcher(const QByteArray &pattern) Copies the \a other byte array matcher to this byte array matcher. */ QByteArrayMatcher::QByteArrayMatcher(const QByteArrayMatcher &other) - : d(0) + : d(nullptr) { operator=(other); } diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index d6061defc3..e097e4a5fe 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -1339,7 +1339,7 @@ static const unsigned short * QT_FASTCALL decompositionHelper if (index == 0xffff) { *length = 0; *tag = QChar::NoDecomposition; - return 0; + return nullptr; } const unsigned short *decomposition = uc_decomposition_map+index; diff --git a/src/corelib/tools/qcollator.cpp b/src/corelib/tools/qcollator.cpp index 6e85027462..958216bde8 100644 --- a/src/corelib/tools/qcollator.cpp +++ b/src/corelib/tools/qcollator.cpp @@ -166,7 +166,7 @@ QCollator &QCollator::operator=(const QCollator &other) */ void QCollator::detach() { - if (d->ref.load() != 1) { + if (d->ref.loadRelaxed() != 1) { QCollatorPrivate *x = new QCollatorPrivate(d->locale); if (!d->ref.deref()) delete d; diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h index 592e31bfd2..7b74b4f526 100644 --- a/src/corelib/tools/qcontiguouscache.h +++ b/src/corelib/tools/qcontiguouscache.h @@ -100,8 +100,8 @@ public: inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) freeData(p); } - inline void detach() { if (d->ref.load() != 1) detach_helper(); } - inline bool isDetached() const { return d->ref.load() == 1; } + inline void detach() { if (d->ref.loadRelaxed() != 1) detach_helper(); } + inline bool isDetached() const { return d->ref.loadRelaxed() == 1; } #if !defined(QT_NO_UNSHARABLE_CONTAINERS) inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; } #endif @@ -176,7 +176,7 @@ void QContiguousCache<T>::detach_helper() union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x; x.d = allocateData(d->alloc); - x.d->ref.store(1); + x.d->ref.storeRelaxed(1); x.d->count = d->count; x.d->start = d->start; x.d->offset = d->offset; @@ -215,7 +215,7 @@ void QContiguousCache<T>::setCapacity(int asize) detach(); union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x; x.d = allocateData(asize); - x.d->ref.store(1); + x.d->ref.storeRelaxed(1); x.d->alloc = asize; x.d->count = qMin(d->count, asize); x.d->offset = d->offset + d->count - x.d->count; @@ -251,7 +251,7 @@ void QContiguousCache<T>::setCapacity(int asize) template <typename T> void QContiguousCache<T>::clear() { - if (d->ref.load() == 1) { + if (d->ref.loadRelaxed() == 1) { if (QTypeInfo<T>::isComplex) { int oldcount = d->count; T * i = p->array + d->start; @@ -267,7 +267,7 @@ void QContiguousCache<T>::clear() } else { union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x; x.d = allocateData(d->alloc); - x.d->ref.store(1); + x.d->ref.storeRelaxed(1); x.d->alloc = d->alloc; x.d->count = x.d->start = x.d->offset = 0; x.d->sharable = true; @@ -287,7 +287,7 @@ QContiguousCache<T>::QContiguousCache(int cap) { Q_ASSERT(cap >= 0); d = allocateData(cap); - d->ref.store(1); + d->ref.storeRelaxed(1); d->alloc = cap; d->count = d->start = d->offset = 0; d->sharable = true; diff --git a/src/corelib/tools/qfreelist_p.h b/src/corelib/tools/qfreelist_p.h index d72d6e1b4b..5ba23b344b 100644 --- a/src/corelib/tools/qfreelist_p.h +++ b/src/corelib/tools/qfreelist_p.h @@ -171,7 +171,7 @@ class QFreeList // qDebug("QFreeList: allocating %d elements (%ld bytes) with offset %d", size, size * sizeof(ElementType), offset); ElementType *v = new ElementType[size]; for (int i = 0; i < size; ++i) - v[i].next.store(offset + i + 1); + v[i].next.storeRelaxed(offset + i + 1); return v; } @@ -218,21 +218,21 @@ template <typename T, typename ConstantsType> inline QFreeList<T, ConstantsType>::~QFreeList() { for (int i = 0; i < ConstantsType::BlockCount; ++i) - delete [] _v[i].load(); + delete [] _v[i].loadAcquire(); } template <typename T, typename ConstantsType> inline typename QFreeList<T, ConstantsType>::ConstReferenceType QFreeList<T, ConstantsType>::at(int x) const { const int block = blockfor(x); - return (_v[block].load())[x].t(); + return (_v[block].loadRelaxed())[x].t(); } template <typename T, typename ConstantsType> inline typename QFreeList<T, ConstantsType>::ReferenceType QFreeList<T, ConstantsType>::operator[](int x) { const int block = blockfor(x); - return (_v[block].load())[x].t(); + return (_v[block].loadRelaxed())[x].t(); } template <typename T, typename ConstantsType> @@ -257,7 +257,7 @@ inline int QFreeList<T, ConstantsType>::next() } } - newid = v[at].next.load() | (id & ~ConstantsType::IndexMask); + newid = v[at].next.loadRelaxed() | (id & ~ConstantsType::IndexMask); } while (!_next.testAndSetRelease(id, newid)); // qDebug("QFreeList::next(): returning %d (_next now %d, serial %d)", // id & ConstantsType::IndexMask, @@ -271,12 +271,12 @@ inline void QFreeList<T, ConstantsType>::release(int id) { int at = id & ConstantsType::IndexMask; const int block = blockfor(at); - ElementType *v = _v[block].load(); + ElementType *v = _v[block].loadRelaxed(); int x, newid; do { x = _next.loadAcquire(); - v[at].next.store(x & ConstantsType::IndexMask); + v[at].next.storeRelaxed(x & ConstantsType::IndexMask); newid = incrementserial(x, id); } while (!_next.testAndSetRelease(x, newid)); diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 85a3456d71..a53d6db997 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -321,7 +321,7 @@ static QBasicAtomicInt qt_qhash_seed = Q_BASIC_ATOMIC_INITIALIZER(-1); */ static void qt_initialize_qhash_seed() { - if (qt_qhash_seed.load() == -1) { + if (qt_qhash_seed.loadRelaxed() == -1) { int x(qt_create_qhash_seed() & INT_MAX); qt_qhash_seed.testAndSetRelaxed(-1, x); } @@ -340,7 +340,7 @@ static void qt_initialize_qhash_seed() int qGlobalQHashSeed() { qt_initialize_qhash_seed(); - return qt_qhash_seed.load(); + return qt_qhash_seed.loadRelaxed(); } /*! \relates QHash @@ -372,14 +372,14 @@ void qSetGlobalQHashSeed(int newSeed) return; if (newSeed == -1) { int x(qt_create_qhash_seed() & INT_MAX); - qt_qhash_seed.store(x); + qt_qhash_seed.storeRelaxed(x); } else { if (newSeed) { // can't use qWarning here (reentrancy) fprintf(stderr, "qSetGlobalQHashSeed: forced seed value is not 0, cannot guarantee that the " "hashing functions will produce a stable value."); } - qt_qhash_seed.store(newSeed & INT_MAX); + qt_qhash_seed.storeRelaxed(newSeed & INT_MAX); } } @@ -471,7 +471,7 @@ static int countBits(int hint) const int MinNumBits = 4; const QHashData QHashData::shared_null = { - 0, 0, Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, MinNumBits, 0, 0, 0, true, false, 0 + nullptr, nullptr, Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, MinNumBits, 0, 0, 0, true, false, 0 }; void *QHashData::allocateNode(int nodeAlign) @@ -501,15 +501,15 @@ QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *), if (this == &shared_null) qt_initialize_qhash_seed(); // may throw d = new QHashData; - d->fakeNext = 0; - d->buckets = 0; + d->fakeNext = nullptr; + d->buckets = nullptr; d->ref.initializeOwned(); d->size = size; d->nodeSize = nodeSize; d->userNumBits = userNumBits; d->numBits = numBits; d->numBuckets = numBuckets; - d->seed = (this == &shared_null) ? uint(qt_qhash_seed.load()) : seed; + d->seed = (this == &shared_null) ? uint(qt_qhash_seed.loadRelaxed()) : seed; d->sharable = true; d->strictAlignment = nodeAlign > 8; d->reserved = 0; diff --git a/src/corelib/tools/qiterator.h b/src/corelib/tools/qiterator.h index 82212c3eb5..84a0e116ca 100644 --- a/src/corelib/tools/qiterator.h +++ b/src/corelib/tools/qiterator.h @@ -44,6 +44,8 @@ QT_BEGIN_NAMESPACE +#if !defined(QT_NO_JAVA_STYLE_ITERATORS) + #define Q_DECLARE_SEQUENTIAL_ITERATOR(C) \ \ template <class T> \ @@ -115,11 +117,11 @@ template <class Key, class T> \ class Q##C##Iterator \ { \ typedef typename Q##C<Key,T>::const_iterator const_iterator; \ - typedef const_iterator Item; \ Q##C<Key,T> c; \ const_iterator i, n; \ inline bool item_exists() const { return n != c.constEnd(); } \ public: \ + typedef const_iterator Item; \ inline Q##C##Iterator(const Q##C<Key,T> &container) \ : c(container), i(c.constBegin()), n(c.constEnd()) {} \ inline Q##C##Iterator &operator=(const Q##C<Key,T> &container) \ @@ -148,11 +150,11 @@ class QMutable##C##Iterator \ { \ typedef typename Q##C<Key,T>::iterator iterator; \ typedef typename Q##C<Key,T>::const_iterator const_iterator; \ - typedef iterator Item; \ Q##C<Key,T> *c; \ iterator i, n; \ inline bool item_exists() const { return const_iterator(n) != c->constEnd(); } \ public: \ + typedef iterator Item; \ inline QMutable##C##Iterator(Q##C<Key,T> &container) \ : c(&container) \ { i = c->begin(); n = c->end(); } \ @@ -179,6 +181,13 @@ public: \ n = c->end(); return false; } \ }; +#else // QT_NO_JAVA_STYLE_ITERATORS +#define Q_DECLARE_SEQUENTIAL_ITERATOR(C) +#define Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(C) +#define Q_DECLARE_ASSOCIATIVE_ITERATOR(C) +#define Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(C) +#endif // QT_NO_JAVA_STYLE_ITERATORS + template<typename Key, typename T, class Iterator> class QKeyValueIterator { diff --git a/src/corelib/tools/qlinkedlist.cpp b/src/corelib/tools/qlinkedlist.cpp index c0450f5cd8..d239fe0ef4 100644 --- a/src/corelib/tools/qlinkedlist.cpp +++ b/src/corelib/tools/qlinkedlist.cpp @@ -742,8 +742,7 @@ const QLinkedListData QLinkedListData::shared_null = { \snippet code/src_corelib_tools_qlinkedlist.cpp 7 STL-style iterators can be used as arguments to \l{generic - algorithms}. For example, here's how to find an item in the list - using the qFind() algorithm: + algorithms}. For example, here's how to find an item in the list: \snippet code/src_corelib_tools_qlinkedlist.cpp 8 @@ -987,8 +986,7 @@ const QLinkedListData QLinkedListData::shared_null = { \snippet code/src_corelib_tools_qlinkedlist.cpp 14 STL-style iterators can be used as arguments to \l{generic - algorithms}. For example, here's how to find an item in the list - using the qFind() algorithm: + algorithms}. For example, here's how to find an item in the list: \snippet code/src_corelib_tools_qlinkedlist.cpp 15 diff --git a/src/corelib/tools/qlinkedlist.h b/src/corelib/tools/qlinkedlist.h index 6bc053a4c0..d4e5bca0ed 100644 --- a/src/corelib/tools/qlinkedlist.h +++ b/src/corelib/tools/qlinkedlist.h @@ -340,7 +340,7 @@ void QLinkedList<T>::freeData(QLinkedListData *x) { Node *y = reinterpret_cast<Node*>(x); Node *i = y->n; - Q_ASSERT(x->ref.atomic.load() == 0); + Q_ASSERT(x->ref.atomic.loadRelaxed() == 0); while (i != y) { Node *n = i; i = i->n; diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp index 48617f0539..dfebd57e34 100644 --- a/src/corelib/tools/qlist.cpp +++ b/src/corelib/tools/qlist.cpp @@ -75,7 +75,7 @@ template class Q_CORE_EXPORT QVector<QPoint>; the number of elements in the list. */ -const QListData::Data QListData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, { 0 } }; +const QListData::Data QListData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, { nullptr } }; /*! * Detaches the QListData by allocating new memory for a list which will be bigger diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index c8740e55f3..939f8eb34d 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -301,9 +301,9 @@ QByteArray QLocaleId::name(char separator) const const unsigned char *lang = language_code_list + 3 * language_id; const unsigned char *script = - (script_id != QLocale::AnyScript ? script_code_list + 4 * script_id : 0); + (script_id != QLocale::AnyScript ? script_code_list + 4 * script_id : nullptr); const unsigned char *country = - (country_id != QLocale::AnyCountry ? country_code_list + 3 * country_id : 0); + (country_id != QLocale::AnyCountry ? country_code_list + 3 * country_id : nullptr); char len = (lang[2] != 0 ? 3 : 2) + (script ? 4+1 : 0) + (country ? (country[2] != 0 ? 3 : 2)+1 : 0); QByteArray name(len, Qt::Uninitialized); char *uc = name.data(); @@ -373,7 +373,7 @@ static const QLocaleData *findLocaleDataById(const QLocaleId &localeId) } while (data->m_language_id && data->m_language_id == localeId.language_id); } - return 0; + return nullptr; } const QLocaleData *QLocaleData::findLocaleData(QLocale::Language language, QLocale::Script script, QLocale::Country country) @@ -604,7 +604,7 @@ int qt_repeatCount(QStringView s) return int(j); } -static const QLocaleData *default_data = 0; +static const QLocaleData *default_data = nullptr; static QLocale::NumberOptions default_number_options = QLocale::DefaultNumberOptions; static const QLocaleData *const c_data = locale_data; diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index 15398ded32..1e3da35a02 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -250,14 +250,14 @@ public: if (qIsInf(d)) return float(d); if (std::fabs(d) > std::numeric_limits<float>::max()) { - if (ok != nullptr) + if (ok) *ok = false; const float huge = std::numeric_limits<float>::infinity(); return d < 0 ? -huge : huge; } if (d != 0 && float(d) == 0) { // Values that underflow double already failed. Match them: - if (ok != 0) + if (ok) *ok = false; return 0; } @@ -337,7 +337,7 @@ public: { QLocalePrivate *retval = new QLocalePrivate; retval->m_data = data; - retval->ref.store(0); + retval->ref.storeRelaxed(0); retval->m_numberOptions = numberOptions; return retval; } diff --git a/src/corelib/tools/qlocale_tools.cpp b/src/corelib/tools/qlocale_tools.cpp index 53258bec3e..db8c8cd12f 100644 --- a/src/corelib/tools/qlocale_tools.cpp +++ b/src/corelib/tools/qlocale_tools.cpp @@ -398,7 +398,7 @@ qstrtoull(const char * nptr, const char **endptr, int base, bool *ok) *ok = true; errno = 0; - char *endptr2 = 0; + char *endptr2 = nullptr; unsigned long long result = qt_strtoull(nptr, &endptr2, base); if (endptr) *endptr = endptr2; @@ -415,7 +415,7 @@ qstrtoll(const char * nptr, const char **endptr, int base, bool *ok) { *ok = true; errno = 0; - char *endptr2 = 0; + char *endptr2 = nullptr; long long result = qt_strtoll(nptr, &endptr2, base); if (endptr) *endptr = endptr2; diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index 5f7275c5f8..a0ec372f9a 100644 --- a/src/corelib/tools/qmap.cpp +++ b/src/corelib/tools/qmap.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE -const QMapDataBase QMapDataBase::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, { 0, 0, 0 }, 0 }; +const QMapDataBase QMapDataBase::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, { 0, nullptr, nullptr }, nullptr }; const QMapNodeBase *QMapNodeBase::nextNode() const { @@ -92,7 +92,7 @@ void QMapDataBase::rotateLeft(QMapNodeBase *x) QMapNodeBase *&root = header.left; QMapNodeBase *y = x->right; x->right = y->left; - if (y->left != 0) + if (y->left != nullptr) y->left->setParent(x); y->setParent(x->parent()); if (x == root) @@ -111,7 +111,7 @@ void QMapDataBase::rotateRight(QMapNodeBase *x) QMapNodeBase *&root = header.left; QMapNodeBase *y = x->left; x->left = y->right; - if (y->right != 0) + if (y->right != nullptr) y->right->setParent(x); y->setParent(x->parent()); if (x == root) @@ -173,7 +173,7 @@ void QMapDataBase::freeNodeAndRebalance(QMapNodeBase *z) QMapNodeBase *y = z; QMapNodeBase *x; QMapNodeBase *x_parent; - if (y->left == 0) { + if (y->left == nullptr) { x = y->right; if (y == mostLeftNode) { if (x) @@ -182,11 +182,11 @@ void QMapDataBase::freeNodeAndRebalance(QMapNodeBase *z) mostLeftNode = y->parent(); } } else { - if (y->right == 0) { + if (y->right == nullptr) { x = y->left; } else { y = y->right; - while (y->left != 0) + while (y->left != nullptr) y = y->left; x = y->right; } @@ -228,7 +228,7 @@ void QMapDataBase::freeNodeAndRebalance(QMapNodeBase *z) z->parent()->right = x; } if (y->color() != QMapNodeBase::Red) { - while (x != root && (x == 0 || x->color() == QMapNodeBase::Black)) { + while (x != root && (x == nullptr || x->color() == QMapNodeBase::Black)) { if (x == x_parent->left) { QMapNodeBase *w = x_parent->right; if (w->color() == QMapNodeBase::Red) { @@ -237,13 +237,13 @@ void QMapDataBase::freeNodeAndRebalance(QMapNodeBase *z) rotateLeft(x_parent); w = x_parent->right; } - if ((w->left == 0 || w->left->color() == QMapNodeBase::Black) && - (w->right == 0 || w->right->color() == QMapNodeBase::Black)) { + if ((w->left == nullptr || w->left->color() == QMapNodeBase::Black) && + (w->right == nullptr || w->right->color() == QMapNodeBase::Black)) { w->setColor(QMapNodeBase::Red); x = x_parent; x_parent = x_parent->parent(); } else { - if (w->right == 0 || w->right->color() == QMapNodeBase::Black) { + if (w->right == nullptr || w->right->color() == QMapNodeBase::Black) { if (w->left) w->left->setColor(QMapNodeBase::Black); w->setColor(QMapNodeBase::Red); @@ -265,13 +265,13 @@ void QMapDataBase::freeNodeAndRebalance(QMapNodeBase *z) rotateRight(x_parent); w = x_parent->left; } - if ((w->right == 0 || w->right->color() == QMapNodeBase::Black) && - (w->left == 0 || w->left->color() == QMapNodeBase::Black)) { + if ((w->right == nullptr || w->right->color() == QMapNodeBase::Black) && + (w->left == nullptr|| w->left->color() == QMapNodeBase::Black)) { w->setColor(QMapNodeBase::Red); x = x_parent; x_parent = x_parent->parent(); } else { - if (w->left == 0 || w->left->color() == QMapNodeBase::Black) { + if (w->left == nullptr || w->left->color() == QMapNodeBase::Black) { if (w->right) w->right->setColor(QMapNodeBase::Black); w->setColor(QMapNodeBase::Red); @@ -363,8 +363,8 @@ QMapDataBase *QMapDataBase::createData() d->size = 0; d->header.p = 0; - d->header.left = 0; - d->header.right = 0; + d->header.left = nullptr; + d->header.right = nullptr; d->mostLeftNode = &(d->header); return d; diff --git a/src/corelib/tools/qrect.cpp b/src/corelib/tools/qrect.cpp index d622f92530..cd20102a2b 100644 --- a/src/corelib/tools/qrect.cpp +++ b/src/corelib/tools/qrect.cpp @@ -1194,7 +1194,7 @@ bool QRect::intersects(const QRect &r) const noexcept \fn QRect operator-(const QRect &lhs, const QMargins &rhs) \relates QRect - Returns the \a lhs rectangle shrunken by the \a rhs margins. + Returns the \a lhs rectangle shrunk by the \a rhs margins. \since 5.3 */ @@ -2417,7 +2417,7 @@ QRect QRectF::toAlignedRect() const noexcept \relates QRectF \since 5.3 - Returns the \a lhs rectangle grown by the \a rhs margins. + Returns the \a lhs rectangle shrunk by the \a rhs margins. */ /*! diff --git a/src/corelib/tools/qrefcount.h b/src/corelib/tools/qrefcount.h index 71adb41f28..2e5388ad9a 100644 --- a/src/corelib/tools/qrefcount.h +++ b/src/corelib/tools/qrefcount.h @@ -52,7 +52,7 @@ class RefCount { public: inline bool ref() noexcept { - int count = atomic.load(); + int count = atomic.loadRelaxed(); #if !defined(QT_NO_UNSHARABLE_CONTAINERS) if (count == 0) // !isSharable return false; @@ -63,7 +63,7 @@ public: } inline bool deref() noexcept { - int count = atomic.load(); + int count = atomic.loadRelaxed(); #if !defined(QT_NO_UNSHARABLE_CONTAINERS) if (count == 0) // !isSharable return false; @@ -86,24 +86,24 @@ public: bool isSharable() const noexcept { // Sharable === Shared ownership. - return atomic.load() != 0; + return atomic.loadRelaxed() != 0; } #endif bool isStatic() const noexcept { // Persistent object, never deleted - return atomic.load() == -1; + return atomic.loadRelaxed() == -1; } bool isShared() const noexcept { - int count = atomic.load(); + int count = atomic.loadRelaxed(); return (count != 1) && (count != 0); } - void initializeOwned() noexcept { atomic.store(1); } - void initializeUnsharable() noexcept { atomic.store(0); } + void initializeOwned() noexcept { atomic.storeRelaxed(1); } + void initializeUnsharable() noexcept { atomic.storeRelaxed(0); } QBasicAtomicInt atomic; }; diff --git a/src/corelib/tools/qregexp.cpp b/src/corelib/tools/qregexp.cpp index d970843dea..dd38ba0360 100644 --- a/src/corelib/tools/qregexp.cpp +++ b/src/corelib/tools/qregexp.cpp @@ -822,7 +822,7 @@ static QString wc2rx(const QString &wc_str, const bool enableEscaping) if (wc[i] == QLatin1Char('^')) rx += wc[i++]; if (i < wclen) { - if (rx[i] == QLatin1Char(']')) + if (wc[i] == QLatin1Char(']')) rx += wc[i++]; while (i < wclen && wc[i] != QLatin1Char(']')) { if (wc[i] == QLatin1Char('\\')) @@ -937,10 +937,10 @@ struct QRegExpMatchState const QRegExpEngine *eng; - inline QRegExpMatchState() : bigArray(0), captured(0) {} + inline QRegExpMatchState() : bigArray(nullptr), captured(nullptr) {} inline ~QRegExpMatchState() { free(bigArray); } - void drain() { free(bigArray); bigArray = 0; captured = 0; } // to save memory + void drain() { free(bigArray); bigArray = nullptr; captured = nullptr; } // to save memory void prepareForMatch(QRegExpEngine *eng); void match(const QChar *str, int len, int pos, bool minimal, bool oneTest, int caretIndex); @@ -1420,7 +1420,7 @@ void QRegExpMatchState::match(const QChar *str0, int len0, int pos0, #ifndef QT_NO_REGEXP_OPTIM if (eng->trivial && !oneTest) { - // ### Qt6: qsize + // ### Qt6: qsizetype pos = int(QtPrivate::findString(QStringView(str0, len0), pos0, QStringView(eng->goodStr.unicode(), eng->goodStr.length()), eng->cs)); matchLen = eng->goodStr.length(); matched = (pos != -1); @@ -1428,7 +1428,7 @@ void QRegExpMatchState::match(const QChar *str0, int len0, int pos0, #endif { in = str0; - if (in == 0) + if (in == nullptr) in = &char_null; pos = pos0; caretPos = caretIndex; @@ -1707,7 +1707,7 @@ void QRegExpEngine::dump() const void QRegExpEngine::setup() { - ref.store(1); + ref.storeRelaxed(1); #ifndef QT_NO_REGEXP_CAPTURE f.resize(32); nf = 0; @@ -2910,7 +2910,7 @@ int QRegExpEngine::getEscape() #ifndef QT_NO_REGEXP_ESCAPE if ((prevCh & ~0xff) == 0) { const char *p = strchr(tab, prevCh); - if (p != 0) + if (p != nullptr) return Tok_Char | backTab[p - tab]; } #endif @@ -3530,7 +3530,7 @@ int QRegExpEngine::parse(const QChar *pattern, int len) #endif box.cat(middleBox); box.cat(rightBox); - yyCharClass.reset(0); + yyCharClass.reset(); #ifndef QT_NO_REGEXP_CAPTURE for (int i = 0; i < nf; ++i) { @@ -3608,7 +3608,7 @@ int QRegExpEngine::parse(const QChar *pattern, int len) void QRegExpEngine::parseAtom(Box *box) { #ifndef QT_NO_REGEXP_LOOKAHEAD - QRegExpEngine *eng = 0; + QRegExpEngine *eng = nullptr; bool neg; int len; #endif @@ -3805,9 +3805,9 @@ struct QRegExpPrivate QRegExpMatchState matchState; inline QRegExpPrivate() - : eng(0), engineKey(QString(), QRegExp::RegExp, Qt::CaseSensitive), minimal(false) { } + : eng(nullptr), engineKey(QString(), QRegExp::RegExp, Qt::CaseSensitive), minimal(false) { } inline QRegExpPrivate(const QRegExpEngineKey &key) - : eng(0), engineKey(key), minimal(false) {} + : eng(nullptr), engineKey(key), minimal(false) {} }; #if !defined(QT_NO_REGEXP_OPTIM) @@ -3886,9 +3886,9 @@ static void prepareEngineForMatch(QRegExpPrivate *priv, const QString &str) static void invalidateEngine(QRegExpPrivate *priv) { - if (priv->eng != 0) { + if (priv->eng) { derefEngine(priv->eng, priv->engineKey); - priv->eng = 0; + priv->eng = nullptr; priv->matchState.drain(); } } diff --git a/src/corelib/tools/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp index 9c201e770b..17acd476b2 100644 --- a/src/corelib/tools/qregularexpression.cpp +++ b/src/corelib/tools/qregularexpression.cpp @@ -460,34 +460,13 @@ QT_BEGIN_NAMESPACE \row \li \c{"[a-z]+\\d+"} \li \b true \li \b true \endtable - Exact matching is not reflected in QRegularExpression. If you want to be - sure that the subject string matches the regular expression exactly, you can wrap the - pattern between a couple of anchoring expressions. Simply - putting the pattern between the \c{^} and the \c{$} anchors is enough - in most cases: + Exact matching is not reflected in QRegularExpression. If you want + to be sure that the subject string matches the regular expression + exactly, you can wrap the pattern using the anchoredPattern() + function: \snippet code/src_corelib_tools_qregularexpression.cpp 24 - However, remember that the \c{$} anchor not only matches at the end of the - string, but also at a newline character right before the end of the string; - that is, the previous pattern matches against the string "this pattern must - match exactly\\n". Also, the behaviour of both the \c{^} and the \c{$} - anchors changes if the MultiLineOption is set either explicitly (as a - pattern option) or implicitly (as a directive inside the pattern string). - - Therefore, in the most general case, you should wrap the pattern between - the \c{\A} and the \c{\z} anchors: - - \snippet code/src_corelib_tools_qregularexpression.cpp 25 - - Note the usage of the non-capturing group in order to preserve the meaning - of the branch operator inside the pattern. - - The QRegularExpression::anchoredPattern() helper method does exactly that for - you. - - \sa anchoredPattern - \section3 Porting from QRegExp's Partial Matching When using QRegExp::exactMatch(), if an exact match was not found, one diff --git a/src/corelib/tools/qringbuffer.cpp b/src/corelib/tools/qringbuffer.cpp index 67cce57d01..311058a776 100644 --- a/src/corelib/tools/qringbuffer.cpp +++ b/src/corelib/tools/qringbuffer.cpp @@ -105,7 +105,7 @@ const char *QRingBuffer::readPointerAtPosition(qint64 pos, qint64 &length) const } length = 0; - return 0; + return nullptr; } void QRingBuffer::free(qint64 bytes) diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h index 83e574bf1c..19d6982133 100644 --- a/src/corelib/tools/qset.h +++ b/src/corelib/tools/qset.h @@ -284,11 +284,9 @@ Q_INLINE_TEMPLATE void QSet<T>::reserve(int asize) { q_hash.reserve(asize); } template <class T> Q_INLINE_TEMPLATE QSet<T> &QSet<T>::unite(const QSet<T> &other) { - QSet<T> copy(other); - typename QSet<T>::const_iterator i = copy.constEnd(); - while (i != copy.constBegin()) { - --i; - insert(*i); + if (!q_hash.isSharedWith(other.q_hash)) { + for (const T &e : other) + insert(e); } return *this; } @@ -306,11 +304,9 @@ Q_INLINE_TEMPLATE QSet<T> &QSet<T>::intersect(const QSet<T> &other) copy2 = *this; *this = copy1; } - typename QSet<T>::const_iterator i = copy1.constEnd(); - while (i != copy1.constBegin()) { - --i; - if (!copy2.contains(*i)) - remove(*i); + for (const auto &e : qAsConst(copy1)) { + if (!copy2.contains(e)) + remove(e); } return *this; } @@ -346,14 +342,11 @@ Q_INLINE_TEMPLATE bool QSet<T>::intersects(const QSet<T> &other) const template <class T> Q_INLINE_TEMPLATE QSet<T> &QSet<T>::subtract(const QSet<T> &other) { - if (&other == this) { + if (q_hash.isSharedWith(other.q_hash)) { clear(); } else { - auto i = other.constEnd(); - while (i != other.constBegin()) { - --i; - remove(*i); - } + for (const auto &e : other) + remove(e); } return *this; } @@ -409,6 +402,7 @@ QList<T> QList<T>::fromSet(const QSet<T> &set) Q_DECLARE_SEQUENTIAL_ITERATOR(Set) +#if !defined(QT_NO_JAVA_STYLE_ITERATORS) template <typename T> class QMutableSetIterator { @@ -440,6 +434,7 @@ public: { while (c->constBegin() != i) if (*(n = --i) == t) return true; n = c->end(); return false; } }; +#endif // QT_NO_JAVA_STYLE_ITERATORS QT_END_NAMESPACE diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h index 816583c766..ab54c76720 100644 --- a/src/corelib/tools/qshareddata.h +++ b/src/corelib/tools/qshareddata.h @@ -75,7 +75,7 @@ public: typedef T Type; typedef T *pointer; - inline void detach() { if (d && d->ref.load() != 1) detach_helper(); } + inline void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); } inline T &operator*() { detach(); return *d; } inline const T &operator*() const { return *d; } inline T *operator->() { detach(); return d; } @@ -163,7 +163,7 @@ public: inline const T *constData() const { return d; } inline T *take() { T *x = d; d = nullptr; return x; } - inline void detach() { if (d && d->ref.load() != 1) detach_helper(); } + inline void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); } inline void reset() { diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp index e4de5a2ba9..f185d2f23f 100644 --- a/src/corelib/tools/qsharedpointer.cpp +++ b/src/corelib/tools/qsharedpointer.cpp @@ -1380,7 +1380,7 @@ void QtSharedPointer::ExternalRefCountData::setQObjectShared(const QObject *, bo */ void QtSharedPointer::ExternalRefCountData::checkQObjectShared(const QObject *) { - if (strongref.load() < 0) + if (strongref.loadRelaxed() < 0) qWarning("QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer"); } @@ -1390,7 +1390,7 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject *>(obj)); Q_ASSERT_X(!d->wasDeleted, "QWeakPointer", "Detected QWeakPointer creation in a QObject being deleted"); - ExternalRefCountData *that = d->sharedRefcount.load(); + ExternalRefCountData *that = d->sharedRefcount.loadRelaxed(); if (that) { that->weakref.ref(); return that; @@ -1398,8 +1398,8 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge // we can create the refcount data because it doesn't exist ExternalRefCountData *x = new ExternalRefCountData(Qt::Uninitialized); - x->strongref.store(-1); - x->weakref.store(2); // the QWeakPointer that called us plus the QObject itself + x->strongref.storeRelaxed(-1); + x->weakref.storeRelaxed(2); // the QWeakPointer that called us plus the QObject itself ExternalRefCountData *ret; if (d->sharedRefcount.testAndSetOrdered(nullptr, x, ret)) { // ought to be release+acquire; this is acq_rel+acquire @@ -1407,7 +1407,7 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge } else { // ~ExternalRefCountData has a Q_ASSERT, so we use this trick to // only execute this if Q_ASSERTs are enabled - Q_ASSERT((x->weakref.store(0), true)); + Q_ASSERT((x->weakref.storeRelaxed(0), true)); delete x; ret->weakref.ref(); } diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index 55f0f17c52..198cc58c38 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -107,6 +107,10 @@ template <class X, class T> QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &ptr); #endif +namespace QtPrivate { +struct EnableInternalData; +} + namespace QtSharedPointer { template <class T> class ExternalRefCount; @@ -150,11 +154,11 @@ namespace QtSharedPointer { inline ExternalRefCountData(DestroyerFn d) : destroyer(d) { - strongref.store(1); - weakref.store(1); + strongref.storeRelaxed(1); + weakref.storeRelaxed(1); } inline ExternalRefCountData(Qt::Initialization) { } - ~ExternalRefCountData() { Q_ASSERT(!weakref.load()); Q_ASSERT(strongref.load() <= 0); } + ~ExternalRefCountData() { Q_ASSERT(!weakref.loadRelaxed()); Q_ASSERT(strongref.loadRelaxed() <= 0); } void destroy() { destroyer(this); } @@ -518,12 +522,12 @@ public: if (o) { // increase the strongref, but never up from zero // or less (-1 is used by QWeakPointer on untracked QObject) - int tmp = o->strongref.load(); + int tmp = o->strongref.loadRelaxed(); while (tmp > 0) { // try to increment from "tmp" to "tmp + 1" if (o->strongref.testAndSetRelaxed(tmp, tmp + 1)) break; // succeeded - tmp = o->strongref.load(); // failed, try again + tmp = o->strongref.loadRelaxed(); // failed, try again } if (tmp > 0) { @@ -536,7 +540,7 @@ public: qSwap(d, o); qSwap(this->value, actual); - if (!d || d->strongref.load() == 0) + if (!d || d->strongref.loadRelaxed() == 0) this->value = nullptr; // dereference saved data @@ -562,7 +566,7 @@ public: typedef const value_type &const_reference; typedef qptrdiff difference_type; - bool isNull() const noexcept { return d == nullptr || d->strongref.load() == 0 || value == nullptr; } + bool isNull() const noexcept { return d == nullptr || d->strongref.loadRelaxed() == 0 || value == nullptr; } operator RestrictedBool() const noexcept { return isNull() ? nullptr : &QWeakPointer::value; } bool operator !() const noexcept { return isNull(); } @@ -672,21 +676,12 @@ public: #endif private: - + friend struct QtPrivate::EnableInternalData; #if defined(Q_NO_TEMPLATE_FRIENDS) public: #else template <class X> friend class QSharedPointer; template <class X> friend class QPointer; -# ifndef QT_NO_QOBJECT - template<typename X> - friend QWeakPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<X*>::Value, X>::type> - qWeakPointerFromVariant(const QVariant &variant); -# endif - template<typename X> - friend QPointer<X> - qPointerFromVariant(const QVariant &variant); - friend QtPrivate::QSmartPointerConvertFunctor<QWeakPointer>; #endif template <class X> @@ -714,13 +709,24 @@ public: // a weak pointer's data but the weak pointer itself inline T *internalData() const noexcept { - return d == nullptr || d->strongref.load() == 0 ? nullptr : value; + return d == nullptr || d->strongref.loadRelaxed() == 0 ? nullptr : value; } Data *d; T *value; }; +namespace QtPrivate { +struct EnableInternalData { + template <typename T> + static T *internalData(const QWeakPointer<T> &p) noexcept { return p.internalData(); } +}; +// hack to delay name lookup to instantiation time by making +// EnableInternalData a dependent name: +template <typename T> +struct EnableInternalDataWrap : EnableInternalData {}; +} + template <class T> class QEnableSharedFromThis { @@ -996,7 +1002,7 @@ template<typename T> QWeakPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::type> qWeakPointerFromVariant(const QVariant &variant) { - return QWeakPointer<T>(qobject_cast<T*>(QtSharedPointer::weakPointerFromVariant_internal(variant).internalData())); + return QWeakPointer<T>(qobject_cast<T*>(QtPrivate::EnableInternalData::internalData(QtSharedPointer::weakPointerFromVariant_internal(variant)))); } template<typename T> QSharedPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::type> diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index ddd715f745..ecf1822e42 100644 --- a/src/corelib/tools/qsimd.cpp +++ b/src/corelib/tools/qsimd.cpp @@ -563,9 +563,9 @@ quint64 qDetectCpuFeatures() features_string + features_indices[qCountTrailingZeroBits(missing)]); } - qt_cpu_features[0].store(f | quint32(QSimdInitialized)); + qt_cpu_features[0].storeRelaxed(f | quint32(QSimdInitialized)); #ifndef Q_ATOMIC_INT64_IS_SUPPORTED - qt_cpu_features[1].store(f >> 32); + qt_cpu_features[1].storeRelaxed(f >> 32); #endif return f; } diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index c36e1e484f..db2f546651 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -348,9 +348,9 @@ Q_CORE_EXPORT quint64 qDetectCpuFeatures(); static inline quint64 qCpuFeatures() { - quint64 features = qt_cpu_features[0].load(); + quint64 features = qt_cpu_features[0].loadRelaxed(); #ifndef Q_ATOMIC_INT64_IS_SUPPORTED - features |= quint64(qt_cpu_features[1].load()) << 32; + features |= quint64(qt_cpu_features[1].loadRelaxed()) << 32; #endif if (Q_UNLIKELY(features == 0)) { features = qDetectCpuFeatures(); diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 963c2a4d34..47db97cdfc 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -145,7 +145,8 @@ extern "C" void qt_toLatin1_mips_dsp_asm(uchar *dst, const ushort *src, int leng // internal qsizetype qFindStringBoyerMoore(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs); static inline qsizetype qFindChar(QStringView str, QChar ch, qsizetype from, Qt::CaseSensitivity cs) noexcept; -static inline qsizetype qt_last_index_of(QStringView haystack, QChar needle, qsizetype from, Qt::CaseSensitivity cs); +template <typename Haystack> +static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle, qsizetype from, Qt::CaseSensitivity cs) noexcept; static inline qsizetype qt_string_count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs); static inline qsizetype qt_string_count(QStringView haystack, QChar needle, Qt::CaseSensitivity cs); @@ -1738,6 +1739,24 @@ const QString::Null QString::null = { }; and the \c{'+'} will automatically be performed as the \c{QStringBuilder} \c{'%'} everywhere. + \section1 Maximum size and out-of-memory conditions + + The current version of QString is limited to just under 2 GB (2^31 bytes) + in size. The exact value is architecture-dependent, since it depends on the + overhead required for managing the data block, but is no more than 32 + bytes. Raw data blocks are also limited by the use of \c int type in the + current version to 2 GB minus 1 byte. Since QString uses two bytes per + character, that translates to just under 2^30 characters in one QString. + + In case memory allocation fails, QString will throw a \c std::bad_alloc + exception. Out of memory conditions in the Qt containers are the only case + where Qt will throw exceptions. + + Note that the operating system may impose further limits on applications + holding a lot of allocated memory, especially large, contiguous blocks. + Such considerations, the configuration of such behavior or any mitigation + are outside the scope of the Qt API. + \sa fromRawData(), QChar, QLatin1String, QByteArray, QStringRef */ @@ -3044,7 +3063,7 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar { // Copy after if it lies inside our own d->data() area (which we could // possibly invalidate via a realloc or modify by replacement). - QChar *afterBuffer = 0; + QChar *afterBuffer = nullptr; if (pointsIntoRange(after, d->data(), d->size)) // Use copy in place of vulnerable original: after = afterBuffer = textCopy(after, alen); @@ -3129,7 +3148,7 @@ QString &QString::replace(const QChar *before, int blen, return *this; QStringMatcher matcher(before, blen, cs); - QChar *beforeBuffer = 0, *afterBuffer = 0; + QChar *beforeBuffer = nullptr, *afterBuffer = nullptr; int index = 0; while (1) { @@ -3700,7 +3719,7 @@ bool QString::operator>(QLatin1String other) const noexcept */ int QString::indexOf(const QString &str, int from, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs)); } #endif // QT_STRINGVIEW_LEVEL < 2 @@ -3744,7 +3763,7 @@ int QString::indexOf(const QString &str, int from, Qt::CaseSensitivity cs) const int QString::indexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(QtPrivate::findString(QStringView(unicode(), size()), from, str, cs)); } @@ -3757,7 +3776,7 @@ int QString::indexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const */ int QString::indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(qFindChar(QStringView(unicode(), length()), ch, from, cs)); } @@ -3776,77 +3795,9 @@ int QString::indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const */ int QString::indexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs)); } -#endif // QT_STRINGVIEW_LEVEL < 2 - -static int lastIndexOfHelper(const ushort *haystack, int from, const ushort *needle, int sl, Qt::CaseSensitivity cs) -{ - /* - See indexOf() for explanations. - */ - - auto sv = [sl](const ushort *v) { return QStringView(v, sl); }; - - const ushort *end = haystack; - haystack += from; - const uint sl_minus_1 = sl - 1; - const ushort *n = needle+sl_minus_1; - const ushort *h = haystack+sl_minus_1; - uint hashNeedle = 0, hashHaystack = 0; - int idx; - - if (cs == Qt::CaseSensitive) { - for (idx = 0; idx < sl; ++idx) { - hashNeedle = ((hashNeedle<<1) + *(n-idx)); - hashHaystack = ((hashHaystack<<1) + *(h-idx)); - } - hashHaystack -= *haystack; - - while (haystack >= end) { - hashHaystack += *haystack; - if (hashHaystack == hashNeedle - && qt_compare_strings(sv(needle), sv(haystack), Qt::CaseSensitive) == 0) - return haystack - end; - --haystack; - REHASH(haystack[sl]); - } - } else { - for (idx = 0; idx < sl; ++idx) { - hashNeedle = ((hashNeedle<<1) + foldCase(n-idx, needle)); - hashHaystack = ((hashHaystack<<1) + foldCase(h-idx, end)); - } - hashHaystack -= foldCase(haystack, end); - - while (haystack >= end) { - hashHaystack += foldCase(haystack, end); - if (hashHaystack == hashNeedle - && qt_compare_strings(sv(haystack), sv(needle), Qt::CaseInsensitive) == 0) - return haystack - end; - --haystack; - REHASH(foldCase(haystack + sl, end)); - } - } - return -1; -} - -static inline int lastIndexOfHelper( - const QStringRef &haystack, int from, const QStringRef &needle, Qt::CaseSensitivity cs) -{ - return lastIndexOfHelper(reinterpret_cast<const ushort*>(haystack.unicode()), from, - reinterpret_cast<const ushort*>(needle.unicode()), needle.size(), cs); -} - -static inline int lastIndexOfHelper( - const QStringRef &haystack, int from, QLatin1String needle, Qt::CaseSensitivity cs) -{ - const int size = needle.size(); - QVarLengthArray<ushort> s(size); - qt_from_latin1(s.data(), needle.latin1(), size); - return lastIndexOfHelper(reinterpret_cast<const ushort*>(haystack.unicode()), from, - s.data(), size, cs); -} /*! Returns the index position of the last occurrence of the string \a @@ -3866,9 +3817,12 @@ static inline int lastIndexOfHelper( */ int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) const { - return QStringRef(this).lastIndexOf(QStringRef(&str), from, cs); + // ### Qt6: qsizetype + return int(QtPrivate::lastIndexOf(*this, from, str, cs)); } +#endif // QT_STRINGVIEW_LEVEL < 2 + /*! \since 4.5 \overload lastIndexOf() @@ -3890,7 +3844,8 @@ int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) c */ int QString::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const { - return QStringRef(this).lastIndexOf(str, from, cs); + // ### Qt6: qsizetype + return int(QtPrivate::lastIndexOf(*this, from, str, cs)); } /*! @@ -3901,10 +3856,11 @@ int QString::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) co */ int QString::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize - return int(qt_last_index_of(QStringView(unicode(), size()), ch, from, cs)); + // ### Qt6: qsizetype + return int(qLastIndexOf(*this, ch, from, cs)); } +#if QT_STRINGVIEW_LEVEL < 2 /*! \since 4.8 \overload lastIndexOf() @@ -3922,8 +3878,27 @@ int QString::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const */ int QString::lastIndexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) const { - return QStringRef(this).lastIndexOf(str, from, cs); + // ### Qt6: qsizetype + return int(QtPrivate::lastIndexOf(*this, from, str, cs)); } +#endif // QT_STRINGVIEW_LEVEL < 2 + +/*! + \fn int QString::lastIndexOf(QStringView str, int from, Qt::CaseSensitivity cs) const + \since 5.14 + \overload lastIndexOf() + + Returns the index position of the last occurrence of the string view \a + str in this string, searching backward from index position \a + from. If \a from is -1 (default), the search starts at the last + character; if \a from is -2, at the next to last character and so + on. Returns -1 if \a str is not found. + + If \a cs is Qt::CaseSensitive (default), the search is case + sensitive; otherwise the search is case insensitive. + + \sa indexOf(), contains(), count() +*/ #if !(defined(QT_NO_REGEXP) && !QT_CONFIG(regularexpression)) @@ -4235,7 +4210,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after) int QString::count(const QString &str, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(qt_string_count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs)); } @@ -4252,7 +4227,7 @@ int QString::count(const QString &str, Qt::CaseSensitivity cs) const int QString::count(QChar ch, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(qt_string_count(QStringView(unicode(), size()), ch, cs)); } @@ -4269,7 +4244,7 @@ int QString::count(QChar ch, Qt::CaseSensitivity cs) const */ int QString::count(const QStringRef &str, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(qt_string_count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs)); } @@ -5591,7 +5566,7 @@ QString QString::fromUtf16(const ushort *unicode, int size) while (unicode[size] != 0) ++size; } - return QUtf16::convertToUnicode((const char *)unicode, size*2, 0); + return QUtf16::convertToUnicode((const char *)unicode, size*2, nullptr); } /*! @@ -5645,7 +5620,7 @@ QString QString::fromUcs4(const uint *unicode, int size) while (unicode[size] != 0) ++size; } - return QUtf32::convertToUnicode((const char *)unicode, size*4, 0); + return QUtf32::convertToUnicode((const char *)unicode, size*4, nullptr); } @@ -8060,7 +8035,7 @@ void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar:: version = QChar::currentUnicodeVersion(); } else if (int(version) <= NormalizationCorrectionsVersionMax) { const QString &s = *data; - QChar *d = 0; + QChar *d = nullptr; for (int i = 0; i < NumNormalizationCorrections; ++i) { const NormalizationCorrection &n = uc_normalization_corrections[i]; if (n.version > version) { @@ -8797,19 +8772,23 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha return replaceArgEscapes(*this, d, fieldWidth, arg, locale_arg, fillChar); } -static int getEscape(const QChar *uc, int *pos, int len, int maxNumber = 999) +static inline ushort to_unicode(const QChar c) { return c.unicode(); } +static inline ushort to_unicode(const char c) { return QLatin1Char{c}.unicode(); } + +template <typename Char> +static int getEscape(const Char *uc, qsizetype *pos, qsizetype len, int maxNumber = 999) { int i = *pos; ++i; if (i < len && uc[i] == QLatin1Char('L')) ++i; if (i < len) { - int escape = uc[i].unicode() - '0'; + int escape = to_unicode(uc[i]) - '0'; if (uint(escape) >= 10U) return -1; ++i; while (i < len) { - int digit = uc[i].unicode() - '0'; + int digit = to_unicode(uc[i]) - '0'; if (uint(digit) >= 10U) break; escape = (escape * 10) + digit; @@ -8860,18 +8839,23 @@ static int getEscape(const QChar *uc, int *pos, int len, int maxNumber = 999) namespace { struct Part { - Part() : stringRef(), number(0) {} - Part(const QString &s, int pos, int len, int num = -1) noexcept - : stringRef(&s, pos, len), number(num) {} + Part() = default; // for QVarLengthArray; do not use + Q_DECL_CONSTEXPR Part(QStringView s, int num = -1) + : tag{QtPrivate::ArgBase::U16}, number{num}, data{s.utf16()}, size{s.size()} {} + Q_DECL_CONSTEXPR Part(QLatin1String s, int num = -1) + : tag{QtPrivate::ArgBase::L1}, number{num}, data{s.data()}, size{s.size()} {} + + void reset(QStringView s) noexcept { *this = {s, number}; } + void reset(QLatin1String s) noexcept { *this = {s, number}; } - QStringRef stringRef; + QtPrivate::ArgBase::Tag tag; int number; + const void *data; + qsizetype size; }; } // unnamed namespace -template <> -class QTypeInfo<Part> : public QTypeInfoMerger<Part, QStringRef, int> {}; // Q_DECLARE_METATYPE - +Q_DECLARE_TYPEINFO(Part, Q_PRIMITIVE_TYPE); namespace { @@ -8880,24 +8864,25 @@ enum { ExpectedParts = 32 }; typedef QVarLengthArray<Part, ExpectedParts> ParseResult; typedef QVarLengthArray<int, ExpectedParts/2> ArgIndexToPlaceholderMap; -static ParseResult parseMultiArgFormatString(const QString &s) +template <typename StringView> +static ParseResult parseMultiArgFormatString(StringView s) { ParseResult result; - const QChar *uc = s.constData(); - const int len = s.size(); - const int end = len - 1; - int i = 0; - int last = 0; + const auto uc = s.data(); + const auto len = s.size(); + const auto end = len - 1; + qsizetype i = 0; + qsizetype last = 0; while (i < end) { if (uc[i] == QLatin1Char('%')) { - int percent = i; + qsizetype percent = i; int number = getEscape(uc, &i, len); if (number != -1) { if (last != percent) - result.push_back(Part(s, last, percent - last)); // literal text (incl. failed placeholders) - result.push_back(Part(s, percent, i - percent, number)); // parsed placeholder + result.push_back(Part{s.mid(last, percent - last)}); // literal text (incl. failed placeholders) + result.push_back(Part{s.mid(percent, i - percent), number}); // parsed placeholder last = i; continue; } @@ -8906,7 +8891,7 @@ static ParseResult parseMultiArgFormatString(const QString &s) } if (last < len) - result.push_back(Part(s, last, len - last)); // trailing literal text + result.push_back(Part{s.mid(last, len - last)}); // trailing literal text return result; } @@ -8915,9 +8900,9 @@ static ArgIndexToPlaceholderMap makeArgIndexToPlaceholderMap(const ParseResult & { ArgIndexToPlaceholderMap result; - for (ParseResult::const_iterator it = parts.begin(), end = parts.end(); it != end; ++it) { - if (it->number >= 0) - result.push_back(it->number); + for (Part part : parts) { + if (part.number >= 0) + result.push_back(part.number); } std::sort(result.begin(), result.end()); @@ -8927,54 +8912,107 @@ static ArgIndexToPlaceholderMap makeArgIndexToPlaceholderMap(const ParseResult & return result; } -static int resolveStringRefsAndReturnTotalSize(ParseResult &parts, const ArgIndexToPlaceholderMap &argIndexToPlaceholderMap, const QString *args[]) +static qsizetype resolveStringRefsAndReturnTotalSize(ParseResult &parts, const ArgIndexToPlaceholderMap &argIndexToPlaceholderMap, const QtPrivate::ArgBase *args[]) { - int totalSize = 0; - for (ParseResult::iterator pit = parts.begin(), end = parts.end(); pit != end; ++pit) { - if (pit->number != -1) { - const ArgIndexToPlaceholderMap::const_iterator ait - = std::find(argIndexToPlaceholderMap.begin(), argIndexToPlaceholderMap.end(), pit->number); - if (ait != argIndexToPlaceholderMap.end()) - pit->stringRef = QStringRef(args[ait - argIndexToPlaceholderMap.begin()]); + using namespace QtPrivate; + qsizetype totalSize = 0; + for (Part &part : parts) { + if (part.number != -1) { + const auto it = std::find(argIndexToPlaceholderMap.begin(), argIndexToPlaceholderMap.end(), part.number); + if (it != argIndexToPlaceholderMap.end()) { + const auto &arg = *args[it - argIndexToPlaceholderMap.begin()]; + switch (arg.tag) { + case ArgBase::L1: + part.reset(static_cast<const QLatin1StringArg&>(arg).string); + break; + case ArgBase::U8: + Q_UNREACHABLE(); // waiting for QUtf8String... + break; + case ArgBase::U16: + part.reset(static_cast<const QStringViewArg&>(arg).string); + break; + } + } } - totalSize += pit->stringRef.size(); + totalSize += part.size; } return totalSize; } } // unnamed namespace +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QString QString::multiArg(int numArgs, const QString **args) const { + QVarLengthArray<QtPrivate::QStringViewArg, 9> sva; + sva.reserve(numArgs); + QVarLengthArray<const QtPrivate::ArgBase *, 9> pointers; + pointers.reserve(numArgs); + for (int i = 0; i < numArgs; ++i) { + sva.push_back(QtPrivate::qStringLikeToArg(*args[i])); + pointers.push_back(&sva.back()); + } + return QtPrivate::argToQString(qToStringViewIgnoringNull(*this), static_cast<size_t>(numArgs), pointers.data()); +} +#endif + +Q_ALWAYS_INLINE QString to_string(QLatin1String s) noexcept { return s; } +Q_ALWAYS_INLINE QString to_string(QStringView s) noexcept { return s.toString(); } + +template <typename StringView> +static QString argToQStringImpl(StringView pattern, size_t numArgs, const QtPrivate::ArgBase **args) +{ // Step 1-2 above - ParseResult parts = parseMultiArgFormatString(*this); + ParseResult parts = parseMultiArgFormatString(pattern); // 3-4 ArgIndexToPlaceholderMap argIndexToPlaceholderMap = makeArgIndexToPlaceholderMap(parts); - if (argIndexToPlaceholderMap.size() > numArgs) // 3a - argIndexToPlaceholderMap.resize(numArgs); - else if (argIndexToPlaceholderMap.size() < numArgs) // 3b - qWarning("QString::arg: %d argument(s) missing in %s", - numArgs - argIndexToPlaceholderMap.size(), toLocal8Bit().data()); + if (static_cast<size_t>(argIndexToPlaceholderMap.size()) > numArgs) // 3a + argIndexToPlaceholderMap.resize(int(numArgs)); + else if (Q_UNLIKELY(static_cast<size_t>(argIndexToPlaceholderMap.size()) < numArgs)) // 3b + qWarning("QString::arg: %d argument(s) missing in %ls", + int(numArgs - argIndexToPlaceholderMap.size()), qUtf16Printable(to_string(pattern))); // 5 - const int totalSize = resolveStringRefsAndReturnTotalSize(parts, argIndexToPlaceholderMap, args); + const qsizetype totalSize = resolveStringRefsAndReturnTotalSize(parts, argIndexToPlaceholderMap, args); // 6: QString result(totalSize, Qt::Uninitialized); - QChar *out = result.data(); - - for (ParseResult::const_iterator it = parts.begin(), end = parts.end(); it != end; ++it) { - if (const int sz = it->stringRef.size()) { - memcpy(out, it->stringRef.constData(), sz * sizeof(QChar)); - out += sz; + auto out = const_cast<QChar*>(result.constData()); + + for (Part part : parts) { + switch (part.tag) { + case QtPrivate::ArgBase::L1: + if (part.size) { + qt_from_latin1(reinterpret_cast<ushort*>(out), + reinterpret_cast<const char*>(part.data), part.size); + } + break; + case QtPrivate::ArgBase::U8: + Q_UNREACHABLE(); // waiting for QUtf8String + break; + case QtPrivate::ArgBase::U16: + if (part.size) + memcpy(out, part.data, part.size * sizeof(QChar)); + break; } + out += part.size; } return result; } +QString QtPrivate::argToQString(QStringView pattern, size_t n, const ArgBase **args) +{ + return argToQStringImpl(pattern, n, args); +} + +QString QtPrivate::argToQString(QLatin1String pattern, size_t n, const ArgBase **args) +{ + return argToQStringImpl(pattern, n, args); +} + /*! \fn bool QString::isSimpleText() const \internal @@ -9562,6 +9600,24 @@ QString &QString::setRawData(const QChar *unicode, int size) */ /*! + \fn int QLatin1String::lastIndexOf(QStringView str, int from, Qt::CaseSensitivity cs) const + \fn int QLatin1String::lastIndexOf(QLatin1String l1, int from, Qt::CaseSensitivity cs) const + \fn int QLatin1String::lastIndexOf(QChar c, int from, Qt::CaseSensitivity cs) const + \since 5.14 + + Returns the index position of the last occurrence of the string-view \a str, + Latin-1 string \a l1, or character \a ch, respectively, in this Latin-1 string, + searching backward from index position \a from. If \a from is -1 (default), + the search starts at the last character; if \a from is -2, at the next to last + character and so on. Returns -1 if \a str is not found. + + If \a cs is Qt::CaseSensitive (default), the search is case + sensitive; otherwise the search is case insensitive. + + \sa indexOf(), QStringView::lastIndexOf(), QStringView::indexOf(), QString::indexOf() +*/ + +/*! \fn QLatin1String::const_iterator QLatin1String::begin() const \since 5.10 @@ -11134,7 +11190,7 @@ QStringRef QString::midRef(int position, int n) const */ int QStringRef::indexOf(const QString &str, int from, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs)); } #endif // QT_STRINGVIEW_LEVEL < 2 @@ -11169,7 +11225,7 @@ int QStringRef::indexOf(const QString &str, int from, Qt::CaseSensitivity cs) co */ int QStringRef::indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(qFindChar(QStringView(unicode(), length()), ch, from, cs)); } @@ -11190,7 +11246,7 @@ int QStringRef::indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const */ int QStringRef::indexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(QtPrivate::findString(QStringView(unicode(), size()), from, str, cs)); } @@ -11211,7 +11267,7 @@ int QStringRef::indexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) con */ int QStringRef::indexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(QtPrivate::findString(QStringView(unicode(), size()), from, QStringView(str.unicode(), str.size()), cs)); } #endif // QT_STRINGVIEW_LEVEL < 2 @@ -11232,7 +11288,8 @@ int QStringRef::indexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) */ int QStringRef::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) const { - return lastIndexOf(QStringRef(&str), from, cs); + // ### Qt6: qsizetype + return int(QtPrivate::lastIndexOf(*this, from, str, cs)); } /*! @@ -11246,29 +11303,8 @@ int QStringRef::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs */ int QStringRef::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize - return int(qt_last_index_of(QStringView(unicode(), size()), ch, from, cs)); -} - -template<typename T> -static int last_index_of_impl(const QStringRef &haystack, int from, const T &needle, Qt::CaseSensitivity cs) -{ - const int sl = needle.size(); - if (sl == 1) - return haystack.lastIndexOf(needle.at(0), from, cs); - - const int l = haystack.size(); - if (from < 0) - from += l; - int delta = l - sl; - if (from == l && sl == 0) - return from; - if (uint(from) >= uint(l) || delta < 0) - return -1; - if (from > delta) - from = delta; - - return lastIndexOfHelper(haystack, from, needle, cs); + // ### Qt6: qsizetype + return int(qLastIndexOf(*this, ch, from, cs)); } /*! @@ -11288,7 +11324,8 @@ static int last_index_of_impl(const QStringRef &haystack, int from, const T &nee */ int QStringRef::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const { - return last_index_of_impl(*this, from, str, cs); + // ### Qt6: qsizetype + return int(QtPrivate::lastIndexOf(*this, from, str, cs)); } /*! @@ -11308,10 +11345,28 @@ int QStringRef::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) */ int QStringRef::lastIndexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) const { - return last_index_of_impl(*this, from, str, cs); + // ### Qt6: qsizetype + return int(QtPrivate::lastIndexOf(*this, from, str, cs)); } /*! + \fn int QStringRef::lastIndexOf(QStringView str, int from, Qt::CaseSensitivity cs) const + \since 5.14 + \overload lastIndexOf() + + Returns the index position of the last occurrence of the string view \a + str in this string, searching backward from index position \a + from. If \a from is -1 (default), the search starts at the last + character; if \a from is -2, at the next to last character and so + on. Returns -1 if \a str is not found. + + If \a cs is Qt::CaseSensitive (default), the search is case + sensitive; otherwise the search is case insensitive. + + \sa indexOf(), contains(), count() +*/ + +/*! \since 4.8 Returns the number of (potentially overlapping) occurrences of the string \a str in this string reference. @@ -11323,7 +11378,7 @@ int QStringRef::lastIndexOf(const QStringRef &str, int from, Qt::CaseSensitivity */ int QStringRef::count(const QString &str, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(qt_string_count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs)); } @@ -11341,7 +11396,7 @@ int QStringRef::count(const QString &str, Qt::CaseSensitivity cs) const */ int QStringRef::count(QChar ch, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(qt_string_count(QStringView(unicode(), size()), ch, cs)); } @@ -11359,7 +11414,7 @@ int QStringRef::count(QChar ch, Qt::CaseSensitivity cs) const */ int QStringRef::count(const QStringRef &str, Qt::CaseSensitivity cs) const { - // ### Qt6: qsize + // ### Qt6: qsizetype return int(qt_string_count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs)); } @@ -11613,33 +11668,6 @@ bool QStringRef::endsWith(const QStringRef &str, Qt::CaseSensitivity cs) const \sa indexOf(), count() */ -static inline qsizetype qt_last_index_of(QStringView haystack, QChar needle, - qsizetype from, Qt::CaseSensitivity cs) -{ - if (from < 0) - from += haystack.size(); - if (std::size_t(from) >= std::size_t(haystack.size())) - return -1; - if (from >= 0) { - ushort c = needle.unicode(); - const ushort *b = reinterpret_cast<const ushort*>(haystack.data()); - const ushort *n = b + from; - if (cs == Qt::CaseSensitive) { - for (; n >= b; --n) - if (*n == c) - return n - b; - } else { - c = foldCase(c); - for (; n >= b; --n) - if (foldCase(*n) == c) - return n - b; - } - } - return -1; - - -} - static inline qsizetype qt_string_count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs) { qsizetype num = 0; @@ -11821,6 +11849,38 @@ bool QtPrivate::endsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseS return qt_ends_with_impl(haystack, needle, cs); } +namespace { +template <typename Pointer> +uint foldCaseHelper(Pointer ch, Pointer start) = delete; + +template <> +uint foldCaseHelper<const QChar*>(const QChar* ch, const QChar* start) +{ + return foldCase(reinterpret_cast<const ushort*>(ch), reinterpret_cast<const ushort*>(start)); +} + +template <> +uint foldCaseHelper<const char*>(const char* ch, const char*) +{ + return foldCase(ushort(uchar(*ch))); +} + +template <typename T> +ushort valueTypeToUtf16(T t) = delete; + +template <> +ushort valueTypeToUtf16<QChar>(QChar t) +{ + return t.unicode(); +} + +template <> +ushort valueTypeToUtf16<char>(char t) +{ + return ushort(uchar(t)); +} +} + /*! \internal @@ -11929,6 +11989,97 @@ qsizetype QtPrivate::findString(QStringView haystack0, qsizetype from, QStringVi return -1; } +template <typename Haystack> +static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle, + qsizetype from, Qt::CaseSensitivity cs) noexcept +{ + if (from < 0) + from += haystack.size(); + if (std::size_t(from) >= std::size_t(haystack.size())) + return -1; + if (from >= 0) { + ushort c = needle.unicode(); + const auto b = haystack.data(); + auto n = b + from; + if (cs == Qt::CaseSensitive) { + for (; n >= b; --n) + if (valueTypeToUtf16(*n) == c) + return n - b; + } else { + c = foldCase(c); + for (; n >= b; --n) + if (foldCase(valueTypeToUtf16(*n)) == c) + return n - b; + } + } + return -1; +} + +template<typename Haystack, typename Needle> +static qsizetype qLastIndexOf(Haystack haystack0, qsizetype from, + Needle needle0, Qt::CaseSensitivity cs) noexcept +{ + const qsizetype sl = needle0.size(); + if (sl == 1) + return qLastIndexOf(haystack0, needle0.front(), from, cs); + + const qsizetype l = haystack0.size(); + if (from < 0) + from += l; + if (from == l && sl == 0) + return from; + const qsizetype delta = l - sl; + if (std::size_t(from) >= std::size_t(l) || delta < 0) + return -1; + if (from > delta) + from = delta; + + auto sv = [sl](const typename Haystack::value_type *v) { return Haystack(v, sl); }; + + auto haystack = haystack0.data(); + const auto needle = needle0.data(); + const auto *end = haystack; + haystack += from; + const std::size_t sl_minus_1 = sl - 1; + const auto *n = needle + sl_minus_1; + const auto *h = haystack + sl_minus_1; + std::size_t hashNeedle = 0, hashHaystack = 0; + qsizetype idx; + + if (cs == Qt::CaseSensitive) { + for (idx = 0; idx < sl; ++idx) { + hashNeedle = (hashNeedle << 1) + valueTypeToUtf16(*(n - idx)); + hashHaystack = (hashHaystack << 1) + valueTypeToUtf16(*(h - idx)); + } + hashHaystack -= valueTypeToUtf16(*haystack); + + while (haystack >= end) { + hashHaystack += valueTypeToUtf16(*haystack); + if (hashHaystack == hashNeedle + && qt_compare_strings(needle0, sv(haystack), Qt::CaseSensitive) == 0) + return haystack - end; + --haystack; + REHASH(valueTypeToUtf16(haystack[sl])); + } + } else { + for (idx = 0; idx < sl; ++idx) { + hashNeedle = (hashNeedle << 1) + foldCaseHelper(n - idx, needle); + hashHaystack = (hashHaystack << 1) + foldCaseHelper(h - idx, end); + } + hashHaystack -= foldCaseHelper(haystack, end); + + while (haystack >= end) { + hashHaystack += foldCaseHelper(haystack, end); + if (hashHaystack == hashNeedle + && qt_compare_strings(sv(haystack), needle0, Qt::CaseInsensitive) == 0) + return haystack - end; + --haystack; + REHASH(foldCaseHelper(haystack + sl, end)); + } + } + return -1; +} + qsizetype QtPrivate::findString(QStringView haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs) noexcept { if (haystack.size() < needle.size()) @@ -11962,6 +12113,26 @@ qsizetype QtPrivate::findString(QLatin1String haystack, qsizetype from, QLatin1S QStringView(reinterpret_cast<const QChar*>(n.constData()), n.size()), cs); } +qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs) noexcept +{ + return qLastIndexOf(haystack, from, needle, cs); +} + +qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs) noexcept +{ + return qLastIndexOf(haystack, from, needle, cs); +} + +qsizetype QtPrivate::lastIndexOf(QLatin1String haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs) noexcept +{ + return qLastIndexOf(haystack, from, needle, cs); +} + +qsizetype QtPrivate::lastIndexOf(QLatin1String haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs) noexcept +{ + return qLastIndexOf(haystack, from, needle, cs); +} + /*! \since 4.8 diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index da8260a999..6788e53057 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -106,6 +106,9 @@ public: Q_DECL_CONSTEXPR bool isNull() const noexcept { return !data(); } Q_DECL_CONSTEXPR bool isEmpty() const noexcept { return !size(); } + template <typename...Args> + Q_REQUIRED_RESULT inline QString arg(Args &&...args) const; + Q_DECL_CONSTEXPR QLatin1Char at(int i) const { return Q_ASSERT(i >= 0), Q_ASSERT(i < size()), QLatin1Char(m_data[i]); } Q_DECL_CONSTEXPR QLatin1Char operator[](int i) const { return at(i); } @@ -132,11 +135,11 @@ public: { return QtPrivate::endsWith(*this, QStringView(&c, 1), cs); } Q_REQUIRED_RESULT int indexOf(QStringView s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept - { return int(QtPrivate::findString(*this, from, s, cs)); } // ### Qt6: qsize + { return int(QtPrivate::findString(*this, from, s, cs)); } // ### Qt6: qsizetype Q_REQUIRED_RESULT int indexOf(QLatin1String s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept - { return int(QtPrivate::findString(*this, from, s, cs)); } // ### Qt6: qsize + { return int(QtPrivate::findString(*this, from, s, cs)); } // ### Qt6: qsizetype Q_REQUIRED_RESULT inline int indexOf(QChar c, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept - { return int(QtPrivate::findString(*this, from, QStringView(&c, 1), cs)); } // ### Qt6: qsize + { return int(QtPrivate::findString(*this, from, QStringView(&c, 1), cs)); } // ### Qt6: qsizetype Q_REQUIRED_RESULT bool contains(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return indexOf(s, 0, cs) != -1; } @@ -145,6 +148,13 @@ public: Q_REQUIRED_RESULT inline bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return indexOf(QStringView(&c, 1), 0, cs) != -1; } + Q_REQUIRED_RESULT int lastIndexOf(QStringView s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return int(QtPrivate::lastIndexOf(*this, from, s, cs)); } // ### Qt6: qsizetype + Q_REQUIRED_RESULT int lastIndexOf(QLatin1String s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return int(QtPrivate::lastIndexOf(*this, from, s, cs)); } // ### Qt6: qsizetype + Q_REQUIRED_RESULT inline int lastIndexOf(QChar c, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return int(QtPrivate::lastIndexOf(*this, from, QStringView(&c, 1), cs)); } // ### Qt6: qsizetype + using value_type = const char; using reference = value_type&; using const_reference = reference; @@ -214,7 +224,9 @@ private: Q_DECLARE_TYPEINFO(QLatin1String, Q_MOVABLE_TYPE); // Qt 4.x compatibility -typedef QLatin1String QLatin1Literal; +#if QT_DEPRECATED_SINCE(5, 14) +QT_DEPRECATED_X("Use QLatin1String") typedef QLatin1String QLatin1Literal; +#endif // // QLatin1String inline implementations @@ -233,6 +245,8 @@ qsizetype QStringView::indexOf(QLatin1String s, qsizetype from, Qt::CaseSensitiv { return QtPrivate::findString(*this, from, s, cs); } bool QStringView::contains(QLatin1String s, Qt::CaseSensitivity cs) const noexcept { return indexOf(s, 0, cs) != qsizetype(-1); } +qsizetype QStringView::lastIndexOf(QLatin1String s, qsizetype from, Qt::CaseSensitivity cs) const noexcept +{ return QtPrivate::lastIndexOf(*this, from, s, cs); } class Q_CORE_EXPORT QString { @@ -353,11 +367,16 @@ public: int indexOf(const QStringRef &s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; #endif Q_REQUIRED_RESULT int indexOf(QStringView s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept - { return int(QtPrivate::findString(*this, from, s, cs)); } // ### Qt6: qsize + { return int(QtPrivate::findString(*this, from, s, cs)); } // ### Qt6: qsizetype int lastIndexOf(QChar c, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; - int lastIndexOf(const QString &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; int lastIndexOf(QLatin1String s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; +#if QT_STRINGVIEW_LEVEL < 2 + int lastIndexOf(const QString &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; int lastIndexOf(const QStringRef &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; +#endif + + Q_REQUIRED_RESULT int lastIndexOf(QStringView s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return int(QtPrivate::lastIndexOf(*this, from, s, cs)); } // ### Qt6: qsizetype inline bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; #if QT_STRINGVIEW_LEVEL < 2 @@ -905,8 +924,8 @@ private: void reallocData(uint alloc, bool grow = false); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void expand(int i); -#endif QString multiArg(int numArgs, const QString **args) const; +#endif static int compare_helper(const QChar *data1, int length1, const QChar *data2, int length2, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; @@ -1035,30 +1054,30 @@ inline QString QString::arg(short a, int fieldWidth, int base, QChar fillChar) c inline QString QString::arg(ushort a, int fieldWidth, int base, QChar fillChar) const { return arg(qulonglong(a), fieldWidth, base, fillChar); } inline QString QString::arg(const QString &a1, const QString &a2) const -{ const QString *args[2] = { &a1, &a2 }; return multiArg(2, args); } +{ return qToStringViewIgnoringNull(*this).arg(a1, a2); } inline QString QString::arg(const QString &a1, const QString &a2, const QString &a3) const -{ const QString *args[3] = { &a1, &a2, &a3 }; return multiArg(3, args); } +{ return qToStringViewIgnoringNull(*this).arg(a1, a2, a3); } inline QString QString::arg(const QString &a1, const QString &a2, const QString &a3, const QString &a4) const -{ const QString *args[4] = { &a1, &a2, &a3, &a4 }; return multiArg(4, args); } +{ return qToStringViewIgnoringNull(*this).arg(a1, a2, a3, a4); } inline QString QString::arg(const QString &a1, const QString &a2, const QString &a3, const QString &a4, const QString &a5) const -{ const QString *args[5] = { &a1, &a2, &a3, &a4, &a5 }; return multiArg(5, args); } +{ return qToStringViewIgnoringNull(*this).arg(a1, a2, a3, a4, a5); } inline QString QString::arg(const QString &a1, const QString &a2, const QString &a3, const QString &a4, const QString &a5, const QString &a6) const -{ const QString *args[6] = { &a1, &a2, &a3, &a4, &a5, &a6 }; return multiArg(6, args); } +{ return qToStringViewIgnoringNull(*this).arg(a1, a2, a3, a4, a5, a6); } inline QString QString::arg(const QString &a1, const QString &a2, const QString &a3, const QString &a4, const QString &a5, const QString &a6, const QString &a7) const -{ const QString *args[7] = { &a1, &a2, &a3, &a4, &a5, &a6, &a7 }; return multiArg(7, args); } +{ return qToStringViewIgnoringNull(*this).arg(a1, a2, a3, a4, a5, a6, a7); } inline QString QString::arg(const QString &a1, const QString &a2, const QString &a3, const QString &a4, const QString &a5, const QString &a6, const QString &a7, const QString &a8) const -{ const QString *args[8] = { &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8 }; return multiArg(8, args); } +{ return qToStringViewIgnoringNull(*this).arg(a1, a2, a3, a4, a5, a6, a7, a8); } inline QString QString::arg(const QString &a1, const QString &a2, const QString &a3, const QString &a4, const QString &a5, const QString &a6, const QString &a7, const QString &a8, const QString &a9) const -{ const QString *args[9] = { &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9 }; return multiArg(9, args); } +{ return qToStringViewIgnoringNull(*this).arg(a1, a2, a3, a4, a5, a6, a7, a8, a9); } inline QString QString::section(QChar asep, int astart, int aend, SectionFlags aflags) const { return section(QString(asep), astart, aend, aflags); } @@ -1084,7 +1103,7 @@ class #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) Q_CORE_EXPORT #endif -QCharRef { +QCharRef { // ### Qt 7: remove QString &s; int i; inline QCharRef(QString &str, int idx) @@ -1536,13 +1555,17 @@ public: int indexOf(const QStringRef &str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; #endif Q_REQUIRED_RESULT int indexOf(QStringView s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept - { return int(QtPrivate::findString(*this, from, s, cs)); } // ### Qt6: qsize + { return int(QtPrivate::findString(*this, from, s, cs)); } // ### Qt6: qsizetype int indexOf(QChar ch, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; int indexOf(QLatin1String str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; +#if QT_STRINGVIEW_LEVEL < 2 + int lastIndexOf(const QStringRef &str, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; int lastIndexOf(const QString &str, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; +#endif int lastIndexOf(QChar ch, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; int lastIndexOf(QLatin1String str, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; - int lastIndexOf(const QStringRef &str, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; + Q_REQUIRED_RESULT int lastIndexOf(QStringView s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return int(QtPrivate::lastIndexOf(*this, from, s, cs)); } // ### Qt6: qsizetype #if QT_STRINGVIEW_LEVEL < 2 inline bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; @@ -1959,6 +1982,58 @@ inline const QString &asString(const QString &s) { return s; } inline QString &&asString(QString &&s) { return std::move(s); } } +// +// QStringView::arg() implementation +// + +namespace QtPrivate { + +struct ArgBase { + enum Tag : uchar { L1, U8, U16 } tag; +}; + +struct QStringViewArg : ArgBase { + QStringView string; + QStringViewArg() = default; + Q_DECL_CONSTEXPR explicit QStringViewArg(QStringView v) noexcept : ArgBase{U16}, string{v} {} +}; + +struct QLatin1StringArg : ArgBase { + QLatin1String string; + QLatin1StringArg() = default; + Q_DECL_CONSTEXPR explicit QLatin1StringArg(QLatin1String v) noexcept : ArgBase{L1}, string{v} {} +}; + +Q_REQUIRED_RESULT Q_CORE_EXPORT QString argToQString(QStringView pattern, size_t n, const ArgBase **args); +Q_REQUIRED_RESULT Q_CORE_EXPORT QString argToQString(QLatin1String pattern, size_t n, const ArgBase **args); + +template <typename StringView, typename...Args> +Q_REQUIRED_RESULT Q_ALWAYS_INLINE QString argToQStringDispatch(StringView pattern, const Args &...args) +{ + const ArgBase *argBases[] = {&args..., /* avoid zero-sized array */ nullptr}; + return QtPrivate::argToQString(pattern, sizeof...(Args), argBases); +} + +Q_DECL_CONSTEXPR inline QStringViewArg qStringLikeToArg(QStringView s) noexcept { return QStringViewArg{s}; } + inline QStringViewArg qStringLikeToArg(const QChar &c) noexcept { return QStringViewArg{QStringView{&c, 1}}; } +Q_DECL_CONSTEXPR inline QLatin1StringArg qStringLikeToArg(QLatin1String s) noexcept { return QLatin1StringArg{s}; } + +} // namespace QtPrivate + +template <typename...Args> +Q_ALWAYS_INLINE +QString QStringView::arg(Args &&...args) const +{ + return QtPrivate::argToQStringDispatch(*this, QtPrivate::qStringLikeToArg(args)...); +} + +template <typename...Args> +Q_ALWAYS_INLINE +QString QLatin1String::arg(Args &&...args) const +{ + return QtPrivate::argToQStringDispatch(*this, QtPrivate::qStringLikeToArg(args)...); +} + QT_END_NAMESPACE #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER) diff --git a/src/corelib/tools/qstringalgorithms.h b/src/corelib/tools/qstringalgorithms.h index 51a86cfeb5..2b480b1e4c 100644 --- a/src/corelib/tools/qstringalgorithms.h +++ b/src/corelib/tools/qstringalgorithms.h @@ -80,6 +80,11 @@ Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QStrin Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QLatin1String haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QLatin1String haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; +Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; +Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QStringView haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; +Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QLatin1String haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; +Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QLatin1String haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; + Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION QStringView trimmed(QStringView s) noexcept; Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION QLatin1String trimmed(QLatin1String s) noexcept; diff --git a/src/corelib/tools/qstringlist.cpp b/src/corelib/tools/qstringlist.cpp index f6da7b1428..4bbe424ed2 100644 --- a/src/corelib/tools/qstringlist.cpp +++ b/src/corelib/tools/qstringlist.cpp @@ -283,6 +283,7 @@ void QtPrivate::QStringList_sort(QStringList *that, Qt::CaseSensitivity cs) } +#if QT_STRINGVIEW_LEVEL < 2 /*! \fn QStringList QStringList::filter(const QString &str, Qt::CaseSensitivity cs) const @@ -302,6 +303,26 @@ void QtPrivate::QStringList_sort(QStringList *that, Qt::CaseSensitivity cs) \sa contains() */ +#endif + +/*! + \fn QStringList QStringList::filter(QStringView str, Qt::CaseSensitivity cs) const + \overload + \since 5.14 +*/ +QStringList QtPrivate::QStringList_filter(const QStringList *that, QStringView str, + Qt::CaseSensitivity cs) +{ + QStringMatcher matcher(str, cs); + QStringList res; + for (int i = 0; i < that->size(); ++i) + if (matcher.indexIn(that->at(i)) != -1) + res << that->at(i); + return res; +} + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +/// Not really needed anymore, but kept for binary compatibility QStringList QtPrivate::QStringList_filter(const QStringList *that, const QString &str, Qt::CaseSensitivity cs) { @@ -312,6 +333,7 @@ QStringList QtPrivate::QStringList_filter(const QStringList *that, const QString res << that->at(i); return res; } +#endif template<typename T> static bool stringList_contains(const QStringList &stringList, const T &str, Qt::CaseSensitivity cs) @@ -466,6 +488,7 @@ QStringList QtPrivate::QStringList_filter(const QStringList *that, const QRegula } #endif // QT_CONFIG(regularexpression) +#if QT_STRINGVIEW_LEVEL < 2 /*! \fn QStringList &QStringList::replaceInStrings(const QString &before, const QString &after, Qt::CaseSensitivity cs) @@ -481,12 +504,41 @@ QStringList QtPrivate::QStringList_filter(const QStringList *that, const QRegula \sa QString::replace() */ + +/*! + \fn QStringList &QStringList::replaceInStrings(QStringView before, const QString &after, Qt::CaseSensitivity cs) + \overload + \since 5.14 +*/ + +/*! + \fn QStringList &QStringList::replaceInStrings(const QString &before, QStringView after, Qt::CaseSensitivity cs) + \overload + \since 5.14 +*/ +#endif + +/*! + \fn QStringList &QStringList::replaceInStrings(QStringView before, QStringView after, Qt::CaseSensitivity cs) + \overload + \since 5.14 +*/ +void QtPrivate::QStringList_replaceInStrings(QStringList *that, QStringView before, + QStringView after, Qt::CaseSensitivity cs) +{ + for (int i = 0; i < that->size(); ++i) + (*that)[i].replace(before.data(), before.length(), after.data(), after.length(), cs); +} + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +/// Not really needed anymore, but kept for binary compatibility void QtPrivate::QStringList_replaceInStrings(QStringList *that, const QString &before, const QString &after, Qt::CaseSensitivity cs) { for (int i = 0; i < that->size(); ++i) (*that)[i].replace(before, after, cs); } +#endif #ifndef QT_NO_REGEXP @@ -561,6 +613,7 @@ static int accumulatedSize(const QStringList &list, int seplen) return result; } +#if QT_STRINGVIEW_LEVEL < 2 /*! \fn QString QStringList::join(const QString &separator) const @@ -570,6 +623,7 @@ static int accumulatedSize(const QStringList &list, int seplen) \sa QString::split() */ +#endif /*! \fn QString QStringList::join(QChar separator) const @@ -615,6 +669,16 @@ QString QtPrivate::QStringList_join(const QStringList &list, QLatin1String sep) } /*! + \fn QString QStringList::join(QStringView separator) const + \overload + \since 5.14 +*/ +QString QtPrivate::QStringList_join(const QStringList *that, QStringView sep) +{ + return QStringList_join(that, sep.data(), sep.length()); +} + +/*! \fn QStringList QStringList::operator+(const QStringList &other) const Returns a string list that is the concatenation of this string diff --git a/src/corelib/tools/qstringlist.h b/src/corelib/tools/qstringlist.h index 3bb657069b..a464d443dc 100644 --- a/src/corelib/tools/qstringlist.h +++ b/src/corelib/tools/qstringlist.h @@ -54,8 +54,10 @@ QT_BEGIN_NAMESPACE class QRegExp; class QRegularExpression; +#if !defined(QT_NO_JAVA_STYLE_ITERATORS) typedef QListIterator<QString> QStringListIterator; typedef QMutableListIterator<QString> QMutableStringListIterator; +#endif class QStringList; @@ -73,12 +75,21 @@ public: inline void sort(Qt::CaseSensitivity cs = Qt::CaseSensitive); inline int removeDuplicates(); +#if QT_STRINGVIEW_LEVEL < 2 inline QString join(const QString &sep) const; +#endif + inline QString join(QStringView sep) const; inline QString join(QLatin1String sep) const; inline QString join(QChar sep) const; + inline QStringList filter(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; + inline QStringList &replaceInStrings(QStringView before, QStringView after, Qt::CaseSensitivity cs = Qt::CaseSensitive); +#if QT_STRINGVIEW_LEVEL < 2 inline QStringList filter(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; inline QStringList &replaceInStrings(const QString &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive); + inline QStringList &replaceInStrings(const QString &before, QStringView after, Qt::CaseSensitivity cs = Qt::CaseSensitive); + inline QStringList &replaceInStrings(QStringView before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive); +#endif #ifndef QT_NO_REGEXP inline QStringList filter(const QRegExp &rx) const; @@ -163,18 +174,27 @@ inline const QStringList *QListSpecialMethods<QString>::self() const namespace QtPrivate { void Q_CORE_EXPORT QStringList_sort(QStringList *that, Qt::CaseSensitivity cs); int Q_CORE_EXPORT QStringList_removeDuplicates(QStringList *that); + QString Q_CORE_EXPORT QStringList_join(const QStringList *that, QStringView sep); QString Q_CORE_EXPORT QStringList_join(const QStringList *that, const QChar *sep, int seplen); Q_CORE_EXPORT QString QStringList_join(const QStringList &list, QLatin1String sep); + QStringList Q_CORE_EXPORT QStringList_filter(const QStringList *that, QStringView str, + Qt::CaseSensitivity cs); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QStringList Q_CORE_EXPORT QStringList_filter(const QStringList *that, const QString &str, Qt::CaseSensitivity cs); +#endif #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) bool Q_CORE_EXPORT QStringList_contains(const QStringList *that, const QString &str, Qt::CaseSensitivity cs); #endif bool Q_CORE_EXPORT QStringList_contains(const QStringList *that, QStringView str, Qt::CaseSensitivity cs); bool Q_CORE_EXPORT QStringList_contains(const QStringList *that, QLatin1String str, Qt::CaseSensitivity cs); + void Q_CORE_EXPORT QStringList_replaceInStrings(QStringList *that, QStringView before, QStringView after, + Qt::CaseSensitivity cs); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void Q_CORE_EXPORT QStringList_replaceInStrings(QStringList *that, const QString &before, const QString &after, Qt::CaseSensitivity cs); +#endif #ifndef QT_NO_REGEXP void Q_CORE_EXPORT QStringList_replaceInStrings(QStringList *that, const QRegExp &rx, const QString &after); @@ -203,10 +223,17 @@ inline int QListSpecialMethods<QString>::removeDuplicates() return QtPrivate::QStringList_removeDuplicates(self()); } +#if QT_STRINGVIEW_LEVEL < 2 inline QString QListSpecialMethods<QString>::join(const QString &sep) const { return QtPrivate::QStringList_join(self(), sep.constData(), sep.length()); } +#endif + +inline QString QListSpecialMethods<QString>::join(QStringView sep) const +{ + return QtPrivate::QStringList_join(self(), sep); +} QString QListSpecialMethods<QString>::join(QLatin1String sep) const { @@ -218,10 +245,17 @@ inline QString QListSpecialMethods<QString>::join(QChar sep) const return QtPrivate::QStringList_join(self(), &sep, 1); } +inline QStringList QListSpecialMethods<QString>::filter(QStringView str, Qt::CaseSensitivity cs) const +{ + return QtPrivate::QStringList_filter(self(), str, cs); +} + +#if QT_STRINGVIEW_LEVEL < 2 inline QStringList QListSpecialMethods<QString>::filter(const QString &str, Qt::CaseSensitivity cs) const { return QtPrivate::QStringList_filter(self(), str, cs); } +#endif #if QT_STRINGVIEW_LEVEL < 2 inline bool QStringList::contains(const QString &str, Qt::CaseSensitivity cs) const @@ -240,12 +274,32 @@ inline bool QStringList::contains(QStringView str, Qt::CaseSensitivity cs) const return QtPrivate::QStringList_contains(this, str, cs); } +inline QStringList &QListSpecialMethods<QString>::replaceInStrings(QStringView before, QStringView after, Qt::CaseSensitivity cs) +{ + QtPrivate::QStringList_replaceInStrings(self(), before, after, cs); + return *self(); +} + +#if QT_STRINGVIEW_LEVEL < 2 inline QStringList &QListSpecialMethods<QString>::replaceInStrings(const QString &before, const QString &after, Qt::CaseSensitivity cs) { QtPrivate::QStringList_replaceInStrings(self(), before, after, cs); return *self(); } +inline QStringList &QListSpecialMethods<QString>::replaceInStrings(QStringView before, const QString &after, Qt::CaseSensitivity cs) +{ + QtPrivate::QStringList_replaceInStrings(self(), before, qToStringViewIgnoringNull(after), cs); + return *self(); +} + +inline QStringList &QListSpecialMethods<QString>::replaceInStrings(const QString &before, QStringView after, Qt::CaseSensitivity cs) +{ + QtPrivate::QStringList_replaceInStrings(self(), QStringView(before), after, cs); + return *self(); +} +#endif + inline QStringList operator+(const QList<QString> &one, const QStringList &other) { QStringList n = one; diff --git a/src/corelib/tools/qstringmatcher.cpp b/src/corelib/tools/qstringmatcher.cpp index 2e2ae18b9a..167a467480 100644 --- a/src/corelib/tools/qstringmatcher.cpp +++ b/src/corelib/tools/qstringmatcher.cpp @@ -149,7 +149,7 @@ static inline qsizetype bm_find(const ushort *uc, qsizetype l, qsizetype index, Call setPattern() to give it a pattern to match. */ QStringMatcher::QStringMatcher() - : d_ptr(0), q_cs(Qt::CaseSensitive) + : d_ptr(nullptr), q_cs(Qt::CaseSensitive) { memset(q_data, 0, sizeof(q_data)); } @@ -161,7 +161,7 @@ QStringMatcher::QStringMatcher() Call indexIn() to perform a search. */ QStringMatcher::QStringMatcher(const QString &pattern, Qt::CaseSensitivity cs) - : d_ptr(0), q_pattern(pattern), q_cs(cs) + : d_ptr(nullptr), q_pattern(pattern), q_cs(cs) { p.uc = pattern.unicode(); p.len = pattern.size(); @@ -200,7 +200,7 @@ QStringMatcher::QStringMatcher(QStringView str, Qt::CaseSensitivity cs) Copies the \a other string matcher to this string matcher. */ QStringMatcher::QStringMatcher(const QStringMatcher &other) - : d_ptr(0) + : d_ptr(nullptr) { operator=(other); } diff --git a/src/corelib/tools/qstringview.cpp b/src/corelib/tools/qstringview.cpp index 050097b443..cc852dd042 100644 --- a/src/corelib/tools/qstringview.cpp +++ b/src/corelib/tools/qstringview.cpp @@ -530,6 +530,24 @@ QT_BEGIN_NAMESPACE */ /*! + \fn QString QStringView::arg(Args &&...args) const + \fn QString QLatin1String::arg(Args &&...args) const + \since 5.14 + + Replaces occurrences of \c{%N} in this string with the corresponding + argument from \a args. The arguments are not positional: the first of + the \a args replaces the \c{%N} with the lowest \c{N} (all of them), the + second of the \a args the \c{%N} with the next-lowest \c{N} etc. + + \c Args can consist of anything that implicitly converts to QStringView + or QLatin1String. + + In addition, the following types are also supported: QChar, QLatin1Char. + + \sa QString::arg() +*/ + +/*! \fn QChar QStringView::front() const Returns the first character in the string. Same as first(). @@ -755,6 +773,24 @@ QT_BEGIN_NAMESPACE */ /*! + \fn qsizetype QStringView::lastIndexOf(QStringView str, qsizetype from, Qt::CaseSensitivity cs) const + \fn qsizetype QStringView::lastIndexOf(QLatin1String l1, qsizetype from, Qt::CaseSensitivity cs) const + \fn qsizetype QStringView::lastIndexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs) const + \since 5.14 + + Returns the index position of the last occurrence of the string-view \a str, + Latin-1 string \a l1, or character \a ch, respectively, in this string-view, + searching backward from index position \a from. If \a from is -1 (default), + the search starts at the last character; if \a from is -2, at the next to last + character and so on. Returns -1 if \a str is not found. + + If \a cs is Qt::CaseSensitive (default), the search is case + sensitive; otherwise the search is case insensitive. + + \sa QString::lastIndexOf() +*/ + +/*! \fn QByteArray QStringView::toLatin1() const Returns a Latin-1 representation of the string as a QByteArray. diff --git a/src/corelib/tools/qstringview.h b/src/corelib/tools/qstringview.h index 2c93b31385..b84b2995b9 100644 --- a/src/corelib/tools/qstringview.h +++ b/src/corelib/tools/qstringview.h @@ -226,6 +226,9 @@ public: // QString API // + template <typename...Args> + Q_REQUIRED_RESULT inline QString arg(Args &&...args) const; // defined in qstring.h + Q_REQUIRED_RESULT QByteArray toLatin1() const { return QtPrivate::convertToLatin1(*this); } Q_REQUIRED_RESULT QByteArray toUtf8() const { return QtPrivate::convertToUtf8(*this); } Q_REQUIRED_RESULT QByteArray toLocal8Bit() const { return QtPrivate::convertToLocal8Bit(*this); } @@ -282,6 +285,12 @@ public: { return indexOf(s, 0, cs) != qsizetype(-1); } Q_REQUIRED_RESULT inline bool contains(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; + Q_REQUIRED_RESULT qsizetype lastIndexOf(QChar c, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return QtPrivate::lastIndexOf(*this, from, QStringView(&c, 1), cs); } + Q_REQUIRED_RESULT qsizetype lastIndexOf(QStringView s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return QtPrivate::lastIndexOf(*this, from, s, cs); } + Q_REQUIRED_RESULT inline qsizetype lastIndexOf(QLatin1String s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept; + Q_REQUIRED_RESULT bool isRightToLeft() const noexcept { return QtPrivate::isRightToLeft(*this); } diff --git a/src/corelib/tools/qunicodetools.cpp b/src/corelib/tools/qunicodetools.cpp index d14118abf7..08e1146c59 100644 --- a/src/corelib/tools/qunicodetools.cpp +++ b/src/corelib/tools/qunicodetools.cpp @@ -327,7 +327,7 @@ static const uchar breakTable[BAfter + 1][QUnicodeTables::NumSentenceBreakClasse // Any CR LF Sep Extend Sp Lower Upper OLetter Numeric ATerm SContinue STerm Close { Initial, BAfterC, BAfter , BAfter , Initial, Initial, Lower , Upper , Initial, Initial, ATerm , Initial, STerm , Initial }, // Initial { Initial, BAfterC, BAfter , BAfter , Lower , Initial, Initial, Initial, Initial, Initial, LUATerm, Initial, STerm , Initial }, // Lower - { Initial, BAfterC, BAfter , BAfter , Upper , Initial, Initial, Upper , Initial, Initial, LUATerm, STerm , STerm , Initial }, // Upper + { Initial, BAfterC, BAfter , BAfter , Upper , Initial, Initial, Upper , Initial, Initial, LUATerm, Initial, STerm , Initial }, // Upper { Lookup , BAfterC, BAfter , BAfter , LUATerm, ACS , Initial, Upper , Break , Initial, ATerm , STerm , STerm , ATermC }, // LUATerm { Lookup , BAfterC, BAfter , BAfter , ATerm , ACS , Initial, Break , Break , Initial, ATerm , STerm , STerm , ATermC }, // ATerm diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index 01fc63b677..ba65ae7ef2 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -44,6 +44,7 @@ #include <QtCore/qglobal.h> #include <QtCore/qalgorithms.h> #include <QtCore/qcontainertools_impl.h> +#include <QtCore/qhashfunctions.h> #include <algorithm> #include <initializer_list> @@ -60,7 +61,9 @@ template<class T, int Prealloc> class QVarLengthArray { public: - inline explicit QVarLengthArray(int size = 0); + QVarLengthArray() : QVarLengthArray(0) {} + + inline explicit QVarLengthArray(int size); inline QVarLengthArray(const QVarLengthArray<T, Prealloc> &other) : a(Prealloc), s(0), ptr(reinterpret_cast<T *>(array)) @@ -599,6 +602,13 @@ inline bool operator>=(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengt return !(lhs < rhs); } +template <typename T, int Prealloc> +uint qHash(const QVarLengthArray<T, Prealloc> &key, uint seed = 0) + noexcept(noexcept(qHashRange(key.cbegin(), key.cend(), seed))) +{ + return qHashRange(key.cbegin(), key.cend(), seed); +} + QT_END_NAMESPACE #endif // QVARLENGTHARRAY_H diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc index 80769e3769..e5ba47b8ef 100644 --- a/src/corelib/tools/qvarlengtharray.qdoc +++ b/src/corelib/tools/qvarlengtharray.qdoc @@ -903,3 +903,11 @@ \sa indexOf(), lastIndexOf() */ +/*! + template <typename T, int Prealloc> uint qHash(const QVarLengthArray<T, Prealloc> &key, uint seed = 0) + \relates QVarLengthArray + \since 5.14 + + Returns the hash value for \a key, using \a seed to seed the + calculation. +*/ diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 5d68a283bd..65a5174abf 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -80,6 +80,7 @@ public: QVector<T> &operator=(std::initializer_list<T> args); template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true> inline QVector(InputIterator first, InputIterator last); + explicit QVector(QArrayDataPointerRef<T> ref) noexcept : d(ref.ptr) {} bool operator==(const QVector<T> &v) const; inline bool operator!=(const QVector<T> &v) const { return !(*this == v); } diff --git a/src/corelib/tools/qvector.qdoc b/src/corelib/tools/qvector.qdoc index c1b5054f93..8765b7fbd6 100644 --- a/src/corelib/tools/qvector.qdoc +++ b/src/corelib/tools/qvector.qdoc @@ -173,6 +173,24 @@ For a detailed discussion comparing Qt containers with each other and with STL containers, see \l {Understand the Qt Containers}. + \section1 Maximum size and out-of-memory conditions + + The current version of QVector is limited to just under 2 GB (2^31 bytes) + in size. The exact value is architecture-dependent, since it depends on the + overhead required for managing the data block, but is no more than 32 + bytes. The number of elements that can be stored in a QVector is that size + divided by the size of each element. + + In case memory allocation fails, QVector will use the \l Q_CHECK_PTR macro, + which will throw a \c std::bad_alloc exception if the application is being + compiled with exception support. If exceptions are disabled, then running + out of memory is undefined behavior. + + Note that the operating system may impose further limits on applications + holding a lot of allocated memory, especially large, contiguous blocks. + Such considerations, the configuration of such behavior or any mitigation + are outside the scope of the Qt API. + \sa QVectorIterator, QMutableVectorIterator, QList, QLinkedList */ @@ -251,6 +269,11 @@ The value type of \c InputIterator must be convertible to \c T. */ +/*! + \fn template <typename T> QVector<T>::QVector(QArrayDataPointerRef<T> ref) + \internal +*/ + /*! \fn template <typename T> QVector<T>::~QVector() Destroys the vector. |