github.com/jgbaldwinbrown/perf@v0.1.1/benchproc/key.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package benchproc 6 7 import "strings" 8 9 // A Key is an immutable tuple mapping from Fields to strings whose 10 // structure is given by a Projection. Two Keys are == if they come 11 // from the same Projection and have identical values. 12 type Key struct { 13 k *keyNode 14 } 15 16 // IsZero reports whether k is a zeroed Key with no projection and no fields. 17 func (k Key) IsZero() bool { 18 return k.k == nil 19 } 20 21 // Get returns the value of Field f in this Key. 22 // 23 // It panics if Field f does not come from the same Projection as the 24 // Key or if f is a tuple Field. 25 func (k Key) Get(f *Field) string { 26 if k.IsZero() { 27 panic("zero Key has no fields") 28 } 29 if k.k.proj != f.proj { 30 panic("Key and Field have different Projections") 31 } 32 if f.IsTuple { 33 panic(f.Name + " is a tuple field") 34 } 35 idx := f.idx 36 if idx >= len(k.k.vals) { 37 return "" 38 } 39 return k.k.vals[idx] 40 } 41 42 // Projection returns the Projection describing Key k. 43 func (k Key) Projection() *Projection { 44 if k.IsZero() { 45 return nil 46 } 47 return k.k.proj 48 } 49 50 // String returns Key as a space-separated sequence of key:value 51 // pairs in field order. 52 func (k Key) String() string { 53 return k.string(true) 54 } 55 56 // StringValues returns Key as a space-separated sequences of 57 // values in field order. 58 func (k Key) StringValues() string { 59 return k.string(false) 60 } 61 62 func (k Key) string(keys bool) string { 63 if k.IsZero() { 64 return "<zero>" 65 } 66 buf := new(strings.Builder) 67 for _, field := range k.k.proj.FlattenedFields() { 68 if field.idx >= len(k.k.vals) { 69 continue 70 } 71 val := k.k.vals[field.idx] 72 if val == "" { 73 continue 74 } 75 if buf.Len() > 0 { 76 buf.WriteByte(' ') 77 } 78 if keys { 79 buf.WriteString(field.Name) 80 buf.WriteByte(':') 81 } 82 buf.WriteString(val) 83 } 84 return buf.String() 85 } 86 87 // commonProjection returns the Projection that all Keys have, or panics if any 88 // Key has a different Projection. It returns nil if len(keys) == 0. 89 func commonProjection(keys []Key) *Projection { 90 if len(keys) == 0 { 91 return nil 92 } 93 s := keys[0].Projection() 94 for _, k := range keys[1:] { 95 if k.Projection() != s { 96 panic("Keys must all have the same Projection") 97 } 98 } 99 return s 100 } 101 102 // keyNode is the internal heap-allocated object backing a Key. 103 // This allows Key itself to be a value type whose equality is 104 // determined by the pointer equality of the underlying keyNode. 105 type keyNode struct { 106 proj *Projection 107 // vals are the values in this Key, indexed by fieldInternal.idx. Trailing 108 // ""s are always trimmed. 109 // 110 // Notably, this is *not* in the order of the flattened schema. This is 111 // because fields can be added in the middle of a schema on-the-fly, and we 112 // need to not invalidate existing Keys. 113 vals []string 114 } 115 116 func (n *keyNode) equalRow(row []string) bool { 117 if len(n.vals) != len(row) { 118 return false 119 } 120 for i, v := range n.vals { 121 if row[i] != v { 122 return false 123 } 124 } 125 return true 126 }