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,43 +2173,95 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
// set_vim_var_nr() doesn't set the type // set_vim_var_nr() doesn't set the type
set_vim_var_type(VV_KEY, VAR_NUMBER); set_vim_var_type(VV_KEY, VAR_NUMBER);
CHECK_LIST_MATERIALIZE(l);
if (filtermap != FILTERMAP_FILTER && l->lv_lock == 0) if (filtermap != FILTERMAP_FILTER && l->lv_lock == 0)
l->lv_lock = VAR_LOCKED; l->lv_lock = VAR_LOCKED;
for (li = l->lv_first; li != NULL; li = nli)
{
typval_T newtv;
if (filtermap != FILTERMAP_FILTER if (l->lv_first == &range_list_item)
&& value_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE)) {
break; varnumber_T val = l->lv_u.nonmat.lv_start;
nli = li->li_next; int len = l->lv_len;
set_vim_var_nr(VV_KEY, idx); int stride = l->lv_u.nonmat.lv_stride;
if (filter_map_one(&li->li_tv, expr, filtermap,
&newtv, &rem) == FAIL) // List from range(): loop over the numbers
break; l->lv_first = NULL;
if (did_emsg) 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)
{ {
clear_tv(&newtv); typval_T tv;
break; typval_T newtv;
}
if (filtermap == FILTERMAP_MAP) tv.v_type = VAR_NUMBER;
{ tv.v_lock = 0;
// map(): replace the list item value tv.vval.v_number = val;
clear_tv(&li->li_tv); set_vim_var_nr(VV_KEY, idx);
newtv.v_lock = 0; if (filter_map_one(&tv, expr, filtermap, &newtv, &rem)
li->li_tv = newtv; == FAIL)
}
else if (filtermap == FILTERMAP_MAPNEW)
{
// mapnew(): append the list item value
if (list_append_tv_move(l_ret, &newtv) == FAIL)
break; 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 if (filtermap == FILTERMAP_FILTER && rem)
listitem_remove(l, li);
++idx;
} }
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))
break;
nli = li->li_next;
set_vim_var_nr(VV_KEY, idx);
if (filter_map_one(&li->li_tv, expr, filtermap,
&newtv, &rem) == FAIL)
break;
if (did_emsg)
{
clear_tv(&newtv);
break;
}
if (filtermap == FILTERMAP_MAP)
{
// map(): replace the list item value
clear_tv(&li->li_tv);
newtv.v_lock = 0;
li->li_tv = newtv;
}
else if (filtermap == FILTERMAP_MAPNEW)
{
// mapnew(): append the list item value
if (list_append_tv_move(l_ret, &newtv) == FAIL)
break;
}
else if (filtermap == FILTERMAP_FILTER && rem)
listitem_remove(l, li);
++idx;
}
}
l->lv_lock = prev_lock; l->lv_lock = prev_lock;
} }

View File

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

View File

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