format.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. package utils
  2. // smallInts contains precomputed string representations for small integers 0-99
  3. var smallInts [100]string
  4. // smallNegInts contains precomputed string representations for small negative integers -1 to -99
  5. var smallNegInts [100]string
  6. // uint8Strs contains precomputed string representations for all uint8 values.
  7. var uint8Strs [256]string
  8. // int8Strs contains precomputed string representations for all int8 values indexed by uint8(value).
  9. var int8Strs [256]string
  10. func init() {
  11. for i := range 100 {
  12. smallInts[i] = formatUintSmall(uint64(i))
  13. if i > 0 {
  14. smallNegInts[i] = "-" + smallInts[i]
  15. }
  16. }
  17. for i := range 256 {
  18. v := uint8(i)
  19. uint8Strs[i] = formatUint8Slow(v)
  20. sv := int8(i)
  21. if sv >= 0 {
  22. int8Strs[i] = uint8Strs[sv]
  23. } else {
  24. int8Strs[i] = "-" + uint8Strs[uint8(-sv)]
  25. }
  26. }
  27. }
  28. func formatUintSmall(n uint64) string {
  29. if n < 10 {
  30. return string(byte(n) + '0')
  31. }
  32. return string([]byte{byte(n/10) + '0', byte(n%10) + '0'})
  33. }
  34. func formatUint8Slow(n uint8) string {
  35. if n < 100 {
  36. return smallInts[n]
  37. }
  38. return string([]byte{n/100 + '0', (n/10)%10 + '0', n%10 + '0'})
  39. }
  40. // formatUintBuf writes the digits of n into buf from the end and returns the start index.
  41. // buf must be at least 20 bytes.
  42. func formatUintBuf(buf *[20]byte, n uint64) int {
  43. i := 20
  44. for n >= 10 {
  45. i--
  46. buf[i] = byte(n%10) + '0'
  47. n /= 10
  48. }
  49. i--
  50. buf[i] = byte(n) + '0'
  51. return i
  52. }
  53. // FormatUint formats a uint64 as a decimal string.
  54. // It is faster than strconv.FormatUint for most inputs.
  55. func FormatUint(n uint64) string {
  56. if n < 100 {
  57. return smallInts[n]
  58. }
  59. var buf [20]byte
  60. i := formatUintBuf(&buf, n)
  61. return string(buf[i:])
  62. }
  63. // FormatInt formats an int64 as a decimal string.
  64. // It is faster than strconv.FormatInt for most inputs.
  65. func FormatInt(n int64) string {
  66. if n >= 0 && n < 100 {
  67. return smallInts[n]
  68. }
  69. if n < 0 && n > -100 {
  70. return smallNegInts[-n]
  71. }
  72. if n >= 0 {
  73. var buf [20]byte
  74. i := formatUintBuf(&buf, uint64(n))
  75. return string(buf[i:])
  76. }
  77. var buf [20]byte
  78. i := formatUintBuf(&buf, uint64(-n))
  79. i--
  80. buf[i] = '-'
  81. return string(buf[i:])
  82. }
  83. // FormatUint32 formats a uint32 as a decimal string.
  84. func FormatUint32(n uint32) string {
  85. if n < 100 {
  86. return smallInts[n]
  87. }
  88. var buf [10]byte // max 4294967295
  89. i := 10
  90. for n >= 10 {
  91. i--
  92. buf[i] = byte(n%10) + '0' //nolint:gosec // i is always in bounds: starts at 10, decrements max 10 times for uint32
  93. n /= 10
  94. }
  95. i--
  96. buf[i] = byte(n) + '0' //nolint:gosec // i is always >= 0 after loop
  97. return string(buf[i:])
  98. }
  99. // FormatInt32 formats an int32 as a decimal string.
  100. func FormatInt32(n int32) string {
  101. if n >= 0 && n < 100 {
  102. return smallInts[n]
  103. }
  104. if n < 0 && n > -100 {
  105. return smallNegInts[-n]
  106. }
  107. if n >= 0 {
  108. return FormatUint32(uint32(n))
  109. }
  110. var buf [11]byte // max -2147483648
  111. un := uint32(-n)
  112. i := 11
  113. for un >= 10 {
  114. i--
  115. buf[i] = byte(un%10) + '0'
  116. un /= 10
  117. }
  118. i--
  119. buf[i] = byte(un) + '0'
  120. i--
  121. buf[i] = '-'
  122. return string(buf[i:])
  123. }
  124. // FormatUint16 formats a uint16 as a decimal string.
  125. func FormatUint16(n uint16) string {
  126. if n < 100 {
  127. return smallInts[n]
  128. }
  129. var buf [5]byte // max 65535
  130. i := 5
  131. for n >= 10 {
  132. i--
  133. buf[i] = byte(n%10) + '0' //nolint:gosec // i is always in bounds: starts at 5, decrements max 5 times for uint16
  134. n /= 10
  135. }
  136. i--
  137. buf[i] = byte(n) + '0' //nolint:gosec // i is always >= 0 after loop
  138. return string(buf[i:])
  139. }
  140. // FormatInt16 formats an int16 as a decimal string.
  141. func FormatInt16(n int16) string {
  142. if n >= 0 && n < 100 {
  143. return smallInts[n]
  144. }
  145. if n < 0 && n > -100 {
  146. return smallNegInts[-n]
  147. }
  148. if n >= 0 {
  149. return FormatUint16(uint16(n))
  150. }
  151. var buf [6]byte // max -32768
  152. un := uint16(-n)
  153. i := 6
  154. for un >= 10 {
  155. i--
  156. buf[i] = byte(un%10) + '0' //nolint:gosec // i is always in bounds
  157. un /= 10
  158. }
  159. i--
  160. buf[i] = byte(un) + '0' //nolint:gosec // i is always >= 1 after loop
  161. i--
  162. buf[i] = '-' //nolint:gosec // i is always >= 0 after decrement
  163. return string(buf[i:])
  164. }
  165. // FormatUint8 formats a uint8 as a decimal string.
  166. func FormatUint8(n uint8) string {
  167. return uint8Strs[n]
  168. }
  169. // FormatInt8 formats an int8 as a decimal string.
  170. func FormatInt8(n int8) string {
  171. return int8Strs[uint8(n)]
  172. }
  173. // AppendUint appends the decimal string representation of n to dst.
  174. func AppendUint(dst []byte, n uint64) []byte {
  175. if n < 100 {
  176. return append(dst, smallInts[n]...)
  177. }
  178. var buf [20]byte
  179. i := formatUintBuf(&buf, n)
  180. return append(dst, buf[i:]...)
  181. }
  182. // AppendInt appends the decimal string representation of n to dst.
  183. func AppendInt(dst []byte, n int64) []byte {
  184. if n >= 0 {
  185. return AppendUint(dst, uint64(n))
  186. }
  187. if n > -100 {
  188. return append(dst, smallNegInts[-n]...)
  189. }
  190. var buf [20]byte
  191. i := formatUintBuf(&buf, uint64(-n))
  192. i--
  193. buf[i] = '-' //nolint:gosec // i is always >= 0: formatUintBuf returns at least 1 for any input, so i >= 0 after decrement
  194. return append(dst, buf[i:]...)
  195. }