From e916f0327728c78945e6353eeeeb88749b077c0b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 29 Dec 2025 07:56:45 +0800 Subject: [PATCH] vim-patch:9.1.2030: inefficient use of ga_concat() (#37151) Problem: inefficient use of ga_concat() Solution: Use ga_concat_len() when length is known. (John Marriott) closes: vim/vim#19027 https://github.com/vim/vim/commit/32b801abc35b03e6f88021b29c24dd2411f7a065 Co-authored-by: John Marriott --- src/nvim/cmdexpand.c | 9 +++---- src/nvim/eval/encode.c | 54 ++++++++++++++++++++++++++---------------- src/nvim/getchar.c | 2 +- src/nvim/regexp.c | 6 ++--- 4 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 93f19a35be..206c815141 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -4057,7 +4057,7 @@ static int copy_substring_from_pos(pos_T *start, pos_T *end, char **match, pos_T ga_concat_len(&ga, start_ptr, (size_t)segment_len); if (!is_single_line) { if (exacttext) { - ga_concat_len(&ga, "\\n", 2); + ga_concat_len(&ga, S_LEN("\\n")); } else { ga_append(&ga, '\n'); } @@ -4067,10 +4067,11 @@ static int copy_substring_from_pos(pos_T *start, pos_T *end, char **match, pos_T if (!is_single_line) { for (linenr_T lnum = start->lnum + 1; lnum < end->lnum; lnum++) { char *line = ml_get(lnum); - ga_grow(&ga, ml_get_len(lnum) + 2); - ga_concat(&ga, line); + int linelen = ml_get_len(lnum); + ga_grow(&ga, linelen + 2); + ga_concat_len(&ga, line, (size_t)linelen); if (exacttext) { - ga_concat_len(&ga, "\\n", 2); + ga_concat_len(&ga, S_LEN("\\n")); } else { ga_append(&ga, '\n'); } diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index eb080e1791..bfb1cab619 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -124,7 +124,7 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack, const char *const partial_self_msg = _("partial self dictionary"); for (size_t i = 0; i < kv_size(*mpstack); i++) { if (i != 0) { - ga_concat(&msg_ga, ", "); + ga_concat_len(&msg_ga, S_LEN(", ")); } MPConvStackVal v = kv_A(*mpstack, i); switch (v.type) { @@ -296,7 +296,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s do { \ const char *const buf_ = (buf); \ if (buf_ == NULL) { \ - ga_concat(gap, "''"); \ + ga_concat_len(gap, S_LEN("''")); \ } else { \ const size_t len_ = (len); \ ga_grow(gap, (int)(2 + len_ + memcnt(buf_, '\'', len_))); \ @@ -321,13 +321,13 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s const blob_T *const blob_ = (blob); \ const int len_ = (len); \ if (len_ == 0) { \ - ga_concat(gap, "0z"); \ + ga_concat_len(gap, S_LEN("0z")); \ } else { \ /* Allocate space for "0z", the two hex chars per byte, and a */ \ /* "." separator after every eight hex chars. */ \ /* Example: "0z00112233.44556677.8899" */ \ ga_grow(gap, 2 + 2 * len_ + (len_ - 1) / 4); \ - ga_concat(gap, "0z"); \ + ga_concat_len(gap, S_LEN("0z")); \ char numbuf[NUMBUFLEN]; \ for (int i_ = 0; i_ < len_; i_++) { \ if (i_ > 0 && (i_ & 3) == 0) { \ @@ -352,14 +352,14 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s const float_T flt_ = (flt); \ switch (xfpclassify(flt_)) { \ case FP_NAN: { \ - ga_concat(gap, "str2float('nan')"); \ + ga_concat_len(gap, S_LEN("str2float('nan')")); \ break; \ } \ case FP_INFINITE: { \ if (flt_ < 0) { \ ga_append(gap, '-'); \ } \ - ga_concat(gap, "str2float('inf')"); \ + ga_concat_len(gap, S_LEN("str2float('inf')")); \ break; \ } \ default: { \ @@ -375,10 +375,10 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s const char *const fun_ = (fun); \ if (fun_ == NULL) { \ internal_error("string(): NULL function name"); \ - ga_concat(gap, "function(NULL"); \ + ga_concat_len(gap, S_LEN("function(NULL")); \ } else { \ const char *const prefix_ = (prefix); \ - ga_concat(gap, "function("); \ + ga_concat_len(gap, S_LEN("function(")); \ const int name_off = gap->ga_len; \ ga_concat(gap, prefix_); \ TYPVAL_ENCODE_CONV_STRING(tv, fun_, strlen(fun_)); \ @@ -391,14 +391,14 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s #define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len) \ do { \ if ((len) != 0) { \ - ga_concat(gap, ", "); \ + ga_concat_len(gap, S_LEN(", ")); \ } \ } while (0) #define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len) \ do { \ if ((ptrdiff_t)(len) != -1) { \ - ga_concat(gap, ", "); \ + ga_concat_len(gap, S_LEN(", ")); \ } \ } while (0) @@ -406,7 +406,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s ga_append(gap, ')') #define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \ - ga_concat(gap, "[]") + ga_concat_len(gap, S_LEN("[]")) #define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ ga_append(gap, '[') @@ -414,15 +414,21 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s #define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ - ga_concat(gap, "{}") + ga_concat_len(gap, S_LEN("{}")) #define TYPVAL_ENCODE_CHECK_BEFORE #define TYPVAL_ENCODE_CONV_NIL(tv) \ - ga_concat(gap, "v:null") + ga_concat_len(gap, S_LEN("v:null")) #define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ - ga_concat(gap, ((num) ? "v:true" : "v:false")) + do { \ + if (num) { \ + ga_concat_len(gap, S_LEN("v:true")); \ + } else { \ + ga_concat_len(gap, S_LEN("v:false")); \ + } \ + } while (0) #define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num) @@ -435,10 +441,10 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s ga_append(gap, '}') #define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict) \ - ga_concat(gap, ": ") + ga_concat_len(gap, S_LEN(": ")) #define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) \ - ga_concat(gap, ", ") + ga_concat_len(gap, S_LEN(", ")) #define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(label, key) @@ -546,11 +552,17 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s #undef TYPVAL_ENCODE_CONV_NIL #define TYPVAL_ENCODE_CONV_NIL(tv) \ - ga_concat(gap, "null") + ga_concat_len(gap, S_LEN("null")) #undef TYPVAL_ENCODE_CONV_BOOL #define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ - ga_concat(gap, ((num) ? "true" : "false")) + do { \ + if (num) { \ + ga_concat_len(gap, S_LEN("true")); \ + } else { \ + ga_concat_len(gap, S_LEN("false")); \ + } \ + } while (0) #undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER #define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num) \ @@ -608,7 +620,7 @@ static inline int convert_to_json_string(garray_T *const gap, const char *const { const char *utf_buf = buf; if (utf_buf == NULL) { - ga_concat(gap, "\"\""); + ga_concat_len(gap, S_LEN("\"\"")); } else { size_t utf_len = len; char *tofree = NULL; @@ -737,13 +749,13 @@ static inline int convert_to_json_string(garray_T *const gap, const char *const const blob_T *const blob_ = (blob); \ const int len_ = (len); \ if (len_ == 0) { \ - ga_concat(gap, "[]"); \ + ga_concat_len(gap, S_LEN("[]")); \ } else { \ ga_append(gap, '['); \ char numbuf[NUMBUFLEN]; \ for (int i_ = 0; i_ < len_; i_++) { \ if (i_ > 0) { \ - ga_concat(gap, ", "); \ + ga_concat_len(gap, S_LEN(", ")); \ } \ vim_snprintf((char *)numbuf, ARRAY_SIZE(numbuf), "%d", \ (int)tv_blob_get(blob_, i_)); \ diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index bce8322c5d..36a47ae036 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -3192,7 +3192,7 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat) emsg(_(e_cmd_mapping_must_end_with_cr_before_second_cmd)); aborted = true; } else if (c1 == K_SNR) { - ga_concat(&line_ga, ""); + ga_concat_len(&line_ga, S_LEN("")); } else { if (cmod != 0) { ga_append(&line_ga, K_SPECIAL); diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index e8afffbe63..8447de6624 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -11587,9 +11587,9 @@ static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent) // grow indent for state->out indent->ga_len -= 1; if (state->out1) { - ga_concat(indent, (uint8_t *)"| "); + ga_concat(indent, S_LEN("| ")); } else { - ga_concat(indent, (uint8_t *)" "); + ga_concat(indent, S_LEN(" ")); } ga_append(indent, NUL); @@ -11597,7 +11597,7 @@ static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent) // replace last part of indent for state->out1 indent->ga_len -= 3; - ga_concat(indent, (uint8_t *)" "); + ga_concat(indent, S_LEN(" ")); ga_append(indent, NUL); nfa_print_state2(debugf, state->out1, indent);