gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

slice.go (9185B)


      1 package decoder
      2 
      3 import (
      4 	"reflect"
      5 	"sync"
      6 	"unsafe"
      7 
      8 	"github.com/goccy/go-json/internal/errors"
      9 	"github.com/goccy/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 }