You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1067 lines
25 KiB
1067 lines
25 KiB
#ifndef _KVI_POINTERLIST_H_
|
|
#define _KVI_POINTERLIST_H_
|
|
//=================================================================================================
|
|
//
|
|
// File : kvi_pointerlist.h
|
|
// Creation date : Tue Jul 6 1999 14:52:20 by Szymon Stefanek
|
|
//
|
|
// This file is part of the KVirc irc client distribution
|
|
// Copyright (C) 1999-2007 Szymon Stefanek (pragma at kvirc dot net)
|
|
//
|
|
// This program is FREE software. You can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 2
|
|
// of the License, or (at your opinion) any later version.
|
|
//
|
|
// This program is distributed in the HOPE that it will be USEFUL,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, write to the Free Software Foundation,
|
|
// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
//
|
|
//=================================================================================================
|
|
//=============================================================================
|
|
//
|
|
// C++ Template based double linked pointer list class
|
|
// Original ss_list.h Created on 10 Dec 2001
|
|
// Copyright (C) 2001-2007 Szymon Stefanek (pragma at kvirc dot net)
|
|
// Added to KVIrc on 02 Jan 2008.
|
|
//
|
|
//=============================================================================
|
|
|
|
// TQt changes the collection classes too much and too frequently.
|
|
// I think we need to be independent of that to the maximum degree possible.
|
|
// That's why we have our own fast pointer list class.
|
|
// This does not depend on TQt AT ALL and has an interface similar
|
|
// to the TQt<=3.x series.
|
|
|
|
#include "kvi_settings.h"
|
|
|
|
template<typename T> class KviPointerList;
|
|
template<typename T> class KviPointerListIterator;
|
|
|
|
#ifndef NULL
|
|
#define NULL 0
|
|
#endif
|
|
|
|
///
|
|
/// \internal
|
|
///
|
|
class KviPointerListNode
|
|
{
|
|
public:
|
|
KviPointerListNode * m_pPrev;
|
|
void * m_pData;
|
|
KviPointerListNode * m_pNext;
|
|
};
|
|
|
|
///
|
|
/// \class KviPointerListIterator
|
|
/// \brief A fast KviPointerList iterator.
|
|
///
|
|
/// This class allows traversing the list sequentially.
|
|
/// Multilpe iterators can traverse the list at the same time.
|
|
///
|
|
/// Iteration example 1:
|
|
///
|
|
/// \verbatim
|
|
/// KviPointerListIterator<T> it(list);
|
|
/// for(bool b = it.moveFirst();b;b = it.moveNext())
|
|
/// {
|
|
/// T * pData = it.data();
|
|
/// doSomethingWithData(pData);
|
|
/// }
|
|
/// \endverbatim
|
|
///
|
|
/// Iteration example 2:
|
|
///
|
|
/// \verbatim
|
|
/// KviPointerListIterator<T> it(list);
|
|
/// if(it.moveFirst())
|
|
/// {
|
|
/// do {
|
|
/// T * pData = it.data();
|
|
/// doSomethingWithData(pData);
|
|
/// } while(it.moveNext());
|
|
/// }
|
|
/// \endverbatim
|
|
///
|
|
/// Iteration example 3:
|
|
///
|
|
/// \verbatim
|
|
/// KviPointerListIterator<T> it(list.iteratorAt(10));
|
|
/// if(it.isValid())
|
|
/// {
|
|
/// do {
|
|
/// T * pData = it.data();
|
|
/// doSomethingWithData(pData);
|
|
/// while(it.movePrev());
|
|
/// }
|
|
/// \endverbatim
|
|
///
|
|
/// Please note that you must NOT remove any item from
|
|
/// the list when using the iterators. An iterator pointing
|
|
/// to a removed item will crash your application if you use it.
|
|
/// The following code will NOT work (and crash):
|
|
///
|
|
/// \verbatim
|
|
/// KviPointerList<T> l;
|
|
/// l.append(new KviStr("x"));
|
|
/// l.append(new KviStr("y"));
|
|
/// KviPointerListIterator<T> it(l);
|
|
/// it.moveFirst();
|
|
/// l.removeFirst();
|
|
/// KviStr * tmp = it.data(); <-- this will crash
|
|
/// \endverbatim
|
|
///
|
|
/// In the rare cases in that you need to remove items
|
|
/// while traversing the list you should put them
|
|
/// in a temporary list and remove them after the iteration.
|
|
///
|
|
/// I've choosen this way because usually you don't modify
|
|
/// the list while traversing it and a fix for this
|
|
/// would add a constant overhead to several list operation.
|
|
/// You just must take care of it yourself.
|
|
///
|
|
/// \warning This class is not thread safe by itself.
|
|
///
|
|
template<typename T> class KviPointerListIterator
|
|
{
|
|
protected:
|
|
KviPointerList<T> * m_pList;
|
|
KviPointerListNode * m_pNode;
|
|
public:
|
|
///
|
|
/// Creates an iterator copy.
|
|
/// The new iterator points exactly to the item pointed by src.
|
|
///
|
|
KviPointerListIterator(const KviPointerListIterator<T> &src)
|
|
{
|
|
m_pList = src.m_pList;
|
|
m_pNode = src.m_pNode;
|
|
}
|
|
|
|
///
|
|
/// Creates an iterator for the list l.
|
|
/// The iterator points to the first list item, if any.
|
|
///
|
|
KviPointerListIterator(KviPointerList<T> &l)
|
|
{
|
|
m_pList = (KviPointerList<T> *)&l;
|
|
m_pNode = m_pList->m_pHead;
|
|
}
|
|
|
|
///
|
|
/// Creates an iterator for the list l.
|
|
/// The iterator points to the specified list node.
|
|
///
|
|
KviPointerListIterator(KviPointerList<T> &l,KviPointerListNode * pNode)
|
|
{
|
|
m_pList = (KviPointerList<T> *)&l;
|
|
m_pNode = pNode;
|
|
}
|
|
|
|
///
|
|
/// Creates an iterator copy.
|
|
/// The new iterator points exactly to the item pointed by src.
|
|
///
|
|
void operator = (const KviPointerListIterator<T> &src)
|
|
{
|
|
m_pList = src.m_pList;
|
|
m_pNode = src.m_pNode;
|
|
}
|
|
public:
|
|
///
|
|
/// Moves the iterator to the first element of the list.
|
|
/// Returns true in case of success or false if the list is empty.
|
|
///
|
|
bool moveFirst()
|
|
{
|
|
m_pNode = m_pList->m_pHead;
|
|
return m_pNode != NULL;
|
|
}
|
|
|
|
///
|
|
/// Moves the iterator to the last element of the list.
|
|
/// Returns true in case of success or false if the list is empty.
|
|
///
|
|
bool moveLast()
|
|
{
|
|
m_pNode = m_pList->m_pTail;
|
|
return m_pNode != NULL;
|
|
}
|
|
|
|
///
|
|
/// Moves the iterator to the next element of the list.
|
|
/// The iterator must be actually valid for this function to work.
|
|
/// Returns true in case of success or false if there is no next item.
|
|
///
|
|
bool moveNext()
|
|
{
|
|
if(!m_pNode)return false;
|
|
m_pNode = m_pNode->m_pNext;
|
|
return m_pNode != NULL;
|
|
}
|
|
|
|
///
|
|
/// Moves the iterator to the next element of the list.
|
|
/// The iterator must be actually valid for this operator to work.
|
|
/// Returns true in case of success or false if there is no next item.
|
|
/// This is just a convenient alias to moveNext().
|
|
///
|
|
bool operator ++()
|
|
{
|
|
if(!m_pNode)return false;
|
|
m_pNode = m_pNode->m_pNext;
|
|
return m_pNode != NULL;
|
|
}
|
|
|
|
///
|
|
/// Moves the iterator to the previous element of the list.
|
|
/// The iterator must be actually valid for this function to work.
|
|
/// Returns true in case of success or false if there is no previous item.
|
|
///
|
|
bool movePrev()
|
|
{
|
|
if(!m_pNode)return false;
|
|
m_pNode = m_pNode->m_pPrev;
|
|
return m_pNode != NULL;
|
|
}
|
|
|
|
///
|
|
/// Moves the iterator to the previous element of the list.
|
|
/// The iterator must be actually valid for this operator to work.
|
|
/// Returns true in case of success or false if there is no previous item.
|
|
/// This is just a convenient alias to movePrev().
|
|
///
|
|
bool operator --()
|
|
{
|
|
if(!m_pNode)return false;
|
|
m_pNode = m_pNode->m_pPrev;
|
|
return m_pNode != NULL;
|
|
}
|
|
|
|
///
|
|
/// Returs the value pointed by the iterator
|
|
/// or NULL if the iterator is not valid.
|
|
///
|
|
T * current()
|
|
{
|
|
return m_pNode ? (T *)(m_pNode->m_pData) : NULL;
|
|
}
|
|
|
|
///
|
|
/// Returs the value pointed by the iterator
|
|
/// or NULL if the iterator is not valid.
|
|
/// This is just an alias to current().
|
|
///
|
|
T * operator *()
|
|
{
|
|
return m_pNode ? (T *)(m_pNode->m_pData) : NULL;
|
|
}
|
|
|
|
///
|
|
/// Returns true if this iterator points to a valid
|
|
/// element of the list and false otherwise.
|
|
///
|
|
bool isValid()
|
|
{
|
|
return m_pNode != NULL;
|
|
}
|
|
};
|
|
|
|
///
|
|
/// \class KviPointerList
|
|
/// \brief A template double linked list of pointers.
|
|
///
|
|
/// The main advantage of this type of list is speed.
|
|
/// Insertion of pointers is very fast when compared
|
|
/// to the typical "copy constructor" call used
|
|
/// in the "plain type" template list implementations.
|
|
///
|
|
/// Iterating over pointers is also very fast and this
|
|
/// class contains an internal iterator that allows to
|
|
/// write loops in a compact and clean way.
|
|
/// See the first(), next(), current() and findRef()
|
|
/// functions for the description of this feature.
|
|
///
|
|
/// There is also a non-const external iterator
|
|
/// that you can use to traverse the list concurrently.
|
|
/// There is no const iterator (and no const access methods)
|
|
/// since the list provides the autoDelete() method
|
|
/// which vould implicitly violate constness.
|
|
/// If you have to deal with const objects then
|
|
/// you need to use a TQPtrList instead.
|
|
///
|
|
/// Your objects also do not need to support copy constructors
|
|
/// or >= operators. This class will work fine without them
|
|
/// as opposed to a plain TQPtrList.
|
|
///
|
|
/// This class also supports automatic deletion of the inseted items.
|
|
/// See the setAutoDelete() and autoDelete() members for the
|
|
/// description of the feature.
|
|
///
|
|
/// Typcal usage:
|
|
///
|
|
/// \verbatim
|
|
/// KviPointerList<MyClass> list();
|
|
/// list.append(new MyClass());
|
|
/// list.append(new MyClass());
|
|
/// ...
|
|
/// for(MyClass * c = list.first();c;c = list.next())doSomethingWith(c);
|
|
/// delete list; // autodelete is set to true in the constructor
|
|
/// \endverbatim
|
|
///
|
|
/// \warning This class is absolutely NOT thread safe. You must
|
|
/// protect concurrent access from multiple threads by
|
|
/// using an external synchronization tool (such as KviMutex).
|
|
///
|
|
template<typename T> class KviPointerList
|
|
{
|
|
friend class KviPointerListIterator<T>;
|
|
protected:
|
|
bool m_bAutoDelete; //< do we automatically delete items when they are removed ?
|
|
|
|
KviPointerListNode * m_pHead; //< our list head pointer (NULL if there are no items in the list)
|
|
KviPointerListNode * m_pTail; //< our list tail
|
|
KviPointerListNode * m_pAux; //< our iteration pointer
|
|
|
|
unsigned int m_uCount; //< the count of items in the list
|
|
protected:
|
|
///
|
|
/// \internal
|
|
///
|
|
/// inserts the item d before the item ref or at the beginning
|
|
/// if ref is not found in the list
|
|
/// also sets the current iteration pointer to the newly inserted item
|
|
///
|
|
void insertBeforeSafe(KviPointerListNode * ref,const T * d)
|
|
{
|
|
m_pAux = ref;
|
|
KviPointerListNode * n = new KviPointerListNode;
|
|
n->m_pPrev = m_pAux->m_pPrev;
|
|
n->m_pNext = m_pAux;
|
|
if(m_pAux->m_pPrev)
|
|
{
|
|
m_pAux->m_pPrev->m_pNext = n;
|
|
} else {
|
|
m_pHead = n;
|
|
}
|
|
m_pAux->m_pPrev = n;
|
|
n->m_pData = (void *)d;
|
|
m_uCount++;
|
|
}
|
|
|
|
///
|
|
/// \internal
|
|
///
|
|
/// Grabs the first element from the list src
|
|
/// and puts it as the first element of this list.
|
|
///
|
|
void grabFirstAndPrepend(KviPointerList<T> * src)
|
|
{
|
|
KviPointerListNode * pNewHead = src->m_pHead;
|
|
if(!pNewHead)
|
|
return;
|
|
|
|
if(pNewHead->m_pNext)
|
|
{
|
|
src->m_pHead = pNewHead->m_pNext;
|
|
src->m_pHead->m_pPrev = NULL;
|
|
} else {
|
|
src->m_pHead = NULL;
|
|
src->m_pTail = NULL;
|
|
}
|
|
|
|
if(m_pHead)
|
|
{
|
|
m_pHead->m_pPrev = pNewHead;
|
|
pNewHead->m_pNext = m_pHead;
|
|
m_pHead = pNewHead;
|
|
} else {
|
|
m_pHead = pNewHead;
|
|
m_pTail = pNewHead;
|
|
m_pHead->m_pNext = NULL;
|
|
}
|
|
m_uCount++;
|
|
src->m_uCount--;
|
|
}
|
|
|
|
///
|
|
/// \internal
|
|
///
|
|
/// Removes the current iteration item assuming that it is valid.
|
|
///
|
|
void removeCurrentSafe()
|
|
{
|
|
if(m_pAux->m_pPrev)
|
|
m_pAux->m_pPrev->m_pNext = m_pAux->m_pNext;
|
|
else
|
|
m_pHead = m_pAux->m_pNext;
|
|
if(m_pAux->m_pNext)
|
|
m_pAux->m_pNext->m_pPrev = m_pAux->m_pPrev;
|
|
else
|
|
m_pTail = m_pAux->m_pPrev;
|
|
const T * pAuxData = (const T *)(m_pAux->m_pData);
|
|
delete m_pAux;
|
|
m_pAux = NULL;
|
|
m_uCount--;
|
|
if(m_bAutoDelete)
|
|
delete pAuxData; // this can cause recursion, so do it at the end
|
|
}
|
|
|
|
public:
|
|
///
|
|
/// Inserts the list src inside this list
|
|
/// by respecting the sort order.
|
|
/// The src list elements are removed.
|
|
///
|
|
void merge(KviPointerList<T> * src)
|
|
{
|
|
m_pAux = m_pHead;
|
|
KviPointerListNode * n = src->m_pHead;
|
|
m_uCount += src->m_uCount;
|
|
while(m_pAux && n)
|
|
{
|
|
if(kvi_compare((const T *)(m_pAux->m_pData),(const T *)(n->m_pData)) > 0)
|
|
{
|
|
// our element is greater, n->m_pData goes first
|
|
KviPointerListNode * pNext = n->m_pNext;
|
|
n->m_pPrev = m_pAux->m_pPrev; // his prev becomes
|
|
n->m_pNext = m_pAux;
|
|
if(m_pAux->m_pPrev)
|
|
m_pAux->m_pPrev->m_pNext = n;
|
|
else
|
|
m_pHead = n;
|
|
m_pAux->m_pPrev = n;
|
|
n = pNext;
|
|
} else {
|
|
// that element is greater
|
|
m_pAux = m_pAux->m_pNext;
|
|
}
|
|
}
|
|
if(n)
|
|
{
|
|
// last items to append
|
|
if(m_pTail)
|
|
{
|
|
m_pTail->m_pNext = n;
|
|
n->m_pPrev = m_pTail;
|
|
} else {
|
|
m_pHead = n;
|
|
m_pTail = n;
|
|
n->m_pPrev = NULL;
|
|
}
|
|
m_pTail = src->m_pTail;
|
|
}
|
|
|
|
src->m_pHead = NULL;
|
|
src->m_pTail = NULL;
|
|
src->m_uCount = 0;
|
|
}
|
|
|
|
void swap(KviPointerList<T> * src)
|
|
{
|
|
KviPointerListNode * n = m_pHead;
|
|
m_pHead = src->m_pHead;
|
|
src->m_pHead = n;
|
|
n = m_pTail;
|
|
m_pTail = src->m_pTail;
|
|
src->m_pTail = n;
|
|
unsigned int uCount = m_uCount;
|
|
m_uCount = src->m_uCount;
|
|
src->m_uCount = uCount;
|
|
}
|
|
|
|
|
|
///
|
|
/// Sorts this list in ascending order.
|
|
/// There must be an int kvi_compare(const T *p1,const T *p2) function
|
|
/// which returns a value less than, equal to
|
|
/// or greater than zero when the item p1 is considered lower than,
|
|
/// equal to or greater than p2.
|
|
///
|
|
void sort()
|
|
{
|
|
if(m_uCount < 2)return;
|
|
|
|
KviPointerList<T> carry;
|
|
KviPointerList<T> tmp[64];
|
|
KviPointerList * fill = &tmp[0];
|
|
KviPointerList * counter;
|
|
|
|
do {
|
|
carry.grabFirstAndPrepend(this);
|
|
|
|
for(counter = &tmp[0];counter != fill && !counter->isEmpty();++counter)
|
|
{
|
|
counter->merge(&carry);
|
|
carry.swap(counter);
|
|
}
|
|
carry.swap(counter);
|
|
if(counter == fill)
|
|
++fill;
|
|
} while(m_uCount > 0);
|
|
|
|
for(counter = &tmp[1];counter != fill;++counter)
|
|
counter->merge(counter-1);
|
|
swap(fill-1);
|
|
}
|
|
|
|
///
|
|
/// Inserts the item respecting the sorting order inside the list.
|
|
/// The list itself must be already sorted for this to work correctly.
|
|
/// There must be a int kvi_compare(const T *p1,const T * p2)
|
|
/// that returns a value less than, equal to
|
|
/// or greater than zero when the item p1 is considered lower than,
|
|
/// equal to or greater than p2.
|
|
///
|
|
void inSort(T * t)
|
|
{
|
|
KviPointerListNode * x = m_pHead;
|
|
while(x && (kvi_compare(((T *)x->m_pData),t) > 0))x = x->m_pNext;
|
|
if(!x)append(t);
|
|
else insertBeforeSafe(x,t);
|
|
}
|
|
|
|
///
|
|
/// Returns true if the list is empty
|
|
///
|
|
bool isEmpty() const
|
|
{
|
|
return (m_pHead == NULL);
|
|
}
|
|
|
|
///
|
|
/// Returns the count of the items in the list
|
|
///
|
|
unsigned int count() const
|
|
{
|
|
return m_uCount;
|
|
}
|
|
|
|
///
|
|
/// Sets the iteration pointer to the first item in the list
|
|
/// and returns that item (or 0 if the list is empty)
|
|
///
|
|
T * first()
|
|
{
|
|
if(!m_pHead)
|
|
{
|
|
m_pAux = NULL;
|
|
return NULL;
|
|
}
|
|
m_pAux = m_pHead;
|
|
return (T *)(m_pAux->m_pData);
|
|
}
|
|
|
|
///
|
|
/// Removes the first element from the list
|
|
/// and returns it to the caller. This function
|
|
/// obviously never deletes the item (regadless of autoDeletion()).
|
|
///
|
|
T * takeFirst()
|
|
{
|
|
if(!m_pHead)return NULL;
|
|
T * pData = (T *)m_pHead->m_pData;
|
|
if(m_pHead->m_pNext)
|
|
{
|
|
m_pHead = m_pHead->m_pNext;
|
|
delete m_pHead->m_pPrev;
|
|
m_pHead->m_pPrev = NULL;
|
|
} else {
|
|
delete m_pHead;
|
|
m_pHead = NULL;
|
|
m_pTail = NULL;
|
|
}
|
|
m_uCount--;
|
|
return pData;
|
|
}
|
|
|
|
///
|
|
/// Returns an iterator pointing to the first item of the list.
|
|
///
|
|
KviPointerListIterator<T> iteratorAtFirst()
|
|
{
|
|
return KviPointerListIterator<T>(*this,m_pHead);
|
|
}
|
|
|
|
///
|
|
/// Sets the iteration pointer to the last item in the list
|
|
/// and returns that item (or 0 if the list is empty)
|
|
///
|
|
T * last()
|
|
{
|
|
if(!m_pTail)
|
|
{
|
|
m_pAux = NULL;
|
|
return NULL;
|
|
}
|
|
m_pAux = m_pTail;
|
|
return (T *)(m_pAux->m_pData);
|
|
}
|
|
|
|
///
|
|
/// Returns an iterator pointing to the first item of the list.
|
|
///
|
|
KviPointerListIterator<T> iteratorAtLast()
|
|
{
|
|
return KviPointerListIterator<T>(*this,m_pTail);
|
|
}
|
|
|
|
///
|
|
/// Returns the current iteration item
|
|
/// A call to this function MUST be preceded by a call to
|
|
/// first(),last(),at() or findRef()
|
|
///
|
|
T * current()
|
|
{
|
|
return (T *)(m_pAux->m_pData);
|
|
}
|
|
|
|
///
|
|
/// Returns the current iteration item
|
|
/// A call to this function should be preceded by a call to
|
|
/// first(),last(),at() or findRef().
|
|
/// This function will return a NULL pointer if the current
|
|
/// item has been invalidated due to a remove operation.
|
|
///
|
|
T * safeCurrent()
|
|
{
|
|
return m_pAux ? (T *)(m_pAux->m_pData) : NULL;
|
|
}
|
|
|
|
|
|
///
|
|
/// Returns an iterator pointing to the current item in the list.
|
|
/// A call to this function MUST be preceded by a call to
|
|
/// first(),last(),at() or findRef()
|
|
///
|
|
KviPointerListIterator<T> iteratorAtCurrent()
|
|
{
|
|
return KviPointerListIterator<T>(*this,m_pAux);
|
|
}
|
|
|
|
///
|
|
/// Sets the iteration pointer to the next item in the list
|
|
/// and returns that item (or 0 if the end of the list has been reached)
|
|
/// A call to this function MUST be preceded by a _succesfull_ call to
|
|
/// first(),last(),at() or findRef().
|
|
///
|
|
T * next()
|
|
{
|
|
if(!m_pAux)return NULL;
|
|
m_pAux = m_pAux->m_pNext;
|
|
if(m_pAux)return (T *)(m_pAux->m_pData);
|
|
return NULL;
|
|
}
|
|
|
|
///
|
|
/// Sets the iteration pointer to the previous item in the list
|
|
/// and returns that item (or 0 if the beginning of the list has been reached)
|
|
/// A call to this function MUST be preceded by a _succesfull_ call to
|
|
/// first(),last(),at() or findRef()
|
|
///
|
|
T * prev()
|
|
{
|
|
if(!m_pAux)return NULL;
|
|
m_pAux = m_pAux->m_pPrev;
|
|
if(m_pAux)return (T *)(m_pAux->m_pData);
|
|
return NULL;
|
|
}
|
|
|
|
///
|
|
/// Sets the iteration pointer to the nTh item in the list
|
|
/// and returns that item (or 0 if the index is out of range)
|
|
///
|
|
T * at(int idx)
|
|
{
|
|
T * t = first();
|
|
int cnt = 0;
|
|
while(t)
|
|
{
|
|
if(idx == cnt)return t;
|
|
t = next();
|
|
cnt++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
///
|
|
/// Returns an iterator pointing to the item at the specified index.
|
|
///
|
|
KviPointerListIterator<T> iteratorAt(int idx)
|
|
{
|
|
KviPointerListNode * n = m_pHead;
|
|
int cnt = 0;
|
|
while(n)
|
|
{
|
|
if(idx == cnt)
|
|
return KviPointerListIterator<T>(*this,n);
|
|
n = n->m_pNext;
|
|
cnt++;
|
|
}
|
|
return KviPointerListIterator<T>(*this,NULL);
|
|
}
|
|
|
|
///
|
|
/// Sets the iteration pointer to the item with pointer d
|
|
/// and returns its position (zero based index) in the list or -1 if the
|
|
/// item cannot be found
|
|
///
|
|
int findRef(const T * d)
|
|
{
|
|
int ret = 0;
|
|
for(T * t = first();t;t = next())
|
|
{
|
|
if(t == d)return ret;
|
|
ret++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
///
|
|
/// Returns an iterator pointing to the item with pointer d.
|
|
///
|
|
KviPointerListIterator<T> iteratorAtRef(const T * d)
|
|
{
|
|
KviPointerListNode * n = m_pHead;
|
|
while(n)
|
|
{
|
|
if(n->m_pData == d)
|
|
return KviPointerListIterator<T>(*this,n);
|
|
n = n->m_pNext;
|
|
}
|
|
return KviPointerListIterator<T>(*this,NULL);
|
|
}
|
|
|
|
///
|
|
/// Appends an item at the end of the list
|
|
///
|
|
void append(const T * d)
|
|
{
|
|
if(!m_pHead)
|
|
{
|
|
m_pHead = new KviPointerListNode;
|
|
m_pHead->m_pPrev = NULL;
|
|
m_pHead->m_pNext = NULL;
|
|
m_pHead->m_pData = (void *)d;
|
|
m_pTail = m_pHead;
|
|
} else {
|
|
m_pTail->m_pNext = new KviPointerListNode;
|
|
m_pTail->m_pNext->m_pPrev = m_pTail;
|
|
m_pTail->m_pNext->m_pNext = NULL;
|
|
m_pTail->m_pNext->m_pData = (void *)d;
|
|
m_pTail = m_pTail->m_pNext;
|
|
}
|
|
m_uCount++;
|
|
}
|
|
|
|
///
|
|
/// Appends all the items from the list l to this list
|
|
///
|
|
void append(KviPointerList<T> * l)
|
|
{
|
|
for(T * t = l->first();t;t = l->next())append(t);
|
|
}
|
|
|
|
///
|
|
/// Prepends (inserts in head position) all the items from
|
|
/// the list l to this list
|
|
///
|
|
void prepend(KviPointerList<T> * l)
|
|
{
|
|
for(T * t = l->last();t;t = l->prev())prepend(t);
|
|
}
|
|
|
|
///
|
|
/// Inserts the item d in the head position
|
|
///
|
|
void prepend(const T * d)
|
|
{
|
|
if(!m_pHead)
|
|
{
|
|
m_pHead = new KviPointerListNode;
|
|
m_pHead->m_pPrev = NULL;
|
|
m_pHead->m_pNext = NULL;
|
|
m_pHead->m_pData = (void *)d;
|
|
m_pTail = m_pHead;
|
|
} else {
|
|
m_pHead->m_pPrev = new KviPointerListNode;
|
|
m_pHead->m_pPrev->m_pNext = m_pHead;
|
|
m_pHead->m_pPrev->m_pPrev = NULL;
|
|
m_pHead->m_pPrev->m_pData = (void *)d;
|
|
m_pHead = m_pHead->m_pPrev;
|
|
m_uCount++;
|
|
}
|
|
}
|
|
|
|
///
|
|
/// Inserts the item d at the zero-based position
|
|
/// specified by iIndex. If the specified position
|
|
/// is out of the list then the item is appended.
|
|
/// Note that this function costs O(n).
|
|
/// It's really better to use insertAfter() or
|
|
/// insertBefore(), if possible.
|
|
///
|
|
void insert(int iIndex,const T * d)
|
|
{
|
|
m_pAux = m_pHead;
|
|
while(m_pAux && iIndex > 0)
|
|
{
|
|
iIndex--;
|
|
m_pAux = m_pAux->m_pNext;
|
|
}
|
|
if(m_pAux)
|
|
insertBeforeSafe(m_pAux,d);
|
|
else
|
|
append(d);
|
|
}
|
|
|
|
///
|
|
/// Removes the firstitem (if any)
|
|
/// the item is deleted if autoDelete() is set to true
|
|
///
|
|
bool removeFirst()
|
|
{
|
|
if(!m_pHead)return false;
|
|
const T * pAuxData;
|
|
if(m_pHead->m_pNext)
|
|
{
|
|
m_pHead = m_pHead->m_pNext;
|
|
pAuxData = (const T *)(m_pHead->m_pPrev->m_pData);
|
|
delete m_pHead->m_pPrev;
|
|
m_pHead->m_pPrev = NULL;
|
|
} else {
|
|
pAuxData = (const T *)(m_pHead->m_pData);
|
|
delete m_pHead;
|
|
m_pHead = NULL;
|
|
m_pTail = NULL;
|
|
}
|
|
m_pAux = NULL;
|
|
m_uCount--;
|
|
if(m_bAutoDelete)
|
|
delete pAuxData;
|
|
return true;
|
|
}
|
|
|
|
///
|
|
/// Removes the firstitem (if any)
|
|
/// the item is deleted if autoDelete() is set to true
|
|
///
|
|
bool removeLast()
|
|
{
|
|
if(!m_pTail)return false;
|
|
const T * pAuxData;
|
|
if(m_pTail->m_pPrev)
|
|
{
|
|
m_pTail = m_pTail->m_pPrev;
|
|
pAuxData = (const T *)(m_pTail->m_pNext->m_pData);
|
|
delete m_pTail->m_pNext;
|
|
m_pTail->m_pNext = NULL;
|
|
} else {
|
|
pAuxData = (const T *)(m_pTail->m_pData);
|
|
delete m_pTail;
|
|
m_pHead = NULL;
|
|
m_pTail = NULL;
|
|
}
|
|
m_pAux = NULL;
|
|
m_uCount--;
|
|
if(m_bAutoDelete)
|
|
delete pAuxData;
|
|
return true;
|
|
}
|
|
|
|
///
|
|
/// Removes the item at zero-based position iIndex.
|
|
/// Does nothing and returns false if iIndex is out of the list.
|
|
/// Please note that this function costs O(n).
|
|
///
|
|
bool remove(int iIndex)
|
|
{
|
|
m_pAux = m_pHead;
|
|
while(m_pAux && iIndex > 0)
|
|
{
|
|
iIndex--;
|
|
m_pAux = m_pAux->m_pNext;
|
|
}
|
|
if(!m_pAux)
|
|
return false;
|
|
removeCurrentSafe();
|
|
return true;
|
|
}
|
|
|
|
///
|
|
/// Sets the autodelete flag
|
|
/// When this flag is on (default) , all the items
|
|
/// are deleted when removed from the list (or when the list is destroyed
|
|
/// or cleared explicitly)
|
|
///
|
|
void setAutoDelete(bool bAutoDelete)
|
|
{
|
|
m_bAutoDelete = bAutoDelete;
|
|
}
|
|
|
|
///
|
|
/// Returns the autodelete flag.
|
|
///
|
|
bool autoDelete()
|
|
{
|
|
return m_bAutoDelete;
|
|
};
|
|
|
|
///
|
|
/// Removes all the items from the list
|
|
/// (the items are deleted if the autoDelete() flag is set to true)
|
|
///
|
|
void clear()
|
|
{
|
|
while(m_pHead)removeFirst();
|
|
}
|
|
|
|
///
|
|
/// Removes the current iteration item.
|
|
/// Returns true if the current iteration item was valid (and was removed)
|
|
/// and false otherwise.
|
|
///
|
|
bool removeCurrent()
|
|
{
|
|
if(!m_pAux)
|
|
return false;
|
|
removeCurrentSafe();
|
|
return true;
|
|
}
|
|
|
|
///
|
|
/// Removes the item pointed by d (if found in the list)
|
|
/// the item is deleted if the autoDelete() flag is set to true)
|
|
/// Returns true if the item was in the list and false otherwise.
|
|
///
|
|
bool removeRef(const T * d)
|
|
{
|
|
if(findRef(d) == -1)return false;
|
|
removeCurrentSafe();
|
|
return true;
|
|
}
|
|
|
|
///
|
|
/// inserts the item d after the item ref or at the end
|
|
/// if ref is not found in the list
|
|
/// also sets the current iteration pointer to the newly inserted item
|
|
///
|
|
void insertAfter(const T * ref,const T * d)
|
|
{
|
|
if(findRef(ref) == -1)
|
|
{
|
|
append(d);
|
|
return;
|
|
}
|
|
KviPointerListNode * n = new KviPointerListNode;
|
|
n->m_pPrev = m_pAux;
|
|
n->m_pNext = m_pAux->m_pNext;
|
|
if(m_pAux->m_pNext)
|
|
m_pAux->m_pNext->m_pPrev = n;
|
|
else
|
|
m_pTail = n;
|
|
m_pAux->m_pNext = n;
|
|
n->m_pData = (void *)d;
|
|
m_uCount++;
|
|
}
|
|
|
|
///
|
|
/// inserts the item d before the item ref or at the beginning
|
|
/// if ref is not found in the list
|
|
/// also sets the current iteration pointer to the newly inserted item
|
|
///
|
|
void insertBefore(const T * ref,const T * d)
|
|
{
|
|
if(findRef(ref) == -1)
|
|
{
|
|
prepend(d);
|
|
return;
|
|
}
|
|
KviPointerListNode * n = new KviPointerListNode;
|
|
n->m_pPrev = m_pAux->m_pPrev;
|
|
n->m_pNext = m_pAux;
|
|
if(m_pAux->m_pPrev)
|
|
m_pAux->m_pPrev->m_pNext = n;
|
|
else
|
|
m_pHead = n;
|
|
m_pAux->m_pPrev = n;
|
|
n->m_pData = (void *)d;
|
|
m_uCount++;
|
|
}
|
|
|
|
///
|
|
/// Inverts the elements in the list.
|
|
///
|
|
void invert()
|
|
{
|
|
if(!m_pHead)return;
|
|
KviPointerListNode * oldHead = m_pHead;
|
|
KviPointerListNode * oldTail = m_pTail;
|
|
KviPointerListNode * n = m_pHead;
|
|
while(n)
|
|
{
|
|
KviPointerListNode * next = n->m_pNext;
|
|
n->m_pNext = n->m_pPrev;
|
|
n->m_pPrev = next;
|
|
n = next;
|
|
}
|
|
m_pTail = oldHead;
|
|
m_pHead = oldTail;
|
|
}
|
|
|
|
///
|
|
/// clears the list and inserts all the items from the list l
|
|
///
|
|
void copyFrom(KviPointerList<T> * l)
|
|
{
|
|
clear();
|
|
for(T * t = l->first();t;t = l->next())append(t);
|
|
}
|
|
|
|
///
|
|
/// equivalent to copyFrom(l)
|
|
///
|
|
KviPointerList<T> & operator = (KviPointerList<T> &l)
|
|
{
|
|
copyFrom(&l);
|
|
return *this;
|
|
}
|
|
|
|
///
|
|
/// creates a template list
|
|
///
|
|
KviPointerList<T>(bool bAutoDelete = true)
|
|
{
|
|
m_bAutoDelete = bAutoDelete;
|
|
m_pHead = NULL;
|
|
m_pTail = NULL;
|
|
m_uCount = 0;
|
|
m_pAux = NULL;
|
|
};
|
|
|
|
///
|
|
/// destroys the list
|
|
/// if autoDelete() is set to true, all the items are deleted
|
|
///
|
|
virtual ~KviPointerList<T>()
|
|
{
|
|
clear();
|
|
};
|
|
};
|
|
|
|
#define KviPointerListBase KviPointerList
|
|
|
|
// BROKEN MSVC LINKER
|
|
#ifdef COMPILE_ON_WINDOWS
|
|
#include "kvi_string.h"
|
|
template class KVILIB_API KviPointerList<KviStr>;
|
|
#endif
|
|
|
|
#endif //_KVI_POINTERLIST_H_
|