...
Run Format

Source file src/reflect/swapper.go

  // 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.
  
  package reflect
  
  import "unsafe"
  
  // Swapper returns a function that swaps the elements in the provided
  // slice.
  //
  // Swapper panics if the provided interface is not a slice.
  func Swapper(slice interface{}) func(i, j int) {
  	v := ValueOf(slice)
  	if v.Kind() != Slice {
  		panic(&ValueError{Method: "Swapper", Kind: v.Kind()})
  	}
  	// Fast path for slices of size 0 and 1. Nothing to swap.
  	switch v.Len() {
  	case 0:
  		return func(i, j int) { panic("reflect: slice index out of range") }
  	case 1:
  		return func(i, j int) {
  			if i != 0 || j != 0 {
  				panic("reflect: slice index out of range")
  			}
  		}
  	}
  
  	typ := v.Type().Elem().(*rtype)
  	size := typ.Size()
  	hasPtr := typ.kind&kindNoPointers == 0
  
  	// Some common & small cases, without using memmove:
  	if hasPtr {
  		if size == ptrSize {
  			ps := *(*[]unsafe.Pointer)(v.ptr)
  			return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] }
  		}
  		if typ.Kind() == String {
  			ss := *(*[]string)(v.ptr)
  			return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] }
  		}
  	} else {
  		switch size {
  		case 8:
  			is := *(*[]int64)(v.ptr)
  			return func(i, j int) { is[i], is[j] = is[j], is[i] }
  		case 4:
  			is := *(*[]int32)(v.ptr)
  			return func(i, j int) { is[i], is[j] = is[j], is[i] }
  		case 2:
  			is := *(*[]int16)(v.ptr)
  			return func(i, j int) { is[i], is[j] = is[j], is[i] }
  		case 1:
  			is := *(*[]int8)(v.ptr)
  			return func(i, j int) { is[i], is[j] = is[j], is[i] }
  		}
  	}
  
  	s := (*sliceHeader)(v.ptr)
  	tmp := unsafe_New(typ) // swap scratch space
  
  	return func(i, j int) {
  		if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) {
  			panic("reflect: slice index out of range")
  		}
  		val1 := arrayAt(s.Data, i, size)
  		val2 := arrayAt(s.Data, j, size)
  		typedmemmove(typ, tmp, val1)
  		typedmemmove(typ, val1, val2)
  		typedmemmove(typ, val2, tmp)
  	}
  }
  

View as plain text