aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/ftw
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/ftw')
-rw-r--r--src/qml/qml/ftw/ftw.pri4
-rw-r--r--src/qml/qml/ftw/qbitfield_p.h4
-rw-r--r--src/qml/qml/ftw/qdeferredcleanup_p.h74
-rw-r--r--src/qml/qml/ftw/qfieldlist_p.h22
-rw-r--r--src/qml/qml/ftw/qfinitestack_p.h6
-rw-r--r--src/qml/qml/ftw/qflagpointer_p.h14
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp132
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h878
-rw-r--r--src/qml/qml/ftw/qintrusivelist_p.h25
-rw-r--r--src/qml/qml/ftw/qlinkedstringhash_p.h238
-rw-r--r--src/qml/qml/ftw/qpodvector_p.h14
-rw-r--r--src/qml/qml/ftw/qqmlnullablevalue_p.h4
-rw-r--r--src/qml/qml/ftw/qqmlrefcount_p.h43
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp57
-rw-r--r--src/qml/qml/ftw/qqmlthread_p.h4
-rw-r--r--src/qml/qml/ftw/qrecursionwatcher_p.h4
-rw-r--r--src/qml/qml/ftw/qrecyclepool_p.h4
-rw-r--r--src/qml/qml/ftw/qstringhash.cpp168
-rw-r--r--src/qml/qml/ftw/qstringhash_p.h758
19 files changed, 1301 insertions, 1152 deletions
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri
index 87d80d04bc..0bb8cb954e 100644
--- a/src/qml/qml/ftw/ftw.pri
+++ b/src/qml/qml/ftw/ftw.pri
@@ -12,12 +12,14 @@ HEADERS += \
$$PWD/qflagpointer_p.h \
$$PWD/qlazilyallocated_p.h \
$$PWD/qqmlnullablevalue_p.h \
- $$PWD/qdeferredcleanup_p.h \
+ $$PWD/qstringhash_p.h \
+ $$PWD/qlinkedstringhash_p.h
SOURCES += \
$$PWD/qintrusivelist.cpp \
$$PWD/qhashedstring.cpp \
$$PWD/qqmlthread.cpp \
+ $$PWD/qstringhash.cpp
# mirrors logic in $$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri
# clock_gettime() is implemented in librt on these systems
diff --git a/src/qml/qml/ftw/qbitfield_p.h b/src/qml/qml/ftw/qbitfield_p.h
index 8f35842249..92017580d6 100644
--- a/src/qml/qml/ftw/qbitfield_p.h
+++ b/src/qml/qml/ftw/qbitfield_p.h
@@ -77,12 +77,12 @@ private:
};
QBitField::QBitField()
-: bits(0), ownData(0), data(0)
+: bits(0), ownData(nullptr), data(nullptr)
{
}
QBitField::QBitField(const quint32 *bitData, int bitCount)
-: bits((quint32)bitCount), ownData(0), data(bitData)
+: bits((quint32)bitCount), ownData(nullptr), data(bitData)
{
}
diff --git a/src/qml/qml/ftw/qdeferredcleanup_p.h b/src/qml/qml/ftw/qdeferredcleanup_p.h
deleted file mode 100644
index 6b59f04a77..0000000000
--- a/src/qml/qml/ftw/qdeferredcleanup_p.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDEFERREDCLEANUP_P_H
-#define QDEFERREDCLEANUP_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qglobal.h>
-
-#include <functional>
-
-QT_BEGIN_NAMESPACE
-
-struct QDeferredCleanup
-{
- std::function<void()> callback;
- template <typename Callback>
- QDeferredCleanup(Callback &&cb)
- : callback(cb)
- {}
- ~QDeferredCleanup() { callback(); }
- QDeferredCleanup(const QDeferredCleanup &) = delete;
- QDeferredCleanup &operator=(const QDeferredCleanup &) = delete;
-};
-
-QT_END_NAMESPACE
-
-#endif // QDEFERREDCLEANUP_P_H
diff --git a/src/qml/qml/ftw/qfieldlist_p.h b/src/qml/qml/ftw/qfieldlist_p.h
index d83d708b5e..2bf07fb20d 100644
--- a/src/qml/qml/ftw/qfieldlist_p.h
+++ b/src/qml/qml/ftw/qfieldlist_p.h
@@ -141,7 +141,7 @@ N *QForwardFieldList<N, nextMember>::takeFirst()
N *value = *_first;
if (value) {
_first = next(value);
- value->*nextMember = 0;
+ value->*nextMember = nullptr;
}
return value;
}
@@ -149,7 +149,7 @@ N *QForwardFieldList<N, nextMember>::takeFirst()
template<class N, N *N::*nextMember>
void QForwardFieldList<N, nextMember>::prepend(N *v)
{
- Q_ASSERT(v->*nextMember == 0);
+ Q_ASSERT(v->*nextMember == nullptr);
v->*nextMember = *_first;
_first = v;
}
@@ -229,7 +229,7 @@ void QForwardFieldList<N, nextMember>::setFlag2Value(bool v)
template<class N, N *N::*nextMember>
QFieldList<N, nextMember>::QFieldList()
-: _first(0), _last(0), _flag(0), _count(0)
+: _first(nullptr), _last(nullptr), _flag(0), _count(0)
{
}
@@ -246,10 +246,10 @@ N *QFieldList<N, nextMember>::takeFirst()
if (value) {
_first = next(value);
if (_last == value) {
- Q_ASSERT(_first == 0);
- _last = 0;
+ Q_ASSERT(_first == nullptr);
+ _last = nullptr;
}
- value->*nextMember = 0;
+ value->*nextMember = nullptr;
--_count;
}
return value;
@@ -258,7 +258,7 @@ N *QFieldList<N, nextMember>::takeFirst()
template<class N, N *N::*nextMember>
void QFieldList<N, nextMember>::append(N *v)
{
- Q_ASSERT(v->*nextMember == 0);
+ Q_ASSERT(v->*nextMember == nullptr);
if (isEmpty()) {
_first = v;
_last = v;
@@ -272,7 +272,7 @@ void QFieldList<N, nextMember>::append(N *v)
template<class N, N *N::*nextMember>
void QFieldList<N, nextMember>::prepend(N *v)
{
- Q_ASSERT(v->*nextMember == 0);
+ Q_ASSERT(v->*nextMember == nullptr);
if (isEmpty()) {
_first = v;
_last = v;
@@ -375,7 +375,7 @@ void QFieldList<N, nextMember>::copyAndClear(QFieldList<N, nextMember> &o)
_first = o._first;
_last = o._last;
_count = o._count;
- o._first = o._last = 0;
+ o._first = o._last = nullptr;
o._count = 0;
}
@@ -391,8 +391,8 @@ void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMemb
template<class N, N *N::*nextMember>
void QFieldList<N, nextMember>::copyAndClearPrepend(QForwardFieldList<N, nextMember> &o)
{
- _first = 0;
- _last = 0;
+ _first = nullptr;
+ _last = nullptr;
_count = 0;
while (N *n = o.takeFirst()) prepend(n);
}
diff --git a/src/qml/qml/ftw/qfinitestack_p.h b/src/qml/qml/ftw/qfinitestack_p.h
index f1f1a551d5..9a74199137 100644
--- a/src/qml/qml/ftw/qfinitestack_p.h
+++ b/src/qml/qml/ftw/qfinitestack_p.h
@@ -81,7 +81,7 @@ private:
template<typename T>
QFiniteStack<T>::QFiniteStack()
-: _array(0), _alloc(0), _size(0)
+: _array(nullptr), _alloc(0), _size(0)
{
}
@@ -156,7 +156,7 @@ T &QFiniteStack<T>::operator[](int index)
template<typename T>
void QFiniteStack<T>::allocate(int size)
{
- Q_ASSERT(_array == 0);
+ Q_ASSERT(_array == nullptr);
Q_ASSERT(_alloc == 0);
Q_ASSERT(_size == 0);
@@ -177,7 +177,7 @@ void QFiniteStack<T>::deallocate()
free(_array);
- _array = 0;
+ _array = nullptr;
_alloc = 0;
_size = 0;
}
diff --git a/src/qml/qml/ftw/qflagpointer_p.h b/src/qml/qml/ftw/qflagpointer_p.h
index 6954a8f09c..71b41cd30b 100644
--- a/src/qml/qml/ftw/qflagpointer_p.h
+++ b/src/qml/qml/ftw/qflagpointer_p.h
@@ -82,8 +82,10 @@ public:
inline T *data() const;
+ inline explicit operator bool() const;
+
private:
- quintptr ptr_value;
+ quintptr ptr_value = 0;
static const quintptr FlagBit = 0x1;
static const quintptr Flag2Bit = 0x2;
@@ -115,7 +117,7 @@ public:
inline T2 *asT2() const;
private:
- quintptr ptr_value;
+ quintptr ptr_value = 0;
static const quintptr FlagBit = 0x1;
static const quintptr Flag2Bit = 0x2;
@@ -124,7 +126,6 @@ private:
template<typename T>
QFlagPointer<T>::QFlagPointer()
-: ptr_value(0)
{
}
@@ -231,9 +232,14 @@ T *QFlagPointer<T>::data() const
return (T *)(ptr_value & ~FlagsMask);
}
+template<typename T>
+QFlagPointer<T>::operator bool() const
+{
+ return data() != nullptr;
+}
+
template<typename T, typename T2>
QBiPointer<T, T2>::QBiPointer()
-: ptr_value(0)
{
}
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index 117670dbfc..bb6688599d 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -39,136 +39,7 @@
#include "qhashedstring_p.h"
-
-
-/*
- A QHash has initially around pow(2, MinNumBits) buckets. For
- example, if MinNumBits is 4, it has 17 buckets.
-*/
-const int MinNumBits = 4;
-
-/*
- The prime_deltas array is a table of selected prime values, even
- though it doesn't look like one. The primes we are using are 1,
- 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
- surrounding of a power of two.
-
- The primeForNumBits() function returns the prime associated to a
- power of two. For example, primeForNumBits(8) returns 257.
-*/
-
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
-void QStringHashData::rehashToSize(int size)
-{
- short bits = qMax(MinNumBits, (int)numBits);
- while (primeForNumBits(bits) < size) bits++;
-
- if (bits > numBits)
- rehashToBits(bits);
-}
-
-void QStringHashData::rehashToBits(short bits)
-{
- numBits = qMax(MinNumBits, (int)bits);
-
- int nb = primeForNumBits(numBits);
- if (nb == numBuckets && buckets)
- return;
-
-#ifdef QSTRINGHASH_LINK_DEBUG
- if (linkCount)
- qFatal("QStringHash: Illegal attempt to rehash a linked hash.");
-#endif
-
- QStringHashNode **newBuckets = new QStringHashNode *[nb];
- ::memset(newBuckets, 0, sizeof(QStringHashNode *) * nb);
-
- // Preserve the existing order within buckets so that items with the
- // same key will retain the same find/findNext order
- for (int i = 0; i < numBuckets; ++i) {
- QStringHashNode *bucket = buckets[i];
- if (bucket)
- rehashNode(newBuckets, nb, bucket);
- }
-
- delete [] buckets;
- buckets = newBuckets;
- numBuckets = nb;
-}
-
-void QStringHashData::rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node)
-{
- QStringHashNode *next = node->next.data();
- if (next)
- rehashNode(newBuckets, nb, next);
-
- int bucket = node->hash % nb;
- node->next = newBuckets[bucket];
- newBuckets[bucket] = node;
-}
-
-// Copy of QString's qMemCompare
-bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
-{
- Q_ASSERT(lhs && rhs);
- const quint16 *a = (const quint16 *)lhs;
- const quint16 *b = (const quint16 *)rhs;
-
- if (a == b || !length)
- return true;
-
- union {
- const quint16 *w;
- const quint32 *d;
- quintptr value;
- } sa, sb;
- sa.w = a;
- sb.w = b;
-
- // check alignment
- if ((sa.value & 2) == (sb.value & 2)) {
- // both addresses have the same alignment
- if (sa.value & 2) {
- // both addresses are not aligned to 4-bytes boundaries
- // compare the first character
- if (*sa.w != *sb.w)
- return false;
- --length;
- ++sa.w;
- ++sb.w;
-
- // now both addresses are 4-bytes aligned
- }
-
- // both addresses are 4-bytes aligned
- // do a fast 32-bit comparison
- const quint32 *e = sa.d + (length >> 1);
- for ( ; sa.d != e; ++sa.d, ++sb.d) {
- if (*sa.d != *sb.d)
- return false;
- }
-
- // do we have a tail?
- return (length & 1) ? *sa.w == *sb.w : true;
- } else {
- // one of the addresses isn't 4-byte aligned but the other is
- const quint16 *e = sa.w + length;
- for ( ; sa.w != e; ++sa.w, ++sb.w) {
- if (*sa.w != *sb.w)
- return false;
- }
- }
- return true;
-}
+QT_BEGIN_NAMESPACE
QHashedStringRef QHashedStringRef::mid(int offset, int length) const
{
@@ -228,3 +99,4 @@ QString QHashedCStringRef::toUtf16() const
return rv;
}
+QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
index 9ee50ec931..b9f3f81219 100644
--- a/src/qml/qml/ftw/qhashedstring_p.h
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -63,9 +63,6 @@
QT_BEGIN_NAMESPACE
-// Enable this to debug hash linking assumptions.
-// #define QSTRINGHASH_LINK_DEBUG
-
class QHashedStringRef;
class Q_QML_PRIVATE_EXPORT QHashedString : public QString
{
@@ -94,7 +91,7 @@ private:
friend class QStringHashNode;
inline void computeHash() const;
- mutable quint32 m_hash;
+ mutable quint32 m_hash = 0;
};
class QHashedCStringRef;
@@ -142,9 +139,9 @@ private:
inline void computeHash() const;
- const QChar *m_data;
- int m_length;
- mutable quint32 m_hash;
+ const QChar *m_data = nullptr;
+ int m_length = 0;
+ mutable quint32 m_hash = 0;
};
class Q_AUTOTEST_EXPORT QHashedCStringRef
@@ -169,864 +166,11 @@ private:
inline void computeHash() const;
- const char *m_data;
- int m_length;
- mutable quint32 m_hash;
-};
-
-class QStringHashData;
-class Q_AUTOTEST_EXPORT QStringHashNode
-{
-public:
- QStringHashNode()
- : length(0), hash(0), symbolId(0), ckey(0)
- {
- }
-
- QStringHashNode(const QHashedString &key)
- : length(key.length()), hash(key.hash()), symbolId(0)
- {
- strData = const_cast<QHashedString &>(key).data_ptr();
- setQString(true);
- strData->ref.ref();
- }
-
- QStringHashNode(const QHashedCStringRef &key)
- : length(key.length()), hash(key.hash()), symbolId(0), ckey(key.constData())
- {
- }
-
- QStringHashNode(const QStringHashNode &o)
- : length(o.length), hash(o.hash), symbolId(o.symbolId), ckey(o.ckey)
- {
- setQString(o.isQString());
- if (isQString()) { strData->ref.ref(); }
- }
-
- ~QStringHashNode()
- {
- if (isQString()) { if (!strData->ref.deref()) free(strData); }
- }
-
- QFlagPointer<QStringHashNode> next;
-
- qint32 length;
- quint32 hash;
- quint32 symbolId;
-
- union {
- const char *ckey;
- QStringData *strData;
- };
-
- inline QHashedString key() const
- {
- if (isQString())
- return QHashedString(QString((QChar *)strData->data(), length), hash);
-
- return QHashedString(QString::fromLatin1(ckey, length), hash);
- }
-
- bool isQString() const { return next.flag(); }
- void setQString(bool v) { if (v) next.setFlag(); else next.clearFlag(); }
-
- inline char *cStrData() const { return (char *)ckey; }
- inline quint16 *utf16Data() const { return (quint16 *)strData->data(); }
-
- inline bool equals(const QV4::Value &string) const {
- QString s = string.toQStringNoThrow();
- if (isQString()) {
- QStringDataPtr dd;
- dd.ptr = strData;
- strData->ref.ref();
- return QString(dd) == s;
- } else {
- return QLatin1String(cStrData(), length) == s;
- }
- }
-
- inline bool equals(const QV4::String *string) const {
- if (length != string->d()->length() || hash != string->hashValue())
- return false;
- if (isQString()) {
- QStringDataPtr dd;
- dd.ptr = strData;
- strData->ref.ref();
- return QString(dd) == string->toQString();
- } else {
- return QLatin1String(cStrData(), length) == string->toQString();
- }
- }
-
- inline bool equals(const QHashedStringRef &string) const {
- return length == string.length() &&
- hash == string.hash() &&
- (isQString()?QHashedString::compare(string.constData(), (const QChar *)utf16Data(), length):
- QHashedString::compare(string.constData(), cStrData(), length));
- }
-
- inline bool equals(const QHashedCStringRef &string) const {
- return length == string.length() &&
- hash == string.hash() &&
- (isQString()?QHashedString::compare((const QChar *)utf16Data(), string.constData(), length):
- QHashedString::compare(string.constData(), cStrData(), length));
- }
-};
-
-class Q_AUTOTEST_EXPORT QStringHashData
-{
-public:
- QStringHashData()
- : buckets(0), numBuckets(0), size(0), numBits(0)
-#ifdef QSTRINGHASH_LINK_DEBUG
- , linkCount(0)
-#endif
- {}
-
- QStringHashNode **buckets;
- int numBuckets;
- int size;
- short numBits;
-#ifdef QSTRINGHASH_LINK_DEBUG
- int linkCount;
-#endif
-
- struct IteratorData {
- IteratorData() : n(0), p(0) {}
- QStringHashNode *n;
- void *p;
- };
- void rehashToBits(short);
- void rehashToSize(int);
- void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node);
-
-private:
- QStringHashData(const QStringHashData &);
- QStringHashData &operator=(const QStringHashData &);
-};
-
-// For a supplied key type, in what form do we need to keep a hashed version?
-template<typename T>
-struct HashedForm {};
-
-template<> struct HashedForm<QString> { typedef QHashedString Type; };
-template<> struct HashedForm<QStringRef> { typedef QHashedStringRef Type; };
-template<> struct HashedForm<QHashedString> { typedef const QHashedString &Type; };
-template<> struct HashedForm<QV4::String *> { typedef const QV4::String *Type; };
-template<> struct HashedForm<const QV4::String *> { typedef const QV4::String *Type; };
-template<> struct HashedForm<QHashedStringRef> { typedef const QHashedStringRef &Type; };
-template<> struct HashedForm<QLatin1String> { typedef QHashedCStringRef Type; };
-template<> struct HashedForm<QHashedCStringRef> { typedef const QHashedCStringRef &Type; };
-
-class QStringHashBase
-{
-public:
- static HashedForm<QString>::Type hashedString(const QString &s) { return QHashedString(s);}
- static HashedForm<QStringRef>::Type hashedString(const QStringRef &s) { return QHashedStringRef(s.constData(), s.size());}
- static HashedForm<QHashedString>::Type hashedString(const QHashedString &s) { return s; }
- static HashedForm<QV4::String *>::Type hashedString(QV4::String *s) { return s; }
- static HashedForm<const QV4::String *>::Type hashedString(const QV4::String *s) { return s; }
- static HashedForm<QHashedStringRef>::Type hashedString(const QHashedStringRef &s) { return s; }
-
- static HashedForm<QLatin1String>::Type hashedString(const QLatin1String &s) { return QHashedCStringRef(s.data(), s.size()); }
- static HashedForm<QHashedCStringRef>::Type hashedString(const QHashedCStringRef &s) { return s; }
-
- static const QString &toQString(const QString &s) { return s; }
- static const QString &toQString(const QHashedString &s) { return s; }
- static QString toQString(const QV4::String *s) { return s->toQString(); }
- static QString toQString(const QHashedStringRef &s) { return s.toString(); }
-
- static QString toQString(const QLatin1String &s) { return QString(s); }
- static QString toQString(const QHashedCStringRef &s) { return s.toUtf16(); }
-
- static inline quint32 hashOf(const QHashedStringRef &s) { return s.hash(); }
- static inline quint32 hashOf(QV4::String *s) { return s->hashValue(); }
- static inline quint32 hashOf(const QV4::String *s) { return s->hashValue(); }
-
- template<typename K>
- static inline quint32 hashOf(const K &key) { return hashedString(key).hash(); }
-};
-
-template<class T>
-class QStringHash : public QStringHashBase
-{
-public:
- typedef QHashedString key_type;
- typedef T mapped_type;
-
- struct Node : public QStringHashNode {
- Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {}
- Node(const QHashedCStringRef &key, const T &value) : QStringHashNode(key), value(value) {}
- Node(const Node &o) : QStringHashNode(o), value(o.value) {}
- Node() {}
- T value;
- };
- struct NewedNode : public Node {
- NewedNode(const QHashedString &key, const T &value) : Node(key, value), nextNewed(0) {}
- NewedNode(const QHashedCStringRef &key, const T &value) : Node(key, value), nextNewed(0) {}
- NewedNode(const Node &o) : Node(o), nextNewed(0) {}
- NewedNode *nextNewed;
- };
- struct ReservedNodePool
- {
- ReservedNodePool() : count(0), used(0), nodes(0) {}
- ~ReservedNodePool() { delete [] nodes; }
- int count;
- int used;
- Node *nodes;
- };
-
- QStringHashData data;
- NewedNode *newedNodes;
- ReservedNodePool *nodePool;
- const QStringHash<T> *link;
-
- template<typename K>
- inline Node *findNode(const K &) const;
-
- inline Node *createNode(const Node &o);
-
- template<typename K>
- inline Node *createNode(const K &, const T &);
-
- inline Node *insertNode(Node *, quint32);
-
- inline void initializeNode(Node *, const QHashedString &key);
- inline void initializeNode(Node *, const QHashedCStringRef &key);
-
- template<typename K>
- inline Node *takeNode(const K &key, const T &value);
-
- inline Node *takeNode(const Node &o);
-
- inline void copy(const QStringHash<T> &);
-
- void copyNode(const QStringHashNode *otherNode);
-
- inline QStringHashData::IteratorData iterateFirst() const;
- static inline QStringHashData::IteratorData iterateNext(const QStringHashData::IteratorData &);
-
-public:
- inline QStringHash();
- inline QStringHash(const QStringHash &);
- inline ~QStringHash();
-
- QStringHash &operator=(const QStringHash<T> &);
-
- void copyAndReserve(const QStringHash<T> &other, int additionalReserve);
- void linkAndReserve(const QStringHash<T> &other, int additionalReserve);
-
- inline bool isEmpty() const;
- inline void clear();
- inline int count() const;
-
- inline int numBuckets() const;
- inline bool isLinked() const;
-
- class ConstIterator {
- public:
- inline ConstIterator();
- inline ConstIterator(const QStringHashData::IteratorData &);
-
- inline ConstIterator &operator++();
-
- inline bool operator==(const ConstIterator &o) const;
- inline bool operator!=(const ConstIterator &o) const;
-
- template<typename K>
- inline bool equals(const K &) const;
-
- inline QHashedString key() const;
- inline const T &value() const;
- inline const T &operator*() const;
-
- inline Node *node() const;
- private:
- QStringHashData::IteratorData d;
- };
-
- template<typename K>
- inline void insert(const K &, const T &);
-
- inline void insert(const ConstIterator &);
-
- template<typename K>
- inline T *value(const K &) const;
-
- inline T *value(const QV4::String *string) const;
- inline T *value(const ConstIterator &) const;
-
- template<typename K>
- inline bool contains(const K &) const;
-
- template<typename K>
- inline T &operator[](const K &);
-
- inline ConstIterator begin() const;
- inline ConstIterator end() const;
-
- inline ConstIterator iterator(Node *n) const;
-
- template<typename K>
- inline ConstIterator find(const K &) const;
-
- inline void reserve(int);
-};
-
-template<class T>
-QStringHash<T>::QStringHash()
-: newedNodes(0), nodePool(0), link(0)
-{
-}
-
-template<class T>
-QStringHash<T>::QStringHash(const QStringHash<T> &other)
-: newedNodes(0), nodePool(0), link(0)
-{
- data.numBits = other.data.numBits;
- data.size = other.data.size;
- reserve(other.count());
- copy(other);
-}
-
-template<class T>
-QStringHash<T> &QStringHash<T>::operator=(const QStringHash<T> &other)
-{
- if (&other == this)
- return *this;
-
- clear();
-
- data.numBits = other.data.numBits;
- data.size = other.data.size;
- reserve(other.count());
- copy(other);
-
- return *this;
-}
-
-template<class T>
-void QStringHash<T>::copyAndReserve(const QStringHash<T> &other, int additionalReserve)
-{
- clear();
- data.numBits = other.data.numBits;
- reserve(other.count() + additionalReserve);
- copy(other);
-}
-
-template<class T>
-void QStringHash<T>::linkAndReserve(const QStringHash<T> &other, int additionalReserve)
-{
- clear();
-
- if (other.count()) {
- data.size = other.data.size;
- data.rehashToSize(other.count() + additionalReserve);
-
- if (data.numBuckets == other.data.numBuckets) {
- nodePool = new ReservedNodePool;
- nodePool->count = additionalReserve;
- nodePool->used = 0;
- nodePool->nodes = new Node[additionalReserve];
-
-#ifdef QSTRINGHASH_LINK_DEBUG
- data.linkCount++;
- const_cast<QStringHash<T>&>(other).data.linkCount++;
-#endif
-
- for (int ii = 0; ii < data.numBuckets; ++ii)
- data.buckets[ii] = (Node *)other.data.buckets[ii];
-
- link = &other;
- return;
- }
-
- data.size = 0;
- }
-
- data.numBits = other.data.numBits;
- reserve(other.count() + additionalReserve);
- copy(other);
-}
-
-template<class T>
-QStringHash<T>::~QStringHash()
-{
- clear();
-}
-
-template<class T>
-void QStringHash<T>::clear()
-{
-#ifdef QSTRINGHASH_LINK_DEBUG
- if (link) {
- data.linkCount--;
- const_cast<QStringHash<T> *>(link)->data.linkCount--;
- }
-
- if (data.linkCount)
- qFatal("QStringHash: Illegal attempt to clear a linked hash.");
-#endif
-
- // Delete the individually allocated nodes
- NewedNode *n = newedNodes;
- while (n) {
- NewedNode *c = n;
- n = c->nextNewed;
- delete c;
- }
- // Delete the pool allocated nodes
- if (nodePool) delete nodePool;
- delete [] data.buckets;
-
- data.buckets = 0;
- data.numBuckets = 0;
- data.numBits = 0;
- data.size = 0;
-
- newedNodes = 0;
- nodePool = 0;
- link = 0;
-}
-
-template<class T>
-bool QStringHash<T>::isEmpty() const
-{
- return data.size== 0;
-}
-
-template<class T>
-int QStringHash<T>::count() const
-{
- return data.size;
-}
-
-template<class T>
-int QStringHash<T>::numBuckets() const
-{
- return data.numBuckets;
-}
-
-template<class T>
-bool QStringHash<T>::isLinked() const
-{
- return link != 0;
-}
-
-template<class T>
-void QStringHash<T>::initializeNode(Node *node, const QHashedString &key)
-{
- node->length = key.length();
- node->hash = key.hash();
- node->strData = const_cast<QHashedString &>(key).data_ptr();
- node->strData->ref.ref();
- node->setQString(true);
-}
-
-template<class T>
-void QStringHash<T>::initializeNode(Node *node, const QHashedCStringRef &key)
-{
- node->length = key.length();
- node->hash = key.hash();
- node->ckey = key.constData();
-}
-
-template<class T>
-template<class K>
-typename QStringHash<T>::Node *QStringHash<T>::takeNode(const K &key, const T &value)
-{
- if (nodePool && nodePool->used != nodePool->count) {
- Node *rv = nodePool->nodes + nodePool->used++;
- initializeNode(rv, hashedString(key));
- rv->value = value;
- return rv;
- } else {
- NewedNode *rv = new NewedNode(hashedString(key), value);
- rv->nextNewed = newedNodes;
- newedNodes = rv;
- return rv;
- }
-}
-
-template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::takeNode(const Node &o)
-{
- if (nodePool && nodePool->used != nodePool->count) {
- Node *rv = nodePool->nodes + nodePool->used++;
- rv->length = o.length;
- rv->hash = o.hash;
- if (o.isQString()) {
- rv->strData = o.strData;
- rv->strData->ref.ref();
- rv->setQString(true);
- } else {
- rv->ckey = o.ckey;
- }
- rv->symbolId = o.symbolId;
- rv->value = o.value;
- return rv;
- } else {
- NewedNode *rv = new NewedNode(o);
- rv->nextNewed = newedNodes;
- newedNodes = rv;
- return rv;
- }
-}
-
-template<class T>
-void QStringHash<T>::copyNode(const QStringHashNode *otherNode)
-{
- // Copy the predecessor before the successor
- QStringHashNode *next = otherNode->next.data();
- if (next)
- copyNode(next);
-
- Node *mynode = takeNode(*(const Node *)otherNode);
- int bucket = mynode->hash % data.numBuckets;
- mynode->next = data.buckets[bucket];
- data.buckets[bucket] = mynode;
-}
-
-template<class T>
-void QStringHash<T>::copy(const QStringHash<T> &other)
-{
- Q_ASSERT(data.size == 0);
-
- data.size = other.data.size;
-
- // Ensure buckets array is created
- data.rehashToBits(data.numBits);
-
- // Preserve the existing order within buckets
- for (int i = 0; i < other.data.numBuckets; ++i) {
- QStringHashNode *bucket = other.data.buckets[i];
- if (bucket)
- copyNode(bucket);
- }
-}
-
-template<class T>
-QStringHashData::IteratorData
-QStringHash<T>::iterateNext(const QStringHashData::IteratorData &d)
-{
- QStringHash<T> *This = (QStringHash<T> *)d.p;
- Node *node = (Node *)d.n;
-
- if (This->nodePool && node >= This->nodePool->nodes &&
- node < (This->nodePool->nodes + This->nodePool->used)) {
- node--;
- if (node < This->nodePool->nodes)
- node = 0;
- } else {
- NewedNode *nn = (NewedNode *)node;
- node = nn->nextNewed;
-
- if (node == 0 && This->nodePool && This->nodePool->used)
- node = This->nodePool->nodes + This->nodePool->used - 1;
- }
-
- if (node == 0 && This->link)
- return This->link->iterateFirst();
-
- QStringHashData::IteratorData rv;
- rv.n = node;
- rv.p = d.p;
- return rv;
-}
-
-template<class T>
-QStringHashData::IteratorData QStringHash<T>::iterateFirst() const
-{
- Node *n = 0;
- if (newedNodes)
- n = newedNodes;
- else if (nodePool && nodePool->used)
- n = nodePool->nodes + nodePool->used - 1;
-
- if (n == 0 && link)
- return link->iterateFirst();
-
- QStringHashData::IteratorData rv;
- rv.n = n;
- rv.p = const_cast<QStringHash<T> *>(this);
- return rv;
-}
-
-template<class T>
-typename QStringHash<T>::ConstIterator QStringHash<T>::iterator(Node *n) const
-{
- if (!n)
- return ConstIterator();
-
- const QStringHash<T> *container = this;
-
- if (link) {
- // This node could be in the linked hash
- if ((n >= nodePool->nodes) && (n < (nodePool->nodes + nodePool->used))) {
- // The node is in this hash
- } else if ((n >= link->nodePool->nodes) && (n < (link->nodePool->nodes + link->nodePool->used))) {
- // The node is in the linked hash
- container = link;
- } else {
- const NewedNode *ln = link->newedNodes;
- while (ln) {
- if (ln == n) {
- // This node is in the linked hash's newed list
- container = link;
- break;
- }
- ln = ln->nextNewed;
- }
- }
- }
-
- QStringHashData::IteratorData rv;
- rv.n = n;
- rv.p = const_cast<QStringHash<T> *>(container);
- return ConstIterator(rv);
-}
-
-template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::createNode(const Node &o)
-{
- Node *n = takeNode(o);
- return insertNode(n, n->hash);
-}
-
-template<class T>
-template<class K>
-typename QStringHash<T>::Node *QStringHash<T>::createNode(const K &key, const T &value)
-{
- Node *n = takeNode(key, value);
- return insertNode(n, hashOf(key));
-}
-
-template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::insertNode(Node *n, quint32 hash)
-{
- if (data.size >= data.numBuckets)
- data.rehashToBits(data.numBits + 1);
-
- int bucket = hash % data.numBuckets;
- n->next = data.buckets[bucket];
- data.buckets[bucket] = n;
-
- data.size++;
-
- return n;
-}
-
-template<class T>
-template<class K>
-void QStringHash<T>::insert(const K &key, const T &value)
-{
- // If this is a linked hash, we can't rely on owning the node, so we always
- // create a new one.
- Node *n = link?0:findNode(key);
- if (n) n->value = value;
- else createNode(key, value);
-}
-
-template<class T>
-void QStringHash<T>::insert(const ConstIterator &iter)
-{
- insert(iter.key(), iter.value());
-}
-
-template<class T>
-template<class K>
-typename QStringHash<T>::Node *QStringHash<T>::findNode(const K &key) const
-{
- QStringHashNode *node = data.numBuckets?data.buckets[hashOf(key) % data.numBuckets]:0;
-
- typename HashedForm<K>::Type hashedKey(hashedString(key));
- while (node && !node->equals(hashedKey))
- node = (*node->next);
-
- return (Node *)node;
-}
-
-template<class T>
-template<class K>
-T *QStringHash<T>::value(const K &key) const
-{
- Node *n = findNode(key);
- return n?&n->value:0;
-}
-
-template<class T>
-T *QStringHash<T>::value(const ConstIterator &iter) const
-{
- Node *n = iter.node();
- return value(n->key());
-}
-
-template<class T>
-T *QStringHash<T>::value(const QV4::String *string) const
-{
- Node *n = findNode(string);
- return n?&n->value:0;
-}
-
-template<class T>
-template<class K>
-bool QStringHash<T>::contains(const K &key) const
-{
- return 0 != value(key);
-}
-
-template<class T>
-template<class K>
-T &QStringHash<T>::operator[](const K &key)
-{
- Node *n = findNode(key);
- if (n) return n->value;
- else return createNode(key, T())->value;
-}
-
-template<class T>
-void QStringHash<T>::reserve(int n)
-{
- if (nodePool || 0 == n)
- return;
-
- nodePool = new ReservedNodePool;
- nodePool->count = n;
- nodePool->used = 0;
- nodePool->nodes = new Node[n];
-
- data.rehashToSize(n);
-}
-
-template<class T>
-QStringHash<T>::ConstIterator::ConstIterator()
-{
-}
-
-template<class T>
-QStringHash<T>::ConstIterator::ConstIterator(const QStringHashData::IteratorData &d)
-: d(d)
-{
-}
-
-template<class T>
-typename QStringHash<T>::ConstIterator &QStringHash<T>::ConstIterator::operator++()
-{
- d = QStringHash<T>::iterateNext(d);
- return *this;
-}
-
-template<class T>
-bool QStringHash<T>::ConstIterator::operator==(const ConstIterator &o) const
-{
- return d.n == o.d.n;
-}
-
-template<class T>
-bool QStringHash<T>::ConstIterator::operator!=(const ConstIterator &o) const
-{
- return d.n != o.d.n;
-}
-
-template<class T>
-template<typename K>
-bool QStringHash<T>::ConstIterator::equals(const K &key) const
-{
- return d.n->equals(key);
-}
-
-template<class T>
-QHashedString QStringHash<T>::ConstIterator::key() const
-{
- Node *n = (Node *)d.n;
- return n->key();
-}
-template<class T>
-const T &QStringHash<T>::ConstIterator::value() const
-{
- Node *n = (Node *)d.n;
- return n->value;
-}
-
-template<class T>
-const T &QStringHash<T>::ConstIterator::operator*() const
-{
- Node *n = (Node *)d.n;
- return n->value;
-}
-
-template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::ConstIterator::node() const
-{
- Node *n = (Node *)d.n;
- return n;
-}
-
-template<class T>
-typename QStringHash<T>::ConstIterator QStringHash<T>::begin() const
-{
- return ConstIterator(iterateFirst());
-}
-
-template<class T>
-typename QStringHash<T>::ConstIterator QStringHash<T>::end() const
-{
- return ConstIterator();
-}
-
-template<class T>
-template<class K>
-typename QStringHash<T>::ConstIterator QStringHash<T>::find(const K &key) const
-{
- return iterator(findNode(key));
-}
-
-template<class T>
-class QStringMultiHash : public QStringHash<T>
-{
-public:
- typedef typename QStringHash<T>::ConstIterator ConstIterator;
-
- template<typename K>
- inline void insert(const K &, const T &);
-
- inline void insert(const ConstIterator &);
-
- inline ConstIterator findNext(const ConstIterator &) const;
+ const char *m_data = nullptr;
+ int m_length = 0;
+ mutable quint32 m_hash = 0;
};
-template<class T>
-template<class K>
-void QStringMultiHash<T>::insert(const K &key, const T &value)
-{
- // Always create a new node
- QStringHash<T>::createNode(key, value);
-}
-
-template<class T>
-void QStringMultiHash<T>::insert(const ConstIterator &iter)
-{
- // Always create a new node
- QStringHash<T>::createNode(iter.key(), iter.value());
-}
-
-template<class T>
-typename QStringHash<T>::ConstIterator QStringMultiHash<T>::findNext(const ConstIterator &iter) const
-{
- QStringHashNode *node = iter.node();
- if (node) {
- QHashedString key(node->key());
-
- while ((node = *node->next)) {
- if (node->equals(key)) {
- return QStringHash<T>::iterator(static_cast<typename QStringHash<T>::Node *>(node));
- }
- }
- }
-
- return ConstIterator();
-}
-
inline uint qHash(const QHashedString &string)
{
return uint(string.hash());
@@ -1038,7 +182,7 @@ inline uint qHash(const QHashedStringRef &string)
}
QHashedString::QHashedString()
-: QString(), m_hash(0)
+: QString()
{
}
@@ -1089,7 +233,6 @@ quint32 QHashedString::existingHash() const
}
QHashedStringRef::QHashedStringRef()
-: m_data(0), m_length(0), m_hash(0)
{
}
@@ -1236,7 +379,6 @@ quint32 QHashedStringRef::hash() const
}
QHashedCStringRef::QHashedCStringRef()
-: m_data(0), m_length(0), m_hash(0)
{
}
@@ -1311,12 +453,12 @@ bool QHashedString::compare(const char *lhs, const char *rhs, int length)
quint32 QHashedString::stringHash(const QChar *data, int length)
{
- return QV4::String::createHashValue(data, length, Q_NULLPTR);
+ return QV4::String::createHashValue(data, length, nullptr);
}
quint32 QHashedString::stringHash(const char *data, int length)
{
- return QV4::String::createHashValue(data, length, Q_NULLPTR);
+ return QV4::String::createHashValue(data, length, nullptr);
}
void QHashedString::computeHash() const
diff --git a/src/qml/qml/ftw/qintrusivelist_p.h b/src/qml/qml/ftw/qintrusivelist_p.h
index 3d749e697e..8992be9f93 100644
--- a/src/qml/qml/ftw/qintrusivelist_p.h
+++ b/src/qml/qml/ftw/qintrusivelist_p.h
@@ -95,7 +95,7 @@ public:
private:
static inline N *nodeToN(QIntrusiveListNode *node);
- QIntrusiveListNode *__first;
+ QIntrusiveListNode *__first = nullptr;
};
class QIntrusiveListNode
@@ -107,13 +107,13 @@ public:
inline void remove();
inline bool isInList() const;
- QIntrusiveListNode *_next;
- QIntrusiveListNode**_prev;
+ QIntrusiveListNode *_next = nullptr;
+ QIntrusiveListNode**_prev = nullptr;
};
template<class N, QIntrusiveListNode N::*member>
QIntrusiveList<N, member>::iterator::iterator()
-: _value(0)
+: _value(nullptr)
{
}
@@ -165,7 +165,7 @@ typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterato
template<class N, QIntrusiveListNode N::*member>
QIntrusiveList<N, member>::QIntrusiveList()
-: __first(0)
+
{
}
@@ -178,7 +178,7 @@ QIntrusiveList<N, member>::~QIntrusiveList()
template<class N, QIntrusiveListNode N::*member>
bool QIntrusiveList<N, member>::isEmpty() const
{
- return __first == 0;
+ return __first == nullptr;
}
template<class N, QIntrusiveListNode N::*member>
@@ -215,14 +215,14 @@ bool QIntrusiveList<N, member>::contains(N *n) const
template<class N, QIntrusiveListNode N::*member>
N *QIntrusiveList<N, member>::first() const
{
- return __first?nodeToN(__first):0;
+ return __first?nodeToN(__first):nullptr;
}
template<class N, QIntrusiveListNode N::*member>
N *QIntrusiveList<N, member>::next(N *current)
{
QIntrusiveListNode *nextnode = (current->*member)._next;
- N *nextstruct = nextnode?nodeToN(nextnode):0;
+ N *nextstruct = nextnode?nodeToN(nextnode):nullptr;
return nextstruct;
}
@@ -241,11 +241,10 @@ typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::end()
template<class N, QIntrusiveListNode N::*member>
N *QIntrusiveList<N, member>::nodeToN(QIntrusiveListNode *node)
{
- return (N *)((char *)node - ((char *)&(((N *)0)->*member) - (char *)0));
+ return (N *)((char *)node - ((char *)&(((N *)nullptr)->*member) - (char *)nullptr));
}
QIntrusiveListNode::QIntrusiveListNode()
-: _next(0), _prev(0)
{
}
@@ -258,13 +257,13 @@ void QIntrusiveListNode::remove()
{
if (_prev) *_prev = _next;
if (_next) _next->_prev = _prev;
- _prev = 0;
- _next = 0;
+ _prev = nullptr;
+ _next = nullptr;
}
bool QIntrusiveListNode::isInList() const
{
- return _prev != 0;
+ return _prev != nullptr;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qlinkedstringhash_p.h b/src/qml/qml/ftw/qlinkedstringhash_p.h
new file mode 100644
index 0000000000..67ced7fbbf
--- /dev/null
+++ b/src/qml/qml/ftw/qlinkedstringhash_p.h
@@ -0,0 +1,238 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLINKEDSTRINGHASH_P_H
+#define QLINKEDSTRINGHASH_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qstringhash_p.h>
+
+QT_BEGIN_NAMESPACE
+
+template<class T>
+class QLinkedStringHash : private QStringHash<T>
+{
+public:
+ using typename QStringHash<T>::Node;
+ using typename QStringHash<T>::NewedNode;
+ using typename QStringHash<T>::ReservedNodePool;
+ using typename QStringHash<T>::mapped_type;
+
+ using ConstIteratorData = QStringHashData::IteratorData<const QLinkedStringHash>;
+ using ConstIterator = typename QStringHash<T>::template Iterator<ConstIteratorData, const T>;
+
+ void linkAndReserve(const QLinkedStringHash<T> &other, int additionalReserve)
+ {
+ clear();
+
+ if (other.count()) {
+ data.size = other.data.size;
+ data.rehashToSize(other.count() + additionalReserve);
+
+ if (data.numBuckets == other.data.numBuckets) {
+ nodePool = new ReservedNodePool;
+ nodePool->count = additionalReserve;
+ nodePool->used = 0;
+ nodePool->nodes = new Node[additionalReserve];
+
+ for (int ii = 0; ii < data.numBuckets; ++ii)
+ data.buckets[ii] = (Node *)other.data.buckets[ii];
+
+ link = &other;
+ return;
+ }
+
+ data.size = 0;
+ }
+
+ data.numBits = other.data.numBits;
+ reserve(other.count() + additionalReserve);
+ copy(other);
+ }
+
+ inline bool isLinked() const
+ {
+ return link != 0;
+ }
+
+ void clear()
+ {
+ QStringHash<T>::clear();
+ link = nullptr;
+ }
+
+ template<typename K>
+ void insert(const K &key, const T &value)
+ {
+ // If this is a linked hash, we can't rely on owning the node, so we always
+ // create a new one.
+ Node *n = link ? nullptr : QStringHash<T>::findNode(key);
+ if (n)
+ n->value = value;
+ else
+ QStringHash<T>::createNode(key, value);
+ }
+
+ template<typename K>
+ inline ConstIterator find(const K &key) const
+ {
+ return iterator(QStringHash<T>::findNode(key));
+ }
+
+ ConstIterator begin() const
+ {
+ return ConstIterator(
+ QStringHash<T>::template iterateFirst<const QLinkedStringHash<T>,
+ ConstIteratorData>(this));
+ }
+
+ ConstIterator end() const { return ConstIterator(); }
+
+ inline T *value(const ConstIterator &iter) { return value(iter.node()->key()); }
+
+ using QStringHash<T>::value;
+ using QStringHash<T>::reserve;
+ using QStringHash<T>::copy;
+
+protected:
+ friend QStringHash<T>;
+ using QStringHash<T>::data;
+ using QStringHash<T>::nodePool;
+
+ using QStringHash<T>::createNode;
+
+ inline ConstIteratorData iterateFirst() const
+ {
+ const ConstIteratorData rv
+ = QStringHash<T>::template iterateFirst<const QLinkedStringHash<T>,
+ ConstIteratorData>(this);
+ return (rv.n == nullptr && link) ? link->iterateFirst() : rv;
+ }
+
+ static inline ConstIteratorData iterateNext(const ConstIteratorData &d)
+ {
+ const QLinkedStringHash<T> *self = d.p;
+ const ConstIteratorData rv = QStringHash<T>::iterateNext(d);
+ return (rv.n == nullptr && self->link) ? self->link->iterateFirst() : rv;
+ }
+
+ inline ConstIterator iterator(Node *n) const
+ {
+ if (!n)
+ return ConstIterator();
+
+ const QLinkedStringHash<T> *container = this;
+
+ if (link) {
+ // This node could be in the linked hash
+ if ((n >= nodePool->nodes) && (n < (nodePool->nodes + nodePool->used))) {
+ // The node is in this hash
+ } else if ((n >= link->nodePool->nodes)
+ && (n < (link->nodePool->nodes + link->nodePool->used))) {
+ // The node is in the linked hash
+ container = link;
+ } else {
+ const NewedNode *ln = link->newedNodes;
+ while (ln) {
+ if (ln == n) {
+ // This node is in the linked hash's newed list
+ container = link;
+ break;
+ }
+ ln = ln->nextNewed;
+ }
+ }
+ }
+
+
+ ConstIteratorData rv;
+ rv.n = n;
+ rv.p = container;
+ return ConstIterator(rv);
+ }
+
+ const QLinkedStringHash<T> *link = nullptr;
+};
+
+template<class T>
+class QLinkedStringMultiHash : public QLinkedStringHash<T>
+{
+public:
+ using ConstIterator = typename QLinkedStringHash<T>::ConstIterator;
+
+ template<typename K>
+ inline void insert(const K &key, const T &value)
+ {
+ // Always create a new node
+ QLinkedStringHash<T>::createNode(key, value);
+ }
+
+ inline void insert(const ConstIterator &iter)
+ {
+ // Always create a new node
+ QLinkedStringHash<T>::createNode(iter.key(), iter.value());
+ }
+
+ inline ConstIterator findNext(const ConstIterator &iter) const
+ {
+ if (auto *node = iter.node()) {
+ QHashedString key(node->key());
+ while ((node = static_cast<typename QLinkedStringHash<T>::Node *>(*node->next))) {
+ if (node->equals(key))
+ return QLinkedStringHash<T>::iterator(node);
+ }
+ }
+
+ return ConstIterator();
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QLINKEDSTRINGHASH_P_H
diff --git a/src/qml/qml/ftw/qpodvector_p.h b/src/qml/qml/ftw/qpodvector_p.h
index cafe3367de..b2fb481793 100644
--- a/src/qml/qml/ftw/qpodvector_p.h
+++ b/src/qml/qml/ftw/qpodvector_p.h
@@ -61,7 +61,7 @@ class QPODVector
{
public:
QPODVector()
- : m_count(0), m_capacity(0), m_data(0) {}
+ : m_count(0), m_capacity(0), m_data(nullptr) {}
~QPODVector() { if (m_data) ::free(m_data); }
const T &at(int idx) const {
@@ -87,11 +87,11 @@ public:
void insert(int idx, const T &v) {
if (m_count == m_capacity) {
m_capacity += Increment;
- m_data = (T *)realloc(m_data, m_capacity * sizeof(T));
+ m_data = (T *)realloc(static_cast<void *>(m_data), m_capacity * sizeof(T));
}
int moveCount = m_count - idx;
if (moveCount)
- ::memmove(m_data + idx + 1, m_data + idx, moveCount * sizeof(T));
+ ::memmove(static_cast<void *>(m_data + idx + 1), static_cast<const void *>(m_data + idx), moveCount * sizeof(T));
m_count++;
m_data[idx] = v;
}
@@ -99,7 +99,7 @@ public:
void reserve(int count) {
if (count >= m_capacity) {
m_capacity = (count + (Increment-1)) & (0xFFFFFFFF - Increment + 1);
- m_data = (T *)realloc(m_data, m_capacity * sizeof(T));
+ m_data = (T *)realloc(static_cast<void *>(m_data), m_capacity * sizeof(T));
}
}
@@ -108,7 +108,7 @@ public:
reserve(newSize);
int moveCount = m_count - idx;
if (moveCount)
- ::memmove(m_data + idx + count, m_data + idx,
+ ::memmove(static_cast<void *>(m_data + idx + count), static_cast<const void *>(m_data + idx),
moveCount * sizeof(T));
m_count = newSize;
}
@@ -116,7 +116,7 @@ public:
void remove(int idx, int count = 1) {
int moveCount = m_count - (idx + count);
if (moveCount)
- ::memmove(m_data + idx, m_data + idx + count,
+ ::memmove(static_cast<void *>(m_data + idx), static_cast<const void *>(m_data + idx + count),
moveCount * sizeof(T));
m_count -= count;
}
@@ -154,7 +154,7 @@ public:
other.m_data = m_data;
m_count = 0;
m_capacity = 0;
- m_data = 0;
+ m_data = nullptr;
}
QPODVector<T,Increment> &operator<<(const T &v) { append(v); return *this; }
diff --git a/src/qml/qml/ftw/qqmlnullablevalue_p.h b/src/qml/qml/ftw/qqmlnullablevalue_p.h
index 7a9e4d7b8a..5b3d2fc456 100644
--- a/src/qml/qml/ftw/qqmlnullablevalue_p.h
+++ b/src/qml/qml/ftw/qqmlnullablevalue_p.h
@@ -57,7 +57,7 @@ template<typename T>
struct QQmlNullableValue
{
QQmlNullableValue()
- : isNull(true), value(T()) {}
+ : value(T()) {}
QQmlNullableValue(const QQmlNullableValue<T> &o)
: isNull(o.isNull), value(o.value) {}
QQmlNullableValue(const T &t)
@@ -70,7 +70,7 @@ struct QQmlNullableValue
void invalidate() { isNull = true; }
bool isValid() const { return !isNull; }
- bool isNull;
+ bool isNull = true;
T value;
};
diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h
index 225e18156c..140f129b21 100644
--- a/src/qml/qml/ftw/qqmlrefcount_p.h
+++ b/src/qml/qml/ftw/qqmlrefcount_p.h
@@ -60,18 +60,18 @@ QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QQmlRefCount
{
+ Q_DISABLE_COPY_MOVE(QQmlRefCount)
public:
inline QQmlRefCount();
- inline virtual ~QQmlRefCount();
- inline void addref();
- inline void release();
+ inline void addref() const;
+ inline void release() const;
inline int count() const;
protected:
- inline virtual void destroy();
+ inline virtual ~QQmlRefCount();
private:
- QAtomicInt refCount;
+ mutable QAtomicInt refCount;
};
template<class T>
@@ -85,19 +85,23 @@ public:
inline QQmlRefPointer();
inline QQmlRefPointer(T *, Mode m = AddRef);
inline QQmlRefPointer(const QQmlRefPointer<T> &);
+ inline QQmlRefPointer(QQmlRefPointer<T> &&);
inline ~QQmlRefPointer();
inline QQmlRefPointer<T> &operator=(const QQmlRefPointer<T> &o);
+ inline QQmlRefPointer<T> &operator=(QQmlRefPointer<T> &&o);
inline bool isNull() const { return !o; }
inline T* operator->() const { return o; }
inline T& operator*() const { return *o; }
- inline operator T*() const { return o; }
+ explicit inline operator bool() const { return o != nullptr; }
inline T* data() const { return o; }
inline QQmlRefPointer<T> &adopt(T *);
+ inline T* take() { T *res = o; o = nullptr; return res; }
+
private:
T *o;
};
@@ -112,17 +116,17 @@ QQmlRefCount::~QQmlRefCount()
Q_ASSERT(refCount.load() == 0);
}
-void QQmlRefCount::addref()
+void QQmlRefCount::addref() const
{
Q_ASSERT(refCount.load() > 0);
refCount.ref();
}
-void QQmlRefCount::release()
+void QQmlRefCount::release() const
{
Q_ASSERT(refCount.load() > 0);
if (!refCount.deref())
- destroy();
+ delete this;
}
int QQmlRefCount::count() const
@@ -130,14 +134,9 @@ int QQmlRefCount::count() const
return refCount.load();
}
-void QQmlRefCount::destroy()
-{
- delete this;
-}
-
template<class T>
QQmlRefPointer<T>::QQmlRefPointer()
-: o(0)
+: o(nullptr)
{
}
@@ -156,6 +155,12 @@ QQmlRefPointer<T>::QQmlRefPointer(const QQmlRefPointer<T> &other)
if (o) o->addref();
}
+template <class T>
+QQmlRefPointer<T>::QQmlRefPointer(QQmlRefPointer<T> &&other)
+ : o(other.take())
+{
+}
+
template<class T>
QQmlRefPointer<T>::~QQmlRefPointer()
{
@@ -171,6 +176,14 @@ QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(const QQmlRefPointer<T> &other)
return *this;
}
+template <class T>
+QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(QQmlRefPointer<T> &&other)
+{
+ QQmlRefPointer<T> m(std::move(other));
+ qSwap(o, m.o);
+ return *this;
+}
+
/*!
Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership
of the callers reference of other.
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp
index ffa6e29290..2ef1dc7e93 100644
--- a/src/qml/qml/ftw/qqmlthread.cpp
+++ b/src/qml/qml/ftw/qqmlthread.cpp
@@ -57,6 +57,7 @@ public:
void run() override;
+ inline QMutex &mutex() { return _mutex; }
inline void lock() { _mutex.lock(); }
inline void unlock() { _mutex.unlock(); }
inline void wait() { _wait.wait(&_mutex); }
@@ -123,7 +124,7 @@ bool QQmlThreadPrivate::MainObject::event(QEvent *e)
QQmlThreadPrivate::QQmlThreadPrivate(QQmlThread *q)
: q(q), m_threadProcessing(false), m_mainProcessing(false), m_shutdown(false),
- m_mainThreadWaiting(false), mainSync(0), m_mainObject(this)
+ m_mainThreadWaiting(false), mainSync(nullptr), m_mainObject(this)
{
setObjectName(QStringLiteral("QQmlThread"));
}
@@ -155,7 +156,7 @@ void QQmlThreadPrivate::mainEvent()
m_mainProcessing = true;
while (!mainList.isEmpty() || mainSync) {
- bool isSync = mainSync != 0;
+ bool isSync = mainSync != nullptr;
QQmlThread::Message *message = isSync?mainSync:mainList.takeFirst();
unlock();
@@ -165,7 +166,7 @@ void QQmlThreadPrivate::mainEvent()
lock();
if (isSync) {
- mainSync = 0;
+ mainSync = nullptr;
wakeOne();
}
}
@@ -233,20 +234,27 @@ void QQmlThread::shutdown()
{
d->lock();
Q_ASSERT(!d->m_shutdown);
- d->m_shutdown = true;
- if (d->threadList.isEmpty() && d->m_threadProcessing == false) {
- if (QCoreApplication::closingDown()) {
- d->quit();
+
+ for (;;) {
+ if (d->mainSync || !d->mainList.isEmpty()) {
d->unlock();
- d->QThread::wait();
- return;
+ d->mainEvent();
+ d->lock();
+ } else if (!d->threadList.isEmpty()) {
+ d->wait();
} else {
- d->triggerThreadEvent();
+ break;
}
- } else if (d->mainSync) {
- d->wakeOne();
}
- d->wait();
+
+ d->m_shutdown = true;
+ if (QCoreApplication::closingDown()) {
+ d->quit();
+ } else {
+ d->triggerThreadEvent();
+ d->wait();
+ }
+
d->unlock();
d->QThread::wait();
}
@@ -256,6 +264,11 @@ bool QQmlThread::isShutdown() const
return d->m_shutdown;
}
+QMutex &QQmlThread::mutex()
+{
+ return d->mutex();
+}
+
void QQmlThread::lock()
{
d->lock();
@@ -303,6 +316,12 @@ void QQmlThread::shutdownThread()
void QQmlThread::internalCallMethodInThread(Message *message)
{
+#if !QT_CONFIG(thread)
+ message->call(this);
+ delete message;
+ return;
+#endif
+
Q_ASSERT(!isThisThread());
d->lock();
Q_ASSERT(d->m_mainThreadWaiting == false);
@@ -321,7 +340,7 @@ void QQmlThread::internalCallMethodInThread(Message *message)
message->call(this);
delete message;
lock();
- d->mainSync = 0;
+ d->mainSync = nullptr;
wakeOne();
} else {
d->wait();
@@ -338,7 +357,7 @@ void QQmlThread::internalCallMethodInMain(Message *message)
d->lock();
- Q_ASSERT(d->mainSync == 0);
+ Q_ASSERT(d->mainSync == nullptr);
d->mainSync = message;
if (d->m_mainThreadWaiting) {
@@ -352,7 +371,7 @@ void QQmlThread::internalCallMethodInMain(Message *message)
while (d->mainSync) {
if (d->m_shutdown) {
delete d->mainSync;
- d->mainSync = 0;
+ d->mainSync = nullptr;
break;
}
d->wait();
@@ -363,6 +382,10 @@ void QQmlThread::internalCallMethodInMain(Message *message)
void QQmlThread::internalPostMethodToThread(Message *message)
{
+#if !QT_CONFIG(thread)
+ internalPostMethodToMain(message);
+ return;
+#endif
Q_ASSERT(!isThisThread());
d->lock();
bool wasEmpty = d->threadList.isEmpty();
@@ -398,7 +421,7 @@ void QQmlThread::waitForNextMessage()
message->call(this);
delete message;
lock();
- d->mainSync = 0;
+ d->mainSync = nullptr;
wakeOne();
} else {
d->wait();
diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h
index 295235e255..b5c580fe8b 100644
--- a/src/qml/qml/ftw/qqmlthread_p.h
+++ b/src/qml/qml/ftw/qqmlthread_p.h
@@ -59,6 +59,7 @@
QT_BEGIN_NAMESPACE
class QThread;
+class QMutex;
class QQmlThreadPrivate;
class QQmlThread
@@ -71,6 +72,7 @@ public:
void shutdown();
bool isShutdown() const;
+ QMutex &mutex();
void lock();
void unlock();
void wakeOne();
@@ -124,7 +126,7 @@ private:
friend class QQmlThreadPrivate;
struct Message {
- Message() : next(0) {}
+ Message() : next(nullptr) {}
virtual ~Message() {}
Message *next;
virtual void call(QQmlThread *) = 0;
diff --git a/src/qml/qml/ftw/qrecursionwatcher_p.h b/src/qml/qml/ftw/qrecursionwatcher_p.h
index 99228b9583..56b714f922 100644
--- a/src/qml/qml/ftw/qrecursionwatcher_p.h
+++ b/src/qml/qml/ftw/qrecursionwatcher_p.h
@@ -74,7 +74,7 @@ private:
};
QRecursionNode::QRecursionNode()
-: _r(0)
+: _r(nullptr)
{
}
@@ -89,7 +89,7 @@ QRecursionWatcher<T, Node>::QRecursionWatcher(T *t)
template<class T, QRecursionNode T::*Node>
QRecursionWatcher<T, Node>::~QRecursionWatcher()
{
- if ((_t->*Node)._r == &_r) (_t->*Node)._r = 0;
+ if ((_t->*Node)._r == &_r) (_t->*Node)._r = nullptr;
}
template<class T, QRecursionNode T::*Node>
diff --git a/src/qml/qml/ftw/qrecyclepool_p.h b/src/qml/qml/ftw/qrecyclepool_p.h
index 42a2f13729..39f4f88512 100644
--- a/src/qml/qml/ftw/qrecyclepool_p.h
+++ b/src/qml/qml/ftw/qrecyclepool_p.h
@@ -61,7 +61,7 @@ class QRecyclePoolPrivate
public:
QRecyclePoolPrivate()
: recyclePoolHold(true), outstandingItems(0), cookie(QRECYCLEPOOLCOOKIE),
- currentPage(0), nextAllocated(0)
+ currentPage(nullptr), nextAllocated(nullptr)
{
}
@@ -178,7 +178,7 @@ void QRecyclePoolPrivate<T, Step>::releaseIfPossible()
template<typename T, int Step>
T *QRecyclePoolPrivate<T, Step>::allocate()
{
- PoolType *rv = 0;
+ PoolType *rv = nullptr;
if (nextAllocated) {
rv = nextAllocated;
nextAllocated = rv->nextAllocated;
diff --git a/src/qml/qml/ftw/qstringhash.cpp b/src/qml/qml/ftw/qstringhash.cpp
new file mode 100644
index 0000000000..a483dcb810
--- /dev/null
+++ b/src/qml/qml/ftw/qstringhash.cpp
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstringhash_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*
+ A QHash has initially around pow(2, MinNumBits) buckets. For
+ example, if MinNumBits is 4, it has 17 buckets.
+*/
+static const int MinNumBits = 4;
+
+/*
+ The prime_deltas array is a table of selected prime values, even
+ though it doesn't look like one. The primes we are using are 1,
+ 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
+ surrounding of a power of two.
+
+ The primeForNumBits() function returns the prime associated to a
+ power of two. For example, primeForNumBits(8) returns 257.
+*/
+
+static const uchar prime_deltas[] = {
+ 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
+ 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
+};
+
+static inline int primeForNumBits(int numBits)
+{
+ return (1 << numBits) + prime_deltas[numBits];
+}
+
+void QStringHashData::rehashToSize(int size)
+{
+ short bits = qMax(MinNumBits, (int)numBits);
+ while (primeForNumBits(bits) < size) bits++;
+
+ if (bits > numBits)
+ rehashToBits(bits);
+}
+
+void QStringHashData::rehashToBits(short bits)
+{
+ numBits = qMax(MinNumBits, (int)bits);
+
+ int nb = primeForNumBits(numBits);
+ if (nb == numBuckets && buckets)
+ return;
+
+ QStringHashNode **newBuckets = new QStringHashNode *[nb];
+ ::memset(newBuckets, 0, sizeof(QStringHashNode *) * nb);
+
+ // Preserve the existing order within buckets so that items with the
+ // same key will retain the same find/findNext order
+ for (int i = 0; i < numBuckets; ++i) {
+ QStringHashNode *bucket = buckets[i];
+ if (bucket)
+ rehashNode(newBuckets, nb, bucket);
+ }
+
+ delete [] buckets;
+ buckets = newBuckets;
+ numBuckets = nb;
+}
+
+void QStringHashData::rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node)
+{
+ QStringHashNode *next = node->next.data();
+ if (next)
+ rehashNode(newBuckets, nb, next);
+
+ int bucket = node->hash % nb;
+ node->next = newBuckets[bucket];
+ newBuckets[bucket] = node;
+}
+
+// Copy of QString's qMemCompare
+bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
+{
+ Q_ASSERT(lhs && rhs);
+ const quint16 *a = (const quint16 *)lhs;
+ const quint16 *b = (const quint16 *)rhs;
+
+ if (a == b || !length)
+ return true;
+
+ union {
+ const quint16 *w;
+ const quint32 *d;
+ quintptr value;
+ } sa, sb;
+ sa.w = a;
+ sb.w = b;
+
+ // check alignment
+ if ((sa.value & 2) == (sb.value & 2)) {
+ // both addresses have the same alignment
+ if (sa.value & 2) {
+ // both addresses are not aligned to 4-bytes boundaries
+ // compare the first character
+ if (*sa.w != *sb.w)
+ return false;
+ --length;
+ ++sa.w;
+ ++sb.w;
+
+ // now both addresses are 4-bytes aligned
+ }
+
+ // both addresses are 4-bytes aligned
+ // do a fast 32-bit comparison
+ const quint32 *e = sa.d + (length >> 1);
+ for ( ; sa.d != e; ++sa.d, ++sb.d) {
+ if (*sa.d != *sb.d)
+ return false;
+ }
+
+ // do we have a tail?
+ return (length & 1) ? *sa.w == *sb.w : true;
+ } else {
+ // one of the addresses isn't 4-byte aligned but the other is
+ const quint16 *e = sa.w + length;
+ for ( ; sa.w != e; ++sa.w, ++sb.w) {
+ if (*sa.w != *sb.w)
+ return false;
+ }
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qstringhash_p.h b/src/qml/qml/ftw/qstringhash_p.h
new file mode 100644
index 0000000000..c7251e8837
--- /dev/null
+++ b/src/qml/qml/ftw/qstringhash_p.h
@@ -0,0 +1,758 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTRINGHASH_P_H
+#define QSTRINGHASH_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qhashedstring_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QStringHashData;
+class Q_AUTOTEST_EXPORT QStringHashNode
+{
+public:
+ QStringHashNode()
+ : ckey(nullptr)
+ {
+ }
+
+ QStringHashNode(const QHashedString &key)
+ : length(key.length()), hash(key.hash()), symbolId(0)
+ {
+ strData = const_cast<QHashedString &>(key).data_ptr();
+ setQString(true);
+ strData->ref.ref();
+ }
+
+ QStringHashNode(const QHashedCStringRef &key)
+ : length(key.length()), hash(key.hash()), symbolId(0), ckey(key.constData())
+ {
+ }
+
+ QStringHashNode(const QStringHashNode &o)
+ : length(o.length), hash(o.hash), symbolId(o.symbolId), ckey(o.ckey)
+ {
+ setQString(o.isQString());
+ if (isQString()) { strData->ref.ref(); }
+ }
+
+ ~QStringHashNode()
+ {
+ if (isQString()) { if (!strData->ref.deref()) free(strData); }
+ }
+
+ QFlagPointer<QStringHashNode> next;
+
+ qint32 length = 0;
+ quint32 hash = 0;
+ quint32 symbolId = 0;
+
+ union {
+ const char *ckey;
+ QStringData *strData;
+ };
+
+ inline QHashedString key() const
+ {
+ if (isQString())
+ return QHashedString(QString((QChar *)strData->data(), length), hash);
+
+ return QHashedString(QString::fromLatin1(ckey, length), hash);
+ }
+
+ bool isQString() const { return next.flag(); }
+ void setQString(bool v) { if (v) next.setFlag(); else next.clearFlag(); }
+
+ inline char *cStrData() const { return (char *)ckey; }
+ inline quint16 *utf16Data() const { return (quint16 *)strData->data(); }
+
+ inline bool equals(const QV4::Value &string) const {
+ QString s = string.toQStringNoThrow();
+ if (isQString()) {
+ QStringDataPtr dd;
+ dd.ptr = strData;
+ strData->ref.ref();
+ return QString(dd) == s;
+ } else {
+ return QLatin1String(cStrData(), length) == s;
+ }
+ }
+
+ inline bool equals(const QV4::String *string) const {
+ if (length != string->d()->length() || hash != string->hashValue())
+ return false;
+ if (isQString()) {
+ QStringDataPtr dd;
+ dd.ptr = strData;
+ strData->ref.ref();
+ return QString(dd) == string->toQString();
+ } else {
+ return QLatin1String(cStrData(), length) == string->toQString();
+ }
+ }
+
+ inline bool equals(const QHashedStringRef &string) const {
+ return length == string.length() &&
+ hash == string.hash() &&
+ (isQString()?QHashedString::compare(string.constData(), (const QChar *)utf16Data(), length):
+ QHashedString::compare(string.constData(), cStrData(), length));
+ }
+
+ inline bool equals(const QHashedCStringRef &string) const {
+ return length == string.length() &&
+ hash == string.hash() &&
+ (isQString()?QHashedString::compare((const QChar *)utf16Data(), string.constData(), length):
+ QHashedString::compare(string.constData(), cStrData(), length));
+ }
+};
+
+class Q_AUTOTEST_EXPORT QStringHashData
+{
+public:
+ QStringHashData() {}
+
+ QStringHashNode **buckets = nullptr;
+ int numBuckets = 0;
+ int size = 0;
+ short numBits = 0;
+
+ template<typename StringHash>
+ struct IteratorData {
+ IteratorData(QStringHashNode *n = nullptr, StringHash *p = nullptr) : n(n), p(p) {}
+
+ template<typename OtherData>
+ IteratorData(const OtherData &other) : n(other.n), p(other.p) {}
+
+ QStringHashNode *n;
+ StringHash *p;
+ };
+ void rehashToBits(short);
+ void rehashToSize(int);
+ void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node);
+
+private:
+ QStringHashData(const QStringHashData &);
+ QStringHashData &operator=(const QStringHashData &);
+};
+
+// For a supplied key type, in what form do we need to keep a hashed version?
+template<typename T>
+struct HashedForm {};
+
+template<> struct HashedForm<QString> { typedef QHashedString Type; };
+template<> struct HashedForm<QStringRef> { typedef QHashedStringRef Type; };
+template<> struct HashedForm<QHashedString> { typedef const QHashedString &Type; };
+template<> struct HashedForm<QV4::String *> { typedef const QV4::String *Type; };
+template<> struct HashedForm<const QV4::String *> { typedef const QV4::String *Type; };
+template<> struct HashedForm<QHashedStringRef> { typedef const QHashedStringRef &Type; };
+template<> struct HashedForm<QLatin1String> { typedef QHashedCStringRef Type; };
+template<> struct HashedForm<QHashedCStringRef> { typedef const QHashedCStringRef &Type; };
+
+class QStringHashBase
+{
+public:
+ static HashedForm<QString>::Type hashedString(const QString &s) { return QHashedString(s);}
+ static HashedForm<QStringRef>::Type hashedString(const QStringRef &s) { return QHashedStringRef(s.constData(), s.size());}
+ static HashedForm<QHashedString>::Type hashedString(const QHashedString &s) { return s; }
+ static HashedForm<QV4::String *>::Type hashedString(QV4::String *s) { return s; }
+ static HashedForm<const QV4::String *>::Type hashedString(const QV4::String *s) { return s; }
+ static HashedForm<QHashedStringRef>::Type hashedString(const QHashedStringRef &s) { return s; }
+
+ static HashedForm<QLatin1String>::Type hashedString(const QLatin1String &s) { return QHashedCStringRef(s.data(), s.size()); }
+ static HashedForm<QHashedCStringRef>::Type hashedString(const QHashedCStringRef &s) { return s; }
+
+ static const QString &toQString(const QString &s) { return s; }
+ static const QString &toQString(const QHashedString &s) { return s; }
+ static QString toQString(const QV4::String *s) { return s->toQString(); }
+ static QString toQString(const QHashedStringRef &s) { return s.toString(); }
+
+ static QString toQString(const QLatin1String &s) { return QString(s); }
+ static QString toQString(const QHashedCStringRef &s) { return s.toUtf16(); }
+
+ static inline quint32 hashOf(const QHashedStringRef &s) { return s.hash(); }
+ static inline quint32 hashOf(QV4::String *s) { return s->hashValue(); }
+ static inline quint32 hashOf(const QV4::String *s) { return s->hashValue(); }
+
+ template<typename K>
+ static inline quint32 hashOf(const K &key) { return hashedString(key).hash(); }
+};
+
+template<class T>
+class QStringHash : public QStringHashBase
+{
+public:
+ typedef QHashedString key_type;
+ typedef T mapped_type;
+
+ using MutableIteratorData = QStringHashData::IteratorData<QStringHash<T>>;
+ using ConstIteratorData = QStringHashData::IteratorData<const QStringHash<T>>;
+
+ struct Node : public QStringHashNode {
+ Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {}
+ Node(const QHashedCStringRef &key, const T &value) : QStringHashNode(key), value(value) {}
+ Node(const Node &o) : QStringHashNode(o), value(o.value) {}
+ Node() {}
+ T value;
+ };
+ struct NewedNode : public Node {
+ NewedNode(const QHashedString &key, const T &value) : Node(key, value), nextNewed(nullptr) {}
+ NewedNode(const QHashedCStringRef &key, const T &value) : Node(key, value), nextNewed(nullptr) {}
+ NewedNode(const Node &o) : Node(o), nextNewed(nullptr) {}
+ NewedNode *nextNewed;
+ };
+ struct ReservedNodePool
+ {
+ ReservedNodePool() : nodes(nullptr) {}
+ ~ReservedNodePool() { delete [] nodes; }
+ int count = 0;
+ int used = 0;
+ Node *nodes;
+ };
+
+ QStringHashData data;
+ NewedNode *newedNodes;
+ ReservedNodePool *nodePool;
+
+ template<typename K>
+ inline Node *findNode(const K &) const;
+
+ inline Node *createNode(const Node &o);
+
+ template<typename K>
+ inline Node *createNode(const K &, const T &);
+
+ inline Node *insertNode(Node *, quint32);
+
+ inline void initializeNode(Node *, const QHashedString &key);
+ inline void initializeNode(Node *, const QHashedCStringRef &key);
+
+ template<typename K>
+ inline Node *takeNode(const K &key, const T &value);
+
+ inline Node *takeNode(const Node &o);
+
+ inline void copy(const QStringHash<T> &);
+
+ void copyNode(const QStringHashNode *otherNode);
+
+ template<typename StringHash, typename Data>
+ static inline Data iterateFirst(StringHash *self);
+
+ template<typename Data>
+ static inline Data iterateNext(const Data &);
+
+public:
+ inline QStringHash();
+ inline QStringHash(const QStringHash &);
+ inline ~QStringHash();
+
+ QStringHash &operator=(const QStringHash<T> &);
+
+ void copyAndReserve(const QStringHash<T> &other, int additionalReserve);
+
+ inline bool isEmpty() const;
+ inline void clear();
+ inline int count() const;
+
+ inline int numBuckets() const;
+
+ template<typename Data, typename Value>
+ class Iterator {
+ public:
+ inline Iterator() = default;
+ inline Iterator(const Data &d) : d(d) {}
+
+ inline Iterator &operator++()
+ {
+ d = QStringHash<T>::iterateNext(d);
+ return *this;
+ }
+
+ inline bool operator==(const Iterator &o) const { return d.n == o.d.n; }
+ inline bool operator!=(const Iterator &o) const { return d.n != o.d.n; }
+
+ template<typename K>
+ inline bool equals(const K &key) const { return d.n->equals(key); }
+
+ inline QHashedString key() const { return static_cast<Node *>(d.n)->key(); }
+ inline Value &value() const { return static_cast<Node *>(d.n)->value; }
+ inline Value &operator*() const { return static_cast<Node *>(d.n)->value; }
+
+ Node *node() const { return static_cast<Node *>(d.n); }
+ private:
+ Data d;
+ };
+
+ using MutableIterator = Iterator<MutableIteratorData, T>;
+ using ConstIterator = Iterator<ConstIteratorData, const T>;
+
+ template<typename K>
+ inline void insert(const K &, const T &);
+ inline void insert(const MutableIterator &);
+ inline void insert(const ConstIterator &);
+
+ template<typename K>
+ inline T *value(const K &) const;
+ inline T *value(const QV4::String *string) const;
+ inline T *value(const MutableIterator &) const;
+ inline T *value(const ConstIterator &) const;
+
+ template<typename K>
+ inline bool contains(const K &) const;
+
+ template<typename K>
+ inline T &operator[](const K &);
+
+ inline MutableIterator begin();
+ inline ConstIterator begin() const;
+ inline ConstIterator constBegin() const { return begin(); }
+
+ inline MutableIterator end();
+ inline ConstIterator end() const;
+ inline ConstIterator constEnd() const { return end(); }
+
+ template<typename K>
+ inline MutableIterator find(const K &);
+
+ template<typename K>
+ inline ConstIterator find(const K &) const;
+
+ inline void reserve(int);
+};
+
+template<class T>
+QStringHash<T>::QStringHash()
+: newedNodes(nullptr), nodePool(nullptr)
+{
+}
+
+template<class T>
+QStringHash<T>::QStringHash(const QStringHash<T> &other)
+: newedNodes(nullptr), nodePool(nullptr)
+{
+ data.numBits = other.data.numBits;
+ data.size = other.data.size;
+ reserve(other.count());
+ copy(other);
+}
+
+template<class T>
+QStringHash<T> &QStringHash<T>::operator=(const QStringHash<T> &other)
+{
+ if (&other == this)
+ return *this;
+
+ clear();
+
+ data.numBits = other.data.numBits;
+ data.size = other.data.size;
+ reserve(other.count());
+ copy(other);
+
+ return *this;
+}
+
+template<class T>
+void QStringHash<T>::copyAndReserve(const QStringHash<T> &other, int additionalReserve)
+{
+ clear();
+ data.numBits = other.data.numBits;
+ reserve(other.count() + additionalReserve);
+ copy(other);
+}
+
+template<class T>
+QStringHash<T>::~QStringHash()
+{
+ clear();
+}
+
+template<class T>
+void QStringHash<T>::clear()
+{
+ // Delete the individually allocated nodes
+ NewedNode *n = newedNodes;
+ while (n) {
+ NewedNode *c = n;
+ n = c->nextNewed;
+ delete c;
+ }
+ // Delete the pool allocated nodes
+ if (nodePool) delete nodePool;
+ delete [] data.buckets;
+
+ data.buckets = nullptr;
+ data.numBuckets = 0;
+ data.numBits = 0;
+ data.size = 0;
+
+ newedNodes = nullptr;
+ nodePool = nullptr;
+}
+
+template<class T>
+bool QStringHash<T>::isEmpty() const
+{
+ return data.size== 0;
+}
+
+template<class T>
+int QStringHash<T>::count() const
+{
+ return data.size;
+}
+
+template<class T>
+int QStringHash<T>::numBuckets() const
+{
+ return data.numBuckets;
+}
+
+template<class T>
+void QStringHash<T>::initializeNode(Node *node, const QHashedString &key)
+{
+ node->length = key.length();
+ node->hash = key.hash();
+ node->strData = const_cast<QHashedString &>(key).data_ptr();
+ node->strData->ref.ref();
+ node->setQString(true);
+}
+
+template<class T>
+void QStringHash<T>::initializeNode(Node *node, const QHashedCStringRef &key)
+{
+ node->length = key.length();
+ node->hash = key.hash();
+ node->ckey = key.constData();
+}
+
+template<class T>
+template<class K>
+typename QStringHash<T>::Node *QStringHash<T>::takeNode(const K &key, const T &value)
+{
+ if (nodePool && nodePool->used != nodePool->count) {
+ Node *rv = nodePool->nodes + nodePool->used++;
+ initializeNode(rv, hashedString(key));
+ rv->value = value;
+ return rv;
+ } else {
+ NewedNode *rv = new NewedNode(hashedString(key), value);
+ rv->nextNewed = newedNodes;
+ newedNodes = rv;
+ return rv;
+ }
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::takeNode(const Node &o)
+{
+ if (nodePool && nodePool->used != nodePool->count) {
+ Node *rv = nodePool->nodes + nodePool->used++;
+ rv->length = o.length;
+ rv->hash = o.hash;
+ if (o.isQString()) {
+ rv->strData = o.strData;
+ rv->strData->ref.ref();
+ rv->setQString(true);
+ } else {
+ rv->ckey = o.ckey;
+ }
+ rv->symbolId = o.symbolId;
+ rv->value = o.value;
+ return rv;
+ } else {
+ NewedNode *rv = new NewedNode(o);
+ rv->nextNewed = newedNodes;
+ newedNodes = rv;
+ return rv;
+ }
+}
+
+template<class T>
+void QStringHash<T>::copyNode(const QStringHashNode *otherNode)
+{
+ // Copy the predecessor before the successor
+ QStringHashNode *next = otherNode->next.data();
+ if (next)
+ copyNode(next);
+
+ Node *mynode = takeNode(*(const Node *)otherNode);
+ int bucket = mynode->hash % data.numBuckets;
+ mynode->next = data.buckets[bucket];
+ data.buckets[bucket] = mynode;
+}
+
+template<class T>
+void QStringHash<T>::copy(const QStringHash<T> &other)
+{
+ Q_ASSERT(data.size == 0);
+
+ data.size = other.data.size;
+
+ // Ensure buckets array is created
+ data.rehashToBits(data.numBits);
+
+ // Preserve the existing order within buckets
+ for (int i = 0; i < other.data.numBuckets; ++i) {
+ QStringHashNode *bucket = other.data.buckets[i];
+ if (bucket)
+ copyNode(bucket);
+ }
+}
+
+template<class T>
+template<typename Data>
+Data QStringHash<T>::iterateNext(const Data &d)
+{
+ auto *This = d.p;
+ Node *node = (Node *)d.n;
+
+ if (This->nodePool && node >= This->nodePool->nodes &&
+ node < (This->nodePool->nodes + This->nodePool->used)) {
+ node--;
+ if (node < This->nodePool->nodes)
+ node = nullptr;
+ } else {
+ NewedNode *nn = (NewedNode *)node;
+ node = nn->nextNewed;
+
+ if (node == nullptr && This->nodePool && This->nodePool->used)
+ node = This->nodePool->nodes + This->nodePool->used - 1;
+ }
+
+ Data rv;
+ rv.n = node;
+ rv.p = d.p;
+ return rv;
+}
+
+template<class T>
+template<typename StringHash, typename Data>
+Data QStringHash<T>::iterateFirst(StringHash *self)
+{
+ typename StringHash::Node *n = nullptr;
+ if (self->newedNodes)
+ n = self->newedNodes;
+ else if (self->nodePool && self->nodePool->used)
+ n = self->nodePool->nodes + self->nodePool->used - 1;
+
+ Data rv;
+ rv.n = n;
+ rv.p = self;
+ return rv;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const Node &o)
+{
+ Node *n = takeNode(o);
+ return insertNode(n, n->hash);
+}
+
+template<class T>
+template<class K>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const K &key, const T &value)
+{
+ Node *n = takeNode(key, value);
+ return insertNode(n, hashOf(key));
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::insertNode(Node *n, quint32 hash)
+{
+ if (data.size >= data.numBuckets)
+ data.rehashToBits(data.numBits + 1);
+
+ int bucket = hash % data.numBuckets;
+ n->next = data.buckets[bucket];
+ data.buckets[bucket] = n;
+
+ data.size++;
+
+ return n;
+}
+
+template<class T>
+template<class K>
+void QStringHash<T>::insert(const K &key, const T &value)
+{
+ Node *n = findNode(key);
+ if (n)
+ n->value = value;
+ else
+ createNode(key, value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const MutableIterator &iter)
+{
+ insert(iter.key(), iter.value());
+}
+
+template<class T>
+void QStringHash<T>::insert(const ConstIterator &iter)
+{
+ insert(iter.key(), iter.value());
+}
+
+template<class T>
+template<class K>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const K &key) const
+{
+ QStringHashNode *node = data.numBuckets?data.buckets[hashOf(key) % data.numBuckets]:nullptr;
+
+ typename HashedForm<K>::Type hashedKey(hashedString(key));
+ while (node && !node->equals(hashedKey))
+ node = (*node->next);
+
+ return (Node *)node;
+}
+
+template<class T>
+template<class K>
+T *QStringHash<T>::value(const K &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:nullptr;
+}
+
+template<typename T>
+T *QStringHash<T>::value(const MutableIterator &iter) const
+{
+ return value(iter.node()->key());
+}
+
+template<class T>
+T *QStringHash<T>::value(const ConstIterator &iter) const
+{
+ return value(iter.node()->key());
+}
+
+template<class T>
+T *QStringHash<T>::value(const QV4::String *string) const
+{
+ Node *n = findNode(string);
+ return n?&n->value:nullptr;
+}
+
+template<class T>
+template<class K>
+bool QStringHash<T>::contains(const K &key) const
+{
+ return nullptr != value(key);
+}
+
+template<class T>
+template<class K>
+T &QStringHash<T>::operator[](const K &key)
+{
+ Node *n = findNode(key);
+ if (n) return n->value;
+ else return createNode(key, T())->value;
+}
+
+template<class T>
+void QStringHash<T>::reserve(int n)
+{
+ if (nodePool || 0 == n)
+ return;
+
+ nodePool = new ReservedNodePool;
+ nodePool->count = n;
+ nodePool->used = 0;
+ nodePool->nodes = new Node[n];
+
+ data.rehashToSize(n);
+}
+
+template<class T>
+typename QStringHash<T>::MutableIterator QStringHash<T>::begin()
+{
+ return MutableIterator(iterateFirst<QStringHash<T>, MutableIteratorData>(this));
+}
+
+template<class T>
+typename QStringHash<T>::ConstIterator QStringHash<T>::begin() const
+{
+ return ConstIterator(iterateFirst<const QStringHash<T>, ConstIteratorData>(this));
+}
+
+template<class T>
+typename QStringHash<T>::MutableIterator QStringHash<T>::end()
+{
+ return MutableIterator();
+}
+
+template<class T>
+typename QStringHash<T>::ConstIterator QStringHash<T>::end() const
+{
+ return ConstIterator();
+}
+
+template<class T>
+template<class K>
+typename QStringHash<T>::MutableIterator QStringHash<T>::find(const K &key)
+{
+ Node *n = findNode(key);
+ return n ? MutableIterator(MutableIteratorData(n, this)) : MutableIterator();
+}
+
+template<class T>
+template<class K>
+typename QStringHash<T>::ConstIterator QStringHash<T>::find(const K &key) const
+{
+ Node *n = findNode(key);
+ return n ? ConstIterator(ConstIteratorData(n, this)) : ConstIterator();
+}
+
+QT_END_NAMESPACE
+
+#endif // QSTRINGHASH_P_H