mirror of
https://github.com/0TheSpy/Seaside.git
synced 2025-01-11 03:32:10 +08:00
797 lines
14 KiB
C++
797 lines
14 KiB
C++
#ifndef UTILINTRUSIVELIST_H
|
|
#define UTILINTRUSIVELIST_H
|
|
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "basetypes.h"
|
|
#include "utlmemory.h"
|
|
#include "dbg.h"
|
|
|
|
|
|
|
|
namespace IntrusiveList
|
|
{
|
|
#ifdef SUPERSLOW_DEBUG_VERSION
|
|
template<class T> inline void ValidateDList(T* head)
|
|
{
|
|
if (head)
|
|
{
|
|
Assert(head->m_pPrev == 0);
|
|
}
|
|
while (head)
|
|
{
|
|
if (head->m_pNext)
|
|
{
|
|
Assert(head->m_pNext->m_pPrev == head);
|
|
}
|
|
if (head->m_pPrev)
|
|
{
|
|
Assert(head->m_pPrev->m_pNext == head);
|
|
}
|
|
head = head->m_pNext;
|
|
}
|
|
}
|
|
#else
|
|
template<class T> inline void ValidateDList(T* )
|
|
{
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
template <class T> inline void MoveDNodeBackwards(T* which, T*& head)
|
|
{
|
|
if (which->m_pPrev)
|
|
{
|
|
T* p = which->m_pPrev;
|
|
T* pp = p->m_pPrev;
|
|
T* n = which->m_pNext;
|
|
Assert(p->m_pNext == which);
|
|
if (n)
|
|
{
|
|
Assert(n->m_pPrev == which);
|
|
n->m_pPrev = p;
|
|
}
|
|
if (pp)
|
|
{
|
|
Assert(pp->m_pNext == p);
|
|
pp->m_pNext = which;
|
|
}
|
|
else
|
|
{
|
|
head = which;
|
|
}
|
|
which->m_pNext = p;
|
|
which->m_pPrev = pp;
|
|
p->m_pNext = n;
|
|
p->m_pPrev = which;
|
|
}
|
|
ValidateDList(head);
|
|
}
|
|
|
|
|
|
|
|
template<class T> inline void RemoveFromDList(T*& head, T* which)
|
|
{
|
|
if (which->m_pPrev)
|
|
{
|
|
Assert(which->m_pPrev->m_pNext == which);
|
|
which->m_pPrev->m_pNext = which->m_pNext;
|
|
if (which->m_pNext)
|
|
{
|
|
Assert(which->m_pNext->m_pPrev == which);
|
|
which->m_pNext->m_pPrev = which->m_pPrev;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (head == which)
|
|
{
|
|
head = which->m_pNext;
|
|
if (head)
|
|
{
|
|
Assert(head->m_pPrev == which);
|
|
head->m_pPrev = 0;
|
|
}
|
|
}
|
|
}
|
|
which->m_pNext = which->m_pPrev = 0;
|
|
ValidateDList(head);
|
|
|
|
}
|
|
|
|
template<class T> bool OnDList(T const* head, T const* which)
|
|
{
|
|
return (head == which) || (which->m_pNext != 0) || (which->m_pPrev != 0);
|
|
}
|
|
|
|
template<class T> void AddToDTail(T*& head, T* node)
|
|
{
|
|
node->m_pNext = 0;
|
|
if (!head)
|
|
{
|
|
head = node;
|
|
}
|
|
else
|
|
{
|
|
T* ptr = head;
|
|
while (ptr->m_pNext)
|
|
{
|
|
ptr = ptr->m_pNext;
|
|
}
|
|
ptr->m_pNext = node;
|
|
node->m_pPrev = ptr;
|
|
}
|
|
}
|
|
|
|
template<class T> inline void AddToDHead(T*& head, T* which)
|
|
{
|
|
which->m_pNext = head;
|
|
if (head)
|
|
{
|
|
head->m_pPrev = which;
|
|
}
|
|
which->m_pPrev = 0;
|
|
head = which;
|
|
ValidateDList(head);
|
|
}
|
|
|
|
template<class T> inline void AddToDHeadWithTailPtr(T*& head, T* which, T*& tailptr)
|
|
{
|
|
which->m_pNext = head;
|
|
if (head)
|
|
{
|
|
head->m_pPrev = which;
|
|
}
|
|
else
|
|
{
|
|
tailptr = which;
|
|
}
|
|
which->m_pPrev = 0;
|
|
head = which;
|
|
ValidateDList(head);
|
|
}
|
|
|
|
template<class T> inline void AddToDTailWithTailPtr(T*& head, T* which, T*& tailptr)
|
|
{
|
|
if (!tailptr)
|
|
{
|
|
Assert(!head);
|
|
which->m_pPrev = which->m_pNext = 0;
|
|
tailptr = head = which;
|
|
}
|
|
else
|
|
{
|
|
which->m_pNext = 0;
|
|
which->m_pPrev = tailptr;
|
|
tailptr->m_pNext = which;
|
|
tailptr = which;
|
|
}
|
|
ValidateDList(head);
|
|
}
|
|
|
|
template<class T> inline void RemoveFromDListWithTailPtr(T*& head, T* which, T*& tailptr)
|
|
{
|
|
if (which == tailptr)
|
|
{
|
|
tailptr = which->m_pPrev;
|
|
}
|
|
if (which->m_pPrev)
|
|
{
|
|
Assert(which->m_pPrev->m_pNext == which);
|
|
which->m_pPrev->m_pNext = which->m_pNext;
|
|
if (which->m_pNext)
|
|
{
|
|
Assert(which->m_pNext->m_pPrev == which);
|
|
which->m_pNext->m_pPrev = which->m_pPrev;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (head == which)
|
|
{
|
|
head = which->m_pNext;
|
|
if (head)
|
|
{
|
|
Assert(head->m_pPrev == which);
|
|
head->m_pPrev = 0;
|
|
}
|
|
}
|
|
}
|
|
which->m_pNext = which->m_pPrev = 0;
|
|
ValidateDList(head);
|
|
|
|
}
|
|
|
|
template<class T> inline void DeleteFromDListWithTailPtr(T*& head, T* which, T*& tailptr)
|
|
{
|
|
T* tmp = which;
|
|
if (which == tailptr)
|
|
{
|
|
tailptr = which->m_pPrev;
|
|
}
|
|
if (which->m_pPrev)
|
|
{
|
|
Assert(which->m_pPrev->m_pNext == which);
|
|
which->m_pPrev->m_pNext = which->m_pNext;
|
|
if (which->m_pNext)
|
|
{
|
|
Assert(which->m_pNext->m_pPrev == which);
|
|
which->m_pNext->m_pPrev = which->m_pPrev;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (head == which)
|
|
{
|
|
head = which->m_pNext;
|
|
if (head)
|
|
{
|
|
Assert(head->m_pPrev == which);
|
|
head->m_pPrev = 0;
|
|
}
|
|
}
|
|
}
|
|
which->m_pNext = which->m_pPrev = 0;
|
|
delete tmp;
|
|
ValidateDList(head);
|
|
}
|
|
|
|
template<class T> inline void AddToDPriority(T*& head, T* which)
|
|
{
|
|
T* prevnode = 0;
|
|
for (T* curnode = head; curnode; curnode = curnode->m_pNext)
|
|
{
|
|
if (which->m_Priority >= curnode->m_Priority)
|
|
break;
|
|
prevnode = curnode;
|
|
}
|
|
if (!prevnode)
|
|
{
|
|
AddToDHead(head, which);
|
|
}
|
|
else
|
|
{
|
|
which->m_pNext = prevnode->m_pNext;
|
|
prevnode->m_pNext = which;
|
|
which->m_pPrev = prevnode;
|
|
if (which->m_pNext)
|
|
which->m_pNext->m_pPrev = which;
|
|
}
|
|
}
|
|
|
|
template<class T> inline void AddToDPriorityLowestFirst(T*& head, T* which)
|
|
{
|
|
T* prevnode = 0;
|
|
for (T* curnode = head; curnode; curnode = curnode->m_pNext)
|
|
{
|
|
if (which->m_Priority <= curnode->m_Priority)
|
|
break;
|
|
prevnode = curnode;
|
|
}
|
|
if (!prevnode)
|
|
{
|
|
AddToDHead(head, which);
|
|
}
|
|
else
|
|
{
|
|
which->m_pNext = prevnode->m_pNext;
|
|
prevnode->m_pNext = which;
|
|
which->m_pPrev = prevnode;
|
|
if (which->m_pNext)
|
|
which->m_pNext->m_pPrev = which;
|
|
}
|
|
}
|
|
|
|
|
|
template<class T> T* LastNode(T* head)
|
|
{
|
|
if (head)
|
|
{
|
|
while (head->m_pNext)
|
|
{
|
|
head = head->m_pNext;
|
|
}
|
|
}
|
|
return head;
|
|
}
|
|
|
|
|
|
template<class T, class V> void RemoveFromList(T*& head, V* which)
|
|
{
|
|
if (head == which)
|
|
{
|
|
head = which->m_pNext;
|
|
}
|
|
else
|
|
{
|
|
for (T* i = head; i; i = i->m_pNext)
|
|
{
|
|
if (i->m_pNext == which)
|
|
{
|
|
i->m_pNext = which->m_pNext;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template<class T, class V> void DeleteFromList(T*& head, V* which)
|
|
{
|
|
T* tmp;
|
|
if (head == which)
|
|
{
|
|
tmp = which->m_pNext;
|
|
delete(head);
|
|
head = tmp;
|
|
}
|
|
else
|
|
{
|
|
for (T* i = head; i; i = i->m_pNext)
|
|
{
|
|
if (i->m_pNext == which)
|
|
{
|
|
tmp = which->m_pNext;
|
|
delete(which);
|
|
i->m_pNext = tmp;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template<class T, class V> int PositionInList(T* head, V* node)
|
|
{
|
|
int pos = 0;
|
|
while (head)
|
|
{
|
|
if (head == node) return pos;
|
|
head = head->m_pNext;
|
|
pos++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
template<class T> T* NthNode(T* head, int idx)
|
|
{
|
|
while (idx && head)
|
|
{
|
|
idx--;
|
|
head = head->m_pNext;
|
|
}
|
|
return head;
|
|
}
|
|
|
|
template<class T, class V> static inline void AddToHead(T*& head, V* node)
|
|
{
|
|
node->m_pNext = head;
|
|
head = node;
|
|
}
|
|
|
|
template<class T, class V> static inline void AddToTail(T*& head, V* node)
|
|
{
|
|
node->m_pNext = NULL;
|
|
if (!head)
|
|
head = node;
|
|
else
|
|
{
|
|
T* pLastNode = head;
|
|
while (pLastNode->m_pNext)
|
|
pLastNode = pLastNode->m_pNext;
|
|
pLastNode->m_pNext = node;
|
|
}
|
|
}
|
|
|
|
template<class T, class V> static inline void AddToHead(T*& head, T*& tail, V* node)
|
|
{
|
|
if (!head)
|
|
{
|
|
tail = node;
|
|
}
|
|
node->m_pNext = head;
|
|
head = node;
|
|
}
|
|
|
|
|
|
|
|
template<class T> static inline T* PrevNode(T* head, T* node)
|
|
{
|
|
T* i;
|
|
for (i = head; i; i = i->m_pNext)
|
|
{
|
|
if (i->m_pNext == node)
|
|
break;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
|
|
template<class T, class V> void AddToEnd(T*& head, V* node)
|
|
{
|
|
node->m_pNext = 0;
|
|
if (!head)
|
|
{
|
|
head = node;
|
|
}
|
|
else
|
|
{
|
|
T* ptr = head;
|
|
while (ptr->m_pNext)
|
|
{
|
|
ptr = ptr->m_pNext;
|
|
}
|
|
ptr->m_pNext = node;
|
|
}
|
|
}
|
|
|
|
template<class T, class V> void AddToEndWithTail(T*& head, T*& tail, V* node)
|
|
{
|
|
Assert((head && tail) || ((!head) && (!tail)));
|
|
node->m_pNext = 0;
|
|
if (!head)
|
|
{
|
|
head = tail = node;
|
|
}
|
|
else
|
|
{
|
|
tail->m_pNext = node;
|
|
tail = node;
|
|
}
|
|
}
|
|
|
|
template<class T> void AddSortedByName(T*& head, T* node)
|
|
{
|
|
if ((!head) ||
|
|
(stricmp(node->m_Name, head->m_Name) == -1))
|
|
{
|
|
node->m_pNext = head;
|
|
head = node;
|
|
}
|
|
else
|
|
{
|
|
T* t;
|
|
for (t = head; t->m_pNext; t = t->m_pNext)
|
|
if (stricmp(t->m_pNext->m_Name, node->m_Name) >= 0)
|
|
break;
|
|
node->m_pNext = t->m_pNext;
|
|
t->m_pNext = node;
|
|
}
|
|
}
|
|
|
|
template<class T> int ListLength(T* head)
|
|
{
|
|
int len = 0;
|
|
while (head)
|
|
{
|
|
len++;
|
|
head = head->m_pNext;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
template<class T> void KillList(T*& head)
|
|
{
|
|
while (head)
|
|
{
|
|
delete head;
|
|
}
|
|
}
|
|
|
|
|
|
template<class T> void DeleteList(T*& head)
|
|
{
|
|
while (head)
|
|
{
|
|
T* tmp = head->m_pNext;
|
|
delete head;
|
|
head = tmp;
|
|
}
|
|
}
|
|
|
|
template <class T> static inline T* FindNamedNode(T* head, char const* name)
|
|
{
|
|
for (; head && stricmp(head->m_Name, name); head = head->m_pNext)
|
|
{
|
|
}
|
|
return head;
|
|
}
|
|
|
|
template <class T> static inline T* FindNamedNodeCaseSensitive(T* head, char const* name)
|
|
{
|
|
for (; head && strcmp(head->m_Name, name); head = head->m_pNext)
|
|
{
|
|
}
|
|
return head;
|
|
}
|
|
|
|
template <class T, class U, class V> static inline T* FindNodeByField(T* head, U data, U V::* field)
|
|
{
|
|
while (head)
|
|
{
|
|
if (data == (*head).*field)
|
|
return head;
|
|
head = head->m_pNext;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <class T, class U, class V> static inline T* FindNodeByFieldWithPrev(T* head, U data, U V::* field, T*& prev)
|
|
{
|
|
prev = 0;
|
|
for (T* i = head; i; i = i->m_pNext)
|
|
{
|
|
if (data == (*i).*field)
|
|
return i;
|
|
prev = i;
|
|
}
|
|
prev = 0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
template<class T> void SortList(T*& head, int (*comparefn)(T* a, T* b))
|
|
{
|
|
int didswap = 1;
|
|
while (didswap)
|
|
{
|
|
didswap = 0;
|
|
T* prev = 0;
|
|
for (T* i = head; i && i->m_pNext; i = i->m_pNext)
|
|
{
|
|
int rslt = (*comparefn)(i, i->m_pNext);
|
|
if (rslt == -1)
|
|
{
|
|
didswap = 1;
|
|
T* newfirst = i->m_pNext;
|
|
if (prev)
|
|
{
|
|
prev->m_pNext = newfirst;
|
|
i->m_pNext = newfirst->m_pNext;
|
|
newfirst->m_pNext = i;
|
|
}
|
|
else
|
|
{
|
|
head = i->m_pNext;
|
|
i->m_pNext = newfirst->m_pNext;
|
|
newfirst->m_pNext = i;
|
|
}
|
|
i = newfirst;
|
|
}
|
|
prev = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class T> void SortDList(T*& head, int (*comparefn)(T* a, T* b))
|
|
{
|
|
SortList(head, comparefn);
|
|
T* prev = 0;
|
|
for (T* i = head; i; i = i->m_pNext)
|
|
{
|
|
i->m_pPrev = prev;
|
|
prev = i;
|
|
}
|
|
}
|
|
|
|
template <class T> T* ReversedList(T* head)
|
|
{
|
|
T* pNewHead = NULL;
|
|
while (head)
|
|
{
|
|
T* pNext = head->m_pNext;
|
|
#ifdef INTERVIEW_QUESTION
|
|
head->m_pNext = pNewHead;
|
|
pNewHead = head;
|
|
#else
|
|
AddToHead(pNewHead, head);
|
|
#endif
|
|
head = pNext;
|
|
}
|
|
return pNewHead;
|
|
}
|
|
};
|
|
|
|
template<class T> class CUtlIntrusiveList
|
|
{
|
|
public:
|
|
T* m_pHead;
|
|
|
|
FORCEINLINE T* Head(void) const
|
|
{
|
|
return m_pHead;
|
|
}
|
|
|
|
FORCEINLINE CUtlIntrusiveList(void)
|
|
{
|
|
m_pHead = NULL;
|
|
}
|
|
|
|
|
|
FORCEINLINE void RemoveAll(void)
|
|
{
|
|
m_pHead = NULL;
|
|
}
|
|
FORCEINLINE void AddToHead(T* node)
|
|
{
|
|
IntrusiveList::AddToHead(m_pHead, node);
|
|
}
|
|
|
|
FORCEINLINE void AddToTail(T* node)
|
|
{
|
|
IntrusiveList::AddToTail(m_pHead, node);
|
|
}
|
|
|
|
void RemoveNode(T* which)
|
|
{
|
|
IntrusiveList::RemoveFromList(m_pHead, which);
|
|
}
|
|
|
|
void KillList(void)
|
|
{
|
|
while (m_pHead)
|
|
{
|
|
delete m_pHead;
|
|
}
|
|
}
|
|
|
|
|
|
T* PrevNode(T* node)
|
|
{
|
|
return IntrusiveList::PrevNode(m_pHead, node);
|
|
}
|
|
|
|
int NthNode(int n)
|
|
{
|
|
return NthNode(m_pHead, n);
|
|
}
|
|
|
|
void Purge(void)
|
|
{
|
|
while (m_pHead)
|
|
{
|
|
T* tmp = m_pHead->m_pNext;
|
|
delete m_pHead;
|
|
m_pHead = tmp;
|
|
}
|
|
}
|
|
|
|
int Count(void) const
|
|
{
|
|
return IntrusiveList::ListLength(m_pHead);
|
|
}
|
|
|
|
FORCEINLINE T* FindNamedNodeCaseSensitive(char const* pName) const
|
|
{
|
|
return IntrusiveList::FindNamedNodeCaseSensitive(m_pHead, pName);
|
|
|
|
}
|
|
|
|
T* RemoveHead(void)
|
|
{
|
|
if (m_pHead)
|
|
{
|
|
T* pRet = m_pHead;
|
|
m_pHead = pRet->m_pNext;
|
|
return pRet;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
};
|
|
|
|
template<class T> class CUtlIntrusiveDList : public CUtlIntrusiveList<T>
|
|
{
|
|
public:
|
|
|
|
FORCEINLINE void AddToHead(T* node)
|
|
{
|
|
IntrusiveList::AddToDHead(CUtlIntrusiveList<T>::m_pHead, node);
|
|
}
|
|
FORCEINLINE void AddToTail(T* node)
|
|
{
|
|
IntrusiveList::AddToDTail(CUtlIntrusiveList<T>::m_pHead, node);
|
|
}
|
|
|
|
void RemoveNode(T* which)
|
|
{
|
|
IntrusiveList::RemoveFromDList(CUtlIntrusiveList<T>::m_pHead, which);
|
|
}
|
|
|
|
T* RemoveHead(void)
|
|
{
|
|
if (CUtlIntrusiveList<T>::m_pHead)
|
|
{
|
|
T* pRet = CUtlIntrusiveList<T>::m_pHead;
|
|
CUtlIntrusiveList<T>::m_pHead = CUtlIntrusiveList<T>::m_pHead->m_pNext;
|
|
if (CUtlIntrusiveList<T>::m_pHead)
|
|
CUtlIntrusiveList<T>::m_pHead->m_pPrev = NULL;
|
|
return pRet;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
T* PrevNode(T* node)
|
|
{
|
|
return (node) ? node->m_Prev : NULL;
|
|
}
|
|
|
|
};
|
|
|
|
template<class T> class CUtlIntrusiveDListWithTailPtr : public CUtlIntrusiveDList<T>
|
|
{
|
|
public:
|
|
|
|
T* m_pTailPtr;
|
|
|
|
FORCEINLINE CUtlIntrusiveDListWithTailPtr(void) : CUtlIntrusiveDList<T>()
|
|
{
|
|
m_pTailPtr = NULL;
|
|
}
|
|
|
|
FORCEINLINE void AddToHead(T* node)
|
|
{
|
|
IntrusiveList::AddToDHeadWithTailPtr(CUtlIntrusiveList<T>::m_pHead, node, m_pTailPtr);
|
|
}
|
|
FORCEINLINE void AddToTail(T* node)
|
|
{
|
|
IntrusiveList::AddToDTailWithTailPtr(CUtlIntrusiveList<T>::m_pHead, node, m_pTailPtr);
|
|
}
|
|
|
|
void RemoveNode(T* pWhich)
|
|
{
|
|
IntrusiveList::RemoveFromDListWithTailPtr(CUtlIntrusiveList<T>::m_pHead, pWhich, m_pTailPtr);
|
|
}
|
|
|
|
void Purge(void)
|
|
{
|
|
CUtlIntrusiveList<T>::Purge();
|
|
m_pTailPtr = NULL;
|
|
}
|
|
|
|
void Kill(void)
|
|
{
|
|
CUtlIntrusiveList<T>::Purge();
|
|
m_pTailPtr = NULL;
|
|
}
|
|
|
|
T* RemoveHead(void)
|
|
{
|
|
if (CUtlIntrusiveDList<T>::m_pHead)
|
|
{
|
|
T* pRet = CUtlIntrusiveDList<T>::m_pHead;
|
|
CUtlIntrusiveDList<T>::m_pHead = CUtlIntrusiveDList<T>::m_pHead->m_pNext;
|
|
if (CUtlIntrusiveDList<T>::m_pHead)
|
|
CUtlIntrusiveDList<T>::m_pHead->m_pPrev = NULL;
|
|
if (!CUtlIntrusiveDList<T>::m_pHead)
|
|
m_pTailPtr = NULL;
|
|
ValidateDList(CUtlIntrusiveDList<T>::m_pHead);
|
|
return pRet;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
T* PrevNode(T* node)
|
|
{
|
|
return (node) ? node->m_Prev : NULL;
|
|
}
|
|
|
|
};
|
|
|
|
template<class T> void PrependDListWithTailToDList(CUtlIntrusiveDListWithTailPtr<T>& src,
|
|
CUtlIntrusiveDList<T>& dest)
|
|
{
|
|
if (src.m_pHead)
|
|
{
|
|
src.m_pTailPtr->m_pNext = dest.m_pHead;
|
|
if (dest.m_pHead)
|
|
dest.m_pHead->m_pPrev = src.m_pTailPtr;
|
|
dest.m_pHead = src.m_pHead;
|
|
IntrusiveList::ValidateDList(dest.m_pHead);
|
|
}
|
|
}
|
|
|
|
#endif |