diff options
Diffstat (limited to 'src/qml/qml/ftw')
22 files changed, 2080 insertions, 2733 deletions
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri deleted file mode 100644 index ade05a596b..0000000000 --- a/src/qml/qml/ftw/ftw.pri +++ /dev/null @@ -1,23 +0,0 @@ -HEADERS += \ - $$PWD/qbitfield_p.h \ - $$PWD/qintrusivelist_p.h \ - $$PWD/qpodvector_p.h \ - $$PWD/qhashedstring_p.h \ - $$PWD/qqmlrefcount_p.h \ - $$PWD/qfieldlist_p.h \ - $$PWD/qqmlthread_p.h \ - $$PWD/qfinitestack_p.h \ - $$PWD/qrecursionwatcher_p.h \ - $$PWD/qrecyclepool_p.h \ - $$PWD/qflagpointer_p.h \ - $$PWD/qlazilyallocated_p.h \ - $$PWD/qqmlnullablevalue_p.h - -SOURCES += \ - $$PWD/qintrusivelist.cpp \ - $$PWD/qhashedstring.cpp \ - $$PWD/qqmlthread.cpp \ - -# mirrors logic in $$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri -# clock_gettime() is implemented in librt on these systems -qtConfig(clock-gettime):linux-*|hpux-*|solaris-*:LIBS_PRIVATE *= -lrt diff --git a/src/qml/qml/ftw/qbipointer_p.h b/src/qml/qml/ftw/qbipointer_p.h new file mode 100644 index 0000000000..1597b9e4fc --- /dev/null +++ b/src/qml/qml/ftw/qbipointer_p.h @@ -0,0 +1,203 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QBIPOINTER_P_H +#define QBIPOINTER_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/private/qglobal_p.h> + +#include <QtCore/qhashfunctions.h> + +QT_BEGIN_NAMESPACE + +namespace QtPrivate { +template <typename T> struct QFlagPointerAlignment +{ + enum : size_t { Value = Q_ALIGNOF(T) }; +}; +template <> struct QFlagPointerAlignment<void> +{ + enum : size_t { Value = ~size_t(0) }; +}; +} + +/*! + \internal + \class template<typename T1, typename T2> QBiPointer<T1, T2> + + \short QBiPointer can be thought of as a space-optimized std::variant<T1*, T2*> + with a nicer API to check the active pointer. Its other main feature is that + it only requires sizeof(void *) space. + + \note It can also store one additional flag for a user defined purpose. + */ +template<typename T, typename T2> +class QBiPointer { +public: + Q_NODISCARD_CTOR constexpr QBiPointer() noexcept = default; + ~QBiPointer() noexcept = default; + Q_NODISCARD_CTOR QBiPointer(const QBiPointer &o) noexcept = default; + Q_NODISCARD_CTOR QBiPointer(QBiPointer &&o) noexcept = default; + QBiPointer<T, T2> &operator=(const QBiPointer<T, T2> &o) noexcept = default; + QBiPointer<T, T2> &operator=(QBiPointer<T, T2> &&o) noexcept = default; + + void swap(QBiPointer &other) noexcept { std::swap(ptr_value, other.ptr_value); } + + Q_NODISCARD_CTOR inline QBiPointer(T *); + Q_NODISCARD_CTOR inline QBiPointer(T2 *); + + inline bool isNull() const; + inline bool isT1() const; + inline bool isT2() const; + + inline bool flag() const; + inline void setFlag(); + inline void clearFlag(); + inline void setFlagValue(bool); + + inline QBiPointer<T, T2> &operator=(T *); + inline QBiPointer<T, T2> &operator=(T2 *); + + friend inline bool operator==(QBiPointer<T, T2> ptr1, QBiPointer<T, T2> ptr2) + { + if (ptr1.isNull() && ptr2.isNull()) + return true; + if (ptr1.isT1() && ptr2.isT1()) + return ptr1.asT1() == ptr2.asT1(); + if (ptr1.isT2() && ptr2.isT2()) + return ptr1.asT2() == ptr2.asT2(); + return false; + } + friend inline bool operator!=(QBiPointer<T, T2> ptr1, QBiPointer<T, T2> ptr2) + { + return !(ptr1 == ptr2); + } + + friend void swap(QBiPointer &lhs, QBiPointer &rhs) noexcept { lhs.swap(rhs); } + + inline T *asT1() const; + inline T2 *asT2() const; + + friend size_t qHash(const QBiPointer<T, T2> &ptr, size_t seed = 0) + { + return qHash(ptr.isNull() ? quintptr(0) : ptr.ptr_value, seed); + } + +private: + quintptr ptr_value = 0; + + static const quintptr FlagBit = 0x1; + static const quintptr Flag2Bit = 0x2; + static const quintptr FlagsMask = FlagBit | Flag2Bit; +}; + +template <typename...Ts> // can't use commas in macros +Q_DECLARE_TYPEINFO_BODY(QBiPointer<Ts...>, Q_PRIMITIVE_TYPE); + +template<typename T, typename T2> +QBiPointer<T, T2>::QBiPointer(T *v) +: ptr_value(quintptr(v)) +{ + Q_STATIC_ASSERT_X(QtPrivate::QFlagPointerAlignment<T>::Value >= 4, + "Type T does not have sufficient alignment"); + Q_ASSERT((quintptr(v) & FlagsMask) == 0); +} + +template<typename T, typename T2> +QBiPointer<T, T2>::QBiPointer(T2 *v) +: ptr_value(quintptr(v) | Flag2Bit) +{ + Q_STATIC_ASSERT_X(QtPrivate::QFlagPointerAlignment<T2>::Value >= 4, + "Type T2 does not have sufficient alignment"); + Q_ASSERT((quintptr(v) & FlagsMask) == 0); +} + +template<typename T, typename T2> +bool QBiPointer<T, T2>::isNull() const +{ + return 0 == (ptr_value & (~FlagsMask)); +} + +template<typename T, typename T2> +bool QBiPointer<T, T2>::isT1() const +{ + return !(ptr_value & Flag2Bit); +} + +template<typename T, typename T2> +bool QBiPointer<T, T2>::isT2() const +{ + return ptr_value & Flag2Bit; +} + +template<typename T, typename T2> +bool QBiPointer<T, T2>::flag() const +{ + return ptr_value & FlagBit; +} + +template<typename T, typename T2> +void QBiPointer<T, T2>::setFlag() +{ + ptr_value |= FlagBit; +} + +template<typename T, typename T2> +void QBiPointer<T, T2>::clearFlag() +{ + ptr_value &= ~FlagBit; +} + +template<typename T, typename T2> +void QBiPointer<T, T2>::setFlagValue(bool v) +{ + if (v) setFlag(); + else clearFlag(); +} + +template<typename T, typename T2> +QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T *o) +{ + Q_ASSERT((quintptr(o) & FlagsMask) == 0); + + ptr_value = quintptr(o) | (ptr_value & FlagBit); + return *this; +} + +template<typename T, typename T2> +QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T2 *o) +{ + Q_ASSERT((quintptr(o) & FlagsMask) == 0); + + ptr_value = quintptr(o) | (ptr_value & FlagBit) | Flag2Bit; + return *this; +} + +template<typename T, typename T2> +T *QBiPointer<T, T2>::asT1() const +{ + Q_ASSERT(isT1()); + return (T *)(ptr_value & ~FlagsMask); +} + +template<typename T, typename T2> +T2 *QBiPointer<T, T2>::asT2() const +{ + Q_ASSERT(isT2()); + return (T2 *)(ptr_value & ~FlagsMask); +} + +QT_END_NAMESPACE + +#endif // QBIPOINTER_P_H diff --git a/src/qml/qml/ftw/qbitfield_p.h b/src/qml/qml/ftw/qbitfield_p.h deleted file mode 100644 index 92017580d6..0000000000 --- a/src/qml/qml/ftw/qbitfield_p.h +++ /dev/null @@ -1,167 +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 QBITFIELD_P_H -#define QBITFIELD_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 <QtCore/qtypeinfo.h> - -QT_BEGIN_NAMESPACE - -class QBitField -{ -public: - inline QBitField(); - inline QBitField(const quint32 *, int bits); - inline QBitField(const QBitField &); - inline ~QBitField(); - - inline QBitField &operator=(const QBitField &); - - inline quint32 size() const; - inline QBitField united(const QBitField &); - inline bool testBit(int) const; - -private: - quint32 bits:31; - quint32 *ownData; - const quint32 *data; -}; - -QBitField::QBitField() -: bits(0), ownData(nullptr), data(nullptr) -{ -} - -QBitField::QBitField(const quint32 *bitData, int bitCount) -: bits((quint32)bitCount), ownData(nullptr), data(bitData) -{ -} - -QBitField::QBitField(const QBitField &other) -: bits(other.bits), ownData(other.ownData), data(other.data) -{ - if (ownData) - ++(*ownData); -} - -QBitField::~QBitField() -{ - if (ownData) - if(0 == --(*ownData)) delete [] ownData; -} - -QBitField &QBitField::operator=(const QBitField &other) -{ - if (other.data == data) - return *this; - - if (ownData) - if(0 == --(*ownData)) delete [] ownData; - - bits = other.bits; - ownData = other.ownData; - data = other.data; - - if (ownData) - ++(*ownData); - - return *this; -} - -inline quint32 QBitField::size() const -{ - return bits; -} - -QBitField QBitField::united(const QBitField &o) -{ - if (o.bits == 0) { - return *this; - } else if (bits == 0) { - return o; - } else { - int max = (bits > o.bits)?bits:o.bits; - int length = (max + 31) / 32; - QBitField rv; - rv.bits = max; - rv.ownData = new quint32[length + 1]; - *(rv.ownData) = 1; - quint32 *rvdata; - rv.data = rvdata = rv.ownData + 1; - if (bits > o.bits) { - ::memcpy(rvdata, data, length * sizeof(quint32)); - for (quint32 ii = 0; ii < (o.bits + quint32(31)) / 32; ++ii) - (rvdata)[ii] |= o.data[ii]; - } else { - ::memcpy(rvdata, o.data, length * sizeof(quint32)); - for (quint32 ii = 0; ii < (bits + quint32(31)) / 32; ++ii) - (rvdata)[ii] |= data[ii]; - } - return rv; - } -} - -bool QBitField::testBit(int b) const -{ - Q_ASSERT(b >= 0); - if ((quint32)b < bits) { - return data[b / 32] & (1 << (b % 32)); - } else { - return false; - } -} - -Q_DECLARE_TYPEINFO(QBitField, Q_MOVABLE_TYPE); - -QT_END_NAMESPACE - -#endif // QBITFIELD_P_H diff --git a/src/qml/qml/ftw/qdoubleendedlist_p.h b/src/qml/qml/ftw/qdoubleendedlist_p.h new file mode 100644 index 0000000000..0a4d9f75d3 --- /dev/null +++ b/src/qml/qml/ftw/qdoubleendedlist_p.h @@ -0,0 +1,256 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QDOUBLEENDEDLIST_P_H +#define QDOUBLEENDEDLIST_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/private/qglobal_p.h> + +QT_BEGIN_NAMESPACE + +class QInheritedListNode +{ +public: + ~QInheritedListNode() { remove(); } + bool isInList() const + { + Q_ASSERT((m_prev && m_next) || (!m_prev && !m_next)); + return m_prev != nullptr; + } + +private: + template<class N> + friend class QDoubleEndedList; + + void remove() + { + Q_ASSERT((m_prev && m_next) || (!m_prev && !m_next)); + if (!m_prev) + return; + + m_prev->m_next = m_next; + m_next->m_prev = m_prev; + m_prev = nullptr; + m_next = nullptr; + } + + QInheritedListNode *m_next = nullptr; + QInheritedListNode *m_prev = nullptr; +}; + +template<class N> +class QDoubleEndedList +{ +public: + QDoubleEndedList() + { + m_head.m_next = &m_head; + m_head.m_prev = &m_head; + assertHeadConsistent(); + } + + ~QDoubleEndedList() + { + assertHeadConsistent(); + while (!isEmpty()) + m_head.m_next->remove(); + assertHeadConsistent(); + } + + bool isEmpty() const + { + assertHeadConsistent(); + return m_head.m_next == &m_head; + } + + void prepend(N *n) + { + assertHeadConsistent(); + QInheritedListNode *nnode = n; + nnode->remove(); + + nnode->m_next = m_head.m_next ? m_head.m_next : &m_head; + nnode->m_next->m_prev = nnode; + + m_head.m_next = nnode; + nnode->m_prev = &m_head; + assertHeadConsistent(); + } + + void append(N *n) + { + assertHeadConsistent(); + QInheritedListNode *nnode = n; + nnode->remove(); + + nnode->m_prev = m_head.m_prev ? m_head.m_prev : &m_head; + nnode->m_prev->m_next = nnode; + + m_head.m_prev = nnode; + nnode->m_next = &m_head; + assertHeadConsistent(); + } + + void remove(N *n) { + Q_ASSERT(contains(n)); + QInheritedListNode *nnode = n; + nnode->remove(); + assertHeadConsistent(); + } + + bool contains(const N *n) const + { + assertHeadConsistent(); + for (const QInheritedListNode *nnode = m_head.m_next; + nnode != &m_head; nnode = nnode->m_next) { + if (nnode == n) + return true; + } + + return false; + } + + template<typename T, typename Node> + class base_iterator { + public: + T *operator*() const { return QDoubleEndedList<N>::nodeToN(m_node); } + T *operator->() const { return QDoubleEndedList<N>::nodeToN(m_node); } + + bool operator==(const base_iterator &other) const { return other.m_node == m_node; } + bool operator!=(const base_iterator &other) const { return other.m_node != m_node; } + + base_iterator &operator++() + { + m_node = m_node->m_next; + return *this; + } + + base_iterator operator++(int) + { + const base_iterator self(m_node); + m_node = m_node->m_next; + return self; + } + + private: + friend class QDoubleEndedList<N>; + + base_iterator(Node *node) : m_node(node) + { + Q_ASSERT(m_node != nullptr); + } + + Node *m_node = nullptr; + }; + + using iterator = base_iterator<N, QInheritedListNode>; + using const_iterator = base_iterator<const N, const QInheritedListNode>; + + const N *first() const { return checkedNodeToN(m_head.m_next); } + N *first() { return checkedNodeToN(m_head.m_next); } + + const N *last() const { return checkedNodeToN(m_head.m_prev); } + N *last() { return checkedNodeToN(m_head.m_prev); } + + const N *next(const N *current) const + { + Q_ASSERT(contains(current)); + const QInheritedListNode *nnode = current; + return checkedNodeToN(nnode->m_next); + } + + N *next(N *current) + { + Q_ASSERT(contains(current)); + const QInheritedListNode *nnode = current; + return checkedNodeToN(nnode->m_next); + } + + const N *prev(const N *current) const + { + Q_ASSERT(contains(current)); + const QInheritedListNode *nnode = current; + return checkedNodeToN(nnode->m_prev); + } + + N *prev(N *current) + { + Q_ASSERT(contains(current)); + const QInheritedListNode *nnode = current; + return checkedNodeToN(nnode->m_prev); + } + + iterator begin() + { + assertHeadConsistent(); + return iterator(m_head.m_next); + } + + iterator end() + { + assertHeadConsistent(); + return iterator(&m_head); + } + + const_iterator begin() const + { + assertHeadConsistent(); + return const_iterator(m_head.m_next); + } + + const_iterator end() const + { + assertHeadConsistent(); + return const_iterator(&m_head); + } + + qsizetype count() const + { + assertHeadConsistent(); + qsizetype result = 0; + for (const auto *node = m_head.m_next; node != &m_head; node = node->m_next) + ++result; + return result; + } + +private: + static N *nodeToN(QInheritedListNode *node) + { + return static_cast<N *>(node); + } + + static const N *nodeToN(const QInheritedListNode *node) + { + return static_cast<const N *>(node); + } + + N *checkedNodeToN(QInheritedListNode *node) const + { + assertHeadConsistent(); + return (!node || node == &m_head) ? nullptr : nodeToN(node); + } + + void assertHeadConsistent() const + { + Q_ASSERT(m_head.m_next != nullptr); + Q_ASSERT(m_head.m_prev != nullptr); + Q_ASSERT(m_head.m_next != &m_head || m_head.m_prev == &m_head); + } + + QInheritedListNode m_head; +}; + +QT_END_NAMESPACE + +#endif // QDOUBLEENDEDLIST_P_H diff --git a/src/qml/qml/ftw/qfieldlist_p.h b/src/qml/qml/ftw/qfieldlist_p.h index 2bf07fb20d..b4c6a55f1a 100644 --- a/src/qml/qml/ftw/qfieldlist_p.h +++ b/src/qml/qml/ftw/qfieldlist_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QFIELDLIST_P_H #define QFIELDLIST_P_H @@ -51,12 +15,12 @@ // We mean it. // -#include <QtCore/qglobal.h> +#include <QtCore/private/qglobal_p.h> +#include <QtCore/qtaggedpointer.h> -#include <private/qflagpointer_p.h> // QForwardFieldList is a super simple linked list that can only prepend -template<class N, N *N::*nextMember> +template<class N, N *N::*nextMember, typename Tag = QtPrivate::TagInfo<N>> class QForwardFieldList { public: @@ -65,6 +29,8 @@ public: inline N *takeFirst(); inline void prepend(N *); + template <typename OtherTag> + inline void copyAndClearPrepend(QForwardFieldList<N, nextMember, OtherTag> &); inline bool isEmpty() const; inline bool isOne() const; @@ -72,17 +38,10 @@ public: static inline N *next(N *v); - inline bool flag() const; - inline void setFlag(); - inline void clearFlag(); - inline void setFlagValue(bool); - - inline bool flag2() const; - inline void setFlag2(); - inline void clearFlag2(); - inline void setFlag2Value(bool); + inline Tag tag() const; + inline void setTag(Tag t); private: - QFlagPointer<N> _first; + QTaggedPointer<N, Tag> _first; }; // QFieldList is a simple linked list, that can append and prepend and also @@ -108,8 +67,10 @@ public: inline void insertAfter(N *, QFieldList<N, nextMember> &); inline void copyAndClear(QFieldList<N, nextMember> &); - inline void copyAndClearAppend(QForwardFieldList<N, nextMember> &); - inline void copyAndClearPrepend(QForwardFieldList<N, nextMember> &); + template <typename Tag> + inline void copyAndClearAppend(QForwardFieldList<N, nextMember, Tag> &); + template <typename Tag> + inline void copyAndClearPrepend(QForwardFieldList<N, nextMember, Tag> &); static inline N *next(N *v); @@ -124,21 +85,21 @@ private: quint32 _count:31; }; -template<class N, N *N::*nextMember> -QForwardFieldList<N, nextMember>::QForwardFieldList() +template<class N, N *N::*nextMember, typename Tag> +QForwardFieldList<N, nextMember, Tag>::QForwardFieldList() { } -template<class N, N *N::*nextMember> -N *QForwardFieldList<N, nextMember>::first() const +template<class N, N *N::*nextMember, typename Tag> +N *QForwardFieldList<N, nextMember, Tag>::first() const { - return *_first; + return _first.data(); } -template<class N, N *N::*nextMember> -N *QForwardFieldList<N, nextMember>::takeFirst() +template<class N, N *N::*nextMember, typename Tag> +N *QForwardFieldList<N, nextMember, Tag>::takeFirst() { - N *value = *_first; + N *value = _first.data(); if (value) { _first = next(value); value->*nextMember = nullptr; @@ -146,85 +107,57 @@ N *QForwardFieldList<N, nextMember>::takeFirst() return value; } -template<class N, N *N::*nextMember> -void QForwardFieldList<N, nextMember>::prepend(N *v) +template<class N, N *N::*nextMember, typename Tag> +void QForwardFieldList<N, nextMember, Tag>::prepend(N *v) { Q_ASSERT(v->*nextMember == nullptr); - v->*nextMember = *_first; + v->*nextMember = _first.data(); _first = v; } -template<class N, N *N::*nextMember> -bool QForwardFieldList<N, nextMember>::isEmpty() const +template<class N, N *N::*nextMember, typename Tag> +template <typename OtherTag> +void QForwardFieldList<N, nextMember, Tag>::copyAndClearPrepend(QForwardFieldList<N, nextMember, OtherTag> &o) { - return _first.isNull(); -} - -template<class N, N *N::*nextMember> -bool QForwardFieldList<N, nextMember>::isOne() const -{ - return *_first && _first->*nextMember == 0; -} - -template<class N, N *N::*nextMember> -bool QForwardFieldList<N, nextMember>::isMany() const -{ - return *_first && _first->*nextMember != 0; -} - -template<class N, N *N::*nextMember> -N *QForwardFieldList<N, nextMember>::next(N *v) -{ - Q_ASSERT(v); - return v->*nextMember; -} - -template<class N, N *N::*nextMember> -bool QForwardFieldList<N, nextMember>::flag() const -{ - return _first.flag(); -} - -template<class N, N *N::*nextMember> -void QForwardFieldList<N, nextMember>::setFlag() -{ - _first.setFlag(); + _first = nullptr; + while (N *n = o.takeFirst()) prepend(n); } -template<class N, N *N::*nextMember> -void QForwardFieldList<N, nextMember>::clearFlag() +template<class N, N *N::*nextMember, typename Tag> +bool QForwardFieldList<N, nextMember, Tag>::isEmpty() const { - _first.clearFlag(); + return _first.isNull(); } -template<class N, N *N::*nextMember> -void QForwardFieldList<N, nextMember>::setFlagValue(bool v) +template<class N, N *N::*nextMember, typename Tag> +bool QForwardFieldList<N, nextMember, Tag>::isOne() const { - _first.setFlagValue(v); + return _first.data() && _first->*nextMember == 0; } -template<class N, N *N::*nextMember> -bool QForwardFieldList<N, nextMember>::flag2() const +template<class N, N *N::*nextMember, typename Tag> +bool QForwardFieldList<N, nextMember, Tag>::isMany() const { - return _first.flag2(); + return _first.data() && _first->*nextMember != 0; } -template<class N, N *N::*nextMember> -void QForwardFieldList<N, nextMember>::setFlag2() +template<class N, N *N::*nextMember, typename Tag> +N *QForwardFieldList<N, nextMember, Tag>::next(N *v) { - _first.setFlag2(); + Q_ASSERT(v); + return v->*nextMember; } -template<class N, N *N::*nextMember> -void QForwardFieldList<N, nextMember>::clearFlag2() +template<class N, N *N::*nextMember, typename Tag> +Tag QForwardFieldList<N, nextMember, Tag>::tag() const { - _first.clearFlag2(); + return _first.tag(); } -template<class N, N *N::*nextMember> -void QForwardFieldList<N, nextMember>::setFlag2Value(bool v) +template<class N, N *N::*nextMember, typename Tag> +void QForwardFieldList<N, nextMember, Tag>::setTag(Tag t) { - _first.setFlag2Value(v); + _first.setTag(t); } template<class N, N *N::*nextMember> @@ -380,7 +313,8 @@ void QFieldList<N, nextMember>::copyAndClear(QFieldList<N, nextMember> &o) } template<class N, N *N::*nextMember> -void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMember> &o) +template <typename Tag> +void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMember, Tag> &o) { _first = 0; _last = 0; @@ -389,7 +323,8 @@ void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMemb } template<class N, N *N::*nextMember> -void QFieldList<N, nextMember>::copyAndClearPrepend(QForwardFieldList<N, nextMember> &o) +template <typename Tag> +void QFieldList<N, nextMember>::copyAndClearPrepend(QForwardFieldList<N, nextMember, Tag> &o) { _first = nullptr; _last = nullptr; diff --git a/src/qml/qml/ftw/qfinitestack_p.h b/src/qml/qml/ftw/qfinitestack_p.h index 9a74199137..3e206e205f 100644 --- a/src/qml/qml/ftw/qfinitestack_p.h +++ b/src/qml/qml/ftw/qfinitestack_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QFINITESTACK_P_H #define QFINITESTACK_P_H @@ -51,7 +15,7 @@ // We mean it. // -#include <QtCore/qglobal.h> +#include <QtCore/private/qglobal_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/ftw/qflagpointer_p.h b/src/qml/qml/ftw/qflagpointer_p.h deleted file mode 100644 index 71b41cd30b..0000000000 --- a/src/qml/qml/ftw/qflagpointer_p.h +++ /dev/null @@ -1,350 +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 QFLAGPOINTER_P_H -#define QFLAGPOINTER_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> - -QT_BEGIN_NAMESPACE - -template<typename T> -class QFlagPointer { -public: - inline QFlagPointer(); - inline QFlagPointer(T *); - inline QFlagPointer(const QFlagPointer<T> &o); - - inline bool isNull() const; - - inline bool flag() const; - inline void setFlag(); - inline void clearFlag(); - inline void setFlagValue(bool); - - inline bool flag2() const; - inline void setFlag2(); - inline void clearFlag2(); - inline void setFlag2Value(bool); - - inline QFlagPointer<T> &operator=(const QFlagPointer &o); - inline QFlagPointer<T> &operator=(T *); - - inline T *operator->() const; - inline T *operator*() const; - - inline T *data() const; - - inline explicit operator bool() const; - -private: - quintptr ptr_value = 0; - - static const quintptr FlagBit = 0x1; - static const quintptr Flag2Bit = 0x2; - static const quintptr FlagsMask = FlagBit | Flag2Bit; -}; - -template<typename T, typename T2> -class QBiPointer { -public: - inline QBiPointer(); - inline QBiPointer(T *); - inline QBiPointer(T2 *); - inline QBiPointer(const QBiPointer<T, T2> &o); - - inline bool isNull() const; - inline bool isT1() const; - inline bool isT2() const; - - inline bool flag() const; - inline void setFlag(); - inline void clearFlag(); - inline void setFlagValue(bool); - - inline QBiPointer<T, T2> &operator=(const QBiPointer<T, T2> &o); - inline QBiPointer<T, T2> &operator=(T *); - inline QBiPointer<T, T2> &operator=(T2 *); - - inline T *asT1() const; - inline T2 *asT2() const; - -private: - quintptr ptr_value = 0; - - static const quintptr FlagBit = 0x1; - static const quintptr Flag2Bit = 0x2; - static const quintptr FlagsMask = FlagBit | Flag2Bit; -}; - -template<typename T> -QFlagPointer<T>::QFlagPointer() -{ -} - -template<typename T> -QFlagPointer<T>::QFlagPointer(T *v) -: ptr_value(quintptr(v)) -{ - Q_ASSERT((ptr_value & FlagsMask) == 0); -} - -template<typename T> -QFlagPointer<T>::QFlagPointer(const QFlagPointer<T> &o) -: ptr_value(o.ptr_value) -{ -} - -template<typename T> -bool QFlagPointer<T>::isNull() const -{ - return 0 == (ptr_value & (~FlagsMask)); -} - -template<typename T> -bool QFlagPointer<T>::flag() const -{ - return ptr_value & FlagBit; -} - -template<typename T> -void QFlagPointer<T>::setFlag() -{ - ptr_value |= FlagBit; -} - -template<typename T> -void QFlagPointer<T>::clearFlag() -{ - ptr_value &= ~FlagBit; -} - -template<typename T> -void QFlagPointer<T>::setFlagValue(bool v) -{ - if (v) setFlag(); - else clearFlag(); -} - -template<typename T> -bool QFlagPointer<T>::flag2() const -{ - return ptr_value & Flag2Bit; -} - -template<typename T> -void QFlagPointer<T>::setFlag2() -{ - ptr_value|= Flag2Bit; -} - -template<typename T> -void QFlagPointer<T>::clearFlag2() -{ - ptr_value &= ~Flag2Bit; -} - -template<typename T> -void QFlagPointer<T>::setFlag2Value(bool v) -{ - if (v) setFlag2(); - else clearFlag2(); -} - -template<typename T> -QFlagPointer<T> &QFlagPointer<T>::operator=(const QFlagPointer &o) -{ - ptr_value = o.ptr_value; - return *this; -} - -template<typename T> -QFlagPointer<T> &QFlagPointer<T>::operator=(T *o) -{ - Q_ASSERT((quintptr(o) & FlagsMask) == 0); - - ptr_value = quintptr(o) | (ptr_value & FlagsMask); - return *this; -} - -template<typename T> -T *QFlagPointer<T>::operator->() const -{ - return (T *)(ptr_value & ~FlagsMask); -} - -template<typename T> -T *QFlagPointer<T>::operator*() const -{ - return (T *)(ptr_value & ~FlagsMask); -} - -template<typename T> -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() -{ -} - -template<typename T, typename T2> -QBiPointer<T, T2>::QBiPointer(T *v) -: ptr_value(quintptr(v)) -{ - Q_ASSERT((quintptr(v) & FlagsMask) == 0); -} - -template<typename T, typename T2> -QBiPointer<T, T2>::QBiPointer(T2 *v) -: ptr_value(quintptr(v) | Flag2Bit) -{ - Q_ASSERT((quintptr(v) & FlagsMask) == 0); -} - -template<typename T, typename T2> -QBiPointer<T, T2>::QBiPointer(const QBiPointer<T, T2> &o) -: ptr_value(o.ptr_value) -{ -} - -template<typename T, typename T2> -bool QBiPointer<T, T2>::isNull() const -{ - return 0 == (ptr_value & (~FlagsMask)); -} - -template<typename T, typename T2> -bool QBiPointer<T, T2>::isT1() const -{ - return !(ptr_value & Flag2Bit); -} - -template<typename T, typename T2> -bool QBiPointer<T, T2>::isT2() const -{ - return ptr_value & Flag2Bit; -} - -template<typename T, typename T2> -bool QBiPointer<T, T2>::flag() const -{ - return ptr_value & FlagBit; -} - -template<typename T, typename T2> -void QBiPointer<T, T2>::setFlag() -{ - ptr_value |= FlagBit; -} - -template<typename T, typename T2> -void QBiPointer<T, T2>::clearFlag() -{ - ptr_value &= ~FlagBit; -} - -template<typename T, typename T2> -void QBiPointer<T, T2>::setFlagValue(bool v) -{ - if (v) setFlag(); - else clearFlag(); -} - -template<typename T, typename T2> -QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(const QBiPointer<T, T2> &o) -{ - ptr_value = o.ptr_value; - return *this; -} - -template<typename T, typename T2> -QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T *o) -{ - Q_ASSERT((quintptr(o) & FlagsMask) == 0); - - ptr_value = quintptr(o) | (ptr_value & FlagBit); - return *this; -} - -template<typename T, typename T2> -QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T2 *o) -{ - Q_ASSERT((quintptr(o) & FlagsMask) == 0); - - ptr_value = quintptr(o) | (ptr_value & FlagBit) | Flag2Bit; - return *this; -} - -template<typename T, typename T2> -T *QBiPointer<T, T2>::asT1() const -{ - Q_ASSERT(isT1()); - return (T *)(ptr_value & ~FlagsMask); -} - -template<typename T, typename T2> -T2 *QBiPointer<T, T2>::asT2() const -{ - Q_ASSERT(isT2()); - return (T2 *)(ptr_value & ~FlagsMask); -} - -QT_END_NAMESPACE - -#endif // QFLAGPOINTER_P_H diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp index 117670dbfc..b963bc7984 100644 --- a/src/qml/qml/ftw/qhashedstring.cpp +++ b/src/qml/qml/ftw/qhashedstring.cpp @@ -1,174 +1,9 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #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 { @@ -177,37 +12,41 @@ QHashedStringRef QHashedStringRef::mid(int offset, int length) const (length == -1 || (offset + length) > m_length)?(m_length - offset):length); } -bool QHashedStringRef::endsWith(const QString &s) const +QVector<QHashedStringRef> QHashedStringRef::split(const QChar sep) const { - return s.length() < m_length && - QHashedString::compare(s.constData(), m_data + m_length - s.length(), s.length()); + QVector<QHashedStringRef> ret; + auto curLength = 0; + auto curOffset = m_data; + for (int offset = 0; offset < m_length; ++offset) { + if (*(m_data + offset) == sep) { + ret.push_back({curOffset, curLength}); + curOffset = m_data + offset + 1; + curLength = 0; + } else { + ++curLength; + } + } + if (curLength > 0) + ret.push_back({curOffset, curLength}); + return ret; } -bool QHashedStringRef::startsWith(const QString &s) const +bool QHashedStringRef::endsWith(const QString &s) const { - return s.length() < m_length && - QHashedString::compare(s.constData(), m_data, s.length()); + QStringView view {m_data, m_length}; + return view.endsWith(s); } -static int findChar(const QChar *str, int len, QChar ch, int from) +bool QHashedStringRef::startsWith(const QString &s) const { - const ushort *s = (const ushort *)str; - ushort c = ch.unicode(); - if (from < 0) - from = qMax(from + len, 0); - if (from < len) { - const ushort *n = s + from - 1; - const ushort *e = s + len; - while (++n != e) - if (*n == c) - return n - s; - } - return -1; + QStringView view {m_data, m_length}; + return view.startsWith(s); } int QHashedStringRef::indexOf(const QChar &c, int from) const { - return findChar(m_data, m_length, c, from); + QStringView view {m_data, m_length}; + return view.indexOf(c, from); } QString QHashedStringRef::toString() const @@ -228,3 +67,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 2d6c25bdd3..78ce738f3b 100644 --- a/src/qml/qml/ftw/qhashedstring_p.h +++ b/src/qml/qml/ftw/qhashedstring_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QHASHEDSTRING_P_H #define QHASHEDSTRING_P_H @@ -55,19 +19,14 @@ #include <QtCore/qstring.h> #include <private/qv4string_p.h> -#include <private/qflagpointer_p.h> - #if defined(Q_OS_QNX) #include <stdlib.h> #endif QT_BEGIN_NAMESPACE -// Enable this to debug hash linking assumptions. -// #define QSTRINGHASH_LINK_DEBUG - class QHashedStringRef; -class Q_QML_PRIVATE_EXPORT QHashedString : public QString +class Q_QML_EXPORT QHashedString : public QString { public: inline QHashedString(); @@ -82,7 +41,6 @@ public: inline quint32 hash() const; inline quint32 existingHash() const; - static bool compare(const QChar *lhs, const QChar *rhs, int length); static inline bool compare(const QChar *lhs, const char *rhs, int length); static inline bool compare(const char *lhs, const char *rhs, int length); @@ -98,12 +56,12 @@ private: }; class QHashedCStringRef; -class Q_QML_PRIVATE_EXPORT QHashedStringRef +class Q_QML_EXPORT QHashedStringRef { public: inline QHashedStringRef(); inline QHashedStringRef(const QString &); - inline QHashedStringRef(const QStringRef &); + inline QHashedStringRef(QStringView); inline QHashedStringRef(const QChar *, int); inline QHashedStringRef(const QChar *, int, quint32); inline QHashedStringRef(const QHashedString &); @@ -128,6 +86,7 @@ public: bool endsWith(const QString &) const; int indexOf(const QChar &, int from=0) const; QHashedStringRef mid(int, int) const; + QVector<QHashedStringRef> split(const QChar sep) const; inline bool isEmpty() const; inline int length() const; @@ -147,7 +106,7 @@ private: mutable quint32 m_hash = 0; }; -class Q_AUTOTEST_EXPORT QHashedCStringRef +class QHashedCStringRef { public: inline QHashedCStringRef(); @@ -160,7 +119,7 @@ public: inline const char *constData() const; inline int length() const; - QString toUtf16() const; + Q_AUTOTEST_EXPORT QString toUtf16() const; inline int utf16length() const; inline void writeUtf16(QChar *) const; inline void writeUtf16(quint16 *) const; @@ -174,860 +133,12 @@ private: mutable quint32 m_hash = 0; }; -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; -#ifdef QSTRINGHASH_LINK_DEBUG - int linkCount = 0; -#endif - - struct IteratorData { - IteratorData() {} - QStringHashNode *n = nullptr; - void *p = nullptr; - }; - 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(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; - 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(nullptr), nodePool(nullptr), link(nullptr) -{ -} - -template<class T> -QStringHash<T>::QStringHash(const QStringHash<T> &other) -: newedNodes(nullptr), nodePool(nullptr), link(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> -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 = nullptr; - data.numBuckets = 0; - data.numBits = 0; - data.size = 0; - - newedNodes = nullptr; - nodePool = nullptr; - link = 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> -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 = 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; - } - - if (node == nullptr && 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 = nullptr; - if (newedNodes) - n = newedNodes; - else if (nodePool && nodePool->used) - n = nodePool->nodes + nodePool->used - 1; - - if (n == nullptr && 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?nullptr: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]: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<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: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> -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; -}; - -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) +inline size_t qHash(const QHashedString &string) { return uint(string.hash()); } -inline uint qHash(const QHashedStringRef &string) +inline size_t qHash(const QHashedStringRef &string) { return uint(string.hash()); } @@ -1067,9 +178,10 @@ bool QHashedString::operator==(const QHashedString &string) const bool QHashedString::operator==(const QHashedStringRef &string) const { - return length() == string.m_length && - (string.m_hash == m_hash || !string.m_hash || !m_hash) && - QHashedString::compare(constData(), string.m_data, string.m_length); + if (m_hash && string.m_hash && m_hash != string.m_hash) + return false; + QStringView otherView {string.m_data, string.m_length}; + return static_cast<const QString &>(*this) == otherView; } quint32 QHashedString::hash() const @@ -1087,14 +199,18 @@ QHashedStringRef::QHashedStringRef() { } +// QHashedStringRef is meant for identifiers, property names, etc. +// Those should alsways be smaller than std::numeric_limits<int>::max()) QHashedStringRef::QHashedStringRef(const QString &str) -: m_data(str.constData()), m_length(str.length()), m_hash(0) +: m_data(str.constData()), m_length(int(str.size())), m_hash(0) { + Q_ASSERT(str.size() <= std::numeric_limits<int>::max()); } -QHashedStringRef::QHashedStringRef(const QStringRef &str) -: m_data(str.constData()), m_length(str.length()), m_hash(0) +QHashedStringRef::QHashedStringRef(QStringView str) +: m_data(str.constData()), m_length(int(str.size())), m_hash(0) { + Q_ASSERT(str.size() <= std::numeric_limits<int>::max()); } QHashedStringRef::QHashedStringRef(const QChar *data, int length) @@ -1108,8 +224,9 @@ QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash) } QHashedStringRef::QHashedStringRef(const QHashedString &string) -: m_data(string.constData()), m_length(string.length()), m_hash(string.m_hash) +: m_data(string.constData()), m_length(int(string.size())), m_hash(string.m_hash) { + Q_ASSERT(string.size() <= std::numeric_limits<int>::max()); } QHashedStringRef::QHashedStringRef(const QHashedStringRef &string) @@ -1127,22 +244,26 @@ QHashedStringRef &QHashedStringRef::operator=(const QHashedStringRef &o) bool QHashedStringRef::operator==(const QString &string) const { - return m_length == string.length() && - QHashedString::compare(string.constData(), m_data, m_length); + QStringView view {m_data, m_length}; + return view == string; } bool QHashedStringRef::operator==(const QHashedString &string) const { - return m_length == string.length() && - (m_hash == string.m_hash || !m_hash || !string.m_hash) && - QHashedString::compare(string.constData(), m_data, m_length); + if (m_hash && string.m_hash && m_hash != string.m_hash) + return false; + QStringView view {m_data, m_length}; + QStringView otherView {string.constData(), string.size()}; + return view == otherView; } bool QHashedStringRef::operator==(const QHashedStringRef &string) const { - return m_length == string.m_length && - (m_hash == string.m_hash || !m_hash || !string.m_hash) && - QHashedString::compare(string.m_data, m_data, m_length); + if (m_hash && string.m_hash && m_hash != string.m_hash) + return false; + QStringView view {m_data, m_length}; + QStringView otherView {string.m_data, string.m_length}; + return view == otherView; } bool QHashedStringRef::operator==(const QHashedCStringRef &string) const @@ -1154,29 +275,22 @@ bool QHashedStringRef::operator==(const QHashedCStringRef &string) const bool QHashedStringRef::operator!=(const QString &string) const { - return m_length != string.length() || - !QHashedString::compare(string.constData(), m_data, m_length); + return !(*this == string); } bool QHashedStringRef::operator!=(const QHashedString &string) const { - return m_length != string.length() || - (m_hash != string.m_hash && m_hash && string.m_hash) || - !QHashedString::compare(string.constData(), m_data, m_length); + return !(*this == string); } bool QHashedStringRef::operator!=(const QHashedStringRef &string) const { - return m_length != string.m_length || - (m_hash != string.m_hash && m_hash && string.m_hash) || - QHashedString::compare(string.m_data, m_data, m_length); + return !(*this == string); } bool QHashedStringRef::operator!=(const QHashedCStringRef &string) const { - return m_length != string.m_length || - (m_hash != string.m_hash && m_hash && string.m_hash) || - QHashedString::compare(m_data, string.m_data, m_length); + return !(*this == string); } QChar *QHashedStringRef::data() @@ -1302,6 +416,7 @@ bool QHashedString::compare(const char *lhs, const char *rhs, int length) return 0 == ::memcmp(lhs, rhs, length); } + quint32 QHashedString::stringHash(const QChar *data, int length) { return QV4::String::createHashValue(data, length, nullptr); @@ -1314,7 +429,12 @@ quint32 QHashedString::stringHash(const char *data, int length) void QHashedString::computeHash() const { - m_hash = stringHash(constData(), length()); + m_hash = stringHash(constData(), int(size())); +} + +namespace QtPrivate { +inline QString asString(const QHashedCStringRef &ref) { return ref.toUtf16(); } +inline QString asString(const QHashedStringRef &ref) { return ref.toString(); } } QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qintrusivelist.cpp b/src/qml/qml/ftw/qintrusivelist.cpp index eb337a4de0..a0a1ddb470 100644 --- a/src/qml/qml/ftw/qintrusivelist.cpp +++ b/src/qml/qml/ftw/qintrusivelist.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qintrusivelist_p.h" @@ -150,6 +114,10 @@ Returns an STL-style iterator pointing to the imaginary item after the last item Remove the current object from the list, and return an iterator to the next element. */ +/*! + \class QIntrusiveListNode + \internal +*/ /*! \fn QIntrusiveListNode::QIntrusiveListNode() diff --git a/src/qml/qml/ftw/qintrusivelist_p.h b/src/qml/qml/ftw/qintrusivelist_p.h index 8992be9f93..1170370fae 100644 --- a/src/qml/qml/ftw/qintrusivelist_p.h +++ b/src/qml/qml/ftw/qintrusivelist_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QINTRUSIVELIST_P_H #define QINTRUSIVELIST_P_H @@ -51,220 +15,144 @@ // We mean it. // -#include <QtCore/qglobal.h> +#include <QtCore/private/qglobal_p.h> QT_BEGIN_NAMESPACE -class QIntrusiveListNode; -template<class N, QIntrusiveListNode N::*member> -class QIntrusiveList +class QIntrusiveListNode { public: - inline QIntrusiveList(); - inline ~QIntrusiveList(); - - inline bool isEmpty() const; - inline void insert(N *n); - inline void remove(N *n); - inline bool contains(N *) const; - - class iterator { - public: - inline iterator(); - inline iterator(N *value); - - inline N *operator*() const; - inline N *operator->() const; - inline bool operator==(const iterator &other) const; - inline bool operator!=(const iterator &other) const; - inline iterator &operator++(); - - inline iterator &erase(); - - private: - N *_value; - }; - typedef iterator Iterator; - - inline N *first() const; - static inline N *next(N *current); + ~QIntrusiveListNode() { remove(); } + + void remove() + { + if (_prev) *_prev = _next; + if (_next) _next->_prev = _prev; + _prev = nullptr; + _next = nullptr; + } - inline iterator begin(); - inline iterator end(); + bool isInList() const { return _prev != nullptr; } private: - static inline N *nodeToN(QIntrusiveListNode *node); - - QIntrusiveListNode *__first = nullptr; -}; - -class QIntrusiveListNode -{ -public: - inline QIntrusiveListNode(); - inline ~QIntrusiveListNode(); - - inline void remove(); - inline bool isInList() const; + template<class N, QIntrusiveListNode N::*member> + friend class QIntrusiveList; QIntrusiveListNode *_next = nullptr; QIntrusiveListNode**_prev = nullptr; }; template<class N, QIntrusiveListNode N::*member> -QIntrusiveList<N, member>::iterator::iterator() -: _value(nullptr) -{ -} - -template<class N, QIntrusiveListNode N::*member> -QIntrusiveList<N, member>::iterator::iterator(N *value) -: _value(value) -{ -} - -template<class N, QIntrusiveListNode N::*member> -N *QIntrusiveList<N, member>::iterator::operator*() const -{ - return _value; -} - -template<class N, QIntrusiveListNode N::*member> -N *QIntrusiveList<N, member>::iterator::operator->() const -{ - return _value; -} - -template<class N, QIntrusiveListNode N::*member> -bool QIntrusiveList<N, member>::iterator::operator==(const iterator &other) const -{ - return other._value == _value; -} - -template<class N, QIntrusiveListNode N::*member> -bool QIntrusiveList<N, member>::iterator::operator!=(const iterator &other) const -{ - return other._value != _value; -} - -template<class N, QIntrusiveListNode N::*member> -typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::operator++() -{ - _value = QIntrusiveList<N, member>::next(_value); - return *this; -} - -template<class N, QIntrusiveListNode N::*member> -typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::erase() +class QIntrusiveList { - N *old = _value; - _value = QIntrusiveList<N, member>::next(_value); - (old->*member).remove(); - return *this; -} +private: + template<typename O> + class iterator_impl { + public: + iterator_impl() = default; + iterator_impl(O value) : _value(value) {} + + O operator*() const { return _value; } + O operator->() const { return _value; } + bool operator==(const iterator_impl &other) const { return other._value == _value; } + bool operator!=(const iterator_impl &other) const { return other._value != _value; } + iterator_impl &operator++() + { + _value = QIntrusiveList<N, member>::next(_value); + return *this; + } + + protected: + O _value = nullptr; + }; -template<class N, QIntrusiveListNode N::*member> -QIntrusiveList<N, member>::QIntrusiveList() +public: + class iterator : public iterator_impl<N *> + { + public: + iterator() = default; + iterator(N *value) : iterator_impl<N *>(value) {} + + iterator &erase() + { + N *old = this->_value; + this->_value = QIntrusiveList<N, member>::next(this->_value); + (old->*member).remove(); + return *this; + } + }; -{ -} + using const_iterator = iterator_impl<const N *>; -template<class N, QIntrusiveListNode N::*member> -QIntrusiveList<N, member>::~QIntrusiveList() -{ - while (__first) __first->remove(); -} + using Iterator = iterator; + using ConstIterator = const_iterator; -template<class N, QIntrusiveListNode N::*member> -bool QIntrusiveList<N, member>::isEmpty() const -{ - return __first == nullptr; -} + ~QIntrusiveList() { while (__first) __first->remove(); } -template<class N, QIntrusiveListNode N::*member> -void QIntrusiveList<N, member>::insert(N *n) -{ - QIntrusiveListNode *nnode = &(n->*member); - nnode->remove(); + bool isEmpty() const { return __first == nullptr; } - nnode->_next = __first; - if (nnode->_next) nnode->_next->_prev = &nnode->_next; - __first = nnode; - nnode->_prev = &__first; -} + void insert(N *n) + { + QIntrusiveListNode *nnode = &(n->*member); + nnode->remove(); -template<class N, QIntrusiveListNode N::*member> -void QIntrusiveList<N, member>::remove(N *n) -{ - QIntrusiveListNode *nnode = &(n->*member); - nnode->remove(); -} + nnode->_next = __first; + if (nnode->_next) nnode->_next->_prev = &nnode->_next; + __first = nnode; + nnode->_prev = &__first; + } -template<class N, QIntrusiveListNode N::*member> -bool QIntrusiveList<N, member>::contains(N *n) const -{ - QIntrusiveListNode *nnode = __first; - while (nnode) { - if (nodeToN(nnode) == n) - return true; - nnode = nnode->_next; + void remove(N *n) + { + QIntrusiveListNode *nnode = &(n->*member); + nnode->remove(); } - return false; -} -template<class N, QIntrusiveListNode N::*member> -N *QIntrusiveList<N, member>::first() const -{ - return __first?nodeToN(__first):nullptr; -} + bool contains(const N *n) const + { + QIntrusiveListNode *nnode = __first; + while (nnode) { + if (nodeToN(nnode) == n) + return true; + nnode = nnode->_next; + } + return false; + } -template<class N, QIntrusiveListNode N::*member> -N *QIntrusiveList<N, member>::next(N *current) -{ - QIntrusiveListNode *nextnode = (current->*member)._next; - N *nextstruct = nextnode?nodeToN(nextnode):nullptr; - return nextstruct; -} + const N *first() const { return __first ? nodeToN(__first) : nullptr; } + N *first() { return __first ? nodeToN(__first) : nullptr; } -template<class N, QIntrusiveListNode N::*member> -typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::begin() -{ - return __first?iterator(nodeToN(__first)):iterator(); -} + template<typename O> + static O next(O current) + { + QIntrusiveListNode *nextnode = (current->*member)._next; + return nextnode ? nodeToN(nextnode) : nullptr; + } -template<class N, QIntrusiveListNode N::*member> -typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::end() -{ - return iterator(); -} + iterator begin() { return __first ? iterator(nodeToN(__first)) : iterator(); } + iterator end() { return iterator(); } -template<class N, QIntrusiveListNode N::*member> -N *QIntrusiveList<N, member>::nodeToN(QIntrusiveListNode *node) -{ - return (N *)((char *)node - ((char *)&(((N *)nullptr)->*member) - (char *)nullptr)); -} + const_iterator begin() const + { + return __first ? const_iterator(nodeToN(__first)) : const_iterator(); + } -QIntrusiveListNode::QIntrusiveListNode() -{ -} + const_iterator end() const { return const_iterator(); } -QIntrusiveListNode::~QIntrusiveListNode() -{ - remove(); -} +private: -void QIntrusiveListNode::remove() -{ - if (_prev) *_prev = _next; - if (_next) _next->_prev = _prev; - _prev = nullptr; - _next = nullptr; -} + static N *nodeToN(QIntrusiveListNode *node) + { + QT_WARNING_PUSH +#if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1300 + QT_WARNING_DISABLE_CLANG("-Wnull-pointer-subtraction") +#endif + return (N *)((char *)node - ((char *)&(((N *)nullptr)->*member) - (char *)nullptr)); + QT_WARNING_POP + } -bool QIntrusiveListNode::isInList() const -{ - return _prev != nullptr; -} + QIntrusiveListNode *__first = nullptr; +}; QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qlazilyallocated_p.h b/src/qml/qml/ftw/qlazilyallocated_p.h index 9073e41558..81f6ab7e89 100644 --- a/src/qml/qml/ftw/qlazilyallocated_p.h +++ b/src/qml/qml/ftw/qlazilyallocated_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QLAZILYALLOCATED_P_H #define QLAZILYALLOCATED_P_H @@ -51,13 +15,12 @@ // We mean it. // -#include <QtCore/qglobal.h> - -#include <private/qflagpointer_p.h> +#include <QtCore/private/qglobal_p.h> +#include <QtCore/qtaggedpointer.h> QT_BEGIN_NAMESPACE -template<typename T> +template<typename T, typename Tag = typename QtPrivate::TagInfo<T>::TagType> class QLazilyAllocated { public: inline QLazilyAllocated(); @@ -70,73 +33,59 @@ public: inline T &value(); inline const T &value() const; - inline bool flag() const; - inline void setFlag(); - inline void clearFlag(); - inline void setFlagValue(bool); + inline Tag tag() const; + inline void setTag(Tag t); private: - mutable QFlagPointer<T> d; + mutable QTaggedPointer<T, Tag> d; }; -template<typename T> -QLazilyAllocated<T>::QLazilyAllocated() +template<typename T, typename Tag> +QLazilyAllocated<T, Tag>::QLazilyAllocated() { } -template<typename T> -QLazilyAllocated<T>::~QLazilyAllocated() +template<typename T, typename Tag> +QLazilyAllocated<T, Tag>::~QLazilyAllocated() { - delete *d; + delete d.data(); } -template<typename T> -bool QLazilyAllocated<T>::isAllocated() const +template<typename T, typename Tag> +bool QLazilyAllocated<T, Tag>::isAllocated() const { return !d.isNull(); } -template<typename T> -T &QLazilyAllocated<T>::value() +template<typename T, typename Tag> +T &QLazilyAllocated<T, Tag>::value() { if (d.isNull()) d = new T; - return *(*d); + return *d; } -template<typename T> -const T &QLazilyAllocated<T>::value() const +template<typename T, typename Tag> +const T &QLazilyAllocated<T, Tag>::value() const { if (d.isNull()) d = new T; - return *(*d); -} - -template<typename T> -T *QLazilyAllocated<T>::operator->() const -{ return *d; } -template<typename T> -bool QLazilyAllocated<T>::flag() const -{ - return d.flag(); -} - -template<typename T> -void QLazilyAllocated<T>::setFlag() +template<typename T, typename Tag> +T *QLazilyAllocated<T, Tag>::operator->() const { - d.setFlag(); + return d.data(); } -template<typename T> -void QLazilyAllocated<T>::clearFlag() +template<typename T, typename Tag> +Tag QLazilyAllocated<T, Tag>::tag() const { - d.clearFlag(); + return d.tag(); } -template<typename T> -void QLazilyAllocated<T>::setFlagValue(bool v) +template<typename T, typename Tag> +void QLazilyAllocated<T, Tag>::setTag(Tag t) { - d.setFlagValue(v); + d.setTag(t); } 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..a2309db717 --- /dev/null +++ b/src/qml/qml/ftw/qlinkedstringhash_p.h @@ -0,0 +1,202 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#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.data()))) { + 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 b2fb481793..6508071105 100644 --- a/src/qml/qml/ftw/qpodvector_p.h +++ b/src/qml/qml/ftw/qpodvector_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QPODVECTOR_P_H #define QPODVECTOR_P_H @@ -51,7 +15,7 @@ // We mean it. // -#include <QtCore/qglobal.h> +#include <QtCore/private/qglobal_p.h> #include <QDebug> QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/ftw/qprimefornumbits_p.h b/src/qml/qml/ftw/qprimefornumbits_p.h new file mode 100644 index 0000000000..82c9ea023e --- /dev/null +++ b/src/qml/qml/ftw/qprimefornumbits_p.h @@ -0,0 +1,44 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QPRIMEFORNUMBITS_P_H +#define QPRIMEFORNUMBITS_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/qtqmlglobal_p.h> + +QT_BEGIN_NAMESPACE + +/* + 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 qPrimeForNumBits() function returns the prime associated to a + power of two. For example, qPrimeForNumBits(8) returns 257. +*/ + +inline int qPrimeForNumBits(int numBits) +{ + static constexpr 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 + }; + + return (1 << numBits) + prime_deltas[numBits]; +} + +QT_END_NAMESPACE + +#endif // QPRIMEFORNUMBITS_P_H diff --git a/src/qml/qml/ftw/qqmlnullablevalue_p.h b/src/qml/qml/ftw/qqmlnullablevalue_p.h index 5b3d2fc456..62899e4644 100644 --- a/src/qml/qml/ftw/qqmlnullablevalue_p.h +++ b/src/qml/qml/ftw/qqmlnullablevalue_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QQMLNULLABLEVALUE_P_H #define QQMLNULLABLEVALUE_P_H @@ -51,27 +15,76 @@ // We mean it. // +#include <QtCore/private/qglobal_p.h> + QT_BEGIN_NAMESPACE template<typename T> struct QQmlNullableValue { - QQmlNullableValue() - : value(T()) {} + QQmlNullableValue() = default; + QQmlNullableValue(const QQmlNullableValue<T> &o) - : isNull(o.isNull), value(o.value) {} + : m_value(o.m_value) + , m_isNull(o.m_isNull) + {} + + QQmlNullableValue(QQmlNullableValue<T> &&o) noexcept + : m_value(std::move(o.m_value)) + , m_isNull(std::exchange(o.m_isNull, true)) + {} + QQmlNullableValue(const T &t) - : isNull(false), value(t) {} - QQmlNullableValue<T> &operator=(const T &t) - { isNull = false; value = t; return *this; } + : m_value(t) + , m_isNull(false) + {} + + QQmlNullableValue(T &&t) noexcept + : m_value(std::move(t)) + , m_isNull(false) + {} + QQmlNullableValue<T> &operator=(const QQmlNullableValue<T> &o) - { isNull = o.isNull; value = o.value; return *this; } - operator T() const { return value; } + { + if (&o != this) { + m_value = o.m_value; + m_isNull = o.m_isNull; + } + return *this; + } + + QQmlNullableValue<T> &operator=(QQmlNullableValue<T> &&o) noexcept + { + if (&o != this) { + m_value = std::move(o.m_value); + m_isNull = std::exchange(o.m_isNull, true); + } + return *this; + } + + QQmlNullableValue<T> &operator=(const T &t) + { + m_value = t; + m_isNull = false; + return *this; + } + + QQmlNullableValue<T> &operator=(T &&t) noexcept + { + m_value = std::move(t); + m_isNull = false; + return *this; + } + + const T &value() const { return m_value; } + operator T() const { return m_value; } + + void invalidate() { m_isNull = true; } + bool isValid() const { return !m_isNull; } - void invalidate() { isNull = true; } - bool isValid() const { return !isNull; } - bool isNull = true; - T value; +private: + T m_value = T(); + bool m_isNull = true; }; QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h index d32a08e0f5..e7616915eb 100644 --- a/src/qml/qml/ftw/qqmlrefcount_p.h +++ b/src/qml/qml/ftw/qqmlrefcount_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QQMLREFCOUNT_P_H #define QQMLREFCOUNT_P_H @@ -57,21 +21,32 @@ QT_BEGIN_NAMESPACE +template <typename T> +class QQmlRefCounted; -class Q_QML_PRIVATE_EXPORT QQmlRefCount +class QQmlRefCount { + Q_DISABLE_COPY_MOVE(QQmlRefCount) public: inline QQmlRefCount(); - inline virtual ~QQmlRefCount(); - inline void addref(); - inline void release(); + inline void addref() const; inline int count() const; -protected: - inline virtual void destroy(); +private: + inline ~QQmlRefCount(); + template <typename T> friend class QQmlRefCounted; private: - QAtomicInt refCount; + mutable QAtomicInt refCount; +}; + +template <typename T> +class QQmlRefCounted : public QQmlRefCount +{ +public: + inline void release() const; +protected: + inline ~QQmlRefCounted(); }; template<class T> @@ -82,14 +57,16 @@ public: AddRef, Adopt }; - inline QQmlRefPointer(); - inline QQmlRefPointer(T *, Mode m = AddRef); - inline QQmlRefPointer(const QQmlRefPointer<T> &); - inline QQmlRefPointer(QQmlRefPointer<T> &&); + Q_NODISCARD_CTOR inline QQmlRefPointer() noexcept; + Q_NODISCARD_CTOR inline QQmlRefPointer(T *, Mode m = AddRef); + Q_NODISCARD_CTOR inline QQmlRefPointer(const QQmlRefPointer &); + Q_NODISCARD_CTOR inline QQmlRefPointer(QQmlRefPointer &&) noexcept; inline ~QQmlRefPointer(); + void swap(QQmlRefPointer &other) noexcept { qt_ptr_swap(o, other.o); } + inline QQmlRefPointer<T> &operator=(const QQmlRefPointer<T> &o); - inline QQmlRefPointer<T> &operator=(QQmlRefPointer<T> &&o); + inline QQmlRefPointer<T> &operator=(QQmlRefPointer<T> &&o) noexcept; inline bool isNull() const { return !o; } @@ -102,10 +79,54 @@ public: inline T* take() { T *res = o; o = nullptr; return res; } + friend bool operator==(const QQmlRefPointer &a, const QQmlRefPointer &b) noexcept + { + return a.o == b.o; + } + + friend bool operator!=(const QQmlRefPointer &a, const QQmlRefPointer &b) noexcept + { + return !(a == b); + } + + friend size_t qHash(const QQmlRefPointer &v, size_t seed = 0) noexcept + { + return qHash(v.o, seed); + } + + void reset(T *t = nullptr) + { + if (t == o) + return; + if (o) + o->release(); + if (t) + t->addref(); + o = t; + } + private: T *o; }; +namespace QQml { +/*! + \internal + Creates a QQmlRefPointer which takes ownership of a newly constructed T. + T must derive from QQmlRefCounted<T> (as we rely on an initial refcount of _1_). + T will be constructed by forwarding \a args to its constructor. + */ +template <typename T, typename ...Args> +QQmlRefPointer<T> makeRefPointer(Args&&... args) +{ + static_assert(std::is_base_of_v<QQmlRefCount, T>); + return QQmlRefPointer<T>(new T(std::forward<Args>(args)...), QQmlRefPointer<T>::Adopt); +} +} + +template <typename T> +Q_DECLARE_TYPEINFO_BODY(QQmlRefPointer<T>, Q_RELOCATABLE_TYPE); + QQmlRefCount::QQmlRefCount() : refCount(1) { @@ -113,34 +134,40 @@ QQmlRefCount::QQmlRefCount() QQmlRefCount::~QQmlRefCount() { - Q_ASSERT(refCount.load() == 0); + Q_ASSERT(refCount.loadRelaxed() == 0); } -void QQmlRefCount::addref() +void QQmlRefCount::addref() const { - Q_ASSERT(refCount.load() > 0); + Q_ASSERT(refCount.loadRelaxed() > 0); refCount.ref(); } -void QQmlRefCount::release() +template <typename T> +void QQmlRefCounted<T>::release() const { - Q_ASSERT(refCount.load() > 0); + static_assert(std::is_base_of_v<QQmlRefCounted, T>, + "QQmlRefCounted<T> must be a base of T (CRTP)"); + Q_ASSERT(refCount.loadRelaxed() > 0); if (!refCount.deref()) - destroy(); + delete static_cast<const T *>(this); } -int QQmlRefCount::count() const +template <typename T> +QQmlRefCounted<T>::~QQmlRefCounted() { - return refCount.load(); + static_assert(std::is_final_v<T> || std::has_virtual_destructor_v<T>, + "T must either be marked final or have a virtual dtor, " + "lest release() runs into UB."); } -void QQmlRefCount::destroy() +int QQmlRefCount::count() const { - delete this; + return refCount.loadRelaxed(); } template<class T> -QQmlRefPointer<T>::QQmlRefPointer() +QQmlRefPointer<T>::QQmlRefPointer() noexcept : o(nullptr) { } @@ -161,7 +188,7 @@ QQmlRefPointer<T>::QQmlRefPointer(const QQmlRefPointer<T> &other) } template <class T> -QQmlRefPointer<T>::QQmlRefPointer(QQmlRefPointer<T> &&other) +QQmlRefPointer<T>::QQmlRefPointer(QQmlRefPointer<T> &&other) noexcept : o(other.take()) { } @@ -175,17 +202,21 @@ QQmlRefPointer<T>::~QQmlRefPointer() template<class T> QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(const QQmlRefPointer<T> &other) { - if (other.o) other.o->addref(); - if (o) o->release(); + if (o == other.o) + return *this; + if (other.o) + other.o->addref(); + if (o) + o->release(); o = other.o; return *this; } template <class T> -QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(QQmlRefPointer<T> &&other) +QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(QQmlRefPointer<T> &&other) noexcept { QQmlRefPointer<T> m(std::move(other)); - qSwap(o, m.o); + swap(m); return *this; } diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp index 2ef1dc7e93..57f91b6b4d 100644 --- a/src/qml/qml/ftw/qqmlthread.cpp +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qqmlthread_p.h" @@ -47,6 +11,8 @@ #include <QtCore/qwaitcondition.h> #include <QtCore/qcoreapplication.h> +#include <QtCore/private/qthread_p.h> + QT_BEGIN_NAMESPACE class QQmlThreadPrivate : public QThread @@ -55,19 +21,16 @@ public: QQmlThreadPrivate(QQmlThread *); QQmlThread *q; - void run() override; - inline QMutex &mutex() { return _mutex; } inline void lock() { _mutex.lock(); } inline void unlock() { _mutex.unlock(); } inline void wait() { _wait.wait(&_mutex); } inline void wakeOne() { _wait.wakeOne(); } - inline void wakeAll() { _wait.wakeAll(); } - quint32 m_threadProcessing:1; // Set when the thread is processing messages - quint32 m_mainProcessing:1; // Set when the main thread is processing messages - quint32 m_shutdown:1; // Set by main thread to request a shutdown - quint32 m_mainThreadWaiting:1; // Set by main thread if it is waiting for the message queue to empty + bool m_threadProcessing; // Set when the thread is processing messages + bool m_mainProcessing; // Set when the main thread is processing messages + bool m_shutdown; // Set by main thread to request a shutdown + bool m_mainThreadWaiting; // Set by main thread if it is waiting for the message queue to empty typedef QFieldList<QQmlThread::Message, &QQmlThread::Message::next> MessageList; MessageList threadList; @@ -104,14 +67,18 @@ QQmlThreadPrivate::MainObject::MainObject(QQmlThreadPrivate *p) // Trigger mainEvent in main thread. Must be called from thread. void QQmlThreadPrivate::triggerMainEvent() { +#if QT_CONFIG(thread) Q_ASSERT(q->isThisThread()); +#endif QCoreApplication::postEvent(&m_mainObject, new QEvent(QEvent::User)); } // Trigger even in thread. Must be called from main thread. void QQmlThreadPrivate::triggerThreadEvent() { +#if QT_CONFIG(thread) Q_ASSERT(!q->isThisThread()); +#endif QCoreApplication::postEvent(this, new QEvent(QEvent::User)); } @@ -127,6 +94,9 @@ QQmlThreadPrivate::QQmlThreadPrivate(QQmlThread *q) m_mainThreadWaiting(false), mainSync(nullptr), m_mainObject(this) { setObjectName(QStringLiteral("QQmlThread")); + // This size is aligned with the recursion depth limits in the parser/codegen. In case of + // absurd content we want to hit the recursion checks instead of running out of stack. + setStackSize(8 * 1024 * 1024); } bool QQmlThreadPrivate::event(QEvent *e) @@ -136,19 +106,6 @@ bool QQmlThreadPrivate::event(QEvent *e) return QThread::event(e); } -void QQmlThreadPrivate::run() -{ - lock(); - - wakeOne(); - - unlock(); - - q->startupThread(); - exec(); - q->shutdownThread(); -} - void QQmlThreadPrivate::mainEvent() { lock(); @@ -181,13 +138,7 @@ void QQmlThreadPrivate::threadEvent() lock(); for (;;) { - if (m_shutdown) { - quit(); - wakeOne(); - unlock(); - - return; - } else if (!threadList.isEmpty()) { + if (!threadList.isEmpty()) { m_threadProcessing = true; QQmlThread::Message *message = threadList.first(); @@ -199,6 +150,12 @@ void QQmlThreadPrivate::threadEvent() lock(); delete threadList.takeFirst(); + } else if (m_shutdown) { + quit(); + wakeOne(); + unlock(); + + return; } else { wakeOne(); @@ -221,12 +178,13 @@ QQmlThread::~QQmlThread() delete d; } +/*! + \internal + Starts the actual worker thread. + */ void QQmlThread::startup() { - d->lock(); d->start(); - d->wait(); - d->unlock(); d->moveToThread(d); } @@ -235,28 +193,19 @@ void QQmlThread::shutdown() d->lock(); Q_ASSERT(!d->m_shutdown); - for (;;) { - if (d->mainSync || !d->mainList.isEmpty()) { - d->unlock(); - d->mainEvent(); - d->lock(); - } else if (!d->threadList.isEmpty()) { - d->wait(); - } else { - break; - } - } - d->m_shutdown = true; - if (QCoreApplication::closingDown()) { + + if (QCoreApplication::closingDown()) d->quit(); - } else { + else d->triggerThreadEvent(); - d->wait(); - } d->unlock(); d->QThread::wait(); + + // Discard all remaining messages. + // We don't need the lock anymore because the thread is dead. + discardMessages(); } bool QQmlThread::isShutdown() const @@ -284,11 +233,6 @@ void QQmlThread::wakeOne() d->wakeOne(); } -void QQmlThread::wakeAll() -{ - d->wakeAll(); -} - void QQmlThread::wait() { d->wait(); @@ -296,7 +240,7 @@ void QQmlThread::wait() bool QQmlThread::isThisThread() const { - return QThread::currentThread() == d; + return QThread::currentThreadId() == static_cast<QThreadPrivate *>(QObjectPrivate::get(d))->threadData.loadRelaxed()->threadId.loadRelaxed(); } QThread *QQmlThread::thread() const @@ -304,16 +248,6 @@ QThread *QQmlThread::thread() const return const_cast<QThread *>(static_cast<const QThread *>(d)); } -// Called when the thread starts. Do startup stuff in here. -void QQmlThread::startupThread() -{ -} - -// Called when the thread shuts down. Do cleanup in here. -void QQmlThread::shutdownThread() -{ -} - void QQmlThread::internalCallMethodInThread(Message *message) { #if !QT_CONFIG(thread) @@ -351,8 +285,21 @@ void QQmlThread::internalCallMethodInThread(Message *message) d->unlock(); } +/*! + \internal + \note This method needs to run in the worker/QQmlThread + + This runs \a message in the main thread, and blocks the + worker thread until the call has completed + */ void QQmlThread::internalCallMethodInMain(Message *message) { +#if !QT_CONFIG(thread) + message->call(this); + delete message; + return; +#endif + Q_ASSERT(isThisThread()); d->lock(); @@ -397,7 +344,9 @@ void QQmlThread::internalPostMethodToThread(Message *message) void QQmlThread::internalPostMethodToMain(Message *message) { +#if QT_CONFIG(thread) Q_ASSERT(isThisThread()); +#endif d->lock(); bool wasEmpty = d->mainList.isEmpty(); d->mainList.append(message); @@ -406,10 +355,22 @@ void QQmlThread::internalPostMethodToMain(Message *message) d->unlock(); } +/*! + \internal + \note This method must be called in the main thread + \warning This method requires that the lock is held! + + A call to this method will either: + - run a message requested to run synchronously on the main thread if there is one + (and return afterrwards), + - wait for the worker thread to notify it if the worker thread has pending work, + - or simply return if neither of the conditions above hold + */ void QQmlThread::waitForNextMessage() { +#if QT_CONFIG(thread) Q_ASSERT(!isThisThread()); - d->lock(); +#endif Q_ASSERT(d->m_mainThreadWaiting == false); d->m_mainThreadWaiting = true; @@ -429,8 +390,24 @@ void QQmlThread::waitForNextMessage() } d->m_mainThreadWaiting = false; - d->unlock(); } +/*! + \internal + \note This method must be called in the main thread + \warning This method requires that the lock is held! + + Clear all pending events, for either thread. +*/ +void QQmlThread::discardMessages() +{ + Q_ASSERT(!isThisThread()); + if (Message *mainSync = std::exchange(d->mainSync, nullptr)) + delete mainSync; + while (!d->mainList.isEmpty()) + delete d->mainList.takeFirst(); + while (!d->threadList.isEmpty()) + delete d->threadList.takeFirst(); +} QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h index b5c580fe8b..35f586f7e7 100644 --- a/src/qml/qml/ftw/qqmlthread_p.h +++ b/src/qml/qml/ftw/qqmlthread_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QQMLTHREAD_P_H #define QQMLTHREAD_P_H @@ -76,51 +40,31 @@ public: void lock(); void unlock(); void wakeOne(); - void wakeAll(); void wait(); QThread *thread() const; bool isThisThread() const; // Synchronously invoke a method in the thread - template<class O> - inline void callMethodInThread(void (O::*Member)()); - template<typename T, class V, class O> - inline void callMethodInThread(void (O::*Member)(V), const T &); - template<typename T, typename T2, class V, class V2, class O> - inline void callMethodInThread(void (O::*Member)(V, V2), const T &, const T2 &); + template<typename Method, typename ...Args> + void callMethodInThread(Method &&method, Args &&...args); // Synchronously invoke a method in the main thread. If the main thread is // blocked in a callMethodInThread() call, the call is made from within that // call. - template<class O> - inline void callMethodInMain(void (O::*Member)()); - template<typename T, class V, class O> - inline void callMethodInMain(void (O::*Member)(V), const T &); - template<typename T, typename T2, class V, class V2, class O> - inline void callMethodInMain(void (O::*Member)(V, V2), const T &, const T2 &); + template<typename Method, typename ...Args> + void callMethodInMain(Method &&method, Args &&...args); // Asynchronously invoke a method in the thread. - template<class O> - inline void postMethodToThread(void (O::*Member)()); - template<typename T, class V, class O> - inline void postMethodToThread(void (O::*Member)(V), const T &); - template<typename T, typename T2, class V, class V2, class O> - inline void postMethodToThread(void (O::*Member)(V, V2), const T &, const T2 &); + template<typename Method, typename ...Args> + void postMethodToThread(Method &&method, Args &&...args); // Asynchronously invoke a method in the main thread. - template<class O> - inline void postMethodToMain(void (O::*Member)()); - template<typename T, class V, class O> - inline void postMethodToMain(void (O::*Member)(V), const T &); - template<typename T, typename T2, class V, class V2, class O> - inline void postMethodToMain(void (O::*Member)(V, V2), const T &, const T2 &); + template<typename Method, typename ...Args> + void postMethodToMain(Method &&method, Args &&...args); void waitForNextMessage(); - -protected: - virtual void startupThread(); - virtual void shutdownThread(); + void discardMessages(); private: friend class QQmlThreadPrivate; @@ -131,6 +75,8 @@ private: Message *next; virtual void call(QQmlThread *) = 0; }; + template<typename Method, typename ...Args> + Message *createMessageFromMethod(Method &&method, Args &&...args); void internalCallMethodInThread(Message *); void internalCallMethodInMain(Message *); void internalPostMethodToThread(Message *); @@ -138,184 +84,58 @@ private: QQmlThreadPrivate *d; }; -template<class O> -void QQmlThread::callMethodInThread(void (O::*Member)()) -{ - struct I : public Message { - void (O::*Member)(); - I(void (O::*Member)()) : Member(Member) {} - void call(QQmlThread *thread) override { - O *me = static_cast<O *>(thread); - (me->*Member)(); - } - }; - internalCallMethodInThread(new I(Member)); -} - -template<typename T, class V, class O> -void QQmlThread::callMethodInThread(void (O::*Member)(V), const T &arg) -{ - struct I : public Message { - void (O::*Member)(V); - T arg; - I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {} - void call(QQmlThread *thread) override { - O *me = static_cast<O *>(thread); - (me->*Member)(arg); - } - }; - internalCallMethodInThread(new I(Member, arg)); -} - -template<typename T, typename T2, class V, class V2, class O> -void QQmlThread::callMethodInThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) -{ - struct I : public Message { - void (O::*Member)(V, V2); - T arg; - T2 arg2; - I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {} - void call(QQmlThread *thread) override { - O *me = static_cast<O *>(thread); - (me->*Member)(arg, arg2); - } - }; - internalCallMethodInThread(new I(Member, arg, arg2)); -} - -template<class O> -void QQmlThread::callMethodInMain(void (O::*Member)()) -{ - struct I : public Message { - void (O::*Member)(); - I(void (O::*Member)()) : Member(Member) {} - void call(QQmlThread *thread) override { - O *me = static_cast<O *>(thread); - (me->*Member)(); - } - }; - internalCallMethodInMain(new I(Member)); -} +namespace QtPrivate { +template <typename> struct member_function_traits; -template<typename T, class V, class O> -void QQmlThread::callMethodInMain(void (O::*Member)(V), const T &arg) +template <typename Return, typename Object, typename... Args> +struct member_function_traits<Return (Object::*)(Args...)> { - struct I : public Message { - void (O::*Member)(V); - T arg; - I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {} - void call(QQmlThread *thread) override { - O *me = static_cast<O *>(thread); - (me->*Member)(arg); - } - }; - internalCallMethodInMain(new I(Member, arg)); + using class_type = Object; +}; } -template<typename T, typename T2, class V, class V2, class O> -void QQmlThread::callMethodInMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) +template<typename Method, typename ...Args> +QQmlThread::Message *QQmlThread::createMessageFromMethod(Method &&method, Args &&...args) { struct I : public Message { - void (O::*Member)(V, V2); - T arg; - T2 arg2; - I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {} + Method m; + std::tuple<std::decay_t<Args>...> arguments; + I(Method &&method, Args&& ...args) : m(std::forward<Method>(method)), arguments(std::forward<Args>(args)...) {} void call(QQmlThread *thread) override { - O *me = static_cast<O *>(thread); - (me->*Member)(arg, arg2); + using class_type = typename QtPrivate::member_function_traits<Method>::class_type; + class_type *me = static_cast<class_type *>(thread); + std::apply(m, std::tuple_cat(std::make_tuple(me), arguments)); } }; - internalCallMethodInMain(new I(Member, arg, arg2)); + return new I(std::forward<Method>(method), std::forward<Args>(args)...); } -template<class O> -void QQmlThread::postMethodToThread(void (O::*Member)()) +template<typename Method, typename ...Args> +void QQmlThread::callMethodInMain(Method &&method, Args&& ...args) { - struct I : public Message { - void (O::*Member)(); - I(void (O::*Member)()) : Member(Member) {} - void call(QQmlThread *thread) override { - O *me = static_cast<O *>(thread); - (me->*Member)(); - } - }; - internalPostMethodToThread(new I(Member)); + Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...); + internalCallMethodInMain(m); } -template<typename T, class V, class O> -void QQmlThread::postMethodToThread(void (O::*Member)(V), const T &arg) +template<typename Method, typename ...Args> +void QQmlThread::callMethodInThread(Method &&method, Args&& ...args) { - struct I : public Message { - void (O::*Member)(V); - T arg; - I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {} - void call(QQmlThread *thread) override { - O *me = static_cast<O *>(thread); - (me->*Member)(arg); - } - }; - internalPostMethodToThread(new I(Member, arg)); + Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...); + internalCallMethodInThread(m); } -template<typename T, typename T2, class V, class V2, class O> -void QQmlThread::postMethodToThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) +template<typename Method, typename ...Args> +void QQmlThread::postMethodToThread(Method &&method, Args&& ...args) { - struct I : public Message { - void (O::*Member)(V, V2); - T arg; - T2 arg2; - I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {} - void call(QQmlThread *thread) override { - O *me = static_cast<O *>(thread); - (me->*Member)(arg, arg2); - } - }; - internalPostMethodToThread(new I(Member, arg, arg2)); + Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...); + internalPostMethodToThread(m); } -template<class O> -void QQmlThread::postMethodToMain(void (O::*Member)()) +template<typename Method, typename ...Args> +void QQmlThread::postMethodToMain(Method &&method, Args&& ...args) { - struct I : public Message { - void (O::*Member)(); - I(void (O::*Member)()) : Member(Member) {} - void call(QQmlThread *thread) override { - O *me = static_cast<O *>(thread); - (me->*Member)(); - } - }; - internalPostMethodToMain(new I(Member)); -} - -template<typename T, class V, class O> -void QQmlThread::postMethodToMain(void (O::*Member)(V), const T &arg) -{ - struct I : public Message { - void (O::*Member)(V); - T arg; - I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {} - void call(QQmlThread *thread) override { - O *me = static_cast<O *>(thread); - (me->*Member)(arg); - } - }; - internalPostMethodToMain(new I(Member, arg)); -} - -template<typename T, typename T2, class V, class V2, class O> -void QQmlThread::postMethodToMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) -{ - struct I : public Message { - void (O::*Member)(V, V2); - T arg; - T2 arg2; - I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {} - void call(QQmlThread *thread) override { - O *me = static_cast<O *>(thread); - (me->*Member)(arg, arg2); - } - }; - internalPostMethodToMain(new I(Member, arg, arg2)); + Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...); + internalPostMethodToMain(m); } QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qrecursionwatcher_p.h b/src/qml/qml/ftw/qrecursionwatcher_p.h index 56b714f922..668695877e 100644 --- a/src/qml/qml/ftw/qrecursionwatcher_p.h +++ b/src/qml/qml/ftw/qrecursionwatcher_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QRECURSIONWATCHER_P_H #define QRECURSIONWATCHER_P_H @@ -51,7 +15,7 @@ // We mean it. // -#include <QtCore/qglobal.h> +#include <QtCore/private/qglobal_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/ftw/qrecyclepool_p.h b/src/qml/qml/ftw/qrecyclepool_p.h index 39f4f88512..6661c88631 100644 --- a/src/qml/qml/ftw/qrecyclepool_p.h +++ b/src/qml/qml/ftw/qrecyclepool_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QRECYCLEPOOL_P_H #define QRECYCLEPOOL_P_H @@ -51,6 +15,10 @@ // We mean it. // +#include <QtCore/private/qglobal_p.h> + +#include <QtCore/q20memory.h> + QT_BEGIN_NAMESPACE #define QRECYCLEPOOLCOOKIE 0x33218ADF @@ -101,11 +69,8 @@ public: inline QRecyclePool(); inline ~QRecyclePool(); - inline T *New(); - template<typename T1> - inline T *New(const T1 &); - template<typename T1> - inline T *New(T1 &); + template<typename...Args> + [[nodiscard]] inline T *New(Args&&...args); static inline void Delete(T *); @@ -127,29 +92,10 @@ QRecyclePool<T, Step>::~QRecyclePool() } template<typename T, int Step> -T *QRecyclePool<T, Step>::New() -{ - T *rv = d->allocate(); - new (rv) T; - return rv; -} - -template<typename T, int Step> -template<typename T1> -T *QRecyclePool<T, Step>::New(const T1 &a) +template<typename...Args> +T *QRecyclePool<T, Step>::New(Args&&...args) { - T *rv = d->allocate(); - new (rv) T(a); - return rv; -} - -template<typename T, int Step> -template<typename T1> -T *QRecyclePool<T, Step>::New(T1 &a) -{ - T *rv = d->allocate(); - new (rv) T(a); - return rv; + return q20::construct_at(d->allocate(), std::forward<Args>(args)...); } template<typename T, int Step> diff --git a/src/qml/qml/ftw/qstringhash_p.h b/src/qml/qml/ftw/qstringhash_p.h new file mode 100644 index 0000000000..c431a4d6b3 --- /dev/null +++ b/src/qml/qml/ftw/qstringhash_p.h @@ -0,0 +1,803 @@ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#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> +#include <private/qprimefornumbits_p.h> + +#include <QtCore/qbytearray.h> +#include <QtCore/qstring.h> +#include <QtCore/qtaggedpointer.h> + +QT_BEGIN_NAMESPACE + +static inline QString::DataPointer &mutableStringData(const QHashedString &key) +{ + return const_cast<QHashedString &>(key).data_ptr(); +} + +class QStringHashData; +class QStringHashNode +{ +public: + QStringHashNode() + { + } + + QStringHashNode(const QHashedString &key) + : length(int(key.size())), hash(key.hash()), symbolId(0) + , arrayData(mutableStringData(key).d_ptr()) + , strData(mutableStringData(key).data()) + { + Q_ASSERT(key.size() <= std::numeric_limits<int>::max()); + if (arrayData) + arrayData->ref(); + setQString(true); + } + + 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), arrayData(o.arrayData) + { + setQString(o.isQString()); + if (isQString()) { + strData = o.strData; + if (arrayData) + arrayData->ref(); + } else { + ckey = o.ckey; + } + } + + ~QStringHashNode() + { + if (isQString() && arrayData && !arrayData->deref()) + QTypedArrayData<char16_t>::deallocate(arrayData); + } + + enum Tag { + NodeIsCString, + NodeIsQString + }; + + QTaggedPointer<QStringHashNode, Tag> next; + + qint32 length = 0; + quint32 hash = 0; + quint32 symbolId = 0; + + QTypedArrayData<char16_t> *arrayData = nullptr; + union { + const char *ckey = nullptr; + char16_t *strData; + }; + + inline QHashedString key() const + { + if (isQString()) { + if (arrayData) + arrayData->ref(); + return QHashedString(QString(QStringPrivate(arrayData, strData, length)), hash); + } + + return QHashedString(QString::fromLatin1(ckey, length), hash); + } + + bool isQString() const { return next.tag() == NodeIsQString; } + void setQString(bool v) { if (v) next.setTag(NodeIsQString); else next.setTag(NodeIsCString); } + + inline qsizetype size() const { return length; } + inline const char *cStrData() const { return ckey; } + inline const char16_t *utf16Data() const { return strData; } + + inline bool equals(const QV4::Value &string) const { + QString s = string.toQStringNoThrow(); + if (isQString()) { + return QStringView(utf16Data(), length) == 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()) { + return QStringView(utf16Data(), length) == string->toQString(); + } else { + return QLatin1String(cStrData(), length) == string->toQString(); + } + } + + inline bool equals(const QHashedStringRef &string) const { + return length == string.length() && + hash == string.hash() && + (isQString()? string == QStringView {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 QStringHashData +{ + Q_DISABLE_COPY_MOVE(QStringHashData) +public: + QStringHashData() = default; + ~QStringHashData() = default; + + /* + A QHash has initially around pow(2, MinNumBits) buckets. For + example, if MinNumBits is 4, it has 17 buckets. + */ + enum { MinNumBits = 4 }; + + QStringHashNode **buckets = nullptr; // life cycle managed by QStringHash + 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 bits) + { + numBits = qMax(short(MinNumBits), bits); + + int nb = qPrimeForNumBits(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 rehashToSize(int size) + { + short bits = qMax(short(MinNumBits), numBits); + while (qPrimeForNumBits(bits) < size) + bits++; + + if (bits > numBits) + rehashToBits(bits); + } + + void 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; + } +}; + +// 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<QStringView> { 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<QStringView>::Type hashedString(QStringView s) + { + Q_ASSERT(s.size() <= std::numeric_limits<int>::max()); + return QHashedStringRef(s.constData(), int(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<QLatin1StringView>::Type hashedString(QLatin1StringView s) + { + Q_ASSERT(s.size() <= std::numeric_limits<int>::max()); + return QHashedCStringRef(s.data(), int(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.size(); + node->hash = key.hash(); + node->arrayData = mutableStringData(key).d_ptr(); + node->strData = mutableStringData(key).data(); + if (node->arrayData) + node->arrayData->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; + rv->arrayData = o.arrayData; + if (o.isQString()) { + rv->strData = o.strData; + rv->setQString(true); + if (rv->arrayData) + rv->arrayData->ref(); + } 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.data(); + + 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 |