//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1997 // // File: glnk.h // //-------------------------------------------------------------------------- // // GLNK.H // // This file defines base classes for smart linked lists. // #if !defined(_GLNK_H_) #define _GLNK_H_ #include "basics.h" // Disable "warning C4355: 'this' : used in base member initializer list" #pragma warning ( disable : 4355 ) // Disable warning about using 'bool' #pragma warning ( disable : 4237 ) // Forward declarations class GLNK; // Just a linked list anchor class GELEM; // Base class for trees or dags class GLNKEL; // A linked element class GLNKCHN ; // An imbeddable element class GELEMLNK; // A containerizable element //////////////////////////////////////////////////////////////////// // class GLNKBASE: just a pair of pointers. Used as a basis for // linked lists and bidirectional pointers. // //////////////////////////////////////////////////////////////////// class GLNKBASE // A linked list anchor { protected: GLNKBASE * _plnkNext ; // The next link in the chain GLNKBASE * _plnkPrev ; // The previous link in the chain public: GLNKBASE () : _plnkNext(NULL), _plnkPrev(NULL) {} ~ GLNKBASE () {}; GLNKBASE * & PlnkNext () { return _plnkNext ; } GLNKBASE * & PlnkPrev () { return _plnkPrev ; } private: // Block compiler from generating invalid functions HIDE_UNSAFE(GLNKBASE); }; // Template to generate a pair of pointers to given subclass template class XLBASE { protected: L * _plNext ; L * _plPrev ; public: XLBASE () : _plNext(NULL), _plPrev(NULL) {} L * & PlnkNext () { return _plNext ; } L * & PlnkPrev () { return _plPrev ; } const L * PlnkNext () const { return _plNext ; } const L * PlnkPrev () const { return _plPrev ; } private: XLBASE(const XLBASE &); XLBASE & operator == (const XLBASE &); }; //////////////////////////////////////////////////////////////////// // template XLSS: simple alias template using "source" and "sink" // terminology. //////////////////////////////////////////////////////////////////// template class XLSS : public XLBASE { public: L * & PlnkSink () { return _plNext ; } L * & PlnkSource () { return _plPrev ; } L * PlnkSink () const { return _plNext ; } L * PlnkSource () const { return _plPrev ; } }; //////////////////////////////////////////////////////////////////// // class GLNK: basic doubly-linked list. Linkage is always // done directly between LNKs, not their containing objects // //////////////////////////////////////////////////////////////////// class GLNK : public GLNKBASE // A linked list anchor { protected: void Empty () { PlnkPrev() = this ; PlnkNext() = this ; } GLNK () { Empty() ; } ~ GLNK () { Unlink() ; } void Link ( GLNK * plnkNext ) { Unlink() ; PlnkPrev() = plnkNext->PlnkPrev() ; PlnkNext() = plnkNext ; plnkNext->PlnkPrev()->PlnkNext() = this ; PlnkNext()->PlnkPrev() = this ; } void Unlink () { PlnkNext()->PlnkPrev() = PlnkPrev() ; PlnkPrev()->PlnkNext() = PlnkNext() ; Empty() ; } // Const and non-const accessor to base pointer pair GLNK * & PlnkNext () { return (GLNK *&) _plnkNext ; } GLNK * & PlnkPrev () { return (GLNK *&) _plnkPrev ; } const GLNK * PlnkNext () const { return (GLNK *) _plnkNext ; } const GLNK * PlnkPrev () const { return (GLNK *) _plnkPrev ; } public: // Return count of elements on list, including self long Count () const { long cItem = 1 ; for ( GLNK * plnkNext = (CONST_CAST(GLNK *, this))->PlnkNext() ; plnkNext != this ; plnkNext = plnkNext->PlnkNext() ) { cItem++ ; } return cItem ; } bool BIsEmpty () const { return PlnkNext() == this ; } private: // Block compiler from generating invalid functions HIDE_UNSAFE(GLNK); }; //////////////////////////////////////////////////////////////////// // class GELEM: Base class for linkable objects //////////////////////////////////////////////////////////////////// const int g_IGelemTypeInc = 10000; class GELEM { friend class GLNKCHN ; public: GELEM() {} virtual ~ GELEM () {} enum EGELMTYPE { EGELM_NONE = 0, EGELM_NODE = EGELM_NONE + g_IGelemTypeInc, EGELM_EDGE = EGELM_NODE + g_IGelemTypeInc, EGELM_BRANCH = EGELM_EDGE + g_IGelemTypeInc, EGELM_LEAF = EGELM_BRANCH + g_IGelemTypeInc, EGELM_GRAPH = EGELM_LEAF + g_IGelemTypeInc, EGELM_TREE = EGELM_GRAPH + g_IGelemTypeInc, EGELM_CLIQUE = EGELM_GRAPH + g_IGelemTypeInc }; virtual INT EType () const { return EGELM_NONE ; } bool BIsEType ( INT egelmType ) { INT etype = egelmType / g_IGelemTypeInc; INT etypeThis = EType() / g_IGelemTypeInc; return etype == etypeThis; } protected: // Return the offset of the given pointer pair from the element. int CbOffsetFrom ( const GLNKBASE * p ) const // One could assert that the GLNKCHN really lies within object // boundaries by using a virtualized "sizeof" accessor. Also, // check mod-4 and other validity conditions. { return ((char*)p) - ((char*)this) ; } }; //////////////////////////////////////////////////////////////////// // class GLNKCHN: // A GLNK which knows its offset within the containing object. // // To perform doubly-linked list operations, two pieces of information // are necessary: the location of the pointer pair and the location // of the containing object. By giving the GLNKCHN its offset from // the start of the object during construction, it can perform all // necessary operations, including automatically unlinking during // destruction. //////////////////////////////////////////////////////////////////// class GLNKCHN : public GLNK { private: int _cbOffset ; // Number of bytes offset from // start of owning structure public: GLNKCHN ( GELEM * pgelemOwner ) : _cbOffset(0) { _cbOffset = pgelemOwner->CbOffsetFrom( this ); } ~ GLNKCHN () {} void Link ( GELEM * pgelemNext ) { // Assuming that the GLNKCHN onto which we're linking is at the // same offset in the given GLNKEL as it is in *this, link it. GLNKCHN * plnkchn = PlnkchnPtr( pgelemNext ); GLNK::Link( plnkchn ) ; } void Unlink () { GLNK::Unlink() ; } GELEM * PgelemNext () { return BIsEmpty() ? NULL : PlnkchnNext()->PgelemChainOwnerPtr() ; } GELEM * PgelemPrev () { return BIsEmpty() ? NULL : PlnkchnPrev()->PgelemChainOwnerPtr() ; } protected: // Return a pointer to the base object. given a pointer to one of // its GLNKCHN member objects. GELEM * PgelemChainOwnerPtr () const { return (GELEM *) (((SZC) this) - _cbOffset) ; } // Given a pointer to a GELEM presumed to be of the same base // type as this object's container, return a pointer to the // corresponding GLNKCHN in it. GLNKCHN * PlnkchnPtr ( const GELEM * pgelem ) const { #ifdef _DEBUG // Debug version does error checking GLNKCHN * plnkchn = (GLNKCHN *) (((SZC) pgelem) + _cbOffset); if ( _cbOffset != plnkchn->_cbOffset ) throw GMException(EC_LINK_OFFSET,"invalid GLNKCHN offset"); return plnkchn; #else return (GLNKCHN *) (((SZC) pgelem) + _cbOffset); #endif } // Protected accessors to GLNK pointers cast to GLNKCHN pointers GLNKCHN * PlnkchnNext () { return (GLNKCHN *) GLNK::PlnkNext() ; } GLNKCHN * PlnkchnPrev () { return (GLNKCHN *) GLNK::PlnkPrev() ; } private: HIDE_UNSAFE(GLNKCHN); }; //////////////////////////////////////////////////////////////////// // template XCHN: // for creating types of chains given a containing object // which is a subclass of GELEM //////////////////////////////////////////////////////////////////// template class XCHN : public GLNKCHN { public: XCHN ( XOBJ * pgelemOwner ) : GLNKCHN(pgelemOwner) {} void Link ( XOBJ * pgelemNext ) { GLNKCHN::Link(pgelemNext); } void Unlink () { GLNKCHN::Unlink(); } XOBJ * PgelemNext () { return (XOBJ *) GLNKCHN::PgelemNext(); } XOBJ * PgelemPrev () { return (XOBJ *) GLNKCHN::PgelemPrev(); } XOBJ * PgelemThis () { return PgelemChainOwnerPtr(); } protected: XOBJ * PgelemChainOwnerPtr () const { return (XOBJ *) GLNKCHN::PgelemChainOwnerPtr(); } XCHN * PlnkchnPtr ( const XOBJ * pgelem ) const { return (XCHN *) GLNKCHN::PlnkchnPtr(pgelem); } XCHN * PlnkchnNext () { return (XCHN *) GLNKCHN::PlnkchnNext() ; } XCHN * PlnkchnPrev () { return (XCHN *) GLNKCHN::PlnkchnPrev() ; } private: XCHN(const XCHN &); XCHN & operator == (const XCHN &); }; //////////////////////////////////////////////////////////////////// // Class GLNKEL: // Simple base class for things managed as members of linked lists. // One or more LNKCHNs or LNKs can be contained within subclass objects; // it contains one "implicit" GLNKCHN for linking siblings in the // implicit tree created by NTREE. // Trees are based upon this type. //////////////////////////////////////////////////////////////////// class GLNKEL : public GELEM { public: // Internal class for chains (doubly-linked lists) typedef XCHN CHN; GLNKEL () : _chn( this ), _iType(0), _iMark(0) {} virtual ~ GLNKEL () {} CHN & Chn () { return _chn ; } GLNKEL * PlnkelPrev () { return Chn().PgelemPrev() ; } GLNKEL * PlnkelNext () { return Chn().PgelemNext() ; } // Return the mutable (user-definable) object type INT & IType () { return _iType; } INT IType() const { return _iType; } INT & IMark () { return _iMark; } INT IMark () const { return _iMark; } protected: CHN _chn ; // Primary association chain INT _iType; // User-definable type INT _iMark; // Network walking mark protected: // Throw an exception when an invalid cloning operation occurs void ThrowInvalidClone ( const GLNKEL & t ); HIDE_UNSAFE(GLNKEL); }; //////////////////////////////////////////////////////////////////// // Class GELEMLNK: // Base class for linkable objects in a collection, such as // graph. Trees are NOT based upon this type, since trees // are not forests (they cannot have associated but disjoint // sets of objects). //////////////////////////////////////////////////////////////////// class GELEMLNK : public GLNKEL { public: // Internal class for chains (doubly-linked lists) typedef XCHN CHN; GELEMLNK () {} virtual ~ GELEMLNK () {} // Locate an element (other than 'this') by type GELEMLNK * PglnkFind ( EGELMTYPE eType, bool bExact = false ) { for ( GELEMLNK * pg = this; pg->ChnColl().PgelemThis() != this; pg = pg->ChnColl().PgelemNext() ) { if ( bExact ? pg->EType() == eType : pg->BIsEType(eType) ) return pg; } return NULL; } // Element chain: all items belonging to this collection CHN & ChnColl () { return (CHN &) _chn ; } private: HIDE_UNSAFE(GELEMLNK); }; #endif // !defined(_GLNK_H_) // End of glnk.h