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.
749 lines
16 KiB
C++
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__)
|