mirror of
https://github.com/kubernetes-sigs/prometheus-adapter.git
synced 2026-04-06 17:57:51 +00:00
vendor dependencies
This commit is contained in:
parent
604208ef4f
commit
72abf135d6
1156 changed files with 78178 additions and 105799 deletions
21
vendor/sigs.k8s.io/structured-merge-diff/fieldpath/doc.go
generated
vendored
Normal file
21
vendor/sigs.k8s.io/structured-merge-diff/fieldpath/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package fieldpath defines a way for referencing path elements (e.g., an
|
||||
// index in an array, or a key in a map). It provides types for arranging these
|
||||
// into paths for referencing nested fields, and for grouping those into sets,
|
||||
// for referencing multiple nested fields.
|
||||
package fieldpath
|
||||
184
vendor/sigs.k8s.io/structured-merge-diff/fieldpath/element.go
generated
vendored
Normal file
184
vendor/sigs.k8s.io/structured-merge-diff/fieldpath/element.go
generated
vendored
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fieldpath
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/structured-merge-diff/value"
|
||||
)
|
||||
|
||||
// PathElement describes how to select a child field given a containing object.
|
||||
type PathElement struct {
|
||||
// Exactly one of the following fields should be non-nil.
|
||||
|
||||
// FieldName selects a single field from a map (reminder: this is also
|
||||
// how structs are represented). The containing object must be a map.
|
||||
FieldName *string
|
||||
|
||||
// Key selects the list element which has fields matching those given.
|
||||
// The containing object must be an associative list with map typed
|
||||
// elements.
|
||||
Key []value.Field
|
||||
|
||||
// Value selects the list element with the given value. The containing
|
||||
// object must be an associative list with a primitive typed element
|
||||
// (i.e., a set).
|
||||
Value *value.Value
|
||||
|
||||
// Index selects a list element by its index number. The containing
|
||||
// object must be an atomic list.
|
||||
Index *int
|
||||
}
|
||||
|
||||
// String presents the path element as a human-readable string.
|
||||
func (e PathElement) String() string {
|
||||
switch {
|
||||
case e.FieldName != nil:
|
||||
return "." + *e.FieldName
|
||||
case len(e.Key) > 0:
|
||||
strs := make([]string, len(e.Key))
|
||||
for i, k := range e.Key {
|
||||
strs[i] = fmt.Sprintf("%v=%v", k.Name, k.Value)
|
||||
}
|
||||
// The order must be canonical, since we use the string value
|
||||
// in a set structure.
|
||||
sort.Strings(strs)
|
||||
return "[" + strings.Join(strs, ",") + "]"
|
||||
case e.Value != nil:
|
||||
return fmt.Sprintf("[=%v]", e.Value)
|
||||
case e.Index != nil:
|
||||
return fmt.Sprintf("[%v]", *e.Index)
|
||||
default:
|
||||
return "{{invalid path element}}"
|
||||
}
|
||||
}
|
||||
|
||||
// KeyByFields is a helper function which constructs a key for an associative
|
||||
// list type. `nameValues` must have an even number of entries, alternating
|
||||
// names (type must be string) with values (type must be value.Value). If these
|
||||
// conditions are not met, KeyByFields will panic--it's intended for static
|
||||
// construction and shouldn't have user-produced values passed to it.
|
||||
func KeyByFields(nameValues ...interface{}) []value.Field {
|
||||
if len(nameValues)%2 != 0 {
|
||||
panic("must have a value for every name")
|
||||
}
|
||||
out := []value.Field{}
|
||||
for i := 0; i < len(nameValues)-1; i += 2 {
|
||||
out = append(out, value.Field{
|
||||
Name: nameValues[i].(string),
|
||||
Value: nameValues[i+1].(value.Value),
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// PathElementSet is a set of path elements.
|
||||
// TODO: serialize as a list.
|
||||
type PathElementSet struct {
|
||||
// The strange construction is because there's no way to test
|
||||
// PathElements for equality (it can't be used as a key for a map).
|
||||
members map[string]PathElement
|
||||
}
|
||||
|
||||
// Insert adds pe to the set.
|
||||
func (s *PathElementSet) Insert(pe PathElement) {
|
||||
serialized := pe.String()
|
||||
if s.members == nil {
|
||||
s.members = map[string]PathElement{
|
||||
serialized: pe,
|
||||
}
|
||||
return
|
||||
}
|
||||
if _, ok := s.members[serialized]; !ok {
|
||||
s.members[serialized] = pe
|
||||
}
|
||||
}
|
||||
|
||||
// Union returns a set containing elements that appear in either s or s2.
|
||||
func (s *PathElementSet) Union(s2 *PathElementSet) *PathElementSet {
|
||||
out := &PathElementSet{
|
||||
members: map[string]PathElement{},
|
||||
}
|
||||
for k, v := range s.members {
|
||||
out.members[k] = v
|
||||
}
|
||||
for k, v := range s2.members {
|
||||
out.members[k] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Intersection returns a set containing elements which appear in both s and s2.
|
||||
func (s *PathElementSet) Intersection(s2 *PathElementSet) *PathElementSet {
|
||||
out := &PathElementSet{
|
||||
members: map[string]PathElement{},
|
||||
}
|
||||
for k, v := range s.members {
|
||||
if _, ok := s2.members[k]; ok {
|
||||
out.members[k] = v
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Difference returns a set containing elements which appear in s but not in s2.
|
||||
func (s *PathElementSet) Difference(s2 *PathElementSet) *PathElementSet {
|
||||
out := &PathElementSet{
|
||||
members: map[string]PathElement{},
|
||||
}
|
||||
for k, v := range s.members {
|
||||
if _, ok := s2.members[k]; !ok {
|
||||
out.members[k] = v
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Size retuns the number of elements in the set.
|
||||
func (s *PathElementSet) Size() int { return len(s.members) }
|
||||
|
||||
// Has returns true if pe is a member of the set.
|
||||
func (s *PathElementSet) Has(pe PathElement) bool {
|
||||
if s.members == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := s.members[pe.String()]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Equals returns true if s and s2 have exactly the same members.
|
||||
func (s *PathElementSet) Equals(s2 *PathElementSet) bool {
|
||||
if len(s.members) != len(s2.members) {
|
||||
return false
|
||||
}
|
||||
for k := range s.members {
|
||||
if _, ok := s2.members[k]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Iterate calls f for each PathElement in the set.
|
||||
func (s *PathElementSet) Iterate(f func(PathElement)) {
|
||||
for _, pe := range s.members {
|
||||
f(pe)
|
||||
}
|
||||
}
|
||||
123
vendor/sigs.k8s.io/structured-merge-diff/fieldpath/fromvalue.go
generated
vendored
Normal file
123
vendor/sigs.k8s.io/structured-merge-diff/fieldpath/fromvalue.go
generated
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fieldpath
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/structured-merge-diff/value"
|
||||
)
|
||||
|
||||
// SetFromValue creates a set containing every leaf field mentioned in v.
|
||||
func SetFromValue(v value.Value) *Set {
|
||||
s := NewSet()
|
||||
|
||||
w := objectWalker{
|
||||
path: Path{},
|
||||
value: v,
|
||||
do: func(p Path) { s.Insert(p) },
|
||||
}
|
||||
|
||||
w.walk()
|
||||
return s
|
||||
}
|
||||
|
||||
type objectWalker struct {
|
||||
path Path
|
||||
value value.Value
|
||||
|
||||
do func(Path)
|
||||
}
|
||||
|
||||
func (w *objectWalker) walk() {
|
||||
switch {
|
||||
case w.value.Null:
|
||||
case w.value.FloatValue != nil:
|
||||
case w.value.IntValue != nil:
|
||||
case w.value.StringValue != nil:
|
||||
case w.value.BooleanValue != nil:
|
||||
// All leaf fields handled the same way (after the switch
|
||||
// statement).
|
||||
|
||||
// Descend
|
||||
case w.value.ListValue != nil:
|
||||
// If the list were atomic, we'd break here, but we don't have
|
||||
// a schema, so we can't tell.
|
||||
|
||||
for i, child := range w.value.ListValue.Items {
|
||||
w2 := *w
|
||||
w2.path = append(w.path, GuessBestListPathElement(i, child))
|
||||
w2.value = child
|
||||
w2.walk()
|
||||
}
|
||||
return
|
||||
case w.value.MapValue != nil:
|
||||
// If the map/struct were atomic, we'd break here, but we don't
|
||||
// have a schema, so we can't tell.
|
||||
|
||||
for i := range w.value.MapValue.Items {
|
||||
child := w.value.MapValue.Items[i]
|
||||
w2 := *w
|
||||
w2.path = append(w.path, PathElement{FieldName: &child.Name})
|
||||
w2.value = child.Value
|
||||
w2.walk()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Leaf fields get added to the set.
|
||||
if len(w.path) > 0 {
|
||||
w.do(w.path)
|
||||
}
|
||||
}
|
||||
|
||||
// AssociativeListCandidateFieldNames lists the field names which are
|
||||
// considered keys if found in a list element.
|
||||
var AssociativeListCandidateFieldNames = []string{
|
||||
"key",
|
||||
"id",
|
||||
"name",
|
||||
}
|
||||
|
||||
// GuessBestListPathElement guesses whether item is an associative list
|
||||
// element, which should be referenced by key(s), or if it is not and therefore
|
||||
// referencing by index is acceptable. Currently this is done by checking
|
||||
// whether item has any of the fields listed in
|
||||
// AssociativeListCandidateFieldNames which have scalar values.
|
||||
func GuessBestListPathElement(index int, item value.Value) PathElement {
|
||||
if item.MapValue == nil {
|
||||
// Non map items could be parts of sets or regular "atomic"
|
||||
// lists. We won't try to guess whether something should be a
|
||||
// set or not.
|
||||
return PathElement{Index: &index}
|
||||
}
|
||||
|
||||
var keys []value.Field
|
||||
for _, name := range AssociativeListCandidateFieldNames {
|
||||
f, ok := item.MapValue.Get(name)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// only accept primitive/scalar types as keys.
|
||||
if f.Value.Null || f.Value.MapValue != nil || f.Value.ListValue != nil {
|
||||
continue
|
||||
}
|
||||
keys = append(keys, *f)
|
||||
}
|
||||
if len(keys) > 0 {
|
||||
return PathElement{Key: keys}
|
||||
}
|
||||
return PathElement{Index: &index}
|
||||
}
|
||||
74
vendor/sigs.k8s.io/structured-merge-diff/fieldpath/managers.go
generated
vendored
Normal file
74
vendor/sigs.k8s.io/structured-merge-diff/fieldpath/managers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fieldpath
|
||||
|
||||
// APIVersion describes the version of an object or of a fieldset.
|
||||
type APIVersion string
|
||||
|
||||
// VersionedSet associates a version to a set.
|
||||
type VersionedSet struct {
|
||||
*Set
|
||||
APIVersion APIVersion
|
||||
Applied bool
|
||||
}
|
||||
|
||||
// ManagedFields is a map from manager to VersionedSet (what they own in
|
||||
// what version).
|
||||
type ManagedFields map[string]*VersionedSet
|
||||
|
||||
// Difference returns a symmetric difference between two Managers. If a
|
||||
// given user's entry has version X in lhs and version Y in rhs, then
|
||||
// the return value for that user will be from rhs. If the difference for
|
||||
// a user is an empty set, that user will not be inserted in the map.
|
||||
func (lhs ManagedFields) Difference(rhs ManagedFields) ManagedFields {
|
||||
diff := ManagedFields{}
|
||||
|
||||
for manager, left := range lhs {
|
||||
right, ok := rhs[manager]
|
||||
if !ok {
|
||||
if !left.Empty() {
|
||||
diff[manager] = left
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// If we have sets in both but their version
|
||||
// differs, we don't even diff and keep the
|
||||
// entire thing.
|
||||
if left.APIVersion != right.APIVersion {
|
||||
diff[manager] = right
|
||||
continue
|
||||
}
|
||||
|
||||
newSet := left.Difference(right.Set).Union(right.Difference(left.Set))
|
||||
if !newSet.Empty() {
|
||||
diff[manager] = &VersionedSet{
|
||||
Set: newSet,
|
||||
APIVersion: right.APIVersion,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for manager, set := range rhs {
|
||||
if _, ok := lhs[manager]; ok {
|
||||
// Already done
|
||||
continue
|
||||
}
|
||||
if !set.Empty() {
|
||||
diff[manager] = set
|
||||
}
|
||||
}
|
||||
|
||||
return diff
|
||||
}
|
||||
81
vendor/sigs.k8s.io/structured-merge-diff/fieldpath/path.go
generated
vendored
Normal file
81
vendor/sigs.k8s.io/structured-merge-diff/fieldpath/path.go
generated
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fieldpath
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/structured-merge-diff/value"
|
||||
)
|
||||
|
||||
// Path describes how to select a potentially deeply-nested child field given a
|
||||
// containing object.
|
||||
type Path []PathElement
|
||||
|
||||
func (fp Path) String() string {
|
||||
strs := make([]string, len(fp))
|
||||
for i := range fp {
|
||||
strs[i] = fp[i].String()
|
||||
}
|
||||
return strings.Join(strs, "")
|
||||
}
|
||||
|
||||
func (fp Path) Copy() Path {
|
||||
new := make(Path, len(fp))
|
||||
copy(new, fp)
|
||||
return new
|
||||
}
|
||||
|
||||
// MakePath constructs a Path. The parts may be PathElements, ints, strings.
|
||||
func MakePath(parts ...interface{}) (Path, error) {
|
||||
var fp Path
|
||||
for _, p := range parts {
|
||||
switch t := p.(type) {
|
||||
case PathElement:
|
||||
fp = append(fp, t)
|
||||
case int:
|
||||
// TODO: Understand schema and object and convert this to the
|
||||
// FieldSpecifier below if appropriate.
|
||||
fp = append(fp, PathElement{Index: &t})
|
||||
case string:
|
||||
fp = append(fp, PathElement{FieldName: &t})
|
||||
case []value.Field:
|
||||
if len(t) == 0 {
|
||||
return nil, fmt.Errorf("associative list key type path elements must have at least one key (got zero)")
|
||||
}
|
||||
fp = append(fp, PathElement{Key: t})
|
||||
case value.Value:
|
||||
// TODO: understand schema and verify that this is a set type
|
||||
// TODO: make a copy of t
|
||||
fp = append(fp, PathElement{Value: &t})
|
||||
default:
|
||||
return nil, fmt.Errorf("unable to make %#v into a path element", p)
|
||||
}
|
||||
}
|
||||
return fp, nil
|
||||
}
|
||||
|
||||
// MakePathOrDie panics if parts can't be turned into a path. Good for things
|
||||
// that are known at complie time.
|
||||
func MakePathOrDie(parts ...interface{}) Path {
|
||||
fp, err := MakePath(parts...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return fp
|
||||
}
|
||||
311
vendor/sigs.k8s.io/structured-merge-diff/fieldpath/set.go
generated
vendored
Normal file
311
vendor/sigs.k8s.io/structured-merge-diff/fieldpath/set.go
generated
vendored
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fieldpath
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Set identifies a set of fields.
|
||||
type Set struct {
|
||||
// Members lists fields that are part of the set.
|
||||
// TODO: will be serialized as a list of path elements.
|
||||
Members PathElementSet
|
||||
|
||||
// Children lists child fields which themselves have children that are
|
||||
// members of the set. Appearance in this list does not imply membership.
|
||||
// Note: this is a tree, not an arbitrary graph.
|
||||
Children SetNodeMap
|
||||
}
|
||||
|
||||
// NewSet makes a set from a list of paths.
|
||||
func NewSet(paths ...Path) *Set {
|
||||
s := &Set{}
|
||||
for _, p := range paths {
|
||||
s.Insert(p)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Insert adds the field identified by `p` to the set. Important: parent fields
|
||||
// are NOT added to the set; if that is desired, they must be added separately.
|
||||
func (s *Set) Insert(p Path) {
|
||||
if len(p) == 0 {
|
||||
// Zero-length path identifies the entire object; we don't
|
||||
// track top-level ownership.
|
||||
return
|
||||
}
|
||||
for {
|
||||
if len(p) == 1 {
|
||||
s.Members.Insert(p[0])
|
||||
return
|
||||
}
|
||||
s = s.Children.Descend(p[0])
|
||||
p = p[1:]
|
||||
}
|
||||
}
|
||||
|
||||
// Union returns a Set containing elements which appear in either s or s2.
|
||||
func (s *Set) Union(s2 *Set) *Set {
|
||||
return &Set{
|
||||
Members: *s.Members.Union(&s2.Members),
|
||||
Children: *s.Children.Union(&s2.Children),
|
||||
}
|
||||
}
|
||||
|
||||
// Intersection returns a Set containing leaf elements which appear in both s
|
||||
// and s2. Intersection can be constructed from Union and Difference operations
|
||||
// (example in the tests) but it's much faster to do it in one pass.
|
||||
func (s *Set) Intersection(s2 *Set) *Set {
|
||||
return &Set{
|
||||
Members: *s.Members.Intersection(&s2.Members),
|
||||
Children: *s.Children.Intersection(&s2.Children),
|
||||
}
|
||||
}
|
||||
|
||||
// Difference returns a Set containing elements which:
|
||||
// * appear in s
|
||||
// * do not appear in s2
|
||||
//
|
||||
// In other words, for leaf fields, this acts like a regular set difference
|
||||
// operation. When non leaf fields are compared with leaf fields ("parents"
|
||||
// which contain "children"), the effect is:
|
||||
// * parent - child = parent
|
||||
// * child - parent = {empty set}
|
||||
func (s *Set) Difference(s2 *Set) *Set {
|
||||
return &Set{
|
||||
Members: *s.Members.Difference(&s2.Members),
|
||||
Children: *s.Children.Difference(s2),
|
||||
}
|
||||
}
|
||||
|
||||
// Size returns the number of members of the set.
|
||||
func (s *Set) Size() int {
|
||||
return s.Members.Size() + s.Children.Size()
|
||||
}
|
||||
|
||||
// Empty returns true if there are no members of the set. It is a separate
|
||||
// function from Size since it's common to check whether size > 0, and
|
||||
// potentially much faster to return as soon as a single element is found.
|
||||
func (s *Set) Empty() bool {
|
||||
if s.Members.Size() > 0 {
|
||||
return false
|
||||
}
|
||||
return s.Children.Empty()
|
||||
}
|
||||
|
||||
// Has returns true if the field referenced by `p` is a member of the set.
|
||||
func (s *Set) Has(p Path) bool {
|
||||
if len(p) == 0 {
|
||||
// No one owns "the entire object"
|
||||
return false
|
||||
}
|
||||
for {
|
||||
if len(p) == 1 {
|
||||
return s.Members.Has(p[0])
|
||||
}
|
||||
var ok bool
|
||||
s, ok = s.Children.Get(p[0])
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
p = p[1:]
|
||||
}
|
||||
}
|
||||
|
||||
// Equals returns true if s and s2 have exactly the same members.
|
||||
func (s *Set) Equals(s2 *Set) bool {
|
||||
return s.Members.Equals(&s2.Members) && s.Children.Equals(&s2.Children)
|
||||
}
|
||||
|
||||
// String returns the set one element per line.
|
||||
func (s *Set) String() string {
|
||||
elements := []string{}
|
||||
s.Iterate(func(p Path) {
|
||||
elements = append(elements, p.String())
|
||||
})
|
||||
return strings.Join(elements, "\n")
|
||||
}
|
||||
|
||||
// Iterate calls f once for each field that is a member of the set (preorder
|
||||
// DFS). The path passed to f will be reused so make a copy if you wish to keep
|
||||
// it.
|
||||
func (s *Set) Iterate(f func(Path)) {
|
||||
s.iteratePrefix(Path{}, f)
|
||||
}
|
||||
|
||||
func (s *Set) iteratePrefix(prefix Path, f func(Path)) {
|
||||
s.Members.Iterate(func(pe PathElement) { f(append(prefix, pe)) })
|
||||
s.Children.iteratePrefix(prefix, f)
|
||||
}
|
||||
|
||||
// WithPrefix returns the subset of paths which begin with the given prefix,
|
||||
// with the prefix not included.
|
||||
func (s *Set) WithPrefix(pe PathElement) *Set {
|
||||
subset, ok := s.Children.Get(pe)
|
||||
if !ok {
|
||||
return NewSet()
|
||||
}
|
||||
return subset
|
||||
}
|
||||
|
||||
// setNode is a pair of PathElement / Set, for the purpose of expressing
|
||||
// nested set membership.
|
||||
type setNode struct {
|
||||
pathElement PathElement
|
||||
set *Set
|
||||
}
|
||||
|
||||
// SetNodeMap is a map of PathElement to subset.
|
||||
type SetNodeMap struct {
|
||||
members map[string]setNode
|
||||
}
|
||||
|
||||
// Descend adds pe to the set if necessary, returning the associated subset.
|
||||
func (s *SetNodeMap) Descend(pe PathElement) *Set {
|
||||
serialized := pe.String()
|
||||
if s.members == nil {
|
||||
s.members = map[string]setNode{}
|
||||
}
|
||||
if n, ok := s.members[serialized]; ok {
|
||||
return n.set
|
||||
}
|
||||
ss := &Set{}
|
||||
s.members[serialized] = setNode{
|
||||
pathElement: pe,
|
||||
set: ss,
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
// Size returns the sum of the number of members of all subsets.
|
||||
func (s *SetNodeMap) Size() int {
|
||||
count := 0
|
||||
for _, v := range s.members {
|
||||
count += v.set.Size()
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// Empty returns false if there's at least one member in some child set.
|
||||
func (s *SetNodeMap) Empty() bool {
|
||||
for _, n := range s.members {
|
||||
if !n.set.Empty() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Get returns (the associated set, true) or (nil, false) if there is none.
|
||||
func (s *SetNodeMap) Get(pe PathElement) (*Set, bool) {
|
||||
if s.members == nil {
|
||||
return nil, false
|
||||
}
|
||||
serialized := pe.String()
|
||||
if n, ok := s.members[serialized]; ok {
|
||||
return n.set, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Equals returns true if s and s2 have the same structure (same nested
|
||||
// child sets).
|
||||
func (s *SetNodeMap) Equals(s2 *SetNodeMap) bool {
|
||||
if len(s.members) != len(s2.members) {
|
||||
return false
|
||||
}
|
||||
for k, v := range s.members {
|
||||
v2, ok := s2.members[k]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if !v.set.Equals(v2.set) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Union returns a SetNodeMap with members that appear in either s or s2.
|
||||
func (s *SetNodeMap) Union(s2 *SetNodeMap) *SetNodeMap {
|
||||
out := &SetNodeMap{}
|
||||
for k, sn := range s.members {
|
||||
pe := sn.pathElement
|
||||
if sn2, ok := s2.members[k]; ok {
|
||||
*out.Descend(pe) = *sn.set.Union(sn2.set)
|
||||
} else {
|
||||
*out.Descend(pe) = *sn.set
|
||||
}
|
||||
}
|
||||
for k, sn2 := range s2.members {
|
||||
pe := sn2.pathElement
|
||||
if _, ok := s.members[k]; ok {
|
||||
// already handled
|
||||
continue
|
||||
}
|
||||
*out.Descend(pe) = *sn2.set
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Intersection returns a SetNodeMap with members that appear in both s and s2.
|
||||
func (s *SetNodeMap) Intersection(s2 *SetNodeMap) *SetNodeMap {
|
||||
out := &SetNodeMap{}
|
||||
for k, sn := range s.members {
|
||||
pe := sn.pathElement
|
||||
if sn2, ok := s2.members[k]; ok {
|
||||
i := *sn.set.Intersection(sn2.set)
|
||||
if !i.Empty() {
|
||||
*out.Descend(pe) = i
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Difference returns a SetNodeMap with members that appear in s but not in s2.
|
||||
func (s *SetNodeMap) Difference(s2 *Set) *SetNodeMap {
|
||||
out := &SetNodeMap{}
|
||||
for k, sn := range s.members {
|
||||
pe := sn.pathElement
|
||||
if sn2, ok := s2.Children.members[k]; ok {
|
||||
diff := *sn.set.Difference(sn2.set)
|
||||
// We aren't permitted to add nodes with no elements.
|
||||
if !diff.Empty() {
|
||||
*out.Descend(pe) = diff
|
||||
}
|
||||
} else {
|
||||
*out.Descend(pe) = *sn.set
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Iterate calls f for each PathElement in the set.
|
||||
func (s *SetNodeMap) Iterate(f func(PathElement)) {
|
||||
for _, n := range s.members {
|
||||
f(n.pathElement)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SetNodeMap) iteratePrefix(prefix Path, f func(Path)) {
|
||||
for _, n := range s.members {
|
||||
pe := n.pathElement
|
||||
n.set.iteratePrefix(append(prefix, pe), f)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue