commit 147190d8e7dd53cb329230630f764020b15d9c21
parent ca731d2e55f830d98075a14fb74b494598c70c74
Author: zeertzjq <zeertzjq@outlook.com>
Date: Sat, 3 Jan 2026 09:54:12 +0800
vim-patch:partial:9.1.2044: Inefficient use of ga_concat() (#37209)
Problem: Inefficient use of ga_concat()
Solution: Use ga_concat_len() when the length is already known to avoid
use of strlen() (John Marriott).
Additionally the following changes are done:
os_unix.c:
- in function `socket_server_list_sockets()` use a `string_T` for the
strings `buf` and `path` for use in `ga_concat_len()`
and drop un-needed variable `dir`.
quickfix.c:
- in function `qf_jump_print_msg()` use a `string_T` for the string
`IObuff` for use in `ga_concat_len()`.
- in function `qf_range_text()` use a `string_T` for the string `buf`
for use in `ga_concat_len()`.
register.c:
- simplify function `execreg_line_continuation()`.
terminal.c:
- in function `read_dump_file()` use a `string_T` for the
string `prev_char` for use in `ga_concat_len()`.
tuple.c:
- in function `tuple_join_inner()` use a `string_T` for the
string `s` for use in `ga_concat_len()`. Also, change local struct
`join_T` to use `string_T`.
vim9type.c:
- in functions `type_name_tuple()` and `type_name_func()`
use a `string_T` for the string `arg_type` for use in
`ga_concat_len()`.
closes: vim/vim#19038
https://github.com/vim/vim/commit/a7e671fbb9fa2af9ad6c4ba9a7a881df431cd02b
Skip tuple.
Co-authored-by: John Marriott <basilisk@internode.on.net>
Diffstat:
4 files changed, 37 insertions(+), 35 deletions(-)
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
@@ -333,9 +333,9 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s
if (i_ > 0 && (i_ & 3) == 0) { \
ga_append(gap, '.'); \
} \
- vim_snprintf((char *)numbuf, ARRAY_SIZE(numbuf), "%02X", \
- (int)tv_blob_get(blob_, i_)); \
- ga_concat(gap, numbuf); \
+ size_t numbuflen = vim_snprintf_safelen(numbuf, ARRAY_SIZE(numbuf), "%02X", \
+ (int)tv_blob_get(blob_, i_)); \
+ ga_concat_len(gap, numbuf, numbuflen); \
} \
} \
} while (0)
diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c
@@ -29,6 +29,7 @@
#include "nvim/option_vars.h"
#include "nvim/os/fs.h"
#include "nvim/pos_defs.h"
+#include "nvim/strings.h"
#include "nvim/types_defs.h"
#include "nvim/vim_defs.h"
#include "nvim/window.h"
@@ -854,12 +855,12 @@ void f_winrestcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (!win_has_winnr(wp, curtab)) {
continue;
}
- snprintf(buf, sizeof(buf), "%dresize %d|", winnr,
- wp->w_height);
- ga_concat(&ga, buf);
- snprintf(buf, sizeof(buf), "vert %dresize %d|", winnr,
- wp->w_width);
- ga_concat(&ga, buf);
+ size_t buflen = vim_snprintf_safelen(buf, sizeof(buf),
+ "%dresize %d|", winnr, wp->w_height);
+ ga_concat_len(&ga, buf, buflen);
+ buflen = vim_snprintf_safelen(buf, sizeof(buf),
+ "vert %dresize %d|", winnr, wp->w_width);
+ ga_concat_len(&ga, buf, buflen);
winnr++;
}
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
@@ -3077,12 +3077,13 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf
update_screen();
}
}
- vim_snprintf(IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index,
- qf_get_curlist(qi)->qf_count,
- qf_ptr->qf_cleared ? _(" (line deleted)") : "",
- qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
+ size_t IObufflen = vim_snprintf_safelen(IObuff, IOSIZE,
+ _("(%d of %d)%s%s: "), qf_index,
+ qf_get_curlist(qi)->qf_count,
+ qf_ptr->qf_cleared ? _(" (line deleted)") : "",
+ qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
// Add the message, skipping leading whitespace and newlines.
- ga_concat(gap, IObuff);
+ ga_concat_len(gap, IObuff, IObufflen);
qf_fmt_text(gap, skipwhite(qf_ptr->qf_text));
ga_append(gap, NUL);
@@ -3486,26 +3487,24 @@ static void qf_fmt_text(garray_T *gap, const char *restrict text)
/// of a quickfix entry to the grow array "gap".
static void qf_range_text(garray_T *gap, const qfline_T *qfp)
{
- char *const buf = IObuff;
- const size_t bufsize = IOSIZE;
+ String buf = cbuf_as_string(IObuff, 0);
- vim_snprintf(buf, bufsize, "%" PRIdLINENR, qfp->qf_lnum);
- size_t len = strlen(buf);
+ buf.size = vim_snprintf_safelen(buf.data, IOSIZE, "%" PRIdLINENR, qfp->qf_lnum);
if (qfp->qf_end_lnum > 0 && qfp->qf_lnum != qfp->qf_end_lnum) {
- vim_snprintf(buf + len, bufsize - len, "-%" PRIdLINENR, qfp->qf_end_lnum);
- len += strlen(buf + len);
+ buf.size += vim_snprintf_safelen(buf.data + buf.size, IOSIZE - buf.size,
+ "-%" PRIdLINENR, qfp->qf_end_lnum);
}
if (qfp->qf_col > 0) {
- vim_snprintf(buf + len, bufsize - len, " col %d", qfp->qf_col);
- len += strlen(buf + len);
+ buf.size += vim_snprintf_safelen(buf.data + buf.size, IOSIZE - buf.size,
+ " col %d", qfp->qf_col);
if (qfp->qf_end_col > 0 && qfp->qf_col != qfp->qf_end_col) {
- vim_snprintf(buf + len, bufsize - len, "-%d", qfp->qf_end_col);
- len += strlen(buf + len);
+ buf.size += vim_snprintf_safelen(buf.data + buf.size, IOSIZE - buf.size,
+ "-%d", qfp->qf_end_col);
}
}
- ga_concat_len(gap, buf, len);
+ ga_concat_len(gap, buf.data, buf.size);
}
/// Display information (list number, list size and the title) about a
diff --git a/src/nvim/register.c b/src/nvim/register.c
@@ -570,9 +570,9 @@ static void put_reedit_in_typebuf(int silent)
/// processed next is returned in idx.
static char *execreg_line_continuation(String *lines, size_t *idx)
{
- size_t i = *idx;
- assert(i > 0);
- const size_t cmd_end = i;
+ size_t cmd_start = *idx;
+ assert(cmd_start > 0);
+ const size_t cmd_end = cmd_start;
garray_T ga;
ga_init(&ga, (int)sizeof(char), 400);
@@ -580,32 +580,34 @@ static char *execreg_line_continuation(String *lines, size_t *idx)
// search backwards to find the first line of this command.
// Any line not starting with \ or "\ is the start of the
// command.
- while (--i > 0) {
- char *p = skipwhite(lines[i].data);
+ while (--cmd_start > 0) {
+ char *p = skipwhite(lines[cmd_start].data);
if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' ')) {
break;
}
}
- const size_t cmd_start = i;
// join all the lines
- ga_concat(&ga, lines[cmd_start].data);
+ String *tmp = &lines[cmd_start];
+ ga_concat_len(&ga, tmp->data, tmp->size);
for (size_t j = cmd_start + 1; j <= cmd_end; j++) {
- char *p = skipwhite(lines[j].data);
+ tmp = &lines[j];
+ char *p = skipwhite(tmp->data);
if (*p == '\\') {
// Adjust the growsize to the current length to
// speed up concatenating many lines.
if (ga.ga_len > 400) {
ga_set_growsize(&ga, MIN(ga.ga_len, 8000));
}
- ga_concat(&ga, p + 1);
+ p++;
+ ga_concat_len(&ga, p, (size_t)(tmp->data + tmp->size - p));
}
}
ga_append(&ga, NUL);
char *str = xmemdupz(ga.ga_data, (size_t)ga.ga_len);
ga_clear(&ga);
- *idx = i;
+ *idx = cmd_start;
return str;
}