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  }