github.com/nyan233/littlerpc@v0.4.6-0.20230316182519-0c8d5c48abaf/internal/reflect/slice.go (about)

     1  package reflect
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"unsafe"
     7  )
     8  
     9  // SliceHeader unsafe.Pointer使得编译器能够正确识别指针
    10  type SliceHeader struct {
    11  	Data unsafe.Pointer
    12  	Len  int
    13  	Cap  int
    14  }
    15  
    16  func SliceBackSpace(p interface{}, n uint) interface{} {
    17  	val := reflect.ValueOf(p)
    18  	if val.Kind() != reflect.Slice {
    19  		panic("type is not a slice")
    20  	}
    21  	sizeOf := val.Index(0).Type().Size()
    22  	eface := (*Eface)(unsafe.Pointer(&p))
    23  	header := (*SliceHeader)(eface.data)
    24  	header.Data = unsafe.Pointer((uintptr)(header.Data) - uintptr(n)*sizeOf)
    25  	header.Len += int(n)
    26  	header.Cap += int(n)
    27  	return *(*interface{})(unsafe.Pointer(eface))
    28  }
    29  
    30  // SliceIndex 支持负数索引
    31  func SliceIndex(p interface{}, n int) interface{} {
    32  	val := reflect.ValueOf(p)
    33  	if val.Kind() != reflect.Slice {
    34  		panic("type is not a slice")
    35  	}
    36  	// index out range?
    37  	length := val.Len()
    38  	if length-1 < n || length < -n {
    39  		panic(fmt.Sprintf("index out range [%d:%d]", n, length))
    40  	}
    41  	if -n > 0 {
    42  		return val.Index(length - (-n)).Interface()
    43  	} else {
    44  		return val.Index(n).Interface()
    45  	}
    46  }