The following code implements a package, which can be used to execute functions in the correct order based on dependencies.
Example:
package main
import (
"my/setup"
"fmt"
)
func main() {
// a depends on nothing
a := setup.Add(func() { fmt.Println("a") })
// b depends on a
b := setup.Add(func() { fmt.Println("b") }, a)
// c depends on b
c := setup.Add(func() { fmt.Println("c") }, b)
// d depends on a
d := setup.Add(func() { fmt.Println("d") }, a)
_, _ = c, d
setup.Exec()
// Prints: a, b, d, c
}
Is there anything I can improve?
// Orchestrates the execution of initialization functions with
// dependencies.
package setup
import (
"sort"
)
// Anything that can be done during the initalization.
type Func func()
type Action *Func
type sequence_t func() int
type sernos_t map[Action]int
type ranks_t map[Action]int
type actions_t []Action
type dependencies_t map[Action][]Action
// A list of actions and their dependencies.
type setup_t struct {
sequence sequence_t
sernos sernos_t
dependencies dependencies_t
}
var setup *setup_t = new(setup_t)
// Create a new Setup
func init() {
i := -1
setup.sequence = func() int { i = i + 1; return i }
setup.sernos = make(sernos_t)
setup.dependencies = make(dependencies_t)
}
// Add an action with optional dependencies to the setup. Adding is
// not thread safe.
func Add(init Func, dependencies ...Action) Action {
action := &init
setup.sernos[action] = setup.sequence()
setup.dependencies[action] = dependencies
return action
}
// Execute all actions in the right row, considering their dependenciesetup.
func Exec() {
ranks := make(ranks_t)
// Calculate the rank of an action and memoize the result in
// ranksetup. The rank of an action is one more than the maximum of
// the ranks of all dependenciesetup. The rank of an action defines the
// execution order during the setup.
var rank func(Action)
rank = func(action Action) {
if len(setup.dependencies[action]) == 0 {
ranks[action] = 0
}
max := 0
for _, dependency := range setup.dependencies[action] {
rank(dependency)
if ranks[dependency] > max {
max = ranks[dependency]
}
}
ranks[action] = max + 1
}
// Create a list of all actions and calculate the rank of every
// action.
actions := make(actions_t, len(setup.sernos))
i := 0
for action := range setup.sernos {
actions[i] = action
i = i + 1
_, ok := ranks[action]
if !ok {
rank(action)
}
}
// Sort the actions first by rank and second by serno.
sort.Slice(actions, func(i, j int) bool {
ai := actions[i]
aj := actions[j]
if ranks[ai] == ranks[aj] {
return setup.sernos[ai] < setup.sernos[aj]
}
return ranks[ai] < ranks[aj]
})
// Execute the actions in order.
for i := range actions {
(*actions[i])()
}
// Allow setup only once.
setup = nil
}