mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-29 19:52:24 -05:00 
			
		
		
		
	* update all but bun libraries Signed-off-by: kim <grufwub@gmail.com> * remove my personal build script changes Signed-off-by: kim <grufwub@gmail.com>
		
			
				
	
	
		
			499 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			499 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
 | |
| // Use of this source code is governed by a MIT license found in the LICENSE file.
 | |
| 
 | |
| package codec
 | |
| 
 | |
| import (
 | |
| 	"math"
 | |
| 	"strconv"
 | |
| )
 | |
| 
 | |
| // Per go spec, floats are represented in memory as
 | |
| // IEEE single or double precision floating point values.
 | |
| //
 | |
| // We also looked at the source for stdlib math/modf.go,
 | |
| // reviewed https://github.com/chewxy/math32
 | |
| // and read wikipedia documents describing the formats.
 | |
| //
 | |
| // It became clear that we could easily look at the bits to determine
 | |
| // whether any fraction exists.
 | |
| 
 | |
| func parseFloat32(b []byte) (f float32, err error) {
 | |
| 	return parseFloat32_custom(b)
 | |
| }
 | |
| 
 | |
| func parseFloat64(b []byte) (f float64, err error) {
 | |
| 	return parseFloat64_custom(b)
 | |
| }
 | |
| 
 | |
| func parseFloat32_strconv(b []byte) (f float32, err error) {
 | |
| 	f64, err := strconv.ParseFloat(stringView(b), 32)
 | |
| 	f = float32(f64)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func parseFloat64_strconv(b []byte) (f float64, err error) {
 | |
| 	return strconv.ParseFloat(stringView(b), 64)
 | |
| }
 | |
| 
 | |
| // ------ parseFloat custom below --------
 | |
| 
 | |
| // JSON really supports decimal numbers in base 10 notation, with exponent support.
 | |
| //
 | |
| // We assume the following:
 | |
| //   - a lot of floating point numbers in json files will have defined precision
 | |
| //     (in terms of number of digits after decimal point), etc.
 | |
| //   - these (referenced above) can be written in exact format.
 | |
| //
 | |
| // strconv.ParseFloat has some unnecessary overhead which we can do without
 | |
| // for the common case:
 | |
| //
 | |
| //    - expensive char-by-char check to see if underscores are in right place
 | |
| //    - testing for and skipping underscores
 | |
| //    - check if the string matches ignorecase +/- inf, +/- infinity, nan
 | |
| //    - support for base 16 (0xFFFF...)
 | |
| //
 | |
| // The functions below will try a fast-path for floats which can be decoded
 | |
| // without any loss of precision, meaning they:
 | |
| //
 | |
| //    - fits within the significand bits of the 32-bits or 64-bits
 | |
| //    - exponent fits within the exponent value
 | |
| //    - there is no truncation (any extra numbers are all trailing zeros)
 | |
| //
 | |
| // To figure out what the values are for maxMantDigits, use this idea below:
 | |
| //
 | |
| // 2^23 =                 838 8608 (between 10^ 6 and 10^ 7) (significand bits of uint32)
 | |
| // 2^32 =             42 9496 7296 (between 10^ 9 and 10^10) (full uint32)
 | |
| // 2^52 =      4503 5996 2737 0496 (between 10^15 and 10^16) (significand bits of uint64)
 | |
| // 2^64 = 1844 6744 0737 0955 1616 (between 10^19 and 10^20) (full uint64)
 | |
| //
 | |
| // Note: we only allow for up to what can comfortably fit into the significand
 | |
| // ignoring the exponent, and we only try to parse iff significand fits.
 | |
| 
 | |
| const (
 | |
| 	fMaxMultiplierForExactPow10_64 = 1e15
 | |
| 	fMaxMultiplierForExactPow10_32 = 1e7
 | |
| 
 | |
| 	fUint64Cutoff = (1<<64-1)/10 + 1
 | |
| 	// fUint32Cutoff = (1<<32-1)/10 + 1
 | |
| 
 | |
| 	fBase = 10
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	thousand    = 1000
 | |
| 	million     = thousand * thousand
 | |
| 	billion     = thousand * million
 | |
| 	trillion    = thousand * billion
 | |
| 	quadrillion = thousand * trillion
 | |
| 	quintillion = thousand * quadrillion
 | |
| )
 | |
| 
 | |
| // Exact powers of 10.
 | |
| var uint64pow10 = [...]uint64{
 | |
| 	1, 10, 100,
 | |
| 	1 * thousand, 10 * thousand, 100 * thousand,
 | |
| 	1 * million, 10 * million, 100 * million,
 | |
| 	1 * billion, 10 * billion, 100 * billion,
 | |
| 	1 * trillion, 10 * trillion, 100 * trillion,
 | |
| 	1 * quadrillion, 10 * quadrillion, 100 * quadrillion,
 | |
| 	1 * quintillion, 10 * quintillion,
 | |
| }
 | |
| 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,
 | |
| }
 | |
| var float32pow10 = [...]float32{
 | |
| 	1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10,
 | |
| }
 | |
| 
 | |
| type floatinfo struct {
 | |
| 	mantbits uint8
 | |
| 
 | |
| 	// expbits uint8 // (unused)
 | |
| 	// bias    int16 // (unused)
 | |
| 	// is32bit bool // (unused)
 | |
| 
 | |
| 	exactPow10 int8 // Exact powers of ten are <= 10^N (32: 10, 64: 22)
 | |
| 
 | |
| 	exactInts int8 // Exact integers are <= 10^N (for non-float, set to 0)
 | |
| 
 | |
| 	// maxMantDigits int8 // 10^19 fits in uint64, while 10^9 fits in uint32
 | |
| 
 | |
| 	mantCutoffIsUint64Cutoff bool
 | |
| 
 | |
| 	mantCutoff uint64
 | |
| }
 | |
| 
 | |
| var fi32 = floatinfo{23, 10, 7, false, 1<<23 - 1}
 | |
| var fi64 = floatinfo{52, 22, 15, false, 1<<52 - 1}
 | |
| 
 | |
| var fi64u = floatinfo{0, 19, 0, true, fUint64Cutoff}
 | |
| 
 | |
| func noFrac64(fbits uint64) bool {
 | |
| 	if fbits == 0 {
 | |
| 		return true
 | |
| 	}
 | |
| 
 | |
| 	exp := uint64(fbits>>52)&0x7FF - 1023 // uint(x>>shift)&mask - bias
 | |
| 	// clear top 12+e bits, the integer part; if the rest is 0, then no fraction.
 | |
| 	return exp < 52 && fbits<<(12+exp) == 0 // means there's no fractional part
 | |
| }
 | |
| 
 | |
| func noFrac32(fbits uint32) bool {
 | |
| 	if fbits == 0 {
 | |
| 		return true
 | |
| 	}
 | |
| 
 | |
| 	exp := uint32(fbits>>23)&0xFF - 127 // uint(x>>shift)&mask - bias
 | |
| 	// clear top 9+e bits, the integer part; if the rest is 0, then no fraction.
 | |
| 	return exp < 23 && fbits<<(9+exp) == 0 // means there's no fractional part
 | |
| }
 | |
| 
 | |
| func strconvParseErr(b []byte, fn string) error {
 | |
| 	return &strconv.NumError{
 | |
| 		Func: fn,
 | |
| 		Err:  strconv.ErrSyntax,
 | |
| 		Num:  string(b),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func parseFloat32_reader(r readFloatResult) (f float32, fail bool) {
 | |
| 	f = float32(r.mantissa)
 | |
| 	if r.exp == 0 {
 | |
| 	} else if r.exp < 0 { // int / 10^k
 | |
| 		f /= float32pow10[uint8(-r.exp)]
 | |
| 	} else { // exp > 0
 | |
| 		if r.exp > fi32.exactPow10 {
 | |
| 			f *= float32pow10[r.exp-fi32.exactPow10]
 | |
| 			if f > fMaxMultiplierForExactPow10_32 { // exponent too large - outside range
 | |
| 				fail = true
 | |
| 				return // ok = false
 | |
| 			}
 | |
| 			f *= float32pow10[fi32.exactPow10]
 | |
| 		} else {
 | |
| 			f *= float32pow10[uint8(r.exp)]
 | |
| 		}
 | |
| 	}
 | |
| 	if r.neg {
 | |
| 		f = -f
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func parseFloat32_custom(b []byte) (f float32, err error) {
 | |
| 	r := readFloat(b, fi32)
 | |
| 	if r.bad {
 | |
| 		return 0, strconvParseErr(b, "ParseFloat")
 | |
| 	}
 | |
| 	if r.ok {
 | |
| 		f, r.bad = parseFloat32_reader(r)
 | |
| 		if !r.bad {
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	return parseFloat32_strconv(b)
 | |
| }
 | |
| 
 | |
| func parseFloat64_reader(r readFloatResult) (f float64, fail bool) {
 | |
| 	f = float64(r.mantissa)
 | |
| 	if r.exp == 0 {
 | |
| 	} else if r.exp < 0 { // int / 10^k
 | |
| 		f /= float64pow10[-uint8(r.exp)]
 | |
| 	} else { // exp > 0
 | |
| 		if r.exp > fi64.exactPow10 {
 | |
| 			f *= float64pow10[r.exp-fi64.exactPow10]
 | |
| 			if f > fMaxMultiplierForExactPow10_64 { // exponent too large - outside range
 | |
| 				fail = true
 | |
| 				return
 | |
| 			}
 | |
| 			f *= float64pow10[fi64.exactPow10]
 | |
| 		} else {
 | |
| 			f *= float64pow10[uint8(r.exp)]
 | |
| 		}
 | |
| 	}
 | |
| 	if r.neg {
 | |
| 		f = -f
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func parseFloat64_custom(b []byte) (f float64, err error) {
 | |
| 	r := readFloat(b, fi64)
 | |
| 	if r.bad {
 | |
| 		return 0, strconvParseErr(b, "ParseFloat")
 | |
| 	}
 | |
| 	if r.ok {
 | |
| 		f, r.bad = parseFloat64_reader(r)
 | |
| 		if !r.bad {
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	return parseFloat64_strconv(b)
 | |
| }
 | |
| 
 | |
| func parseUint64_simple(b []byte) (n uint64, ok bool) {
 | |
| 	var i int
 | |
| 	var n1 uint64
 | |
| 	var c uint8
 | |
| LOOP:
 | |
| 	if i < len(b) {
 | |
| 		c = b[i]
 | |
| 		// unsigned integers don't overflow well on multiplication, so check cutoff here
 | |
| 		// e.g. (maxUint64-5)*10 doesn't overflow well ...
 | |
| 		// if n >= fUint64Cutoff || !isDigitChar(b[i]) { // if c < '0' || c > '9' {
 | |
| 		if n >= fUint64Cutoff || c < '0' || c > '9' {
 | |
| 			return
 | |
| 		} else if c == '0' {
 | |
| 			n *= fBase
 | |
| 		} else {
 | |
| 			n1 = n
 | |
| 			n = n*fBase + uint64(c-'0')
 | |
| 			if n < n1 {
 | |
| 				return
 | |
| 			}
 | |
| 		}
 | |
| 		i++
 | |
| 		goto LOOP
 | |
| 	}
 | |
| 	ok = true
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func parseUint64_reader(r readFloatResult) (f uint64, fail bool) {
 | |
| 	f = r.mantissa
 | |
| 	if r.exp == 0 {
 | |
| 	} else if r.exp < 0 { // int / 10^k
 | |
| 		if f%uint64pow10[uint8(-r.exp)] != 0 {
 | |
| 			fail = true
 | |
| 		} else {
 | |
| 			f /= uint64pow10[uint8(-r.exp)]
 | |
| 		}
 | |
| 	} else { // exp > 0
 | |
| 		f *= uint64pow10[uint8(r.exp)]
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func parseInteger_bytes(b []byte) (u uint64, neg, ok bool) {
 | |
| 	if len(b) == 0 {
 | |
| 		ok = true
 | |
| 		return
 | |
| 	}
 | |
| 	if b[0] == '-' {
 | |
| 		if len(b) == 1 {
 | |
| 			return
 | |
| 		}
 | |
| 		neg = true
 | |
| 		b = b[1:]
 | |
| 	}
 | |
| 
 | |
| 	u, ok = parseUint64_simple(b)
 | |
| 	if ok {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	r := readFloat(b, fi64u)
 | |
| 	if r.ok {
 | |
| 		var fail bool
 | |
| 		u, fail = parseUint64_reader(r)
 | |
| 		if fail {
 | |
| 			f, err := parseFloat64(b)
 | |
| 			if err != nil {
 | |
| 				return
 | |
| 			}
 | |
| 			if !noFrac64(math.Float64bits(f)) {
 | |
| 				return
 | |
| 			}
 | |
| 			u = uint64(f)
 | |
| 		}
 | |
| 		ok = true
 | |
| 		return
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // parseNumber will return an integer if only composed of [-]?[0-9]+
 | |
| // Else it will return a float.
 | |
| func parseNumber(b []byte, z *fauxUnion, preferSignedInt bool) (err error) {
 | |
| 	var ok, neg bool
 | |
| 	var f uint64
 | |
| 
 | |
| 	if len(b) == 0 {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if b[0] == '-' {
 | |
| 		neg = true
 | |
| 		f, ok = parseUint64_simple(b[1:])
 | |
| 	} else {
 | |
| 		f, ok = parseUint64_simple(b)
 | |
| 	}
 | |
| 
 | |
| 	if ok {
 | |
| 		if neg {
 | |
| 			z.v = valueTypeInt
 | |
| 			if chkOvf.Uint2Int(f, neg) {
 | |
| 				return strconvParseErr(b, "ParseInt")
 | |
| 			}
 | |
| 			z.i = -int64(f)
 | |
| 		} else if preferSignedInt {
 | |
| 			z.v = valueTypeInt
 | |
| 			if chkOvf.Uint2Int(f, neg) {
 | |
| 				return strconvParseErr(b, "ParseInt")
 | |
| 			}
 | |
| 			z.i = int64(f)
 | |
| 		} else {
 | |
| 			z.v = valueTypeUint
 | |
| 			z.u = f
 | |
| 		}
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	z.v = valueTypeFloat
 | |
| 	z.f, err = parseFloat64_custom(b)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| type readFloatResult struct {
 | |
| 	mantissa uint64
 | |
| 	exp      int8
 | |
| 	neg      bool
 | |
| 	trunc    bool
 | |
| 	bad      bool // bad decimal string
 | |
| 	hardexp  bool // exponent is hard to handle (> 2 digits, etc)
 | |
| 	ok       bool
 | |
| 	// sawdot   bool
 | |
| 	// sawexp   bool
 | |
| 	//_ [2]bool // padding
 | |
| }
 | |
| 
 | |
| func readFloat(s []byte, y floatinfo) (r readFloatResult) {
 | |
| 	var i uint // uint, so that we eliminate bounds checking
 | |
| 	var slen = uint(len(s))
 | |
| 	if slen == 0 {
 | |
| 		// read an empty string as the zero value
 | |
| 		// r.bad = true
 | |
| 		r.ok = true
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if s[0] == '-' {
 | |
| 		r.neg = true
 | |
| 		i++
 | |
| 	}
 | |
| 
 | |
| 	// 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
 | |
| 
 | |
| 	var nd, ndMant, dp int8
 | |
| 	var sawdot, sawexp bool
 | |
| 	var xu uint64
 | |
| 
 | |
| LOOP:
 | |
| 	for ; i < slen; i++ {
 | |
| 		switch s[i] {
 | |
| 		case '.':
 | |
| 			if sawdot {
 | |
| 				r.bad = true
 | |
| 				return
 | |
| 			}
 | |
| 			sawdot = true
 | |
| 			dp = nd
 | |
| 		case 'e', 'E':
 | |
| 			sawexp = true
 | |
| 			break LOOP
 | |
| 		case '0':
 | |
| 			if nd == 0 {
 | |
| 				dp--
 | |
| 				continue LOOP
 | |
| 			}
 | |
| 			nd++
 | |
| 			if r.mantissa < y.mantCutoff {
 | |
| 				r.mantissa *= fBase
 | |
| 				ndMant++
 | |
| 			}
 | |
| 		case '1', '2', '3', '4', '5', '6', '7', '8', '9':
 | |
| 			nd++
 | |
| 			if y.mantCutoffIsUint64Cutoff && r.mantissa < fUint64Cutoff {
 | |
| 				r.mantissa *= fBase
 | |
| 				xu = r.mantissa + uint64(s[i]-'0')
 | |
| 				if xu < r.mantissa {
 | |
| 					r.trunc = true
 | |
| 					return
 | |
| 				}
 | |
| 				r.mantissa = xu
 | |
| 			} else if r.mantissa < y.mantCutoff {
 | |
| 				// mantissa = (mantissa << 1) + (mantissa << 3) + uint64(c-'0')
 | |
| 				r.mantissa = r.mantissa*fBase + uint64(s[i]-'0')
 | |
| 			} else {
 | |
| 				r.trunc = true
 | |
| 				return
 | |
| 			}
 | |
| 			ndMant++
 | |
| 		default:
 | |
| 			r.bad = true
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if !sawdot {
 | |
| 		dp = nd
 | |
| 	}
 | |
| 
 | |
| 	if sawexp {
 | |
| 		i++
 | |
| 		if i < slen {
 | |
| 			var eneg bool
 | |
| 			if s[i] == '+' {
 | |
| 				i++
 | |
| 			} else if s[i] == '-' {
 | |
| 				i++
 | |
| 				eneg = true
 | |
| 			}
 | |
| 			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 {
 | |
| 					r.hardexp = true
 | |
| 					return
 | |
| 				}
 | |
| 				var e int8
 | |
| 				if s[i] < '0' || s[i] > '9' { // !isDigitChar(s[i]) { //
 | |
| 					r.bad = true
 | |
| 					return
 | |
| 				}
 | |
| 				e = int8(s[i] - '0')
 | |
| 				i++
 | |
| 				if i < slen {
 | |
| 					if s[i] < '0' || s[i] > '9' { // !isDigitChar(s[i]) { //
 | |
| 						r.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
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if r.mantissa != 0 {
 | |
| 		r.exp = dp - ndMant
 | |
| 		// do not set ok=true for cases we cannot handle
 | |
| 		if r.exp < -y.exactPow10 ||
 | |
| 			r.exp > y.exactInts+y.exactPow10 ||
 | |
| 			(y.mantbits != 0 && r.mantissa>>y.mantbits != 0) {
 | |
| 			r.hardexp = true
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	r.ok = true
 | |
| 	return
 | |
| }
 |