Skip to content

Commit 8008407

Browse files
committed
⚡✅ Update all net-imap regexps to run in O(n)
The BIDI_FAILURE regexps all used `\g<name>` to define char classes and then re-use them. Unfortunately, ruby 3.2 can't compile that to run in linear time. The regexps could also be written using lookahead, but that also wouldn't run in linear time. The debug output gsub is simple to accomplish without negative lookahead by using a block with gsub and checking `$'.empty?`. `bin/check-regexps` was added for quick double-check, just in case the tests aren't catching everything.
1 parent 92db350 commit 8008407

File tree

6 files changed

+43
-79
lines changed

6 files changed

+43
-79
lines changed

bin/check-regexps

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
# See also: test/net/imap/regexp_collector.rb
5+
# See also: test/net/imap/test_regexps.rb
6+
7+
def traverse(m=Object, s=Set.new, &b)
8+
m.constants(false).map{m.const_get _1 rescue nil}.select{_1 in Module}.each do
9+
next if s.include?(_1); s << _1
10+
b and b[_1]
11+
traverse(_1, s, &b)
12+
end
13+
end
14+
15+
def collect_regexps = ObjectSpace
16+
.each_object(Regexp)
17+
.reject{Regexp.linear_time? _1}
18+
19+
2.times{traverse}
20+
before = collect_regexps
21+
22+
$LOAD_PATH.unshift "./lib"
23+
require 'net/imap'
24+
2.times{traverse}
25+
traverse(Net::IMAP) { puts _1.name }
26+
after = collect_regexps - before
27+
p before: before.count, count: after.count, after:;

lib/net/imap.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2443,8 +2443,8 @@ def put_string(str)
24432443
if @debug_output_bol
24442444
$stderr.print("C: ")
24452445
end
2446-
$stderr.print(str.gsub(/\n(?!\z)/n, "\nC: "))
2447-
if /\r\n\z/n.match(str)
2446+
$stderr.print(str.gsub(/\n/n) { $'.empty? ? $& : "\nC: " })
2447+
if /\n\z/n.match(str)
24482448
@debug_output_bol = true
24492449
else
24502450
@debug_output_bol = false

lib/net/imap/stringprep/saslprep_tables.rb

Lines changed: 1 addition & 13 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)