blob: 5583f334819d53d2813f082ca61ec2f5792ca531 [file] [log] [blame]
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package benchunit manipulates benchmark units and formats numbers
// in those units.
package benchunit
import (
"fmt"
"unicode"
)
// A Class specifies what class of unit prefixes are in use.
type Class int
const (
// Decimal indicates values of a given unit should be scaled
// by powers of 1000. Decimal units use the International
// System of Units SI prefixes, such as "k", and "M".
Decimal Class = iota
// Binary indicates values of a given unit should be scaled by
// powers of 1024. Binary units use the International
// Electrotechnical Commission (IEC) binary prefixes, such as
// "Ki" and "Mi".
Binary
)
func (c Class) String() string {
switch c {
case Decimal:
return "Decimal"
case Binary:
return "Binary"
}
return fmt.Sprintf("Class(%d)", int(c))
}
// ClassOf returns the Class of unit. If unit contains some measure of
// bytes in the numerator, this is Binary. Otherwise, it is Decimal.
func ClassOf(unit string) Class {
p := newParser(unit)
for p.next() {
if (p.tok == "B" || p.tok == "MB" || p.tok == "bytes") && !p.denom {
return Binary
}
}
return Decimal
}
type parser struct {
rest string // unparsed unit
rpos int // byte consumed from original unit
// Current token
tok string
pos int // byte offset of tok in original unit
denom bool // current token is in denominator
}
func newParser(unit string) *parser {
return &parser{rest: unit}
}
func (p *parser) next() bool {
// Consume separators.
for i, r := range p.rest {
if r == '*' {
p.denom = false
} else if r == '/' {
p.denom = true
} else if !(r == '-' || unicode.IsSpace(r)) {
p.rpos += i
p.rest = p.rest[i:]
goto tok
}
}
// End of string.
p.rest = ""
return false
tok:
// Consume until separator.
end := len(p.rest)
for i, r := range p.rest {
if r == '*' || r == '/' || r == '-' || unicode.IsSpace(r) {
end = i
break
}
}
p.tok = p.rest[:end]
p.pos = p.rpos
p.rpos += end
p.rest = p.rest[end:]
return true
}