Files
firestorm/Gameleap/code/mw4/Code/mw4print/dblinks.inl
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

749 lines
16 KiB
C++

#if !defined(__DBLINKS__)
#define __DBLINKS__
#ifndef NULL_CLASS_DEFINED
#define NULL_CLASS_DEFINED
class CNullClass {};
#endif
#define TDBLNK(TYPE) TDoubleLinkRef<TYPE,CNullClass> // TDBLNK(CObject*)
#define TDBLNKCUT(TYPE) TDoubleLinkCut<TYPE,CNullClass> // TDBLNKDESTROY(TDBLNK(CObject*))
#define TDBLNKFREE(TYPE) TDoubleLinkFree<TYPE,CNullClass> // TDBLNKFREE(TDBLNK(CObject*))
#define TDBLNKDESTROY(TYPE) TDoubleLinkDestroy<TYPE,CNullClass> // TDBLNKDESTROY(TDBLNK(CObject*))
#define TDBLNKTREE(TYPE) TDoubleLinkTreeRef<TYPE,CNullClass> // TDBLNKTREE(CObject*)
#if !defined(DO_VERIFY)
#ifdef _DEBUG
#define DO_VERIFY 0
#else // !_DEBUG
#define DO_VERIFY 0
#endif // _DEBUG
#endif // !defined(DO_VERIFY)
template <class TYPE, class BaseClass>
class TDoubleLinkRef : public BaseClass
{
public:
TYPE m_pPrev;
TYPE m_pNext;
public:
#if DO_VERIFY
void VerifyLinks(const TYPE& pHead) const
{
ASSERT(&pHead);
if (pHead) {
ASSERT(!pHead->m_pPrev);
TYPE pLink = (TYPE)this;
while(pLink != pHead) {
ASSERT(pLink);
pLink = pLink->m_pPrev;
}
while((pLink = pLink->m_pNext) != NULL)
;
} else {
ASSERT(!this);
}
}
#endif // DO_VERIFY
public:
TDoubleLinkRef()
{
m_pPrev = NULL;
m_pNext = NULL;
}
static TYPE CutHead(TYPE& pHead);
static void CutListAll(TYPE& pHead);
static void FreeListAll(TYPE& pHead);
static void DestroyListAll(TYPE& pHead);
int GetCount() const;
TYPE GetHead() const;
TYPE GetTail() const;
TYPE GetNeighbor(BOOL bNext);
TYPE GetTerminal(BOOL bNext);
BOOL CutCheck(TYPE& pHead);
TYPE Cut(TYPE& pHead);
void InsHead(TYPE& pHead);
void InsBefore(TYPE& pHead, TYPE pPrev = NULL);
void InsAfter(TYPE& pHead, TYPE pNext = NULL);
void AddTail(TYPE& pHead);
TYPE CutGroup(TYPE& pHead);
void InsHeadGroup(TYPE& pHead);
void InsGroup(TYPE& pHead, TYPE pPrev = NULL);
void AddTailGroup(TYPE& pHead);
};
template <class TYPE, class BaseClass>
TYPE TDoubleLinkRef<TYPE, BaseClass>::CutHead(TYPE& pHead)
{
#if DO_VERIFY
pHead->VerifyLinks(pHead);
#endif // DO_VERIFY
TYPE pLink = pHead;
if (pLink) {
ASSERT(!pLink->m_pPrev);
TYPE pLink2 = pLink->m_pNext;
if (pLink2) {
ASSERT(pLink2->m_pPrev == pLink);
pLink2->m_pPrev = NULL;
pLink->m_pNext = NULL;
}
pHead = pLink2;
}
return pLink;
}
template <class TYPE, class BaseClass>
void TDoubleLinkRef<TYPE, BaseClass>::CutListAll(TYPE& pHead)
{
#if DO_VERIFY
pHead->VerifyLinks(pHead);
#endif // DO_VERIFY
TYPE pLink;
while((pLink = CutHead(pHead)) != NULL)
;
}
template <class TYPE, class BaseClass>
void TDoubleLinkRef<TYPE, BaseClass>::FreeListAll(TYPE& pHead)
{
#if DO_VERIFY
pHead->VerifyLinks(pHead);
#endif // DO_VERIFY
TYPE pLink;
while((pLink = CutHead(pHead)) != NULL)
free(pLink);
}
template <class TYPE, class BaseClass>
void TDoubleLinkRef<TYPE, BaseClass>::DestroyListAll(TYPE& pHead)
{
#if DO_VERIFY
pHead->VerifyLinks(pHead);
#endif // DO_VERIFY
TYPE pLink;
while((pLink = CutHead(pHead)) != NULL)
delete pLink;
}
template <class TYPE, class BaseClass>
int TDoubleLinkRef<TYPE, BaseClass>::GetCount() const
{
int nCount = 0;
TYPE pLink = (TYPE)this;
while(pLink) {
nCount++;
pLink = pLink->m_pNext;
}
return nCount;
}
template <class TYPE, class BaseClass>
TYPE TDoubleLinkRef<TYPE, BaseClass>::GetHead() const
{
TYPE p = (TYPE)this;
if (p) {
TYPE pLink;
while((pLink = p->m_pPrev) != NULL)
p = pLink;
}
return p;
}
template <class TYPE, class BaseClass>
TYPE TDoubleLinkRef<TYPE, BaseClass>::GetTail() const
{
TYPE p = (TYPE)this;
if (p) {
TYPE pLink;
while((pLink = p->m_pNext) != NULL)
p = pLink;
}
return p;
}
template <class TYPE, class BaseClass>
TYPE TDoubleLinkRef<TYPE, BaseClass>::GetNeighbor(BOOL bNext)
{
ASSERT(this);
if (bNext)
return m_pNext;
return m_pPrev;
}
template <class TYPE, class BaseClass>
TYPE TDoubleLinkRef<TYPE, BaseClass>::GetTerminal(BOOL bNext)
{
if (bNext) {
return GetTail();
}
return GetHead();
}
template <class TYPE, class BaseClass>
BOOL TDoubleLinkRef<TYPE, BaseClass>::CutCheck(TYPE& pHead)
{
ASSERT(this);
TYPE pPrev = m_pPrev;
if (pPrev) {
#if DO_VERIFY
VerifyLinks(pHead);
#endif // DO_VERIFY
pPrev->m_pNext = m_pNext;
TYPE pNext;
if ((pNext = m_pNext) != NULL) {
pNext->m_pPrev = pPrev;
m_pNext = NULL;
}
m_pPrev = NULL;
return TRUE;
} else {
if (this == pHead) {
TYPE pNext = m_pNext;
pHead = pNext;
if (pNext) {
pNext->m_pPrev = NULL;
m_pNext = NULL;
}
return TRUE;
} else {
ASSERT(!m_pNext);
return FALSE;
}
}
}
template <class TYPE, class BaseClass>
TYPE TDoubleLinkRef<TYPE, BaseClass>::Cut(TYPE& pHead)
{
ASSERT(this);
#if DO_VERIFY
VerifyLinks(pHead);
#endif // DO_VERIFY
TYPE pPrev = m_pPrev;
TYPE pNext = m_pNext;
if (pPrev) {
pPrev->m_pNext = pNext;
if (pNext != NULL) {
pNext->m_pPrev = pPrev;
m_pNext = NULL;
}
m_pPrev = NULL;
} else {
ASSERT(this == pHead);
pHead = pNext;
if (pNext) {
pNext->m_pPrev = NULL;
m_pNext = NULL;
}
}
return pPrev;
}
template <class TYPE, class BaseClass>
void TDoubleLinkRef<TYPE, BaseClass>::InsHead(TYPE& pHead)
{
ASSERT(this && !m_pPrev && !m_pNext);
m_pNext = pHead;
if (pHead) {
pHead->m_pPrev = (TYPE)this;
}
pHead = (TYPE)this;
#if DO_VERIFY
VerifyLinks(pHead);
#endif // DO_VERIFY
}
template <class TYPE, class BaseClass>
void TDoubleLinkRef<TYPE, BaseClass>::InsBefore(TYPE& pHead, TYPE pPrev/* = NULL*/)
{
ASSERT(this && !m_pPrev && !m_pNext);
if (pPrev) {
TYPE pPrevPrev = pPrev->m_pPrev;
pPrev->m_pPrev = (TYPE)this;
m_pNext = pPrev;
if (pPrevPrev) {
pPrevPrev->m_pNext = (TYPE)this;
m_pPrev = pPrevPrev;
} else {
pHead = (TYPE)this;
}
#if DO_VERIFY
VerifyLinks(pHead);
#endif // DO_VERIFY
} else {
AddTail(pHead);
}
}
template <class TYPE, class BaseClass>
void TDoubleLinkRef<TYPE, BaseClass>::InsAfter(TYPE& pHead, TYPE pNext/* = NULL*/)
{
ASSERT(this && !m_pPrev && !m_pNext);
if (pNext) {
TYPE pNextNext = pNext->m_pNext;
pNext->m_pNext = (TYPE)this;
m_pPrev = pNext;
if (pNextNext) {
pNextNext->m_pPrev = (TYPE)this;
m_pNext = pNextNext;
}
#if DO_VERIFY
VerifyLinks(pHead);
#endif // DO_VERIFY
} else {
AddTail(pHead);
}
}
template <class TYPE, class BaseClass>
void TDoubleLinkRef<TYPE, BaseClass>::AddTail(TYPE& pHead)
{
ASSERT(this && !m_pPrev && !m_pNext);
if (pHead) {
TYPE pTail = pHead->GetTail();
ASSERT(pTail && !pTail->m_pNext);
pTail->m_pNext = (TYPE)this;
m_pPrev = pTail;
} else {
pHead = (TYPE)this;
}
#if DO_VERIFY
VerifyLinks(pHead);
#endif // DO_VERIFY
}
template <class TYPE, class BaseClass>
TYPE TDoubleLinkRef<TYPE, BaseClass>::CutGroup(TYPE& pHead)
{
if (this) {
#if DO_VERIFY
VerifyLinks(pHead);
#endif // DO_VERIFY
TYPE pPrev = m_pPrev;
if (pPrev) {
pPrev->m_pNext = NULL;
m_pPrev = NULL;
} else {
ASSERT(this == pHead);
pHead = NULL;
}
}
return (TYPE)this;
}
template <class TYPE, class BaseClass>
void TDoubleLinkRef<TYPE, BaseClass>::InsHeadGroup(TYPE& pHead)
{
if (this) {
ASSERT(!m_pPrev);
if (pHead) {
TYPE pTail = GetTail();
pTail->m_pNext = pHead;
pHead->m_pPrev = pTail;
}
pHead = (TYPE)this;
#if DO_VERIFY
VerifyLinks(pHead);
#endif // DO_VERIFY
}
}
template <class TYPE, class BaseClass>
void TDoubleLinkRef<TYPE, BaseClass>::InsGroup(TYPE& pHead, TYPE pPrev/* = NULL*/)
{
if (this) {
ASSERT(!m_pPrev);
if (pPrev) {
TYPE pNext = pPrev->m_pNext;
pPrev->m_pNext = (TYPE)this;
m_pPrev = pPrev;
if (pNext) {
TYPE pTail = GetTail();
pTail->m_pNext = pNext;
pNext->m_pPrev = pTail;
}
#if DO_VERIFY
VerifyLinks(pHead);
#endif // DO_VERIFY
} else {
InsHeadGroup(pHead);
}
}
}
template <class TYPE, class BaseClass>
void TDoubleLinkRef<TYPE, BaseClass>::AddTailGroup(TYPE& pHead)
{
if (this) {
ASSERT(!m_pPrev);
if (pHead) {
TYPE pTail = pHead->GetTail();
ASSERT(pTail && !pTail->m_pNext);
pTail->m_pNext = (TYPE)this;
m_pPrev = pTail;
} else {
pHead = (TYPE)this;
}
#if DO_VERIFY
VerifyLinks(pHead);
#endif // DO_VERIFY
}
}
template <class TYPE, class BaseClass>
class TDoubleLink : public BaseClass
{
public:
TYPE* m_pLinkStart;
public:
TDoubleLink()
{
m_pLinkStart = NULL;
}
~TDoubleLink()
{
ASSERT(!m_pLinkStart);
}
operator TYPE* () const { return m_pLinkStart; }
TYPE* CutHead()
{
return TYPE::CutHead(m_pLinkStart);
}
void CutListAll()
{
TYPE::CutListAll(m_pLinkStart);
}
void FreeListAll()
{
TYPE::FreeListAll(m_pLinkStart);
}
void DestroyListAll()
{
TYPE::DestroyListAll(m_pLinkStart);
}
int GetCount() const
{
return m_pLinkStart->GetCount();
}
TYPE* GetHead() const
{
return m_pLinkStart;
}
TYPE* GetTail() const
{
return m_pLinkStart->GetTail();
}
BOOL CutCheck(TYPE* pLink)
{
return pLink->CutCheck(m_pLinkStart);
}
TYPE* Cut(TYPE* pLink)
{
return pLink->Cut(m_pLinkStart);
}
void InsHead(TYPE* pLink)
{
pLink->InsHead(m_pLinkStart);
}
void InsBefore(TYPE* pLink, TYPE* pPrev = NULL)
{
pLink->InsBefore(m_pLinkStart, pPrev);
}
void InsAfter(TYPE* pLink, TYPE* pNext = NULL)
{
pLink->InsAfter(m_pLinkStart, pNext);
}
void AddTail(TYPE* pLink)
{
pLink->AddTail(m_pLinkStart);
}
TYPE* CutGroup(TYPE* pLink)
{
return pLink->CutGroup(m_pLinkStart);
}
void InsHeadGroup(TYPE* pLink)
{
pLink->InsHeadGroup(m_pLinkStart);
}
void InsGroup(TYPE* pLink, TYPE* pPrev = NULL)
{
pLink->InsGroup(m_pLinkStart, pPrev);
}
void AddTailGroup(TYPE* pLink)
{
pLink->AddTailGroup(m_pLinkStart);
}
TYPE* FindIndex(int nIndex) const
{
if (nIndex >= 0) {
TYPE* pLink = m_pLinkStart;
while(pLink) {
if (nIndex == 0) {
return pLink;
}
pLink = pLink->m_pNext;
nIndex--;
}
}
return NULL;
}
int Find(TYPE* pLink) const
{
if (pLink) {
int nIndex = 0;
TYPE* pLink2 = m_pLinkStart;
while(pLink2) {
if (pLink2 == pLink) {
return nIndex;
}
pLink2 = pLink2->m_pNext;
nIndex++;
}
}
return -1;
}
};
template <class TYPE, class BaseClass>
class TDoubleLinkCut : public TDoubleLink<TYPE, BaseClass>
{
public:
~TDoubleLinkCut()
{
Reset();
}
void Reset()
{
CutListAll();
}
void Del(TYPE* pLink)
{
CutCheck(pLink);
}
};
template <class TYPE, class BaseClass>
class TDoubleLinkFree : public TDoubleLink<TYPE, BaseClass>
{
public:
~TDoubleLinkFree()
{
Reset();
}
void Reset()
{
FreeListAll();
}
void Del(TYPE* pLink)
{
CutCheck(pLink);
free(pLink);
}
};
template <class TYPE, class BaseClass>
class TDoubleLinkDestroy : public TDoubleLink<TYPE, BaseClass>
{
public:
~TDoubleLinkDestroy()
{
Reset();
}
void Reset()
{
DestroyListAll();
}
void Del(TYPE* pLink)
{
CutCheck(pLink);
delete pLink;
}
};
template <class TYPE, class BaseClass>
class TDoubleLinkTreeRef : public TDoubleLinkRef<TYPE, BaseClass>
{
public:
TYPE m_pParent;
TYPE m_pChild;
public:
TDoubleLinkTreeRef()
{
m_pParent = NULL;
m_pChild = NULL;
}
#ifdef _DEBUG
~TDoubleLinkTreeRef()
{
ASSERT(!(m_pPrev || m_pNext || m_pParent));
}
#endif // _DEBUG
int CountChildren() const
{
return m_pChild->TDoubleLinkRef<TYPE, BaseClass>::GetCount();
}
int CountChildrenAll() const
{
if (this) {
TYPE pChild = m_pChild;
int nCount;
for(nCount = 0; pChild; nCount++) {
nCount += pChild->CountChildrenAll();
pChild = pChild->m_pNext;
}
return nCount;
}
return 0;
}
int CountParent() const
{
ASSERT(this);
TYPE pParent = m_pParent;
int nCount = 0;
while(pParent) {
nCount++;
pParent = pParent->m_pParent;
}
return nCount;
}
TYPE CutChild(TYPE pLink)
{
ASSERT(pLink->m_pParent == (TYPE)this);
TYPE pPrev = pLink->TDoubleLinkRef<TYPE, BaseClass>::Cut(m_pChild);
pLink->m_pParent = NULL;
return pPrev;
}
void InsChild(TYPE pLink)
{
pLink->TDoubleLinkRef<TYPE, BaseClass>::InsHead(m_pChild);
pLink->m_pParent = (TYPE)this;
}
void InsChildBefore(TYPE pLink, TYPE pPrev = NULL)
{
pLink->TDoubleLinkRef<TYPE, BaseClass>::InsBefore(m_pChild, pPrev);
pLink->m_pParent = (TYPE)this;
}
void AddChild(TYPE pLink)
{
pLink->TDoubleLinkRef<TYPE, BaseClass>::AddTail(m_pChild);
pLink->m_pParent = (TYPE)this;
}
TYPE CutChildren()
{
TYPE pChild = m_pChild;
m_pChild = NULL;
TYPE p = pChild;
while(p) {
p->m_pParent = NULL;
p = p->m_pNext;
}
return pChild;
}
void AddChildren(TYPE pChild)
{
if (pChild) {
ASSERT(!pChild->m_pPrev);
TYPE pTail = m_pChild->TDoubleLinkRef<TYPE, BaseClass>::GetTail();
if (pTail) {
pTail->m_pNext = pChild;
pChild->m_pPrev = pTail;
} else {
m_pChild = pChild;
}
while(pChild) {
ASSERT(!pChild->m_pParent);
pChild->m_pParent = (TYPE)this;
pChild = pChild->m_pNext;
}
}
}
static void DestroyAll(TYPE& pStart)
{
pStart->DestroyAll();
pStart = NULL;
}
void DestroyAll()
{
if (this) {
DestroyAllChildren();
if (m_pParent) {
m_pParent->CutChild((TYPE)this);
}
delete this;
}
}
void DestroyAllChildren()
{
ASSERT(this);
while(m_pChild) {
TYPE pChild = m_pChild;
CutChild(pChild);
pChild->DestroyAllChildren();
delete pChild;
}
}
void SetAtArray(TYPE* pArray, int& nIndex) const
{
// this is not included...
ASSERT(&nIndex);
if (this) {
TYPE pChild = m_pChild;
while(pChild) {
pArray[nIndex++] = pChild;
pChild->SetAtArray(pArray, nIndex);
pChild = pChild->m_pNext;
}
}
}
void MakeArray(TARRAY(TYPE)& aTree) const
{
aTree.Reset();
int nSize = CountChildrenAll();
int nIndex = 0;
SetAtArray(&aTree.Add(nSize), nIndex);
}
};
#endif // !defined(__DBLINKS__)