Upgrade dependent version: github.com/open-policy-agent/opa v0.18.0 -> v0.45.0 Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io> Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io>
136 lines
2.7 KiB
Go
136 lines
2.7 KiB
Go
// Copyright 2020 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 copypropagation
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/open-policy-agent/opa/ast"
|
|
"github.com/open-policy-agent/opa/util"
|
|
)
|
|
|
|
type rankFunc func(*unionFindRoot, *unionFindRoot) (*unionFindRoot, *unionFindRoot)
|
|
|
|
type unionFind struct {
|
|
roots *util.HashMap
|
|
parents *ast.ValueMap
|
|
rank rankFunc
|
|
}
|
|
|
|
func newUnionFind(rank rankFunc) *unionFind {
|
|
return &unionFind{
|
|
roots: util.NewHashMap(func(a util.T, b util.T) bool {
|
|
return a.(ast.Value).Compare(b.(ast.Value)) == 0
|
|
}, func(v util.T) int {
|
|
return v.(ast.Value).Hash()
|
|
}),
|
|
parents: ast.NewValueMap(),
|
|
rank: rank,
|
|
}
|
|
}
|
|
|
|
func (uf *unionFind) MakeSet(v ast.Value) *unionFindRoot {
|
|
|
|
root, ok := uf.Find(v)
|
|
if ok {
|
|
return root
|
|
}
|
|
|
|
root = newUnionFindRoot(v)
|
|
uf.parents.Put(v, v)
|
|
uf.roots.Put(v, root)
|
|
return root
|
|
}
|
|
|
|
func (uf *unionFind) Find(v ast.Value) (*unionFindRoot, bool) {
|
|
|
|
parent := uf.parents.Get(v)
|
|
if parent == nil {
|
|
return nil, false
|
|
}
|
|
|
|
if parent.Compare(v) == 0 {
|
|
r, ok := uf.roots.Get(v)
|
|
return r.(*unionFindRoot), ok
|
|
}
|
|
|
|
return uf.Find(parent)
|
|
}
|
|
|
|
func (uf *unionFind) Merge(a, b ast.Value) (*unionFindRoot, bool) {
|
|
|
|
r1 := uf.MakeSet(a)
|
|
r2 := uf.MakeSet(b)
|
|
|
|
if r1 != r2 {
|
|
|
|
r1, r2 = uf.rank(r1, r2)
|
|
|
|
uf.parents.Put(r2.key, r1.key)
|
|
uf.roots.Delete(r2.key)
|
|
|
|
// Sets can have at most one constant value associated with them. When
|
|
// unioning, we must preserve this invariant. If a set has two constants,
|
|
// there will be no way to prove the query.
|
|
if r1.constant != nil && r2.constant != nil && !r1.constant.Equal(r2.constant) {
|
|
return nil, false
|
|
} else if r1.constant == nil {
|
|
r1.constant = r2.constant
|
|
}
|
|
}
|
|
|
|
return r1, true
|
|
}
|
|
|
|
func (uf *unionFind) String() string {
|
|
o := struct {
|
|
Roots map[string]interface{}
|
|
Parents map[string]ast.Value
|
|
}{
|
|
map[string]interface{}{},
|
|
map[string]ast.Value{},
|
|
}
|
|
|
|
uf.roots.Iter(func(k util.T, v util.T) bool {
|
|
o.Roots[k.(ast.Value).String()] = struct {
|
|
Constant *ast.Term
|
|
Key ast.Value
|
|
}{
|
|
v.(*unionFindRoot).constant,
|
|
v.(*unionFindRoot).key,
|
|
}
|
|
return true
|
|
})
|
|
|
|
uf.parents.Iter(func(k ast.Value, v ast.Value) bool {
|
|
o.Parents[k.String()] = v
|
|
return true
|
|
})
|
|
|
|
return string(util.MustMarshalJSON(o))
|
|
}
|
|
|
|
type unionFindRoot struct {
|
|
key ast.Value
|
|
constant *ast.Term
|
|
}
|
|
|
|
func newUnionFindRoot(key ast.Value) *unionFindRoot {
|
|
return &unionFindRoot{
|
|
key: key,
|
|
}
|
|
}
|
|
|
|
func (r *unionFindRoot) Value() ast.Value {
|
|
if r.constant != nil {
|
|
return r.constant.Value
|
|
}
|
|
return r.key
|
|
}
|
|
|
|
func (r *unionFindRoot) String() string {
|
|
return fmt.Sprintf("{key: %s, constant: %s", r.key, r.constant)
|
|
}
|