Skip to content

Instantly share code, notes, and snippets.

@rhysd
Last active April 9, 2017 15:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rhysd/0dbd94544862cd0f9deea72dbfa38389 to your computer and use it in GitHub Desktop.
Save rhysd/0dbd94544862cd0f9deea72dbfa38389 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"strings"
"testing"
)
// Version A (traditional)
type Node interface {
String() string
}
type Constant struct {
Value int
}
func (c *Constant) String() string {
return fmt.Sprintf("%d", c.Value)
}
type BinOp struct {
Left Expr
Right Expr
}
func (o *BinOp) String() string {
return fmt.Sprintf("%s + %s", o.Left.String(), o.Right.String())
}
type Sequence struct {
Exprs []Expr
}
func (o *Sequence) String() string {
ss := make([]string, 0, len(o.Exprs))
for _, e := range o.Exprs {
ss = append(ss, e.String())
}
return strings.Join(ss, ";")
}
type Expr interface {
Node
exprNode()
}
func (e *BinOp) exprNode() {}
func (e *Constant) exprNode() {}
func Check(n Node) string {
switch n := n.(type) {
case Expr:
return "Expression: " + n.String()
default:
return "Not an expression: " + n.String()
}
}
func BenchmarkTypeA(b *testing.B) {
for i := 0; i < b.N; i++ {
nodes := []Node{
&Constant{42},
&BinOp{&Constant{42}, &BinOp{&Constant{1}, &Constant{0}}},
&Sequence{[]Expr{}},
&Sequence{[]Expr{&Constant{42}, &Constant{1}, &Constant{0}}},
&Sequence{[]Expr{&BinOp{&Constant{42}, &BinOp{&Constant{1}, &Constant{0}}}}},
&BinOp{&Constant{42}, &BinOp{&Constant{1}, &Constant{0}}},
}
for _, n := range nodes {
Check(n)
}
}
}
// Version B (new)
type Node2 interface {
String() string
}
type Expr2 interface {
Node2
exprNode()
}
type Constant2 struct {
Expr2
Value int
}
func (c *Constant2) String() string {
return fmt.Sprintf("%d", c.Value)
}
type BinOp2 struct {
Expr2
Left Expr2
Right Expr2
}
func (o *BinOp2) String() string {
return fmt.Sprintf("%s + %s", o.Left.String(), o.Right.String())
}
type Sequence2 struct {
Exprs []Expr2
}
func (o *Sequence2) String() string {
ss := make([]string, 0, len(o.Exprs))
for _, e := range o.Exprs {
ss = append(ss, e.String())
}
return strings.Join(ss, ";")
}
func Check2(n Node2) string {
switch n := n.(type) {
case Expr2:
return "Expression: " + n.String()
default:
return "Not an expression: " + n.String()
}
}
func BenchmarkTypeB(b *testing.B) {
for i := 0; i < b.N; i++ {
nodes := []Node2{
&Constant2{Value: 42},
&BinOp2{Left: &Constant2{Value: 42}, Right: &BinOp2{Left: &Constant2{Value: 1}, Right: &Constant2{Value: 0}}},
&Sequence2{[]Expr2{}},
&Sequence2{[]Expr2{&Constant2{Value: 42}, &Constant2{Value: 1}, &Constant2{Value: 0}}},
&Sequence2{[]Expr2{&BinOp2{Left: &Constant2{Value: 42}, Right: &BinOp2{Left: &Constant2{Value: 1}, Right: &Constant2{Value: 0}}}}},
&BinOp2{Left: &Constant2{Value: 42}, Right: &BinOp2{Left: &Constant2{Value: 1}, Right: &Constant2{Value: 0}}},
}
for _, n := range nodes {
Check2(n)
}
}
}
// Baseline
type Node3 interface {
String() string
}
type Constant3 struct {
Value int
}
func (c *Constant3) String() string {
return fmt.Sprintf("%d", c.Value)
}
type BinOp3 struct {
Left Node3
Right Node3
}
func (o *BinOp3) String() string {
return fmt.Sprintf("%s + %s", o.Left.String(), o.Right.String())
}
type Sequence3 struct {
Exprs []Node3
}
func (o *Sequence3) String() string {
ss := make([]string, 0, len(o.Exprs))
for _, e := range o.Exprs {
ss = append(ss, e.String())
}
return strings.Join(ss, ";")
}
func Check3(n Node3) string {
switch n := n.(type) {
case *Constant3, *BinOp3:
return "Expression: " + n.String()
default:
return "Not an expression: " + n.String()
}
}
func BenchmarkTypeBaseline(b *testing.B) {
for i := 0; i < b.N; i++ {
nodes := []Node3{
&Constant3{Value: 42},
&BinOp3{Left: &Constant3{Value: 42}, Right: &BinOp3{Left: &Constant3{Value: 1}, Right: &Constant3{Value: 0}}},
&Sequence3{[]Node3{}},
&Sequence3{[]Node3{&Constant3{Value: 42}, &Constant3{Value: 1}, &Constant3{Value: 0}}},
&Sequence3{[]Node3{&BinOp3{Left: &Constant3{Value: 42}, Right: &BinOp3{Left: &Constant3{Value: 1}, Right: &Constant3{Value: 0}}}}},
&BinOp3{Left: &Constant3{Value: 42}, Right: &BinOp3{Left: &Constant3{Value: 1}, Right: &Constant3{Value: 0}}},
}
for _, n := range nodes {
Check3(n)
}
}
}
BenchmarkTypeA-8 500000 3588 ns/op
BenchmarkTypeB-8 500000 3813 ns/op
BenchmarkTypeBaseline-8 500000 3512 ns/op
PASS
ok github.com/rhysd/ast-test 5.581s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment