mirror of
https://github.com/golang/go
synced 2024-11-12 07:00:21 -07:00
sort, internal/reflectlite: flesh out reflectlite enough for use by sort
Now the net package is back to no longer depending on unicode. And lock that in with a test. Fixes #30440 Change-Id: I18b89b02f7d96488783adc07308da990f505affd Reviewed-on: https://go-review.googlesource.com/c/go/+/169137 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
f0e0be6e90
commit
39a51a4b0d
@ -1888,7 +1888,7 @@ func TestGoListTest(t *testing.T) {
|
||||
tg.grepStdout(`^runtime/cgo$`, "missing runtime/cgo")
|
||||
|
||||
tg.run("list", "-deps", "-f", "{{if .DepOnly}}{{.ImportPath}}{{end}}", "sort")
|
||||
tg.grepStdout(`^reflect$`, "missing reflect")
|
||||
tg.grepStdout(`^internal/reflectlite$`, "missing internal/reflectlite")
|
||||
tg.grepStdoutNot(`^sort`, "unexpected sort")
|
||||
}
|
||||
|
||||
|
@ -969,6 +969,13 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p *
|
||||
return p
|
||||
}
|
||||
|
||||
// The sort package depends on internal/reflectlite, but during bootstrap
|
||||
// the path rewriting causes the normal internal checks to fail.
|
||||
// Instead, just ignore the internal rules during bootstrap.
|
||||
if p.Standard && strings.HasPrefix(importerPath, "bootstrap/") {
|
||||
return p
|
||||
}
|
||||
|
||||
// The stack includes p.ImportPath.
|
||||
// If that's the only thing on the stack, we started
|
||||
// with a name given on the command line, not an
|
||||
|
@ -120,7 +120,7 @@ var pkgDeps = map[string][]string{
|
||||
"image/color/palette": {"L2", "image/color"},
|
||||
"internal/fmtsort": {"reflect", "sort"},
|
||||
"reflect": {"L2"},
|
||||
"sort": {"reflect"},
|
||||
"sort": {"internal/reflectlite"},
|
||||
|
||||
"L3": {
|
||||
"L2",
|
||||
@ -563,11 +563,12 @@ func TestDependencies(t *testing.T) {
|
||||
// these dependency paths:
|
||||
badPaths := []struct{ from, to string }{
|
||||
{"net", "unicode"},
|
||||
{"os", "unicode"},
|
||||
}
|
||||
|
||||
for _, path := range badPaths {
|
||||
if how := depPath(path.from, path.to); how != "" {
|
||||
t.Logf("TODO(issue 30440): policy violation: %s", how)
|
||||
t.Errorf("policy violation: %s", how)
|
||||
}
|
||||
}
|
||||
|
||||
@ -585,6 +586,11 @@ func findImports(pkg string) ([]string, error) {
|
||||
var haveImport = map[string]bool{}
|
||||
for _, file := range files {
|
||||
name := file.Name()
|
||||
if name == "slice_pre113.go" {
|
||||
// This file is ignored by build tags which aren't
|
||||
// handled by this findImports func.
|
||||
continue
|
||||
}
|
||||
if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
|
||||
continue
|
||||
}
|
||||
|
74
src/internal/reflectlite/swapper.go
Normal file
74
src/internal/reflectlite/swapper.go
Normal file
@ -0,0 +1,74 @@
|
||||
// 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 reflectlite
|
||||
|
||||
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.ptrdata != 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, "i < s.Len")
|
||||
val2 := arrayAt(s.Data, j, size, "j < s.Len")
|
||||
typedmemmove(typ, tmp, val1)
|
||||
typedmemmove(typ, val1, val2)
|
||||
typedmemmove(typ, val2, tmp)
|
||||
}
|
||||
}
|
@ -35,6 +35,10 @@ type Type interface {
|
||||
// will be the empty string.
|
||||
PkgPath() string
|
||||
|
||||
// Size returns the number of bytes needed to store
|
||||
// a value of the given type; it is analogous to unsafe.Sizeof.
|
||||
Size() uintptr
|
||||
|
||||
// Kind returns the specific kind of this type.
|
||||
Kind() Kind
|
||||
|
||||
@ -482,8 +486,12 @@ func (t *rtype) String() string {
|
||||
return s
|
||||
}
|
||||
|
||||
func (t *rtype) Size() uintptr { return t.size }
|
||||
|
||||
func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
|
||||
|
||||
func (t *rtype) pointers() bool { return t.ptrdata != 0 }
|
||||
|
||||
func (t *rtype) common() *rtype { return t }
|
||||
|
||||
func (t *rtype) exportedMethods() []method {
|
||||
|
@ -9,6 +9,8 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
|
||||
|
||||
// Value is the reflection interface to a Go value.
|
||||
//
|
||||
// Not all methods apply to all kinds of values. Restrictions,
|
||||
@ -84,6 +86,18 @@ func (f flag) ro() flag {
|
||||
return 0
|
||||
}
|
||||
|
||||
// pointer returns the underlying pointer represented by v.
|
||||
// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
|
||||
func (v Value) pointer() unsafe.Pointer {
|
||||
if v.typ.size != ptrSize || !v.typ.pointers() {
|
||||
panic("can't call pointer on a non-pointer Value")
|
||||
}
|
||||
if v.flag&flagIndir != 0 {
|
||||
return *(*unsafe.Pointer)(v.ptr)
|
||||
}
|
||||
return v.ptr
|
||||
}
|
||||
|
||||
// packEface converts v to the empty interface.
|
||||
func packEface(v Value) interface{} {
|
||||
t := v.typ
|
||||
@ -316,6 +330,32 @@ func (v Value) Kind() Kind {
|
||||
return v.kind()
|
||||
}
|
||||
|
||||
// implemented in runtime:
|
||||
func chanlen(unsafe.Pointer) int
|
||||
func maplen(unsafe.Pointer) int
|
||||
|
||||
// Len returns v's length.
|
||||
// It panics if v's Kind is not Array, Chan, Map, Slice, or String.
|
||||
func (v Value) Len() int {
|
||||
k := v.kind()
|
||||
switch k {
|
||||
case Array:
|
||||
tt := (*arrayType)(unsafe.Pointer(v.typ))
|
||||
return int(tt.len)
|
||||
case Chan:
|
||||
return chanlen(v.pointer())
|
||||
case Map:
|
||||
return maplen(v.pointer())
|
||||
case Slice:
|
||||
// Slice is bigger than a word; assume flagIndir.
|
||||
return (*sliceHeader)(v.ptr).Len
|
||||
case String:
|
||||
// String is bigger than a word; assume flagIndir.
|
||||
return (*stringHeader)(v.ptr).Len
|
||||
}
|
||||
panic(&ValueError{"reflect.Value.Len", v.kind()})
|
||||
}
|
||||
|
||||
// NumMethod returns the number of exported methods in the value's method set.
|
||||
func (v Value) numMethod() int {
|
||||
if v.typ == nil {
|
||||
@ -427,6 +467,17 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value
|
||||
panic(context + ": value of type " + v.typ.String() + " is not assignable to type " + dst.String())
|
||||
}
|
||||
|
||||
// arrayAt returns the i-th element of p,
|
||||
// an array whose elements are eltSize bytes wide.
|
||||
// The array pointed at by p must have at least i+1 elements:
|
||||
// it is invalid (but impossible to check here) to pass i >= len,
|
||||
// because then the result will point outside the array.
|
||||
// whySafe must explain why i < len. (Passing "i < len" is fine;
|
||||
// the benefit is to surface this assumption at the call site.)
|
||||
func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer {
|
||||
return add(p, uintptr(i)*eltSize, "i < len")
|
||||
}
|
||||
|
||||
func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer)
|
||||
|
||||
// typedmemmove copies a value of type t to dst from src.
|
||||
|
@ -678,6 +678,14 @@ func reflect_chanlen(c *hchan) int {
|
||||
return int(c.qcount)
|
||||
}
|
||||
|
||||
//go:linkname reflectlite_chanlen internal/reflectlite.chanlen
|
||||
func reflectlite_chanlen(c *hchan) int {
|
||||
if c == nil {
|
||||
return 0
|
||||
}
|
||||
return int(c.qcount)
|
||||
}
|
||||
|
||||
//go:linkname reflect_chancap reflect.chancap
|
||||
func reflect_chancap(c *hchan) int {
|
||||
if c == nil {
|
||||
|
@ -1371,6 +1371,18 @@ func reflect_maplen(h *hmap) int {
|
||||
return h.count
|
||||
}
|
||||
|
||||
//go:linkname reflectlite_maplen internal/reflectlite.maplen
|
||||
func reflectlite_maplen(h *hmap) int {
|
||||
if h == nil {
|
||||
return 0
|
||||
}
|
||||
if raceenabled {
|
||||
callerpc := getcallerpc()
|
||||
racereadpc(unsafe.Pointer(h), callerpc, funcPC(reflect_maplen))
|
||||
}
|
||||
return h.count
|
||||
}
|
||||
|
||||
//go:linkname reflect_ismapkey reflect.ismapkey
|
||||
func reflect_ismapkey(t *_type) bool {
|
||||
return ismapkey(t)
|
||||
|
@ -2,11 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !compiler_bootstrap go1.8
|
||||
// +build !compiler_bootstrap go1.13
|
||||
|
||||
package sort
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"internal/reflectlite"
|
||||
)
|
||||
|
||||
// Slice sorts the provided slice given the provided less function.
|
||||
//
|
||||
@ -15,8 +17,8 @@ import "reflect"
|
||||
//
|
||||
// The function panics if the provided interface is not a slice.
|
||||
func Slice(slice interface{}, less func(i, j int) bool) {
|
||||
rv := reflect.ValueOf(slice)
|
||||
swap := reflect.Swapper(slice)
|
||||
rv := reflectlite.ValueOf(slice)
|
||||
swap := reflectlite.Swapper(slice)
|
||||
length := rv.Len()
|
||||
quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length))
|
||||
}
|
||||
@ -26,8 +28,8 @@ func Slice(slice interface{}, less func(i, j int) bool) {
|
||||
//
|
||||
// The function panics if the provided interface is not a slice.
|
||||
func SliceStable(slice interface{}, less func(i, j int) bool) {
|
||||
rv := reflect.ValueOf(slice)
|
||||
swap := reflect.Swapper(slice)
|
||||
rv := reflectlite.ValueOf(slice)
|
||||
swap := reflectlite.Swapper(slice)
|
||||
stable_func(lessSwap{less, swap}, rv.Len())
|
||||
}
|
||||
|
||||
@ -35,7 +37,7 @@ func SliceStable(slice interface{}, less func(i, j int) bool) {
|
||||
//
|
||||
// The function panics if the provided interface is not a slice.
|
||||
func SliceIsSorted(slice interface{}, less func(i, j int) bool) bool {
|
||||
rv := reflect.ValueOf(slice)
|
||||
rv := reflectlite.ValueOf(slice)
|
||||
n := rv.Len()
|
||||
for i := n - 1; i > 0; i-- {
|
||||
if less(i, i-1) {
|
||||
|
46
src/sort/slice_pre113.go
Normal file
46
src/sort/slice_pre113.go
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
// +build go1.8,!go1.13
|
||||
|
||||
package sort
|
||||
|
||||
import "reflect"
|
||||
|
||||
// Slice sorts the provided slice given the provided less function.
|
||||
//
|
||||
// The sort is not guaranteed to be stable. For a stable sort, use
|
||||
// SliceStable.
|
||||
//
|
||||
// The function panics if the provided interface is not a slice.
|
||||
func Slice(slice interface{}, less func(i, j int) bool) {
|
||||
rv := reflect.ValueOf(slice)
|
||||
swap := reflect.Swapper(slice)
|
||||
length := rv.Len()
|
||||
quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length))
|
||||
}
|
||||
|
||||
// SliceStable sorts the provided slice given the provided less
|
||||
// function while keeping the original order of equal elements.
|
||||
//
|
||||
// The function panics if the provided interface is not a slice.
|
||||
func SliceStable(slice interface{}, less func(i, j int) bool) {
|
||||
rv := reflect.ValueOf(slice)
|
||||
swap := reflect.Swapper(slice)
|
||||
stable_func(lessSwap{less, swap}, rv.Len())
|
||||
}
|
||||
|
||||
// SliceIsSorted tests whether a slice is sorted.
|
||||
//
|
||||
// The function panics if the provided interface is not a slice.
|
||||
func SliceIsSorted(slice interface{}, less func(i, j int) bool) bool {
|
||||
rv := reflect.ValueOf(slice)
|
||||
n := rv.Len()
|
||||
for i := n - 1; i > 0; i-- {
|
||||
if less(i, i-1) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
Loading…
Reference in New Issue
Block a user