Commit: patch 9.2.0157: Vim9: concatenation can be improved

0 views
Skip to first unread message

Christian Brabandt

unread,
Mar 13, 2026, 5:47:01 PM (10 days ago) Mar 13
to vim...@googlegroups.com
patch 9.2.0157: Vim9: concatenation can be improved

Commit: https://github.com/vim/vim/commit/90d751b3fb79a71662f3c060711d5eb9069030bd
Author: John Marriott <basi...@internode.on.net>
Date: Fri Mar 13 21:26:55 2026 +0000

patch 9.2.0157: Vim9: concatenation can be improved

Problem: Vim9: concatenation can be improved
Solution: Cache string segments lengths in exe_concat() and avoid
strlen() calls (John Marriott).

closes: #19647

Signed-off-by: John Marriott <basi...@internode.on.net>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/version.c b/src/version.c
index 3676c461b..dd050e2b3 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 157,
/**/
156,
/**/
diff --git a/src/vim9execute.c b/src/vim9execute.c
index c58992f5d..76d160cd9 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -133,28 +133,57 @@ ufunc_argcount(ufunc_T *ufunc)
exe_concat(int count, ectx_T *ectx)
{
int idx;
- int len = 0;
- typval_T *tv;
+ size_t len = 0;
garray_T ga;
+ typedef struct
+ {
+ typval_T *tv;
+ size_t length;
+ } string_segment_T;
+ enum
+ {
+ STRING_SEGMENT_CACHE_SIZE = 10
+ };
+ string_segment_T fixed_string_segment_tab[STRING_SEGMENT_CACHE_SIZE];
+ string_segment_T *string_segment_tab = &fixed_string_segment_tab[0]; // an array of cached typevals and lengths
+ string_segment_T *segment;
+
+ if (count > (int)ARRAY_LENGTH(fixed_string_segment_tab))
+ {
+ // make an array big enough to store the length of each string segment
+ string_segment_tab = ALLOC_MULT(string_segment_T, count);
+ if (string_segment_tab == NULL)
+ return FAIL;
+ }

ga_init2(&ga, sizeof(char), 1);
// Preallocate enough space for the whole string to avoid having to grow
// and copy.
for (idx = 0; idx < count; ++idx)
{
- tv = STACK_TV_BOT(idx - count);
- if (tv->vval.v_string != NULL)
- len += (int)STRLEN(tv->vval.v_string);
+ segment = &string_segment_tab[idx];
+ segment->tv = STACK_TV_BOT(idx - count);
+ if (segment->tv->vval.v_string != NULL)
+ {
+ segment->length = STRLEN(segment->tv->vval.v_string);
+ len += segment->length;
+ }
+ else
+ segment->length = 0; // Ensure clean state for the second pass
}

- if (ga_grow(&ga, len + 1) == FAIL)
+ if (ga_grow(&ga, (int)len + 1) == FAIL)
+ {
+ if (string_segment_tab != fixed_string_segment_tab)
+ vim_free(string_segment_tab);
return FAIL;
+ }

for (idx = 0; idx < count; ++idx)
{
- tv = STACK_TV_BOT(idx - count);
- ga_concat(&ga, tv->vval.v_string);
- clear_tv(tv);
+ segment = &string_segment_tab[idx];
+ ga_concat_len(&ga, segment->tv->vval.v_string, segment->length);
+ clear_tv(segment->tv);
}

// add a terminating NUL
@@ -163,6 +192,9 @@ exe_concat(int count, ectx_T *ectx)
ectx->ec_stack.ga_len -= count - 1;
STACK_TV_BOT(-1)->vval.v_string = ga.ga_data;

+ if (string_segment_tab != fixed_string_segment_tab)
+ vim_free(string_segment_tab);
+
return OK;
}

Reply all
Reply to author
Forward
0 new messages