float.go (3372B)
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-- // for retry current character 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 }