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

View as plain text