Skip to content

Commit

Permalink
Merge pull request #42 from tdakkota/feat/improve-int-decoding
Browse files Browse the repository at this point in the history
test: use integers.json file to benchmark integer decoder
  • Loading branch information
ernado committed Mar 21, 2022
2 parents 8bfec7d + 1535c41 commit 27f88a8
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 68 deletions.
9 changes: 5 additions & 4 deletions dec_int.go
Expand Up @@ -8,13 +8,14 @@ import (
"github.com/go-faster/errors"
)

var intDigits []int8
var intDigits [256]int8

const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1
const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1
const (
uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1
uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1
)

func init() {
intDigits = make([]int8, 256)
for i := 0; i < len(intDigits); i++ {
intDigits[i] = invalidCharForNumber
}
Expand Down
60 changes: 41 additions & 19 deletions dec_int_test.go
Expand Up @@ -7,28 +7,50 @@ import (
)

func BenchmarkDecoder_Int(b *testing.B) {
data := []byte(`69315063`)
d := GetDecoder()
for i := 0; i < b.N; i++ {
d.ResetBytes(data)
if _, err := d.Int(); err != nil {
b.Fatal(err)
}
}
runTestdataFile("integers.json", b.Fatal, func(name string, data []byte) {
b.Run(name, func(b *testing.B) {
d := GetDecoder()
cb := func(d *Decoder) error {
_, err := d.Int()
return err
}
b.ReportAllocs()
b.ResetTimer()

for i := 0; i < b.N; i++ {
d.ResetBytes(data)

if err := d.Arr(cb); err != nil {
b.Fatal(err)
}
}
})
})
}

func BenchmarkDecoder_Uint(b *testing.B) {
data := []byte(`69315063`)
d := GetDecoder()
for i := 0; i < b.N; i++ {
d.ResetBytes(data)
if _, err := d.UInt(); err != nil {
b.Fatal(err)
}
}
runTestdataFile("integers.json", b.Fatal, func(name string, data []byte) {
b.Run(name, func(b *testing.B) {
d := GetDecoder()
cb := func(d *Decoder) error {
_, err := d.UInt()
return err
}
b.ReportAllocs()
b.ResetTimer()

for i := 0; i < b.N; i++ {
d.ResetBytes(data)

if err := d.Arr(cb); err != nil {
b.Fatal(err)
}
}
})
})
}

func TestDecoder_int_sizes(t *testing.T) {
func TestDecoderIntSizes(t *testing.T) {
data := []byte(`69315063`)
d := GetDecoder()
for _, size := range []int{32, 64} {
Expand All @@ -39,7 +61,7 @@ func TestDecoder_int_sizes(t *testing.T) {
}
}

func TestDecoder_uint_sizes(t *testing.T) {
func TestDecoderUintSizes(t *testing.T) {
data := []byte(`69315063`)
d := GetDecoder()
for _, size := range []int{32, 64} {
Expand All @@ -56,7 +78,7 @@ func TestDecoder_Int(t *testing.T) {
return &Decoder{
buf: []byte{'1', '2'},
tail: 2,
reader: errReader{},
reader: r,
}
}
t.Run("32", func(t *testing.T) {
Expand Down
31 changes: 18 additions & 13 deletions dec_test.go
Expand Up @@ -12,8 +12,8 @@ import (
"github.com/stretchr/testify/require"
)

func runTestCases(t *testing.T, cases []string, cb func(t *testing.T, d *Decoder) error) {
testCase := func(d *Decoder, input string, valid bool) func(t *testing.T) {
func createTestCase(input string, cb func(t *testing.T, d *Decoder) error) func(t *testing.T) {
run := func(d *Decoder, input string, valid bool) func(t *testing.T) {
return func(t *testing.T) {
t.Cleanup(func() {
if t.Failed() {
Expand All @@ -29,21 +29,26 @@ func runTestCases(t *testing.T, cases []string, cb func(t *testing.T, d *Decoder
}
}
}
for i, input := range cases {

return func(t *testing.T) {
valid := json.Valid([]byte(input))

t.Run(fmt.Sprintf("Test%d", i), func(t *testing.T) {
t.Run("Buffer", testCase(DecodeStr(input), input, valid))
t.Run("Buffer", run(DecodeStr(input), input, valid))

r := strings.NewReader(input)
d := Decode(r, 512)
t.Run("Reader", testCase(d, input, valid))
r := strings.NewReader(input)
d := Decode(r, 512)
t.Run("Reader", run(d, input, valid))

r.Reset(input)
obr := iotest.OneByteReader(r)
d.Reset(obr)
t.Run("OneByteReader", testCase(d, input, valid))
})
r.Reset(input)
obr := iotest.OneByteReader(r)
d.Reset(obr)
t.Run("OneByteReader", run(d, input, valid))
}
}

func runTestCases(t *testing.T, cases []string, cb func(t *testing.T, d *Decoder) error) {
for i, input := range cases {
t.Run(fmt.Sprintf("Test%d", i), createTestCase(input, cb))
}
}

Expand Down
6 changes: 3 additions & 3 deletions enc_test.go
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/stretchr/testify/require"
)

func TestEncoder_byte_should_grow_buffer(t *testing.T) {
func TestEncoderByteShouldGrowBuffer(t *testing.T) {
should := require.New(t)
e := GetEncoder()
e.byte('1')
Expand Down Expand Up @@ -41,14 +41,14 @@ func TestEncoder(t *testing.T) {
})
}

func TestEncoder_Raw_should_grow_buffer(t *testing.T) {
func TestEncoderRawShouldGrowBuffer(t *testing.T) {
should := require.New(t)
e := GetEncoder()
e.RawStr("123")
should.Equal("123", string(e.Bytes()))
}

func TestEncoder_Str_should_grow_buffer(t *testing.T) {
func TestEncoderStrShouldGrowBuffer(t *testing.T) {
should := require.New(t)
e := GetEncoder()
e.Str("123")
Expand Down
119 changes: 90 additions & 29 deletions int_test.go
@@ -1,11 +1,11 @@
package jx

import (
"bytes"
"fmt"
"io"
"math"
"strconv"
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -73,26 +73,56 @@ func TestDecoderIntNumbers(t *testing.T) {
}

func TestReadInt32(t *testing.T) {
inputs := []string{`1`, `12`, `123`, `1234`, `12345`, `123456`, `2147483647`, `-2147483648`}
for _, input := range inputs {
t.Run(input, func(t *testing.T) {
inputs := []string{
`-12`,
`-1`,
`0`,
`1`,
`12`,
`123`,
`1234`,
`12345`,
`123456`,
`1234567`,
`12345678`,
`123456789`,
`1234567890`,
`2147483647`,
`-2147483648`,
}
for i, input := range inputs {
input := input
t.Run(fmt.Sprintf("Test%d", i+1), createTestCase(input, func(t *testing.T, d *Decoder) error {
should := require.New(t)
iter := DecodeStr(input)
expected, err := strconv.ParseInt(input, 10, 32)
should.NoError(err)
v, err := iter.Int32()
v, err := d.Int32()
should.NoError(err)
should.Equal(int32(expected), v)
})
t.Run(input, func(t *testing.T) {
return nil
}))
}

{
input := "[" + strings.Join(inputs, ",") + "]"
t.Run("Array", createTestCase(input, func(t *testing.T, d *Decoder) error {
should := require.New(t)
iter := Decode(bytes.NewBufferString(input), 2)
expected, err := strconv.ParseInt(input, 10, 32)
should.NoError(err)
v, err := iter.Int32()
should.NoError(err)
should.Equal(int32(expected), v)
})
i := 0

return d.Arr(func(d *Decoder) error {
expected, err := strconv.ParseInt(inputs[i], 10, 32)
should.NoError(err)

v, err := d.Int32()
if err != nil {
return err
}
should.Equal(int32(expected), v)

i++
return nil
})
}))
}
}

Expand Down Expand Up @@ -175,26 +205,57 @@ func TestReadInt64Overflow(t *testing.T) {
}

func TestReadInt64(t *testing.T) {
inputs := []string{`1`, `12`, `123`, `1234`, `12345`, `123456`, `9223372036854775807`, `-9223372036854775808`}
for _, input := range inputs {
t.Run(input, func(t *testing.T) {
inputs := []string{
`-12`,
`-1`,
`0`,
`1`,
`12`,
`123`,
`1234`,
`12345`,
`123456`,
`1234567`,
`12345678`,
`123456789`,
`1234567890`,
`12345678901`,
`9223372036854775807`,
`-9223372036854775808`,
}
for i, input := range inputs {
input := input
t.Run(fmt.Sprintf("Test%d", i+1), createTestCase(input, func(t *testing.T, d *Decoder) error {
should := require.New(t)
iter := DecodeStr(input)
expected, err := strconv.ParseInt(input, 10, 64)
should.NoError(err)
v, err := iter.Int64()
v, err := d.Int64()
should.NoError(err)
should.Equal(expected, v)
})
t.Run(input, func(t *testing.T) {
return nil
}))
}

{
input := "[" + strings.Join(inputs, ",") + "]"
t.Run("Array", createTestCase(input, func(t *testing.T, d *Decoder) error {
should := require.New(t)
iter := Decode(bytes.NewBufferString(input), 2)
expected, err := strconv.ParseInt(input, 10, 64)
should.NoError(err)
v, err := iter.Int64()
should.NoError(err)
should.Equal(expected, v)
})
i := 0

return d.Arr(func(d *Decoder) error {
expected, err := strconv.ParseInt(inputs[i], 10, 64)
should.NoError(err)

v, err := d.Int64()
if err != nil {
return err
}
should.Equal(expected, v)

i++
return nil
})
}))
}
}

Expand Down

0 comments on commit 27f88a8

Please sign in to comment.