patch 9.2.0157: Vim9: concatenation can be improved
Commit:
https://github.com/vim/vim/commit/90d751b3fb79a71662f3c060711d5eb9069030bd
Author: John Marriott <[email protected]>
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 <[email protected]>
Signed-off-by: Christian Brabandt <[email protected]>
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;
}
--
--
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
---
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 email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/vim_dev/E1w1AJb-003ysr-ND%40256bit.org.