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