number.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package json
  5. import (
  6. "bytes"
  7. "math"
  8. "strconv"
  9. )
  10. // appendFloat formats given float in bitSize, and appends to the given []byte.
  11. func appendFloat(out []byte, n float64, bitSize int) []byte {
  12. switch {
  13. case math.IsNaN(n):
  14. return append(out, `"NaN"`...)
  15. case math.IsInf(n, +1):
  16. return append(out, `"Infinity"`...)
  17. case math.IsInf(n, -1):
  18. return append(out, `"-Infinity"`...)
  19. }
  20. // JSON number formatting logic based on encoding/json.
  21. // See floatEncoder.encode for reference.
  22. fmt := byte('f')
  23. if abs := math.Abs(n); abs != 0 {
  24. if bitSize == 64 && (abs < 1e-6 || abs >= 1e21) ||
  25. bitSize == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
  26. fmt = 'e'
  27. }
  28. }
  29. out = strconv.AppendFloat(out, n, fmt, -1, bitSize)
  30. if fmt == 'e' {
  31. n := len(out)
  32. if n >= 4 && out[n-4] == 'e' && out[n-3] == '-' && out[n-2] == '0' {
  33. out[n-2] = out[n-1]
  34. out = out[:n-1]
  35. }
  36. }
  37. return out
  38. }
  39. // numberParts is the result of parsing out a valid JSON number. It contains
  40. // the parts of a number. The parts are used for integer conversion.
  41. type numberParts struct {
  42. neg bool
  43. intp []byte
  44. frac []byte
  45. exp []byte
  46. }
  47. // parseNumber returns a numberParts instance if it is able to read a JSON
  48. // number from the given []byte. It also returns the number of bytes read.
  49. // Parsing logic follows the definition in
  50. // https://tools.ietf.org/html/rfc7159#section-6, and is based off
  51. // encoding/json.isValidNumber function.
  52. func parseNumber(input []byte) (*numberParts, int) {
  53. var n int
  54. var neg bool
  55. var intp []byte
  56. var frac []byte
  57. var exp []byte
  58. s := input
  59. if len(s) == 0 {
  60. return nil, 0
  61. }
  62. // Optional -
  63. if s[0] == '-' {
  64. neg = true
  65. s = s[1:]
  66. n++
  67. if len(s) == 0 {
  68. return nil, 0
  69. }
  70. }
  71. // Digits
  72. switch {
  73. case s[0] == '0':
  74. // Skip first 0 and no need to store.
  75. s = s[1:]
  76. n++
  77. case '1' <= s[0] && s[0] <= '9':
  78. intp = append(intp, s[0])
  79. s = s[1:]
  80. n++
  81. for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
  82. intp = append(intp, s[0])
  83. s = s[1:]
  84. n++
  85. }
  86. default:
  87. return nil, 0
  88. }
  89. // . followed by 1 or more digits.
  90. if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
  91. frac = append(frac, s[1])
  92. s = s[2:]
  93. n += 2
  94. for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
  95. frac = append(frac, s[0])
  96. s = s[1:]
  97. n++
  98. }
  99. }
  100. // e or E followed by an optional - or + and
  101. // 1 or more digits.
  102. if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
  103. s = s[1:]
  104. n++
  105. if s[0] == '+' || s[0] == '-' {
  106. exp = append(exp, s[0])
  107. s = s[1:]
  108. n++
  109. if len(s) == 0 {
  110. return nil, 0
  111. }
  112. }
  113. for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
  114. exp = append(exp, s[0])
  115. s = s[1:]
  116. n++
  117. }
  118. }
  119. // Check that next byte is a delimiter or it is at the end.
  120. if n < len(input) && isNotDelim(input[n]) {
  121. return nil, 0
  122. }
  123. return &numberParts{
  124. neg: neg,
  125. intp: intp,
  126. frac: bytes.TrimRight(frac, "0"), // Remove unnecessary 0s to the right.
  127. exp: exp,
  128. }, n
  129. }
  130. // normalizeToIntString returns an integer string in normal form without the
  131. // E-notation for given numberParts. It will return false if it is not an
  132. // integer or if the exponent exceeds than max/min int value.
  133. func normalizeToIntString(n *numberParts) (string, bool) {
  134. num := n.intp
  135. intpSize := len(num)
  136. fracSize := len(n.frac)
  137. if intpSize == 0 && fracSize == 0 {
  138. return "0", true
  139. }
  140. var exp int
  141. if len(n.exp) > 0 {
  142. i, err := strconv.ParseInt(string(n.exp), 10, 32)
  143. if err != nil {
  144. return "", false
  145. }
  146. exp = int(i)
  147. }
  148. if exp >= 0 {
  149. // For positive E, shift fraction digits into integer part and also pad
  150. // with zeroes as needed.
  151. // If there are more digits in fraction than the E value, then number is
  152. // not an integer.
  153. if fracSize > exp {
  154. return "", false
  155. }
  156. num = append(num, n.frac...)
  157. for i := 0; i < exp-fracSize; i++ {
  158. num = append(num, '0')
  159. }
  160. } else {
  161. // For negative E, shift digits in integer part out.
  162. // If there are any fractions to begin with, then number is not an
  163. // integer.
  164. if fracSize > 0 {
  165. return "", false
  166. }
  167. index := intpSize + exp
  168. if index < 0 {
  169. return "", false
  170. }
  171. // If any of the digits being shifted out is non-zero, then number is
  172. // not an integer.
  173. for i := index; i < intpSize; i++ {
  174. if num[i] != '0' {
  175. return "", false
  176. }
  177. }
  178. num = num[:index]
  179. }
  180. if n.neg {
  181. return "-" + string(num), true
  182. }
  183. return string(num), true
  184. }