Team Fortress 2 Source Code as on 22/4/2020
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.

658 lines
17 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Header: $
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #ifndef UTLGRAPH_H
  9. #define UTLGRAPH_H
  10. #include "tier1/utlmap.h"
  11. #include "tier1/utlvector.h"
  12. #include <limits.h>
  13. //-------------------------------------
  14. //-----------------------------------------------------------------------------
  15. // A Graph class
  16. //
  17. // Nodes must have a unique Node ID.
  18. //
  19. // Edges are unidirectional, specified from the beginning node.
  20. //
  21. //-----------------------------------------------------------------------------
  22. template <class T, class C >
  23. class CUtlGraphVisitor;
  24. template <class T, class C = int >
  25. class CUtlGraph
  26. {
  27. public:
  28. typedef int I;
  29. typedef I IndexType_t;
  30. typedef T NodeID_t;
  31. typedef C CostType_t;
  32. typedef CUtlGraphVisitor<T,C> Visitor_t;
  33. struct Edge_t
  34. {
  35. IndexType_t m_DestinationNode;
  36. CostType_t m_EdgeCost;
  37. Edge_t( IndexType_t i = 0 )
  38. {
  39. m_DestinationNode = i;
  40. m_EdgeCost = 0;
  41. }
  42. bool operator==(const Edge_t &that ) const
  43. {
  44. return m_DestinationNode == that.m_DestinationNode;
  45. }
  46. static int SortFn( const Edge_t *plhs, const Edge_t *prhs )
  47. {
  48. if ( plhs->m_EdgeCost < prhs->m_EdgeCost )
  49. return -1;
  50. else if ( plhs->m_EdgeCost > prhs->m_EdgeCost )
  51. return 1;
  52. else return 0;
  53. }
  54. };
  55. typedef CUtlVector<Edge_t> vecEdges_t;
  56. // constructor, destructor
  57. CUtlGraph( );
  58. ~CUtlGraph();
  59. // Add an edge
  60. bool AddEdge( T SourceNode, T DestNode, C nCost );
  61. // Remove an edge
  62. bool RemoveEdge( T SourceNode, T DestNode );
  63. // gets particular elements
  64. T& Element( I i );
  65. T const &Element( I i ) const;
  66. T& operator[]( I i );
  67. T const &operator[]( I i ) const;
  68. // Find a node
  69. I Find( T Node ) { return m_Nodes.Find( Node ); }
  70. I Find( T Node ) const { return m_Nodes.Find( Node ); }
  71. // Num elements
  72. unsigned int Count() const { return m_Nodes.Count() ; }
  73. // Max "size" of the vector
  74. I MaxElement() const { return m_Nodes.MaxElement(); }
  75. // Checks if a node is valid and in the graph
  76. bool IsValidIndex( I i ) const { return m_Nodes.IsValidIndex( i ); }
  77. // Checks if the graph as a whole is valid
  78. bool IsValid() const { return m_Nodes.IsValid(); }
  79. // Invalid index
  80. static I InvalidIndex() { return CUtlMap< NodeID_t, vecEdges_t*>::InvalidIndex(); }
  81. // Remove methods
  82. void RemoveAt( I i );
  83. void RemoveAll();
  84. // Makes sure we have enough memory allocated to store a requested # of elements
  85. void EnsureCapacity( int num );
  86. // Create Path Matrix once you've added all nodes and edges
  87. void CreatePathMatrix();
  88. // For Visitor classes
  89. vecEdges_t *GetEdges( I i );
  90. // shortest path costs
  91. vecEdges_t *GetPathCosts( I i );
  92. #ifdef DBGFLAG_VALIDATE
  93. void Validate( CValidator &validator, const char *pchName );
  94. #endif // DBGFLAG_VALIDATE
  95. protected:
  96. struct Node_t
  97. {
  98. vecEdges_t *m_pvecEdges;
  99. vecEdges_t *m_pvecPaths;
  100. Node_t()
  101. {
  102. m_pvecEdges = NULL;
  103. m_pvecPaths = NULL;
  104. }
  105. };
  106. CUtlMap< NodeID_t, Node_t > m_Nodes;
  107. };
  108. //-----------------------------------------------------------------------------
  109. // A Graph "visitor" class
  110. //
  111. // From the specified beginning point, visits each node in an expanding radius
  112. //
  113. //-----------------------------------------------------------------------------
  114. template <class T, class C = int >
  115. class CUtlGraphVisitor
  116. {
  117. public:
  118. CUtlGraphVisitor( CUtlGraph<T, C> &graph );
  119. bool Begin( T StartNode );
  120. bool Advance();
  121. T CurrentNode();
  122. C AccumulatedCost();
  123. int CurrentRadius();
  124. private:
  125. typedef typename CUtlGraph<T,C>::IndexType_t IndexType_t;
  126. typedef typename CUtlGraph<T,C>::Edge_t Edge_t;
  127. typedef CUtlVector<Edge_t> vecEdges_t;
  128. CUtlGraph<T, C> &m_Graph;
  129. vecEdges_t m_vecVisitQueue;
  130. int m_iVisiting;
  131. int m_nCurrentRadius;
  132. vecEdges_t m_vecFringeQueue;
  133. CUtlVector<T> m_vecNodesVisited;
  134. };
  135. //-----------------------------------------------------------------------------
  136. // constructor, destructor
  137. //-----------------------------------------------------------------------------
  138. template <class T, class C >
  139. inline CUtlGraph<T, C>::CUtlGraph()
  140. {
  141. SetDefLessFunc( m_Nodes );
  142. }
  143. template <class T, class C >
  144. inline CUtlGraph<T, C>::~CUtlGraph()
  145. {
  146. RemoveAll();
  147. }
  148. //-----------------------------------------------------------------------------
  149. // gets particular elements
  150. //-----------------------------------------------------------------------------
  151. template <class T, class C >
  152. inline T &CUtlGraph<T, C>::Element( I i )
  153. {
  154. return m_Nodes.Key( i );
  155. }
  156. template <class T, class C >
  157. inline T const &CUtlGraph<T, C>::Element( I i ) const
  158. {
  159. return m_Nodes.Key( i );
  160. }
  161. template <class T, class C >
  162. inline T &CUtlGraph<T, C>::operator[]( I i )
  163. {
  164. return Element(i);
  165. }
  166. template <class T, class C >
  167. inline T const &CUtlGraph<T, C>::operator[]( I i ) const
  168. {
  169. return Element(i);
  170. }
  171. //-----------------------------------------------------------------------------
  172. //
  173. // various accessors
  174. //
  175. //-----------------------------------------------------------------------------
  176. //-----------------------------------------------------------------------------
  177. // Removes all nodes from the tree
  178. //-----------------------------------------------------------------------------
  179. template <class T, class C >
  180. void CUtlGraph<T, C>::RemoveAll()
  181. {
  182. FOR_EACH_MAP_FAST( m_Nodes, iNode )
  183. {
  184. delete m_Nodes[iNode].m_pvecEdges;
  185. delete m_Nodes[iNode].m_pvecPaths;
  186. }
  187. m_Nodes.RemoveAll();
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Makes sure we have enough memory allocated to store a requested # of elements
  191. //-----------------------------------------------------------------------------
  192. template <class T, class C >
  193. void CUtlGraph<T, C>::EnsureCapacity( int num )
  194. {
  195. m_Nodes.EnsureCapacity(num);
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Add an edge
  199. //-----------------------------------------------------------------------------
  200. template <class T, class C >
  201. bool CUtlGraph<T, C>::AddEdge( T SourceNode, T DestNode, C nCost )
  202. {
  203. I iSrcNode = m_Nodes.Find( SourceNode );
  204. if ( !m_Nodes.IsValidIndex( iSrcNode ) )
  205. {
  206. Node_t Node;
  207. Node.m_pvecEdges = new vecEdges_t();
  208. Node.m_pvecPaths = new vecEdges_t();
  209. iSrcNode = m_Nodes.Insert( SourceNode, Node );
  210. }
  211. I iDstNode = m_Nodes.Find( DestNode );
  212. if ( !m_Nodes.IsValidIndex( iDstNode ) )
  213. {
  214. Node_t Node;
  215. Node.m_pvecEdges = new vecEdges_t();
  216. Node.m_pvecPaths = new vecEdges_t();
  217. iDstNode = m_Nodes.Insert( DestNode, Node );
  218. }
  219. vecEdges_t &vecEdges = *m_Nodes[iSrcNode].m_pvecEdges;
  220. #ifdef _DEBUG
  221. FOR_EACH_VEC( vecEdges, iEdge )
  222. {
  223. if ( vecEdges[iEdge].m_DestinationNode == iDstNode )
  224. return false;
  225. }
  226. #endif
  227. Edge_t newEdge;
  228. newEdge.m_DestinationNode = iDstNode;
  229. newEdge.m_EdgeCost = nCost;
  230. vecEdges[ vecEdges.AddToTail() ] = newEdge;
  231. return true;
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Remove an edge
  235. //-----------------------------------------------------------------------------
  236. template <class T, class C >
  237. bool CUtlGraph<T, C>::RemoveEdge( T SourceNode, T DestNode )
  238. {
  239. I iSrcNode = m_Nodes.Find( SourceNode );
  240. if ( !m_Nodes.IsValidIndex( iSrcNode ) )
  241. return false;
  242. I iDstNode = m_Nodes.Find( DestNode );
  243. if ( !m_Nodes.IsValidIndex( iDstNode ) )
  244. return false;
  245. vecEdges_t &vecEdges = *m_Nodes[iSrcNode].m_pvecEdges;
  246. FOR_EACH_VEC( vecEdges, iEdge )
  247. {
  248. if ( vecEdges[iEdge].m_DestinationNode == iDstNode )
  249. {
  250. // could use FastRemove, but nodes won't have that
  251. // many edges, and the elements are small, and
  252. // preserving the original ordering is nice
  253. vecEdges.Remove( iEdge );
  254. return true;
  255. }
  256. }
  257. return false;
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Get all of a Node's edges
  261. //-----------------------------------------------------------------------------
  262. template <class T, class C >
  263. typename CUtlGraph<T, C>::vecEdges_t *CUtlGraph<T, C>::GetEdges( I i )
  264. {
  265. return m_Nodes[i].m_pvecEdges;
  266. }
  267. //-----------------------------------------------------------------------------
  268. // Get all of a Node's edges
  269. //-----------------------------------------------------------------------------
  270. template <class T, class C >
  271. typename CUtlGraph<T, C>::vecEdges_t *CUtlGraph<T, C>::GetPathCosts( I i )
  272. {
  273. return m_Nodes[i].m_pvecPaths;
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Data and memory validation
  277. //-----------------------------------------------------------------------------
  278. #ifdef DBGFLAG_VALIDATE
  279. template <class T, class C >
  280. void CUtlGraph<T, C>::Validate( CValidator &validator, const char *pchName )
  281. {
  282. #ifdef _WIN32
  283. validator.Push( typeid(*this).raw_name(), this, pchName );
  284. #else
  285. validator.Push( typeid(*this).name(), this, pchName );
  286. #endif
  287. ValidateObj( m_Nodes );
  288. FOR_EACH_MAP_FAST( m_Nodes, iNode )
  289. {
  290. validator.ClaimMemory( m_Nodes[iNode].m_pvecEdges );
  291. ValidateObj( *m_Nodes[iNode].m_pvecEdges );
  292. validator.ClaimMemory( m_Nodes[iNode].m_pvecPaths );
  293. ValidateObj( *m_Nodes[iNode].m_pvecPaths );
  294. }
  295. validator.Pop();
  296. }
  297. #endif // DBGFLAG_VALIDATE
  298. //-----------------------------------------------------------------------------
  299. // Get all of a Node's edges
  300. //-----------------------------------------------------------------------------
  301. template <class T, class C >
  302. void CUtlGraph<T, C>::CreatePathMatrix()
  303. {
  304. int n = MaxElement();
  305. // Notes
  306. // Because CUtlMap stores its nodes in essentially a vector,
  307. // we know that we can use its indices in our own path matrix
  308. // vectors safely (they will be numbers in the range (0,N) where
  309. // N is largest number of nodes ever present in the graph).
  310. //
  311. // This lets us very quickly access previous best-path estimates
  312. // by indexing into a node's vecPaths directly.
  313. //
  314. // When we are all done, we can then compact the vector, removing
  315. // "null" paths, and then sorting by cost.
  316. // Initialize matrix with all edges
  317. FOR_EACH_MAP_FAST( m_Nodes, iNode )
  318. {
  319. vecEdges_t &vecEdges = *m_Nodes.Element( iNode ).m_pvecEdges;
  320. vecEdges_t &vecPaths = *m_Nodes.Element( iNode ).m_pvecPaths;
  321. vecPaths.RemoveAll();
  322. vecPaths.AddMultipleToTail( n );
  323. FOR_EACH_VEC( vecPaths, iPath )
  324. {
  325. vecPaths[iPath].m_DestinationNode = InvalidIndex();
  326. }
  327. // Path to self
  328. vecPaths[iNode].m_DestinationNode = iNode;
  329. // zero cost to self
  330. vecPaths[iNode].m_EdgeCost = 0;
  331. FOR_EACH_VEC( vecEdges, iEdge )
  332. {
  333. // Path to a neighbor node - we know exactly what the cost is
  334. Edge_t &edge = vecEdges[iEdge];
  335. vecPaths[ edge.m_DestinationNode ].m_DestinationNode = edge.m_DestinationNode;
  336. vecPaths[ edge.m_DestinationNode ].m_EdgeCost = edge.m_EdgeCost;
  337. }
  338. }
  339. // Floyd-Warshall
  340. // for k:= 0 to n-1
  341. // for each (i,j) in (0..n-1)
  342. // path[i][j] = min( path[i][j], path[i][k]+path[k][j] );
  343. for ( int k = 0; k < n; ++ k )
  344. {
  345. if ( !m_Nodes.IsValidIndex( k ) )
  346. continue;
  347. // All current known paths from K
  348. vecEdges_t &destMapFromK = *m_Nodes[k].m_pvecPaths;
  349. for ( int i = 0; i < n; ++i )
  350. {
  351. if ( !m_Nodes.IsValidIndex( i ) )
  352. continue;
  353. // All current known paths from J
  354. vecEdges_t &destMapFromI = *m_Nodes[i].m_pvecPaths;
  355. // Path from I to K?
  356. int iFromIToK = k;
  357. bool bFromIToK = destMapFromI[iFromIToK].m_DestinationNode != InvalidIndex();
  358. CostType_t cIToK = ( bFromIToK ) ? destMapFromI[iFromIToK].m_EdgeCost : INT_MAX;
  359. for ( int j = 0; j < n; ++ j )
  360. {
  361. if ( !m_Nodes.IsValidIndex( j ) )
  362. continue;
  363. // Path from I to J already?
  364. int iFromIToJ = j;
  365. bool bFromIToJ = destMapFromI[iFromIToJ].m_DestinationNode != InvalidIndex();
  366. CostType_t cIToJ = ( bFromIToJ ) ? destMapFromI[iFromIToJ].m_EdgeCost : INT_MAX;
  367. // Path from K to J?
  368. int iFromKToJ = j;
  369. bool bFromKToJ = destMapFromK[iFromKToJ].m_DestinationNode != InvalidIndex();
  370. CostType_t cKToJ = ( bFromKToJ ) ? destMapFromK[iFromKToJ].m_EdgeCost : INT_MAX;
  371. // Is the new path valid?
  372. bool bNewPathFound = ( bFromIToK && bFromKToJ );
  373. if ( bNewPathFound )
  374. {
  375. if ( bFromIToJ )
  376. {
  377. // Pick min of previous best and current path
  378. destMapFromI[iFromIToJ].m_EdgeCost = min( cIToJ, cIToK + cKToJ );
  379. }
  380. else
  381. {
  382. // Current path is the first, hence the best so far
  383. destMapFromI[iFromIToJ].m_DestinationNode = iFromIToJ;
  384. destMapFromI[iFromIToJ].m_EdgeCost = cIToK + cKToJ;
  385. }
  386. }
  387. }
  388. }
  389. }
  390. // Clean up and sort the paths
  391. FOR_EACH_MAP_FAST( m_Nodes, iNode )
  392. {
  393. vecEdges_t &vecPaths = *m_Nodes.Element( iNode ).m_pvecPaths;
  394. FOR_EACH_VEC( vecPaths, iPath )
  395. {
  396. Edge_t &edge = vecPaths[iPath];
  397. if ( edge.m_DestinationNode == InvalidIndex() )
  398. {
  399. // No path to this destination was found.
  400. // Remove this entry from the vector.
  401. vecPaths.FastRemove( iPath );
  402. --iPath; // adjust for the removal
  403. }
  404. }
  405. // Sort the vector by cost, given that it
  406. // is likely consumers will want to
  407. // iterate destinations in that order.
  408. vecPaths.Sort( Edge_t::SortFn );
  409. }
  410. }
  411. //-----------------------------------------------------------------------------
  412. // Constructor
  413. //-----------------------------------------------------------------------------
  414. template <class T, class C >
  415. CUtlGraphVisitor<T, C>::CUtlGraphVisitor( CUtlGraph<T,C> &graph )
  416. : m_Graph( graph )
  417. {
  418. m_iVisiting = 0;
  419. m_nCurrentRadius = 0;
  420. }
  421. //-----------------------------------------------------------------------------
  422. // Begin visiting the nodes in the graph. Returns false if the start node
  423. // does not exist
  424. //-----------------------------------------------------------------------------
  425. template <class T, class C >
  426. bool CUtlGraphVisitor<T, C>::Begin( T StartNode )
  427. {
  428. m_vecVisitQueue.RemoveAll();
  429. m_vecFringeQueue.RemoveAll();
  430. m_vecNodesVisited.RemoveAll();
  431. m_iVisiting = 0;
  432. m_nCurrentRadius = 0;
  433. IndexType_t iStartNode = m_Graph.Find( StartNode );
  434. if ( !m_Graph.IsValidIndex( iStartNode ) )
  435. return false;
  436. vecEdges_t *pvecEdges = m_Graph.GetEdges( iStartNode );
  437. Edge_t edge;
  438. edge.m_DestinationNode = iStartNode;
  439. edge.m_EdgeCost = 0;
  440. m_vecVisitQueue[ m_vecVisitQueue.AddToTail() ] = edge;
  441. m_vecNodesVisited[ m_vecNodesVisited.AddToTail() ] = iStartNode;
  442. m_vecFringeQueue = *pvecEdges;
  443. // cells actually get marked as "visited" as soon as we put
  444. // them in the fringe queue, so we don't put them in the *next*
  445. // fringe queue (we build the fringe queue before we actually visit
  446. // the nodes in the new visit queue).
  447. FOR_EACH_VEC( m_vecFringeQueue, iFringe )
  448. {
  449. m_vecNodesVisited[ m_vecNodesVisited.AddToTail() ] = m_vecFringeQueue[iFringe].m_DestinationNode;
  450. }
  451. return true;
  452. }
  453. //-----------------------------------------------------------------------------
  454. // Advance to the next node. Returns false when all nodes have been visited
  455. //-----------------------------------------------------------------------------
  456. template <class T, class C>
  457. bool CUtlGraphVisitor<T, C>::Advance()
  458. {
  459. m_iVisiting++;
  460. // Is the VisitQueue empty? move outward one radius if so
  461. if ( m_iVisiting >= m_vecVisitQueue.Count() )
  462. {
  463. m_nCurrentRadius++;
  464. m_iVisiting = 0;
  465. m_vecVisitQueue = m_vecFringeQueue;
  466. m_vecFringeQueue.RemoveAll();
  467. if ( !m_vecVisitQueue.Count() )
  468. return false;
  469. // create new fringe queue
  470. FOR_EACH_VEC( m_vecVisitQueue, iNode )
  471. {
  472. Edge_t &node = m_vecVisitQueue[iNode];
  473. vecEdges_t &vecEdges = *m_Graph.GetEdges( node.m_DestinationNode );
  474. FOR_EACH_VEC( vecEdges, iEdge )
  475. {
  476. Edge_t &edge = vecEdges[iEdge];
  477. if ( m_vecNodesVisited.InvalidIndex() == m_vecNodesVisited.Find( edge.m_DestinationNode ) )
  478. {
  479. m_vecNodesVisited[ m_vecNodesVisited.AddToTail() ] = edge.m_DestinationNode;
  480. int iNewFringeNode = m_vecFringeQueue.AddToTail();
  481. m_vecFringeQueue[ iNewFringeNode ] = edge;
  482. // Accumulate the cost to get to the current point
  483. m_vecFringeQueue[ iNewFringeNode ].m_EdgeCost += node.m_EdgeCost;
  484. }
  485. }
  486. }
  487. }
  488. return true;
  489. }
  490. //-----------------------------------------------------------------------------
  491. // Get the current node in the visit sequence
  492. //-----------------------------------------------------------------------------
  493. template <class T, class C>
  494. T CUtlGraphVisitor<T, C>::CurrentNode()
  495. {
  496. if ( m_iVisiting >= m_vecVisitQueue.Count() )
  497. {
  498. AssertMsg( false, "Visitor invalid" );
  499. return T();
  500. }
  501. return m_Graph[ m_vecVisitQueue[ m_iVisiting ].m_DestinationNode ];
  502. }
  503. //-----------------------------------------------------------------------------
  504. // Get the accumulated cost to traverse the graph to the current node
  505. //-----------------------------------------------------------------------------
  506. template <class T, class C>
  507. C CUtlGraphVisitor<T, C>::AccumulatedCost()
  508. {
  509. if ( m_iVisiting >= m_vecVisitQueue.Count() )
  510. {
  511. AssertMsg( false, "Visitor invalid" );
  512. return C();
  513. }
  514. return m_vecVisitQueue[ m_iVisiting ].m_EdgeCost;
  515. }
  516. //-----------------------------------------------------------------------------
  517. // Get the current radius from the start point to this node
  518. //-----------------------------------------------------------------------------
  519. template <class T, class C>
  520. int CUtlGraphVisitor<T, C>::CurrentRadius()
  521. {
  522. if ( m_iVisiting >= m_vecVisitQueue.Count() )
  523. {
  524. AssertMsg( false, "Visitor invalid" );
  525. return 0;
  526. }
  527. return m_nCurrentRadius;
  528. }
  529. #endif // UTLGRAPH_H