github.com/3JoB/go-json@v0.10.4/internal/decoder/slice.go (about) 1 package decoder 2 3 import ( 4 "sync" 5 "unsafe" 6 7 "github.com/3JoB/go-reflect" 8 9 "github.com/3JoB/go-json/internal/errors" 10 "github.com/3JoB/go-json/internal/runtime" 11 ) 12 13 var ( 14 sliceType = runtime.Type2RType( 15 reflect.ToRT(reflect.TypeOf((*sliceHeader)(nil)).Elem()), 16 ) 17 nilSlice = unsafe.Pointer(&sliceHeader{}) 18 ) 19 20 type sliceDecoder struct { 21 elemType *runtime.Type 22 isElemPointerType bool 23 valueDecoder Decoder 24 size uintptr 25 arrayPool sync.Pool 26 structName string 27 fieldName string 28 } 29 30 // If use reflect.SliceHeader, data type is uintptr. 31 // In this case, Go compiler cannot trace reference created by newArray(). 32 // So, define using unsafe.Pointer as data type 33 type sliceHeader struct { 34 data unsafe.Pointer 35 len int 36 cap int 37 } 38 39 const ( 40 defaultSliceCapacity = 2 41 ) 42 43 func newSliceDecoder(dec Decoder, elemType *runtime.Type, size uintptr, structName, fieldName string) *sliceDecoder { 44 return &sliceDecoder{ 45 valueDecoder: dec, 46 elemType: elemType, 47 isElemPointerType: elemType.Kind() == reflect.Ptr || elemType.Kind() == reflect.Map, 48 size: size, 49 arrayPool: sync.Pool{ 50 New: func() any { 51 return &sliceHeader{ 52 data: newArray(elemType, defaultSliceCapacity), 53 len: 0, 54 cap: defaultSliceCapacity, 55 } 56 }, 57 }, 58 structName: structName, 59 fieldName: fieldName, 60 } 61 } 62 63 func (d *sliceDecoder) newSlice(src *sliceHeader) *sliceHeader { 64 slice := d.arrayPool.Get().(*sliceHeader) 65 if src.len > 0 { 66 // copy original elem 67 if slice.cap < src.cap { 68 data := newArray(d.elemType, src.cap) 69 slice = &sliceHeader{data: data, len: src.len, cap: src.cap} 70 } else { 71 slice.len = src.len 72 } 73 copySlice(d.elemType, *slice, *src) 74 } else { 75 slice.len = 0 76 } 77 return slice 78 } 79 80 func (d *sliceDecoder) releaseSlice(p *sliceHeader) { 81 d.arrayPool.Put(p) 82 } 83 84 //go:linkname copySlice reflect.typedslicecopy 85 func copySlice(elemType *runtime.Type, dst, src sliceHeader) int 86 87 //go:linkname newArray reflect.unsafe_NewArray 88 func newArray(*runtime.Type, int) unsafe.Pointer 89 90 //go:linkname typedmemmove reflect.typedmemmove 91 func typedmemmove(t *runtime.Type, dst, src unsafe.Pointer) 92 93 func (d *sliceDecoder) errNumber(offset int64) *errors.UnmarshalTypeError { 94 return &errors.UnmarshalTypeError{ 95 Value: "number", 96 Type: reflect.SliceOf(reflect.ToT(runtime.RType2Type(d.elemType))), 97 Struct: d.structName, 98 Field: d.fieldName, 99 Offset: offset, 100 } 101 } 102 103 func (d *sliceDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { 104 depth++ 105 if depth > maxDecodeNestingDepth { 106 return errors.ErrExceededMaxDepth(s.char(), s.cursor) 107 } 108 109 for { 110 switch s.char() { 111 case ' ', '\n', '\t', '\r': 112 s.cursor++ 113 continue 114 case 'n': 115 if err := nullBytes(s); err != nil { 116 return err 117 } 118 typedmemmove(sliceType, p, nilSlice) 119 return nil 120 case '[': 121 s.cursor++ 122 if s.skipWhiteSpace() == ']' { 123 dst := (*sliceHeader)(p) 124 if dst.data == nil { 125 dst.data = newArray(d.elemType, 0) 126 } else { 127 dst.len = 0 128 } 129 s.cursor++ 130 return nil 131 } 132 idx := 0 133 slice := d.newSlice((*sliceHeader)(p)) 134 srcLen := slice.len 135 capacity := slice.cap 136 data := slice.data 137 for { 138 if capacity <= idx { 139 src := sliceHeader{data: data, len: idx, cap: capacity} 140 capacity *= 2 141 data = newArray(d.elemType, capacity) 142 dst := sliceHeader{data: data, len: idx, cap: capacity} 143 copySlice(d.elemType, dst, src) 144 } 145 ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size) 146 147 // if srcLen is greater than idx, keep the original reference 148 if srcLen <= idx { 149 if d.isElemPointerType { 150 **(**unsafe.Pointer)(unsafe.Pointer(&ep)) = nil // initialize elem pointer 151 } else { 152 // assign new element to the slice 153 typedmemmove(d.elemType, ep, unsafe_New(d.elemType)) 154 } 155 } 156 157 if err := d.valueDecoder.DecodeStream(s, depth, ep); err != nil { 158 return err 159 } 160 s.skipWhiteSpace() 161 RETRY: 162 switch s.char() { 163 case ']': 164 slice.cap = capacity 165 slice.len = idx + 1 166 slice.data = data 167 dst := (*sliceHeader)(p) 168 dst.len = idx + 1 169 if dst.len > dst.cap { 170 dst.data = newArray(d.elemType, dst.len) 171 dst.cap = dst.len 172 } 173 copySlice(d.elemType, *dst, *slice) 174 d.releaseSlice(slice) 175 s.cursor++ 176 return nil 177 case ',': 178 idx++ 179 case nul: 180 if s.read() { 181 goto RETRY 182 } 183 slice.cap = capacity 184 slice.data = data 185 d.releaseSlice(slice) 186 goto ERROR 187 default: 188 slice.cap = capacity 189 slice.data = data 190 d.releaseSlice(slice) 191 goto ERROR 192 } 193 s.cursor++ 194 } 195 case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': 196 return d.errNumber(s.totalOffset()) 197 case nul: 198 if s.read() { 199 continue 200 } 201 goto ERROR 202 default: 203 goto ERROR 204 } 205 } 206 ERROR: 207 return errors.ErrUnexpectedEndOfJSON("slice", s.totalOffset()) 208 } 209 210 func (d *sliceDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { 211 buf := ctx.Buf 212 depth++ 213 if depth > maxDecodeNestingDepth { 214 return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) 215 } 216 217 for { 218 switch buf[cursor] { 219 case ' ', '\n', '\t', '\r': 220 cursor++ 221 continue 222 case 'n': 223 if err := validateNull(buf, cursor); err != nil { 224 return 0, err 225 } 226 cursor += 4 227 typedmemmove(sliceType, p, nilSlice) 228 return cursor, nil 229 case '[': 230 cursor++ 231 cursor = skipWhiteSpace(buf, cursor) 232 if buf[cursor] == ']' { 233 dst := (*sliceHeader)(p) 234 if dst.data == nil { 235 dst.data = newArray(d.elemType, 0) 236 } else { 237 dst.len = 0 238 } 239 cursor++ 240 return cursor, nil 241 } 242 idx := 0 243 slice := d.newSlice((*sliceHeader)(p)) 244 srcLen := slice.len 245 capacity := slice.cap 246 data := slice.data 247 for { 248 if capacity <= idx { 249 src := sliceHeader{data: data, len: idx, cap: capacity} 250 capacity *= 2 251 data = newArray(d.elemType, capacity) 252 dst := sliceHeader{data: data, len: idx, cap: capacity} 253 copySlice(d.elemType, dst, src) 254 } 255 ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size) 256 // if srcLen is greater than idx, keep the original reference 257 if srcLen <= idx { 258 if d.isElemPointerType { 259 **(**unsafe.Pointer)(unsafe.Pointer(&ep)) = nil // initialize elem pointer 260 } else { 261 // assign new element to the slice 262 typedmemmove(d.elemType, ep, unsafe_New(d.elemType)) 263 } 264 } 265 c, err := d.valueDecoder.Decode(ctx, cursor, depth, ep) 266 if err != nil { 267 return 0, err 268 } 269 cursor = c 270 cursor = skipWhiteSpace(buf, cursor) 271 switch buf[cursor] { 272 case ']': 273 slice.cap = capacity 274 slice.len = idx + 1 275 slice.data = data 276 dst := (*sliceHeader)(p) 277 dst.len = idx + 1 278 if dst.len > dst.cap { 279 dst.data = newArray(d.elemType, dst.len) 280 dst.cap = dst.len 281 } 282 copySlice(d.elemType, *dst, *slice) 283 d.releaseSlice(slice) 284 cursor++ 285 return cursor, nil 286 case ',': 287 idx++ 288 default: 289 slice.cap = capacity 290 slice.data = data 291 d.releaseSlice(slice) 292 return 0, errors.ErrInvalidCharacter(buf[cursor], "slice", cursor) 293 } 294 cursor++ 295 } 296 case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': 297 return 0, d.errNumber(cursor) 298 default: 299 return 0, errors.ErrUnexpectedEndOfJSON("slice", cursor) 300 } 301 } 302 } 303 304 func (d *sliceDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { 305 buf := ctx.Buf 306 depth++ 307 if depth > maxDecodeNestingDepth { 308 return nil, 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) 309 } 310 311 ret := [][]byte{} 312 for { 313 switch buf[cursor] { 314 case ' ', '\n', '\t', '\r': 315 cursor++ 316 continue 317 case 'n': 318 if err := validateNull(buf, cursor); err != nil { 319 return nil, 0, err 320 } 321 cursor += 4 322 return [][]byte{nullbytes}, cursor, nil 323 case '[': 324 cursor++ 325 cursor = skipWhiteSpace(buf, cursor) 326 if buf[cursor] == ']' { 327 cursor++ 328 return ret, cursor, nil 329 } 330 idx := 0 331 for { 332 child, found, err := ctx.Option.Path.node.Index(idx) 333 if err != nil { 334 return nil, 0, err 335 } 336 if found { 337 if child != nil { 338 oldPath := ctx.Option.Path.node 339 ctx.Option.Path.node = child 340 paths, c, err := d.valueDecoder.DecodePath(ctx, cursor, depth) 341 if err != nil { 342 return nil, 0, err 343 } 344 ctx.Option.Path.node = oldPath 345 ret = append(ret, paths...) 346 cursor = c 347 } else { 348 start := cursor 349 end, err := skipValue(buf, cursor, depth) 350 if err != nil { 351 return nil, 0, err 352 } 353 ret = append(ret, buf[start:end]) 354 cursor = end 355 } 356 } else { 357 c, err := skipValue(buf, cursor, depth) 358 if err != nil { 359 return nil, 0, err 360 } 361 cursor = c 362 } 363 cursor = skipWhiteSpace(buf, cursor) 364 switch buf[cursor] { 365 case ']': 366 cursor++ 367 return ret, cursor, nil 368 case ',': 369 idx++ 370 default: 371 return nil, 0, errors.ErrInvalidCharacter(buf[cursor], "slice", cursor) 372 } 373 cursor++ 374 } 375 case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': 376 return nil, 0, d.errNumber(cursor) 377 default: 378 return nil, 0, errors.ErrUnexpectedEndOfJSON("slice", cursor) 379 } 380 } 381 }