github.com/batchcorp/thrift-iterator@v0.0.0-20220918180557-4c4a158fc6e9/binding/reflection/decode_slice.go (about)

     1  package reflection
     2  
     3  import (
     4  	"unsafe"
     5  	"github.com/batchcorp/thrift-iterator/spi"
     6  	"reflect"
     7  )
     8  
     9  type sliceDecoder struct {
    10  	sliceType   reflect.Type
    11  	elemType    reflect.Type
    12  	elemDecoder internalDecoder
    13  }
    14  
    15  func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter spi.Iterator) {
    16  	slice := (*sliceHeader)(ptr)
    17  	slice.Len = 0
    18  	offset := uintptr(0)
    19  	_, length := iter.ReadListHeader()
    20  
    21  	if slice.Cap < length {
    22  		newVal := reflect.MakeSlice(decoder.sliceType, 0, length)
    23  		slice.Data = unsafe.Pointer(newVal.Pointer())
    24  		slice.Cap = length
    25  	}
    26  
    27  	for i := 0; i < length; i++ {
    28  		decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
    29  		offset += decoder.elemType.Size()
    30  		slice.Len += 1
    31  	}
    32  }
    33  
    34  // grow grows the slice s so that it can hold extra more values, allocating
    35  // more capacity if needed. It also returns the old and new slice lengths.
    36  func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
    37  	newLen := slice.Len + 1
    38  	if newLen <= slice.Cap {
    39  		slice.Len = newLen
    40  		return
    41  	}
    42  	newCap := slice.Cap
    43  	if newCap == 0 {
    44  		newCap = 1
    45  	} else {
    46  		for newCap < newLen {
    47  			if slice.Len < 1024 {
    48  				newCap += newCap
    49  			} else {
    50  				newCap += newCap / 4
    51  			}
    52  		}
    53  	}
    54  	newVal := reflect.MakeSlice(sliceType, newLen, newCap)
    55  	dst := unsafe.Pointer(newVal.Pointer())
    56  	// copy old array into new array
    57  	originalBytesCount := slice.Len * int(elementType.Size())
    58  	srcSliceHeader := (unsafe.Pointer)(&sliceHeader{slice.Data, originalBytesCount, originalBytesCount})
    59  	dstSliceHeader := (unsafe.Pointer)(&sliceHeader{dst, originalBytesCount, originalBytesCount})
    60  	copy(*(*[]byte)(dstSliceHeader), *(*[]byte)(srcSliceHeader))
    61  	slice.Data = dst
    62  	slice.Len = newLen
    63  	slice.Cap = newCap
    64  }