diff options
author | 2021-02-25 10:10:23 +0100 | |
---|---|---|
committer | 2021-02-25 10:10:23 +0100 | |
commit | e84db0ddd9250b91cf574d562810979fff0e6d24 (patch) | |
tree | 29294008d72a002dc60c4d219f3cbd9ed0cc3537 | |
parent | copy an optimization from CPython: when the search string of str.replace and (diff) | |
download | pypy-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.py | 30 |
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: |