diff options
author | ZyX <kp-pav@yandex.ru> | 2018-01-03 00:00:16 +0300 |
---|---|---|
committer | ZyX <kp-pav@yandex.ru> | 2018-01-14 01:33:16 +0300 |
commit | 9ea1752d60589e8fc5e7184144bc6d1c1b9f16a3 (patch) | |
tree | 8d7fd11beeb2a300bd21f997e3fdca5b4f29382e | |
parent | 9ddeb6e187e6ef6045bf037e4225dc46c8efb693 (diff) | |
download | rneovim-9ea1752d60589e8fc5e7184144bc6d1c1b9f16a3.tar.gz rneovim-9ea1752d60589e8fc5e7184144bc6d1c1b9f16a3.tar.bz2 rneovim-9ea1752d60589e8fc5e7184144bc6d1c1b9f16a3.zip |
*: Provide list length when allocating lists
-rw-r--r-- | src/nvim/api/private/helpers.c | 2 | ||||
-rw-r--r-- | src/nvim/channel.c | 37 | ||||
-rw-r--r-- | src/nvim/eval.c | 225 | ||||
-rw-r--r-- | src/nvim/eval/decode.c | 32 | ||||
-rw-r--r-- | src/nvim/eval/typval.c | 18 | ||||
-rw-r--r-- | src/nvim/eval/typval.h | 19 | ||||
-rw-r--r-- | src/nvim/ex_cmds2.c | 6 | ||||
-rw-r--r-- | src/nvim/lua/converter.c | 7 | ||||
-rw-r--r-- | src/nvim/main.c | 2 | ||||
-rw-r--r-- | src/nvim/menu.c | 2 | ||||
-rw-r--r-- | src/nvim/ops.c | 21 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 2 | ||||
-rw-r--r-- | src/nvim/regexp.c | 4 | ||||
-rw-r--r-- | src/nvim/shada.c | 2 | ||||
-rw-r--r-- | src/nvim/tag.c | 2 | ||||
-rw-r--r-- | src/nvim/undo.c | 29 | ||||
-rw-r--r-- | src/nvim/window.c | 4 | ||||
-rw-r--r-- | test/unit/eval/helpers.lua | 5 | ||||
-rw-r--r-- | test/unit/eval/typval_spec.lua | 2 |
19 files changed, 221 insertions, 200 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 26ad7ac1a6..9baa996560 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -783,7 +783,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) break; case kObjectTypeArray: { - list_T *const list = tv_list_alloc(); + list_T *const list = tv_list_alloc((ptrdiff_t)obj.data.array.size); for (uint32_t i = 0; i < obj.data.array.size; i++) { Object item = obj.data.array.items[i]; diff --git a/src/nvim/channel.c b/src/nvim/channel.c index efef95de01..9d0a7d3c21 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -4,6 +4,7 @@ #include "nvim/api/ui.h" #include "nvim/channel.h" #include "nvim/eval.h" +#include "nvim/eval/encode.h" #include "nvim/event/socket.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/server.h" @@ -522,32 +523,18 @@ err: return 0; } -/// NB: mutates buf in place! -static list_T *buffer_to_tv_list(char *buf, size_t count) +/// Convert binary byte array to a readfile()-style list +/// +/// @param[in] buf Array to convert. +/// @param[in] len Array length. +/// +/// @return [allocated] Converted list. +static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE { - list_T *ret = tv_list_alloc(); - char *ptr = buf; - size_t remaining = count; - size_t off = 0; - - while (off < remaining) { - // append the line - if (ptr[off] == NL) { - tv_list_append_string(ret, ptr, (ssize_t)off); - size_t skip = off + 1; - ptr += skip; - remaining -= skip; - off = 0; - continue; - } - if (ptr[off] == NUL) { - // Translate NUL to NL - ptr[off] = NL; - } - off++; - } - tv_list_append_string(ret, ptr, (ssize_t)off); - return ret; + list_T *const l = tv_list_alloc(kListLenMayKnow); + encode_list_write(l, buf, len); + return l; } // vimscript job callbacks must be executed on Nvim main loop diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 2e8bf18f2d..ec32f1821d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -568,7 +568,7 @@ void eval_init(void) dict_T *const msgpack_types_dict = tv_dict_alloc(); for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) { - list_T *const type_list = tv_list_alloc(); + list_T *const type_list = tv_list_alloc(0); tv_list_set_lock(type_list, VAR_FIXED); tv_list_ref(type_list); dictitem_T *const di = tv_dict_item_alloc(msgpack_type_names[i]); @@ -591,7 +591,7 @@ void eval_init(void) dict_T *v_event = tv_dict_alloc(); v_event->dv_lock = VAR_FIXED; set_vim_var_dict(VV_EVENT, v_event); - set_vim_var_list(VV_ERRORS, tv_list_alloc()); + set_vim_var_list(VV_ERRORS, tv_list_alloc(kListLenUnknown)); set_vim_var_nr(VV_STDERR, CHAN_STDERR); set_vim_var_nr(VV_SEARCHFORWARD, 1L); set_vim_var_nr(VV_HLSEARCH, 1L); @@ -1546,6 +1546,7 @@ ex_let_vars ( assert(l != NULL); listitem_T *item = tv_list_first(l); + size_t rest_len = tv_list_len(l); while (*arg != ']') { arg = skipwhite(arg + 1); arg = ex_let_one(arg, TV_LIST_ITEM_TV(item), true, (const char_u *)",;]", @@ -1553,13 +1554,14 @@ ex_let_vars ( if (arg == NULL) { return FAIL; } + rest_len--; item = TV_LIST_ITEM_NEXT(l, item); arg = skipwhite(arg); if (*arg == ';') { /* Put the rest of the list (may be empty) in the var after ';'. * Create a new list for this. */ - list_T *const rest_list = tv_list_alloc(); + list_T *const rest_list = tv_list_alloc(rest_len); while (item != NULL) { tv_list_append_tv(rest_list, TV_LIST_ITEM_TV(item)); item = TV_LIST_ITEM_NEXT(l, item); @@ -4512,7 +4514,7 @@ eval_index ( if (!empty2 && (n2 < 0 || n2 + 1 < n1)) { n2 = -1; } - l = tv_list_alloc(); + l = tv_list_alloc(n2 - n1 + 1); item = tv_list_find(rettv->vval.v_list, n1); while (n1++ <= n2) { tv_list_append_tv(l, TV_LIST_ITEM_TV(item)); @@ -4870,7 +4872,7 @@ static int get_list_tv(char_u **arg, typval_T *rettv, int evaluate) list_T *l = NULL; if (evaluate) { - l = tv_list_alloc(); + l = tv_list_alloc(kListLenShouldKnow); } *arg = skipwhite(*arg + 1); @@ -6666,7 +6668,7 @@ static void f_argv(typval_T *argvars, typval_T *rettv, FunPtr fptr) } rettv->v_type = VAR_STRING; } else { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, ARGCOUNT); for (idx = 0; idx < ARGCOUNT; idx++) { tv_list_append_string(rettv->vval.v_list, (const char *)alist_name(&ARGLIST[idx]), -1); @@ -6776,7 +6778,7 @@ static void assert_error(garray_T *gap) if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL) { // Make sure v:errors is a list. - set_vim_var_list(VV_ERRORS, tv_list_alloc()); + set_vim_var_list(VV_ERRORS, tv_list_alloc(1)); } tv_list_append_string(vimvars[VV_ERRORS].vv_list, (const char *)gap->ga_data, (ptrdiff_t)gap->ga_len); @@ -8225,7 +8227,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr) result = eval_vars((char_u *)s, (char_u *)s, &len, NULL, &errormsg, NULL); emsg_off--; if (rettv->v_type == VAR_LIST) { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, (result != NULL)); if (result != NULL) { tv_list_append_string(rettv->vval.v_list, (const char *)result, -1); } @@ -8248,8 +8250,8 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_string = ExpandOne(&xpc, (char_u *)s, NULL, options, WILD_ALL); } else { - tv_list_alloc_ret(rettv); ExpandOne(&xpc, (char_u *)s, NULL, options, WILD_ALL_KEEP); + tv_list_alloc_ret(rettv, xpc.xp_numfiles); for (int i = 0; i < xpc.xp_numfiles; i++) { tv_list_append_string(rettv->vval.v_list, (const char *)xpc.xp_files[i], -1); @@ -8266,7 +8268,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// "menu_get(path [, modes])" function static void f_menu_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, kListLenMayKnow); int modes = MENU_ALL_MODES; if (argvars[1].v_type == VAR_STRING) { const char_u *const strmodes = (char_u *)tv_get_string(&argvars[1]); @@ -8427,7 +8429,7 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) } if (count < 0) { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, kListLenUnknown); } if (*fname != NUL && !error) { @@ -9108,7 +9110,7 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } else if (strcmp(what, "args") == 0) { rettv->v_type = VAR_LIST; - if (tv_list_alloc_ret(rettv) != NULL) { + if (tv_list_alloc_ret(rettv, pt->pt_argc) != NULL) { for (int i = 0; i < pt->pt_argc; i++) { tv_list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]); } @@ -9132,8 +9134,10 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// Returns information about signs placed in a buffer as list of dicts. -static void get_buffer_signs(buf_T *buf, list_T *l) +static list_T *get_buffer_signs(buf_T *buf) + FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { + list_T *const l = tv_list_alloc(kListLenMayKnow); for (signlist_T *sign = buf->b_signlist; sign; sign = sign->next) { dict_T *const d = tv_dict_alloc(); @@ -9144,6 +9148,7 @@ static void get_buffer_signs(buf_T *buf, list_T *l) tv_list_append_dict(l, d); } + return l; } /// Returns buffer options, variables and other attributes in a dictionary. @@ -9167,7 +9172,7 @@ static dict_T *get_buffer_info(buf_T *buf) tv_dict_add_dict(dict, S_LEN("variables"), buf->b_vars); // List of windows displaying this buffer - list_T *const windows = tv_list_alloc(); + list_T *const windows = tv_list_alloc(kListLenMayKnow); FOR_ALL_TAB_WINDOWS(tp, wp) { if (wp->w_buffer == buf) { tv_list_append_number(windows, (varnumber_T)wp->handle); @@ -9177,9 +9182,7 @@ static dict_T *get_buffer_info(buf_T *buf) if (buf->b_signlist != NULL) { // List of signs placed in this buffer - list_T *const signs = tv_list_alloc(); - get_buffer_signs(buf, signs); - tv_dict_add_list(dict, S_LEN("signs"), signs); + tv_dict_add_list(dict, S_LEN("signs"), get_buffer_signs(buf)); } return dict; @@ -9193,7 +9196,7 @@ static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) bool sel_buflisted = false; bool sel_bufloaded = false; - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, kListLenMayKnow); // List of all the buffers or selected buffers if (argvars[0].v_type == VAR_DICT) { @@ -9252,35 +9255,31 @@ static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv) { - char_u *p; - - rettv->v_type = VAR_STRING; + rettv->v_type = (retlist ? VAR_LIST : VAR_STRING); rettv->vval.v_string = NULL; - if (retlist) { - tv_list_alloc_ret(rettv); - } - if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0) + if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0 || end < start) { + tv_list_alloc_ret(rettv, 0); return; + } - if (!retlist) { - if (start >= 1 && start <= buf->b_ml.ml_line_count) - p = ml_get_buf(buf, start, FALSE); - else - p = (char_u *)""; - rettv->vval.v_string = vim_strsave(p); - } else { - if (end < start) - return; - - if (start < 1) + if (retlist) { + if (start < 1) { start = 1; - if (end > buf->b_ml.ml_line_count) + } + if (end > buf->b_ml.ml_line_count) { end = buf->b_ml.ml_line_count; + } + tv_list_alloc_ret(rettv, end - start + 1); while (start <= end) { tv_list_append_string(rettv->vval.v_list, (const char *)ml_get_buf(buf, start++, false), -1); } + } else { + rettv->v_type = VAR_STRING; + rettv->vval.v_string = ((start >= 1 && start <= buf->b_ml.ml_line_count) + ? vim_strsave(ml_get_buf(buf, start, false)) + : NULL); } } @@ -9605,8 +9604,8 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr) theend: pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); - tv_list_alloc_ret(rettv); ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP); + tv_list_alloc_ret(rettv, xpc.xp_numfiles); for (int i = 0; i < xpc.xp_numfiles; i++) { tv_list_append_string(rettv->vval.v_list, (const char *)xpc.xp_files[i], @@ -9900,7 +9899,7 @@ static void f_getline(typval_T *argvars, typval_T *rettv, FunPtr fptr) const linenr_T lnum = tv_get_lnum(argvars); if (argvars[1].v_type == VAR_UNKNOWN) { - end = 0; + end = lnum; retlist = false; } else { end = tv_get_lnum(&argvars[1]); @@ -9914,7 +9913,7 @@ static void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv) { if (what_arg->v_type == VAR_UNKNOWN) { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, kListLenMayKnow); if (is_qf || wp != NULL) { (void)get_errorlist(wp, -1, rettv->vval.v_list); } @@ -9949,7 +9948,7 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) matchitem_T *cur = curwin->w_match_head; int i; - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, kListLenMayKnow); while (cur != NULL) { dict_T *dict = tv_dict_alloc(); if (cur->match.regprog == NULL) { @@ -9962,7 +9961,7 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (llpos->lnum == 0) { break; } - list_T *l = tv_list_alloc(); + list_T *const l = tv_list_alloc(1 + (llpos->col > 0 ? 2 : 0)); tv_list_append_number(l, (varnumber_T)llpos->lnum); if (llpos->col > 0) { tv_list_append_number(l, (varnumber_T)llpos->col); @@ -10011,7 +10010,7 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos) fp = var2fpos(&argvars[0], true, &fnum); } - list_T *l = tv_list_alloc_ret(rettv); + list_T *const l = tv_list_alloc_ret(rettv, 4 + (!!getcurpos)); tv_list_append_number(l, (fnum != -1) ? (varnumber_T)fnum : (varnumber_T)0); tv_list_append_number(l, ((fp != NULL) ? (varnumber_T)fp->lnum @@ -10084,10 +10083,10 @@ static void f_getreg(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (return_list) { rettv->v_type = VAR_LIST; - rettv->vval.v_list = + rettv->vval.v_list = get_reg_contents(regname, (arg2 ? kGRegExprSrc : 0) | kGRegList); if (rettv->vval.v_list == NULL) { - rettv->vval.v_list = tv_list_alloc(); + rettv->vval.v_list = tv_list_alloc(0); } tv_list_ref(rettv->vval.v_list); } else { @@ -10137,7 +10136,7 @@ static dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx) tv_dict_add_nr(dict, S_LEN("tabnr"), tp_idx); - list_T *const l = tv_list_alloc(); + list_T *const l = tv_list_alloc(kListLenMayKnow); FOR_ALL_WINDOWS_IN_TAB(wp, tp) { tv_list_append_number(l, (varnumber_T)wp->handle); } @@ -10154,7 +10153,9 @@ static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) { tabpage_T *tparg = NULL; - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, (argvars[0].v_type == VAR_UNKNOWN + ? 1 + : kListLenMayKnow)); if (argvars[0].v_type != VAR_UNKNOWN) { // Information about one tab page @@ -10253,7 +10254,7 @@ static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) { win_T *wparg = NULL; - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, kListLenMayKnow); if (argvars[0].v_type != VAR_UNKNOWN) { wparg = win_id2wp(argvars); @@ -10478,9 +10479,9 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_string = ExpandOne( &xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options, WILD_ALL); } else { - tv_list_alloc_ret(rettv); ExpandOne(&xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options, WILD_ALL_KEEP); + tv_list_alloc_ret(rettv, xpc.xp_numfiles); for (int i = 0; i < xpc.xp_numfiles; i++) { tv_list_append_string(rettv->vval.v_list, (const char *)xpc.xp_files[i], -1); @@ -10529,7 +10530,7 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (rettv->v_type == VAR_STRING) { rettv->vval.v_string = ga_concat_strings_sep(&ga, "\n"); } else { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, ga.ga_len); for (int i = 0; i < ga.ga_len; i++) { tv_list_append_string(rettv->vval.v_list, ((const char **)(ga.ga_data))[i], -1); @@ -11429,7 +11430,7 @@ static void dict_list(typval_T *const tv, typval_T *const rettv, return; } - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, tv_dict_len(tv->vval.v_dict)); TV_DICT_ITER(tv->vval.v_dict, di, { typval_T tv = { .v_lock = VAR_UNLOCKED }; @@ -11446,7 +11447,7 @@ static void dict_list(typval_T *const tv, typval_T *const rettv, } case kDictListItems: { // items() - list_T *const sub_l = tv_list_alloc(); + list_T *const sub_l = tv_list_alloc(2); tv.v_type = VAR_LIST; tv.vval.v_list = sub_l; tv_list_ref(sub_l); @@ -11776,7 +11777,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - list_T *rv = tv_list_alloc(); + list_T *const rv = tv_list_alloc(tv_list_len(args)); // restore the parent queue for any jobs still alive for (i = 0; i < tv_list_len(args); i++) { @@ -12204,12 +12205,12 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, switch (type) { // matchlist(): return empty list when there are no matches. case kSomeMatchList: { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, kListLenMayKnow); break; } // matchstrpos(): return ["", -1, -1, -1] case kSomeMatchStrPos: { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, 4); tv_list_append_string(rettv->vval.v_list, "", 0); tv_list_append_number(rettv->vval.v_list, -1); tv_list_append_number(rettv->vval.v_list, -1); @@ -12516,10 +12517,12 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_matcharg(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - tv_list_alloc_ret(rettv); - const int id = tv_get_number(&argvars[0]); + tv_list_alloc_ret(rettv, (id >= 1 && id <= 3 + ? 2 + : 0)); + if (id >= 1 && id <= 3) { matchitem_T *const m = (matchitem_T *)get_match(curwin, id); @@ -12705,8 +12708,8 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, FunPtr fptr) EMSG2(_(e_listarg), "msgpackdump()"); return; } - list_T *ret_list = tv_list_alloc_ret(rettv); - list_T *list = argvars[0].vval.v_list; + list_T *const ret_list = tv_list_alloc_ret(rettv, kListLenMayKnow); + list_T *const list = argvars[0].vval.v_list; msgpack_packer *lpacker = msgpack_packer_new(ret_list, &encode_list_write); const char *const msg = _("msgpackdump() argument, index %i"); // Assume that translation will not take more then 4 times more space @@ -12730,8 +12733,8 @@ static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr) EMSG2(_(e_listarg), "msgpackparse()"); return; } - list_T *ret_list = tv_list_alloc_ret(rettv); - const list_T *list = argvars[0].vval.v_list; + list_T *const ret_list = tv_list_alloc_ret(rettv, kListLenMayKnow); + const list_T *const list = argvars[0].vval.v_list; if (tv_list_len(list) == 0) { return; } @@ -12986,7 +12989,7 @@ static void f_range(typval_T *argvars, typval_T *rettv, FunPtr fptr) } else if (stride > 0 ? end + 1 < start : end - 1 > start) { emsgf(_("E727: Start past end")); } else { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, (end - start) / stride); for (i = start; stride > 0 ? i <= end : i >= end; i += stride) { tv_list_append_number(rettv->vval.v_list, (varnumber_T)i); } @@ -13017,8 +13020,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - tv_list_alloc_ret(rettv); - list_T *const l = rettv->vval.v_list; + list_T *const l = tv_list_alloc_ret(rettv, kListLenUnknown); // Always open the file in binary mode, library functions have a mind of // their own about CR-LF conversion. @@ -13231,7 +13233,7 @@ static void f_reltime(typval_T *argvars, typval_T *rettv, FunPtr fptr) STATIC_ASSERT(sizeof(u.prof) == sizeof(u) && sizeof(u.split) == sizeof(u), "type punning will produce incorrect results on this platform"); - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, 2); tv_list_append_number(rettv->vval.v_list, u.split.high); tv_list_append_number(rettv->vval.v_list, u.split.low); } @@ -13324,7 +13326,8 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (li == NULL) { // Didn't find "item2" after "item". emsgf(_(e_invrange)); } else { - tv_list_move_items(l, item, item2, tv_list_alloc_ret(rettv), cnt); + tv_list_move_items(l, item, item2, tv_list_alloc_ret(rettv, cnt), + cnt); } } } @@ -13354,7 +13357,7 @@ static void f_repeat(typval_T *argvars, typval_T *rettv, FunPtr fptr) { varnumber_T n = tv_get_number(&argvars[1]); if (argvars[0].v_type == VAR_LIST) { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, (n > 0) * n * tv_list_len(argvars[0].vval.v_list)); while (n-- > 0) { tv_list_extend(rettv->vval.v_list, argvars[0].vval.v_list, NULL); } @@ -14124,7 +14127,7 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) int lnum = 0; int col = 0; - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, 2); if (searchpair_cmn(argvars, &match_pos) > 0) { lnum = match_pos.lnum; @@ -14292,18 +14295,14 @@ do_searchpair ( static void f_searchpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) { pos_T match_pos; - int lnum = 0; - int col = 0; - int n; int flags = 0; - tv_list_alloc_ret(rettv); + const int n = search_cmn(argvars, &match_pos, &flags); - n = search_cmn(argvars, &match_pos, &flags); - if (n > 0) { - lnum = match_pos.lnum; - col = match_pos.col; - } + tv_list_alloc_ret(rettv, 2 + (!!(flags & SP_SUBPAT))); + + const int lnum = (n > 0 ? match_pos.lnum : 0); + const int col = (n > 0 ? match_pos.col : 0); tv_list_append_number(rettv->vval.v_list, (varnumber_T)lnum); tv_list_append_number(rettv->vval.v_list, (varnumber_T)col); @@ -14319,7 +14318,7 @@ static void f_serverlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) char **addrs = server_address_list(&n); // Copy addrs into a linked list. - list_T *l = tv_list_alloc_ret(rettv); + list_T *const l = tv_list_alloc_ret(rettv, n); for (size_t i = 0; i < n; i++) { tv_list_append_allocated_string(l, addrs[i]); } @@ -14715,7 +14714,7 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) dictitem_T *const di = tv_dict_find(d, S_LEN("pattern")); if (di == NULL) { if (s == NULL) { - s = tv_list_alloc(); + s = tv_list_alloc(9); } // match from matchaddpos() @@ -15531,8 +15530,6 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr) hlf_T attr = HLF_COUNT; size_t len = 0; - tv_list_alloc_ret(rettv); - if (argvars[0].v_type == VAR_UNKNOWN) { // Find the start and length of the badly spelled word. len = spell_move_to(curwin, FORWARD, true, true, &attr); @@ -15557,6 +15554,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr) } assert(len <= INT_MAX); + tv_list_alloc_ret(rettv, 2); tv_list_append_string(rettv->vval.v_list, word, len); tv_list_append_string(rettv->vval.v_list, (attr == HLF_SPB ? "bad" @@ -15573,35 +15571,36 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, FunPtr fptr) { bool typeerr = false; int maxcount; - garray_T ga; + garray_T ga = GA_EMPTY_INIT_VALUE; bool need_capital = false; - tv_list_alloc_ret(rettv); - if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) { const char *const str = tv_get_string(&argvars[0]); if (argvars[1].v_type != VAR_UNKNOWN) { maxcount = tv_get_number_chk(&argvars[1], &typeerr); if (maxcount <= 0) { - return; + goto f_spellsuggest_return; } if (argvars[2].v_type != VAR_UNKNOWN) { need_capital = tv_get_number_chk(&argvars[2], &typeerr); if (typeerr) { - return; + goto f_spellsuggest_return; } } - } else + } else { maxcount = 25; + } spell_suggest_list(&ga, (char_u *)str, maxcount, need_capital, false); + } - for (int i = 0; i < ga.ga_len; i++) { - char *p = ((char **)ga.ga_data)[i]; - tv_list_append_allocated_string(rettv->vval.v_list, p); - } - ga_clear(&ga); +f_spellsuggest_return: + tv_list_alloc_ret(rettv, (ptrdiff_t)ga.ga_len); + for (int i = 0; i < ga.ga_len; i++) { + char *const p = ((char **)ga.ga_data)[i]; + tv_list_append_allocated_string(rettv->vval.v_list, p); } + ga_clear(&ga); } static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr) @@ -15633,10 +15632,11 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr) pat = "[\\x01- ]\\+"; } - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, kListLenMayKnow); - if (typeerr) + if (typeerr) { return; + } regmatch.regprog = vim_regcomp((char_u *)pat, RE_MAGIC + RE_STRING); if (regmatch.regprog != NULL) { @@ -16263,7 +16263,6 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr) memset(str, NUL, sizeof(str)); - tv_list_alloc_ret(rettv); if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count && col >= 0 && (size_t)col <= STRLEN(ml_get(lnum)) && curwin->w_p_cole > 0) { (void)syn_get_id(curwin, lnum, col, false, NULL, false); @@ -16276,14 +16275,12 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr) cchar = lcs_conceal; } if (cchar != NUL) { - if (has_mbyte) - (*mb_char2bytes)(cchar, str); - else - str[0] = cchar; + utf_char2bytes(cchar, str); } } } + tv_list_alloc_ret(rettv, 3); tv_list_append_number(rettv->vval.v_list, (syntax_flags & HL_CONCEAL) != 0); // -1 to auto-determine strlen tv_list_append_string(rettv->vval.v_list, (const char *)str, -1); @@ -16306,7 +16303,7 @@ static void f_synstack(typval_T *argvars, typval_T *rettv, FunPtr fptr) && lnum <= curbuf->b_ml.ml_line_count && col >= 0 && (size_t)col <= STRLEN(ml_get(lnum))) { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, kListLenMayKnow); (void)syn_get_id(curwin, lnum, col, false, NULL, true); int id; @@ -16322,7 +16319,7 @@ static list_T *string_to_list(const char *str, size_t len, const bool keepempty) if (!keepempty && str[len - 1] == NL) { len--; } - list_T *const list = tv_list_alloc(); + list_T *const list = tv_list_alloc(kListLenMayKnow); encode_list_write(list, str, len); return list; } @@ -16368,7 +16365,7 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv, if (res == NULL) { if (retlist) { // return an empty list when there's no output - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, 0); } else { rettv->vval.v_string = (char_u *) xstrdup(""); } @@ -16434,7 +16431,7 @@ static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } if (wp != NULL) { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, kListLenMayKnow); while (wp != NULL) { tv_list_append_number(rettv->vval.v_list, wp->w_buffer->b_fnum); wp = wp->w_next; @@ -16532,7 +16529,7 @@ static void f_tagfiles(typval_T *argvars, typval_T *rettv, FunPtr fptr) char *fname; tagname_T tn; - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, kListLenUnknown); fname = xmalloc(MAXPATHL); bool first = true; @@ -16561,8 +16558,8 @@ static void f_taglist(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (argvars[1].v_type != VAR_UNKNOWN) { fname = tv_get_string(&argvars[1]); } - (void)get_tags(tv_list_alloc_ret(rettv), (char_u *)tag_pattern, - (char_u *)fname); + (void)get_tags(tv_list_alloc_ret(rettv, kListLenUnknown), + (char_u *)tag_pattern, (char_u *)fname); } /* @@ -16803,7 +16800,9 @@ static void add_timer_info_all(typval_T *rettv) /// "timer_info([timer])" function static void f_timer_info(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, (argvars[0].v_type != VAR_UNKNOWN + ? 1 + : timers->table->n_occupied)); if (argvars[0].v_type != VAR_UNKNOWN) { if (argvars[0].v_type != VAR_NUMBER) { EMSG(_(e_number_exp)); @@ -17163,7 +17162,6 @@ static void f_undotree(typval_T *argvars, typval_T *rettv, FunPtr fptr) tv_dict_alloc_ret(rettv); dict_T *dict = rettv->vval.v_dict; - list_T *list; tv_dict_add_nr(dict, S_LEN("synced"), (varnumber_T)curbuf->b_u_synced); tv_dict_add_nr(dict, S_LEN("seq_last"), (varnumber_T)curbuf->b_u_seq_last); @@ -17173,9 +17171,7 @@ static void f_undotree(typval_T *argvars, typval_T *rettv, FunPtr fptr) tv_dict_add_nr(dict, S_LEN("time_cur"), (varnumber_T)curbuf->b_u_time_cur); tv_dict_add_nr(dict, S_LEN("save_cur"), (varnumber_T)curbuf->b_u_save_nr_cur); - list = tv_list_alloc(); - u_eval_tree(curbuf->b_u_oldhead, list); - tv_dict_add_list(dict, S_LEN("entries"), list); + tv_dict_add_list(dict, S_LEN("entries"), u_eval_tree(curbuf->b_u_oldhead)); } /* @@ -17234,7 +17230,7 @@ static void f_wildmenumode(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// "win_findbuf()" function static void f_win_findbuf(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - tv_list_alloc_ret(rettv); + tv_list_alloc_ret(rettv, kListLenMayKnow); win_findbuf(argvars, rettv->vval.v_list); } @@ -17253,8 +17249,7 @@ static void f_win_gotoid(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// "win_id2tabwin()" function static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - tv_list_alloc_ret(rettv); - win_id2tabwin(argvars, rettv->vval.v_list); + win_id2tabwin(argvars, rettv); } /// "win_id2win()" function @@ -22367,7 +22362,7 @@ static void script_host_eval(char *name, typval_T *argvars, typval_T *rettv) return; } - list_T *args = tv_list_alloc(); + list_T *args = tv_list_alloc(1); tv_list_append_string(args, (const char *)argvars[0].vval.v_string, -1); *rettv = eval_call_provider(name, "eval", args); } diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index af4e055d23..c729d00ae7 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -150,7 +150,7 @@ static inline int json_decoder_pop(ValuesStackItem obj, } obj_di->di_tv = obj.val; } else { - list_T *const kv_pair = tv_list_alloc(); + list_T *const kv_pair = tv_list_alloc(2); tv_list_append_list(last_container.special_val, kv_pair); tv_list_append_owned_tv(kv_pair, key.val); tv_list_append_owned_tv(kv_pair, obj.val); @@ -221,13 +221,18 @@ static inline int json_decoder_pop(ValuesStackItem obj, /// Create a new special dictionary that ought to represent a MAP /// /// @param[out] ret_tv Address where new special dictionary is saved. +/// @param[in] len Expected number of items to be populated before list +/// becomes accessible from VimL. It is still valid to +/// underpopulate a list, value only controls how many elements +/// will be allocated in advance. @see ListLenSpecials. /// /// @return [allocated] list which should contain key-value pairs. Return value /// may be safely ignored. -list_T *decode_create_map_special_dict(typval_T *const ret_tv) +list_T *decode_create_map_special_dict(typval_T *const ret_tv, + const ptrdiff_t len) FUNC_ATTR_NONNULL_ALL { - list_T *const list = tv_list_alloc(); + list_T *const list = tv_list_alloc(len); tv_list_ref(list); create_special_dict(ret_tv, kMPMap, ((typval_T) { .v_type = VAR_LIST, @@ -263,7 +268,7 @@ typval_T decode_string(const char *const s, const size_t len, ? ((s != NULL) && (memchr(s, NUL, len) != NULL)) : (bool)hasnul); if (really_hasnul) { - list_T *const list = tv_list_alloc(); + list_T *const list = tv_list_alloc(kListLenMayKnow); tv_list_ref(list); typval_T tv; create_special_dict(&tv, binary ? kMPBinary : kMPString, ((typval_T) { @@ -843,7 +848,7 @@ json_decode_string_cycle_start: break; } case '[': { - list_T *list = tv_list_alloc(); + list_T *list = tv_list_alloc(kListLenMayKnow); tv_list_ref(list); typval_T tv = { .v_type = VAR_LIST, @@ -864,7 +869,7 @@ json_decode_string_cycle_start: list_T *val_list = NULL; if (next_map_special) { next_map_special = false; - val_list = decode_create_map_special_dict(&tv); + val_list = decode_create_map_special_dict(&tv, kListLenMayKnow); } else { dict_T *dict = tv_dict_alloc(); dict->dv_refcount++; @@ -964,7 +969,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv) .vval = { .v_number = (varnumber_T) mobj.via.u64 }, }; } else { - list_T *const list = tv_list_alloc(); + list_T *const list = tv_list_alloc(4); tv_list_ref(list); create_special_dict(rettv, kMPInteger, ((typval_T) { .v_type = VAR_LIST, @@ -987,7 +992,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv) .vval = { .v_number = (varnumber_T) mobj.via.i64 }, }; } else { - list_T *const list = tv_list_alloc(); + list_T *const list = tv_list_alloc(4); tv_list_ref(list); create_special_dict(rettv, kMPInteger, ((typval_T) { .v_type = VAR_LIST, @@ -1033,7 +1038,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv) break; } case MSGPACK_OBJECT_ARRAY: { - list_T *const list = tv_list_alloc(); + list_T *const list = tv_list_alloc((ptrdiff_t)mobj.via.array.size); tv_list_ref(list); *rettv = (typval_T) { .v_type = VAR_LIST, @@ -1085,9 +1090,10 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv) } break; msgpack_to_vim_generic_map: {} - list_T *const list = decode_create_map_special_dict(rettv); + list_T *const list = decode_create_map_special_dict( + rettv, (ptrdiff_t)mobj.via.map.size); for (size_t i = 0; i < mobj.via.map.size; i++) { - list_T *const kv_pair = tv_list_alloc(); + list_T *const kv_pair = tv_list_alloc(2); tv_list_append_list(list, kv_pair); typval_T key_tv = { .v_type = VAR_UNKNOWN }; @@ -1107,10 +1113,10 @@ msgpack_to_vim_generic_map: {} break; } case MSGPACK_OBJECT_EXT: { - list_T *const list = tv_list_alloc(); + list_T *const list = tv_list_alloc(2); tv_list_ref(list); tv_list_append_number(list, mobj.via.ext.type); - list_T *const ext_val_list = tv_list_alloc(); + list_T *const ext_val_list = tv_list_alloc(kListLenMayKnow); tv_list_append_list(list, ext_val_list); create_special_dict(rettv, kMPExt, ((typval_T) { .v_type = VAR_LIST, diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index ac6c8c8aa6..6f829be0b4 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -132,8 +132,14 @@ void tv_list_watch_fix(list_T *const l, const listitem_T *const item) /// /// Caller should take care of the reference count. /// +/// @param[in] len Expected number of items to be populated before list +/// becomes accessible from VimL. It is still valid to +/// underpopulate a list, value only controls how many elements +/// will be allocated in advance. Currently does nothing. +/// @see ListLenSpecials. +/// /// @return [allocated] new list. -list_T *tv_list_alloc(void) +list_T *tv_list_alloc(const ptrdiff_t len) FUNC_ATTR_NONNULL_RET { list_T *const list = xcalloc(1, sizeof(list_T)); @@ -521,7 +527,7 @@ list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig, return NULL; } - list_T *copy = tv_list_alloc(); + list_T *copy = tv_list_alloc(tv_list_len(orig)); tv_list_ref(copy); if (copyID != 0) { // Do this before adding the items, because one of the items may @@ -1817,12 +1823,16 @@ void tv_dict_set_keys_readonly(dict_T *const dict) /// Also sets reference count. /// /// @param[out] ret_tv Structure where list is saved. +/// @param[in] len Expected number of items to be populated before list +/// becomes accessible from VimL. It is still valid to +/// underpopulate a list, value only controls how many elements +/// will be allocated in advance. @see ListLenSpecials. /// /// @return [allocated] pointer to the created list. -list_T *tv_list_alloc_ret(typval_T *const ret_tv) +list_T *tv_list_alloc_ret(typval_T *const ret_tv, const ptrdiff_t len) FUNC_ATTR_NONNULL_ALL { - list_T *const l = tv_list_alloc(); + list_T *const l = tv_list_alloc(len); ret_tv->vval.v_list = l; ret_tv->v_type = VAR_LIST; ret_tv->v_lock = VAR_UNLOCKED; diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index c9a9a3e7e8..3993a384d2 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -31,6 +31,25 @@ typedef double float_T; /// Refcount for dict or list that should not be freed enum { DO_NOT_FREE_CNT = (INT_MAX / 2) }; +/// Additional values for tv_list_alloc() len argument +enum { + /// List length is not known in advance + /// + /// To be used when there is neither a way to know how many elements will be + /// needed nor are any educated guesses. + kListLenUnknown = -1, + /// List length *should* be known, but is actually not + /// + /// All occurrences of this value should be eventually removed. This is for + /// the case when the only reason why list length is not known is that it + /// would be hard to code without refactoring, but refactoring is needed. + kListLenShouldKnow = -2, + /// List length may be known in advance, but it requires too much effort + /// + /// To be used when it looks impractical to determine list length. + kListLenMayKnow = -3, +} ListLenSpecials; + /// Maximal possible value of varnumber_T variable #define VARNUMBER_MAX INT64_MAX #define UVARNUMBER_MAX UINT64_MAX diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index ec4ce63e17..28b021d4e4 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -3758,7 +3758,7 @@ static void script_host_execute(char *name, exarg_T *eap) char *const script = script_get(eap, &len); if (script != NULL) { - list_T *const args = tv_list_alloc(); + list_T *const args = tv_list_alloc(3); // script tv_list_append_allocated_string(args, script); // current range @@ -3773,7 +3773,7 @@ static void script_host_execute_file(char *name, exarg_T *eap) uint8_t buffer[MAXPATHL]; vim_FullName((char *)eap->arg, (char *)buffer, sizeof(buffer), false); - list_T *args = tv_list_alloc(); + list_T *args = tv_list_alloc(3); // filename tv_list_append_string(args, (const char *)buffer, -1); // current range @@ -3784,7 +3784,7 @@ static void script_host_execute_file(char *name, exarg_T *eap) static void script_host_do_range(char *name, exarg_T *eap) { - list_T *args = tv_list_alloc(); + list_T *args = tv_list_alloc(3); tv_list_append_number(args, (int)eap->line1); tv_list_append_number(args, (int)eap->line2); tv_list_append_string(args, (const char *)eap->arg, -1); diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 61cb428923..9e3063b164 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -211,7 +211,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) size_t len; const char *s = lua_tolstring(lstate, -2, &len); if (cur.special) { - list_T *const kv_pair = tv_list_alloc(); + list_T *const kv_pair = tv_list_alloc(2); typval_T s_tv = decode_string(s, len, kTrue, false, false); if (s_tv.v_type == VAR_UNKNOWN) { @@ -321,7 +321,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) switch (table_props.type) { case kObjectTypeArray: { cur.tv->v_type = VAR_LIST; - cur.tv->vval.v_list = tv_list_alloc(); + cur.tv->vval.v_list = tv_list_alloc((ptrdiff_t)table_props.maxidx); tv_list_ref(cur.tv->vval.v_list); if (table_props.maxidx != 0) { cur.container = true; @@ -338,7 +338,8 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) } else { cur.special = table_props.has_string_with_nul; if (table_props.has_string_with_nul) { - decode_create_map_special_dict(cur.tv); + decode_create_map_special_dict( + cur.tv, (ptrdiff_t)table_props.string_keys_num); assert(cur.tv->v_type == VAR_DICT); dictitem_T *const val_di = tv_dict_find(cur.tv->vval.v_dict, S_LEN("_VAL")); diff --git a/src/nvim/main.c b/src/nvim/main.c index 0b24023ad0..015df5d070 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -412,7 +412,7 @@ int main(int argc, char **argv) } // It's better to make v:oldfiles an empty list than NULL. if (get_vim_var_list(VV_OLDFILES) == NULL) { - set_vim_var_list(VV_OLDFILES, tv_list_alloc()); + set_vim_var_list(VV_OLDFILES, tv_list_alloc(0)); } /* diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 01c8e94bac..42417f75d5 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -714,7 +714,7 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes) } } else { // visit recursively all children - list_T *children_list = tv_list_alloc(); + list_T *const children_list = tv_list_alloc(kListLenMayKnow); for (menu = menu->children; menu != NULL; menu = menu->next) { dict_T *dic = menu_get_recursive(menu, modes); if (tv_dict_len(dict) > 0) { diff --git a/src/nvim/ops.c b/src/nvim/ops.c index a5e131190d..b606f10b88 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -2564,7 +2564,7 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg) dict_T *dict = get_vim_var_dict(VV_EVENT); // the yanked text - list_T *list = tv_list_alloc(); + list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size); for (size_t i = 0; i < reg->y_size; i++) { tv_list_append_string(list, (const char *)reg->y_array[i], -1); } @@ -4854,7 +4854,7 @@ static void *get_reg_wrap_one_line(char_u *s, int flags) if (!(flags & kGRegList)) { return s; } - list_T *const list = tv_list_alloc(); + list_T *const list = tv_list_alloc(1); tv_list_append_allocated_string(list, (char *)s); return list; } @@ -4904,7 +4904,7 @@ void *get_reg_contents(int regname, int flags) return NULL; if (flags & kGRegList) { - list_T *list = tv_list_alloc(); + list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size); for (size_t i = 0; i < reg->y_size; i++) { tv_list_append_string(list, (const char *)reg->y_array[i], -1); } @@ -5593,7 +5593,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) } free_register(reg); - list_T *const args = tv_list_alloc(); + list_T *const args = tv_list_alloc(1); const char regname = (char)name; tv_list_append_string(args, ®name, 1); @@ -5712,15 +5712,13 @@ static void set_clipboard(int name, yankreg_T *reg) return; } - list_T *lines = tv_list_alloc(); + list_T *const lines = tv_list_alloc( + (ptrdiff_t)reg->y_size + (reg->y_type != kMTCharWise)); for (size_t i = 0; i < reg->y_size; i++) { tv_list_append_string(lines, (const char *)reg->y_array[i], -1); } - list_T *args = tv_list_alloc(); - tv_list_append_list(args, lines); - char regtype; switch (reg->y_type) { case kMTLineWise: { @@ -5741,10 +5739,11 @@ static void set_clipboard(int name, yankreg_T *reg) assert(false); } } - tv_list_append_string(args, ®type, 1); - const char regname = (char)name; - tv_list_append_string(args, ®name, 1); + list_T *args = tv_list_alloc(3); + tv_list_append_list(args, lines); + tv_list_append_string(args, ®type, 1); + tv_list_append_string(args, ((char[]) { (char)name }), 1); (void)eval_call_provider("clipboard", "set", args); } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 224e43008d..63252df3dc 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -4193,7 +4193,7 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) } } if ((status == OK) && (flags & QF_GETLIST_ITEMS)) { - list_T *l = tv_list_alloc(); + list_T *l = tv_list_alloc(kListLenMayKnow); (void)get_errorlist(wp, qf_idx, l); tv_dict_add_list(retdict, S_LEN("items"), l); } diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index ddc3681867..e4de43b49e 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -7044,7 +7044,7 @@ list_T *reg_submatch_list(int no) colnr_T scol = rsm.sm_mmatch->startpos[no].col; colnr_T ecol = rsm.sm_mmatch->endpos[no].col; - list = tv_list_alloc(); + list = tv_list_alloc(elnum - slnum + 1); s = (const char *)reg_getline_submatch(slnum) + scol; if (slnum == elnum) { @@ -7063,7 +7063,7 @@ list_T *reg_submatch_list(int no) if (s == NULL || rsm.sm_match->endp[no] == NULL) { return NULL; } - list = tv_list_alloc(); + list = tv_list_alloc(1); tv_list_append_string(list, s, (const char *)rsm.sm_match->endp[no] - s); } diff --git a/src/nvim/shada.c b/src/nvim/shada.c index ce9303f14d..c00fd912ec 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -1217,7 +1217,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) khash_t(fnamebufs) fname_bufs = KHASH_EMPTY_TABLE(fnamebufs); khash_t(strset) oldfiles_set = KHASH_EMPTY_TABLE(strset); if (get_old_files && (oldfiles_list == NULL || force)) { - oldfiles_list = tv_list_alloc(); + oldfiles_list = tv_list_alloc(kListLenUnknown); set_vim_var_list(VV_OLDFILES, oldfiles_list); } ShaDaReadResult srni_ret; diff --git a/src/nvim/tag.c b/src/nvim/tag.c index be9d621c7d..f23465e501 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -667,7 +667,7 @@ do_tag ( fname = xmalloc(MAXPATHL + 1); cmd = xmalloc(CMDBUFFSIZE + 1); - list = tv_list_alloc(); + list = tv_list_alloc(num_matches); for (i = 0; i < num_matches; ++i) { int len, cmd_len; diff --git a/src/nvim/undo.c b/src/nvim/undo.c index f611a3bb29..b902f82f31 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2941,17 +2941,20 @@ bool curbufIsChanged(void) && (curbuf->b_changed || file_ff_differs(curbuf, true))); } -/* - * For undotree(): Append the list of undo blocks at "first_uhp" to "list". - * Recursive. - */ -void u_eval_tree(u_header_T *first_uhp, list_T *list) +/// Append the list of undo blocks to a newly allocated list +/// +/// For use in undotree(). Recursive. +/// +/// @param[in] first_uhp Undo blocks list to start with. +/// +/// @return [allocated] List with a representation of undo blocks. +list_T *u_eval_tree(const u_header_T *const first_uhp) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET { - u_header_T *uhp = first_uhp; - dict_T *dict; + list_T *const list = tv_list_alloc(kListLenMayKnow); - while (uhp != NULL) { - dict = tv_dict_alloc(); + for (const u_header_T *uhp = first_uhp; uhp != NULL; uhp = uhp->uh_prev.ptr) { + dict_T *const dict = tv_dict_alloc(); tv_dict_add_nr(dict, S_LEN("seq"), (varnumber_T)uhp->uh_seq); tv_dict_add_nr(dict, S_LEN("time"), (varnumber_T)uhp->uh_time); if (uhp == curbuf->b_u_newhead) { @@ -2965,14 +2968,12 @@ void u_eval_tree(u_header_T *first_uhp, list_T *list) } if (uhp->uh_alt_next.ptr != NULL) { - list_T *alt_list = tv_list_alloc(); - // Recursive call to add alternate undo tree. - u_eval_tree(uhp->uh_alt_next.ptr, alt_list); - tv_dict_add_list(dict, S_LEN("alt"), alt_list); + tv_dict_add_list(dict, S_LEN("alt"), u_eval_tree(uhp->uh_alt_next.ptr)); } tv_list_append_dict(list, dict); - uhp = uhp->uh_prev.ptr; } + + return list; } diff --git a/src/nvim/window.c b/src/nvim/window.c index b687781dfb..4dfc72f212 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -5921,13 +5921,15 @@ void win_get_tabwin(handle_T id, int *tabnr, int *winnr) } } -void win_id2tabwin(typval_T *argvars, list_T *list) +void win_id2tabwin(typval_T *const argvars, typval_T *const rettv) { int winnr = 1; int tabnr = 1; handle_T id = (handle_T)tv_get_number(&argvars[0]); win_get_tabwin(id, &tabnr, &winnr); + + list_T *const list = tv_list_alloc_ret(rettv, 2); tv_list_append_number(list, tabnr); tv_list_append_number(list, winnr); } diff --git a/test/unit/eval/helpers.lua b/test/unit/eval/helpers.lua index 6babd4be77..3d1c42c3a0 100644 --- a/test/unit/eval/helpers.lua +++ b/test/unit/eval/helpers.lua @@ -312,7 +312,7 @@ local lua2typvalt_type_tab = { processed[l].lv_refcount = processed[l].lv_refcount + 1 return typvalt(eval.VAR_LIST, {v_list=processed[l]}) end - local lst = populate_list(eval.tv_list_alloc(), l, processed) + local lst = populate_list(eval.tv_list_alloc(#l), l, processed) return typvalt(eval.VAR_LIST, {v_list=lst}) end, [dict_type] = function(l, processed) @@ -433,7 +433,8 @@ local function int(n) end local function list(...) - return populate_list(ffi.gc(eval.tv_list_alloc(), eval.tv_list_unref), + return populate_list(ffi.gc(eval.tv_list_alloc(select('#', ...)), + eval.tv_list_unref), {...}, {}) end diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua index b668144175..919a42fbb9 100644 --- a/test/unit/eval/typval_spec.lua +++ b/test/unit/eval/typval_spec.lua @@ -2407,7 +2407,7 @@ describe('typval.c', function() describe('list ret()', function() itp('works', function() local rettv = typvalt(lib.VAR_UNKNOWN) - local l = lib.tv_list_alloc_ret(rettv) + local l = lib.tv_list_alloc_ret(rettv, 0) eq(empty_list, typvalt2lua(rettv)) eq(rettv.vval.v_list, l) end) |