diff --git a/engine/graph/actions.go b/engine/graph/actions.go index c3dfc93e81..5e7ab0a02f 100644 --- a/engine/graph/actions.go +++ b/engine/graph/actions.go @@ -20,6 +20,7 @@ package graph import ( "context" "fmt" + "slices" "strings" "sync" "time" @@ -76,7 +77,7 @@ func (obj *Engine) Process(ctx context.Context, vertex pgraph.Vertex) error { // back poke in parallel (sync b/c of waitgroup) wg := &sync.WaitGroup{} for _, v := range obj.graph.IncomingGraphVertices(vertex) { - if !pgraph.VertexContains(v, vs) { // only poke what's needed + if !slices.Contains(vs, v) { // only poke what's needed continue } diff --git a/engine/graph/engine.go b/engine/graph/engine.go index 8c04dbbf92..eb39a3a63d 100644 --- a/engine/graph/engine.go +++ b/engine/graph/engine.go @@ -24,6 +24,7 @@ import ( "fmt" "os" "path" + "slices" "sync" "github.com/purpleidea/mgmt/converger" @@ -420,9 +421,9 @@ func (obj *Engine) Resume() error { return err } //indegree := obj.graph.InDegree() // compute all of the indegree's - reversed := pgraph.Reverse(topoSort) + slices.Reverse(topoSort) - for _, vertex := range reversed { + for _, vertex := range topoSort { // The very first resume is skipped as those resources are // already running! We could do that by checking here, but it is // more convenient to just have a state struct field (paused) to diff --git a/lang/funcs/dage/dage.go b/lang/funcs/dage/dage.go index c109d362e7..e6054d52d6 100644 --- a/lang/funcs/dage/dage.go +++ b/lang/funcs/dage/dage.go @@ -23,6 +23,7 @@ import ( "context" "fmt" "os" + "slices" "sort" "strings" "sync" @@ -1185,8 +1186,8 @@ func (obj *Engine) Run(ctx context.Context) (reterr error) { if err != nil { return err } - reversed := pgraph.Reverse(topoSort2) - for _, v := range reversed { + slices.Reverse(topoSort2) + for _, v := range topoSort2 { f, ok := v.(interfaces.Func) if !ok { panic("not a Func") diff --git a/lang/unification/util.go b/lang/unification/util.go index 51e0eeb9e6..92986403a2 100644 --- a/lang/unification/util.go +++ b/lang/unification/util.go @@ -18,6 +18,8 @@ package unification import ( + "slices" + "github.com/purpleidea/mgmt/lang/interfaces" ) @@ -53,17 +55,6 @@ func UniqueExprList(exprList []interfaces.Expr) []interfaces.Expr { return ExprMapToExprList(exprMap) } -// ExprContains is an "in array" function to test for an expr in a slice of -// expressions. -func ExprContains(needle interfaces.Expr, haystack []interfaces.Expr) bool { - for _, v := range haystack { - if needle == v { - return true - } - } - return false -} - // pairs is a simple list of pairs of expressions which can be used as a simple // undirected graph structure, or as a simple list of equalities. type pairs []*interfaces.EqualityInvariant @@ -112,7 +103,7 @@ func (obj pairs) DFS(start interfaces.Expr) []interfaces.Expr { for len(s) > 0 { v, s = s[len(s)-1], s[:len(s)-1] // s.pop() - if !ExprContains(v, d) { // if not discovered + if !slices.Contains(d, v) { // if not discovered d = append(d, v) // label as discovered for _, w := range obj.Vertices(v) { diff --git a/pgraph/graphsync.go b/pgraph/graphsync.go index b5c8412391..3056d9f71f 100644 --- a/pgraph/graphsync.go +++ b/pgraph/graphsync.go @@ -19,6 +19,7 @@ package pgraph import ( "fmt" + "slices" "github.com/purpleidea/mgmt/util/errwrap" ) @@ -105,7 +106,7 @@ func (obj *Graph) GraphSync(newGraph *Graph, vertexCmpFn func(Vertex, Vertex) (b } // get rid of any vertices we shouldn't keep (that aren't in new graph) for v := range oldGraph.Adjacency() { - if !VertexContains(v, vertexKeep) { + if !slices.Contains(vertexKeep, v) { vertexDels = append(vertexDels, v) // append } } @@ -163,7 +164,7 @@ func (obj *Graph) GraphSync(newGraph *Graph, vertexCmpFn func(Vertex, Vertex) (b for v1 := range oldGraph.Adjacency() { for _, e := range oldGraph.Adjacency()[v1] { // we have an edge! - if !EdgeContains(e, edgeKeep) { + if !slices.Contains(edgeKeep, e) { oldGraph.DeleteEdge(e) } } diff --git a/pgraph/pgraph.go b/pgraph/pgraph.go index 8c6491e0b9..dc01abf004 100644 --- a/pgraph/pgraph.go +++ b/pgraph/pgraph.go @@ -21,6 +21,7 @@ package pgraph import ( "errors" "fmt" + "slices" "sort" "strings" @@ -362,11 +363,11 @@ func (vs VertexSlice) Sort() { sort.Sort(vs) } // VerticesSorted returns a sorted slice of all vertices in the graph. The order // is sorted by String() to avoid the non-determinism in the map type. func (g *Graph) VerticesSorted() []Vertex { - var vertices []Vertex + var vertices VertexSlice for k := range g.adjacency { vertices = append(vertices, k) } - sort.Sort(VertexSlice(vertices)) // add determinism + sort.Sort(vertices) // add determinism return vertices } @@ -387,11 +388,11 @@ func (g *Graph) Sprint() string { str += fmt.Sprintf("Vertex: %s\n", v) } for _, v1 := range g.VerticesSorted() { - vs := []Vertex{} + var vs VertexSlice for v2 := range g.Adjacency()[v1] { vs = append(vs, v2) } - sort.Sort(VertexSlice(vs)) // deterministic order + sort.Sort(vs) // deterministic order for _, v2 := range vs { e := g.Adjacency()[v1][v2] str += fmt.Sprintf("Edge: %s -> %s # %s\n", v1, v2, e) @@ -488,7 +489,7 @@ func (g *Graph) DFS(start Vertex) []Vertex { for len(s) > 0 { v, s = s[len(s)-1], s[:len(s)-1] // s.pop() - if !VertexContains(v, d) { // if not discovered + if !slices.Contains(d, v) { // if not discovered d = append(d, v) // label as discovered for _, w := range g.GraphVertices(v) { @@ -502,7 +503,7 @@ func (g *Graph) DFS(start Vertex) []Vertex { // FilterGraph builds a new graph containing only vertices from the list. func (g *Graph) FilterGraph(vertices []Vertex) (*Graph, error) { fn := func(v Vertex) (bool, error) { - return VertexContains(v, vertices), nil + return slices.Contains(vertices, v), nil } return g.FilterGraphWithFn(fn) } @@ -545,7 +546,7 @@ func (g *Graph) DisconnectedGraphs() ([]*Graph, error) { // get an undiscovered vertex to start from for _, s := range g.Vertices() { - if !VertexContains(s, d) { + if !slices.Contains(d, s) { start = s } } @@ -675,7 +676,7 @@ func (g *Graph) Reachability(a, b Vertex) ([]Vertex, error) { if len(vertices) == 0 { return []Vertex{}, nil // nope } - if VertexContains(b, vertices) { + if slices.Contains(vertices, b) { return []Vertex{a, b}, nil // found } // TODO: parallelize this with go routines? @@ -764,10 +765,10 @@ Loop: m1 := []Vertex{} m2 := []Vertex{} for k, v := range m { - if VertexContains(k, m1) { + if slices.Contains(m1, k) { return fmt.Errorf("mapping from %s is used more than once to: %s", k, m1) } - if VertexContains(v, m2) { + if slices.Contains(m2, v) { return fmt.Errorf("mapping to %s is used more than once from: %s", v, m2) } m1 = append(m1, k) @@ -804,47 +805,3 @@ Loop: return nil // success! } - -// VertexContains is an "in array" function to test for a vertex in a slice of -// vertices. -func VertexContains(needle Vertex, haystack []Vertex) bool { - for _, v := range haystack { - if needle == v { - return true - } - } - return false -} - -// EdgeContains is an "in array" function to test for an edge in a slice of -// edges. -func EdgeContains(needle Edge, haystack []Edge) bool { - for _, v := range haystack { - if needle == v { - return true - } - } - return false -} - -// Reverse reverses a list of vertices. -func Reverse(vs []Vertex) []Vertex { - out := []Vertex{} - l := len(vs) - for i := range vs { - out = append(out, vs[l-i-1]) - } - return out -} - -// Sort the list of vertices and return a copy without modifying the input. -func Sort(vs []Vertex) []Vertex { - vertices := []Vertex{} - for _, v := range vs { // copy - vertices = append(vertices, v) - } - sort.Sort(VertexSlice(vertices)) - return vertices - // sort.Sort(VertexSlice(vs)) // this is wrong, it would modify input! - //return vs -} diff --git a/pgraph/pgraph_test.go b/pgraph/pgraph_test.go index 87b12a2fc5..c4f2393594 100644 --- a/pgraph/pgraph_test.go +++ b/pgraph/pgraph_test.go @@ -323,34 +323,6 @@ func TestDeleteVertex2(t *testing.T) { } } -func TestVertexContains1(t *testing.T) { - v1 := NV("v1") - v2 := NV("v2") - v3 := NV("v3") - if VertexContains(v1, []Vertex{v1, v2, v3}) != true { - t.Errorf("should be true instead of false.") - } - - v4 := NV("v4") - v5 := NV("v5") - v6 := NV("v6") - if VertexContains(v4, []Vertex{v5, v6}) != false { - t.Errorf("should be false instead of true.") - } - - v7 := NV("v7") - v8 := NV("v8") - v9 := NV("v9") - if VertexContains(v8, []Vertex{v7, v8, v9}) != true { - t.Errorf("should be true instead of false.") - } - - v1b := NV("v1") // same value, different objects - if VertexContains(v1b, []Vertex{v1, v2, v3}) != false { - t.Errorf("should be false instead of true.") - } -} - func TestTopoSort1(t *testing.T) { G, _ := NewGraph("g9") v1 := NV("v1") @@ -683,31 +655,6 @@ func TestReachability4(t *testing.T) { } } -func TestReverse1(t *testing.T) { - v1 := NV("v1") - v2 := NV("v2") - v3 := NV("v3") - v4 := NV("v4") - v5 := NV("v5") - v6 := NV("v6") - - if rev := Reverse([]Vertex{}); !reflect.DeepEqual(rev, []Vertex{}) { - t.Errorf("reverse of vertex slice failed (empty)") - } - - if rev := Reverse([]Vertex{v1}); !reflect.DeepEqual(rev, []Vertex{v1}) { - t.Errorf("reverse of vertex slice failed (single)") - } - - if rev := Reverse([]Vertex{v1, v2, v3, v4, v5, v6}); !reflect.DeepEqual(rev, []Vertex{v6, v5, v4, v3, v2, v1}) { - t.Errorf("reverse of vertex slice failed (1..6)") - } - - if rev := Reverse([]Vertex{v6, v5, v4, v3, v2, v1}); !reflect.DeepEqual(rev, []Vertex{v1, v2, v3, v4, v5, v6}) { - t.Errorf("reverse of vertex slice failed (6..1)") - } -} - func TestCopy1(t *testing.T) { g1 := &Graph{} g2 := g1.Copy() // check this doesn't panic @@ -750,54 +697,6 @@ func TestGraphCmp1(t *testing.T) { // } //} -func TestSort0(t *testing.T) { - vs := []Vertex{} - s := Sort(vs) - - if !reflect.DeepEqual(s, []Vertex{}) { - t.Errorf("sort failed!") - if s == nil { - t.Logf("output is nil!") - } else { - str := "Got:" - for _, v := range s { - str += " " + v.String() - } - t.Errorf(str) - } - } -} - -func TestSort1(t *testing.T) { - v1 := NV("v1") - v2 := NV("v2") - v3 := NV("v3") - v4 := NV("v4") - v5 := NV("v5") - v6 := NV("v6") - - vs := []Vertex{v3, v2, v6, v1, v5, v4} - s := Sort(vs) - - if !reflect.DeepEqual(s, []Vertex{v1, v2, v3, v4, v5, v6}) { - t.Errorf("sort failed!") - str := "Got:" - for _, v := range s { - str += " " + v.String() - } - t.Errorf(str) - } - - if !reflect.DeepEqual(vs, []Vertex{v3, v2, v6, v1, v5, v4}) { - t.Errorf("sort modified input!") - str := "Got:" - for _, v := range vs { - str += " " + v.String() - } - t.Errorf(str) - } -} - func TestSprint1(t *testing.T) { g, _ := NewGraph("graph1") v1 := NV("v1")