/Sources/Engine/Base/Lists.cpp
https://gitlab.com/dahbearz/Serious-Engine · C++ · 290 lines · 156 code · 40 blank · 94 comment · 29 complexity · baa97f5cfda11b1cfc23efe530585652 MD5 · raw file
- /* Copyright (c) 2002-2012 Croteam Ltd.
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as published by
- the Free Software Foundation
- 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. */
- #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 = ≻
- 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 = ≻
- 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;
- }