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