aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/ftw/qdoubleendedlist_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/ftw/qdoubleendedlist_p.h')
-rw-r--r--src/qml/qml/ftw/qdoubleendedlist_p.h256
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