parse.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. package utils
  2. import (
  3. "math"
  4. "strconv"
  5. )
  6. const maxFracDigits = 16
  7. type Signed interface {
  8. ~int | ~int8 | ~int16 | ~int32 | ~int64
  9. }
  10. type Unsigned interface {
  11. ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
  12. }
  13. // ParseUint parses a decimal ASCII string or byte slice into a uint64.
  14. // It returns the parsed value and nil on success.
  15. // If the input contains non-digit characters, it returns 0 and an error.
  16. func ParseUint[S byteSeq](s S) (uint64, error) {
  17. return parseUnsigned[S, uint64]("ParseUint", s, uint64(math.MaxUint64))
  18. }
  19. // ParseInt parses a decimal ASCII string or byte slice into an int64.
  20. // Returns the parsed value and nil on success, else 0 and an error.
  21. func ParseInt[S byteSeq](s S) (int64, error) {
  22. if len(s) > 0 && s[0] != '-' && s[0] != '+' && len(s) <= 19 {
  23. var n uint64
  24. for i := range len(s) {
  25. c := s[i] - '0'
  26. if c > 9 {
  27. return 0, &strconv.NumError{Func: "ParseInt", Num: string(s), Err: strconv.ErrSyntax}
  28. }
  29. n = n*10 + uint64(c)
  30. }
  31. if n > uint64(math.MaxInt64) {
  32. return 0, &strconv.NumError{Func: "ParseInt", Num: string(s), Err: strconv.ErrRange}
  33. }
  34. return int64(n), nil
  35. }
  36. return parseSigned[S, int64]("ParseInt", s, math.MinInt64, math.MaxInt64)
  37. }
  38. // ParseInt32 parses a decimal ASCII string or byte slice into an int32.
  39. func ParseInt32[S byteSeq](s S) (int32, error) {
  40. return parseSigned[S, int32]("ParseInt32", s, math.MinInt32, math.MaxInt32)
  41. }
  42. // ParseInt16 parses a decimal ASCII string or byte slice into an int16.
  43. func ParseInt16[S byteSeq](s S) (int16, error) {
  44. return parseSigned[S, int16]("ParseInt16", s, math.MinInt16, math.MaxInt16)
  45. }
  46. // ParseInt8 parses a decimal ASCII string or byte slice into an int8.
  47. func ParseInt8[S byteSeq](s S) (int8, error) {
  48. if len(s) == 0 {
  49. return 0, &strconv.NumError{Func: "ParseInt8", Num: "", Err: strconv.ErrSyntax}
  50. }
  51. neg := false
  52. i := 0
  53. switch s[0] {
  54. case '-':
  55. neg = true
  56. i++
  57. case '+':
  58. i++
  59. }
  60. if i == len(s) {
  61. return 0, &strconv.NumError{Func: "ParseInt8", Num: string(s), Err: strconv.ErrSyntax}
  62. }
  63. if len(s)-i <= 3 {
  64. var n uint16
  65. for ; i < len(s); i++ {
  66. c := s[i] - '0'
  67. if c > 9 {
  68. return 0, &strconv.NumError{Func: "ParseInt8", Num: string(s), Err: strconv.ErrSyntax}
  69. }
  70. n = n*10 + uint16(c)
  71. }
  72. if neg {
  73. if n > 128 {
  74. return 0, &strconv.NumError{Func: "ParseInt8", Num: string(s), Err: strconv.ErrRange}
  75. }
  76. if n == 128 {
  77. return math.MinInt8, nil
  78. }
  79. return -int8(n), nil
  80. }
  81. if n > math.MaxInt8 {
  82. return 0, &strconv.NumError{Func: "ParseInt8", Num: string(s), Err: strconv.ErrRange}
  83. }
  84. return int8(n), nil
  85. }
  86. return parseSigned[S, int8]("ParseInt8", s, math.MinInt8, math.MaxInt8)
  87. }
  88. // ParseUint32 parses a decimal ASCII string or byte slice into a uint32.
  89. func ParseUint32[S byteSeq](s S) (uint32, error) {
  90. return parseUnsigned[S, uint32]("ParseUint32", s, uint32(math.MaxUint32))
  91. }
  92. // ParseUint16 parses a decimal ASCII string or byte slice into a uint16.
  93. func ParseUint16[S byteSeq](s S) (uint16, error) {
  94. return parseUnsigned[S, uint16]("ParseUint16", s, uint16(math.MaxUint16))
  95. }
  96. // ParseUint8 parses a decimal ASCII string or byte slice into a uint8.
  97. func ParseUint8[S byteSeq](s S) (uint8, error) {
  98. if len(s) == 0 {
  99. return 0, &strconv.NumError{Func: "ParseUint8", Num: "", Err: strconv.ErrSyntax}
  100. }
  101. if len(s) <= 3 {
  102. var n uint16
  103. for i := range len(s) {
  104. c := s[i] - '0'
  105. if c > 9 {
  106. return 0, &strconv.NumError{Func: "ParseUint8", Num: string(s), Err: strconv.ErrSyntax}
  107. }
  108. n = n*10 + uint16(c)
  109. }
  110. if n > math.MaxUint8 {
  111. return 0, &strconv.NumError{Func: "ParseUint8", Num: string(s), Err: strconv.ErrRange}
  112. }
  113. return uint8(n), nil
  114. }
  115. return parseUnsigned[S, uint8]("ParseUint8", s, uint8(math.MaxUint8))
  116. }
  117. // parseDigits parses a sequence of digits and returns the uint64 value.
  118. // It returns an error if any non-digit is encountered or overflow happens.
  119. func parseDigits[S byteSeq](s S, i int) (uint64, error) {
  120. var n uint64
  121. const (
  122. cutoff = math.MaxUint64 / 10
  123. cutlim = math.MaxUint64 % 10
  124. )
  125. digits := 0
  126. for ; i < len(s); i++ {
  127. c := s[i] - '0'
  128. if c > 9 {
  129. return 0, strconv.ErrSyntax
  130. }
  131. d := uint64(c)
  132. // Any value with <= 19 digits is guaranteed to fit in uint64.
  133. if digits >= 19 && (n > cutoff || (n == cutoff && d > cutlim)) {
  134. return 0, strconv.ErrRange
  135. }
  136. n = n*10 + d
  137. digits++
  138. }
  139. return n, nil
  140. }
  141. // parseSigned parses a decimal ASCII string or byte slice into a signed integer type T.
  142. // It supports optional '+' or '-' prefix, checks for overflow and underflow, and returns (0, error) on error.
  143. func parseSigned[S byteSeq, T Signed](fn string, s S, minRange, maxRange T) (T, error) {
  144. if len(s) == 0 {
  145. return 0, &strconv.NumError{Func: fn, Num: "", Err: strconv.ErrSyntax}
  146. }
  147. neg := false
  148. i := 0
  149. switch s[0] {
  150. case '-':
  151. neg = true
  152. i++
  153. case '+':
  154. i++
  155. }
  156. if i == len(s) {
  157. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrSyntax}
  158. }
  159. // Parse digits.
  160. n, err := parseDigits(s, i)
  161. if err != nil {
  162. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: err}
  163. }
  164. if !neg {
  165. // Check for overflow
  166. if n > uint64(int64(maxRange)) {
  167. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrRange}
  168. }
  169. return T(n), nil
  170. }
  171. // Check for underflow
  172. minAbs := uint64(-int64(minRange))
  173. if n > minAbs {
  174. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrRange}
  175. }
  176. return T(-int64(n)), nil
  177. }
  178. // parseUnsigned parses a decimal ASCII string or byte slice into an unsigned integer type T.
  179. // It does not support sign prefixes, checks for overflow, and returns (0, error) on error.
  180. func parseUnsigned[S byteSeq, T Unsigned](fn string, s S, maxRange T) (T, error) {
  181. if len(s) == 0 {
  182. return 0, &strconv.NumError{Func: fn, Num: "", Err: strconv.ErrSyntax}
  183. }
  184. // Parse digits directly from index 0.
  185. n, err := parseDigits(s, 0)
  186. if err != nil {
  187. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: err}
  188. }
  189. // Check for overflow
  190. if n > uint64(maxRange) {
  191. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrRange}
  192. }
  193. return T(n), nil
  194. }
  195. // parseFloat parses a decimal ASCII string or byte slice into a float64.
  196. // It supports optional sign, fractional part and exponent. It returns (0, error)
  197. // on error or overflow.
  198. func parseFloat[S byteSeq](fn string, s S) (float64, error) {
  199. if len(s) == 0 {
  200. return 0, &strconv.NumError{Func: fn, Num: "", Err: strconv.ErrSyntax}
  201. }
  202. i := 0
  203. neg := false
  204. switch s[0] {
  205. case '-':
  206. neg = true
  207. i++
  208. case '+':
  209. i++
  210. }
  211. if i == len(s) {
  212. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrSyntax}
  213. }
  214. var intPart uint64
  215. for i < len(s) {
  216. c := s[i] - '0'
  217. if c > 9 {
  218. break
  219. }
  220. nn := intPart*10 + uint64(c)
  221. if nn < intPart {
  222. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrRange}
  223. }
  224. intPart = nn
  225. i++
  226. }
  227. var fracPart uint64
  228. var fracDiv uint64 = 1
  229. var fracDigits int
  230. if i < len(s) && s[i] == '.' {
  231. i++
  232. for i < len(s) {
  233. c := s[i] - '0'
  234. if c > 9 {
  235. break
  236. }
  237. if fracDigits >= maxFracDigits {
  238. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrRange}
  239. }
  240. fracPart = fracPart*10 + uint64(c)
  241. fracDiv *= 10
  242. fracDigits++
  243. i++
  244. }
  245. }
  246. var expSign bool
  247. var exp int64
  248. if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
  249. i++
  250. if i == len(s) {
  251. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrSyntax}
  252. }
  253. switch s[i] {
  254. case '-':
  255. expSign = true
  256. i++
  257. case '+':
  258. i++
  259. }
  260. if i == len(s) {
  261. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrSyntax}
  262. }
  263. for i < len(s) {
  264. c := s[i] - '0'
  265. if c > 9 {
  266. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrSyntax}
  267. }
  268. exp = exp*10 + int64(c)
  269. if !expSign && exp > 308 {
  270. exp = 309
  271. }
  272. if expSign && exp > 324 {
  273. exp = 325
  274. }
  275. i++
  276. }
  277. }
  278. if i != len(s) {
  279. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrSyntax}
  280. }
  281. if expSign {
  282. exp = -exp
  283. }
  284. f := float64(intPart)
  285. if fracPart > 0 {
  286. f += float64(fracPart) / float64(fracDiv)
  287. }
  288. if exp != 0 {
  289. f *= math.Pow10(int(exp))
  290. }
  291. if neg {
  292. f = -f
  293. }
  294. if math.IsInf(f, 0) || math.IsNaN(f) {
  295. return 0, &strconv.NumError{Func: fn, Num: string(s), Err: strconv.ErrRange}
  296. }
  297. return f, nil
  298. }
  299. // ParseFloat64 parses a decimal ASCII string or byte slice into a float64. It
  300. // delegates the actual parsing to parseFloat.
  301. func ParseFloat64[S byteSeq](s S) (float64, error) {
  302. return parseFloat[S]("ParseFloat64", s)
  303. }
  304. // ParseFloat32 parses a decimal ASCII string or byte slice into a float32. It
  305. // returns (0, false) on error or if the parsed value overflows float32.
  306. func ParseFloat32[S byteSeq](s S) (float32, error) {
  307. f, err := parseFloat[S]("ParseFloat32", s)
  308. if err != nil {
  309. return 0, err
  310. }
  311. if f > math.MaxFloat32 || f < -math.MaxFloat32 {
  312. return 0, &strconv.NumError{Func: "ParseFloat32", Num: string(s), Err: strconv.ErrRange}
  313. }
  314. return float32(f), nil
  315. }