474 lines
12 KiB
C++
474 lines
12 KiB
C++
#ifndef QXTLINKEDTREE_H
|
|
/****************************************************************************
|
|
** Copyright (c) 2006 - 2011, the LibQxt project.
|
|
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions are met:
|
|
** * Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** * Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
** documentation and/or other materials provided with the distribution.
|
|
** * Neither the name of the LibQxt project nor the
|
|
** names of its contributors may be used to endorse or promote products
|
|
** derived from this software without specific prior written permission.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
**
|
|
** <http://libqxt.org> <foundation@libqxt.org>
|
|
*****************************************************************************/
|
|
|
|
#define QXTLINKEDTREE_H
|
|
|
|
#include <qxtglobal.h>
|
|
#include <qxtsharedprivate.h>
|
|
|
|
template<class T>
|
|
class QxtLinkedTree;
|
|
|
|
template<class T>
|
|
class QxtLinkedTreeIterator;
|
|
|
|
template<class T>
|
|
class QXT_CORE_EXPORT QxtLinkedTreeItem
|
|
{
|
|
public:
|
|
~QxtLinkedTreeItem()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
private:
|
|
QxtLinkedTreeItem(T tt)
|
|
{
|
|
t = tt;
|
|
next = 0;
|
|
previous = 0;
|
|
parent = 0;
|
|
child = 0;
|
|
childcount = 0;
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
if (child)
|
|
{
|
|
QxtLinkedTreeItem * c = child;
|
|
while (c)
|
|
{
|
|
QxtLinkedTreeItem * e = c;
|
|
c = c->next;
|
|
delete e;
|
|
}
|
|
child = 0;
|
|
}
|
|
}
|
|
|
|
friend class QxtLinkedTree<T>;
|
|
friend class QxtLinkedTreeIterator<T>;
|
|
QxtLinkedTreeItem * next;
|
|
QxtLinkedTreeItem * previous;
|
|
QxtLinkedTreeItem * parent;
|
|
QxtLinkedTreeItem * child;
|
|
int childcount;
|
|
|
|
T t;
|
|
///TODO: somehow notify all iterators when one deletes this. so they can be made invalid instead of undefined.
|
|
};
|
|
|
|
///FIXME: nested would be cooler but c++ has no typdefs with templates and doxygen doesn't undertsand nested templates
|
|
template<class T>
|
|
class QXT_CORE_EXPORT QxtLinkedTreeIterator
|
|
{
|
|
public:
|
|
QxtLinkedTreeIterator();
|
|
QxtLinkedTreeIterator(const QxtLinkedTreeIterator<T> & other);
|
|
QxtLinkedTreeIterator & operator= (const QxtLinkedTreeIterator<T> & other);
|
|
|
|
QxtLinkedTreeIterator parent() const;
|
|
QxtLinkedTreeIterator next() const;
|
|
QxtLinkedTreeIterator previous() const;
|
|
QxtLinkedTreeIterator child() const;
|
|
|
|
bool isValid() const;
|
|
int children() const;
|
|
|
|
T & operator*() const;
|
|
T * operator-> () const;
|
|
operator T() const;
|
|
|
|
QxtLinkedTreeIterator operator + (int j) const;
|
|
QxtLinkedTreeIterator & operator ++ ();
|
|
QxtLinkedTreeIterator operator ++ (int);
|
|
QxtLinkedTreeIterator & operator += (int j);
|
|
|
|
QxtLinkedTreeIterator operator - (int j) const;
|
|
QxtLinkedTreeIterator & operator -- ();
|
|
QxtLinkedTreeIterator operator -- (int);
|
|
QxtLinkedTreeIterator & operator -= (int j);
|
|
|
|
bool operator== (const QxtLinkedTreeIterator<T> & other) const;
|
|
bool operator!= (const QxtLinkedTreeIterator<T> & other) const;
|
|
|
|
QxtLinkedTreeIterator erase() ;
|
|
QxtLinkedTreeIterator append(const T & value);
|
|
QxtLinkedTreeIterator insert(int i, const T & value);
|
|
|
|
private:
|
|
friend class QxtLinkedTree<T>;
|
|
|
|
QxtLinkedTreeIterator(QxtLinkedTreeItem<T> * t);
|
|
QxtLinkedTreeItem<T> *item;
|
|
};
|
|
|
|
template<class T>
|
|
class QXT_CORE_EXPORT QxtLinkedTree
|
|
{
|
|
public:
|
|
|
|
QxtLinkedTree();
|
|
QxtLinkedTree(T t);
|
|
~QxtLinkedTree();
|
|
void clear();
|
|
QxtLinkedTreeIterator<T> root();
|
|
static QxtLinkedTreeIterator<T> fromVoid(void *) ;
|
|
static void * toVoid(QxtLinkedTreeIterator<T>) ;
|
|
|
|
#if 0
|
|
QxtLinkedTreeIterator insert(iterator before, const T & value);
|
|
#endif
|
|
|
|
private:
|
|
QxtSharedPrivate< QxtLinkedTreeItem<T> > qxt_d;
|
|
};
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T>::QxtLinkedTreeIterator()
|
|
{
|
|
item = 0;
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T>::QxtLinkedTreeIterator(const QxtLinkedTreeIterator<T> & other)
|
|
{
|
|
item = other.item;
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> & QxtLinkedTreeIterator<T>::operator= (const QxtLinkedTreeIterator<T> & other)
|
|
{
|
|
item = other.item;
|
|
return *this;
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTreeIterator<T>::parent() const
|
|
{
|
|
Q_ASSERT_X(item, Q_FUNC_INFO, "iterator out of range");
|
|
return QxtLinkedTreeIterator<T>(item->parent);
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTreeIterator<T>::next() const
|
|
{
|
|
Q_ASSERT_X(item, Q_FUNC_INFO, "iterator out of range");
|
|
return QxtLinkedTreeIterator<T>(item->next);
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTreeIterator<T>::previous() const
|
|
{
|
|
Q_ASSERT_X(item, Q_FUNC_INFO, "iterator out of range");
|
|
return QxtLinkedTreeIterator<T>(item->previous);
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTreeIterator<T>::child() const
|
|
{
|
|
Q_ASSERT_X(item, Q_FUNC_INFO, "iterator out of range");
|
|
return QxtLinkedTreeIterator<T>(item->child);
|
|
}
|
|
|
|
template<class T>
|
|
bool QxtLinkedTreeIterator<T>::isValid() const
|
|
{
|
|
return (item != 0);
|
|
}
|
|
|
|
template<class T>
|
|
int QxtLinkedTreeIterator<T>::children() const
|
|
{
|
|
Q_ASSERT_X(item, Q_FUNC_INFO, "iterator out of range");
|
|
return item->childcount;
|
|
}
|
|
|
|
template<class T>
|
|
T & QxtLinkedTreeIterator<T>::operator*() const
|
|
{
|
|
Q_ASSERT_X(item, Q_FUNC_INFO, "iterator out of range");
|
|
return item->t;
|
|
}
|
|
|
|
template<class T>
|
|
T * QxtLinkedTreeIterator<T>::operator-> () const
|
|
{
|
|
Q_ASSERT_X(item, Q_FUNC_INFO, "iterator out of range");
|
|
return &item->t;
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T>::operator T() const
|
|
{
|
|
Q_ASSERT_X(item,Q_FUNC_INFO, "iterator out of range");
|
|
return item->t;
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T>::QxtLinkedTreeIterator(QxtLinkedTreeItem<T> * t)
|
|
{
|
|
item = t;
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTreeIterator<T>::operator + (int j) const
|
|
{
|
|
QxtLinkedTreeItem<T> * m = item;
|
|
for (int i = 0;i < j;i++)
|
|
{
|
|
m = m->next;
|
|
if (m == 0)
|
|
return QxtLinkedTreeIterator<T>();
|
|
}
|
|
return QxtLinkedTreeIterator<T>(m);
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> & QxtLinkedTreeIterator<T>::operator ++ () /*prefix*/
|
|
{
|
|
*this = QxtLinkedTreeIterator<T>(item->next);
|
|
return *this;
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTreeIterator<T>::operator ++ (int) /*postfix*/
|
|
{
|
|
QxtLinkedTreeIterator<T> d(*this);
|
|
*this = QxtLinkedTreeIterator<T>(item->next);
|
|
return d;
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> & QxtLinkedTreeIterator<T>::operator += (int j)
|
|
{
|
|
*this = *this + j;
|
|
return *this;
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTreeIterator<T>::operator - (int j) const
|
|
{
|
|
QxtLinkedTreeItem<T> * m = item;
|
|
for (int i = 0;i < j;i++)
|
|
{
|
|
m = m->previous;
|
|
if (m == 0)
|
|
return QxtLinkedTreeIterator<T>();
|
|
}
|
|
return QxtLinkedTreeIterator<T>(m);
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> & QxtLinkedTreeIterator<T>::operator -- () /*prefix*/
|
|
{
|
|
*this = QxtLinkedTreeIterator<T>(item->previous);
|
|
return *this;
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTreeIterator<T>::operator -- (int) /*postfix*/
|
|
{
|
|
QxtLinkedTreeIterator<T> d(*this);
|
|
*this = QxtLinkedTreeIterator<T>(item->previous);
|
|
return d;
|
|
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> & QxtLinkedTreeIterator<T>::operator -= (int j)
|
|
{
|
|
*this = *this - j;
|
|
return *this;
|
|
}
|
|
|
|
template<class T>
|
|
bool QxtLinkedTreeIterator<T>::operator== (const QxtLinkedTreeIterator<T> & other) const
|
|
{
|
|
return (other.item == item);
|
|
}
|
|
|
|
template<class T>
|
|
bool QxtLinkedTreeIterator<T>::operator!= (const QxtLinkedTreeIterator<T> & other) const
|
|
{
|
|
return (other.item != item);
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTreeIterator<T>::erase()
|
|
{
|
|
QxtLinkedTreeItem <T> *node = item;
|
|
Q_ASSERT_X(item, Q_FUNC_INFO, "can't erase invalid node.");
|
|
QxtLinkedTreeItem <T> *parent = item->parent;
|
|
Q_ASSERT_X(parent, Q_FUNC_INFO, "erasing root node not supported.");
|
|
QxtLinkedTreeItem <T> *next = node->next;
|
|
|
|
///delete children
|
|
QxtLinkedTreeIterator<T> ci = child();
|
|
while (ci.isValid())
|
|
{
|
|
ci = ci.erase();
|
|
}
|
|
|
|
///realign chains
|
|
if (parent->child == node)
|
|
{
|
|
parent->child = node->next;
|
|
}
|
|
else
|
|
{
|
|
QxtLinkedTreeItem <T> * n = parent->child;
|
|
while (n->next != node)
|
|
{
|
|
Q_ASSERT_X(n->next != 0, Q_FUNC_INFO, "reached end of chain and didn't find the node requested for removal.");
|
|
n = n->next;
|
|
}
|
|
n->next = node->next;
|
|
}
|
|
parent->childcount--;
|
|
delete node;
|
|
item = 0;
|
|
return QxtLinkedTreeIterator<T>(next);
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTreeIterator<T>::append(const T & value)
|
|
{
|
|
QxtLinkedTreeItem <T> * parent = item;
|
|
Q_ASSERT_X(parent, Q_FUNC_INFO, "invalid iterator");
|
|
|
|
QxtLinkedTreeItem<T> *node = new QxtLinkedTreeItem<T>(value);
|
|
|
|
if (parent->child == 0)
|
|
{
|
|
parent->child = node;
|
|
node->parent = parent;
|
|
node->previous = 0;
|
|
parent->childcount = 1;
|
|
return QxtLinkedTreeIterator<T>(node);
|
|
}
|
|
|
|
QxtLinkedTreeItem <T> * n = parent->child;
|
|
while (n->next != 0)
|
|
n = n->next;
|
|
n->next = node;
|
|
node->parent = parent;
|
|
node->previous = n;
|
|
parent->childcount++;
|
|
return QxtLinkedTreeIterator<T>(node);
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTreeIterator<T>::insert(int i, const T & value)
|
|
{
|
|
QxtLinkedTreeItem <T> * parent = item;
|
|
Q_ASSERT_X(parent, Q_FUNC_INFO, "invalid iterator");
|
|
|
|
|
|
Q_ASSERT_X(i <= children(), Q_FUNC_INFO, "cannot insert out of range");
|
|
|
|
|
|
if (parent->child == 0 || i == children())
|
|
{
|
|
return append(value);
|
|
}
|
|
|
|
QxtLinkedTreeItem<T> *node = new QxtLinkedTreeItem<T>(value);
|
|
|
|
QxtLinkedTreeItem <T> * n = parent->child;
|
|
|
|
while (i-- > 0)
|
|
{
|
|
n = n->next;
|
|
Q_ASSERT_X(n, Q_FUNC_INFO, "out of range");
|
|
}
|
|
if (n->previous)
|
|
{
|
|
n->previous->next = node;
|
|
node->previous = n->previous;
|
|
}
|
|
else
|
|
{
|
|
Q_ASSERT_X(parent->child == n, Q_FUNC_INFO, "corupted linked tree");
|
|
parent->child = node;
|
|
node->previous = 0;
|
|
}
|
|
node->next = n;
|
|
n->previous = node;
|
|
node->parent = parent;
|
|
parent->childcount++;
|
|
return QxtLinkedTreeIterator<T>(node);
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTree<T>::QxtLinkedTree(T t)
|
|
{
|
|
qxt_d = new QxtLinkedTreeItem<T>(t);
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTree<T>::QxtLinkedTree()
|
|
{
|
|
qxt_d = new QxtLinkedTreeItem<T>(T());
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTree<T>::~QxtLinkedTree()
|
|
{
|
|
}
|
|
|
|
template<class T>
|
|
void QxtLinkedTree<T>::clear()
|
|
{
|
|
qxt_d().clear();
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTree<T>::fromVoid(void * d)
|
|
{
|
|
return QxtLinkedTreeIterator<T>(reinterpret_cast<QxtLinkedTreeItem<T> *>(d));
|
|
}
|
|
|
|
template<class T>
|
|
void * QxtLinkedTree<T>::toVoid(QxtLinkedTreeIterator<T> n)
|
|
{
|
|
return reinterpret_cast<void*>(n.item);
|
|
}
|
|
|
|
template<class T>
|
|
QxtLinkedTreeIterator<T> QxtLinkedTree<T>::root()
|
|
{
|
|
return QxtLinkedTreeIterator<T>(&qxt_d());
|
|
}
|
|
|
|
#endif // QXTLINKEDTREE_H
|