diff options
author | Josh Bleecher Snyder <josharian@gmail.com> | 2021-05-21 09:43:58 -0700 |
---|---|---|
committer | Josh Bleecher Snyder <josharian@gmail.com> | 2021-09-07 23:09:06 +0000 |
commit | 07f623063ddf8216b03a4a17a27110d330e80c7e (patch) | |
tree | c6d35df3fa5ed8dffffba4ac862472fd344de515 /src/reflect/all_test.go | |
parent | a9a01a3fbdf70e7a9d914fe0b9b5ab1199fd74fe (diff) | |
download | go-07f623063ddf8216b03a4a17a27110d330e80c7e.tar.gz go-07f623063ddf8216b03a4a17a27110d330e80c7e.zip |
reflect: add MapIter.Reset
This allows callers to do (amortized) allocation-free iteration
over many maps.
Fixes #46293
Change-Id: I3aa6134dd00da35b508bd1e3b487332a871a3673
Reviewed-on: https://go-review.googlesource.com/c/go/+/321891
Trust: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/reflect/all_test.go')
-rw-r--r-- | src/reflect/all_test.go | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 6cb603cb16..01ce8b0c43 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -7223,6 +7223,72 @@ func TestMapIterNilMap(t *testing.T) { } } +func TestMapIterReset(t *testing.T) { + iter := new(MapIter) + + // Use of zero iterator should panic. + func() { + defer func() { recover() }() + iter.Next() + t.Error("Next did not panic") + }() + + // Reset to new Map should work. + m := map[string]int{"one": 1, "two": 2, "three": 3} + iter.Reset(ValueOf(m)) + if got, want := iterateToString(iter), `[one: 1, three: 3, two: 2]`; got != want { + t.Errorf("iterator returned %s (after sorting), want %s", got, want) + } + + // Reset to Zero value should work, but iterating over it should panic. + iter.Reset(Value{}) + func() { + defer func() { recover() }() + iter.Next() + t.Error("Next did not panic") + }() + + // Reset to a different Map with different types should work. + m2 := map[int]string{1: "one", 2: "two", 3: "three"} + iter.Reset(ValueOf(m2)) + if got, want := iterateToString(iter), `[1: one, 2: two, 3: three]`; got != want { + t.Errorf("iterator returned %s (after sorting), want %s", got, want) + } + + // Check that Reset, Next, and SetKey/SetValue play nicely together. + m3 := map[uint64]uint64{ + 1 << 0: 1 << 1, + 1 << 1: 1 << 2, + 1 << 2: 1 << 3, + } + kv := New(TypeOf(uint64(0))).Elem() + for i := 0; i < 5; i++ { + var seenk, seenv uint64 + iter.Reset(ValueOf(m3)) + for iter.Next() { + iter.SetKey(kv) + seenk ^= kv.Uint() + iter.SetValue(kv) + seenv ^= kv.Uint() + } + if seenk != 0b111 { + t.Errorf("iteration yielded keys %b, want %b", seenk, 0b111) + } + if seenv != 0b1110 { + t.Errorf("iteration yielded values %b, want %b", seenv, 0b1110) + } + } + + // Reset should not allocate. + n := int(testing.AllocsPerRun(10, func() { + iter.Reset(ValueOf(m2)) + iter.Reset(Value{}) + })) + if n > 0 { + t.Errorf("MapIter.Reset allocated %d times", n) + } +} + func TestMapIterSafety(t *testing.T) { // Using a zero MapIter causes a panic, but not a crash. func() { |