mirror of
https://github.com/golang/go
synced 2024-11-14 21:00:28 -07:00
da382a3978
The new package "internal/unsafeheader" depends only on "unsafe", and provides declarations equivalent to reflect.StringHeader and reflect.SliceHeader but with Data fields of the proper unsafe.Pointer type (instead of uintptr). Unlike the types it replaces, the "internal/unsafeheader" package has a regression test to ensure that its header types remain equivalent to the declarations provided by the "reflect" package. Since "internal/unsafeheader" has almost no dependencies, it can be used in other low-level packages such as "syscall" and "reflect". This change is based on the corresponding x/sys change in CL 231177. Fixes #37805 Updates #19367 Change-Id: I7a6d93ef8dd6e235bcab94e7c47270aad047af31 Reviewed-on: https://go-review.googlesource.com/c/go/+/231223 Reviewed-by: Ian Lance Taylor <iant@golang.org>
78 lines
2.0 KiB
Go
78 lines
2.0 KiB
Go
// 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 reflect
|
|
|
|
import (
|
|
"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 interface{}) 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 == 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)
|
|
}
|
|
}
|