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 }