Windows-Server-2003/enduser/troubleshoot/bn/gelmwalk.h

160 lines
3.8 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1997
//
// File: gelmwalk.h
//
//--------------------------------------------------------------------------
//
// gelmwalk.h
//
#ifndef _GELMWALK_H_
#define _GELMWALK_H_
#include "gelem.h"
// Control structure
struct EWALKCTL
{
int _bBreadth : 1; // Breath-first or Depth-first
int _bAscend : 1; // Up or down
int _bInvert : 1; // Normal order or backwards
};
////////////////////////////////////////////////////////////////////
// class GRPHWALK: Generalize walk-a-graph class.
//
// Subclass and declare BSelect() and BMark().
// BSelect() is called to decide if a node should be followed.
// BMark() is called to perform unique work on the node. If
// it returns false, walk is terminated immediately.
//
////////////////////////////////////////////////////////////////////
class GRPHWALK
{
public:
GRPHWALK ( GNODE * pnodeStart, EWALKCTL ectl )
: _pnodeStart(pnodeStart),
_ectl(ectl)
{}
~ GRPHWALK() {}
void Walk ()
{
if ( _ectl._bBreadth )
BBreadthFirst( _pnodeStart );
else
BDepthFirst( _pnodeStart );
}
protected:
GNODE * _pnodeStart; // Point of origin
EWALKCTL _ectl; // Type, ordering and direction flags
protected:
// Return true if this node should be followed
virtual bool BSelect ( GNODE * pnode ) = 0;
// Mark/fiddle with the node; return false if enumeration should end
virtual bool BMark ( GNODE * pnode ) = 0;
bool BDepthFirst ( GNODE * pnode );
bool BBreadthFirst ( GNODE * pnode );
};
////////////////////////////////////////////////////////////////////
// template GRPHWALKER:
// Template for generating walk-a-graph routines
////////////////////////////////////////////////////////////////////
template <class GND>
class GRPHWALKER : public GRPHWALK
{
public:
GRPHWALKER ( GND * pnodeStart, EWALKCTL ectl );
// You must write your own variants of these
virtual bool BSelect ( GND * pnode );
virtual bool BMark ( GND * pnode );
protected:
// Type-safe redirectors for derived base types.
virtual bool BSelect ( GNODE * pnode )
{ return BSelect( (GND *) pnode ); }
virtual bool BMark ( GNODE * pnode )
{ return BMark( (GND *) pnode ); }
};
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Inline member functions
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
inline
bool GRPHWALK :: BDepthFirst ( GNODE * pnode )
{
GNODENUM<GNODE> itnd( _ectl._bAscend, _ectl._bInvert );
for ( ; itnd.PnodeCurrent(); itnd++ )
{
GNODE * pnode2 = *itnd;
if ( BSelect( pnode2 ) )
{
if ( ! BMark( pnode2 ) )
return false;
BDepthFirst( pnode2 );
}
}
return true;
}
inline
bool GRPHWALK :: BBreadthFirst ( GNODE * pnode )
{
VPGNODE vpnodeA;
VPGNODE vpnodeB;
VPGNODE * pvThis = & vpnodeA;
VPGNODE * pvNext = & vpnodeB;
VPGNODE * pvTemp = NULL;
// Seed the arrays with the starting position
pvNext->push_back(pnode);
// Create the reusable enumerator
GNODENUM<GNODE> itnd( _ectl._bAscend, _ectl._bInvert );
while ( pvNext->size() > 0)
{
// Swap the arrays from the last cycle and this cycle
pvTemp = pvThis;
pvThis = pvNext;
pvNext = pvTemp;
pvNext->clear();
// Walk all descendents at this level and expand the next level
// into the secondary array
for ( INT iThis = 0; iThis < pvThis->size(); iThis++ )
{
GNODE * pnode = (*pvThis)[iThis];
for ( itnd.Set( pnode ); itnd.PnodeCurrent(); itnd++ )
{
GNODE * pnode2 = *itnd;
if ( BSelect( pnode2 ) )
{
if ( ! BMark( pnode2 ) )
return false;
pvNext->push_back(pnode2);
}
}
}
}
return true;
}
#endif //