Skip to content

Commit

Permalink
[tailscale1.17] reflect: add MapIter.Reset
Browse files Browse the repository at this point in the history
This allows callers to do (amortized) allocation-free iteration
over many maps.

Fixes golang#46293

(cherry picked from golang.org/cl/321891)

Change-Id: I3aa6134dd00da35b508bd1e3b487332a871a3673
  • Loading branch information
josharian committed Aug 5, 2021
1 parent b7cc3c6 commit 4c85d98
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/reflect/all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7298,6 +7298,48 @@ 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.Fatal("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.Fatal("Next did not panic")
}()

// Reset to a diferent 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)
}

// 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() {
Expand Down
11 changes: 11 additions & 0 deletions src/reflect/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,17 @@ func (it *MapIter) Next() bool {
return mapiterkey(it.it) != nil
}

// Reset modifies it to iterate over v.
// It panics if v's Kind is not Map and v is not the zero Value.
func (it *MapIter) Reset(v Value) {
if v.IsValid() {
v.mustBe(Map)
}
it.m = v
it.it = nil
it.hiter = hiter{}
}

// MapRange returns a range iterator for a map.
// It panics if v's Kind is not Map.
//
Expand Down

0 comments on commit 4c85d98

Please sign in to comment.