2012-12-19 15:54:47 -05:00
|
|
|
# encoding: utf-8
|
2013-08-07 14:13:11 -04:00
|
|
|
|
2012-12-19 15:54:47 -05:00
|
|
|
module ActionDispatch
|
2012-12-19 19:24:25 -05:00
|
|
|
module Journey # :nodoc:
|
2014-05-20 16:12:59 -04:00
|
|
|
class Format
|
|
|
|
ESCAPE_PATH = ->(value) { Router::Utils.escape_path(value) }
|
|
|
|
ESCAPE_SEGMENT = ->(value) { Router::Utils.escape_segment(value) }
|
|
|
|
|
|
|
|
class Parameter < Struct.new(:name, :escaper)
|
|
|
|
def escape(value); escaper.call value; end
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.required_path(symbol)
|
|
|
|
Parameter.new symbol, ESCAPE_PATH
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.required_segment(symbol)
|
|
|
|
Parameter.new symbol, ESCAPE_SEGMENT
|
|
|
|
end
|
|
|
|
|
|
|
|
def initialize(parts)
|
|
|
|
@parts = parts
|
|
|
|
@children = []
|
|
|
|
@parameters = []
|
|
|
|
|
|
|
|
parts.each_with_index do |object,i|
|
|
|
|
case object
|
|
|
|
when Journey::Format
|
|
|
|
@children << i
|
|
|
|
when Parameter
|
|
|
|
@parameters << i
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def evaluate(hash)
|
|
|
|
parts = @parts.dup
|
|
|
|
|
|
|
|
@parameters.each do |index|
|
|
|
|
param = parts[index]
|
2014-05-21 17:27:09 -04:00
|
|
|
value = hash[param.name]
|
|
|
|
return ''.freeze unless value
|
2014-05-20 16:12:59 -04:00
|
|
|
parts[index] = param.escape value
|
|
|
|
end
|
|
|
|
|
|
|
|
@children.each { |index| parts[index] = parts[index].evaluate(hash) }
|
|
|
|
|
|
|
|
parts.join
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-12-19 19:24:25 -05:00
|
|
|
module Visitors # :nodoc:
|
2012-12-19 15:54:47 -05:00
|
|
|
class Visitor # :nodoc:
|
2014-05-20 14:10:52 -04:00
|
|
|
DISPATCH_CACHE = {}
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def accept(node)
|
|
|
|
visit(node)
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def visit node
|
|
|
|
send(DISPATCH_CACHE[node.type], node)
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def binary(node)
|
|
|
|
visit(node.left)
|
|
|
|
visit(node.right)
|
|
|
|
end
|
|
|
|
def visit_CAT(n); binary(n); end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def nary(node)
|
|
|
|
node.children.each { |c| visit(c) }
|
|
|
|
end
|
|
|
|
def visit_OR(n); nary(n); end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def unary(node)
|
|
|
|
visit(node.left)
|
|
|
|
end
|
|
|
|
def visit_GROUP(n); unary(n); end
|
|
|
|
def visit_STAR(n); unary(n); end
|
|
|
|
|
|
|
|
def terminal(node); end
|
2014-05-20 14:10:52 -04:00
|
|
|
def visit_LITERAL(n); terminal(n); end
|
|
|
|
def visit_SYMBOL(n); terminal(n); end
|
|
|
|
def visit_SLASH(n); terminal(n); end
|
|
|
|
def visit_DOT(n); terminal(n); end
|
|
|
|
|
|
|
|
private_instance_methods(false).each do |pim|
|
|
|
|
next unless pim =~ /^visit_(.*)$/
|
|
|
|
DISPATCH_CACHE[$1.to_sym] = pim
|
2012-12-20 15:42:39 -05:00
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
2014-05-20 16:12:59 -04:00
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
class FunctionalVisitor # :nodoc:
|
|
|
|
DISPATCH_CACHE = {}
|
|
|
|
|
|
|
|
def accept(node, seed)
|
|
|
|
visit(node, seed)
|
|
|
|
end
|
|
|
|
|
|
|
|
def visit node, seed
|
|
|
|
send(DISPATCH_CACHE[node.type], node, seed)
|
|
|
|
end
|
|
|
|
|
|
|
|
def binary(node, seed)
|
|
|
|
visit(node.right, visit(node.left, seed))
|
|
|
|
end
|
|
|
|
def visit_CAT(n, seed); binary(n, seed); end
|
|
|
|
|
|
|
|
def nary(node, seed)
|
|
|
|
node.children.inject(seed) { |s, c| visit(c, s) }
|
|
|
|
end
|
|
|
|
def visit_OR(n, seed); nary(n, seed); end
|
|
|
|
|
|
|
|
def unary(node, seed)
|
|
|
|
visit(node.left, seed)
|
|
|
|
end
|
|
|
|
def visit_GROUP(n, seed); unary(n, seed); end
|
|
|
|
def visit_STAR(n, seed); unary(n, seed); end
|
|
|
|
|
|
|
|
def terminal(node, seed); seed; end
|
|
|
|
def visit_LITERAL(n, seed); terminal(n, seed); end
|
|
|
|
def visit_SYMBOL(n, seed); terminal(n, seed); end
|
|
|
|
def visit_SLASH(n, seed); terminal(n, seed); end
|
|
|
|
def visit_DOT(n, seed); terminal(n, seed); end
|
|
|
|
|
|
|
|
instance_methods(false).each do |pim|
|
|
|
|
next unless pim =~ /^visit_(.*)$/
|
|
|
|
DISPATCH_CACHE[$1.to_sym] = pim
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-05-20 16:12:59 -04:00
|
|
|
class FormatBuilder < Visitor # :nodoc:
|
|
|
|
def accept(node); Journey::Format.new(super); end
|
|
|
|
def terminal(node); [node.left]; end
|
|
|
|
|
|
|
|
def binary(node)
|
|
|
|
visit(node.left) + visit(node.right)
|
|
|
|
end
|
|
|
|
|
|
|
|
def visit_GROUP(n); [Journey::Format.new(unary(n))]; end
|
|
|
|
|
|
|
|
def visit_STAR(n)
|
|
|
|
[Journey::Format.required_path(n.left.to_sym)]
|
|
|
|
end
|
|
|
|
|
|
|
|
def visit_SYMBOL(n)
|
|
|
|
symbol = n.to_sym
|
|
|
|
if symbol == :controller
|
|
|
|
[Journey::Format.required_path(symbol)]
|
|
|
|
else
|
|
|
|
[Journey::Format.required_segment(symbol)]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
|
|
|
# Loop through the requirements AST
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
class Each < FunctionalVisitor # :nodoc:
|
|
|
|
def visit(node, block)
|
2012-12-20 15:42:39 -05:00
|
|
|
block.call(node)
|
2014-05-20 14:00:06 -04:00
|
|
|
super
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
|
|
|
|
INSTANCE = new
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
class String < FunctionalVisitor # :nodoc:
|
2012-12-19 15:54:47 -05:00
|
|
|
private
|
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def binary(node, seed)
|
|
|
|
visit(node.right, visit(node.left, seed))
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def nary(node, seed)
|
|
|
|
last_child = node.children.last
|
|
|
|
node.children.inject(seed) { |s, c|
|
|
|
|
string = visit(c, s)
|
|
|
|
string << "|".freeze unless last_child == c
|
|
|
|
string
|
|
|
|
}
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def terminal(node, seed)
|
|
|
|
seed + node.left
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def visit_GROUP(node, seed)
|
|
|
|
visit(node.left, seed << "(".freeze) << ")".freeze
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
|
|
|
|
INSTANCE = new
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
class Dot < FunctionalVisitor # :nodoc:
|
2012-12-19 15:54:47 -05:00
|
|
|
def initialize
|
|
|
|
@nodes = []
|
|
|
|
@edges = []
|
|
|
|
end
|
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def accept(node, seed = [[], []])
|
2012-12-19 15:54:47 -05:00
|
|
|
super
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
nodes, edges = seed
|
2012-12-19 15:54:47 -05:00
|
|
|
<<-eodot
|
|
|
|
digraph parse_tree {
|
|
|
|
size="8,5"
|
|
|
|
node [shape = none];
|
|
|
|
edge [dir = none];
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
#{nodes.join "\n"}
|
|
|
|
#{edges.join("\n")}
|
2012-12-19 15:54:47 -05:00
|
|
|
}
|
|
|
|
eodot
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
2012-12-20 15:42:39 -05:00
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def binary(node, seed)
|
|
|
|
seed.last.concat node.children.map { |c|
|
|
|
|
"#{node.object_id} -> #{c.object_id};"
|
|
|
|
}
|
2012-12-20 15:42:39 -05:00
|
|
|
super
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def nary(node, seed)
|
|
|
|
seed.last.concat node.children.map { |c|
|
|
|
|
"#{node.object_id} -> #{c.object_id};"
|
|
|
|
}
|
2012-12-20 15:42:39 -05:00
|
|
|
super
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def unary(node, seed)
|
|
|
|
seed.last << "#{node.object_id} -> #{node.left.object_id};"
|
2012-12-20 15:42:39 -05:00
|
|
|
super
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def visit_GROUP(node, seed)
|
|
|
|
seed.first << "#{node.object_id} [label=\"()\"];"
|
2012-12-20 15:42:39 -05:00
|
|
|
super
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def visit_CAT(node, seed)
|
|
|
|
seed.first << "#{node.object_id} [label=\"○\"];"
|
2012-12-20 15:42:39 -05:00
|
|
|
super
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def visit_STAR(node, seed)
|
|
|
|
seed.first << "#{node.object_id} [label=\"*\"];"
|
2012-12-20 15:42:39 -05:00
|
|
|
super
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def visit_OR(node, seed)
|
|
|
|
seed.first << "#{node.object_id} [label=\"|\"];"
|
2012-12-20 15:42:39 -05:00
|
|
|
super
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
def terminal(node, seed)
|
2012-12-20 15:42:39 -05:00
|
|
|
value = node.left
|
2012-12-19 15:54:47 -05:00
|
|
|
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
seed.first << "#{node.object_id} [label=\"#{value}\"];"
|
|
|
|
seed
|
2012-12-20 15:42:39 -05:00
|
|
|
end
|
drop object allocation during routes setup
This commit introduces a functional Path AST visitor and implements
`each` on the AST in terms of the functional visitor. The functional
visitor doesn't maintain state, so we only need to allocate one of them.
Given this benchmark route file:
```ruby
require 'action_pack'
require 'action_dispatch'
route_set = ActionDispatch::Routing::RouteSet.new
routes = ActionDispatch::Routing::Mapper.new route_set
ObjectSpace::AllocationTracer.setup(%i{path line type})
result = ObjectSpace::AllocationTracer.trace do
500.times{|i|
routes.resource :omglol
}
end
result.find_all { |k,v| k.first =~ /git\/rails/ }.sort_by { |k,v|
v.first
}.each { |k,v|
p k => v
}
```
node.rb line 17 was in our top 3 allocation spot:
```
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/journey/nodes/node.rb", 17, :T_OBJECT]=>[31526, 0, 28329, 0, 2, 1123160]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2080, :T_IMEMO]=>[34002, 0, 30563, 0, 2, 1211480]}
{["/Users/aaron/git/rails/actionpack/lib/action_dispatch/routing/mapper.rb", 2071, :T_IMEMO]=>[121934, 1, 109608, 0, 7, 4344400]}
```
This commit eliminates allocations at that place.
2015-08-17 18:57:06 -04:00
|
|
|
INSTANCE = new
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|