0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 8.2.2065: using map() and filter() on a range() is inefficient

Problem:    Using map() and filter() on a range() is inefficient.
Solution:   Do not materialize the range. (closes #7388)
This commit is contained in:
Bram Moolenaar 2020-11-28 20:32:29 +01:00
parent ebec3e29b8
commit f8ca03bf91
3 changed files with 88 additions and 30 deletions

View File

@ -2173,15 +2173,65 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
// set_vim_var_nr() doesn't set the type
set_vim_var_type(VV_KEY, VAR_NUMBER);
CHECK_LIST_MATERIALIZE(l);
if (filtermap != FILTERMAP_FILTER && l->lv_lock == 0)
l->lv_lock = VAR_LOCKED;
if (l->lv_first == &range_list_item)
{
varnumber_T val = l->lv_u.nonmat.lv_start;
int len = l->lv_len;
int stride = l->lv_u.nonmat.lv_stride;
// List from range(): loop over the numbers
l->lv_first = NULL;
l->lv_u.mat.lv_last = NULL;
l->lv_len = 0;
l->lv_u.mat.lv_idx_item = NULL;
for (idx = 0; idx < len; ++idx)
{
typval_T tv;
typval_T newtv;
tv.v_type = VAR_NUMBER;
tv.v_lock = 0;
tv.vval.v_number = val;
set_vim_var_nr(VV_KEY, idx);
if (filter_map_one(&tv, expr, filtermap, &newtv, &rem)
== FAIL)
break;
if (did_emsg)
{
clear_tv(&newtv);
break;
}
if (filtermap != FILTERMAP_FILTER)
{
// map(), mapnew(): always append the new value to the
// list
if (list_append_tv_move(filtermap == FILTERMAP_MAP
? l : l_ret, &newtv) == FAIL)
break;
}
else if (!rem)
{
// filter(): append the list item value when not rem
if (list_append_tv_move(l, &tv) == FAIL)
break;
}
val += stride;
}
}
else
{
// Materialized list from range(): loop over the items
for (li = l->lv_first; li != NULL; li = nli)
{
typval_T newtv;
if (filtermap != FILTERMAP_FILTER
&& value_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
if (filtermap != FILTERMAP_FILTER && value_check_lock(
li->li_tv.v_lock, arg_errmsg, TRUE))
break;
nli = li->li_next;
set_vim_var_nr(VV_KEY, idx);
@ -2210,6 +2260,8 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
listitem_remove(l, li);
++idx;
}
}
l->lv_lock = prev_lock;
}

View File

@ -2302,6 +2302,7 @@ func Test_range()
" filter()
call assert_equal([1, 3], filter(range(5), 'v:val % 2'))
call assert_equal([1, 5, 7, 11, 13], filter(filter(range(15), 'v:val % 2'), 'v:val % 3'))
" funcref()
call assert_equal([0, 1], funcref('TwoArgs', range(2))())
@ -2358,6 +2359,9 @@ func Test_range()
" map()
call assert_equal([0, 2, 4, 6, 8], map(range(5), 'v:val * 2'))
call assert_equal([3, 5, 7, 9, 11], map(map(range(5), 'v:val * 2'), 'v:val + 3'))
call assert_equal([2, 6], map(filter(range(5), 'v:val % 2'), 'v:val * 2'))
call assert_equal([2, 4, 8], filter(map(range(5), 'v:val * 2'), 'v:val % 3'))
" match()
call assert_equal(3, match(range(5), 3))

View File

@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2065,
/**/
2064,
/**/