github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/dag/graph.go (about) 1 package dag 2 3 import ( 4 "bytes" 5 "fmt" 6 "sort" 7 ) 8 9 // Graph is used to represent a dependency graph. 10 type Graph struct { 11 vertices Set 12 edges Set 13 downEdges map[interface{}]Set 14 upEdges map[interface{}]Set 15 } 16 17 // Subgrapher allows a Vertex to be a Graph itself, by returning a Grapher. 18 type Subgrapher interface { 19 Subgraph() Grapher 20 } 21 22 // A Grapher is any type that returns a Grapher, mainly used to identify 23 // dag.Graph and dag.AcyclicGraph. In the case of Graph and AcyclicGraph, they 24 // return themselves. 25 type Grapher interface { 26 DirectedGraph() Grapher 27 } 28 29 // Vertex of the graph. 30 type Vertex interface{} 31 32 // NamedVertex is an optional interface that can be implemented by Vertex 33 // to give it a human-friendly name that is used for outputting the graph. 34 type NamedVertex interface { 35 Vertex 36 Name() string 37 } 38 39 func (g *Graph) DirectedGraph() Grapher { 40 return g 41 } 42 43 // Vertices returns the list of all the vertices in the graph. 44 func (g *Graph) Vertices() []Vertex { 45 result := make([]Vertex, 0, len(g.vertices)) 46 for _, v := range g.vertices { 47 result = append(result, v.(Vertex)) 48 } 49 50 return result 51 } 52 53 // Edges returns the list of all the edges in the graph. 54 func (g *Graph) Edges() []Edge { 55 result := make([]Edge, 0, len(g.edges)) 56 for _, v := range g.edges { 57 result = append(result, v.(Edge)) 58 } 59 60 return result 61 } 62 63 // EdgesFrom returns the list of edges from the given source. 64 func (g *Graph) EdgesFrom(v Vertex) []Edge { 65 var result []Edge 66 from := hashcode(v) 67 for _, e := range g.Edges() { 68 if hashcode(e.Source()) == from { 69 result = append(result, e) 70 } 71 } 72 73 return result 74 } 75 76 // EdgesTo returns the list of edges to the given target. 77 func (g *Graph) EdgesTo(v Vertex) []Edge { 78 var result []Edge 79 search := hashcode(v) 80 for _, e := range g.Edges() { 81 if hashcode(e.Target()) == search { 82 result = append(result, e) 83 } 84 } 85 86 return result 87 } 88 89 // HasVertex checks if the given Vertex is present in the graph. 90 func (g *Graph) HasVertex(v Vertex) bool { 91 return g.vertices.Include(v) 92 } 93 94 // HasEdge checks if the given Edge is present in the graph. 95 func (g *Graph) HasEdge(e Edge) bool { 96 return g.edges.Include(e) 97 } 98 99 // Add adds a vertex to the graph. This is safe to call multiple time with 100 // the same Vertex. 101 func (g *Graph) Add(v Vertex) Vertex { 102 g.init() 103 g.vertices.Add(v) 104 return v 105 } 106 107 // Remove removes a vertex from the graph. This will also remove any 108 // edges with this vertex as a source or target. 109 func (g *Graph) Remove(v Vertex) Vertex { 110 // Delete the vertex itself 111 g.vertices.Delete(v) 112 113 // Delete the edges to non-existent things 114 for _, target := range g.downEdgesNoCopy(v) { 115 g.RemoveEdge(BasicEdge(v, target)) 116 } 117 for _, source := range g.upEdgesNoCopy(v) { 118 g.RemoveEdge(BasicEdge(source, v)) 119 } 120 121 return nil 122 } 123 124 // Replace replaces the original Vertex with replacement. If the original 125 // does not exist within the graph, then false is returned. Otherwise, true 126 // is returned. 127 func (g *Graph) Replace(original, replacement Vertex) bool { 128 // If we don't have the original, we can't do anything 129 if !g.vertices.Include(original) { 130 return false 131 } 132 133 // If they're the same, then don't do anything 134 if original == replacement { 135 return true 136 } 137 138 // Add our new vertex, then copy all the edges 139 g.Add(replacement) 140 for _, target := range g.downEdgesNoCopy(original) { 141 g.Connect(BasicEdge(replacement, target)) 142 } 143 for _, source := range g.upEdgesNoCopy(original) { 144 g.Connect(BasicEdge(source, replacement)) 145 } 146 147 // Remove our old vertex, which will also remove all the edges 148 g.Remove(original) 149 150 return true 151 } 152 153 // RemoveEdge removes an edge from the graph. 154 func (g *Graph) RemoveEdge(edge Edge) { 155 g.init() 156 157 // Delete the edge from the set 158 g.edges.Delete(edge) 159 160 // Delete the up/down edges 161 if s, ok := g.downEdges[hashcode(edge.Source())]; ok { 162 s.Delete(edge.Target()) 163 } 164 if s, ok := g.upEdges[hashcode(edge.Target())]; ok { 165 s.Delete(edge.Source()) 166 } 167 } 168 169 // UpEdges returns the vertices that are *sources* of edges that target the 170 // destination Vertex v. 171 func (g *Graph) UpEdges(v Vertex) Set { 172 return g.upEdgesNoCopy(v).Copy() 173 } 174 175 // DownEdges returns the vertices that are *targets* of edges that originate 176 // from the source Vertex v. 177 func (g *Graph) DownEdges(v Vertex) Set { 178 return g.downEdgesNoCopy(v).Copy() 179 } 180 181 // downEdgesNoCopy returns the vertices targeted by edges from the source Vertex 182 // v as a Set. This Set is the same as used internally by the Graph to prevent a 183 // copy, and must not be modified by the caller. 184 func (g *Graph) downEdgesNoCopy(v Vertex) Set { 185 g.init() 186 return g.downEdges[hashcode(v)] 187 } 188 189 // upEdgesNoCopy returns the vertices that are sources of edges targeting the 190 // destination Vertex v as a Set. This Set is the same as used internally by the 191 // Graph to prevent a copy, and must not be modified by the caller. 192 func (g *Graph) upEdgesNoCopy(v Vertex) Set { 193 g.init() 194 return g.upEdges[hashcode(v)] 195 } 196 197 // Connect adds an edge with the given source and target. This is safe to 198 // call multiple times with the same value. Note that the same value is 199 // verified through pointer equality of the vertices, not through the 200 // value of the edge itself. 201 func (g *Graph) Connect(edge Edge) { 202 g.init() 203 204 source := edge.Source() 205 target := edge.Target() 206 sourceCode := hashcode(source) 207 targetCode := hashcode(target) 208 209 // Do we have this already? If so, don't add it again. 210 if s, ok := g.downEdges[sourceCode]; ok && s.Include(target) { 211 return 212 } 213 214 // Add the edge to the set 215 g.edges.Add(edge) 216 217 // Add the down edge 218 s, ok := g.downEdges[sourceCode] 219 if !ok { 220 s = make(Set) 221 g.downEdges[sourceCode] = s 222 } 223 s.Add(target) 224 225 // Add the up edge 226 s, ok = g.upEdges[targetCode] 227 if !ok { 228 s = make(Set) 229 g.upEdges[targetCode] = s 230 } 231 s.Add(source) 232 } 233 234 // Subsume imports all of the nodes and edges from the given graph into the 235 // reciever, leaving the given graph unchanged. 236 // 237 // If any of the nodes in the given graph are already present in the reciever 238 // then the existing node will be retained and any new edges from the given 239 // graph will be connected with it. 240 // 241 // If the given graph has edges in common with the reciever then they will be 242 // ignored, because each pair of nodes can only be connected once. 243 func (g *Graph) Subsume(other *Graph) { 244 // We're using Set.Filter just as a "visit each element" here, so we're 245 // not doing anything with the result (which will always be empty). 246 other.vertices.Filter(func(i interface{}) bool { 247 g.Add(i) 248 return false 249 }) 250 other.edges.Filter(func(i interface{}) bool { 251 g.Connect(i.(Edge)) 252 return false 253 }) 254 } 255 256 // String outputs some human-friendly output for the graph structure. 257 func (g *Graph) StringWithNodeTypes() string { 258 var buf bytes.Buffer 259 260 // Build the list of node names and a mapping so that we can more 261 // easily alphabetize the output to remain deterministic. 262 vertices := g.Vertices() 263 names := make([]string, 0, len(vertices)) 264 mapping := make(map[string]Vertex, len(vertices)) 265 for _, v := range vertices { 266 name := VertexName(v) 267 names = append(names, name) 268 mapping[name] = v 269 } 270 sort.Strings(names) 271 272 // Write each node in order... 273 for _, name := range names { 274 v := mapping[name] 275 targets := g.downEdges[hashcode(v)] 276 277 buf.WriteString(fmt.Sprintf("%s - %T\n", name, v)) 278 279 // Alphabetize dependencies 280 deps := make([]string, 0, targets.Len()) 281 targetNodes := make(map[string]Vertex) 282 for _, target := range targets { 283 dep := VertexName(target) 284 deps = append(deps, dep) 285 targetNodes[dep] = target 286 } 287 sort.Strings(deps) 288 289 // Write dependencies 290 for _, d := range deps { 291 buf.WriteString(fmt.Sprintf(" %s - %T\n", d, targetNodes[d])) 292 } 293 } 294 295 return buf.String() 296 } 297 298 // String outputs some human-friendly output for the graph structure. 299 func (g *Graph) String() string { 300 var buf bytes.Buffer 301 302 // Build the list of node names and a mapping so that we can more 303 // easily alphabetize the output to remain deterministic. 304 vertices := g.Vertices() 305 names := make([]string, 0, len(vertices)) 306 mapping := make(map[string]Vertex, len(vertices)) 307 for _, v := range vertices { 308 name := VertexName(v) 309 names = append(names, name) 310 mapping[name] = v 311 } 312 sort.Strings(names) 313 314 // Write each node in order... 315 for _, name := range names { 316 v := mapping[name] 317 targets := g.downEdges[hashcode(v)] 318 319 buf.WriteString(fmt.Sprintf("%s\n", name)) 320 321 // Alphabetize dependencies 322 deps := make([]string, 0, targets.Len()) 323 for _, target := range targets { 324 deps = append(deps, VertexName(target)) 325 } 326 sort.Strings(deps) 327 328 // Write dependencies 329 for _, d := range deps { 330 buf.WriteString(fmt.Sprintf(" %s\n", d)) 331 } 332 } 333 334 return buf.String() 335 } 336 337 func (g *Graph) init() { 338 if g.vertices == nil { 339 g.vertices = make(Set) 340 } 341 if g.edges == nil { 342 g.edges = make(Set) 343 } 344 if g.downEdges == nil { 345 g.downEdges = make(map[interface{}]Set) 346 } 347 if g.upEdges == nil { 348 g.upEdges = make(map[interface{}]Set) 349 } 350 } 351 352 // Dot returns a dot-formatted representation of the Graph. 353 func (g *Graph) Dot(opts *DotOpts) []byte { 354 return newMarshalGraph("", g).Dot(opts) 355 } 356 357 // VertexName returns the name of a vertex. 358 func VertexName(raw Vertex) string { 359 switch v := raw.(type) { 360 case NamedVertex: 361 return v.Name() 362 case fmt.Stringer: 363 return v.String() 364 default: 365 return fmt.Sprintf("%v", v) 366 } 367 }