github.com/ns1/terraform@v0.7.10-0.20161109153551-8949419bef40/dag/graph.go (about) 1 package dag 2 3 import ( 4 "bytes" 5 "fmt" 6 "sort" 7 "sync" 8 ) 9 10 // Graph is used to represent a dependency graph. 11 type Graph struct { 12 vertices *Set 13 edges *Set 14 downEdges map[interface{}]*Set 15 upEdges map[interface{}]*Set 16 once sync.Once 17 } 18 19 // Vertex of the graph. 20 type Vertex interface{} 21 22 // NamedVertex is an optional interface that can be implemented by Vertex 23 // to give it a human-friendly name that is used for outputting the graph. 24 type NamedVertex interface { 25 Vertex 26 Name() string 27 } 28 29 // Vertices returns the list of all the vertices in the graph. 30 func (g *Graph) Vertices() []Vertex { 31 list := g.vertices.List() 32 result := make([]Vertex, len(list)) 33 for i, v := range list { 34 result[i] = v.(Vertex) 35 } 36 37 return result 38 } 39 40 // Edges returns the list of all the edges in the graph. 41 func (g *Graph) Edges() []Edge { 42 list := g.edges.List() 43 result := make([]Edge, len(list)) 44 for i, v := range list { 45 result[i] = v.(Edge) 46 } 47 48 return result 49 } 50 51 // EdgesFrom returns the list of edges from the given source. 52 func (g *Graph) EdgesFrom(v Vertex) []Edge { 53 var result []Edge 54 from := hashcode(v) 55 for _, e := range g.Edges() { 56 if hashcode(e.Source()) == from { 57 result = append(result, e) 58 } 59 } 60 61 return result 62 } 63 64 // EdgesTo returns the list of edges to the given target. 65 func (g *Graph) EdgesTo(v Vertex) []Edge { 66 var result []Edge 67 search := hashcode(v) 68 for _, e := range g.Edges() { 69 if hashcode(e.Target()) == search { 70 result = append(result, e) 71 } 72 } 73 74 return result 75 } 76 77 // HasVertex checks if the given Vertex is present in the graph. 78 func (g *Graph) HasVertex(v Vertex) bool { 79 return g.vertices.Include(v) 80 } 81 82 // HasEdge checks if the given Edge is present in the graph. 83 func (g *Graph) HasEdge(e Edge) bool { 84 return g.edges.Include(e) 85 } 86 87 // Add adds a vertex to the graph. This is safe to call multiple time with 88 // the same Vertex. 89 func (g *Graph) Add(v Vertex) Vertex { 90 g.once.Do(g.init) 91 g.vertices.Add(v) 92 return v 93 } 94 95 // Remove removes a vertex from the graph. This will also remove any 96 // edges with this vertex as a source or target. 97 func (g *Graph) Remove(v Vertex) Vertex { 98 // Delete the vertex itself 99 g.vertices.Delete(v) 100 101 // Delete the edges to non-existent things 102 for _, target := range g.DownEdges(v).List() { 103 g.RemoveEdge(BasicEdge(v, target)) 104 } 105 for _, source := range g.UpEdges(v).List() { 106 g.RemoveEdge(BasicEdge(source, v)) 107 } 108 109 return nil 110 } 111 112 // Replace replaces the original Vertex with replacement. If the original 113 // does not exist within the graph, then false is returned. Otherwise, true 114 // is returned. 115 func (g *Graph) Replace(original, replacement Vertex) bool { 116 // If we don't have the original, we can't do anything 117 if !g.vertices.Include(original) { 118 return false 119 } 120 121 // If they're the same, then don't do anything 122 if original == replacement { 123 return true 124 } 125 126 // Add our new vertex, then copy all the edges 127 g.Add(replacement) 128 for _, target := range g.DownEdges(original).List() { 129 g.Connect(BasicEdge(replacement, target)) 130 } 131 for _, source := range g.UpEdges(original).List() { 132 g.Connect(BasicEdge(source, replacement)) 133 } 134 135 // Remove our old vertex, which will also remove all the edges 136 g.Remove(original) 137 138 return true 139 } 140 141 // RemoveEdge removes an edge from the graph. 142 func (g *Graph) RemoveEdge(edge Edge) { 143 g.once.Do(g.init) 144 145 // Delete the edge from the set 146 g.edges.Delete(edge) 147 148 // Delete the up/down edges 149 if s, ok := g.downEdges[hashcode(edge.Source())]; ok { 150 s.Delete(edge.Target()) 151 } 152 if s, ok := g.upEdges[hashcode(edge.Target())]; ok { 153 s.Delete(edge.Source()) 154 } 155 } 156 157 // DownEdges returns the outward edges from the source Vertex v. 158 func (g *Graph) DownEdges(v Vertex) *Set { 159 g.once.Do(g.init) 160 return g.downEdges[hashcode(v)] 161 } 162 163 // UpEdges returns the inward edges to the destination Vertex v. 164 func (g *Graph) UpEdges(v Vertex) *Set { 165 g.once.Do(g.init) 166 return g.upEdges[hashcode(v)] 167 } 168 169 // Connect adds an edge with the given source and target. This is safe to 170 // call multiple times with the same value. Note that the same value is 171 // verified through pointer equality of the vertices, not through the 172 // value of the edge itself. 173 func (g *Graph) Connect(edge Edge) { 174 g.once.Do(g.init) 175 176 source := edge.Source() 177 target := edge.Target() 178 sourceCode := hashcode(source) 179 targetCode := hashcode(target) 180 181 // Do we have this already? If so, don't add it again. 182 if s, ok := g.downEdges[sourceCode]; ok && s.Include(target) { 183 return 184 } 185 186 // Add the edge to the set 187 g.edges.Add(edge) 188 189 // Add the down edge 190 s, ok := g.downEdges[sourceCode] 191 if !ok { 192 s = new(Set) 193 g.downEdges[sourceCode] = s 194 } 195 s.Add(target) 196 197 // Add the up edge 198 s, ok = g.upEdges[targetCode] 199 if !ok { 200 s = new(Set) 201 g.upEdges[targetCode] = s 202 } 203 s.Add(source) 204 } 205 206 // String outputs some human-friendly output for the graph structure. 207 func (g *Graph) StringWithNodeTypes() string { 208 var buf bytes.Buffer 209 210 // Build the list of node names and a mapping so that we can more 211 // easily alphabetize the output to remain deterministic. 212 vertices := g.Vertices() 213 names := make([]string, 0, len(vertices)) 214 mapping := make(map[string]Vertex, len(vertices)) 215 for _, v := range vertices { 216 name := VertexName(v) 217 names = append(names, name) 218 mapping[name] = v 219 } 220 sort.Strings(names) 221 222 // Write each node in order... 223 for _, name := range names { 224 v := mapping[name] 225 targets := g.downEdges[hashcode(v)] 226 227 buf.WriteString(fmt.Sprintf("%s - %T\n", name, v)) 228 229 // Alphabetize dependencies 230 deps := make([]string, 0, targets.Len()) 231 targetNodes := make(map[string]Vertex) 232 for _, target := range targets.List() { 233 dep := VertexName(target) 234 deps = append(deps, dep) 235 targetNodes[dep] = target 236 } 237 sort.Strings(deps) 238 239 // Write dependencies 240 for _, d := range deps { 241 buf.WriteString(fmt.Sprintf(" %s - %T\n", d, targetNodes[d])) 242 } 243 } 244 245 return buf.String() 246 } 247 248 // String outputs some human-friendly output for the graph structure. 249 func (g *Graph) String() string { 250 var buf bytes.Buffer 251 252 // Build the list of node names and a mapping so that we can more 253 // easily alphabetize the output to remain deterministic. 254 vertices := g.Vertices() 255 names := make([]string, 0, len(vertices)) 256 mapping := make(map[string]Vertex, len(vertices)) 257 for _, v := range vertices { 258 name := VertexName(v) 259 names = append(names, name) 260 mapping[name] = v 261 } 262 sort.Strings(names) 263 264 // Write each node in order... 265 for _, name := range names { 266 v := mapping[name] 267 targets := g.downEdges[hashcode(v)] 268 269 buf.WriteString(fmt.Sprintf("%s\n", name)) 270 271 // Alphabetize dependencies 272 deps := make([]string, 0, targets.Len()) 273 for _, target := range targets.List() { 274 deps = append(deps, VertexName(target)) 275 } 276 sort.Strings(deps) 277 278 // Write dependencies 279 for _, d := range deps { 280 buf.WriteString(fmt.Sprintf(" %s\n", d)) 281 } 282 } 283 284 return buf.String() 285 } 286 287 func (g *Graph) init() { 288 g.vertices = new(Set) 289 g.edges = new(Set) 290 g.downEdges = make(map[interface{}]*Set) 291 g.upEdges = make(map[interface{}]*Set) 292 } 293 294 // VertexName returns the name of a vertex. 295 func VertexName(raw Vertex) string { 296 switch v := raw.(type) { 297 case NamedVertex: 298 return v.Name() 299 case fmt.Stringer: 300 return fmt.Sprintf("%s", v) 301 default: 302 return fmt.Sprintf("%v", v) 303 } 304 }