90
vendor/github.com/open-policy-agent/opa/util/graph.go
generated
vendored
Normal file
90
vendor/github.com/open-policy-agent/opa/util/graph.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright 2016 The OPA Authors. All rights reserved.
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
// Traversal defines a basic interface to perform traversals.
|
||||
type Traversal interface {
|
||||
|
||||
// Edges should return the neighbours of node "u".
|
||||
Edges(u T) []T
|
||||
|
||||
// Visited should return true if node "u" has already been visited in this
|
||||
// traversal. If the same traversal is used multiple times, the state that
|
||||
// tracks visited nodes should be reset.
|
||||
Visited(u T) bool
|
||||
}
|
||||
|
||||
// Equals should return true if node "u" equals node "v".
|
||||
type Equals func(u T, v T) bool
|
||||
|
||||
// Iter should return true to indicate stop.
|
||||
type Iter func(u T) bool
|
||||
|
||||
// DFS performs a depth first traversal calling f for each node starting from u.
|
||||
// If f returns true, traversal stops and DFS returns true.
|
||||
func DFS(t Traversal, f Iter, u T) bool {
|
||||
lifo := NewLIFO(u)
|
||||
for lifo.Size() > 0 {
|
||||
next, _ := lifo.Pop()
|
||||
if t.Visited(next) {
|
||||
continue
|
||||
}
|
||||
if f(next) {
|
||||
return true
|
||||
}
|
||||
for _, v := range t.Edges(next) {
|
||||
lifo.Push(v)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// BFS performs a breadth first traversal calling f for each node starting from
|
||||
// u. If f returns true, traversal stops and BFS returns true.
|
||||
func BFS(t Traversal, f Iter, u T) bool {
|
||||
fifo := NewFIFO(u)
|
||||
for fifo.Size() > 0 {
|
||||
next, _ := fifo.Pop()
|
||||
if t.Visited(next) {
|
||||
continue
|
||||
}
|
||||
if f(next) {
|
||||
return true
|
||||
}
|
||||
for _, v := range t.Edges(next) {
|
||||
fifo.Push(v)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// DFSPath returns a path from node a to node z found by performing
|
||||
// a depth first traversal. If no path is found, an empty slice is returned.
|
||||
func DFSPath(t Traversal, eq Equals, a, z T) []T {
|
||||
p := dfsRecursive(t, eq, a, z, []T{})
|
||||
for i := len(p)/2 - 1; i >= 0; i-- {
|
||||
o := len(p) - i - 1
|
||||
p[i], p[o] = p[o], p[i]
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func dfsRecursive(t Traversal, eq Equals, u, z T, path []T) []T {
|
||||
if t.Visited(u) {
|
||||
return path
|
||||
}
|
||||
for _, v := range t.Edges(u) {
|
||||
if eq(v, z) {
|
||||
path = append(path, z)
|
||||
path = append(path, u)
|
||||
return path
|
||||
}
|
||||
if p := dfsRecursive(t, eq, v, z, path); len(p) > 0 {
|
||||
path = append(p, u)
|
||||
return path
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
||||
Reference in New Issue
Block a user