mirror of
https://github.com/golang/go
synced 2024-11-02 11:50:30 +00:00
reflect: add Value.SetZero
The v.SetZero method is a faster equivalent of v.Set(Zero(v.Type())). Performance: Direct CachedZero NewZero SetZero/Bool 2.20ns ± 0% 8.97ns ± 5% 11.4ns ± 1% SetZero/Int 3.08ns ± 1% 9.06ns ± 1% 11.5ns ± 0% SetZero/Uint 2.88ns ± 1% 9.04ns ± 1% 11.7ns ± 5% SetZero/Float 2.65ns ± 2% 9.05ns ± 1% 11.5ns ± 1% SetZero/Complex 2.68ns ± 3% 9.31ns ± 1% 11.7ns ± 1% SetZero/Array 6.69ns ± 4% 9.32ns ± 1% 11.8ns ± 1% SetZero/Chan 3.31ns ± 1% 6.19ns ± 1% 8.20ns ± 1% SetZero/Func 3.32ns ± 1% 6.20ns ± 0% 8.24ns ± 1% SetZero/Interface 2.66ns ± 1% 9.31ns ± 1% 11.8ns ± 1% SetZero/Map 3.31ns ± 1% 6.21ns ± 2% 8.19ns ± 1% SetZero/Pointer 3.30ns ± 1% 6.22ns ± 1% 8.17ns ± 1% SetZero/Slice 2.90ns ± 4% 9.13ns ± 1% 11.6ns ± 1% SetZero/String 3.11ns ± 1% 9.30ns ± 1% 11.8ns ± 2% SetZero/Struct 6.37ns ± 1% 9.18ns ± 4% 11.5ns ± 1% where: * Direct is measuring Value.SetZero * CachedZero is measuring Value.Set with a cached Zero value * NewZero is measuring Value.Set with a new Zero value Fixes #52376 Change-Id: I793ca723aa97627824c5f5b356b2da30c8e46d71 Reviewed-on: https://go-review.googlesource.com/c/go/+/411476 Auto-Submit: Joseph Tsai <joetsai@digital-static.net> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Joseph Tsai <joetsai@digital-static.net> Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Daniel Martí <mvdan@mvdan.cc> Reviewed-by: Dan Kortschak <dan@kortschak.io>
This commit is contained in:
parent
e0ec1d6770
commit
bc1d0d8eb1
3 changed files with 108 additions and 2 deletions
1
api/next/52376.txt
Normal file
1
api/next/52376.txt
Normal file
|
@ -0,0 +1 @@
|
|||
pkg reflect, method (Value) SetZero() #52376
|
|
@ -1374,6 +1374,8 @@ func TestIsZero(t *testing.T) {
|
|||
{[3][]int{{1}}, false}, // incomparable array
|
||||
{[1 << 12]byte{}, true},
|
||||
{[1 << 12]byte{1}, false},
|
||||
{[3]Value{}, true},
|
||||
{[3]Value{{}, ValueOf(0), {}}, false},
|
||||
// Chan
|
||||
{(chan string)(nil), true},
|
||||
{make(chan string), false},
|
||||
|
@ -1406,6 +1408,8 @@ func TestIsZero(t *testing.T) {
|
|||
{struct{ p *int }{new(int)}, false}, // direct pointer struct
|
||||
{struct{ s []int }{}, true}, // incomparable struct
|
||||
{struct{ s []int }{[]int{1}}, false}, // incomparable struct
|
||||
{struct{ Value }{}, true},
|
||||
{struct{ Value }{ValueOf(0)}, false},
|
||||
// UnsafePointer
|
||||
{(unsafe.Pointer)(nil), true},
|
||||
{(unsafe.Pointer)(new(int)), false},
|
||||
|
@ -1425,6 +1429,13 @@ func TestIsZero(t *testing.T) {
|
|||
if !Zero(TypeOf(tt.x)).IsZero() {
|
||||
t.Errorf("%d: IsZero(Zero(TypeOf((%s)(%+v)))) is false", i, x.Kind(), tt.x)
|
||||
}
|
||||
|
||||
p := New(x.Type()).Elem()
|
||||
p.Set(x)
|
||||
p.SetZero()
|
||||
if !p.IsZero() {
|
||||
t.Errorf("%d: IsZero((%s)(%+v)) is true after SetZero", i, p.Kind(), tt.x)
|
||||
}
|
||||
}
|
||||
|
||||
func() {
|
||||
|
@ -1456,6 +1467,46 @@ func BenchmarkIsZero(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkSetZero(b *testing.B) {
|
||||
source := ValueOf(new(struct {
|
||||
Bool bool
|
||||
Int int64
|
||||
Uint uint64
|
||||
Float float64
|
||||
Complex complex128
|
||||
Array [4]Value
|
||||
Chan chan Value
|
||||
Func func() Value
|
||||
Interface interface{ String() string }
|
||||
Map map[string]Value
|
||||
Pointer *Value
|
||||
Slice []Value
|
||||
String string
|
||||
Struct Value
|
||||
})).Elem()
|
||||
|
||||
for i := 0; i < source.NumField(); i++ {
|
||||
name := source.Type().Field(i).Name
|
||||
value := source.Field(i)
|
||||
zero := Zero(value.Type())
|
||||
b.Run(name+"/Direct", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
value.SetZero()
|
||||
}
|
||||
})
|
||||
b.Run(name+"/CachedZero", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
value.Set(zero)
|
||||
}
|
||||
})
|
||||
b.Run(name+"/NewZero", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
value.Set(Zero(value.Type()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterfaceExtraction(t *testing.T) {
|
||||
var s struct {
|
||||
W io.Writer
|
||||
|
|
|
@ -1615,12 +1615,66 @@ func (v Value) IsZero() bool {
|
|||
}
|
||||
return true
|
||||
default:
|
||||
// This should never happens, but will act as a safeguard for
|
||||
// later, as a default value doesn't makes sense here.
|
||||
// This should never happen, but will act as a safeguard for later,
|
||||
// as a default value doesn't makes sense here.
|
||||
panic(&ValueError{"reflect.Value.IsZero", v.Kind()})
|
||||
}
|
||||
}
|
||||
|
||||
// SetZero sets v to be the zero value of v's type.
|
||||
// It panics if CanSet returns false.
|
||||
func (v Value) SetZero() {
|
||||
v.mustBeAssignable()
|
||||
switch v.kind() {
|
||||
case Bool:
|
||||
*(*bool)(v.ptr) = false
|
||||
case Int:
|
||||
*(*int)(v.ptr) = 0
|
||||
case Int8:
|
||||
*(*int8)(v.ptr) = 0
|
||||
case Int16:
|
||||
*(*int16)(v.ptr) = 0
|
||||
case Int32:
|
||||
*(*int32)(v.ptr) = 0
|
||||
case Int64:
|
||||
*(*int64)(v.ptr) = 0
|
||||
case Uint:
|
||||
*(*uint)(v.ptr) = 0
|
||||
case Uint8:
|
||||
*(*uint8)(v.ptr) = 0
|
||||
case Uint16:
|
||||
*(*uint16)(v.ptr) = 0
|
||||
case Uint32:
|
||||
*(*uint32)(v.ptr) = 0
|
||||
case Uint64:
|
||||
*(*uint64)(v.ptr) = 0
|
||||
case Uintptr:
|
||||
*(*uintptr)(v.ptr) = 0
|
||||
case Float32:
|
||||
*(*float32)(v.ptr) = 0
|
||||
case Float64:
|
||||
*(*float64)(v.ptr) = 0
|
||||
case Complex64:
|
||||
*(*complex64)(v.ptr) = 0
|
||||
case Complex128:
|
||||
*(*complex128)(v.ptr) = 0
|
||||
case String:
|
||||
*(*string)(v.ptr) = ""
|
||||
case Slice:
|
||||
*(*unsafeheader.Slice)(v.ptr) = unsafeheader.Slice{}
|
||||
case Interface:
|
||||
*(*[2]unsafe.Pointer)(v.ptr) = [2]unsafe.Pointer{}
|
||||
case Chan, Func, Map, Pointer, UnsafePointer:
|
||||
*(*unsafe.Pointer)(v.ptr) = nil
|
||||
case Array, Struct:
|
||||
typedmemclr(v.typ, v.ptr)
|
||||
default:
|
||||
// This should never happen, but will act as a safeguard for later,
|
||||
// as a default value doesn't makes sense here.
|
||||
panic(&ValueError{"reflect.Value.SetZero", v.Kind()})
|
||||
}
|
||||
}
|
||||
|
||||
// Kind returns v's Kind.
|
||||
// If v is the zero Value (IsValid returns false), Kind returns Invalid.
|
||||
func (v Value) Kind() Kind {
|
||||
|
|
Loading…
Reference in a new issue