Skip to content

Commit

Permalink
meta: make NameEquals alloc-free
Browse files Browse the repository at this point in the history
name                 old time/op    new time/op    delta
NameEquals/1part-8     76.2ns ± 2%    15.3ns ± 2%   -79.94%  (p=0.008 n=5+5)
NameEquals/3parts-8     174ns ± 1%      30ns ± 1%   -82.74%  (p=0.008 n=5+5)

name                 old alloc/op   new alloc/op   delta
NameEquals/1part-8      16.0B ± 0%      0.0B       -100.00%  (p=0.008 n=5+5)
NameEquals/3parts-8     48.0B ± 0%      0.0B       -100.00%  (p=0.008 n=5+5)

name                 old allocs/op  new allocs/op  delta
NameEquals/1part-8       1.00 ± 0%      0.00       -100.00%  (p=0.008 n=5+5)
NameEquals/3parts-8      1.00 ± 0%      0.00       -100.00%  (p=0.008 n=5+5)

Refs #364

Signed-off-by: Iskander Sharipov <quasilyte@gmail.com>
  • Loading branch information
quasilyte committed Mar 20, 2020
1 parent 0b12e6e commit d45856a
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 7 deletions.
77 changes: 77 additions & 0 deletions src/meta/meta_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package meta

import (
"strings"
"testing"

"github.com/VKCOM/noverify/src/php/parser/node"
"github.com/VKCOM/noverify/src/php/parser/node/name"
)

func TestNameEquals(t *testing.T) {
tests := []struct {
x string
y string
want bool
}{
{`foo`, `foo`, true},
{`foo\bar2`, `foo\bar2`, true},
{`foo\bar2\BazBaz`, `foo\bar2\BazBaz`, true},
{`foo \ bar`, `foo\bar`, true},
{`a\b\c\d`, `a\b\c\d`, true},

{`first`, ``, false},
{`first\second`, `first`, false},
{`first`, `first\second`, false},
{`first\first`, `first\second`, false},
{`first\second`, `firstsecond`, false},
{`firstsecond`, `first\second`, false},
{`a\b\c`, `a\b\x`, false},
}

makeNameNode := func(s string) *name.Name {
parts := strings.Split(s, `\`)
nm := &name.Name{Parts: make([]node.Node, len(parts))}
for i := range parts {
nm.Parts[i] = &name.NamePart{Value: strings.TrimSpace(parts[i])}
}
return nm
}

for _, test := range tests {
x := makeNameNode(test.x)
y := test.y
have := NameEquals(x, y)
if have != test.want {
t.Errorf("NameEquals(%q, %q): have %v, want %v",
test.x, test.y, have, test.want)
}
}
}

var theName1 = &name.Name{
Parts: []node.Node{
&name.NamePart{Value: `method_exists`},
},
}

var theName3 = &name.Name{
Parts: []node.Node{
&name.NamePart{Value: `a`},
&name.NamePart{Value: `b`},
&name.NamePart{Value: `c`},
},
}

func BenchmarkNameEquals(b *testing.B) {
b.Run("1part", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = NameEquals(theName1, `method_exists`)
}
})
b.Run("3parts", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = NameEquals(theName3, `a\b\c`)
}
})
}
12 changes: 5 additions & 7 deletions src/meta/metainfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -492,16 +492,14 @@ func NameEquals(n *name.Name, s string) bool {
return false
}

sParts := strings.Split(s, `\`)

rest := s
for i, part := range n.Parts {
p, ok := part.(*name.NamePart)
if !ok {
part := part.(*name.NamePart)
if !strings.HasPrefix(rest, part.Value) {
return false
}

if p.Value != sParts[i] {
return false
if i != len(n.Parts)-1 {
rest = rest[len(part.Value)+len(`\`):]
}
}

Expand Down

0 comments on commit d45856a

Please sign in to comment.