|  | // Copyright 2016 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package reflectlite | 
|  |  | 
|  | import ( | 
|  | "internal/goarch" | 
|  | "internal/unsafeheader" | 
|  | "unsafe" | 
|  | ) | 
|  |  | 
|  | // Swapper returns a function that swaps the elements in the provided | 
|  | // slice. | 
|  | // | 
|  | // Swapper panics if the provided interface is not a slice. | 
|  | func Swapper(slice any) func(i, j int) { | 
|  | v := ValueOf(slice) | 
|  | if v.Kind() != Slice { | 
|  | panic(&ValueError{Method: "Swapper", Kind: v.Kind()}) | 
|  | } | 
|  | // Fast path for slices of size 0 and 1. Nothing to swap. | 
|  | switch v.Len() { | 
|  | case 0: | 
|  | return func(i, j int) { panic("reflect: slice index out of range") } | 
|  | case 1: | 
|  | return func(i, j int) { | 
|  | if i != 0 || j != 0 { | 
|  | panic("reflect: slice index out of range") | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | typ := v.Type().Elem().(*rtype) | 
|  | size := typ.Size() | 
|  | hasPtr := typ.ptrdata != 0 | 
|  |  | 
|  | // Some common & small cases, without using memmove: | 
|  | if hasPtr { | 
|  | if size == goarch.PtrSize { | 
|  | ps := *(*[]unsafe.Pointer)(v.ptr) | 
|  | return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] } | 
|  | } | 
|  | if typ.Kind() == String { | 
|  | ss := *(*[]string)(v.ptr) | 
|  | return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] } | 
|  | } | 
|  | } else { | 
|  | switch size { | 
|  | case 8: | 
|  | is := *(*[]int64)(v.ptr) | 
|  | return func(i, j int) { is[i], is[j] = is[j], is[i] } | 
|  | case 4: | 
|  | is := *(*[]int32)(v.ptr) | 
|  | return func(i, j int) { is[i], is[j] = is[j], is[i] } | 
|  | case 2: | 
|  | is := *(*[]int16)(v.ptr) | 
|  | return func(i, j int) { is[i], is[j] = is[j], is[i] } | 
|  | case 1: | 
|  | is := *(*[]int8)(v.ptr) | 
|  | return func(i, j int) { is[i], is[j] = is[j], is[i] } | 
|  | } | 
|  | } | 
|  |  | 
|  | s := (*unsafeheader.Slice)(v.ptr) | 
|  | tmp := unsafe_New(typ) // swap scratch space | 
|  |  | 
|  | return func(i, j int) { | 
|  | if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) { | 
|  | panic("reflect: slice index out of range") | 
|  | } | 
|  | val1 := arrayAt(s.Data, i, size, "i < s.Len") | 
|  | val2 := arrayAt(s.Data, j, size, "j < s.Len") | 
|  | typedmemmove(typ, tmp, val1) | 
|  | typedmemmove(typ, val1, val2) | 
|  | typedmemmove(typ, val2, tmp) | 
|  | } | 
|  | } |