Skip to content

Commit

Permalink
Add support for uint64 and 64-bit binary notation
Browse files Browse the repository at this point in the history
Add decode tests for uint,uint64,int,int64,float32,float64

Unmarshal uint64, use math constants for precision boundaries

Remove uint case, let uint64 cover uint overflows

Handle int64 and uint64 with 0b... notation

Make test cases contain literal values, reference math constants
  • Loading branch information
liggitt committed Oct 29, 2014
1 parent eca94c4 commit 1dd72ac
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 6 deletions.
22 changes: 18 additions & 4 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding"
"encoding/base64"
"fmt"
"math"
"reflect"
"strconv"
"time"
Expand Down Expand Up @@ -389,8 +390,13 @@ func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
out.SetInt(resolved)
good = true
}
case uint64:
if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
out.SetInt(int64(resolved))
good = true
}
case float64:
if resolved < 1<<63-1 && !out.OverflowInt(int64(resolved)) {
if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
out.SetInt(int64(resolved))
good = true
}
Expand All @@ -406,17 +412,22 @@ func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
switch resolved := resolved.(type) {
case int:
if resolved >= 0 {
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
out.SetUint(uint64(resolved))
good = true
}
case int64:
if resolved >= 0 {
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
out.SetUint(uint64(resolved))
good = true
}
case uint64:
if !out.OverflowUint(uint64(resolved)) {
out.SetUint(uint64(resolved))
good = true
}
case float64:
if resolved < 1<<64-1 && !out.OverflowUint(uint64(resolved)) {
if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
out.SetUint(uint64(resolved))
good = true
}
Expand All @@ -435,6 +446,9 @@ func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
case int64:
out.SetFloat(float64(resolved))
good = true
case uint64:
out.SetFloat(float64(resolved))
good = true
case float64:
out.SetFloat(resolved)
good = true
Expand Down
108 changes: 108 additions & 0 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,114 @@ var unmarshalTests = []struct {
map[string]uint64{},
},

// int
{
"int_max: 2147483647", // math.MaxInt32
map[string]int{"int_max": 2147483647},
},
{
"int_min: -2147483648", // math.MinInt32
map[string]int{"int_min": -2147483648},
},
{
"int_overflow: 9223372036854775808", // math.MaxInt64 + 1
map[string]int{},
},

// int64
{
"int64_max: 9223372036854775807", // math.MaxInt64
map[string]int64{"int64_max": 9223372036854775807},
},
{
"int64_max_base2: 0b111111111111111111111111111111111111111111111111111111111111111", // math.MaxInt64
map[string]int64{"int64_max_base2": 9223372036854775807},
},
{
"int64_min: -9223372036854775808", // math.MinInt64
map[string]int64{"int64_min": -9223372036854775808},
},
{
"int64_neg_base2: -0b111111111111111111111111111111111111111111111111111111111111111", // -math.MaxInt64
map[string]int64{"int64_neg_base2": -9223372036854775807},
},
{
"int64_overflow: 9223372036854775808", // math.MaxInt64 + 1
map[string]int64{},
},

// uint
{
"uint_min: 0",
map[string]uint{"uint_min": 0},
},
{
"uint_max: 4294967295", // math.MaxUint32
map[string]uint{"uint_max": 4294967295},
},
{
"uint_underflow: -1",
map[string]uint{},
},

// uint64
{
"uint64_min: 0",
map[string]uint{"uint64_min": 0},
},
{
"uint64_max: 18446744073709551615", // math.MaxUint64
map[string]uint64{"uint64_max": 18446744073709551615},
},
{
"uint64_max_base2: 0b1111111111111111111111111111111111111111111111111111111111111111", // math.MaxUint64
map[string]uint64{"uint64_max_base2": 18446744073709551615},
},
{
"uint64_maxint64: 9223372036854775807", // math.MaxInt64
map[string]uint64{"uint64_maxint64": 9223372036854775807},
},
{
"uint64_underflow: -1",
map[string]uint64{},
},

// float32
{
"float32_max: 3.40282346638528859811704183484516925440e+38", // math.MaxFloat32
map[string]float32{"float32_max": 3.40282346638528859811704183484516925440e+38},
},
{
"float32_nonzero: 1.401298464324817070923729583289916131280e-45", // math.SmallestNonzeroFloat32
map[string]float32{"float32_nonzero": 1.401298464324817070923729583289916131280e-45},
},
{
"float32_maxuint64: 18446744073709551615", // math.MaxUint64
map[string]float32{"float32_maxuint64": 1.8446744e+19},
},
{
"float32_maxuint64+1: 18446744073709551616", // math.MaxUint64 + 1
map[string]float32{"float32_maxuint64+1": 1.8446744e+19},
},

// float64
{
"float64_max: 1.797693134862315708145274237317043567981e+308", // math.MaxFloat64
map[string]float64{"float64_max": 1.797693134862315708145274237317043567981e+308},
},
{
"float64_nonzero: 4.940656458412465441765687928682213723651e-324", // math.SmallestNonzeroFloat64
map[string]float64{"float64_nonzero": 4.940656458412465441765687928682213723651e-324},
},
{
"float64_maxuint64: 18446744073709551615", // math.MaxUint64
map[string]float64{"float64_maxuint64": 1.8446744073709552e+19},
},
{
"float64_maxuint64+1: 18446744073709551616", // math.MaxUint64 + 1
map[string]float64{"float64_maxuint64+1": 1.8446744073709552e+19},
},

// Overflow cases.
{
"v: 4294967297",
Expand Down
20 changes: 18 additions & 2 deletions resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,35 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
return yaml_INT_TAG, intv
}
}
uintv, err := strconv.ParseUint(plain, 0, 64)
if err == nil {
return yaml_INT_TAG, uintv
}
floatv, err := strconv.ParseFloat(plain, 64)
if err == nil {
return yaml_FLOAT_TAG, floatv
}
if strings.HasPrefix(plain, "0b") {
intv, err := strconv.ParseInt(plain[2:], 2, 64)
if err == nil {
return yaml_INT_TAG, int(intv)
if intv == int64(int(intv)) {
return yaml_INT_TAG, int(intv)
} else {
return yaml_INT_TAG, intv
}
}
uintv, err := strconv.ParseUint(plain[2:], 2, 64)
if err == nil {
return yaml_INT_TAG, uintv
}
} else if strings.HasPrefix(plain, "-0b") {
intv, err := strconv.ParseInt(plain[3:], 2, 64)
if err == nil {
return yaml_INT_TAG, -int(intv)
if intv == int64(int(intv)) {
return yaml_INT_TAG, -int(intv)
} else {
return yaml_INT_TAG, -intv
}
}
}
// XXX Handle timestamps here.
Expand Down

0 comments on commit 1dd72ac

Please sign in to comment.