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 }