#if !defined(__DBLINKS__) #define __DBLINKS__ #ifndef NULL_CLASS_DEFINED #define NULL_CLASS_DEFINED class CNullClass {}; #endif #define TDBLNK(TYPE) TDoubleLinkRef // TDBLNK(CObject*) #define TDBLNKCUT(TYPE) TDoubleLinkCut // TDBLNKDESTROY(TDBLNK(CObject*)) #define TDBLNKFREE(TYPE) TDoubleLinkFree // TDBLNKFREE(TDBLNK(CObject*)) #define TDBLNKDESTROY(TYPE) TDoubleLinkDestroy // TDBLNKDESTROY(TDBLNK(CObject*)) #define TDBLNKTREE(TYPE) TDoubleLinkTreeRef // 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 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 TYPE TDoubleLinkRef::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 void TDoubleLinkRef::CutListAll(TYPE& pHead) { #if DO_VERIFY pHead->VerifyLinks(pHead); #endif // DO_VERIFY TYPE pLink; while((pLink = CutHead(pHead)) != NULL) ; } template void TDoubleLinkRef::FreeListAll(TYPE& pHead) { #if DO_VERIFY pHead->VerifyLinks(pHead); #endif // DO_VERIFY TYPE pLink; while((pLink = CutHead(pHead)) != NULL) free(pLink); } template void TDoubleLinkRef::DestroyListAll(TYPE& pHead) { #if DO_VERIFY pHead->VerifyLinks(pHead); #endif // DO_VERIFY TYPE pLink; while((pLink = CutHead(pHead)) != NULL) delete pLink; } template int TDoubleLinkRef::GetCount() const { int nCount = 0; TYPE pLink = (TYPE)this; while(pLink) { nCount++; pLink = pLink->m_pNext; } return nCount; } template TYPE TDoubleLinkRef::GetHead() const { TYPE p = (TYPE)this; if (p) { TYPE pLink; while((pLink = p->m_pPrev) != NULL) p = pLink; } return p; } template TYPE TDoubleLinkRef::GetTail() const { TYPE p = (TYPE)this; if (p) { TYPE pLink; while((pLink = p->m_pNext) != NULL) p = pLink; } return p; } template TYPE TDoubleLinkRef::GetNeighbor(BOOL bNext) { ASSERT(this); if (bNext) return m_pNext; return m_pPrev; } template TYPE TDoubleLinkRef::GetTerminal(BOOL bNext) { if (bNext) { return GetTail(); } return GetHead(); } template BOOL TDoubleLinkRef::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 TYPE TDoubleLinkRef::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 void TDoubleLinkRef::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 void TDoubleLinkRef::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 void TDoubleLinkRef::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 void TDoubleLinkRef::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 TYPE TDoubleLinkRef::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 void TDoubleLinkRef::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 void TDoubleLinkRef::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 void TDoubleLinkRef::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 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 TDoubleLinkCut : public TDoubleLink { public: ~TDoubleLinkCut() { Reset(); } void Reset() { CutListAll(); } void Del(TYPE* pLink) { CutCheck(pLink); } }; template class TDoubleLinkFree : public TDoubleLink { public: ~TDoubleLinkFree() { Reset(); } void Reset() { FreeListAll(); } void Del(TYPE* pLink) { CutCheck(pLink); free(pLink); } }; template class TDoubleLinkDestroy : public TDoubleLink { public: ~TDoubleLinkDestroy() { Reset(); } void Reset() { DestroyListAll(); } void Del(TYPE* pLink) { CutCheck(pLink); delete pLink; } }; template class TDoubleLinkTreeRef : public TDoubleLinkRef { 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::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::Cut(m_pChild); pLink->m_pParent = NULL; return pPrev; } void InsChild(TYPE pLink) { pLink->TDoubleLinkRef::InsHead(m_pChild); pLink->m_pParent = (TYPE)this; } void InsChildBefore(TYPE pLink, TYPE pPrev = NULL) { pLink->TDoubleLinkRef::InsBefore(m_pChild, pPrev); pLink->m_pParent = (TYPE)this; } void AddChild(TYPE pLink) { pLink->TDoubleLinkRef::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::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__)