Commit: patch 9.2.0906: slow transstr() with long strings
Christian Brabandt <[email protected]> Mon, 3 Aug 2026 22:45:04 +0200
| Newsgroups | gmane.editors.vim.devel |
|---|---|
| Message-ID | <[email protected]> |
patch 9.2.0906: slow transstr() with long strings Commit: https://github.com/vim/vim/commit/124c86868c253a5ec1347e7cbe102504d= 2d66a07 Author: Samuel Schlesinger <[email protected]> Date: Mon Aug 3 20:30:09 2026 +0000 patch 9.2.0906: slow transstr() with long strings =20 Problem: transstr() appends with STRCAT()/STRLEN() from the start of the result on every iteration, making it quadratic to the length of the string. Solution: Keep a tail pointer and append at it. (Samuel Schlesinger). =20 closes: #20925 =20 Signed-off-by: Samuel Schlesinger <[email protected]> Signed-off-by: Christian Brabandt <[email protected]> diff --git a/src/charset.c b/src/charset.c index 1c45688fe..3be32f5fb 100644 --- a/src/charset.c +++ b/src/charset.c @@ -383,7 +383,10 @@ transstr(char_u *s) if (res =3D=3D NULL) return NULL; =20 - *res =3D NUL; + // Keep a tail pointer to append to, appending with STRCAT would make + // this loop quadratic. + char_u *d =3D res; + p =3D s; while (*p !=3D NUL) { @@ -391,14 +394,28 @@ transstr(char_u *s) { c =3D (*mb_ptr2char)(p); if (vim_isprintc(c)) - STRNCAT(res, p, l); // append printable multi-byte char + { + // append printable multi-byte char + mch_memmove(d, p, (size_t)l); + d +=3D l; + } else - transchar_hex(res + STRLEN(res), c); + { + transchar_hex(d, c); + d +=3D STRLEN(d); + } p +=3D l; } else - STRCAT(res, transchar_byte(*p++)); + { + char_u *trs =3D transchar_byte(*p++); + int trs_len =3D (int)STRLEN(trs); + + mch_memmove(d, trs, (size_t)trs_len); + d +=3D trs_len; + } } + *d =3D NUL; return res; } =20 diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vi= m index 645ff531e..2f2a7fc5f 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -211,6 +211,56 @@ func Test_strwidth() set ambiwidth& endfunc =20 +func Test_strtrans() + " The default of 'isprint' is platform-dependent: 0x7f and 0x9f are + " printable on Win32 and VMS. Set it so the expectations below hold + " everywhere. + let save_isprint =3D &isprint + set isprint=3D@,161-255 + + " printable ASCII is unchanged + call assert_equal('', strtrans('')) + call assert_equal('abc', strtrans('abc')) + + " control characters are displayed as ^X + call assert_equal('^I', strtrans(" ")) + call assert_equal('a^Mb^[c', strtrans("a b c")) + call assert_equal('^A^_^?', strtrans("\x01\x1f\x7f")) + + " printable multibyte characters are unchanged, including composing + " characters and characters above 0xffff + call assert_equal('h=C3=A9llo =E4=BD=A0=E5=A5=BD', strtrans('h=C3=A9llo = =E4=BD=A0=E5=A5=BD')) + let s =3D 'e' .. nr2char(0x301) .. 'x' + call assert_equal(s, strtrans(s)) + call assert_equal(nr2char(0x1d11e), strtrans(nr2char(0x1d11e))) + + " unprintable multibyte characters are displayed in <xx> hex form + call assert_equal('<9f>', strtrans(nr2char(0x9f))) + call assert_equal('<200b>', strtrans(nr2char(0x200b))) + call assert_equal('<feff>', strtrans(nr2char(0xfeff))) + + " illegal bytes are displayed in <xx> hex form + call assert_equal('A<ff>B', strtrans("A\xffB")) + + " a long string mixing all kinds of characters + call assert_equal(repeat('a^B=C3=A9<9f>', 100), + \ strtrans(repeat("a\x02=C3=A9" .. nr2char(0x9f), 100))) + + " the non-multi-byte code path + set encoding=3Dlatin1 + set isprint=3D@,161-255 + call assert_equal('a^Mb^[c', strtrans("a b c")) + call assert_equal('^A^_^?', strtrans("\x01\x1f\x7f")) + " an unprintable byte above 0x7f uses the meta notation + call assert_equal('| ', strtrans("\xa0")) + " a printable high byte is unchanged + call assert_equal("\xe9", strtrans("\xe9")) + call assert_equal("x^B\xe9| y", strtrans("x\x02\xe9\xa0y")) + set encoding=3Dutf-8 + + let &isprint =3D save_isprint +endfunc + func Test_str2nr() call assert_equal(0, str2nr('')) call assert_equal(1, str2nr('1')) diff --git a/src/version.c b/src/version.c index 7bb915f93..13c9fc7d3 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) =3D =20 static int included_patches[] =3D { /* Add new patch number below this line */ +/**/ + 906, /**/ 905, /**/ --=20 --=20 You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php ---=20 You received this message because you are subscribed to the Google Groups "= vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an e= mail to [email protected]. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1w= qzWy-00BQyS-EI%40256bit.org.