From d3bca3b7fab4aefdb6e86afd3b9cdec81fb1f3d7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 14 Mar 2026 08:14:34 +0800 Subject: [PATCH] vim-patch:9.2.0152: concatenating strings is slow (#38286) Problem: concatenating strings is slow Solution: Use grow_string_tv() to grow the existing string buffer in place when possible (Yasuhiro Matsumoto). closes: vim/vim#19642 https://github.com/vim/vim/commit/16d421a4d95b45ebbcf47ab60173cdb1b87ce419 Co-authored-by: Yasuhiro Matsumoto --- src/nvim/eval.c | 22 ++++++++++++++++++++++ src/nvim/eval/executor.c | 9 +++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ab02298d2b..e95ce22f6b 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2267,6 +2267,23 @@ static int eval_addlist(typval_T *tv1, typval_T *tv2) return OK; } +/// Append string "s2" to the string in "tv1". +/// Returns OK if "tv1" was grown in place, FAIL otherwise. +int grow_string_tv(typval_T *tv1, const char *s2) +{ + if (tv1->v_type != VAR_STRING || tv1->vval.v_string == NULL) { + return FAIL; + } + + size_t len1 = strlen(tv1->vval.v_string); + size_t len2 = strlen(s2); + char *p = xrealloc(tv1->vval.v_string, len1 + len2 + 1); + + memmove(p + len1, s2, len2 + 1); + tv1->vval.v_string = p; + return OK; +} + /// Concatenate strings "tv1" and "tv2" and store the result in "tv1". static int eval_concat_str(typval_T *tv1, typval_T *tv2) { @@ -2281,6 +2298,11 @@ static int eval_concat_str(typval_T *tv1, typval_T *tv2) return FAIL; } + // When possible, grow the existing string in place to avoid alloc/free. + if (grow_string_tv(tv1, s2) == OK) { + return OK; + } + char *p = concat_str(s1, s2); tv_clear(tv1); tv1->v_type = VAR_STRING; diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index 39b8df9760..d8d10992a6 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -129,10 +129,15 @@ static int tv_op_string(typval_T *tv1, const typval_T *tv2, const char *op) return FAIL; } + char numbuf[NUMBUFLEN]; + const char *s2 = tv_get_string_buf(tv2, numbuf); + if (grow_string_tv(tv1, s2) == OK) { + return OK; + } + // str .= str const char *tvs = tv_get_string(tv1); - char numbuf[NUMBUFLEN]; - char *const s = concat_str(tvs, tv_get_string_buf(tv2, numbuf)); + char *const s = concat_str(tvs, s2); tv_clear(tv1); tv1->v_type = VAR_STRING; tv1->vval.v_string = s;