Skip to content

Commit

Permalink
feat: improve decoding layout, reduce bound checks
Browse files Browse the repository at this point in the history
name                                old time/op    new time/op    delta
Decoder_Float64/floats.json-4         3.17µs ± 4%    2.96µs ± 1%   -6.66%  (p=0.000 n=23+25)
Decoder_Float64/slow_floats.json-4    21.2µs ± 2%    20.8µs ± 2%   -1.93%  (p=0.000 n=23+25)
Decoder_Float64/integers.json-4       4.32µs ± 2%    3.85µs ± 4%  -10.92%  (p=0.000 n=24+25)
  • Loading branch information
tdakkota committed Mar 18, 2022
1 parent fbc62c5 commit 9f27e28
Showing 1 changed file with 26 additions and 24 deletions.
50 changes: 26 additions & 24 deletions dec_float.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ import (
"github.com/go-faster/errors"
)

var pow10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000}

var floatDigits []int8
var (
pow10 = [...]uint64{1, 10, 100, 1000, 10000, 100000, 1000000}
floatDigits = [256]int8{}
)

const invalidCharForNumber = int8(-1)
const endOfNumber = int8(-2)
const dotInNumber = int8(-3)
const maxFloat64 = 1<<63 - 1
const (
invalidCharForNumber = int8(-1)
endOfNumber = int8(-2)
dotInNumber = int8(-3)
maxFloat64 = 1<<63 - 1
)

func init() {
floatDigits = make([]int8, 256)
for i := 0; i < len(floatDigits); i++ {
floatDigits[i] = invalidCharForNumber
}
Expand Down Expand Up @@ -88,25 +90,24 @@ func (d *Decoder) positiveFloat32() (float32, error) {
i := d.head
// First char.
if i == d.tail {
return d.f32Slow()
return d.float32Slow()
}
c := d.buf[i]
i++
ind := floatDigits[c]
switch ind {
case invalidCharForNumber:
return d.f32Slow()
return d.float32Slow()
case endOfNumber:
return 0, errors.New("empty")
case dotInNumber:
return 0, errors.New("leading dot")
case 0:
if i == d.tail {
return d.f32Slow()
return d.float32Slow()
}
c = d.buf[i]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
if floatDigits[c] >= 0 {
return 0, errors.New("leading zero")
}
}
Expand All @@ -118,15 +119,15 @@ NonDecimalLoop:
ind := floatDigits[c]
switch ind {
case invalidCharForNumber:
return d.f32Slow()
return d.float32Slow()
case endOfNumber:
d.head = i
return float32(value), nil
case dotInNumber:
break NonDecimalLoop
}
if value > uint64SafeToMultiple10 {
return d.f32Slow()
return d.float32Slow()
}
value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind;
}
Expand All @@ -135,7 +136,7 @@ NonDecimalLoop:
i++
decimalPlaces := 0
if i == d.tail {
return d.f32Slow()
return d.float32Slow()
}
for ; i < d.tail; i++ {
c = d.buf[i]
Expand All @@ -147,18 +148,18 @@ NonDecimalLoop:
return float32(float64(value) / float64(pow10[decimalPlaces])), nil
}
// too many decimal places
return d.f32Slow()
return d.float32Slow()
case invalidCharForNumber, dotInNumber:
return d.f32Slow()
return d.float32Slow()
}
decimalPlaces++
if value > uint64SafeToMultiple10 {
return d.f32Slow()
return d.float32Slow()
}
value = (value << 3) + (value << 1) + uint64(ind)
}
}
return d.f32Slow()
return d.float32Slow()
}

var numberSet = [256]byte{
Expand Down Expand Up @@ -214,7 +215,7 @@ const (
size64 = 64
)

func (d *Decoder) f32Slow() (float32, error) {
func (d *Decoder) float32Slow() (float32, error) {
v, err := d.floatSlow(size32)
if err != nil {
return 0, err
Expand All @@ -228,16 +229,17 @@ func (d *Decoder) Float64() (float64, error) {
if err != nil {
return 0, errors.Wrap(err, "byte")
}
if floatDigits[c] >= 0 {
d.unread()
return d.positiveFloat64()
}
switch c {
case '-':
v, err := d.positiveFloat64()
if err != nil {
return 0, err
}
return -v, err
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
d.unread()
return d.positiveFloat64()
default:
return 0, badToken(c)
}
Expand Down

0 comments on commit 9f27e28

Please sign in to comment.