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.
kvirc/src/kvilib/core/kvi_pointerlist.h

1070 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. The pointer lists with the autodelete
// feature was great and I don't completly understand why they have
// been removed from TQt4 in favor of the value based non-autodeleting
// lists... anyway: here we go :)
#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 tqfindRef()
/// 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 TQList 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 TQList.
///
/// 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 tqfindRef()
///
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 tqfindRef().
/// 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 tqfindRef()
///
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 tqfindRef().
///
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 tqfindRef()
///
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 tqfindRef(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(tqfindRef(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(tqfindRef(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(tqfindRef(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_