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