/src/CMake/Source/cmComputeComponentGraph.h
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #pragma once |
4 | | |
5 | | #include "cmConfigure.h" // IWYU pragma: keep |
6 | | |
7 | | #include <cstddef> |
8 | | #include <stack> |
9 | | #include <vector> |
10 | | |
11 | | #include "cmGraphAdjacencyList.h" |
12 | | |
13 | | /** \class cmComputeComponentGraph |
14 | | * \brief Analyze a graph to determine strongly connected components. |
15 | | * |
16 | | * Convert a directed graph into a directed acyclic graph whose nodes |
17 | | * correspond to strongly connected components of the original graph. |
18 | | * |
19 | | * We use Tarjan's algorithm to enumerate the components efficiently. |
20 | | * An advantage of this approach is that the components are identified |
21 | | * in a topologically sorted order. |
22 | | */ |
23 | | class cmComputeComponentGraph |
24 | | { |
25 | | public: |
26 | | // Represent the graph with an adjacency list. |
27 | | using NodeList = cmGraphNodeList; |
28 | | using EdgeList = cmGraphEdgeList; |
29 | | using Graph = cmGraphAdjacencyList; |
30 | | |
31 | | cmComputeComponentGraph(Graph const& input); |
32 | | ~cmComputeComponentGraph(); |
33 | | |
34 | | /** Run the computation. */ |
35 | | void Compute(); |
36 | | |
37 | | /** Get the adjacency list of the component graph. */ |
38 | 0 | Graph const& GetComponentGraph() const { return this->ComponentGraph; } |
39 | | EdgeList const& GetComponentGraphEdges(size_t c) const |
40 | 0 | { |
41 | 0 | return this->ComponentGraph[c]; |
42 | 0 | } |
43 | | |
44 | | /** Get map from component index to original node indices. */ |
45 | | std::vector<NodeList> const& GetComponents() const |
46 | 0 | { |
47 | 0 | return this->Components; |
48 | 0 | } |
49 | 0 | NodeList const& GetComponent(size_t c) const { return this->Components[c]; } |
50 | | |
51 | | /** Get map from original node index to component index. */ |
52 | | std::vector<size_t> const& GetComponentMap() const |
53 | 0 | { |
54 | 0 | return this->TarjanComponents; |
55 | 0 | } |
56 | | |
57 | | static size_t const INVALID_COMPONENT; |
58 | | |
59 | | private: |
60 | | void TransferEdges(); |
61 | | |
62 | | Graph const& InputGraph; |
63 | | Graph ComponentGraph; |
64 | | |
65 | | // Tarjan's algorithm. |
66 | | struct TarjanEntry |
67 | | { |
68 | | size_t Root; |
69 | | size_t VisitIndex; |
70 | | }; |
71 | | std::vector<size_t> TarjanVisited; |
72 | | std::vector<size_t> TarjanComponents; |
73 | | std::vector<TarjanEntry> TarjanEntries; |
74 | | std::vector<NodeList> Components; |
75 | | std::stack<size_t> TarjanStack; |
76 | | size_t TarjanWalkId; |
77 | | size_t TarjanIndex; |
78 | | void Tarjan(); |
79 | | void TarjanVisit(size_t i); |
80 | | |
81 | | // Connected components. |
82 | | }; |