diff options
Diffstat (limited to 'src/qml/qml/ftw/qdoubleendedlist_p.h')
-rw-r--r-- | src/qml/qml/ftw/qdoubleendedlist_p.h | 256 |
1 files changed, 256 insertions, 0 deletions
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 |