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