github.com/jgbaldwinbrown/perf@v0.1.1/benchunit/parse.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 benchunit manipulates benchmark units and formats numbers 6 // in those units. 7 package benchunit 8 9 import ( 10 "fmt" 11 "unicode" 12 ) 13 14 // A Class specifies what class of unit prefixes are in use. 15 type Class int 16 17 const ( 18 // Decimal indicates values of a given unit should be scaled 19 // by powers of 1000. Decimal units use the International 20 // System of Units SI prefixes, such as "k", and "M". 21 Decimal Class = iota 22 // Binary indicates values of a given unit should be scaled by 23 // powers of 1024. Binary units use the International 24 // Electrotechnical Commission (IEC) binary prefixes, such as 25 // "Ki" and "Mi". 26 Binary 27 ) 28 29 func (c Class) String() string { 30 switch c { 31 case Decimal: 32 return "Decimal" 33 case Binary: 34 return "Binary" 35 } 36 return fmt.Sprintf("Class(%d)", int(c)) 37 } 38 39 // ClassOf returns the Class of unit. If unit contains some measure of 40 // bytes in the numerator, this is Binary. Otherwise, it is Decimal. 41 func ClassOf(unit string) Class { 42 p := newParser(unit) 43 for p.next() { 44 if (p.tok == "B" || p.tok == "MB" || p.tok == "bytes") && !p.denom { 45 return Binary 46 } 47 } 48 return Decimal 49 } 50 51 type parser struct { 52 rest string // unparsed unit 53 rpos int // byte consumed from original unit 54 55 // Current token 56 tok string 57 pos int // byte offset of tok in original unit 58 denom bool // current token is in denominator 59 } 60 61 func newParser(unit string) *parser { 62 return &parser{rest: unit} 63 } 64 65 func (p *parser) next() bool { 66 // Consume separators. 67 for i, r := range p.rest { 68 if r == '*' { 69 p.denom = false 70 } else if r == '/' { 71 p.denom = true 72 } else if !(r == '-' || unicode.IsSpace(r)) { 73 p.rpos += i 74 p.rest = p.rest[i:] 75 goto tok 76 } 77 } 78 // End of string. 79 p.rest = "" 80 return false 81 82 tok: 83 // Consume until separator. 84 end := len(p.rest) 85 for i, r := range p.rest { 86 if r == '*' || r == '/' || r == '-' || unicode.IsSpace(r) { 87 end = i 88 break 89 } 90 } 91 p.tok = p.rest[:end] 92 p.pos = p.rpos 93 p.rpos += end 94 p.rest = p.rest[end:] 95 return true 96 }