...

Source file src/pkg/reflect/swapper.go

     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.ptrdata != 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, "i < s.Len")
    69			val2 := arrayAt(s.Data, j, size, "j < s.Len")
    70			typedmemmove(typ, tmp, val1)
    71			typedmemmove(typ, val1, val2)
    72			typedmemmove(typ, val2, tmp)
    73		}
    74	}
    75	

View as plain text