Commit aa388017 authored by Robert Griesemer's avatar Robert Griesemer

reflect: fix FieldByNameFunc

The existing algorithm did not properly propagate the type
count from one level to the next, and as a consequence it
missed collisions.

Properly propagate multiplicity (count) information to the
next level.

benchmark                old ns/op    new ns/op    delta
BenchmarkFieldByName1          182          180   -1.10%
BenchmarkFieldByName2         6273         6183   -1.43%
BenchmarkFieldByName3        49267        46784   -5.04%

Fixes #4355.

R=rsc
CC=golang-dev
https://golang.org/cl/6821094
parent 2e77bc48
...@@ -1694,6 +1694,20 @@ type S13 struct { ...@@ -1694,6 +1694,20 @@ type S13 struct {
S8 S8
} }
// The X in S15.S11.S1 and S16.S11.S1 annihilate.
type S14 struct {
S15
S16
}
type S15 struct {
S11
}
type S16 struct {
S11
}
var fieldTests = []FTest{ var fieldTests = []FTest{
{struct{}{}, "", nil, 0}, {struct{}{}, "", nil, 0},
{struct{}{}, "Foo", nil, 0}, {struct{}{}, "Foo", nil, 0},
...@@ -1719,6 +1733,7 @@ var fieldTests = []FTest{ ...@@ -1719,6 +1733,7 @@ var fieldTests = []FTest{
{S5{}, "Y", []int{2, 0, 1}, 0}, {S5{}, "Y", []int{2, 0, 1}, 0},
{S10{}, "X", nil, 0}, {S10{}, "X", nil, 0},
{S10{}, "Y", []int{2, 0, 0, 1}, 0}, {S10{}, "Y", []int{2, 0, 0, 1}, 0},
{S14{}, "X", nil, 0},
} }
func TestFieldByIndex(t *testing.T) { func TestFieldByIndex(t *testing.T) {
......
...@@ -913,19 +913,22 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel ...@@ -913,19 +913,22 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel
// Queue embedded struct fields for processing with next level, // Queue embedded struct fields for processing with next level,
// but only if we haven't seen a match yet at this level and only // but only if we haven't seen a match yet at this level and only
// if the embedded types haven't alredy been queued. // if the embedded types haven't already been queued.
if ok || ntyp == nil || ntyp.Kind() != Struct { if ok || ntyp == nil || ntyp.Kind() != Struct {
continue continue
} }
styp := (*structType)(unsafe.Pointer(ntyp)) styp := (*structType)(unsafe.Pointer(ntyp))
if nextCount[styp] > 0 { if nextCount[styp] > 0 {
nextCount[styp]++ nextCount[styp] = 2 // exact multiple doesn't matter
continue continue
} }
if nextCount == nil { if nextCount == nil {
nextCount = map[*structType]int{} nextCount = map[*structType]int{}
} }
nextCount[styp] = 1 nextCount[styp] = 1
if count[t] > 1 {
nextCount[styp] = 2 // exact multiple doesn't matter
}
var index []int var index []int
index = append(index, scan.index...) index = append(index, scan.index...)
index = append(index, i) index = append(index, i)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment