Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions big.go
Original file line number Diff line number Diff line change
Expand Up @@ -1406,7 +1406,8 @@ func (x *Big) Scale() int {

// Scan implements fmt.Scanner.
func (z *Big) Scan(state fmt.ScanState, verb rune) error {
return z.scan(byteReader{state})
scanner := byteScanner{r: byteReader{state}}
return z.scan(&scanner)
}

// Set sets z to x and returns z.
Expand Down Expand Up @@ -1665,7 +1666,8 @@ var Regexp = regexp.MustCompile(`(?i)(([+-]?(\d+\.\d*|\.?\d+)([eE][+-]?\d+)?)|(i
// SetString will only return (nil, false) if a library error
// occurs. In general, it safe to ignore the bool result.
func (z *Big) SetString(s string) (*Big, bool) {
if err := z.scan(strings.NewReader(s)); err != nil {
scanner := byteScanner{s: s}
if err := z.scan(&scanner); err != nil {
return nil, false
}
return z, true
Expand Down Expand Up @@ -1766,7 +1768,8 @@ func (z *Big) UnmarshalJSON(data []byte) error {

// UnmarshalText implements encoding.TextUnmarshaler.
func (z *Big) UnmarshalText(data []byte) error {
return z.scan(bytes.NewReader(data))
scanner := byteScanner{b: data}
return z.scan(&scanner)
}

// validate ensures x's internal state is correct. There's no need for it to
Expand Down Expand Up @@ -1815,4 +1818,4 @@ func (x *Big) validate() {
default:
panic(fmt.Sprintf("invalid form %s", x.form))
}
}
}
41 changes: 41 additions & 0 deletions bytes_scanner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package decimal

import "io"

type byteScanner struct {
r io.ByteScanner
s string
b []byte
i int
}

func (s *byteScanner) ReadByte() (byte, error) {
if s.r != nil {
return s.r.ReadByte()
}
if s.b != nil {
if s.i >= len(s.b) {
return 0, io.EOF
}
c := s.b[s.i]
s.i++
return c, nil
}
if s.i >= len(s.s) {
return 0, io.EOF
}
c := s.s[s.i]
s.i++
return c, nil
}

func (s *byteScanner) UnreadByte() error {
if s.r != nil {
return s.r.UnreadByte()
}
if s.i <= 0 {
return io.EOF
}
s.i--
return nil
}
18 changes: 15 additions & 3 deletions format.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,18 @@ func (f *formatter) Write(p []byte) (n int, err error) {

var sciE = [2]byte{GDA: 'E', Go: 'e'}

func (f *formatter) writeZeros(n int) {
const zeros = "0000000000000000000000000000000000000000000000000000000000000000" // 64
for n > 0 {
chunk := n
if chunk > len(zeros) {
chunk = len(zeros)
}
f.WriteString(zeros[:chunk])
n -= chunk
}
}

func (f *formatter) format(x *Big, format format, e byte) {
if x == nil {
f.WriteString("<nil>")
Expand Down Expand Up @@ -186,7 +198,7 @@ func (f *formatter) format(x *Big, format format, e byte) {
f.WriteByte('0')
} else {
f.WriteString("0.")
io.CopyN(f, zeroReader{}, int64(f.width))
f.writeZeros(f.width)
}
return
}
Expand Down Expand Up @@ -237,7 +249,7 @@ func (f *formatter) format(x *Big, format format, e byte) {
// No decimal places, write b and fill with zeros.
if format == plain && exp > 0 {
f.Write(b)
io.CopyN(f, zeroReader{}, int64(exp))
f.writeZeros(exp)
return
}
}
Expand Down Expand Up @@ -282,7 +294,7 @@ func (f *formatter) formatPlain(b []byte, exp int) {
// log10(b) < scale, so before p "0s" and before b: 0.00000123456
default:
f.WriteString(zeroRadix)
io.CopyN(f, zeroReader{}, -int64(radix))
f.writeZeros(-radix)

end := len(b)
if f.prec < end {
Expand Down
14 changes: 7 additions & 7 deletions scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/ericlagergren/decimal/internal/c"
)

func (z *Big) scan(r io.ByteScanner) error {
func (z *Big) scan(r *byteScanner) error {
if debug {
defer func() { z.validate() }()
}
Expand Down Expand Up @@ -97,7 +97,7 @@ func (z *Big) scan(r io.ByteScanner) error {
return nil
}

func scanSign(r io.ByteScanner) (bool, error) {
func scanSign(r *byteScanner) (bool, error) {
ch, err := r.ReadByte()
if err != nil {
return false, err
Expand All @@ -112,7 +112,7 @@ func scanSign(r io.ByteScanner) (bool, error) {
}
}

func (z *Big) scanForm(r io.ByteScanner) (form, error) {
func (z *Big) scanForm(r *byteScanner) (form, error) {
ch, err := r.ReadByte()
if err != nil {
return 0, err
Expand Down Expand Up @@ -186,7 +186,7 @@ func (z *Big) scanForm(r io.ByteScanner) (form, error) {
return qnan, nil
}

func (z *Big) scanInfinity(r io.ByteScanner) (form, error) {
func (z *Big) scanInfinity(r *byteScanner) (form, error) {
const (
s = "infinity"
)
Expand All @@ -208,7 +208,7 @@ func (z *Big) scanInfinity(r io.ByteScanner) (form, error) {
return inf, nil
}

func (z *Big) scanMant(r io.ByteScanner) (err error) {
func (z *Big) scanMant(r *byteScanner) (err error) {
buf := make([]byte, 0, 20)
seenDot := false
dot := 0
Expand Down Expand Up @@ -282,7 +282,7 @@ Loop:
return nil
}

func (z *Big) scanExponent(r io.ByteScanner) error {
func (z *Big) scanExponent(r *byteScanner) error {
ch, err := r.ReadByte()
if err != nil {
if err == io.EOF {
Expand Down Expand Up @@ -375,4 +375,4 @@ func (r byteReader) ReadByte() (byte, error) {

func (r byteReader) UnreadByte() error {
return r.UnreadRune()
}
}