github.com/fisco-bcos/crypto@v0.0.0-20200202032121-bd8ab0b5d4f1/internal/reflectlite/swapper.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package reflectlite
     6  
     7  import "unsafe"
     8  
     9  // Swapper returns a function that swaps the elements in the provided
    10  // slice.
    11  //
    12  // Swapper panics if the provided interface is not a slice.
    13  func Swapper(slice interface{}) func(i, j int) {
    14  	v := ValueOf(slice)
    15  	if v.Kind() != Slice {
    16  		panic(&ValueError{Method: "Swapper", Kind: v.Kind()})
    17  	}
    18  	// Fast path for slices of size 0 and 1. Nothing to swap.
    19  	switch v.Len() {
    20  	case 0:
    21  		return func(i, j int) { panic("reflect: slice index out of range") }
    22  	case 1:
    23  		return func(i, j int) {
    24  			if i != 0 || j != 0 {
    25  				panic("reflect: slice index out of range")
    26  			}
    27  		}
    28  	}
    29  
    30  	typ := v.Type().Elem().(*rtype)
    31  	size := typ.Size()
    32  	hasPtr := typ.ptrdata != 0
    33  
    34  	// Some common & small cases, without using memmove:
    35  	if hasPtr {
    36  		if size == ptrSize {
    37  			ps := *(*[]unsafe.Pointer)(v.ptr)
    38  			return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] }
    39  		}
    40  		if typ.Kind() == String {
    41  			ss := *(*[]string)(v.ptr)
    42  			return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] }
    43  		}
    44  	} else {
    45  		switch size {
    46  		case 8:
    47  			is := *(*[]int64)(v.ptr)
    48  			return func(i, j int) { is[i], is[j] = is[j], is[i] }
    49  		case 4:
    50  			is := *(*[]int32)(v.ptr)
    51  			return func(i, j int) { is[i], is[j] = is[j], is[i] }
    52  		case 2:
    53  			is := *(*[]int16)(v.ptr)
    54  			return func(i, j int) { is[i], is[j] = is[j], is[i] }
    55  		case 1:
    56  			is := *(*[]int8)(v.ptr)
    57  			return func(i, j int) { is[i], is[j] = is[j], is[i] }
    58  		}
    59  	}
    60  
    61  	s := (*sliceHeader)(v.ptr)
    62  	tmp := unsafe_New(typ) // swap scratch space
    63  
    64  	return func(i, j int) {
    65  		if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) {
    66  			panic("reflect: slice index out of range")
    67  		}
    68  		val1 := arrayAt(s.Data, i, size, "i < s.Len")
    69  		val2 := arrayAt(s.Data, j, size, "j < s.Len")
    70  		typedmemmove(typ, tmp, val1)
    71  		typedmemmove(typ, val1, val2)
    72  		typedmemmove(typ, val2, tmp)
    73  	}
    74  }