aboutsummaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorMichael Matloob <matloob@golang.org>2021-08-26 15:04:40 -0400
committerMichael Matloob <matloob@golang.org>2021-08-26 15:04:42 -0400
commitde83ef67acaaf5c2ce12dd831e8d3d04f02a6fc9 (patch)
treede1e9db916cb810d3360137a7b5ead7c00f7bce5 /src/reflect
parentde23549a3967ade982d848a5b6ae3cb3fa0dba45 (diff)
parent5e6a7e9b860d7c8f589eec3c123469ea8071689f (diff)
downloadgo-de83ef67acaaf5c2ce12dd831e8d3d04f02a6fc9.tar.gz
go-de83ef67acaaf5c2ce12dd831e8d3d04f02a6fc9.zip
[dev.cmdgo] all: merge master (5e6a7e9) into dev.cmdgo
Merge List: + 2021-08-26 5e6a7e9b86 embed: remove reference to global variables in docs + 2021-08-26 166b691b65 cmd/compile/internal/types2: remove need for instance (struct) + 2021-08-26 d6bdae33e9 cmd/compile/internal/types2: address some TODOs (cleanup) + 2021-08-26 770df2e18d crypto/tls: fix typo in PreferServerCipherSuites comment + 2021-08-26 a6ff433d6a cmd/go: pass -gcflags after other flags generated by the go command + 2021-08-25 4f2620285d cmd/compile/internal/types2: fix type set printing and add test + 2021-08-25 0ac64f6d70 cmd/compile/internal/types2: rename IsMethodSet to IsConstraint (cleanup) + 2021-08-25 4068fb6c21 cmd/compile: always accept 1.18 syntax but complain if not 1.18 + 2021-08-25 bf0bc4122f go/types, types2: don't re-evaluate context string for each function argument (optimization) + 2021-08-25 4158e88f64 cmd/compile/internal/syntax: fix position of type parameter field + 2021-08-25 647bef6c59 go/types: implement NewTypeList and use it instead of composite literals + 2021-08-25 6cf1d5d0fa cmd/compile: generic SSA rules for simplifying 2 and 3 operand integer arithmetic expressions + 2021-08-25 5baf60d472 bytes, strings: optimize Trim for single byte cutsets + 2021-08-25 3d667671ad cmd/compile: fix function contains no TParam in generic function + 2021-08-25 4f2ebfe34b cmd/compile: allow embed into any byte slice type + 2021-08-25 d2f002cb39 time/format: avoid growslice in time.String()/time.GoString() + 2021-08-25 08d4cc20ca cmd/compile: fix stencil call expression. + 2021-08-25 099b819085 cmd/compile: fix CheckSize() calculation for -G=3 and stencils + 2021-08-25 e1fcf8857e test: add test that caused gofrontend compiler crash + 2021-08-25 d37b8dedf7 test: add test case that gofrontend miscompiled + 2021-08-25 41b99dab0f os/user: don't skip TestLookupGroup if supported + 2021-08-25 de1c934b97 cmd/compile: fix checkptr false positive for (*[Big]T)(ptr)[:n:n] pattern + 2021-08-24 54cdef1f10 reflect: add MapIter.SetKey and MapIter.SetValue + 2021-08-24 5d863f89fe cmd/compile: simplify bad conversion check Change-Id: I29ab927f0e47f44d82f9307c642900f75f4f678f
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/all_test.go41
-rw-r--r--src/reflect/value.go62
2 files changed, 99 insertions, 4 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index df79f05807..40ac6a95fa 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -336,6 +336,47 @@ func TestSetValue(t *testing.T) {
}
}
+func TestMapIterSet(t *testing.T) {
+ m := make(map[string]interface{}, len(valueTests))
+ for _, tt := range valueTests {
+ m[tt.s] = tt.i
+ }
+ v := ValueOf(m)
+
+ k := New(v.Type().Key()).Elem()
+ e := New(v.Type().Elem()).Elem()
+
+ iter := v.MapRange()
+ for iter.Next() {
+ iter.SetKey(k)
+ iter.SetValue(e)
+ want := m[k.String()]
+ got := e.Interface()
+ if got != want {
+ t.Errorf("%q: want (%T) %v, got (%T) %v", k.String(), want, want, got, got)
+ }
+ if setkey, key := valueToString(k), valueToString(iter.Key()); setkey != key {
+ t.Errorf("MapIter.Key() = %q, MapIter.SetKey() = %q", key, setkey)
+ }
+ if setval, val := valueToString(e), valueToString(iter.Value()); setval != val {
+ t.Errorf("MapIter.Value() = %q, MapIter.SetValue() = %q", val, setval)
+ }
+ }
+
+ got := int(testing.AllocsPerRun(10, func() {
+ iter := v.MapRange()
+ for iter.Next() {
+ iter.SetKey(k)
+ iter.SetValue(e)
+ }
+ }))
+ // Making a *MapIter and making an hiter both allocate.
+ // Those should be the only two allocations.
+ if got != 2 {
+ t.Errorf("wanted 2 allocs, got %d", got)
+ }
+}
+
func TestCanSetField(t *testing.T) {
type embed struct{ x, X int }
type Embed struct{ x, X int }
diff --git a/src/reflect/value.go b/src/reflect/value.go
index de01f13825..a8274cc871 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -1578,13 +1578,40 @@ func (it *MapIter) Key() Value {
if it.it == nil {
panic("MapIter.Key called before Next")
}
- if mapiterkey(it.it) == nil {
+ iterkey := mapiterkey(it.it)
+ if iterkey == nil {
panic("MapIter.Key called on exhausted iterator")
}
t := (*mapType)(unsafe.Pointer(it.m.typ))
ktype := t.key
- return copyVal(ktype, it.m.flag.ro()|flag(ktype.Kind()), mapiterkey(it.it))
+ return copyVal(ktype, it.m.flag.ro()|flag(ktype.Kind()), iterkey)
+}
+
+// SetKey assigns dst to the key of the iterator's current map entry.
+// It is equivalent to dst.Set(it.Key()), but it avoids allocating a new Value.
+// As in Go, the key must be assignable to dst's type.
+func (it *MapIter) SetKey(dst Value) {
+ if it.it == nil {
+ panic("MapIter.SetKey called before Next")
+ }
+ iterkey := mapiterkey(it.it)
+ if iterkey == nil {
+ panic("MapIter.SetKey called on exhausted iterator")
+ }
+
+ dst.mustBeAssignable()
+ var target unsafe.Pointer
+ if dst.kind() == Interface {
+ target = dst.ptr
+ }
+
+ t := (*mapType)(unsafe.Pointer(it.m.typ))
+ ktype := t.key
+
+ key := Value{ktype, iterkey, it.m.flag | flag(ktype.Kind())}
+ key = key.assignTo("reflect.MapIter.SetKey", dst.typ, target)
+ typedmemmove(dst.typ, dst.ptr, key.ptr)
}
// Value returns the value of the iterator's current map entry.
@@ -1592,13 +1619,40 @@ func (it *MapIter) Value() Value {
if it.it == nil {
panic("MapIter.Value called before Next")
}
- if mapiterkey(it.it) == nil {
+ iterelem := mapiterelem(it.it)
+ if iterelem == nil {
panic("MapIter.Value called on exhausted iterator")
}
t := (*mapType)(unsafe.Pointer(it.m.typ))
vtype := t.elem
- return copyVal(vtype, it.m.flag.ro()|flag(vtype.Kind()), mapiterelem(it.it))
+ return copyVal(vtype, it.m.flag.ro()|flag(vtype.Kind()), iterelem)
+}
+
+// SetValue assigns dst to the value of the iterator's current map entry.
+// It is equivalent to dst.Set(it.Value()), but it avoids allocating a new Value.
+// As in Go, the value must be assignable to dst's type.
+func (it *MapIter) SetValue(dst Value) {
+ if it.it == nil {
+ panic("MapIter.SetValue called before Next")
+ }
+ iterelem := mapiterelem(it.it)
+ if iterelem == nil {
+ panic("MapIter.SetValue called on exhausted iterator")
+ }
+
+ dst.mustBeAssignable()
+ var target unsafe.Pointer
+ if dst.kind() == Interface {
+ target = dst.ptr
+ }
+
+ t := (*mapType)(unsafe.Pointer(it.m.typ))
+ vtype := t.elem
+
+ elem := Value{vtype, iterelem, it.m.flag | flag(vtype.Kind())}
+ elem = elem.assignTo("reflect.MapIter.SetValue", dst.typ, target)
+ typedmemmove(dst.typ, dst.ptr, elem.ptr)
}
// Next advances the map iterator and reports whether there is another