Skip to content

Commit e3f3af8

Browse files
committed
init
1 parent 5bd6445 commit e3f3af8

File tree

5 files changed

+191
-1
lines changed

5 files changed

+191
-1
lines changed

.github/workflows/test.yml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: test
2+
3+
on: [push]
4+
5+
permissions: read-all
6+
7+
jobs:
8+
build:
9+
name: test
10+
runs-on: ubuntu-latest
11+
timeout-minutes: 5
12+
steps:
13+
- name: code
14+
uses: actions/checkout@v4
15+
16+
- name: go
17+
uses: actions/setup-go@v5
18+
with:
19+
go-version: ^1.23
20+
21+
- name: test
22+
run: |
23+
go get -v -t -d ./...
24+
go test -short -cover -coverprofile=coverage.out -covermode=atomic ./...
25+
26+
- name: fuzz
27+
run: go test -list . | grep Fuzz | xargs -P 8 -I {} go test -fuzz {} -fuzztime 5s ./base10quant
28+
29+
- name: codecov.io coverage
30+
uses: codecov/[email protected]
31+
with:
32+
token: ${{ secrets.CODECOV_TOKEN }}
33+
files: coverage.out

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
# base10quant
1+
base10 encoding of primitive types

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/ndx-technologies/base10quant
2+
3+
go 1.23.0

l9.go

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package base10quant
2+
3+
import (
4+
"errors"
5+
)
6+
7+
var ErrInvalidFormat = errors.New("invalid format")
8+
9+
const MaxL9 = 999_999_999
10+
11+
// L9 is base10 chars encoding least significant 9 decimals of uint32.
12+
type L9 struct{ v uint32 }
13+
14+
func L9FromUint32(v uint32) L9 { return L9{v: v} }
15+
16+
func L9FromString(s string) (L9, error) {
17+
var v L9
18+
err := (&v).UnmarshalText([]byte(s))
19+
return v, err
20+
}
21+
22+
func (s L9) UInt32() uint32 { return s.v }
23+
24+
func (s L9) IsEmpty() bool { return s.v == 0 }
25+
26+
func (s L9) AppendBytes(b []byte) {
27+
v := s.v
28+
v, b[8] = v/10, '0'+byte(v%10)
29+
v, b[7] = v/10, '0'+byte(v%10)
30+
v, b[6] = v/10, '0'+byte(v%10)
31+
v, b[5] = v/10, '0'+byte(v%10)
32+
v, b[4] = v/10, '0'+byte(v%10)
33+
v, b[3] = v/10, '0'+byte(v%10)
34+
v, b[2] = v/10, '0'+byte(v%10)
35+
v, b[1] = v/10, '0'+byte(v%10)
36+
_, b[0] = v/10, '0'+byte(v%10)
37+
}
38+
39+
func (s L9) MarshalText() ([]byte, error) {
40+
b := make([]byte, 9)
41+
s.AppendBytes(b)
42+
return b, nil
43+
}
44+
45+
func (s *L9) UnmarshalText(b []byte) error {
46+
if len(b) != 9 {
47+
return ErrInvalidFormat
48+
}
49+
s.v = 0
50+
for i := 0; i < 9; i++ {
51+
if b[i] < '0' || b[i] > '9' {
52+
return ErrInvalidFormat
53+
}
54+
s.v *= 10
55+
s.v += uint32(b[i] - '0')
56+
}
57+
return nil
58+
}
59+
60+
func (s L9) String() string {
61+
b, _ := s.MarshalText()
62+
return string(b)
63+
}

l9_test.go

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package base10quant_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/ndx-technologies/base10quant"
7+
)
8+
9+
func TestL9(t *testing.T) {
10+
t.Run("ok", func(t *testing.T) {
11+
tests := []struct {
12+
s string
13+
v uint32
14+
}{
15+
{s: "999999999", v: 999_999_999},
16+
{s: "123456789", v: 123_456_789},
17+
}
18+
for _, tc := range tests {
19+
v := base10quant.L9FromUint32(tc.v)
20+
if tc.s != v.String() {
21+
t.Errorf("expected %s, got %s", tc.s, v.String())
22+
}
23+
if tc.v != v.UInt32() {
24+
t.Errorf("expected %d, got %d", tc.v, v.UInt32())
25+
}
26+
27+
x, err := base10quant.L9FromString(tc.s)
28+
if err != nil {
29+
t.Error(err)
30+
}
31+
if v != x {
32+
t.Errorf("expected %v, got %v", v, x)
33+
}
34+
}
35+
})
36+
37+
t.Run("error", func(t *testing.T) {
38+
tests := []string{
39+
"0123456789",
40+
"a",
41+
"",
42+
"1234a6789",
43+
"1234 6789",
44+
}
45+
for _, tc := range tests {
46+
_, err := base10quant.L9FromString(tc)
47+
if err == nil {
48+
t.Errorf("expected error")
49+
}
50+
}
51+
})
52+
}
53+
54+
func FuzzL9(f *testing.F) {
55+
f.Add(uint32(999_999_999))
56+
f.Add(uint32(1))
57+
f.Add(uint32(0))
58+
59+
f.Fuzz(func(t *testing.T, v uint32) {
60+
v = v % 999_999_999
61+
62+
q := base10quant.L9FromUint32(v)
63+
if v != q.UInt32() {
64+
t.Errorf("expected %d, got %d", v, q.UInt32())
65+
}
66+
67+
g, err := base10quant.L9FromString(q.String())
68+
if err != nil {
69+
t.Error(err)
70+
}
71+
if q != g {
72+
t.Errorf("expected %v, got %v", q, g)
73+
}
74+
75+
b, err := q.MarshalText()
76+
if err != nil {
77+
t.Errorf("unexpected error: %v", err)
78+
}
79+
80+
var f base10quant.L9
81+
if !f.IsEmpty() {
82+
t.Errorf("expected empty")
83+
}
84+
if err := (f).UnmarshalText(b); err != nil {
85+
t.Error(err)
86+
}
87+
if f != q {
88+
t.Errorf("expected %v, got %v", q, f)
89+
}
90+
})
91+
}

0 commit comments

Comments
 (0)