Permalink
Browse files

Add support for uint64 and 64-bit binary notation

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...
1 parent eca94c4 commit 1dd72ac3928693b9db2533639dfc2a5f831697eb @liggitt liggitt committed Oct 29, 2014
Showing with 144 additions and 6 deletions.
  1. +18 −4 decode.go
  2. +108 −0 decode_test.go
  3. +18 −2 resolve.go
View
@@ -4,6 +4,7 @@ import (
"encoding"
"encoding/base64"
"fmt"
+ "math"
"reflect"
"strconv"
"time"
@@ -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
}
@@ -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
}
@@ -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
View
@@ -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",
View
@@ -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.

0 comments on commit 1dd72ac

Please sign in to comment.