// 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 ast import ( "fmt" "slices" "github.com/open-policy-agent/opa/v1/util" ) // VarSet represents a set of variables. type VarSet map[Var]struct{ *Location } // NewVarSet returns a new VarSet containing the specified variables. func NewVarSet(vs ...Var) VarSet { s := make(VarSet, len(vs)) for _, v := range vs { s.Add(v) } return s } // NewVarSet returns a new VarSet containing the specified variables. func NewVarSetOfSize(size int) VarSet { return make(VarSet, size) } // Add updates the set to include the variable "v". func (s VarSet) Add(v Var) { if _, ok := s[v]; !ok { s[v] = struct{ *Location }{} } } func (s VarSet) AddLocation(v Var, l *Location) { if entry, ok := s[v]; ok { entry.Location = l s[v] = entry } } // Contains returns true if the set contains the variable "v". func (s VarSet) Contains(v Var) bool { _, ok := s[v] return ok } // Copy returns a shallow copy of the VarSet. func (s VarSet) Copy() VarSet { cpy := NewVarSetOfSize(len(s)) for v := range s { cpy.Add(v) } return cpy } // Diff returns a VarSet containing variables in s that are not in vs. func (s VarSet) Diff(vs VarSet) VarSet { r := NewVarSetOfSize(s.DiffCount(vs)) for v := range s { if !vs.Contains(v) { r.Add(v) r.AddLocation(v, s[v].Location) } } return r } // DiffCount returns the number of variables in s that are not in vs. func (s VarSet) DiffCount(vs VarSet) (i int) { for v := range s { if !vs.Contains(v) { i++ } } return } // Equal returns true if s contains exactly the same elements as vs. func (s VarSet) Equal(vs VarSet) bool { if len(s) != len(vs) { return false } for v := range s { if !vs.Contains(v) { return false } } return true } // Intersect returns a VarSet containing variables in s that are in vs. func (s VarSet) Intersect(vs VarSet) VarSet { i := 0 for v := range s { if vs.Contains(v) { i++ } } r := NewVarSetOfSize(i) for v := range s { if vs.Contains(v) { r.Add(v) } } return r } // Sorted returns a new sorted slice of vars from s. func (s VarSet) Sorted() []Var { sorted := make([]Var, 0, len(s)) for v := range s { sorted = append(sorted, v) } slices.SortFunc(sorted, VarCompare) return sorted } // Update merges the other VarSet into this VarSet. func (s VarSet) Update(vs VarSet) { for v := range vs { s.Add(v) } } func (s VarSet) String() string { return fmt.Sprintf("%v", util.KeysSorted(s)) }