github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/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 // Add adds a vertex to the graph. This is safe to call multiple time with 52 // the same Vertex. 53 func (g *Graph) Add(v Vertex) Vertex { 54 g.once.Do(g.init) 55 g.vertices.Add(v) 56 return v 57 } 58 59 // Remove removes a vertex from the graph. This will also remove any 60 // edges with this vertex as a source or target. 61 func (g *Graph) Remove(v Vertex) Vertex { 62 // Delete the vertex itself 63 g.vertices.Delete(v) 64 65 // Delete the edges to non-existent things 66 for _, target := range g.DownEdges(v).List() { 67 g.RemoveEdge(BasicEdge(v, target)) 68 } 69 for _, source := range g.UpEdges(v).List() { 70 g.RemoveEdge(BasicEdge(source, v)) 71 } 72 73 return nil 74 } 75 76 // Replace replaces the original Vertex with replacement. If the original 77 // does not exist within the graph, then false is returned. Otherwise, true 78 // is returned. 79 func (g *Graph) Replace(original, replacement Vertex) bool { 80 // If we don't have the original, we can't do anything 81 if !g.vertices.Include(original) { 82 return false 83 } 84 85 // If they're the same, then don't do anything 86 if original == replacement { 87 return true 88 } 89 90 // Add our new vertex, then copy all the edges 91 g.Add(replacement) 92 for _, target := range g.DownEdges(original).List() { 93 g.Connect(BasicEdge(replacement, target)) 94 } 95 for _, source := range g.UpEdges(original).List() { 96 g.Connect(BasicEdge(source, replacement)) 97 } 98 99 // Remove our old vertex, which will also remove all the edges 100 g.Remove(original) 101 102 return true 103 } 104 105 // RemoveEdge removes an edge from the graph. 106 func (g *Graph) RemoveEdge(edge Edge) { 107 g.once.Do(g.init) 108 109 // Delete the edge from the set 110 g.edges.Delete(edge) 111 112 // Delete the up/down edges 113 if s, ok := g.downEdges[hashcode(edge.Source())]; ok { 114 s.Delete(edge.Target()) 115 } 116 if s, ok := g.upEdges[hashcode(edge.Target())]; ok { 117 s.Delete(edge.Source()) 118 } 119 } 120 121 // DownEdges returns the outward edges from the source Vertex v. 122 func (g *Graph) DownEdges(v Vertex) *Set { 123 g.once.Do(g.init) 124 return g.downEdges[hashcode(v)] 125 } 126 127 // UpEdges returns the inward edges to the destination Vertex v. 128 func (g *Graph) UpEdges(v Vertex) *Set { 129 g.once.Do(g.init) 130 return g.upEdges[hashcode(v)] 131 } 132 133 // Connect adds an edge with the given source and target. This is safe to 134 // call multiple times with the same value. Note that the same value is 135 // verified through pointer equality of the vertices, not through the 136 // value of the edge itself. 137 func (g *Graph) Connect(edge Edge) { 138 g.once.Do(g.init) 139 140 source := edge.Source() 141 target := edge.Target() 142 sourceCode := hashcode(source) 143 targetCode := hashcode(target) 144 145 // Do we have this already? If so, don't add it again. 146 if s, ok := g.downEdges[sourceCode]; ok && s.Include(target) { 147 return 148 } 149 150 // Add the edge to the set 151 g.edges.Add(edge) 152 153 // Add the down edge 154 s, ok := g.downEdges[sourceCode] 155 if !ok { 156 s = new(Set) 157 g.downEdges[sourceCode] = s 158 } 159 s.Add(target) 160 161 // Add the up edge 162 s, ok = g.upEdges[targetCode] 163 if !ok { 164 s = new(Set) 165 g.upEdges[targetCode] = s 166 } 167 s.Add(source) 168 } 169 170 // String outputs some human-friendly output for the graph structure. 171 func (g *Graph) String() string { 172 var buf bytes.Buffer 173 174 // Build the list of node names and a mapping so that we can more 175 // easily alphabetize the output to remain deterministic. 176 vertices := g.Vertices() 177 names := make([]string, 0, len(vertices)) 178 mapping := make(map[string]Vertex, len(vertices)) 179 for _, v := range vertices { 180 name := VertexName(v) 181 names = append(names, name) 182 mapping[name] = v 183 } 184 sort.Strings(names) 185 186 // Write each node in order... 187 for _, name := range names { 188 v := mapping[name] 189 targets := g.downEdges[hashcode(v)] 190 191 buf.WriteString(fmt.Sprintf("%s\n", name)) 192 193 // Alphabetize dependencies 194 deps := make([]string, 0, targets.Len()) 195 for _, target := range targets.List() { 196 deps = append(deps, VertexName(target)) 197 } 198 sort.Strings(deps) 199 200 // Write dependencies 201 for _, d := range deps { 202 buf.WriteString(fmt.Sprintf(" %s\n", d)) 203 } 204 } 205 206 return buf.String() 207 } 208 209 func (g *Graph) init() { 210 g.vertices = new(Set) 211 g.edges = new(Set) 212 g.downEdges = make(map[interface{}]*Set) 213 g.upEdges = make(map[interface{}]*Set) 214 } 215 216 // VertexName returns the name of a vertex. 217 func VertexName(raw Vertex) string { 218 switch v := raw.(type) { 219 case NamedVertex: 220 return v.Name() 221 case fmt.Stringer: 222 return fmt.Sprintf("%s", v) 223 default: 224 return fmt.Sprintf("%v", v) 225 } 226 }