| package jsoniter |
| |
| import ( |
| "fmt" |
| "io" |
| "reflect" |
| "unsafe" |
| ) |
| |
| func decoderOfSlice(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { |
| decoder := decoderOfType(cfg, prefix+"[slice]->", typ.Elem()) |
| return &sliceDecoder{typ, typ.Elem(), decoder} |
| } |
| |
| func encoderOfSlice(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { |
| encoder := encoderOfType(cfg, prefix+"[slice]->", typ.Elem()) |
| if typ.Elem().Kind() == reflect.Map { |
| encoder = &OptionalEncoder{encoder} |
| } |
| return &sliceEncoder{typ, typ.Elem(), encoder} |
| } |
| |
| type sliceEncoder struct { |
| sliceType reflect.Type |
| elemType reflect.Type |
| elemEncoder ValEncoder |
| } |
| |
| func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { |
| slice := (*sliceHeader)(ptr) |
| if slice.Data == nil { |
| stream.WriteNil() |
| return |
| } |
| if slice.Len == 0 { |
| stream.WriteEmptyArray() |
| return |
| } |
| stream.WriteArrayStart() |
| elemPtr := unsafe.Pointer(slice.Data) |
| encoder.elemEncoder.Encode(unsafe.Pointer(elemPtr), stream) |
| for i := 1; i < slice.Len; i++ { |
| stream.WriteMore() |
| elemPtr = unsafe.Pointer(uintptr(elemPtr) + encoder.elemType.Size()) |
| encoder.elemEncoder.Encode(unsafe.Pointer(elemPtr), stream) |
| } |
| stream.WriteArrayEnd() |
| if stream.Error != nil && stream.Error != io.EOF { |
| stream.Error = fmt.Errorf("%v: %s", encoder.sliceType, stream.Error.Error()) |
| } |
| } |
| |
| func (encoder *sliceEncoder) EncodeInterface(val interface{}, stream *Stream) { |
| WriteToStream(val, stream, encoder) |
| } |
| |
| func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool { |
| slice := (*sliceHeader)(ptr) |
| return slice.Len == 0 |
| } |
| |
| type sliceDecoder struct { |
| sliceType reflect.Type |
| elemType reflect.Type |
| elemDecoder ValDecoder |
| } |
| |
| // sliceHeader is a safe version of SliceHeader used within this package. |
| type sliceHeader struct { |
| Data unsafe.Pointer |
| Len int |
| Cap int |
| } |
| |
| func (decoder *sliceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { |
| decoder.doDecode(ptr, iter) |
| if iter.Error != nil && iter.Error != io.EOF { |
| iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error()) |
| } |
| } |
| |
| func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { |
| slice := (*sliceHeader)(ptr) |
| if iter.ReadNil() { |
| slice.Len = 0 |
| slice.Cap = 0 |
| slice.Data = nil |
| return |
| } |
| reuseSlice(slice, decoder.sliceType, 4) |
| slice.Len = 0 |
| offset := uintptr(0) |
| iter.ReadArrayCB(func(iter *Iterator) bool { |
| growOne(slice, decoder.sliceType, decoder.elemType) |
| decoder.elemDecoder.Decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter) |
| offset += decoder.elemType.Size() |
| return true |
| }) |
| } |
| |
| // grow grows the slice s so that it can hold extra more values, allocating |
| // more capacity if needed. It also returns the old and new slice lengths. |
| func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) { |
| newLen := slice.Len + 1 |
| if newLen <= slice.Cap { |
| slice.Len = newLen |
| return |
| } |
| newCap := slice.Cap |
| if newCap == 0 { |
| newCap = 1 |
| } else { |
| for newCap < newLen { |
| if slice.Len < 1024 { |
| newCap += newCap |
| } else { |
| newCap += newCap / 4 |
| } |
| } |
| } |
| newVal := reflect.MakeSlice(sliceType, newLen, newCap).Interface() |
| newValPtr := extractInterface(newVal).word |
| dst := (*sliceHeader)(newValPtr).Data |
| // copy old array into new array |
| originalBytesCount := slice.Len * int(elementType.Size()) |
| srcSliceHeader := (unsafe.Pointer)(&sliceHeader{slice.Data, originalBytesCount, originalBytesCount}) |
| dstSliceHeader := (unsafe.Pointer)(&sliceHeader{dst, originalBytesCount, originalBytesCount}) |
| copy(*(*[]byte)(dstSliceHeader), *(*[]byte)(srcSliceHeader)) |
| slice.Data = dst |
| slice.Len = newLen |
| slice.Cap = newCap |
| } |
| |
| func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) { |
| if expectedCap <= slice.Cap { |
| return |
| } |
| newVal := reflect.MakeSlice(sliceType, 0, expectedCap).Interface() |
| newValPtr := extractInterface(newVal).word |
| dst := (*sliceHeader)(newValPtr).Data |
| slice.Data = dst |
| slice.Cap = expectedCap |
| } |