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:
parent
ebec3e29b8
commit
f8ca03bf91
58
src/list.c
58
src/list.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
@ -750,6 +750,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
2065,
|
||||
/**/
|
||||
2064,
|
||||
/**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user