Skip to content

Instantly share code, notes, and snippets.

@felixdorn
Last active July 31, 2025 23:24
Show Gist options
  • Select an option

  • Save felixdorn/8f73be5171ed3a44096e200224e5fab7 to your computer and use it in GitHub Desktop.

Select an option

Save felixdorn/8f73be5171ed3a44096e200224e5fab7 to your computer and use it in GitHub Desktop.
package quantity
import (
"fmt"
"unsafe"
)
type Quantity struct {
// Scalar represents the magnitude of the quantity
Scalar uint64
// Prefix is one of 'k', 'K', 'M', 'G', 'T', 'P', 'E', or 0 if absent.
Prefix byte
// BinaryPrefix indicates whether the prefix should be interpreted as a power of 2 instead of a power of 10.
BinaryPrefix bool
// Unit is a string of letters, it ends after the first '/', or EOF
Unit string
// Over is a string of letters, it ends at EOF
Over string
}
const (
StateScalar = iota
StateScalarEnd
StatePrefix
StateUnit
StateUnitEnd
StateOver
StateOverEnd
)
// Parse parses an ASCII string representing a quantity, like "1Gib/s" or "10 Kg"
func Parse(s string) (Quantity, error) {
qty := Quantity{}
var cursor int
length := len(s)
state := StateScalar
var scalarBytes [64]byte
var scalarIdx uint8
// First alloc (escape)
var unitBytes [32]byte
var unitIdx uint8
// Second alloc (escape)
var overBytes [32]byte
var overIdx uint8
cursor:
for {
if cursor >= length {
switch state {
case StateScalar, StateUnit, StateOver:
state += 1
default:
break cursor
}
} else if isSpace(s[cursor]) {
cursor++
continue
}
switch state {
case StateScalar:
if scalarIdx == 64 {
return Quantity{}, fmt.Errorf("invalid scalar: too long (over 64 bytes)")
}
// We shouldn't discard this byte!
if !isDigit(s[cursor]) {
state = StateScalarEnd
continue
}
scalarBytes[scalarIdx] = s[cursor]
scalarIdx++
cursor++
continue
case StateScalarEnd:
if scalarIdx != 0 {
qty.Scalar = parseValidBase10Uint(scalarBytes[:scalarIdx])
} else {
// There's no scalar value, so we assume 0.
qty.Scalar = 0
}
state = StatePrefix
continue
case StatePrefix:
switch s[cursor] {
case 'k', 'K', 'M', 'G', 'T', 'P', 'E':
qty.Prefix = s[cursor]
default:
// We shouldn't discard this byte!
state = StateUnit
continue
}
cursor++
// We look-ahead to check if the prefix is binary, e.g. 1024 not 1000.
if cursor < length && s[cursor] == 'i' {
qty.BinaryPrefix = true
cursor++
}
// "ki" is wrong, it's Ki.
if qty.Prefix == 'k' && qty.BinaryPrefix {
qty.Prefix = 0
cursor -= 2
}
state = StateUnit
continue
case StateUnit:
if !isLetter(s[cursor]) && s[cursor] != '/' {
return Quantity{}, fmt.Errorf("unexpected character '%c' in position %d, expected a letter or '/'", s[cursor], cursor)
}
if s[cursor] == '/' {
state = StateUnitEnd
cursor++
continue
}
unitBytes[unitIdx] = s[cursor]
unitIdx++
cursor++
continue
case StateUnitEnd:
qty.Unit = unsafe.String(unsafe.SliceData(unitBytes[:unitIdx]), unitIdx)
state = StateOver
continue
case StateOver:
if !isLetter(s[cursor]) {
return Quantity{}, fmt.Errorf("unexpected character '%c' in position %d, expected a letter", s[cursor], cursor)
}
overBytes[overIdx] = s[cursor]
overIdx++
cursor++
continue
case StateOverEnd:
qty.Over = unsafe.String(unsafe.SliceData(overBytes[:overIdx]), overIdx)
break cursor
}
return Quantity{}, fmt.Errorf("unexpected character '%c' in position %d", s[cursor], cursor)
}
return qty, nil
}
func isLetter(b byte) bool {
return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z')
}
func isSpace(b byte) bool {
switch b {
case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
return true
}
return false
}
func isDigit(b byte) bool {
return b >= '0' && b <= '9'
}
// parseValidBase10Uint expects b to be less than 64 bytes long
// and contain only digits
func parseValidBase10Uint(b []byte) uint64 {
var n uint64
for _, c := range b {
n *= 10
n += uint64(c - '0')
}
return n
}
package quantity
import (
"testing"
)
func TestParse_Ok(t *testing.T) {
cases := map[string]struct {
In string
Qty Quantity
}{
"scalar only": {
"4",
Quantity{Scalar: 4},
},
"scalar with unit": {
"4bit",
Quantity{Scalar: 4, Unit: "bit"},
},
"scalar with prefix": {
"4M",
Quantity{Scalar: 4, Prefix: 'M'},
},
"scalar with unit and prefix": {
"4Mb",
Quantity{Scalar: 4, Prefix: 'M', Unit: "b"},
},
"scalar with unit and binary prefix": {
"11Tib",
Quantity{Scalar: 11, Prefix: 'T', BinaryPrefix: true, Unit: "b"},
},
"scalar with unit and binary prefix over a unit": {
"1Gib/s",
Quantity{Scalar: 1, Prefix: 'G', BinaryPrefix: true, Unit: "b", Over: "s"},
},
"with whitespace": {
" 1 0 0 0 G b it / second ",
Quantity{Scalar: 1000, Prefix: 'G', Unit: "bit", Over: "second"},
},
}
for name, tt := range cases {
t.Run(name, func(t *testing.T) {
qty, err := Parse(tt.In)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if qty.Scalar != tt.Qty.Scalar {
t.Errorf("unexpected scalar value, expected `%v`, got `%v`", tt.Qty.Scalar, qty.Scalar)
}
if qty.Prefix != tt.Qty.Prefix {
t.Errorf("unexpected prefix, expected `%v`, got `%v`", tt.Qty.Prefix, qty.Prefix)
}
if qty.BinaryPrefix != tt.Qty.BinaryPrefix {
t.Errorf("unexpected binary prefix, expected `%v`, got `%v`", tt.Qty.BinaryPrefix, qty.BinaryPrefix)
}
if qty.Unit != tt.Qty.Unit {
t.Errorf("unexpected unit, expected `%v`, got `%v`", tt.Qty.Unit, qty.Unit)
}
if qty.Over != tt.Qty.Over {
t.Errorf("unexpected over value, expected `%v`, got `%v`", tt.Qty.Over, qty.Over)
}
})
}
}
func BenchmarkParse(b *testing.B) {
for i := 0; i < b.N; i++ {
Parse("1Gibit / second")
}
}
@felixdorn
Copy link
Author

MIT LICENSED

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment