Problem: Vim9: performance can be improved.
Solution: Don't call break. Inline check for list materialize. Make an
inline version of ga_grow().
list_T *l = item->jq_value->vval.v_list;
typval_T *tv;
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
tv = &l->lv_first->li_tv;
if ((without_callback || !item->jq_no_callback)
return FAIL;
}
- range_list_materialize(item->vval.v_list);
+ CHECK_LIST_MATERIALIZE(item->vval.v_list);
li = item->vval.v_list->lv_first;
for (; li != NULL && n < 16; li = li->li_next, n++)
{
listitem_T *li;
char_u *s;
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
FOR_ALL_LIST_ITEMS(l, li)
{
s = tv_get_string_chk(&li->li_tv);
else
{
// Need a real list here.
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
// No need to increment the refcount, it's already set for
// the list being used in "tv".
rettv->vval.v_number = 1; // FAIL
goto done;
}
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
li = l->lv_first;
}
else
{
listitem_T *item;
- range_list_materialize(list);
+ CHECK_LIST_MATERIALIZE(list);
item = list->lv_first;
do_cmdline(NULL, get_list_line, (void *)&item,
DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
if (lv_len > 0)
{
- range_list_materialize(list);
+ CHECK_LIST_MATERIALIZE(list);
FOR_ALL_LIST_ITEMS(list, li)
copy_tv(&li->li_tv, &pt->pt_argv[i++]);
}
l = argvars[0].vval.v_list;
if (l != NULL)
{
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
item = l->lv_first;
if (argvars[2].v_type != VAR_UNKNOWN)
{
msg_clr_eos();
l = argvars[0].vval.v_list;
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
FOR_ALL_LIST_ITEMS(l, li)
{
msg_puts((char *)tv_get_string(&li->li_tv));
{
if ((l = argvars[0].vval.v_list) == NULL)
goto theend;
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
li = l->lv_first;
}
else
list_T *list = rettv->vval.v_list;
// Create a non-materialized list. This is much more efficient and
- // works with ":for". If used otherwise range_list_materialize() must
+ // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must
// be called.
list->lv_first = &range_list_item;
list->lv_u.nonmat.lv_start = start;
}
/*
- * If "list" is a non-materialized list then materialize it now.
+ * Materialize "list".
+ * Do not call directly, use CHECK_LIST_MATERIALIZE()
*/
void
range_list_materialize(list_T *list)
{
- if (list->lv_first == &range_list_item)
- {
- varnumber_T start = list->lv_u.nonmat.lv_start;
- varnumber_T end = list->lv_u.nonmat.lv_end;
- int stride = list->lv_u.nonmat.lv_stride;
- varnumber_T i;
-
- list->lv_first = NULL;
- list->lv_u.mat.lv_last = NULL;
- list->lv_len = 0;
- list->lv_u.mat.lv_idx_item = NULL;
- for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
- if (list_append_number(list, (varnumber_T)i) == FAIL)
- break;
- }
+ varnumber_T start = list->lv_u.nonmat.lv_start;
+ varnumber_T end = list->lv_u.nonmat.lv_end;
+ int stride = list->lv_u.nonmat.lv_stride;
+ varnumber_T i;
+
+ list->lv_first = NULL;
+ list->lv_u.mat.lv_last = NULL;
+ list->lv_len = 0;
+ list->lv_u.mat.lv_idx_item = NULL;
+ for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
+ if (list_append_number(list, (varnumber_T)i) == FAIL)
+ break;
}
static void
if (ll != NULL)
{
- range_list_materialize(ll);
+ CHECK_LIST_MATERIALIZE(ll);
FOR_ALL_LIST_ITEMS(ll, li)
{
strval = tv_get_string_buf_chk(&li->li_tv, buf);
return FAIL;
}
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
item = l->lv_first;
while (*arg != ']')
{
list = argvars[0].vval.v_list;
if (list == NULL)
return;
- range_list_materialize(list);
+ CHECK_LIST_MATERIALIZE(list);
FOR_ALL_LIST_ITEMS(list, li)
if (tv_get_string_chk(&li->li_tv) == NULL)
return;
listitem_T *li;
int i;
- range_list_materialize(pos_list);
+ CHECK_LIST_MATERIALIZE(pos_list);
for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH;
i++, li = li->li_next)
{
return NULL;
}
- range_list_materialize(list);
+ CHECK_LIST_MATERIALIZE(list);
FOR_ALL_LIST_ITEMS(list, curr)
{
if (!(newObj = VimToPython(&curr->li_tv, depth + 1, lookup_dict)))
return NULL;
self->list = list;
++list->lv_refcount;
- range_list_materialize(list);
+ CHECK_LIST_MATERIALIZE(list);
pyll_add((PyObject *)(self), &self->ref, &lastlist);
return NULL;
}
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
list_add_watch(l, &lii->lw);
lii->lw.lw_item = l->lv_first;
lii->list = l;
return NULL;
}
argslist = argstv.vval.v_list;
- range_list_materialize(argslist);
+ CHECK_LIST_MATERIALIZE(argslist);
argc = argslist->lv_len;
if (argc != 0)
int dir = compl_direction;
// Go through the List with matches and add each of them.
- range_list_materialize(list);
+ CHECK_LIST_MATERIALIZE(list);
FOR_ALL_LIST_ITEMS(list, li)
{
if (ins_compl_add_tv(&li->li_tv, dir) == OK)
else
{
what_flag = 0;
- range_list_materialize(what_list);
+ CHECK_LIST_MATERIALIZE(what_list);
FOR_ALL_LIST_ITEMS(what_list, item)
{
char_u *what = tv_get_string(&item->li_tv);
l->lv_copyID = copyID;
ga_append(gap, '[');
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
for (li = l->lv_first; li != NULL && !got_int; )
{
if (json_encode_item(gap, &li->li_tv, copyID,
if (l1 == NULL || l2 == NULL)
return FALSE;
- range_list_materialize(l1);
- range_list_materialize(l2);
+ CHECK_LIST_MATERIALIZE(l1);
+ CHECK_LIST_MATERIALIZE(l2);
for (item1 = l1->lv_first, item2 = l2->lv_first;
item1 != NULL && item2 != NULL;
if (n < 0 || n >= l->lv_len)
return NULL;
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
// When there is a cached index may start search from there.
if (l->lv_u.mat.lv_idx_item != NULL)
if (l == NULL)
return -1;
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
idx = 0;
for (li = l->lv_first; li != NULL && li != item; li = li->li_next)
++idx;
void
list_append(list_T *l, listitem_T *item)
{
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
if (l->lv_u.mat.lv_last == NULL)
{
// empty list
void
list_insert(list_T *l, listitem_T *ni, listitem_T *item)
{
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
if (item == NULL)
// Append new item at end of list.
list_append(l, ni);
listitem_T *item;
int todo = l2->lv_len;
- range_list_materialize(l1);
- range_list_materialize(l2);
+ CHECK_LIST_MATERIALIZE(l1);
+ CHECK_LIST_MATERIALIZE(l2);
// We also quit the loop when we have inserted the original item count of
// the list, avoid a hang when we extend a list with itself.
orig->lv_copyID = copyID;
orig->lv_copylist = copy;
}
- range_list_materialize(orig);
+ CHECK_LIST_MATERIALIZE(orig);
for (item = orig->lv_first; item != NULL && !got_int;
item = item->li_next)
{
{
listitem_T *ip;
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
// notify watchers
for (ip = item; ip != NULL; ip = ip->li_next)
return NULL;
ga_init2(&ga, (int)sizeof(char), 80);
ga_append(&ga, '[');
- range_list_materialize(tv->vval.v_list);
+ CHECK_LIST_MATERIALIZE(tv->vval.v_list);
if (list_join(&ga, tv->vval.v_list, (char_u *)", ",
FALSE, restore_copyID, copyID) == FAIL)
{
char_u *s;
// Stringify each item in the list.
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
for (item = l->lv_first; item != NULL && !got_int; item = item->li_next)
{
s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID,
int ret = OK;
char_u *s;
- range_list_materialize(list);
+ CHECK_LIST_MATERIALIZE(list);
FOR_ALL_LIST_ITEMS(list, li)
{
for (s = tv_get_string(&li->li_tv); *s != NUL; ++s)
if (argvars[1].v_type != VAR_UNKNOWN)
utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
ga_init2(&ga, 1, 80);
if (has_mbyte || utf8)
{
TRUE))
goto theend;
rettv_list_set(rettv, l);
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
len = list_len(l);
if (len <= 1)
// set_vim_var_nr() doesn't set the type
set_vim_var_type(VV_KEY, VAR_NUMBER);
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
if (map && l->lv_lock == 0)
l->lv_lock = VAR_LOCKED;
for (li = l->lv_first; li != NULL; li = nli)
if ((l = argvars[0].vval.v_list) != NULL)
{
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
li = l->lv_first;
if (argvars[2].v_type != VAR_UNKNOWN)
{
# define ESTACK_CHECK_NOW
# define CHECK_CURBUF
#endif
+
+// Inline the condition for performance.
+#define CHECK_LIST_MATERIALIZE(l) if ((l)->lv_first == &range_list_item) range_list_materialize(l)
+
+// Inlined version of ga_grow(). Especially useful if "n" is a constant.
+#define GA_GROW(gap, n) (((gap)->ga_maxlen - (gap)->ga_len < n) ? ga_grow_inner((gap), (n)) : OK)
*/
int
ga_grow(garray_T *gap, int n)
+{
+ if (gap->ga_maxlen - gap->ga_len < n)
+ return ga_grow_inner(gap, n);
+ return OK;
+}
+
+ int
+ga_grow_inner(garray_T *gap, int n)
{
size_t old_len;
size_t new_len;
char_u *pp;
- if (gap->ga_maxlen - gap->ga_len < n)
- {
- if (n < gap->ga_growsize)
- n = gap->ga_growsize;
-
- // A linear growth is very inefficient when the array grows big. This
- // is a compromise between allocating memory that won't be used and too
- // many copy operations. A factor of 1.5 seems reasonable.
- if (n < gap->ga_len / 2)
- n = gap->ga_len / 2;
-
- new_len = gap->ga_itemsize * (gap->ga_len + n);
- pp = vim_realloc(gap->ga_data, new_len);
- if (pp == NULL)
- return FAIL;
- old_len = gap->ga_itemsize * gap->ga_maxlen;
- vim_memset(pp + old_len, 0, new_len - old_len);
- gap->ga_maxlen = gap->ga_len + n;
- gap->ga_data = pp;
- }
+ if (n < gap->ga_growsize)
+ n = gap->ga_growsize;
+
+ // A linear growth is very inefficient when the array grows big. This
+ // is a compromise between allocating memory that won't be used and too
+ // many copy operations. A factor of 1.5 seems reasonable.
+ if (n < gap->ga_len / 2)
+ n = gap->ga_len / 2;
+
+ new_len = gap->ga_itemsize * (gap->ga_len + n);
+ pp = vim_realloc(gap->ga_data, new_len);
+ if (pp == NULL)
+ return FAIL;
+ old_len = gap->ga_itemsize * gap->ga_maxlen;
+ vim_memset(pp + old_len, 0, new_len - old_len);
+ gap->ga_maxlen = gap->ga_len + n;
+ gap->ga_data = pp;
return OK;
}
balloon_array = ALLOC_CLEAR_MULT(pumitem_T, list->lv_len);
if (balloon_array == NULL)
return;
- range_list_materialize(list);
+ CHECK_LIST_MATERIALIZE(list);
for (idx = 0, li = list->lv_first; li != NULL; li = li->li_next, ++idx)
{
char_u *text = tv_get_string_chk(&li->li_tv);
array[i] = 1;
if (list != NULL)
{
- range_list_materialize(list);
+ CHECK_LIST_MATERIALIZE(list);
for (i = 0, li = list->lv_first; i < 4 && i < list->lv_len;
++i, li = li->li_next)
{
int mincol;
int maxcol;
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
li = l->lv_first;
if (l->lv_len == 3)
{
listitem_T *li;
int i;
- range_list_materialize(list);
+ CHECK_LIST_MATERIALIZE(list);
for (i = 0, li = list->lv_first; i < 4 && i < list->lv_len;
++i, li = li->li_next)
{
if (list != NULL)
{
- range_list_materialize(list);
+ CHECK_LIST_MATERIALIZE(list);
for (i = 0, li = list->lv_first; i < 8 && i < list->lv_len;
++i, li = li->li_next)
{
break;
}
else
- range_list_materialize(li->li_tv.vval.v_list);
+ CHECK_LIST_MATERIALIZE(li->li_tv.vval.v_list);
}
}
if (ok)
void ga_init(garray_T *gap);
void ga_init2(garray_T *gap, int itemsize, int growsize);
int ga_grow(garray_T *gap, int n);
+int ga_grow_inner(garray_T *gap, int n);
char_u *ga_concat_strings(garray_T *gap, char *sep);
void ga_add_string(garray_T *gap, char_u *p);
void ga_concat(garray_T *gap, char_u *s);
int argc = 0;
int r = 0;
- range_list_materialize(l);
+ CHECK_LIST_MATERIALIZE(l);
FOR_ALL_LIST_ITEMS(l, item)
{
if (argc == MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc))