aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Friedrich Bolz-Tereick <cfbolz@gmx.de>2021-02-25 10:10:23 +0100
committerCarl Friedrich Bolz-Tereick <cfbolz@gmx.de>2021-02-25 10:10:23 +0100
commite84db0ddd9250b91cf574d562810979fff0e6d24 (patch)
tree29294008d72a002dc60c4d219f3cbd9ed0cc3537
parentcopy an optimization from CPython: when the search string of str.replace and (diff)
downloadpypy-e84db0ddd9250b91cf574d562810979fff0e6d24.tar.gz
pypy-e84db0ddd9250b91cf574d562810979fff0e6d24.tar.bz2
pypy-e84db0ddd9250b91cf574d562810979fff0e6d24.zip
second optimization: have a fast path in replace for single character strings
here too
-rw-r--r--rpython/rlib/rstring.py30
1 files changed, 30 insertions, 0 deletions
diff --git a/rpython/rlib/rstring.py b/rpython/rlib/rstring.py
index efb9b41cfd..0f30b6aa2b 100644
--- a/rpython/rlib/rstring.py
+++ b/rpython/rlib/rstring.py
@@ -250,6 +250,36 @@ def replace_count(input, sub, by, maxsplit=-1, isutf8=False):
builder.append(by)
builder.append_slice(input, upper, len(input))
replacements = upper + 1
+
+ elif isinstance(sub, str) and len(sub) == 1:
+ # a copy of the code that is specialized for single (ascii) characters
+ sub = sub[0]
+ cnt = count(input, sub, 0, len(input))
+ if cnt == 0:
+ return input, 0
+ if maxsplit > 0 and cnt > maxsplit:
+ cnt = maxsplit
+ diff_len = len(by) - 1
+ try:
+ result_size = ovfcheck(diff_len * cnt)
+ result_size = ovfcheck(result_size + len(input))
+ except OverflowError:
+ raise
+ replacements = cnt
+
+ builder = Builder(result_size)
+ start = 0
+ while maxsplit != 0:
+ next = find(input, sub, start, len(input))
+ if next < 0:
+ break
+ builder.append_slice(input, start, next)
+ builder.append(by)
+ start = next + 1
+ maxsplit -= 1 # NB. if it's already < 0, it stays < 0
+
+ builder.append_slice(input, start, len(input))
+
else:
# First compute the exact result size
if sub: