github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/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 ( 8 "internal/unsafeheader" 9 "unsafe" 10 ) 11 12 // Swapper returns a function that swaps the elements in the provided 13 // slice. 14 // 15 // Swapper panics if the provided interface is not a slice. 16 func Swapper(slice interface{}) func(i, j int) { 17 v := ValueOf(slice) 18 if v.Kind() != Slice { 19 panic(&ValueError{Method: "Swapper", Kind: v.Kind()}) 20 } 21 // Fast path for slices of size 0 and 1. Nothing to swap. 22 switch v.Len() { 23 case 0: 24 return func(i, j int) { panic("reflect: slice index out of range") } 25 case 1: 26 return func(i, j int) { 27 if i != 0 || j != 0 { 28 panic("reflect: slice index out of range") 29 } 30 } 31 } 32 33 typ := v.Type().Elem().(*rtype) 34 size := typ.Size() 35 hasPtr := typ.ptrdata != 0 36 37 // Some common & small cases, without using memmove: 38 if hasPtr { 39 if size == ptrSize { 40 ps := *(*[]unsafe.Pointer)(v.ptr) 41 return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] } 42 } 43 if typ.Kind() == String { 44 ss := *(*[]string)(v.ptr) 45 return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] } 46 } 47 } else { 48 switch size { 49 case 8: 50 is := *(*[]int64)(v.ptr) 51 return func(i, j int) { is[i], is[j] = is[j], is[i] } 52 case 4: 53 is := *(*[]int32)(v.ptr) 54 return func(i, j int) { is[i], is[j] = is[j], is[i] } 55 case 2: 56 is := *(*[]int16)(v.ptr) 57 return func(i, j int) { is[i], is[j] = is[j], is[i] } 58 case 1: 59 is := *(*[]int8)(v.ptr) 60 return func(i, j int) { is[i], is[j] = is[j], is[i] } 61 } 62 } 63 64 s := (*unsafeheader.Slice)(v.ptr) 65 tmp := unsafe_New(typ) // swap scratch space 66 67 return func(i, j int) { 68 if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) { 69 panic("reflect: slice index out of range") 70 } 71 val1 := arrayAt(s.Data, i, size, "i < s.Len") 72 val2 := arrayAt(s.Data, j, size, "j < s.Len") 73 typedmemmove(typ, tmp, val1) 74 typedmemmove(typ, val1, val2) 75 typedmemmove(typ, val2, tmp) 76 } 77 }