pulumi/pkg/graph/topsort.go
joeduffy 6f42e1134b Create object monikers
This change introduces object monikers.  These are unique, serializable
names that refer to resources created during the execution of a MuIL
program.  They are pretty darned ugly at the moment, but at least they
serve their desired purpose.  I suspect we will eventually want to use
more information (like edge "labels" (variable names and what not)),
but this should suffice for the time being.  The names right now are
particularly sensitive to simple refactorings.

This is enough for marapongo/mu#69 during the current sprint, although
I will keep the work item (in a later sprint) to think more about how
to make these more stable.  I'd prefer to do that with a bit of
experience under our belts first.
2017-02-18 10:22:04 -08:00

44 lines
1.4 KiB
Go

// Copyright 2016 Marapongo, Inc. All rights reserved.
package graph
import (
"errors"
)
// Topsort topologically sorts the graph, yielding an array of nodes that are in dependency order, using a simple
// DFS-based algorithm. The graph must be acyclic, otherwise this function will return an error.
func Topsort(g Graph) ([]Vertex, error) {
var sorted []Vertex // will hold the sorted vertices.
visiting := make(map[Vertex]bool) // temporary entries to detect cycles.
visited := make(map[Vertex]bool) // entries to avoid visiting the same node twice.
// Now enumerate the roots, topologically sorting their dependencies.
roots := g.Roots()
for _, r := range roots {
if err := topvisit(r.To(), &sorted, visiting, visited); err != nil {
return sorted, err
}
}
return sorted, nil
}
func topvisit(n Vertex, sorted *[]Vertex, visiting map[Vertex]bool, visited map[Vertex]bool) error {
if visiting[n] {
// This is not a DAG! Stop sorting right away, and issue an error.
// TODO: use a real error here; and also ideally give an error message that makes sense (w/ the full cycle).
return errors.New("Graph is not a DAG")
}
if !visited[n] {
visiting[n] = true
for _, m := range n.Outs() {
if err := topvisit(m.To(), sorted, visiting, visited); err != nil {
return err
}
}
visited[n] = true
visiting[n] = false
*sorted = append(*sorted, n)
}
return nil
}