1 package decoder
2
3 import (
4 "strconv"
5 "unsafe"
6
7 "github.com/goccy/go-json/internal/errors"
8 )
9
10 type floatDecoder struct {
11 op func(unsafe.Pointer, float64)
12 structName string
13 fieldName string
14 }
15
16 func newFloatDecoder(structName, fieldName string, op func(unsafe.Pointer, float64)) *floatDecoder {
17 return &floatDecoder{op: op, structName: structName, fieldName: fieldName}
18 }
19
20 var (
21 floatTable = [256]bool{
22 '0': true,
23 '1': true,
24 '2': true,
25 '3': true,
26 '4': true,
27 '5': true,
28 '6': true,
29 '7': true,
30 '8': true,
31 '9': true,
32 '.': true,
33 'e': true,
34 'E': true,
35 '+': true,
36 '-': true,
37 }
38
39 validEndNumberChar = [256]bool{
40 nul: true,
41 ' ': true,
42 '\t': true,
43 '\r': true,
44 '\n': true,
45 ',': true,
46 ':': true,
47 '}': true,
48 ']': true,
49 }
50 )
51
52 func floatBytes(s *Stream) []byte {
53 start := s.cursor
54 for {
55 s.cursor++
56 if floatTable[s.char()] {
57 continue
58 } else if s.char() == nul {
59 if s.read() {
60 s.cursor--
61 continue
62 }
63 }
64 break
65 }
66 return s.buf[start:s.cursor]
67 }
68
69 func (d *floatDecoder) decodeStreamByte(s *Stream) ([]byte, error) {
70 for {
71 switch s.char() {
72 case ' ', '\n', '\t', '\r':
73 s.cursor++
74 continue
75 case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
76 return floatBytes(s), nil
77 case 'n':
78 if err := nullBytes(s); err != nil {
79 return nil, err
80 }
81 return nil, nil
82 case nul:
83 if s.read() {
84 continue
85 }
86 goto ERROR
87 default:
88 goto ERROR
89 }
90 }
91 ERROR:
92 return nil, errors.ErrUnexpectedEndOfJSON("float", s.totalOffset())
93 }
94
95 func (d *floatDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) {
96 for {
97 switch buf[cursor] {
98 case ' ', '\n', '\t', '\r':
99 cursor++
100 continue
101 case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
102 start := cursor
103 cursor++
104 for floatTable[buf[cursor]] {
105 cursor++
106 }
107 num := buf[start:cursor]
108 return num, cursor, nil
109 case 'n':
110 if err := validateNull(buf, cursor); err != nil {
111 return nil, 0, err
112 }
113 cursor += 4
114 return nil, cursor, nil
115 default:
116 return nil, 0, errors.ErrUnexpectedEndOfJSON("float", cursor)
117 }
118 }
119 }
120
121 func (d *floatDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
122 bytes, err := d.decodeStreamByte(s)
123 if err != nil {
124 return err
125 }
126 if bytes == nil {
127 return nil
128 }
129 str := *(*string)(unsafe.Pointer(&bytes))
130 f64, err := strconv.ParseFloat(str, 64)
131 if err != nil {
132 return errors.ErrSyntax(err.Error(), s.totalOffset())
133 }
134 d.op(p, f64)
135 return nil
136 }
137
138 func (d *floatDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
139 buf := ctx.Buf
140 bytes, c, err := d.decodeByte(buf, cursor)
141 if err != nil {
142 return 0, err
143 }
144 if bytes == nil {
145 return c, nil
146 }
147 cursor = c
148 if !validEndNumberChar[buf[cursor]] {
149 return 0, errors.ErrUnexpectedEndOfJSON("float", cursor)
150 }
151 s := *(*string)(unsafe.Pointer(&bytes))
152 f64, err := strconv.ParseFloat(s, 64)
153 if err != nil {
154 return 0, errors.ErrSyntax(err.Error(), cursor)
155 }
156 d.op(p, f64)
157 return cursor, nil
158 }
159
160 func (d *floatDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) {
161 buf := ctx.Buf
162 bytes, c, err := d.decodeByte(buf, cursor)
163 if err != nil {
164 return nil, 0, err
165 }
166 if bytes == nil {
167 return [][]byte{nullbytes}, c, nil
168 }
169 return [][]byte{bytes}, c, nil
170 }
171
View as plain text