spec.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. //go:build (amd64 && go1.16 && !go1.25) || (arm64 && go1.20 && !go1.25)
  2. // +build amd64,go1.16,!go1.25 arm64,go1.20,!go1.25
  3. /**
  4. * Copyright 2024 ByteDance Inc.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package alg
  19. import (
  20. "runtime"
  21. "unsafe"
  22. "github.com/bytedance/sonic/internal/native"
  23. "github.com/bytedance/sonic/internal/native/types"
  24. "github.com/bytedance/sonic/internal/rt"
  25. )
  26. // Valid validates json and returns first non-blank character position,
  27. // if it is only one valid json value.
  28. // Otherwise returns invalid character position using start.
  29. //
  30. // Note: it does not check for the invalid UTF-8 characters.
  31. func Valid(data []byte) (ok bool, start int) {
  32. n := len(data)
  33. if n == 0 {
  34. return false, -1
  35. }
  36. s := rt.Mem2Str(data)
  37. p := 0
  38. m := types.NewStateMachine()
  39. ret := native.ValidateOne(&s, &p, m, 0)
  40. types.FreeStateMachine(m)
  41. if ret < 0 {
  42. return false, p-1
  43. }
  44. /* check for trailing spaces */
  45. for ;p < n; p++ {
  46. if (types.SPACE_MASK & (1 << data[p])) == 0 {
  47. return false, p
  48. }
  49. }
  50. return true, ret
  51. }
  52. var typeByte = rt.UnpackEface(byte(0)).Type
  53. //go:nocheckptr
  54. func Quote(buf []byte, val string, double bool) []byte {
  55. if len(val) == 0 {
  56. if double {
  57. return append(buf, `"\"\""`...)
  58. }
  59. return append(buf, `""`...)
  60. }
  61. if double {
  62. buf = append(buf, `"\"`...)
  63. } else {
  64. buf = append(buf, `"`...)
  65. }
  66. sp := rt.IndexChar(val, 0)
  67. nb := len(val)
  68. b := (*rt.GoSlice)(unsafe.Pointer(&buf))
  69. // input buffer
  70. for nb > 0 {
  71. // output buffer
  72. dp := unsafe.Pointer(uintptr(b.Ptr) + uintptr(b.Len))
  73. dn := b.Cap - b.Len
  74. // call native.Quote, dn is byte count it outputs
  75. opts := uint64(0)
  76. if double {
  77. opts = types.F_DOUBLE_UNQUOTE
  78. }
  79. ret := native.Quote(sp, nb, dp, &dn, opts)
  80. // update *buf length
  81. b.Len += dn
  82. // no need more output
  83. if ret >= 0 {
  84. break
  85. }
  86. // double buf size
  87. *b = rt.GrowSlice(typeByte, *b, b.Cap*2)
  88. // ret is the complement of consumed input
  89. ret = ^ret
  90. // update input buffer
  91. nb -= ret
  92. sp = unsafe.Pointer(uintptr(sp) + uintptr(ret))
  93. }
  94. runtime.KeepAlive(buf)
  95. runtime.KeepAlive(sp)
  96. if double {
  97. buf = append(buf, `\""`...)
  98. } else {
  99. buf = append(buf, `"`...)
  100. }
  101. return buf
  102. }
  103. func HtmlEscape(dst []byte, src []byte) []byte {
  104. var sidx int
  105. dst = append(dst, src[:0]...) // avoid check nil dst
  106. sbuf := (*rt.GoSlice)(unsafe.Pointer(&src))
  107. dbuf := (*rt.GoSlice)(unsafe.Pointer(&dst))
  108. /* grow dst if it is shorter */
  109. if cap(dst)-len(dst) < len(src)+types.BufPaddingSize {
  110. cap := len(src)*3/2 + types.BufPaddingSize
  111. *dbuf = rt.GrowSlice(typeByte, *dbuf, cap)
  112. }
  113. for sidx < sbuf.Len {
  114. sp := rt.Add(sbuf.Ptr, uintptr(sidx))
  115. dp := rt.Add(dbuf.Ptr, uintptr(dbuf.Len))
  116. sn := sbuf.Len - sidx
  117. dn := dbuf.Cap - dbuf.Len
  118. nb := native.HTMLEscape(sp, sn, dp, &dn)
  119. /* check for errors */
  120. if dbuf.Len += dn; nb >= 0 {
  121. break
  122. }
  123. /* not enough space, grow the slice and try again */
  124. sidx += ^nb
  125. *dbuf = rt.GrowSlice(typeByte, *dbuf, dbuf.Cap*2)
  126. }
  127. return dst
  128. }
  129. func F64toa(buf []byte, v float64) ([]byte) {
  130. if v == 0 {
  131. return append(buf, '0')
  132. }
  133. buf = rt.GuardSlice2(buf, 64)
  134. ret := native.F64toa((*byte)(rt.IndexByte(buf, len(buf))), v)
  135. if ret > 0 {
  136. return buf[:len(buf)+ret]
  137. } else {
  138. return buf
  139. }
  140. }
  141. func F32toa(buf []byte, v float32) ([]byte) {
  142. if v == 0 {
  143. return append(buf, '0')
  144. }
  145. buf = rt.GuardSlice2(buf, 64)
  146. ret := native.F32toa((*byte)(rt.IndexByte(buf, len(buf))), v)
  147. if ret > 0 {
  148. return buf[:len(buf)+ret]
  149. } else {
  150. return buf
  151. }
  152. }
  153. func I64toa(buf []byte, v int64) ([]byte) {
  154. buf = rt.GuardSlice2(buf, 32)
  155. ret := native.I64toa((*byte)(rt.IndexByte(buf, len(buf))), v)
  156. if ret > 0 {
  157. return buf[:len(buf)+ret]
  158. } else {
  159. return buf
  160. }
  161. }
  162. func U64toa(buf []byte, v uint64) ([]byte) {
  163. buf = rt.GuardSlice2(buf, 32)
  164. ret := native.U64toa((*byte)(rt.IndexByte(buf, len(buf))), v)
  165. if ret > 0 {
  166. return buf[:len(buf)+ret]
  167. } else {
  168. return buf
  169. }
  170. }