Patch 8.2.2065
Problem: Using map() and filter() on a range() is inefficient.
Solution: Do not materialize the range. (closes #7388)
Files: src/list.c, src/testdir/test_functions.vim
*** ../vim-8.2.2064/src/list.c 2020-11-21 13:58:46.420203217 +0100
--- src/list.c 2020-11-28 20:31:43.010797933 +0100
***************
*** 2173,2215 ****
// 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;
! 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;
}
--- 2173,2267 ----
// set_vim_var_nr() doesn't set the type
set_vim_var_type(VV_KEY, VAR_NUMBER);
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))
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;
}
*** ../vim-8.2.2064/src/testdir/test_functions.vim 2020-11-23 18:14:51.276875903 +0100
--- src/testdir/test_functions.vim 2020-11-28 20:25:48.947668193 +0100
***************
*** 2302,2307 ****
--- 2302,2308 ----
" 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,2363 ****
--- 2359,2367 ----
" 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))
*** ../vim-8.2.2064/src/version.c 2020-11-28 20:22:03.096081255 +0100
--- src/version.c 2020-11-28 20:27:03.659502881 +0100
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2065,
/**/
--
There are 2 kinds of people in my world: those who know Unix, Perl, Vim, GNU,
Linux, etc, and those who know COBOL. It gets very difficult for me at
parties, not knowing which group to socialise with :-)
Sitaram Chamarty
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///