...

Source file src/reflect/swapper.go

Documentation: 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 (
		 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