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