Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

604 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1997
  6. //
  7. // File: gelem.h
  8. //
  9. //--------------------------------------------------------------------------
  10. //
  11. // GELEM.H
  12. //
  13. #ifndef _GELEM_H_
  14. #define _GELEM_H_
  15. // Disable warning about using 'bool'
  16. #pragma warning ( disable : 4237 )
  17. #include "glnk.h"
  18. #include "leakchk.h"
  19. class GNODE;
  20. class GEDGE;
  21. // Classes for the type-safe links in arcs to nodes and links in nodes
  22. // to arcs.
  23. class GEDGLNK : public XLSS<GEDGE> {};
  24. class GNODLNK : public XLSS<GNODE> {};
  25. ////////////////////////////////////////////////////////////////////
  26. // class GNODE: Base class for node in a graph or tree. Subclassed
  27. // from GELEM to imbedded LNKs will know how to compute
  28. // proper offsets.
  29. ////////////////////////////////////////////////////////////////////
  30. class GNODE : public GELEMLNK
  31. {
  32. friend class GEDGE;
  33. public:
  34. GNODE ();
  35. virtual ~ GNODE ();
  36. // Accessors (const and non-const)
  37. // Return the source arc cursor (or NULL)
  38. // Return the sink arc cursor (or NULL)
  39. virtual GEDGE * & PedgeSource ()
  40. { return _glkArcs.PlnkSource() ; }
  41. virtual GEDGE * & PedgeSink ()
  42. { return _glkArcs.PlnkSink() ; }
  43. virtual GEDGE * PedgeSource () const
  44. { return _glkArcs.PlnkSource() ; }
  45. virtual GEDGE * PedgeSink () const
  46. { return _glkArcs.PlnkSink() ; }
  47. // Return counts of arcs in the given direction
  48. virtual UINT CSourceArc () const;
  49. virtual UINT CSinkArc () const;
  50. // Return counts of arcs in the given direction filtering by type
  51. virtual UINT CSourceArcByEType ( int eType ) const;
  52. virtual UINT CSinkArcByEType ( int eType ) const;
  53. virtual INT EType () const
  54. { return EGELM_NODE ; }
  55. LEAK_VAR_ACCESSOR
  56. protected:
  57. // Return the correct insertion point for a new arc, source or sink.
  58. // Called whenever a new arc is created to maintain ordering of arcs.
  59. // Default behavior is to add the new arc as the last.
  60. virtual GEDGE * PedgeOrdering ( GEDGE * pgedge, bool bSource );
  61. // Notification routine called when an arc dies; used to adjust cursors
  62. virtual void ArcDeath ( GEDGE * pgedge, bool bSource );
  63. protected:
  64. // Arc cursors: pointers to one source and one sink arc
  65. GEDGLNK _glkArcs;
  66. LEAK_VAR_DECL
  67. HIDE_UNSAFE(GNODE);
  68. };
  69. DEFINEVP(GNODE);
  70. ////////////////////////////////////////////////////////////////////
  71. // class GEDGE: Base class for an arc in a graph.
  72. ////////////////////////////////////////////////////////////////////
  73. class GEDGE : public GELEMLNK
  74. {
  75. public:
  76. // Internal class for chains (doubly-linked lists) of arcs
  77. typedef XCHN<GEDGE> CHN;
  78. // Constructor requires source and sink nodes
  79. GEDGE ( GNODE * pgnSource, GNODE * pgnSink );
  80. virtual ~ GEDGE ();
  81. // Accessors:
  82. // Return source and sink arc chains
  83. CHN & ChnSource () { return _lkchnSource; }
  84. CHN & ChnSink () { return _lkchnSink; }
  85. // Return source and sink node
  86. GNODE * & PnodeSource() { return _glkNodes.PlnkSource(); }
  87. GNODE * & PnodeSink() { return _glkNodes.PlnkSink(); }
  88. virtual INT EType () const
  89. { return EGELM_EDGE ; }
  90. LEAK_VAR_ACCESSOR
  91. protected:
  92. // Chain of all arcs originating in the same source node
  93. CHN _lkchnSource;
  94. // Chain of all arcs terminating in the same sink node
  95. CHN _lkchnSink;
  96. // Source and sink node pointers
  97. GNODLNK _glkNodes;
  98. LEAK_VAR_DECL
  99. HIDE_UNSAFE(GEDGE);
  100. };
  101. ////////////////////////////////////////////////////////////////////
  102. // class GNODENUM_BASE:
  103. //
  104. // Base class for generic linkable object enumerators.
  105. // Each enumerator can enumerate up or down (source or sink)
  106. // and forward or reverse in the chain.
  107. ////////////////////////////////////////////////////////////////////
  108. class GNODENUM_BASE
  109. {
  110. // typedefs for pointer-to-member-function pointer types
  111. typedef bool (*PFFOLLOW) (GEDGE *);
  112. typedef GEDGE::CHN & (GEDGE::*PARCCHN)();
  113. typedef GEDGE * (GEDGE::CHN::*PNX)();
  114. typedef GNODE * & (GEDGE::*PARCDGN)();
  115. public:
  116. // Construct an enumerator.
  117. GNODENUM_BASE ( bool bSource, // true ==> enumerate source (parent) arcs
  118. bool bDir = true, // true ==> follow arc ordering forwards
  119. bool bBoth = false ) ; // true ==> enumerate other arcs also
  120. // Set the enumerator to have a new base; iDir == -1 means don't
  121. // change direction flag; otherwise, it's really a "bool".
  122. void Reset ( bool bSource, int iDir = 0, int bBoth = 0 ) ;
  123. // Set the arc following test function pointer. To use, declare
  124. // a function like "bool BMyFollow (GEDGE * pge)", and pass its
  125. // address to "SetPfFollow()". It will be called during enumeration
  126. // to see if an arc should be followed. Alternatively, you can
  127. // override "BFollow()" in your templated-derived subclass.
  128. void SetPfFollow ( PFFOLLOW pfFollow )
  129. { _pfFollow = pfFollow ; }
  130. // Set the intrinsic type of arc to follow (i.e., "EType()"); -1 ==> all.
  131. void SetETypeFollow ( int iEgelmTypeMin = -1, int iEgelmTypeMax = -1 )
  132. { _iETypeFollowMin = iEgelmTypeMin;
  133. _iETypeFollowMax = iEgelmTypeMax; }
  134. // Set the user-definable type of arc to follow (i.e., "IType()"); -1 ==> all.
  135. void SetITypeFollow ( int iITypeFollowMin = -1, int iITypeFollowMax = -1 )
  136. { _iITypeFollowMin = iITypeFollowMin;
  137. _iITypeFollowMax = iITypeFollowMax; }
  138. // Return the edge used for the current position
  139. GEDGE * PgedgeCurrent ()
  140. { return _pedgeCurrent; }
  141. protected:
  142. // Position to the next pointer; return NULL when done.
  143. bool BNext () ;
  144. // Assign the node being enumerated and the starting point
  145. void Set ( GNODE * pnode );
  146. // Overrideable routine to check arc type
  147. virtual bool BFollow ( GEDGE * pedge );
  148. // Call either the "follower" function or the virtualized follower.
  149. bool BFollowTest ( GEDGE * pedge )
  150. {
  151. return _pfFollow
  152. ? (*_pfFollow)(pedge)
  153. : BFollow(pedge);
  154. }
  155. // Set the starting point for this mode of iteration
  156. void SetStartPoint ();
  157. protected:
  158. PARCCHN _pfChn; // Pointer to member function to return chain
  159. PNX _pfNxPv; // Ptr to mbr func to move forward or back
  160. PARCDGN _pfPgn; // Ptr to member func to get node from arc
  161. GEDGE * _pedgeNext; // Next arc
  162. GEDGE * _pedgeStart; // Starting arc
  163. GEDGE * _pedgeCurrent; // Arc used for recent answer
  164. GNODE * _pnodeCurrent; // Recent answer
  165. GNODE * _pnodeBase; // Node of origin
  166. PFFOLLOW _pfFollow; // Follow override
  167. bool _bDir; // Horizontal direction of enumeration
  168. bool _bSource; // Vertical direction of enumeration
  169. bool _bBoth; // Enumerate arcs in both directions
  170. bool _bPhase; // Phase of the search (for _bBoth == true)
  171. // These values determine which kinds of arcs are to be followed;
  172. // -1 implies not set. Used by BFollow().
  173. int _iETypeFollowMin; // Follow this canonical type of arc
  174. int _iETypeFollowMax;
  175. int _iITypeFollowMin; // Follow this user-defined type of arc
  176. int _iITypeFollowMax;
  177. };
  178. ////////////////////////////////////////////////////////////////////
  179. // template GNODENUM:
  180. //
  181. // Generic enumeration class for nodes. All conversions are type-safe;
  182. // exceptions will be thrown if accesses are made to objects which are
  183. // node subclasses of GNODE.
  184. //
  185. // Each enumerator can enumerate up or down (source or sink)
  186. // and forward or reverse in the chain.
  187. //
  188. // * Use Set() to set the starting node point.
  189. //
  190. // * Use the post-increment operator to advance.
  191. //
  192. // * Use Pcurrent() or pointer-dereference operator to get the
  193. // current node pointer.
  194. //
  195. // * Enumerators are reusable. To restart, reissue "Set()"; to
  196. // change enumeration parameters, use Reset().
  197. //
  198. ////////////////////////////////////////////////////////////////////
  199. template <class GND>
  200. class GNODENUM : public GNODENUM_BASE
  201. {
  202. public:
  203. GNODENUM ( bool bSrc, bool bDir = true, bool bBoth = false )
  204. : GNODENUM_BASE( bSrc, bDir, bBoth )
  205. {}
  206. void Set ( GND * pgnd )
  207. { GNODENUM_BASE::Set( pgnd ); }
  208. bool operator++ (int i)
  209. { return BNext() ; }
  210. bool operator++ ()
  211. { return BNext() ; }
  212. GND * PnodeCurrent ()
  213. {
  214. GND * pnode = NULL;
  215. if ( _pnodeCurrent )
  216. DynCastThrow( _pnodeCurrent, pnode );
  217. return pnode;
  218. }
  219. GND * operator -> ()
  220. { return PnodeCurrent() ; }
  221. GND * operator * ()
  222. { return PnodeCurrent() ; }
  223. void Reset ( bool bSrc, int iDir = -1, int iBoth = -1 )
  224. { GNODENUM_BASE::Reset( bSrc, iDir, iBoth ) ; }
  225. protected:
  226. bool BNext ()
  227. { return GNODENUM_BASE::BNext() ; }
  228. HIDE_UNSAFE(GNODENUM);
  229. };
  230. ////////////////////////////////////////////////////////////////////
  231. // class GRPH: a generalized graph
  232. //
  233. // This is a linkable object because it acts as the anchor
  234. // for its linked list, which connects all enumerable items
  235. // in this collection.
  236. ////////////////////////////////////////////////////////////////////
  237. class GRPH : public GELEMLNK
  238. {
  239. public:
  240. GRPH () {}
  241. virtual ~ GRPH ()
  242. { Clear(); }
  243. virtual void AddElem ( GELEMLNK & gelemlnk )
  244. { gelemlnk.ChnColl().Link( this ); }
  245. virtual INT EType () const
  246. { return EGELM_GRAPH ; }
  247. // Remove all elements from the graph
  248. void Clear ()
  249. {
  250. GELEMLNK * pgelem;
  251. while ( pgelem = ChnColl().PgelemNext() )
  252. delete pgelem;
  253. }
  254. HIDE_UNSAFE(GRPH);
  255. };
  256. ////////////////////////////////////////////////////////////////////
  257. ////////////////////////////////////////////////////////////////////
  258. // Inline member functions
  259. ////////////////////////////////////////////////////////////////////
  260. ////////////////////////////////////////////////////////////////////
  261. inline
  262. GNODE :: GNODE ()
  263. {
  264. LEAK_VAR_UPD(1)
  265. }
  266. inline
  267. GNODE :: ~ GNODE ()
  268. {
  269. GEDGE * pedge = NULL;
  270. while ( pedge = PedgeSource() )
  271. delete pedge;
  272. while ( pedge = PedgeSink() )
  273. delete pedge;
  274. LEAK_VAR_UPD(-1)
  275. }
  276. inline
  277. GEDGE :: GEDGE ( GNODE * pnodeSource, GNODE * pnodeSink )
  278. : _lkchnSource(this),
  279. _lkchnSink(this)
  280. {
  281. if ( pnodeSource == NULL || pnodeSink == NULL )
  282. throw GMException( EC_NULLP,
  283. "attempt to construct a GEDGE without linkage" );
  284. // Bind to the pair of nodes
  285. PnodeSource() = pnodeSource;
  286. PnodeSink() = pnodeSink;
  287. // Determine insertion point into source and sink chains, and
  288. // inform nodes of our existence
  289. GEDGE * pedgeSource = pnodeSource->PedgeOrdering( this, false );
  290. GEDGE * pedgeSink = pnodeSink->PedgeOrdering( this, true );
  291. if ( pedgeSource )
  292. {
  293. ChnSource().Link( pedgeSource );
  294. }
  295. if ( pedgeSink )
  296. {
  297. ChnSink().Link( pedgeSink );
  298. }
  299. LEAK_VAR_UPD(1)
  300. }
  301. inline
  302. GEDGE :: ~ GEDGE ()
  303. {
  304. PnodeSource()->ArcDeath( this, false );
  305. PnodeSink()->ArcDeath( this, true );
  306. LEAK_VAR_UPD(-1)
  307. }
  308. inline
  309. UINT GNODE :: CSourceArc () const
  310. {
  311. return PedgeSource()
  312. ? PedgeSource()->ChnSink().Count()
  313. : 0;
  314. }
  315. inline
  316. UINT GNODE :: CSinkArc () const
  317. {
  318. return PedgeSink()
  319. ? PedgeSink()->ChnSource().Count()
  320. : 0;
  321. }
  322. // Return counts of arcs in the given direction filtering by type
  323. inline
  324. UINT GNODE :: CSourceArcByEType ( int eType ) const
  325. {
  326. UINT cArcs = 0;
  327. GEDGE * pgedgeStart = PedgeSource();
  328. GEDGE * pgedge = pgedgeStart;
  329. while ( pgedge )
  330. {
  331. if ( pgedge->EType() == eType )
  332. ++cArcs;
  333. pgedge = pgedge->ChnSink().PgelemNext();
  334. if ( pgedge == pgedgeStart )
  335. break;
  336. }
  337. return cArcs;
  338. }
  339. inline
  340. UINT GNODE :: CSinkArcByEType ( int eType ) const
  341. {
  342. UINT cArcs = 0;
  343. GEDGE * pgedgeStart = PedgeSink();
  344. GEDGE * pgedge = pgedgeStart;
  345. while ( pgedge )
  346. {
  347. if ( pgedge->EType() == eType )
  348. ++cArcs;
  349. pgedge = pgedge->ChnSource().PgelemNext();
  350. if ( pgedge == pgedgeStart )
  351. break;
  352. }
  353. return cArcs;
  354. }
  355. // Return the correct insertion point for a new edge,
  356. // source or sink.
  357. inline
  358. GEDGE * GNODE :: PedgeOrdering ( GEDGE * pedge, bool bSource )
  359. {
  360. GEDGE * pedgeOrdering = NULL;
  361. if ( bSource )
  362. {
  363. pedgeOrdering = PedgeSource();
  364. if ( ! pedgeOrdering )
  365. PedgeSource() = pedge;
  366. }
  367. else
  368. {
  369. pedgeOrdering = PedgeSink();
  370. if ( ! pedgeOrdering )
  371. PedgeSink() = pedge;
  372. }
  373. return pedgeOrdering;
  374. }
  375. inline
  376. void GNODE :: ArcDeath ( GEDGE * pedge, bool bSource )
  377. {
  378. if ( bSource )
  379. {
  380. if ( pedge == PedgeSource() )
  381. PedgeSource() = pedge->ChnSink().PgelemNext();
  382. if ( pedge == PedgeSource() )
  383. PedgeSource() = NULL;
  384. }
  385. else
  386. {
  387. if ( pedge == PedgeSink() )
  388. PedgeSink() = pedge->ChnSource().PgelemNext();
  389. if ( pedge == PedgeSink() )
  390. PedgeSink() = NULL;
  391. }
  392. }
  393. inline
  394. GNODENUM_BASE :: GNODENUM_BASE ( bool bSource, bool bDir, bool bBoth )
  395. : _pfChn(NULL),
  396. _pfNxPv(NULL),
  397. _pfPgn(NULL),
  398. _pfFollow(NULL),
  399. _iETypeFollowMin(-1),
  400. _iETypeFollowMax(-1),
  401. _iITypeFollowMin(-1),
  402. _iITypeFollowMax(-1),
  403. _pnodeBase(NULL)
  404. {
  405. Reset( bSource, bDir, bBoth ) ;
  406. }
  407. // Set the base object for the enumeration
  408. inline
  409. void GNODENUM_BASE :: Reset ( bool bSource, int iDir, int iBoth )
  410. {
  411. if ( iDir >= 0 )
  412. _bDir = iDir ;
  413. if ( iBoth >= 0 )
  414. _bBoth = iBoth;
  415. _bSource = bSource;
  416. _pfNxPv = _bDir
  417. ? & GEDGE::CHN::PgelemNext
  418. : & GEDGE::CHN::PgelemPrev;
  419. if ( _bSource )
  420. {
  421. _pfChn = & GEDGE::ChnSink;
  422. _pfPgn = & GEDGE::PnodeSource;
  423. }
  424. else
  425. {
  426. _pfChn = & GEDGE::ChnSource;
  427. _pfPgn = & GEDGE::PnodeSink;
  428. }
  429. _pedgeStart = _pedgeNext = _pedgeCurrent = NULL;
  430. _pnodeCurrent = NULL;
  431. _bPhase = false;
  432. }
  433. // Set the starting point of the iteration. If 'pnode' is NULL,
  434. // use the original node.
  435. inline
  436. void GNODENUM_BASE :: Set ( GNODE * pnode )
  437. {
  438. if ( pnode )
  439. _pnodeBase = pnode;
  440. SetStartPoint();
  441. BNext();
  442. }
  443. inline
  444. void GNODENUM_BASE :: SetStartPoint ()
  445. {
  446. _pedgeNext = _bSource
  447. ? _pnodeBase->PedgeSource()
  448. : _pnodeBase->PedgeSink();
  449. _pedgeStart = _pedgeNext;
  450. }
  451. // Follow the arc if the constraints are met, both inherent type (EType())
  452. // and user-definable type (IType().
  453. inline
  454. bool GNODENUM_BASE :: BFollow ( GEDGE * pedge )
  455. {
  456. if ( _iETypeFollowMin >= 0 )
  457. {
  458. int etype = pedge->EType();
  459. if ( _iETypeFollowMax < 0 )
  460. {
  461. // Just the "min" is set; compare equal
  462. if ( etype !=_iETypeFollowMin )
  463. return false;
  464. }
  465. else
  466. {
  467. if ( etype < _iETypeFollowMin || etype > _iETypeFollowMax )
  468. return false;
  469. }
  470. }
  471. if ( _iITypeFollowMin >= 0 )
  472. {
  473. int itype = pedge->IType();
  474. if ( _iITypeFollowMax < 0 )
  475. {
  476. // Just the "min" is set; compare equal
  477. if ( itype !=_iITypeFollowMin )
  478. return false;
  479. }
  480. else
  481. {
  482. if ( itype < _iITypeFollowMin || itype > _iITypeFollowMax )
  483. return false;
  484. }
  485. }
  486. return true;
  487. }
  488. inline
  489. bool GNODENUM_BASE :: BNext ()
  490. {
  491. _pnodeCurrent = NULL;
  492. _pedgeCurrent = NULL;
  493. do
  494. {
  495. while ( _pedgeNext == NULL )
  496. {
  497. // If we're not iterating both directions,
  498. // or this is phase 2, exit.
  499. if ( _bPhase || ! _bBoth )
  500. return false;
  501. // Set "2nd phase" flag, invert source/sink
  502. Reset( !_bSource );
  503. _bPhase = true;
  504. SetStartPoint();
  505. }
  506. if ( BFollowTest( _pedgeNext ) )
  507. {
  508. _pedgeCurrent = _pedgeNext;
  509. _pnodeCurrent = (_pedgeNext->*_pfPgn)();
  510. }
  511. GEDGE::CHN & chn = (_pedgeNext->*_pfChn)();
  512. _pedgeNext = (chn.*_pfNxPv)();
  513. if ( _pedgeStart == _pedgeNext )
  514. _pedgeNext = NULL;
  515. } while ( _pnodeCurrent == NULL );
  516. return _pnodeCurrent != NULL;
  517. }
  518. #endif