/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 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, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ /***************************************************************************** * * $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/pnUtList.h * ***/ #ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNUTILS_PRIVATE_PNUTLIST_H #error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/pnUtList.h included more than once" #endif #define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNUTILS_PRIVATE_PNUTLIST_H /**************************************************************************** * * Constants * ***/ enum ELinkType { kListUnlinked, kListLinkAfter, kListLinkBefore, kListHead = kListLinkAfter, kListTail = kListLinkBefore }; /**************************************************************************** * * Macros * ***/ #define LINK(class) TLink< class > #define LIST(class) TList< class > #define LISTDECL(class,field) TListDecl< class, offsetof(class,field) > #define LISTDYN(class) TListDyn< class > /**************************************************************************** * * Forward declarations * ***/ template class TLink; template class TList; /**************************************************************************** * * CBaseLink * ***/ class CBaseLink { friend class CBaseList; inline static bool TermCheck (byte * ptr); inline static byte * TermMark (byte * ptr); inline static byte * TermUnmarkAlways (byte * ptr); protected: CBaseLink * volatile m_prevLink; byte * volatile m_next; inline int CalcLinkOffset () const; inline void InitializeLinks (); inline void InitializeLinksWithOffset (int linkOffset); inline void InsertAfter (byte * node, CBaseLink * prevLink, int linkOffset); inline void InsertBefore (byte * node, CBaseLink * nextLink); inline byte * Next () const; inline byte * NextIgnoreTerm () const; inline byte * NextUnchecked () const; inline CBaseLink * NextLink () const; inline CBaseLink * NextLink (int linkOffset) const; inline byte * Prev () const; inline void UnlinkFromNeighbors (); public: inline CBaseLink (); inline CBaseLink (const CBaseLink & source); inline ~CBaseLink (); inline CBaseLink & operator= (const CBaseLink & source); inline bool IsLinked () const; inline void Unlink (); }; //=========================================================================== CBaseLink::CBaseLink () { InitializeLinks(); } //=========================================================================== CBaseLink::CBaseLink (const CBaseLink & source) { #ifdef HS_DEBUGGING if (source.IsLinked()) FATAL("No copy constructor"); #endif InitializeLinks(); } //=========================================================================== CBaseLink::~CBaseLink () { UnlinkFromNeighbors(); } //=========================================================================== CBaseLink & CBaseLink::operator= (const CBaseLink & source) { #ifdef HS_DEBUGGING FATAL("No assignment operator"); #endif return *this; } //=========================================================================== int CBaseLink::CalcLinkOffset () const { return (int)((byte *)this - m_prevLink->NextIgnoreTerm()); } //=========================================================================== void CBaseLink::InitializeLinks () { ASSERT(!((unsigned_ptr)this & 3)); m_prevLink = this; m_next = TermMark((byte *)this); } //=========================================================================== void CBaseLink::InitializeLinksWithOffset (int linkOffset) { m_prevLink = this; m_next = TermMark((byte *)this - linkOffset); } //=========================================================================== void CBaseLink::InsertAfter (byte * node, CBaseLink * prevLink, int linkOffset) { UnlinkFromNeighbors(); m_prevLink = prevLink; m_next = prevLink->m_next; prevLink->NextLink(linkOffset)->m_prevLink = this; prevLink->m_next = node; } //=========================================================================== void CBaseLink::InsertBefore (byte * node, CBaseLink * nextLink) { UnlinkFromNeighbors(); m_prevLink = nextLink->m_prevLink; m_next = m_prevLink->m_next; nextLink->m_prevLink->m_next = node; nextLink->m_prevLink = this; } //=========================================================================== bool CBaseLink::IsLinked () const { return (m_prevLink != this); } //=========================================================================== byte * CBaseLink::Next () const { return TermCheck(m_next) ? nil : m_next; } //=========================================================================== byte * CBaseLink::NextIgnoreTerm () const { return TermUnmarkAlways(m_next); } //=========================================================================== byte * CBaseLink::NextUnchecked () const { return m_next; } //=========================================================================== CBaseLink * CBaseLink::NextLink () const { return (CBaseLink *)(NextIgnoreTerm() + CalcLinkOffset()); } //=========================================================================== CBaseLink * CBaseLink::NextLink (int linkOffset) const { ASSERT(linkOffset == CalcLinkOffset()); return (CBaseLink *)(NextIgnoreTerm() + linkOffset); } //=========================================================================== byte * CBaseLink::Prev () const { return m_prevLink->m_prevLink->Next(); } //=========================================================================== bool CBaseLink::TermCheck (byte * ptr) { return (unsigned_ptr)ptr & 1; } //=========================================================================== byte * CBaseLink::TermMark (byte * ptr) { // Converts an unmarked pointer to a marked pointer ASSERT(!TermCheck(ptr)); return (byte *)((unsigned_ptr)ptr + 1); } //=========================================================================== byte * CBaseLink::TermUnmarkAlways (byte * ptr) { // Returns an unmarked pointer regardless of whether the source pointer // was marked on unmarked return (byte *)((unsigned_ptr)ptr & ~1); } //=========================================================================== void CBaseLink::Unlink () { UnlinkFromNeighbors(); InitializeLinks(); } //=========================================================================== void CBaseLink::UnlinkFromNeighbors () { NextLink()->m_prevLink = m_prevLink; m_prevLink->m_next = m_next; } /**************************************************************************** * * TLink * ***/ template class TLink : public CBaseLink { public: inline T * Next (); inline const T * Next () const; inline T * NextUnchecked (); inline const T * NextUnchecked () const; inline T * Prev (); inline const T * Prev () const; }; //=========================================================================== template T * TLink::Next () { return (T *)CBaseLink::Next(); } //=========================================================================== template const T * TLink::Next () const { return (const T *)CBaseLink::Next(); } //=========================================================================== template T * TLink::NextUnchecked () { return (T *)CBaseLink::NextUnchecked(); } //=========================================================================== template const T * TLink::NextUnchecked () const { return (const T *)CBaseLink::NextUnchecked(); } //=========================================================================== template T * TLink::Prev () { return (T *)CBaseLink::Prev(); } //=========================================================================== template const T * TLink::Prev () const { return (const T *)CBaseLink::Prev(); } /**************************************************************************** * * CBaseList * ***/ class CBaseList { private: enum { LINK_OFFSET_UNINIT = 0xDDDDDDDD }; int m_linkOffset; CBaseLink m_terminator; protected: inline CBaseLink * GetLink (const byte * node) const; inline byte * Head () const; inline bool IsLinked (const byte * node) const; inline void Link (byte * node, ELinkType linkType, byte * existingNode); void Link (CBaseList * list, byte * afterNode, byte * beforeNode, ELinkType linkType, byte * existingNode); inline byte * Next (const byte * node) const; inline byte * NextUnchecked (const byte * node) const; inline byte * Prev (byte * node) const; inline byte * Tail () const; inline void Unlink (byte * node); public: inline CBaseList (); inline CBaseList (const CBaseList & source); inline ~CBaseList (); inline CBaseList & operator= (const CBaseList & source); inline void SetLinkOffset (int linkOffset); void UnlinkAll (); }; //=========================================================================== CBaseList::CBaseList () { m_linkOffset = LINK_OFFSET_UNINIT; } //=========================================================================== CBaseList::CBaseList (const CBaseList & source) { m_linkOffset = LINK_OFFSET_UNINIT; } //=========================================================================== CBaseList::~CBaseList () { if (m_terminator.IsLinked()) UnlinkAll(); } //=========================================================================== CBaseList & CBaseList::operator= (const CBaseList & source) { return *this; } //=========================================================================== CBaseLink * CBaseList::GetLink (const byte * node) const { return (CBaseLink *)(node + m_linkOffset); } //=========================================================================== byte * CBaseList::Head () const { return m_terminator.Next(); } //=========================================================================== bool CBaseList::IsLinked (const byte * node) const { ASSERT(node); return GetLink(node)->IsLinked(); } //=========================================================================== void CBaseList::Link (byte * node, ELinkType linkType, byte * existingNode) { ASSERT(node != existingNode); ASSERT(m_linkOffset != LINK_OFFSET_UNINIT); ASSERT((linkType == kListLinkAfter) || (linkType == kListLinkBefore)); if (linkType == kListLinkAfter) GetLink(node)->InsertAfter(node, existingNode ? GetLink(existingNode) : &m_terminator, m_linkOffset); else GetLink(node)->InsertBefore(node, existingNode ? GetLink(existingNode) : &m_terminator); } //=========================================================================== byte * CBaseList::Next (const byte * node) const { ASSERT(node); return GetLink(node)->Next(); } //=========================================================================== byte * CBaseList::NextUnchecked (const byte * node) const { ASSERT(node); return GetLink(node)->NextUnchecked(); } //=========================================================================== byte * CBaseList::Prev (byte * node) const { ASSERT(node); return GetLink(node)->Prev(); } //=========================================================================== void CBaseList::SetLinkOffset (int linkOffset) { ASSERT(!Head()); m_linkOffset = linkOffset; m_terminator.InitializeLinksWithOffset(linkOffset); } //=========================================================================== byte * CBaseList::Tail () const { return m_terminator.Prev(); } //=========================================================================== void CBaseList::Unlink (byte * node) { ASSERT(node); GetLink(node)->Unlink(); } /**************************************************************************** * * TList * ***/ template class TList : public CBaseList { private: inline T * NewFlags (unsigned flags, ELinkType linkType, T * existingNode, const char file[], int line); public: inline void Clear (); inline void Delete (T * node); inline T * Head (); inline const T * Head () const; inline bool IsLinked (const T * node) const; inline void Link (T * node, ELinkType linkType = kListTail, T * existingNode = nil); inline void Link (TList * list, ELinkType linkType = kListTail, T * existingNode = nil); inline void Link (TList * list, T * afterNode, T * beforeNode, ELinkType linkType = kListTail, T * existingNode = nil); inline T * New (ELinkType linkType = kListTail, T * existingNode = nil, const char file[] = nil, int line = 0); inline T * NewZero (ELinkType linkType = kListTail, T * existingNode = nil, const char file[] = nil, int line = 0); inline T * Next (const T * node); inline const T * Next (const T * node) const; inline T * NextUnchecked (const T * node); inline const T * NextUnchecked (const T * node) const; inline T * Prev (const T * node); inline const T * Prev (const T * node) const; inline T * Tail (); inline const T * Tail () const; inline void Unlink (T * node); }; //=========================================================================== template void TList::Clear () { for (T * curr; (curr = Head()) != nil; Delete(curr)) ; } //=========================================================================== template void TList::Delete (T * node) { DEL(node); } //=========================================================================== template T * TList::Head () { return (T *)CBaseList::Head(); } //=========================================================================== template const T * TList::Head () const { return (const T *)CBaseList::Head(); } //=========================================================================== template bool TList::IsLinked (const T * node) const { return CBaseList::IsLinked((const byte *)node); } //=========================================================================== template void TList::Link (T * node, ELinkType linkType, T * existingNode) { CBaseList::Link((byte *)node, linkType, (byte *)existingNode); } //=========================================================================== template void TList::Link (TList * list, ELinkType linkType, T * existingNode) { CBaseList::Link(list, nil, nil, linkType, (byte *)existingNode); } //=========================================================================== template void TList::Link (TList * list, T * afterNode, T * beforeNode, ELinkType linkType, T * existingNode) { CBaseList::Link(list, (byte *)afterNode, (byte *)beforeNode, linkType, (byte *)existingNode); } //=========================================================================== template inline T * TList::Next (const T * node) { return (T *)CBaseList::Next((byte *)node); } //=========================================================================== template inline const T * TList::Next (const T * node) const { return (const T *)CBaseList::Next((byte *)node); } //=========================================================================== template inline T * TList::NextUnchecked (const T * node) { return (T *)CBaseList::NextUnchecked((byte *)node); } //=========================================================================== template inline const T * TList::NextUnchecked (const T * node) const { return (const T *)CBaseList::NextUnchecked((byte *)node); } //=========================================================================== template inline T * TList::New (ELinkType linkType, T * existingNode, const char file[], int line) { return NewFlags(0, linkType, existingNode, file, line); } //=========================================================================== template inline T * TList::NewFlags (unsigned flags, ELinkType linkType, T * existingNode, const char file[], int line) { if (!file) { file = __FILE__; line = __LINE__; } T * node = new(MemAlloc(sizeof(T), flags, file, line)) T; if (linkType != kListUnlinked) Link(node, linkType, existingNode); return node; } //=========================================================================== template inline T * TList::NewZero (ELinkType linkType, T * existingNode, const char file[], int line) { return NewFlags(0, linkType, existingNode, file, line); } //=========================================================================== template inline T * TList::Prev (const T * node) { return (T *)CBaseList::Prev((byte *)node); } //=========================================================================== template inline const T * TList::Prev (const T * node) const { return (const T *)CBaseList::Prev((byte *)node); } //=========================================================================== template inline T * TList::Tail () { return (T *)CBaseList::Tail(); } //=========================================================================== template inline const T * TList::Tail () const { return (const T *)CBaseList::Tail(); } //=========================================================================== template inline void TList::Unlink (T * node) { CBaseList::Unlink((byte *)node); } /**************************************************************************** * * TListDecl * ***/ template class TListDecl : public TList { public: inline TListDecl (); }; //=========================================================================== template TListDecl::TListDecl () { this->SetLinkOffset(linkOffset); } /**************************************************************************** * * TListDyn * ***/ template class TListDyn : public TList { public: void Initialize (int linkOffset); }; //=========================================================================== template void TListDyn::Initialize (int linkOffset) { this->SetLinkOffset(linkOffset); }