/*++ Copyright (c) 1994 Microsoft Corporation All rights reserved. Module Name: splutil.hxx Abstract: Common utils. Author: Albert Ting (AlbertT) 29-May-1994 Revision History: --*/ #ifndef _SPLUTIL_HXX #define _SPLUTIL_HXX // // Double linked list. DLINK must be the same as DLINKBASE, except // with differnt constructors. // typedef struct DLINK { DLINK() { FLink = NULL; } DLINK* FLink; DLINK* BLink; } *PDLINK; typedef struct DLINKBASE { DLINKBASE() { FLink = BLink = (PDLINK)this; } DLINK* FLink; DLINK* BLink; } *PDLINKBASE; class TIter { public: PDLINK _pdlink; PDLINK _pdlBase; BOOL bValid() { return _pdlink != _pdlBase; } VOID vNext() { _pdlink = _pdlink->FLink; } VOID vPrev() { _pdlink = _pdlink->BLink; } operator PDLINK() { return _pdlink; } }; VOID LinkListDump( PDLINK pHead, DWORD offset, LPCSTR pcszType, LPCSTR pcszName ); /******************************************************************** // Forward reference. class TLink; TBase has two linked lists of TLink. class TBase { DLINK_BASE( TLink, Link, Link ); DLINK_BASE( TLink, Link2, Link2 ); }; class TLink { DLINK( TLink, Link ); DLINK( TLink, Link2 ); }; // // Append pLink to the end of the Link2 list. // pBase->Link2_vAppend( pLink ); // // Insert pLinkInsert right after pLinkMiddle. // pBase->Link_vInsert( pLinkMiddle, pLinkInsert ); // // Get to the head. // pLinkHead = pBase->Link_pHead(); // // To get to the next element in the list. // pLink = pLinkHead->Link_pNext(); // // Remove an element from the list. // pLink->pLink_vDelinkSelf(); // // Using the iter class. // TIter Iter; for( Link_vIterInit( Iter ), Iter.vNext(); Iter.bValid(); Iter.vNext( )){ // // Use pLink. // vLinkOperation( pLink ); } ********************************************************************/ #define DLINK_BASE( type, name, linkname ) \ VOID name##_vReset() \ { pdl##name()->FLink = pdl##name()->BLink = pdl##name(); } \ \ PDLINK name##_pdlHead() const \ { return pdl##name()->FLink; } \ \ PDLINK name##_pdlBase() const \ { return pdl##name(); } \ \ type* name##_pHead( VOID ) const \ { \ return name##_bValid( name##_pdlHead() ) ? \ (type*)((PBYTE)name##_pdlHead() - OFFSETOF( type, \ _dl##linkname )) : \ NULL; \ } \ \ BOOL name##_bValid( PDLINK pdlink ) const \ { return pdlink != pdl##name(); } \ \ VOID name##_vAdd( type* pType ) \ { name##_vInsert( pdl##name(), pType->pdl##linkname( )); } \ \ VOID name##_vAppend( type* pType ) \ { name##_vInsert( pdl##name()->BLink, pType->pdl##linkname( )); } \ \ VOID name##_vInsert( PDLINK pdlink1, type* pType2 ) \ { name##_vInsert( pdlink1, pType2->pdl##linkname() ); } \ \ VOID name##_vInsert( PDLINK pdlink1, PDLINK pdlink2 ) \ { \ SPLASSERT( !pdlink2->FLink ); \ pdlink1->FLink->BLink = pdlink2; \ \ pdlink2->BLink = pdlink1; \ pdlink2->FLink = pdlink1->FLink; \ \ pdlink1->FLink = pdlink2; \ } \ \ VOID name##_vInsertBefore( PDLINK pdlink1, type* pType2 ) \ { name##_vInsertBefore( pdlink1, pType2->pdl##linkname() ); } \ \ VOID name##_vInsertBefore( PDLINK pdlink1, PDLINK pdlink2 ) \ { \ SPLASSERT( !pdlink2->FLink ); \ pdlink1->BLink->FLink = pdlink2; \ \ pdlink2->FLink = pdlink1; \ pdlink2->BLink = pdlink1->BLink; \ \ pdlink1->BLink = pdlink2; \ } \ \ VOID name##_vDelink( type* pType ) \ { name##_vDelink( pType->pdl##linkname( )); } \ \ VOID name##_vDelink( PDLINK pdlink ) \ { \ pdlink->FLink->BLink = pdlink->BLink; \ pdlink->BLink->FLink = pdlink->FLink; \ pdlink->FLink = NULL; \ } \ \ type* name##_pFind( type* pType ) const \ { \ PDLINK pdlinkT; \ PDLINK pdlink = pType->pdl##linkname(); \ \ for( pdlinkT = name##_pdlHead(); \ name##_bValid( pdlinkT ); \ pdlinkT = pdlinkT->FLink ){ \ \ if( pType->pdl##linkname() == pdlinkT ) \ return (type*)((PBYTE)pdlink - OFFSETOF( type, \ _dl##linkname )); \ } \ return NULL; \ } \ \ PDLINK name##_pdlFind( PDLINK pdlink ) const \ { \ PDLINK pdlinkT; \ for( pdlinkT = name##_pdlHead(); \ name##_bValid( pdlinkT ); \ pdlinkT = pdlinkT->FLink ){ \ \ if( pdlink == pdlinkT ) \ return pdlink; \ } \ return NULL; \ } \ \ PDLINK name##_pdlGetByIndex( UINT uIndex ) const \ { \ PDLINK pdlink; \ for( pdlink = name##_pdlHead(); \ uIndex; \ uIndex--, pdlink = pdlink->FLink ){ \ \ SPLASSERT( name##_bValid( pdlink )); \ } \ return pdlink; \ } \ \ type* name##_pGetByIndex( UINT uIndex ) const \ { \ PDLINK pdlink; \ for( pdlink = name##_pdlHead(); \ uIndex; \ uIndex--, pdlink = pdlink->FLink ){ \ \ SPLASSERT( name##_bValid( pdlink )); \ } \ return name##_pConvert( pdlink ); \ } \ \ VOID name##_vDump( VOID ) const \ { \ LinkListDump( pdl##name(), \ OFFSETOF( type, _dl##linkname ), \ #type, \ #name ); \ } \ \ static PDLINK name##_pdlNext( PDLINK pdlink ) \ { return pdlink->FLink; } \ \ static type* name##_pConvert( PDLINK pdlink ) \ { return (type*)( (PBYTE)pdlink - OFFSETOF( type, _dl##linkname )); } \ \ PDLINK pdl##name( VOID ) const \ { return (PDLINK)&_dlb##name; } \ \ BOOL name##_bEmpty() const \ { return pdl##name()->FLink == pdl##name(); } \ \ VOID name##_vIterInit( TIter& Iter ) const \ { Iter._pdlBase = Iter._pdlink = (PDLINK)&_dlb##name; } \ \ DLINKBASE _dlb##name; \ #define DLINK( type, name ) \ PDLINK pdl##name() \ { return &_dl##name; } \ \ VOID name##_vDelinkSelf( VOID ) \ { \ _dl##name.FLink->BLink = _dl##name.BLink; \ _dl##name.BLink->FLink = _dl##name.FLink; \ _dl##name.FLink = NULL; \ } \ \ BOOL name##_bLinked() const \ { return _dl##name.FLink != NULL; } \ \ PDLINK name##_pdlNext( VOID ) const \ { return _dl##name.FLink; } \ \ PDLINK name##_pdlPrev( VOID ) const \ { return _dl##name.BLink; } \ \ type* name##_pNext( VOID ) const \ { return name##_pConvert( _dl##name.FLink ); } \ \ type* name##_pPrev( VOID ) const \ { return name##_pConvert( _dl##name.BLink ); } \ \ static type* name##_pConvert( PDLINK pdlink ) \ { return (type*)( (PBYTE)pdlink - OFFSETOF( type, _dl##name )); } \ \ DLINK _dl##name // // Generic MEntry class that allows objects to be stored on a list // and searched by name. // class MEntry { SIGNATURE( 'entr' ) public: DLINK( MEntry, Entry ); TString _strName; BOOL bValid() { return _strName.bValid(); } static MEntry* pFindEntry( PDLINK pdlink, LPCTSTR pszName ); }; #define ENTRY_BASE( type, name ) \ friend MEntry; \ type* name##_pFindByName( LPCTSTR pszName ) const \ { \ MEntry* pEntry = MEntry::pFindEntry( name##_pdlBase(), pszName ); \ return pEntry ? (type*)pEntry : NULL; \ } \ static type* name##_pConvertEntry( PDLINK pdlink ) \ { \ return (type*)name##_pConvert( pdlink ); \ } \ DLINK_BASE( MEntry, name, Entry ) #define DELETE_ENTRY_LIST( type, name ) \ { \ PDLINK pdlink; \ type* pType; \ \ for( pdlink = name##_pdlHead(); name##_bValid( pdlink ); ){ \ \ pType = name##_pConvertEntry( pdlink ); \ pdlink = name##_pdlNext( pdlink ); \ \ pType->vDelete(); \ } \ } #endif // ndef _SPLUTIL_HXX