Skip to content

Commit

Permalink
_rl_adjust_point: performance fix with large point
Browse files Browse the repository at this point in the history
_rl_adjust_point() takes a long time when inserting text. If point
argument is a large value, performance is poor. In this case, counting
byte size from tail of the string will improve performance. Resetting
encoding instead of String#dup will give a small improvement.

Tested-by: Mark Somerville <mark@scottishclimbs.com> [F16, MRI 1.8.7, MRI 1.9.3]
Signed-off-by: Mark Somerville <mark@scottishclimbs.com>
  • Loading branch information
shirosaki authored and Spakman committed Sep 3, 2012
1 parent d1aaa2d commit 671713d
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 5 deletions.
26 changes: 26 additions & 0 deletions bench/_rl_adjust_point.rb
@@ -0,0 +1,26 @@
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib/"
require 'rbreadline'
require 'benchmark'

N = 100_000

Benchmark.bmbm do |x|
x.report do
N.times { RbReadline._rl_adjust_point("a", 0) }
end
x.report do
N.times { RbReadline._rl_adjust_point("a", 1) }
end
x.report do
N.times { RbReadline._rl_adjust_point("aaaaaaaaaaaaaaaaaaaaa", 0) }
end
x.report do
N.times { RbReadline._rl_adjust_point("aaaaaaaaaaaaaaaaaaaaa", 40) }
end
x.report do
N.times { RbReadline._rl_adjust_point("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0) }
end
x.report do
N.times { RbReadline._rl_adjust_point("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 40) }
end
end
25 changes: 20 additions & 5 deletions lib/rbreadline.rb
Expand Up @@ -8524,12 +8524,27 @@ def _rl_adjust_point(string, point)
i += 1
end
when 'X'
str = string.dup.force_encoding(@encoding_name)
i, len = 0, str.length
while (pos < point && i < len)
pos += str[i].bytesize
i += 1
enc = string.encoding
str = string.force_encoding(@encoding_name)
len = str.length
if point <= length / 2
# count byte size from head
i = 0
while (pos < point && i < len)
pos += str[i].bytesize
i += 1
end
else
# count byte size from tail
pos = str.bytesize
i = len - 1
while (pos > point && i >= 0)
pos -= str[i].bytesize
i -= 1
end
pos += str[i + 1].bytesize if pos < point
end
string.force_encoding(enc)
else
pos = point
end
Expand Down
14 changes: 14 additions & 0 deletions test/test_rbreadline.rb
Expand Up @@ -6,4 +6,18 @@ def test_versions
assert_equal('5.2', RbReadline::RL_LIBRARY_VERSION)
assert_equal(0x0502, RbReadline::RL_READLINE_VERSION)
end

def test_rl_adjust_point
encoding_name = RbReadline.instance_variable_get(:@encoding_name)
RbReadline.instance_variable_set(:@encoding_name, Encoding.find('UTF-8'))

assert_equal(0, RbReadline._rl_adjust_point("a".force_encoding('ASCII-8BIT'), 0))
assert_equal(0, RbReadline._rl_adjust_point("a".force_encoding('ASCII-8BIT'), 1))
assert_equal(0, RbReadline._rl_adjust_point(("a" * 40).force_encoding('ASCII-8BIT'), 0))
assert_equal(0, RbReadline._rl_adjust_point(("a" * 40).force_encoding('ASCII-8BIT'), 40))
assert_equal(2, RbReadline._rl_adjust_point(("\u3042" * 10).force_encoding('ASCII-8BIT'), 1))
assert_equal(1, RbReadline._rl_adjust_point(("\u3042" * 15).force_encoding('ASCII-8BIT'), 38))
ensure
RbReadline.instance_variable_set(:@encoding_name, encoding_name)
end if defined?(Encoding)
end

0 comments on commit 671713d

Please sign in to comment.