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  }