summaryrefslogtreecommitdiff
path: root/vendor/github.com/tdewolff/parse/v2/strconv
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tdewolff/parse/v2/strconv')
-rw-r--r--vendor/github.com/tdewolff/parse/v2/strconv/float.go257
-rw-r--r--vendor/github.com/tdewolff/parse/v2/strconv/int.go108
-rw-r--r--vendor/github.com/tdewolff/parse/v2/strconv/price.go83
3 files changed, 448 insertions, 0 deletions
diff --git a/vendor/github.com/tdewolff/parse/v2/strconv/float.go b/vendor/github.com/tdewolff/parse/v2/strconv/float.go
new file mode 100644
index 000000000..c89bdb29d
--- /dev/null
+++ b/vendor/github.com/tdewolff/parse/v2/strconv/float.go
@@ -0,0 +1,257 @@
+package strconv
+
+import (
+ "math"
+)
+
+var float64pow10 = []float64{
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22,
+}
+
+// ParseFloat parses a byte-slice and returns the float it represents.
+// If an invalid character is encountered, it will stop there.
+func ParseFloat(b []byte) (float64, int) {
+ i := 0
+ neg := false
+ if i < len(b) && (b[i] == '+' || b[i] == '-') {
+ neg = b[i] == '-'
+ i++
+ }
+ start := i
+ dot := -1
+ trunk := -1
+ n := uint64(0)
+ for ; i < len(b); i++ {
+ c := b[i]
+ if c >= '0' && c <= '9' {
+ if trunk == -1 {
+ if n > math.MaxUint64/10 {
+ trunk = i
+ } else {
+ n *= 10
+ n += uint64(c - '0')
+ }
+ }
+ } else if dot == -1 && c == '.' {
+ dot = i
+ } else {
+ break
+ }
+ }
+ if i == start || i == start+1 && dot == start {
+ return 0.0, 0
+ }
+
+ f := float64(n)
+ if neg {
+ f = -f
+ }
+
+ mantExp := int64(0)
+ if dot != -1 {
+ if trunk == -1 {
+ trunk = i
+ }
+ mantExp = int64(trunk - dot - 1)
+ } else if trunk != -1 {
+ mantExp = int64(trunk - i)
+ }
+ expExp := int64(0)
+ if i < len(b) && (b[i] == 'e' || b[i] == 'E') {
+ startExp := i
+ i++
+ if e, expLen := ParseInt(b[i:]); expLen > 0 {
+ expExp = e
+ i += expLen
+ } else {
+ i = startExp
+ }
+ }
+ exp := expExp - mantExp
+
+ // copied from strconv/atof.go
+ if exp == 0 {
+ return f, i
+ } else if exp > 0 && exp <= 15+22 { // int * 10^k
+ // If exponent is big but number of digits is not,
+ // can move a few zeros into the integer part.
+ if exp > 22 {
+ f *= float64pow10[exp-22]
+ exp = 22
+ }
+ if f <= 1e15 && f >= -1e15 {
+ return f * float64pow10[exp], i
+ }
+ } else if exp < 0 && exp >= -22 { // int / 10^k
+ return f / float64pow10[-exp], i
+ }
+ f *= math.Pow10(int(-mantExp))
+ return f * math.Pow10(int(expExp)), i
+}
+
+const log2 = 0.3010299956639812
+
+func float64exp(f float64) int {
+ exp2 := 0
+ if f != 0.0 {
+ x := math.Float64bits(f)
+ exp2 = int(x>>(64-11-1))&0x7FF - 1023 + 1
+ }
+
+ exp10 := float64(exp2) * log2
+ if exp10 < 0 {
+ exp10 -= 1.0
+ }
+ return int(exp10)
+}
+
+// AppendFloat appends a float to `b` with precision `prec`. It returns the new slice and whether successful or not. Precision is the number of decimals to display, thus prec + 1 == number of significant digits.
+func AppendFloat(b []byte, f float64, prec int) ([]byte, bool) {
+ if math.IsNaN(f) || math.IsInf(f, 0) {
+ return b, false
+ }
+
+ neg := false
+ if f < 0.0 {
+ f = -f
+ neg = true
+ }
+ if prec < 0 || 17 < prec {
+ prec = 17 // maximum number of significant digits in double
+ }
+ prec -= float64exp(f) // number of digits in front of the dot
+ f *= math.Pow10(prec)
+
+ // calculate mantissa and exponent
+ mant := int64(f)
+ mantLen := LenInt(mant)
+ mantExp := mantLen - prec - 1
+ if mant == 0 {
+ return append(b, '0'), true
+ }
+
+ // expLen is zero for positive exponents, because positive exponents are determined later on in the big conversion loop
+ exp := 0
+ expLen := 0
+ if mantExp > 0 {
+ // positive exponent is determined in the loop below
+ // but if we initially decreased the exponent to fit in an integer, we can't set the new exponent in the loop alone,
+ // since the number of zeros at the end determines the positive exponent in the loop, and we just artificially lost zeros
+ if prec < 0 {
+ exp = mantExp
+ }
+ expLen = 1 + LenInt(int64(exp)) // e + digits
+ } else if mantExp < -3 {
+ exp = mantExp
+ expLen = 2 + LenInt(int64(exp)) // e + minus + digits
+ } else if mantExp < -1 {
+ mantLen += -mantExp - 1 // extra zero between dot and first digit
+ }
+
+ // reserve space in b
+ i := len(b)
+ maxLen := 1 + mantLen + expLen // dot + mantissa digits + exponent
+ if neg {
+ maxLen++
+ }
+ if i+maxLen > cap(b) {
+ b = append(b, make([]byte, maxLen)...)
+ } else {
+ b = b[:i+maxLen]
+ }
+
+ // write to string representation
+ if neg {
+ b[i] = '-'
+ i++
+ }
+
+ // big conversion loop, start at the end and move to the front
+ // initially print trailing zeros and remove them later on
+ // for example if the first non-zero digit is three positions in front of the dot, it will overwrite the zeros with a positive exponent
+ zero := true
+ last := i + mantLen // right-most position of digit that is non-zero + dot
+ dot := last - prec - exp // position of dot
+ j := last
+ for mant > 0 {
+ if j == dot {
+ b[j] = '.'
+ j--
+ }
+ newMant := mant / 10
+ digit := mant - 10*newMant
+ if zero && digit > 0 {
+ // first non-zero digit, if we are still behind the dot we can trim the end to this position
+ // otherwise trim to the dot (including the dot)
+ if j > dot {
+ i = j + 1
+ // decrease negative exponent further to get rid of dot
+ if exp < 0 {
+ newExp := exp - (j - dot)
+ // getting rid of the dot shouldn't lower the exponent to more digits (e.g. -9 -> -10)
+ if LenInt(int64(newExp)) == LenInt(int64(exp)) {
+ exp = newExp
+ dot = j
+ j--
+ i--
+ }
+ }
+ } else {
+ i = dot
+ }
+ last = j
+ zero = false
+ }
+ b[j] = '0' + byte(digit)
+ j--
+ mant = newMant
+ }
+
+ if j > dot {
+ // extra zeros behind the dot
+ for j > dot {
+ b[j] = '0'
+ j--
+ }
+ b[j] = '.'
+ } else if last+3 < dot {
+ // add positive exponent because we have 3 or more zeros in front of the dot
+ i = last + 1
+ exp = dot - last - 1
+ } else if j == dot {
+ // handle 0.1
+ b[j] = '.'
+ }
+
+ // exponent
+ if exp != 0 {
+ if exp == 1 {
+ b[i] = '0'
+ i++
+ } else if exp == 2 {
+ b[i] = '0'
+ b[i+1] = '0'
+ i += 2
+ } else {
+ b[i] = 'e'
+ i++
+ if exp < 0 {
+ b[i] = '-'
+ i++
+ exp = -exp
+ }
+ i += LenInt(int64(exp))
+ j := i
+ for exp > 0 {
+ newExp := exp / 10
+ digit := exp - 10*newExp
+ j--
+ b[j] = '0' + byte(digit)
+ exp = newExp
+ }
+ }
+ }
+ return b[:i], true
+}
diff --git a/vendor/github.com/tdewolff/parse/v2/strconv/int.go b/vendor/github.com/tdewolff/parse/v2/strconv/int.go
new file mode 100644
index 000000000..e3483bd3a
--- /dev/null
+++ b/vendor/github.com/tdewolff/parse/v2/strconv/int.go
@@ -0,0 +1,108 @@
+package strconv
+
+import (
+ "math"
+)
+
+// ParseInt parses a byte-slice and returns the integer it represents.
+// If an invalid character is encountered, it will stop there.
+func ParseInt(b []byte) (int64, int) {
+ i := 0
+ neg := false
+ if len(b) > 0 && (b[0] == '+' || b[0] == '-') {
+ neg = b[0] == '-'
+ i++
+ }
+ start := i
+ n := uint64(0)
+ for i < len(b) {
+ c := b[i]
+ if n > math.MaxUint64/10 {
+ return 0, 0
+ } else if c >= '0' && c <= '9' {
+ n *= 10
+ n += uint64(c - '0')
+ } else {
+ break
+ }
+ i++
+ }
+ if i == start {
+ return 0, 0
+ }
+ if !neg && n > uint64(math.MaxInt64) || n > uint64(math.MaxInt64)+1 {
+ return 0, 0
+ } else if neg {
+ return -int64(n), i
+ }
+ return int64(n), i
+}
+
+// ParseUint parses a byte-slice and returns the integer it represents.
+// If an invalid character is encountered, it will stop there.
+func ParseUint(b []byte) (uint64, int) {
+ i := 0
+ n := uint64(0)
+ for i < len(b) {
+ c := b[i]
+ if n > math.MaxUint64/10 {
+ return 0, 0
+ } else if c >= '0' && c <= '9' {
+ n *= 10
+ n += uint64(c - '0')
+ } else {
+ break
+ }
+ i++
+ }
+ return n, i
+}
+
+// LenInt returns the written length of an integer.
+func LenInt(i int64) int {
+ if i < 0 {
+ if i == -9223372036854775808 {
+ return 19
+ }
+ i = -i
+ }
+ switch {
+ case i < 10:
+ return 1
+ case i < 100:
+ return 2
+ case i < 1000:
+ return 3
+ case i < 10000:
+ return 4
+ case i < 100000:
+ return 5
+ case i < 1000000:
+ return 6
+ case i < 10000000:
+ return 7
+ case i < 100000000:
+ return 8
+ case i < 1000000000:
+ return 9
+ case i < 10000000000:
+ return 10
+ case i < 100000000000:
+ return 11
+ case i < 1000000000000:
+ return 12
+ case i < 10000000000000:
+ return 13
+ case i < 100000000000000:
+ return 14
+ case i < 1000000000000000:
+ return 15
+ case i < 10000000000000000:
+ return 16
+ case i < 100000000000000000:
+ return 17
+ case i < 1000000000000000000:
+ return 18
+ }
+ return 19
+}
diff --git a/vendor/github.com/tdewolff/parse/v2/strconv/price.go b/vendor/github.com/tdewolff/parse/v2/strconv/price.go
new file mode 100644
index 000000000..94b38343e
--- /dev/null
+++ b/vendor/github.com/tdewolff/parse/v2/strconv/price.go
@@ -0,0 +1,83 @@
+package strconv
+
+// AppendPrice will append an int64 formatted as a price, where the int64 is the price in cents.
+// It does not display whether a price is negative or not.
+func AppendPrice(b []byte, price int64, dec bool, milSeparator byte, decSeparator byte) []byte {
+ if price < 0 {
+ if price == -9223372036854775808 {
+ x := []byte("92 233 720 368 547 758 08")
+ x[2] = milSeparator
+ x[6] = milSeparator
+ x[10] = milSeparator
+ x[14] = milSeparator
+ x[18] = milSeparator
+ x[22] = decSeparator
+ return append(b, x...)
+ }
+ price = -price
+ }
+
+ // rounding
+ if !dec {
+ firstDec := (price / 10) % 10
+ if firstDec >= 5 {
+ price += 100
+ }
+ }
+
+ // calculate size
+ n := LenInt(price) - 2
+ if n > 0 {
+ n += (n - 1) / 3 // mil separator
+ } else {
+ n = 1
+ }
+ if dec {
+ n += 2 + 1 // decimals + dec separator
+ }
+
+ // resize byte slice
+ i := len(b)
+ if i+n > cap(b) {
+ b = append(b, make([]byte, n)...)
+ } else {
+ b = b[:i+n]
+ }
+
+ // print fractional-part
+ i += n - 1
+ if dec {
+ for j := 0; j < 2; j++ {
+ c := byte(price%10) + '0'
+ price /= 10
+ b[i] = c
+ i--
+ }
+ b[i] = decSeparator
+ i--
+ } else {
+ price /= 100
+ }
+
+ if price == 0 {
+ b[i] = '0'
+ return b
+ }
+
+ // print integer-part
+ j := 0
+ for price > 0 {
+ if j == 3 {
+ b[i] = milSeparator
+ i--
+ j = 0
+ }
+
+ c := byte(price%10) + '0'
+ price /= 10
+ b[i] = c
+ i--
+ j++
+ }
+ return b
+}