Serious-Engine/Sources/Engine/Base/Lists.cpp
2016-03-11 15:57:17 +02:00

278 lines
5.8 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
#include "stdh.h"
#include <Engine/Base/Lists.h>
#include <Engine/Base/ListIterator.inl>
/////////////////////////////////////////////////////////////////////
// CListHead implementation
/*
* Initialize a list head.
*/
void CListHead::Clear(void)
{
ASSERT(this!=NULL);
lh_Head = (CListNode *) &(lh_NULL);
lh_NULL = (CListNode *) NULL;
lh_Tail = (CListNode *) &(lh_Head);
}
/*
* Check if list head is valid.
*/
BOOL CListHead::IsValid(void) const
{
ASSERT(this!=NULL);
ASSERT(lh_NULL == NULL);
ASSERT((lh_Head == (CListNode *) &lh_NULL) && (lh_Tail == (CListNode *) &lh_Head)
|| lh_Tail->IsValid() && lh_Head->IsValid() );
return TRUE;
}
/*
* Check if list is empty.
*/
BOOL CListHead::IsEmpty(void) const
{
ASSERT(IsValid());
return( lh_Head == (CListNode *) &lh_NULL );
}
/*
* Add a node to head of list.
*/
void CListHead::AddHead(CListNode &element)
{
ASSERT(IsValid()&& !element.IsLinked());
CListNode &first = *lh_Head;
lh_Head = &element;
element.ln_Succ = &first;
element.ln_Pred = first.ln_Pred;
first.ln_Pred = &element;
}
/*
* Add a node to tail of list.
*/
void CListHead::AddTail(CListNode &element)
{
ASSERT(IsValid()&& !element.IsLinked());
CListNode &last = *lh_Tail;
lh_Tail = &element;
element.ln_Succ = last.ln_Succ;
element.ln_Pred = &last;
last.ln_Succ = &element;
}
/*
* Remove a node from head of list.
*/
void CListHead::RemHead(void)
{
ASSERT(!IsEmpty());
lh_Head->Remove();
}
/*
* Remove a node from tail of list.
*/
void CListHead::RemTail(void)
{
ASSERT(!IsEmpty());
lh_Tail->Remove();
}
/* Remove all elements from list. */
void CListHead::RemAll(void)
{
// for each element
for ( CListIter<CListNode, 0> iter(*this), iternext;
iternext=iter, iternext.IsPastEnd() || (iternext.MoveToNext(),1), !iter.IsPastEnd();
iter = iternext) {
// remove it
iter->Remove();
}
}
/*
* Move all elements of another list into this one.
*/
void CListHead::MoveList(CListHead &lhOther)
{
ASSERT(IsValid() && lhOther.IsValid());
// if the second list is empty
if (lhOther.IsEmpty()) {
// no moving
return;
}
// get first element in other list
CListNode &lnOtherFirst = *lhOther.lh_Head;
// get last element in other list
CListNode &lnOtherLast = *lhOther.lh_Tail;
// get last element in this list
CListNode &lnThisLast = *lh_Tail;
// relink elements
lnOtherLast.ln_Succ = lnThisLast.ln_Succ;
lnThisLast.ln_Succ = &lnOtherFirst;
lnOtherFirst.ln_Pred = &lnThisLast;
lh_Tail = &lnOtherLast;
// clear the other list
lhOther.Clear();
}
/*
* Return the number of elements in list.
*/
INDEX CListHead::Count(void) const
{
INDEX slCount = 0;
// walk the list -- modification of FOREACHINLIST that works with base CListNode class
for ( CListIter<CListNode, 0> iter(*this); !iter.IsPastEnd(); iter.MoveToNext() ) {
slCount++;
}
return slCount;
}
/* Sort the list. */
void CListHead::Sort(int (*pCompare)(const void *p0, const void *p1), int iNodeOffset)
{
// get number of elements
INDEX ctCount = Count();
// if none
if (ctCount==0) {
// do not sort
}
// create array of that much integers (the array will hold pointers to the list)
ULONG *aulPointers = new ULONG[ctCount];
// fill it
INDEX i=0;
for ( CListIter<int, 0> iter(*this); !iter.IsPastEnd(); iter.MoveToNext() ) {
aulPointers[i] = ((ULONG)&*iter)-iNodeOffset;
i++;
}
// sort it
qsort(aulPointers, ctCount, sizeof(SLONG), pCompare);
// make temporary list
CListHead lhTmp;
// for each pointer
{for(INDEX i=0; i<ctCount; i++) {
ULONG ul = aulPointers[i];
// get the node
CListNode *pln = (CListNode*)(ul+iNodeOffset);
// remove it from original list
pln->Remove();
// add it to the end of new list
lhTmp.AddTail(*pln);
}}
// free the pointer array
delete[] aulPointers;
// move the sorted list here
MoveList(lhTmp);
}
/////////////////////////////////////////////////////////////////////
// CListNode implementation
/*
* Check if list node is valid.
*/
BOOL CListNode::IsValid(void) const
{
ASSERT(this!=NULL);
ASSERT((ln_Pred==NULL && ln_Succ==NULL) || (ln_Pred!=NULL && ln_Succ!=NULL));
// it is valid if it is cleared or if it is linked
return (ln_Pred==NULL && ln_Succ==NULL)
|| (ln_Pred->ln_Succ == this) && (ln_Succ->ln_Pred == this);
}
/*
* Check is linked in some list.
*/
BOOL CListNode::IsLinked(void) const
{
ASSERT(IsValid());
return ln_Pred != NULL;
}
/*
* Remove a node from list.
*/
void CListNode::Remove(void)
{
ASSERT(IsLinked());
CListNode &next = *ln_Succ;
CListNode &prev = *ln_Pred;
ASSERT(next.IsTailMarker() || next.IsLinked());
ASSERT(prev.IsHeadMarker() || prev.IsLinked());
next.ln_Pred = &prev;
prev.ln_Succ = &next;
// make a non-linked node
ln_Succ = NULL;
ln_Pred = NULL;
}
/*
* Add a node after this node.
*/
void CListNode::AddAfter(CListNode &lnToAdd)
{
ASSERT(IsLinked() && !lnToAdd.IsLinked());
CListNode &succ = IterationSucc();
CListNode &pred = *this;
succ.ln_Pred = &lnToAdd;
pred.ln_Succ = &lnToAdd;
lnToAdd.ln_Succ = &succ;
lnToAdd.ln_Pred = &pred;
}
/*
* Add a node before this node.
*/
void CListNode::AddBefore(CListNode &lnToAdd)
{
ASSERT(IsLinked() && !lnToAdd.IsLinked());
CListNode &succ = *this;
CListNode &pred = IterationPred();
succ.ln_Pred = &lnToAdd;
pred.ln_Succ = &lnToAdd;
lnToAdd.ln_Succ = &succ;
lnToAdd.ln_Pred = &pred;
}
/*
* Find the head of the list that this node is in.
*/
CListHead &CListNode::GetHead(void)
{
// start at this node
CListNode *pln = this;
// while current node is not pointer to list.lh_Head
while(pln->ln_Pred != NULL) {
// go backwards
pln = pln->ln_Pred;
}
// return the head pointer
return *(CListHead*)pln;
}