blob: 102dd5053a1f327f4be4fdaac5ecc002b94f6aae [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2008-2012 NVIDIA Corporation.
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Quick 3D.
**
** $QT_BEGIN_LICENSE:GPL$
** 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 General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) 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.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-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSSGINVASIVELINKEDLIST_H
#define QSSGINVASIVELINKEDLIST_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 <QtQuick3DUtils/private/qtquick3dutilsglobal_p.h>
QT_BEGIN_NAMESPACE
// Used for singly linked list where
// items have either no head or tail ptr.
template<typename T>
struct QSSGNullOp
{
static void set(T &, T *) {}
static T *get(const T &) { return nullptr; }
};
template <typename T, T *T::*n>
struct QSSGListAccessorNext
{
static inline T *get(T &o) { return o.*n; }
static inline const T *get(const T &o) { return o.*n; }
static inline void set(T &o, T *next) { o.*n = next; }
};
template <typename T, T *T::*p>
struct QSSGListAccessorPrevious
{
static inline T *get(T &o) { return o.*p; }
static inline const T *get(const T &o) { return o.*p; }
static inline void set(T &o, T *next) { o.*p = next; }
};
// Base linked list without an included head or tail member.
template<typename T, typename HeadOp, typename TailOp>
struct QSSGInvasiveLinkListBase
{
inline T *tail(T *inObj) { return inObj ? TailOp::get(inObj) : nullptr; }
inline T *head(T *inObj) { return inObj ? HeadOp::get(inObj) : nullptr; }
inline const T *tail(const T *inObj) { return inObj ? TailOp::get(inObj) : nullptr; }
inline const T *head(const T *inObj) { return inObj ? HeadOp::get(inObj) : nullptr; }
void remove(T &inObj)
{
T *theHead = HeadOp::get(inObj);
T *theTail = TailOp::get(inObj);
if (theHead)
TailOp::set(*theHead, theTail);
if (theTail)
HeadOp::set(*theTail, theHead);
HeadOp::set(inObj, nullptr);
TailOp::set(inObj, nullptr);
}
void insert_after(T &inPosition, T &inObj)
{
T *theHead = &inPosition;
T *theTail = TailOp::get(inPosition);
insert_unsafe(theHead, theTail, inObj);
}
void insert_before(T &inPosition, T &inObj)
{
T *theHead = HeadOp::get(inPosition);
T *theTail = &inPosition;
insert_unsafe(theHead, theTail, inObj);
}
// The name here is intentionally named "unsafe" to discourage use
// with out knowing what it implies to call this function.
// In most cases this will be used to insert before and after a neighboring pair
// (see: insert_before()/_after), but it can also be convenient if you want to split
// up a list and retain the chain for the removed section.
void insert_unsafe(T *inHead, T *inTail, T &inObj)
{
if (inHead)
TailOp::set(*inHead, &inObj);
if (inTail)
HeadOp::set(*inTail, &inObj);
HeadOp::set(inObj, inHead);
TailOp::set(inObj, inTail);
}
};
template<typename T, typename TailOp>
struct QSSGLinkedListIterator
{
using Iterator = QSSGLinkedListIterator<T, TailOp>;
T *m_obj;
explicit QSSGLinkedListIterator(T *inObj = nullptr) : m_obj(inObj) {}
inline bool operator!=(const Iterator &inIter) const { return m_obj != inIter.m_obj; }
inline bool operator==(const Iterator &inIter) const { return m_obj == inIter.m_obj; }
Iterator &operator++()
{
if (m_obj)
m_obj = TailOp::get(*m_obj);
return *this;
}
Iterator &operator++(int)
{
Iterator retval(*this);
++(*this);
return retval;
}
T &operator*() { return *m_obj; }
T *operator->() { return m_obj; }
};
template<typename T, T *T::*Next>
struct QSSGInvasiveSingleLinkedList : public QSSGInvasiveLinkListBase<T, QSSGNullOp<T>, QSSGListAccessorNext<T, Next>>
{
using TailOp = QSSGListAccessorNext<T, Next>;
using List = QSSGInvasiveSingleLinkedList<T, Next>;
using BaseList = QSSGInvasiveLinkListBase<T, QSSGNullOp<T>, TailOp>;
using iterator = QSSGLinkedListIterator<T, TailOp>;
using const_iterator = iterator;
T *m_head = nullptr;
QSSGInvasiveSingleLinkedList() = default;
QSSGInvasiveSingleLinkedList(const List &inOther) : m_head(inOther.m_head) {}
List &operator=(const List &inOther)
{
m_head = inOther.m_head;
return *this;
}
inline T &front() const { return *m_head; }
void push_front(T &inObj)
{
if (m_head != nullptr)
BaseList::insert_before(*m_head, inObj);
m_head = &inObj;
}
void push_back(T &inObj)
{
if (m_head == nullptr)
m_head = &inObj;
else {
T *lastObj = nullptr;
for (iterator iter = begin(), endIter = end(); iter != endIter; ++iter)
lastObj = &(*iter);
Q_ASSERT(lastObj);
if (lastObj)
TailOp::set(*lastObj, &inObj);
}
}
void remove(T &inObj)
{
if (m_head == &inObj)
m_head = TailOp::get(inObj);
BaseList::remove(inObj);
}
inline bool empty() const { return m_head == nullptr; }
inline iterator begin() { return iterator(m_head); }
inline iterator end() { return iterator(nullptr); }
inline const_iterator begin() const { return iterator(m_head); }
inline const_iterator end() const { return iterator(nullptr); }
};
template<typename T, T *T::*Previous, T *T::*Next>
struct QSSGInvasiveLinkedList : public QSSGInvasiveLinkListBase<T, QSSGListAccessorPrevious<T, Previous>, QSSGListAccessorNext<T, Next>>
{
using HeadOp = QSSGListAccessorPrevious<T, Previous>;
using TailOp = QSSGListAccessorNext<T, Next>;
using List = QSSGInvasiveLinkedList<T, Previous, Next>;
using BaseList = QSSGInvasiveLinkListBase<T, HeadOp, TailOp>;
using iterator = QSSGLinkedListIterator<T, TailOp>;
using const_iterator = iterator;
using reverse_iterator = QSSGLinkedListIterator<T, HeadOp>;
using const_reverse_iterator = reverse_iterator;
T *m_head = nullptr;
T *m_tail = nullptr;
QSSGInvasiveLinkedList() = default;
QSSGInvasiveLinkedList(const List &inOther) : m_head(inOther.m_head), m_tail(inOther.m_tail) {}
List &operator=(const List &inOther)
{
m_head = inOther.m_head;
m_tail = inOther.m_tail;
return *this;
}
inline T &front() const
{
Q_ASSERT(m_head);
return *m_head;
}
inline T &back() const
{
Q_ASSERT(m_tail);
return *m_tail;
}
inline T *front_ptr() const { return m_head; }
inline T *back_ptr() const { return m_tail; }
void push_front(T &inObj)
{
if (m_head != nullptr)
BaseList::insert_before(*m_head, inObj);
m_head = &inObj;
if (m_tail == nullptr)
m_tail = &inObj;
}
void push_back(T &inObj)
{
if (m_tail != nullptr)
BaseList::insert_after(*m_tail, inObj);
m_tail = &inObj;
if (m_head == nullptr)
m_head = &inObj;
}
void remove(T &inObj)
{
if (m_head == &inObj)
m_head = TailOp::get(inObj);
if (m_tail == &inObj)
m_tail = HeadOp::get(inObj);
BaseList::remove(inObj);
}
inline bool empty() const { return m_head == nullptr; }
inline iterator begin() { return iterator(m_head); }
inline iterator end() { return iterator(nullptr); }
inline const_iterator begin() const { return iterator(m_head); }
inline const_iterator end() const { return iterator(nullptr); }
inline reverse_iterator rbegin() { return reverse_iterator(m_tail); }
inline reverse_iterator rend() { return reverse_iterator(nullptr); }
inline const_reverse_iterator rbegin() const { return reverse_iterator(m_tail); }
inline const_reverse_iterator rend() const { return reverse_iterator(nullptr); }
};
QT_END_NAMESPACE
#endif // QSSGINVASIVELINKEDLIST_H