123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- /*
- Copyright 2015 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 generators has the generators for the set-gen utility.
- package generators
- import (
- "io"
- "k8s.io/gengo/args"
- "k8s.io/gengo/generator"
- "k8s.io/gengo/namer"
- "k8s.io/gengo/types"
- "k8s.io/klog"
- )
- // NameSystems returns the name system used by the generators in this package.
- func NameSystems() namer.NameSystems {
- return namer.NameSystems{
- "public": namer.NewPublicNamer(0),
- "private": namer.NewPrivateNamer(0),
- "raw": namer.NewRawNamer("", nil),
- }
- }
- // DefaultNameSystem returns the default name system for ordering the types to be
- // processed by the generators in this package.
- func DefaultNameSystem() string {
- return "public"
- }
- // Packages makes the sets package definition.
- func Packages(_ *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
- boilerplate, err := arguments.LoadGoBoilerplate()
- if err != nil {
- klog.Fatalf("Failed loading boilerplate: %v", err)
- }
- return generator.Packages{&generator.DefaultPackage{
- PackageName: "sets",
- PackagePath: arguments.OutputPackagePath,
- HeaderText: boilerplate,
- PackageDocumentation: []byte(
- `// Package sets has auto-generated set types.
- `),
- // GeneratorFunc returns a list of generators. Each generator makes a
- // single file.
- GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
- generators = []generator.Generator{
- // Always generate a "doc.go" file.
- generator.DefaultGen{OptionalName: "doc"},
- // Make a separate file for the Empty type, since it's shared by every type.
- generator.DefaultGen{
- OptionalName: "empty",
- OptionalBody: []byte(emptyTypeDecl),
- },
- }
- // Since we want a file per type that we generate a set for, we
- // have to provide a function for this.
- for _, t := range c.Order {
- generators = append(generators, &genSet{
- DefaultGen: generator.DefaultGen{
- // Use the privatized version of the
- // type name as the file name.
- //
- // TODO: make a namer that converts
- // camelCase to '-' separation for file
- // names?
- OptionalName: c.Namers["private"].Name(t),
- },
- outputPackage: arguments.OutputPackagePath,
- typeToMatch: t,
- imports: generator.NewImportTracker(),
- })
- }
- return generators
- },
- FilterFunc: func(c *generator.Context, t *types.Type) bool {
- // It would be reasonable to filter by the type's package here.
- // It might be necessary if your input directory has a big
- // import graph.
- switch t.Kind {
- case types.Map, types.Slice, types.Pointer:
- // These types can't be keys in a map.
- return false
- case types.Builtin:
- return true
- case types.Struct:
- // Only some structs can be keys in a map. This is triggered by the line
- // // +genset
- // or
- // // +genset=true
- return extractBoolTagOrDie("genset", t.CommentLines) == true
- }
- return false
- },
- }}
- }
- // genSet produces a file with a set for a single type.
- type genSet struct {
- generator.DefaultGen
- outputPackage string
- typeToMatch *types.Type
- imports namer.ImportTracker
- }
- // Filter ignores all but one type because we're making a single file per type.
- func (g *genSet) Filter(c *generator.Context, t *types.Type) bool { return t == g.typeToMatch }
- func (g *genSet) Namers(c *generator.Context) namer.NameSystems {
- return namer.NameSystems{
- "raw": namer.NewRawNamer(g.outputPackage, g.imports),
- }
- }
- func (g *genSet) Imports(c *generator.Context) (imports []string) {
- return append(g.imports.ImportLines(), "reflect", "sort")
- }
- // args constructs arguments for templates. Usage:
- // g.args(t, "key1", value1, "key2", value2, ...)
- //
- // 't' is loaded with the key 'type'.
- //
- // We could use t directly as the argument, but doing it this way makes it easy
- // to mix in additional parameters. This feature is not used in this set
- // generator, but is present as an example.
- func (g *genSet) args(t *types.Type, kv ...interface{}) interface{} {
- m := map[interface{}]interface{}{"type": t}
- for i := 0; i < len(kv)/2; i++ {
- m[kv[i*2]] = kv[i*2+1]
- }
- return m
- }
- // GenerateType makes the body of a file implementing a set for type t.
- func (g *genSet) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
- sw := generator.NewSnippetWriter(w, c, "$", "$")
- sw.Do(setCode, g.args(t))
- sw.Do("func less$.type|public$(lhs, rhs $.type|raw$) bool {\n", g.args(t))
- g.lessBody(sw, t)
- sw.Do("}\n", g.args(t))
- return sw.Error()
- }
- func (g *genSet) lessBody(sw *generator.SnippetWriter, t *types.Type) {
- // TODO: make this recursive, handle pointers and multiple nested structs...
- switch t.Kind {
- case types.Struct:
- for _, m := range types.FlattenMembers(t.Members) {
- sw.Do("if lhs.$.Name$ < rhs.$.Name$ { return true }\n", m)
- sw.Do("if lhs.$.Name$ > rhs.$.Name$ { return false }\n", m)
- }
- sw.Do("return false\n", nil)
- default:
- sw.Do("return lhs < rhs\n", nil)
- }
- }
- // written to the "empty.go" file.
- var emptyTypeDecl = `
- // Empty is public since it is used by some internal API objects for conversions between external
- // string arrays and internal sets, and conversion logic requires public types today.
- type Empty struct{}
- `
- // Written for every type. If you've never used text/template before:
- // $.type$ refers to the source type; |public means to
- // call the function giving the public name, |raw the raw type name.
- var setCode = `// sets.$.type|public$ is a set of $.type|raw$s, implemented via map[$.type|raw$]struct{} for minimal memory consumption.
- type $.type|public$ map[$.type|raw$]Empty
- // New$.type|public$ creates a $.type|public$ from a list of values.
- func New$.type|public$(items ...$.type|raw$) $.type|public$ {
- ss := $.type|public${}
- ss.Insert(items...)
- return ss
- }
- // $.type|public$KeySet creates a $.type|public$ from a keys of a map[$.type|raw$](? extends interface{}).
- // If the value passed in is not actually a map, this will panic.
- func $.type|public$KeySet(theMap interface{}) $.type|public$ {
- v := reflect.ValueOf(theMap)
- ret := $.type|public${}
- for _, keyValue := range v.MapKeys() {
- ret.Insert(keyValue.Interface().($.type|raw$))
- }
- return ret
- }
- // Insert adds items to the set.
- func (s $.type|public$) Insert(items ...$.type|raw$) {
- for _, item := range items {
- s[item] = Empty{}
- }
- }
- // Delete removes all items from the set.
- func (s $.type|public$) Delete(items ...$.type|raw$) {
- for _, item := range items {
- delete(s, item)
- }
- }
- // Has returns true if and only if item is contained in the set.
- func (s $.type|public$) Has(item $.type|raw$) bool {
- _, contained := s[item]
- return contained
- }
- // HasAll returns true if and only if all items are contained in the set.
- func (s $.type|public$) HasAll(items ...$.type|raw$) bool {
- for _, item := range items {
- if !s.Has(item) {
- return false
- }
- }
- return true
- }
- // HasAny returns true if any items are contained in the set.
- func (s $.type|public$) HasAny(items ...$.type|raw$) bool {
- for _, item := range items {
- if s.Has(item) {
- return true
- }
- }
- return false
- }
- // Difference returns a set of objects that are not in s2
- // For example:
- // s1 = {a1, a2, a3}
- // s2 = {a1, a2, a4, a5}
- // s1.Difference(s2) = {a3}
- // s2.Difference(s1) = {a4, a5}
- func (s $.type|public$) Difference(s2 $.type|public$) $.type|public$ {
- result := New$.type|public$()
- for key := range s {
- if !s2.Has(key) {
- result.Insert(key)
- }
- }
- return result
- }
- // Union returns a new set which includes items in either s1 or s2.
- // For example:
- // s1 = {a1, a2}
- // s2 = {a3, a4}
- // s1.Union(s2) = {a1, a2, a3, a4}
- // s2.Union(s1) = {a1, a2, a3, a4}
- func (s1 $.type|public$) Union(s2 $.type|public$) $.type|public$ {
- result := New$.type|public$()
- for key := range s1 {
- result.Insert(key)
- }
- for key := range s2 {
- result.Insert(key)
- }
- return result
- }
- // Intersection returns a new set which includes the item in BOTH s1 and s2
- // For example:
- // s1 = {a1, a2}
- // s2 = {a2, a3}
- // s1.Intersection(s2) = {a2}
- func (s1 $.type|public$) Intersection(s2 $.type|public$) $.type|public$ {
- var walk, other $.type|public$
- result := New$.type|public$()
- if s1.Len() < s2.Len() {
- walk = s1
- other = s2
- } else {
- walk = s2
- other = s1
- }
- for key := range walk {
- if other.Has(key) {
- result.Insert(key)
- }
- }
- return result
- }
- // IsSuperset returns true if and only if s1 is a superset of s2.
- func (s1 $.type|public$) IsSuperset(s2 $.type|public$) bool {
- for item := range s2 {
- if !s1.Has(item) {
- return false
- }
- }
- return true
- }
- // Equal returns true if and only if s1 is equal (as a set) to s2.
- // Two sets are equal if their membership is identical.
- // (In practice, this means same elements, order doesn't matter)
- func (s1 $.type|public$) Equal(s2 $.type|public$) bool {
- return len(s1) == len(s2) && s1.IsSuperset(s2)
- }
- type sortableSliceOf$.type|public$ []$.type|raw$
- func (s sortableSliceOf$.type|public$) Len() int { return len(s) }
- func (s sortableSliceOf$.type|public$) Less(i, j int) bool { return less$.type|public$(s[i], s[j]) }
- func (s sortableSliceOf$.type|public$) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
- // List returns the contents as a sorted $.type|raw$ slice.
- func (s $.type|public$) List() []$.type|raw$ {
- res := make(sortableSliceOf$.type|public$, 0, len(s))
- for key := range s {
- res = append(res, key)
- }
- sort.Sort(res)
- return []$.type|raw$(res)
- }
- // UnsortedList returns the slice with contents in random order.
- func (s $.type|public$) UnsortedList() []$.type|raw$ {
- res :=make([]$.type|raw$, 0, len(s))
- for key := range s {
- res = append(res, key)
- }
- return res
- }
- // Returns a single element from the set.
- func (s $.type|public$) PopAny() ($.type|raw$, bool) {
- for key := range s {
- s.Delete(key)
- return key, true
- }
- var zeroValue $.type|raw$
- return zeroValue, false
- }
- // Len returns the size of the set.
- func (s $.type|public$) Len() int {
- return len(s)
- }
- `
|