diff --git a/src/reflect/swapper.go b/src/reflect/swapper.go index 2f880167..6b8b26a3 100644 --- a/src/reflect/swapper.go +++ b/src/reflect/swapper.go @@ -1,5 +1,40 @@ package reflect +import "unsafe" + +// Some of code here has been copied from the Go sources: +// https://github.com/golang/go/blob/go1.15.2/src/reflect/swapper.go +// It has the following copyright note: +// +// 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. + func Swapper(slice interface{}) func(i, j int) { - panic("unimplemented: reflect.Swapper") + v := ValueOf(slice) + if v.Kind() != Slice { + panic(&ValueError{Method: "Swapper"}) + } + + // Just return Nop func if nothing to swap. + if v.Len() < 2 { + return func(i, j int) {} + } + + typ := v.Type().Elem() + size := typ.Size() + + header := (*SliceHeader)(v.value) + tmp := unsafe.Pointer(&make([]byte, size)[0]) + + return func(i, j int) { + if uint(i) >= uint(header.Len) || uint(j) >= uint(header.Len) { + panic("reflect: slice index out of range") + } + val1 := unsafe.Pointer(header.Data + uintptr(i)*size) + val2 := unsafe.Pointer(header.Data + uintptr(j)*size) + memcpy(tmp, val1, size) + memcpy(val1, val2, size) + memcpy(val2, tmp, size) + } } diff --git a/testdata/sort.go b/testdata/sort.go new file mode 100644 index 00000000..33647fd6 --- /dev/null +++ b/testdata/sort.go @@ -0,0 +1,183 @@ +package main + +import "sort" + +// sort.Slice implicitly uses reflect.Swapper + +func strings() { + data := []string{"aaaa", "cccc", "bbb", "fff", "ggg"} + sort.Slice(data, func(i, j int) bool { + return data[i] > data[j] + }) + println("strings") + for _, d := range data { + println(d) + } +} + +func int64s() { + sd := []int64{1, 6, 3, 2, 1923, 123, -123, -29, 3, 0, 1} + sort.Slice(sd, func(i, j int) bool { + return sd[i] > sd[j] + }) + println("int64s") + for _, d := range sd { + println(d) + } + + ud := []uint64{1, 6, 3, 2, 1923, 123, 29, 3, 0, 1} + sort.Slice(ud, func(i, j int) bool { + return ud[i] > ud[j] + }) + println("uint64s") + for _, d := range ud { + println(d) + } +} + +func int32s() { + sd := []int32{1, 6, 3, 2, 1923, 123, -123, -29, 3, 0, 1} + sort.Slice(sd, func(i, j int) bool { + return sd[i] > sd[j] + }) + println("int32s") + for _, d := range sd { + println(d) + } + + ud := []uint32{1, 6, 3, 2, 1923, 123, 29, 3, 0, 1} + sort.Slice(ud, func(i, j int) bool { + return ud[i] > ud[j] + }) + println("uint32s") + for _, d := range ud { + println(d) + } +} + +func int16s() { + sd := []int16{1, 6, 3, 2, 1923, 123, -123, -29, 3, 0, 1} + sort.Slice(sd, func(i, j int) bool { + return sd[i] > sd[j] + }) + println("int16s") + for _, d := range sd { + println(d) + } + + ud := []uint16{1, 6, 3, 2, 1923, 123, 29, 3, 0, 1} + sort.Slice(ud, func(i, j int) bool { + return ud[i] > ud[j] + }) + println("uint16s") + for _, d := range ud { + println(d) + } +} + +func int8s() { + sd := []int8{1, 6, 3, 2, 123, -123, -29, 3, 0, 1} + sort.Slice(sd, func(i, j int) bool { + return sd[i] > sd[j] + }) + println("int8s") + for _, d := range sd { + println(d) + } + + ud := []uint8{1, 6, 3, 2, 123, 29, 3, 0, 1} + sort.Slice(ud, func(i, j int) bool { + return ud[i] > ud[j] + }) + println("uint8s") + for _, d := range ud { + println(d) + } +} + +func ints() { + sd := []int{1, 6, 3, 2, 123, -123, -29, 3, 0, 1} + sort.Slice(sd, func(i, j int) bool { + return sd[i] > sd[j] + }) + println("ints") + for _, d := range sd { + println(d) + } + + ud := []uint{1, 6, 3, 2, 123, 29, 3, 0, 1} + sort.Slice(ud, func(i, j int) bool { + return ud[i] > ud[j] + }) + println("uints") + for _, d := range ud { + println(d) + } +} + +func structs() { + type s struct { + name string + a uint64 + b uint32 + c uint16 + d int + e *struct { + aa uint16 + bb int + } + } + + data := []s{ + { + name: "struct 1", + d: 100, + e: &struct { + aa uint16 + bb int + }{aa: 123, bb: -10}, + }, + { + name: "struct 2", + d: 1, + e: &struct { + aa uint16 + bb int + }{aa: 15, bb: 10}, + }, + { + name: "struct 3", + d: 10, + e: &struct { + aa uint16 + bb int + }{aa: 31, bb: -1030}, + }, + { + name: "struct 4", + e: &struct { + aa uint16 + bb int + }{}, + }, + } + sort.Slice(data, func(i, j int) bool { + di := data[i] + dj := data[j] + return di.d*di.e.bb > dj.d*dj.e.bb + }) + println("structs") + for _, d := range data { + println(d.name) + } +} + +func main() { + strings() + int64s() + int32s() + int16s() + int8s() + ints() + structs() +} diff --git a/testdata/sort.txt b/testdata/sort.txt new file mode 100644 index 00000000..74d2ca0c --- /dev/null +++ b/testdata/sort.txt @@ -0,0 +1,122 @@ +strings +ggg +fff +cccc +bbb +aaaa +int64s +1923 +123 +6 +3 +3 +2 +1 +1 +0 +-29 +-123 +uint64s +1923 +123 +29 +6 +3 +3 +2 +1 +1 +0 +int32s +1923 +123 +6 +3 +3 +2 +1 +1 +0 +-29 +-123 +uint32s +1923 +123 +29 +6 +3 +3 +2 +1 +1 +0 +int16s +1923 +123 +6 +3 +3 +2 +1 +1 +0 +-29 +-123 +uint16s +1923 +123 +29 +6 +3 +3 +2 +1 +1 +0 +int8s +123 +6 +3 +3 +2 +1 +1 +0 +-29 +-123 +uint8s +123 +29 +6 +3 +3 +2 +1 +1 +0 +ints +123 +6 +3 +3 +2 +1 +1 +0 +-29 +-123 +uints +123 +29 +6 +3 +3 +2 +1 +1 +0 +structs +struct 2 +struct 4 +struct 1 +struct 3