package decoder

import (
	
	
	

	
	
)

var (
	sliceType = runtime.Type2RType(
		reflect.TypeOf((*sliceHeader)(nil)).Elem(),
	)
	nilSlice = unsafe.Pointer(&sliceHeader{})
)

type sliceDecoder struct {
	elemType          *runtime.Type
	isElemPointerType bool
	valueDecoder      Decoder
	size              uintptr
	arrayPool         sync.Pool
	structName        string
	fieldName         string
}

// If use reflect.SliceHeader, data type is uintptr.
// In this case, Go compiler cannot trace reference created by newArray().
// So, define using unsafe.Pointer as data type
type sliceHeader struct {
	data unsafe.Pointer
	len  int
	cap  int
}

const (
	defaultSliceCapacity = 2
)

func newSliceDecoder( Decoder,  *runtime.Type,  uintptr, ,  string) *sliceDecoder {
	return &sliceDecoder{
		valueDecoder:      ,
		elemType:          ,
		isElemPointerType: .Kind() == reflect.Ptr || .Kind() == reflect.Map,
		size:              ,
		arrayPool: sync.Pool{
			New: func() interface{} {
				return &sliceHeader{
					data: newArray(, defaultSliceCapacity),
					len:  0,
					cap:  defaultSliceCapacity,
				}
			},
		},
		structName: ,
		fieldName:  ,
	}
}

func ( *sliceDecoder) ( *sliceHeader) *sliceHeader {
	 := .arrayPool.Get().(*sliceHeader)
	if .len > 0 {
		// copy original elem
		if .cap < .cap {
			 := newArray(.elemType, .cap)
			 = &sliceHeader{data: , len: .len, cap: .cap}
		} else {
			.len = .len
		}
		copySlice(.elemType, *, *)
	} else {
		.len = 0
	}
	return 
}

func ( *sliceDecoder) ( *sliceHeader) {
	.arrayPool.Put()
}

//go:linkname copySlice reflect.typedslicecopy
func copySlice( *runtime.Type, ,  sliceHeader) int

//go:linkname newArray reflect.unsafe_NewArray
func newArray(*runtime.Type, int) unsafe.Pointer

//go:linkname typedmemmove reflect.typedmemmove
func typedmemmove( *runtime.Type, ,  unsafe.Pointer)

func ( *sliceDecoder) ( int64) *errors.UnmarshalTypeError {
	return &errors.UnmarshalTypeError{
		Value:  "number",
		Type:   reflect.SliceOf(runtime.RType2Type(.elemType)),
		Struct: .structName,
		Field:  .fieldName,
		Offset: ,
	}
}

func ( *sliceDecoder) ( *Stream,  int64,  unsafe.Pointer) error {
	++
	if  > maxDecodeNestingDepth {
		return errors.ErrExceededMaxDepth(.char(), .cursor)
	}

	for {
		switch .char() {
		case ' ', '\n', '\t', '\r':
			.cursor++
			continue
		case 'n':
			if  := nullBytes();  != nil {
				return 
			}
			typedmemmove(sliceType, , nilSlice)
			return nil
		case '[':
			.cursor++
			if .skipWhiteSpace() == ']' {
				 := (*sliceHeader)()
				if .data == nil {
					.data = newArray(.elemType, 0)
				} else {
					.len = 0
				}
				.cursor++
				return nil
			}
			 := 0
			 := .newSlice((*sliceHeader)())
			 := .len
			 := .cap
			 := .data
			for {
				if  <=  {
					 := sliceHeader{data: , len: , cap: }
					 *= 2
					 = newArray(.elemType, )
					 := sliceHeader{data: , len: , cap: }
					copySlice(.elemType, , )
				}
				 := unsafe.Pointer(uintptr() + uintptr()*.size)

				// if srcLen is greater than idx, keep the original reference
				if  <=  {
					if .isElemPointerType {
						**(**unsafe.Pointer)(unsafe.Pointer(&)) = nil // initialize elem pointer
					} else {
						// assign new element to the slice
						typedmemmove(.elemType, , unsafe_New(.elemType))
					}
				}

				if  := .valueDecoder.DecodeStream(, , );  != nil {
					return 
				}
				.skipWhiteSpace()
			:
				switch .char() {
				case ']':
					.cap = 
					.len =  + 1
					.data = 
					 := (*sliceHeader)()
					.len =  + 1
					if .len > .cap {
						.data = newArray(.elemType, .len)
						.cap = .len
					}
					copySlice(.elemType, *, *)
					.releaseSlice()
					.cursor++
					return nil
				case ',':
					++
				case nul:
					if .read() {
						goto 
					}
					.cap = 
					.data = 
					.releaseSlice()
					goto 
				default:
					.cap = 
					.data = 
					.releaseSlice()
					goto 
				}
				.cursor++
			}
		case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
			return .errNumber(.totalOffset())
		case nul:
			if .read() {
				continue
			}
			goto 
		default:
			goto 
		}
	}
:
	return errors.ErrUnexpectedEndOfJSON("slice", .totalOffset())
}

func ( *sliceDecoder) ( *RuntimeContext, ,  int64,  unsafe.Pointer) (int64, error) {
	 := .Buf
	++
	if  > maxDecodeNestingDepth {
		return 0, errors.ErrExceededMaxDepth([], )
	}

	for {
		switch [] {
		case ' ', '\n', '\t', '\r':
			++
			continue
		case 'n':
			if  := validateNull(, );  != nil {
				return 0, 
			}
			 += 4
			typedmemmove(sliceType, , nilSlice)
			return , nil
		case '[':
			++
			 = skipWhiteSpace(, )
			if [] == ']' {
				 := (*sliceHeader)()
				if .data == nil {
					.data = newArray(.elemType, 0)
				} else {
					.len = 0
				}
				++
				return , nil
			}
			 := 0
			 := .newSlice((*sliceHeader)())
			 := .len
			 := .cap
			 := .data
			for {
				if  <=  {
					 := sliceHeader{data: , len: , cap: }
					 *= 2
					 = newArray(.elemType, )
					 := sliceHeader{data: , len: , cap: }
					copySlice(.elemType, , )
				}
				 := unsafe.Pointer(uintptr() + uintptr()*.size)
				// if srcLen is greater than idx, keep the original reference
				if  <=  {
					if .isElemPointerType {
						**(**unsafe.Pointer)(unsafe.Pointer(&)) = nil // initialize elem pointer
					} else {
						// assign new element to the slice
						typedmemmove(.elemType, , unsafe_New(.elemType))
					}
				}
				,  := .valueDecoder.Decode(, , , )
				if  != nil {
					return 0, 
				}
				 = 
				 = skipWhiteSpace(, )
				switch [] {
				case ']':
					.cap = 
					.len =  + 1
					.data = 
					 := (*sliceHeader)()
					.len =  + 1
					if .len > .cap {
						.data = newArray(.elemType, .len)
						.cap = .len
					}
					copySlice(.elemType, *, *)
					.releaseSlice()
					++
					return , nil
				case ',':
					++
				default:
					.cap = 
					.data = 
					.releaseSlice()
					return 0, errors.ErrInvalidCharacter([], "slice", )
				}
				++
			}
		case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
			return 0, .errNumber()
		default:
			return 0, errors.ErrUnexpectedEndOfJSON("slice", )
		}
	}
}

func ( *sliceDecoder) ( *RuntimeContext, ,  int64) ([][]byte, int64, error) {
	 := .Buf
	++
	if  > maxDecodeNestingDepth {
		return nil, 0, errors.ErrExceededMaxDepth([], )
	}

	 := [][]byte{}
	for {
		switch [] {
		case ' ', '\n', '\t', '\r':
			++
			continue
		case 'n':
			if  := validateNull(, );  != nil {
				return nil, 0, 
			}
			 += 4
			return [][]byte{nullbytes}, , nil
		case '[':
			++
			 = skipWhiteSpace(, )
			if [] == ']' {
				++
				return , , nil
			}
			 := 0
			for {
				, ,  := .Option.Path.node.Index()
				if  != nil {
					return nil, 0, 
				}
				if  {
					if  != nil {
						 := .Option.Path.node
						.Option.Path.node = 
						, ,  := .valueDecoder.DecodePath(, , )
						if  != nil {
							return nil, 0, 
						}
						.Option.Path.node = 
						 = append(, ...)
						 = 
					} else {
						 := 
						,  := skipValue(, , )
						if  != nil {
							return nil, 0, 
						}
						 = append(, [:])
						 = 
					}
				} else {
					,  := skipValue(, , )
					if  != nil {
						return nil, 0, 
					}
					 = 
				}
				 = skipWhiteSpace(, )
				switch [] {
				case ']':
					++
					return , , nil
				case ',':
					++
				default:
					return nil, 0, errors.ErrInvalidCharacter([], "slice", )
				}
				++
			}
		case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
			return nil, 0, .errNumber()
		default:
			return nil, 0, errors.ErrUnexpectedEndOfJSON("slice", )
		}
	}
}