Browse Source

codec: clean up float handling code

Also, remove unnecessary padding from simple.go
Ugorji Nwoke 6 years ago
parent
commit
6edad4e9b6
2 changed files with 102 additions and 74 deletions
  1. 101 73
      codec/float.go
  2. 1 1
      codec/simple.go

+ 101 - 73
codec/float.go

@@ -91,6 +91,8 @@ var fi64 = floatinfo{52, 11, -1023, 22, 15, 19} // maxMantDigits = 19
 const fMax64 = 1e15
 const fMax64 = 1e15
 const fMax32 = 1e7
 const fMax32 = 1e7
 
 
+const fBase = 10
+
 func parseFloatErr(b []byte) error {
 func parseFloatErr(b []byte) error {
 	return &strconv.NumError{
 	return &strconv.NumError{
 		Func: "ParseFloat",
 		Func: "ParseFloat",
@@ -100,7 +102,7 @@ func parseFloatErr(b []byte) error {
 }
 }
 
 
 func parseFloat32_custom(b []byte) (f float32, err error) {
 func parseFloat32_custom(b []byte) (f float32, err error) {
-	mantissa, exp, i16, neg, _, bad, ok := readFloat(b, fi32)
+	mantissa, exp, neg, _, bad, ok := readFloat(b, fi32)
 	if bad {
 	if bad {
 		return 0, parseFloatErr(b)
 		return 0, parseFloatErr(b)
 	}
 	}
@@ -110,19 +112,20 @@ func parseFloat32_custom(b []byte) (f float32, err error) {
 		if neg {
 		if neg {
 			f = -f
 			f = -f
 		}
 		}
-		if exp == 0 {
-		} else if exp < 0 { // int / 10^k
-			f /= float32pow10[-exp]
-		} else { // exp > 0
-			i16 = int16(fi32.exactPow10)
-			if exp > i16 {
-				f *= float32pow10[exp-i16]
-				exp = i16
-			}
-			if f < -fMax32 || f > fMax32 { // exponent may be too large - outside range
-				goto FALLBACK
+		if exp != 0 {
+			indx := fExpIndx(exp)
+			if exp < 0 { // int / 10^k
+				f /= float32pow10[indx]
+			} else { // exp > 0
+				if exp > fi32.exactPow10 {
+					f *= float32pow10[exp-fi32.exactPow10]
+					if f < -fMax32 || f > fMax32 { // exponent too large - outside range
+						goto FALLBACK
+					}
+					indx = uint8(fi32.exactPow10)
+				}
+				f *= float32pow10[indx]
 			}
 			}
-			f *= float32pow10[exp]
 		}
 		}
 		return
 		return
 	}
 	}
@@ -131,29 +134,29 @@ FALLBACK:
 }
 }
 
 
 func parseFloat64_custom(b []byte) (f float64, err error) {
 func parseFloat64_custom(b []byte) (f float64, err error) {
-	mantissa, exp, i16, neg, _, bad, ok := readFloat(b, fi64)
+	mantissa, exp, neg, _, bad, ok := readFloat(b, fi64)
 	if bad {
 	if bad {
 		return 0, parseFloatErr(b)
 		return 0, parseFloatErr(b)
 	}
 	}
-	// defer parseFloatDebug(b, 64, &trunc, exp, trunc, ok)
 	if ok {
 	if ok {
 		f = float64(mantissa)
 		f = float64(mantissa)
 		if neg {
 		if neg {
 			f = -f
 			f = -f
 		}
 		}
-		if exp == 0 {
-		} else if exp < 0 { // int / 10^k
-			f /= float64pow10[-exp]
-		} else { // exp > 0
-			i16 = int16(fi64.exactPow10)
-			if exp > i16 {
-				f *= float64pow10[exp-i16]
-				exp = i16
-			}
-			if f < -fMax64 || f > fMax64 { // exponent may be too large - outside range
-				goto FALLBACK
+		if exp != 0 {
+			indx := fExpIndx(exp)
+			if exp < 0 { // int / 10^k
+				f /= float64pow10[indx]
+			} else { // exp > 0
+				if exp > fi64.exactPow10 {
+					f *= float64pow10[exp-fi64.exactPow10]
+					if f < -fMax64 || f > fMax64 { // exponent too large - outside range
+						goto FALLBACK
+					}
+					indx = uint8(fi64.exactPow10)
+				}
+				f *= float64pow10[indx]
 			}
 			}
-			f *= float64pow10[exp]
 		}
 		}
 		return
 		return
 	}
 	}
@@ -161,9 +164,17 @@ FALLBACK:
 	return parseFloat64_strconv(b)
 	return parseFloat64_strconv(b)
 }
 }
 
 
-func readFloat(s []byte, y floatinfo) (mantissa uint64, exp, i16 int16, neg, trunc, bad, ok bool) {
-	var i int
-	if len(s) == 0 {
+func fExpIndx(v int8) uint8 {
+	if v < 0 {
+		return uint8(-v)
+	}
+	return uint8(v)
+}
+
+func readFloat(s []byte, y floatinfo) (mantissa uint64, exp int8, neg, trunc, bad, ok bool) {
+	var i uint // make it uint, so that we eliminate bounds checking
+	var slen = uint(len(s))
+	if slen == 0 {
 		bad = true
 		bad = true
 		return
 		return
 	}
 	}
@@ -178,13 +189,11 @@ func readFloat(s []byte, y floatinfo) (mantissa uint64, exp, i16 int16, neg, tru
 	// we considered punting early if string has length > maxMantDigits, but this doesn't account
 	// we considered punting early if string has length > maxMantDigits, but this doesn't account
 	// for trailing 0's e.g. 700000000000000000000 can be encoded exactly as it is 7e20
 	// for trailing 0's e.g. 700000000000000000000 can be encoded exactly as it is 7e20
 
 
-	const base = 10
-
 	// var sawdot, sawdigits, sawexp bool
 	// var sawdot, sawdigits, sawexp bool
-	var sawdot bool
+	var sawdot, sawexp bool
 	var nd, ndMant, dp int8
 	var nd, ndMant, dp int8
 L:
 L:
-	for ; i < len(s); i++ {
+	for ; i < slen; i++ {
 		switch s[i] {
 		switch s[i] {
 		case '.':
 		case '.':
 			if sawdot {
 			if sawdot {
@@ -200,26 +209,42 @@ L:
 			}
 			}
 			nd++
 			nd++
 			if ndMant < y.maxMantDigits {
 			if ndMant < y.maxMantDigits {
-				mantissa *= base
+				// mantissa = (mantissa << 1) + (mantissa << 3)
+				mantissa *= fBase
 				ndMant++
 				ndMant++
 			}
 			}
 		case '1', '2', '3', '4', '5', '6', '7', '8', '9':
 		case '1', '2', '3', '4', '5', '6', '7', '8', '9':
 			// sawdigits = true
 			// sawdigits = true
 			nd++
 			nd++
 			if ndMant < y.maxMantDigits {
 			if ndMant < y.maxMantDigits {
-				mantissa *= base
-				mantissa += uint64(s[i] - '0')
+				// mantissa = (mantissa << 1) + (mantissa << 3) + uint64(s[i]-'0')
+				mantissa = mantissa*fBase + uint64(s[i]-'0')
+				// mantissa *= fBase
+				// mantissa += uint64(s[i] - '0')
 				ndMant++
 				ndMant++
 			} else {
 			} else {
 				trunc = true
 				trunc = true
 				return // break L
 				return // break L
 			}
 			}
 		case 'e', 'E':
 		case 'e', 'E':
-			// sawexp = true
-			i++
-			if i == len(s) {
-				break L
-			}
+			sawexp = true
+			break L
+		default:
+			bad = true
+			return
+		}
+	}
+	// if !sawdigits {
+	// 	bad = true
+	// 	return
+	// }
+	if !sawdot {
+		dp = nd
+	}
+
+	if sawexp {
+		i++
+		if i < slen {
 			var eneg bool
 			var eneg bool
 			if s[i] == '+' {
 			if s[i] == '+' {
 				i++
 				i++
@@ -227,52 +252,55 @@ L:
 				i++
 				i++
 				eneg = true
 				eneg = true
 			}
 			}
-			if i == len(s) {
-				break L
-			}
-			// for exact match, exponent is in single or double digits (-22 to 37 for float64).
-			// exit quick if exponent is more than 2 digits.
-			if len(s)-i > 2 {
-				return
-			}
-			var e int8
-			for ; i < len(s); i++ {
+			if i < slen {
+				// for exact match, exponent is 1 or 2 digits (float64: -22 to 37, float32: -1 to 17).
+				// exit quick if exponent is more than 2 digits.
+				if i+2 < slen {
+					return
+				}
+
+				var e int8
+
 				if s[i] < '0' || s[i] > '9' {
 				if s[i] < '0' || s[i] > '9' {
 					bad = true
 					bad = true
 					return
 					return
 				}
 				}
-				e = e*base + int8(s[i]-'0')
-			}
-			if eneg {
-				dp -= e
-			} else {
-				dp += e
+				e = e*fBase + int8(s[i]-'0') // (e << 1) + (e << 3) + int8(s[i]-'0')
+				i++
+
+				if i < slen {
+					if s[i] < '0' || s[i] > '9' {
+						bad = true
+						return
+					}
+					e = e*fBase + int8(s[i]-'0') // (e << 1) + (e << 3) + int8(s[i]-'0')
+					i++
+				}
+
+				if eneg {
+					dp -= e
+				} else {
+					dp += e
+				}
 			}
 			}
-			break L
-		default:
-			bad = true
-			return
 		}
 		}
 	}
 	}
-	// if !sawdigits {
-	// 	bad = true
-	// 	return
-	// }
-	if !sawdot {
-		dp = nd
-	}
 
 
 	if mantissa != 0 {
 	if mantissa != 0 {
-		nd = dp - ndMant
-		if nd < -y.exactPow10 || nd > y.exactInts+y.exactPow10 { // cannot handle it
+		if mantissa>>y.mantbits != 0 {
+			return
+		}
+		exp = dp - ndMant
+		if exp < -y.exactPow10 || exp > y.exactInts+y.exactPow10 { // cannot handle it
 			return
 			return
 		}
 		}
-		exp = int16(nd)
 	}
 	}
-	ok = true && !trunc && mantissa>>y.mantbits == 0
+	ok = true // && !trunc // if trunc=true, we return early (so here trunc=false)
 	return
 	return
 }
 }
 
 
+// fMul10ShiftU64
+
 // func parseFloatDebug(b []byte, bitsize int, strconv *bool, exp int16, trunc, ok bool) {
 // func parseFloatDebug(b []byte, bitsize int, strconv *bool, exp int16, trunc, ok bool) {
 // 	if false && bitsize == 64 {
 // 	if false && bitsize == 64 {
 // 		return
 // 		return

+ 1 - 1
codec/simple.go

@@ -41,7 +41,7 @@ type simpleEncDriver struct {
 	b [8]byte
 	b [8]byte
 	// c containerState
 	// c containerState
 	// encDriverTrackContainerWriter
 	// encDriverTrackContainerWriter
-	_ [2]uint64 // padding (cache-aligned)
+	// _ [2]uint64 // padding (cache-aligned)
 }
 }
 
 
 func (e *simpleEncDriver) EncodeNil() {
 func (e *simpleEncDriver) EncodeNil() {