diff options
author | LemonBoy <thatlemon@gmail.com> | 2022-04-25 12:43:20 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-04-25 12:43:20 +0100 |
commit | 372bcceeee8012ef3fb2f3dbc8132c3a33cb84fc (patch) | |
tree | fd5e5a86cf23a018f653097a7c7477c532316a36 /src/vim9execute.c | |
parent | af59e34f1bf214ec6f2d0304c1c5b11ecda25a83 (diff) | |
download | vim-git-372bcceeee8012ef3fb2f3dbc8132c3a33cb84fc.tar.gz |
patch 8.2.4823: concat more than 2 strings in :def function is inefficientv8.2.4823
Problem: Concatenating more than 2 strings in a :def function is
inefficient.
Solution: Add a count to the CONCAT instruction. (closes #10276)
Diffstat (limited to 'src/vim9execute.c')
-rw-r--r-- | src/vim9execute.c | 66 |
1 files changed, 51 insertions, 15 deletions
diff --git a/src/vim9execute.c b/src/vim9execute.c index afa0dcf19..bf55d18cd 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -120,6 +120,48 @@ ufunc_argcount(ufunc_T *ufunc) } /* + * Create a new string from "count" items at the bottom of the stack. + * A trailing NUL is appended. + * When "count" is zero an empty string is added to the stack. + */ + static int +exe_concat(int count, ectx_T *ectx) +{ + int idx; + int len = 0; + typval_T *tv; + garray_T ga; + + 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); + } + + if (ga_grow(&ga, len + 1) == FAIL) + return FAIL; + + for (idx = 0; idx < count; ++idx) + { + tv = STACK_TV_BOT(idx - count); + ga_concat(&ga, tv->vval.v_string); + clear_tv(tv); + } + + // add a terminating NUL + ga_append(&ga, NUL); + + ectx->ec_stack.ga_len -= count - 1; + STACK_TV_BOT(-1)->vval.v_string = ga.ga_data; + + return OK; +} + +/* * Create a new list from "count" items at the bottom of the stack. * When "count" is zero an empty list is added to the stack. * When "count" is -1 a NULL list is added to the stack. @@ -3536,6 +3578,11 @@ exec_instructions(ectx_T *ectx) } break; + case ISN_CONCAT: + if (exe_concat(iptr->isn_arg.number, ectx) == FAIL) + goto theend; + break; + // create a partial with NULL value case ISN_NEWPARTIAL: if (GA_GROW_FAILS(&ectx->ec_stack, 1)) @@ -4343,20 +4390,6 @@ exec_instructions(ectx_T *ectx) } break; - case ISN_CONCAT: - { - char_u *str1 = STACK_TV_BOT(-2)->vval.v_string; - char_u *str2 = STACK_TV_BOT(-1)->vval.v_string; - char_u *res; - - res = concat_str(str1, str2); - clear_tv(STACK_TV_BOT(-2)); - clear_tv(STACK_TV_BOT(-1)); - --ectx->ec_stack.ga_len; - STACK_TV_BOT(-1)->vval.v_string = res; - } - break; - case ISN_STRINDEX: case ISN_STRSLICE: { @@ -6083,7 +6116,10 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc) case ISN_ADDBLOB: smsg("%s%4d ADDBLOB", pfx, current); break; // expression operations - case ISN_CONCAT: smsg("%s%4d CONCAT", pfx, current); break; + case ISN_CONCAT: + smsg("%s%4d CONCAT size %lld", pfx, current, + (varnumber_T)(iptr->isn_arg.number)); + break; case ISN_STRINDEX: smsg("%s%4d STRINDEX", pfx, current); break; case ISN_STRSLICE: smsg("%s%4d STRSLICE", pfx, current); break; case ISN_BLOBINDEX: smsg("%s%4d BLOBINDEX", pfx, current); break; |