Patch 9.0.0615

7 views
Skip to first unread message

Bram Moolenaar

unread,
Sep 28, 2022, 8:24:14 AM9/28/22
to vim...@googlegroups.com

Patch 9.0.0615
Problem: Using reduce() on a list from range() is a bit slow.
Solution: Avoid materializing the list.
Files: src/list.c, src/testdir/test_listdict.vim


*** ../vim-9.0.0614/src/list.c 2022-09-22 17:06:56.295037465 +0100
--- src/list.c 2022-09-28 12:56:19.060434241 +0100
***************
*** 2377,2385 ****
rettv->v_type = VAR_LIST;
rettv->vval.v_list = NULL;
}
! if (l == NULL
! || (filtermap == FILTERMAP_FILTER
! && value_check_lock(l->lv_lock, arg_errmsg, TRUE)))
return;

prev_lock = l->lv_lock;
--- 2377,2384 ----
rettv->v_type = VAR_LIST;
rettv->vval.v_list = NULL;
}
! if (l == NULL || (filtermap == FILTERMAP_FILTER
! && value_check_lock(l->lv_lock, arg_errmsg, TRUE)))
return;

prev_lock = l->lv_lock;
***************
*** 3011,3038 ****
{
list_T *l = argvars[0].vval.v_list;
listitem_T *li = NULL;
typval_T initial;
typval_T argv[3];
int r;
int called_emsg_start = called_emsg;
int prev_locked;

! if (l != NULL)
! CHECK_LIST_MATERIALIZE(l);
if (argvars[2].v_type == VAR_UNKNOWN)
{
! if (l == NULL || l->lv_first == NULL)
{
semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "List");
return;
}
! initial = l->lv_first->li_tv;
! li = l->lv_first->li_next;
}
else
{
initial = argvars[2];
! if (l != NULL)
li = l->lv_first;
}
copy_tv(&initial, rettv);
--- 3010,3053 ----
{
list_T *l = argvars[0].vval.v_list;
listitem_T *li = NULL;
+ int range_list;
+ int range_idx = 0;
+ varnumber_T range_val = 0;
typval_T initial;
typval_T argv[3];
int r;
int called_emsg_start = called_emsg;
int prev_locked;

! // Using reduce on a range() uses "range_idx" and "range_val".
! range_list = l != NULL && l->lv_first == &range_list_item;
! if (range_list)
! range_val = l->lv_u.nonmat.lv_start;
!
if (argvars[2].v_type == VAR_UNKNOWN)
{
! if (l == NULL || l->lv_len == 0)
{
semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "List");
return;
}
! if (range_list)
! {
! initial.v_type = VAR_NUMBER;
! initial.vval.v_number = range_val;
! range_val += l->lv_u.nonmat.lv_stride;
! range_idx = 1;
! }
! else
! {
! initial = l->lv_first->li_tv;
! li = l->lv_first->li_next;
! }
}
else
{
initial = argvars[2];
! if (l != NULL && !range_list)
li = l->lv_first;
}
copy_tv(&initial, rettv);
***************
*** 3041,3060 ****
return;

prev_locked = l->lv_lock;
-
l->lv_lock = VAR_FIXED; // disallow the list changing here
! for ( ; li != NULL; li = li->li_next)
{
argv[0] = *rettv;
- argv[1] = li->li_tv;
rettv->v_type = VAR_UNKNOWN;

r = eval_expr_typval(expr, argv, 2, rettv);

clear_tv(&argv[0]);
if (r == FAIL || called_emsg != called_emsg_start)
break;
}
l->lv_lock = prev_locked;
}

--- 3056,3091 ----
return;

prev_locked = l->lv_lock;
l->lv_lock = VAR_FIXED; // disallow the list changing here
!
! while (range_list ? range_idx < l->lv_len : li != NULL)
{
argv[0] = *rettv;
rettv->v_type = VAR_UNKNOWN;

+ if (range_list)
+ {
+ argv[1].v_type = VAR_NUMBER;
+ argv[1].vval.v_number = range_val;
+ }
+ else
+ argv[1] = li->li_tv;
+
r = eval_expr_typval(expr, argv, 2, rettv);

clear_tv(&argv[0]);
if (r == FAIL || called_emsg != called_emsg_start)
break;
+
+ if (range_list)
+ {
+ range_val += l->lv_u.nonmat.lv_stride;
+ ++range_idx;
+ }
+ else
+ li = li->li_next;
}
+
l->lv_lock = prev_locked;
}

*** ../vim-9.0.0614/src/testdir/test_listdict.vim 2022-09-22 17:06:56.299037474 +0100
--- src/testdir/test_listdict.vim 2022-09-28 12:58:36.771957027 +0100
***************
*** 1015,1020 ****
--- 1015,1026 ----
call assert_equal('x y z', reduce(['x', 'y', 'z'], LSTART acc, val LMIDDLE acc .. ' ' .. val LEND))
call assert_equal(120, range(1, 5)->reduce(LSTART acc, val LMIDDLE acc * val LEND))

+ call assert_equal(0, range(1)->reduce(LSTART acc, val LMIDDLE acc + val LEND))
+ call assert_equal(1, range(2)->reduce(LSTART acc, val LMIDDLE acc + val LEND))
+ call assert_equal(3, range(3)->reduce(LSTART acc, val LMIDDLE acc + val LEND))
+ call assert_equal(6, range(4)->reduce(LSTART acc, val LMIDDLE acc + val LEND))
+ call assert_equal(10, range(5)->reduce(LSTART acc, val LMIDDLE acc + val LEND))
+
call assert_equal(1, reduce(0z, LSTART acc, val LMIDDLE acc + val LEND, 1))
call assert_equal(1 + 0xaf + 0xbf + 0xcf, reduce(0zAFBFCF, LSTART acc, val LMIDDLE acc + val LEND, 1))
call assert_equal(2 * (2 * 1 + 0xaf) + 0xbf, 0zAFBF->reduce(LSTART acc, val LMIDDLE 2 * acc + val LEND, 1))
***************
*** 1038,1043 ****
--- 1044,1050 ----
vim9 assert_equal({'x': 1, 'y': 1, 'z': 1 }, ['x', 'y', 'z']->reduce((acc, val) => extend(acc, {[val]: 1 }), {}))

call assert_fails("call reduce([], { acc, val -> acc + val })", 'E998: Reduce of an empty List with no initial value')
+ call assert_fails("call reduce(range(0), { acc, val -> acc + val })", 'E998: Reduce of an empty List with no initial value')
call assert_fails("call reduce(0z, { acc, val -> acc + val })", 'E998: Reduce of an empty Blob with no initial value')
call assert_fails("call reduce(test_null_blob(), { acc, val -> acc + val })", 'E998: Reduce of an empty Blob with no initial value')
call assert_fails("call reduce('', { acc, val -> acc + val })", 'E998: Reduce of an empty String with no initial value')
*** ../vim-9.0.0614/src/version.c 2022-09-28 11:48:26.677156955 +0100
--- src/version.c 2022-09-28 13:20:48.906575541 +0100
***************
*** 701,702 ****
--- 701,704 ----
{ /* Add new patch number below this line */
+ /**/
+ 615,
/**/

--
hundred-and-one symptoms of being an internet addict:
208. Your goals for the future are obtaining a second Gbit connection
and upgrade your NAS to all SSD

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
Reply all
Reply to author
Forward
0 new messages