Skip to content

Commit d3e1fb4

Browse files
authored
Merge pull request rails#54491 from skipkayhil/hm-journey-bytes
Speed up GTG Simulator by reducing slices/matches
2 parents 9621e59 + c1c528d commit d3e1fb4

File tree

3 files changed

+29
-19
lines changed

3 files changed

+29
-19
lines changed

actionpack/lib/action_dispatch/journey/gtg/simulator.rb

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
# :markup: markdown
44

5-
require "strscan"
6-
75
module ActionDispatch
86
module Journey # :nodoc:
97
module GTG # :nodoc:
@@ -16,6 +14,12 @@ def initialize(memos)
1614
end
1715

1816
class Simulator # :nodoc:
17+
STATIC_TOKENS = Array.new(64)
18+
STATIC_TOKENS[".".ord] = "."
19+
STATIC_TOKENS["/".ord] = "/"
20+
STATIC_TOKENS["?".ord] = "?"
21+
STATIC_TOKENS.freeze
22+
1923
INITIAL_STATE = [ [0, nil] ].freeze
2024

2125
attr_reader :tt
@@ -25,16 +29,25 @@ def initialize(transition_table)
2529
end
2630

2731
def memos(string)
28-
input = StringScanner.new(string)
2932
state = INITIAL_STATE
30-
start_index = 0
3133

32-
while sym = input.scan(%r([/.?]|[^/.?]+))
33-
end_index = start_index + sym.length
34+
pos = 0
35+
eos = string.bytesize
36+
37+
while pos < eos
38+
start_index = pos
39+
pos += 1
3440

35-
state = tt.move(state, string, start_index, end_index)
41+
if (token = STATIC_TOKENS[string.getbyte(start_index)])
42+
state = tt.move(state, string, token, start_index, false)
43+
else
44+
while pos < eos && STATIC_TOKENS[string.getbyte(pos)].nil?
45+
pos += 1
46+
end
3647

37-
start_index = end_index
48+
token = string.byteslice(start_index, pos - start_index)
49+
state = tt.move(state, string, token, start_index, true)
50+
end
3851
end
3952

4053
acceptance_states = state.each_with_object([]) do |s_d, memos|

actionpack/lib/action_dispatch/journey/gtg/transition_table.rb

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,22 @@ def eclosure(t)
4747
Array(t)
4848
end
4949

50-
def move(t, full_string, start_index, end_index)
50+
def move(t, full_string, token, start_index, token_matches_default)
5151
return [] if t.empty?
5252

5353
next_states = []
5454

55-
tok = full_string.slice(start_index, end_index - start_index)
56-
token_matches_default_component = DEFAULT_EXP_ANCHORED.match?(tok)
57-
5855
t.each { |s, previous_start|
5956
if previous_start.nil?
6057
# In the simple case of a "default" param regex do this fast-path and add all
6158
# next states.
62-
if token_matches_default_component && std_state = @stdparam_states[s]
59+
if token_matches_default && std_state = @stdparam_states[s]
6360
next_states << [std_state, nil].freeze
6461
end
6562

6663
# When we have a literal string, we can just pull the next state
6764
if states = @string_states[s]
68-
next_states << [states[tok], nil].freeze unless states[tok].nil?
65+
next_states << [states[token], nil].freeze unless states[token].nil?
6966
end
7067
end
7168

@@ -80,7 +77,7 @@ def move(t, full_string, start_index, end_index)
8077
previous_start
8178
end
8279

83-
slice_length = end_index - slice_start
80+
slice_length = start_index + token.length - slice_start
8481
curr_slice = full_string.slice(slice_start, slice_length)
8582

8683
states.each { |re, v|

actionpack/test/journey/gtg/builder_test.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ module GTG
88
class TestBuilder < ActiveSupport::TestCase
99
def test_following_states_multi
1010
table = tt ["a|a"]
11-
assert_equal 1, table.move([[0, nil]], "a", 0, 1).length
11+
assert_equal 1, table.move([[0, nil]], "a", "a", 0, true).length
1212
end
1313

1414
def test_following_states_multi_regexp
1515
table = tt [":a|b"]
16-
assert_equal 1, table.move([[0, nil]], "fooo", 0, 4).length
17-
assert_equal 2, table.move([[0, nil]], "b", 0, 1).length
16+
assert_equal 1, table.move([[0, nil]], "fooo", "fooo", 0, true).length
17+
assert_equal 2, table.move([[0, nil]], "b", "b", 0, true).length
1818
end
1919

2020
def test_multi_path
@@ -26,7 +26,7 @@ def test_multi_path
2626
[2, "/"],
2727
[1, "c"],
2828
].inject([[0, nil]]) { |state, (exp, sym)|
29-
new = table.move(state, sym, 0, sym.length)
29+
new = table.move(state, sym, sym, 0, sym != "/")
3030
assert_equal exp, new.length
3131
new
3232
}

0 commit comments

Comments
 (0)