mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
patch 9.0.0615: using reduce() on a list from range() is a bit slow
Problem: Using reduce() on a list from range() is a bit slow. Solution: Avoid materializing the list.
This commit is contained in:
55
src/list.c
55
src/list.c
@@ -2377,9 +2377,8 @@ list_filter_map(
|
|||||||
rettv->v_type = VAR_LIST;
|
rettv->v_type = VAR_LIST;
|
||||||
rettv->vval.v_list = NULL;
|
rettv->vval.v_list = NULL;
|
||||||
}
|
}
|
||||||
if (l == NULL
|
if (l == NULL || (filtermap == FILTERMAP_FILTER
|
||||||
|| (filtermap == FILTERMAP_FILTER
|
&& value_check_lock(l->lv_lock, arg_errmsg, TRUE)))
|
||||||
&& value_check_lock(l->lv_lock, arg_errmsg, TRUE)))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
prev_lock = l->lv_lock;
|
prev_lock = l->lv_lock;
|
||||||
@@ -3011,28 +3010,44 @@ list_reduce(
|
|||||||
{
|
{
|
||||||
list_T *l = argvars[0].vval.v_list;
|
list_T *l = argvars[0].vval.v_list;
|
||||||
listitem_T *li = NULL;
|
listitem_T *li = NULL;
|
||||||
|
int range_list;
|
||||||
|
int range_idx = 0;
|
||||||
|
varnumber_T range_val = 0;
|
||||||
typval_T initial;
|
typval_T initial;
|
||||||
typval_T argv[3];
|
typval_T argv[3];
|
||||||
int r;
|
int r;
|
||||||
int called_emsg_start = called_emsg;
|
int called_emsg_start = called_emsg;
|
||||||
int prev_locked;
|
int prev_locked;
|
||||||
|
|
||||||
if (l != NULL)
|
// Using reduce on a range() uses "range_idx" and "range_val".
|
||||||
CHECK_LIST_MATERIALIZE(l);
|
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 (argvars[2].v_type == VAR_UNKNOWN)
|
||||||
{
|
{
|
||||||
if (l == NULL || l->lv_first == NULL)
|
if (l == NULL || l->lv_len == 0)
|
||||||
{
|
{
|
||||||
semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "List");
|
semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "List");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
initial = l->lv_first->li_tv;
|
if (range_list)
|
||||||
li = l->lv_first->li_next;
|
{
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
initial = argvars[2];
|
initial = argvars[2];
|
||||||
if (l != NULL)
|
if (l != NULL && !range_list)
|
||||||
li = l->lv_first;
|
li = l->lv_first;
|
||||||
}
|
}
|
||||||
copy_tv(&initial, rettv);
|
copy_tv(&initial, rettv);
|
||||||
@@ -3041,20 +3056,36 @@ list_reduce(
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
prev_locked = l->lv_lock;
|
prev_locked = l->lv_lock;
|
||||||
|
|
||||||
l->lv_lock = VAR_FIXED; // disallow the list changing here
|
l->lv_lock = VAR_FIXED; // disallow the list changing here
|
||||||
for ( ; li != NULL; li = li->li_next)
|
|
||||||
|
while (range_list ? range_idx < l->lv_len : li != NULL)
|
||||||
{
|
{
|
||||||
argv[0] = *rettv;
|
argv[0] = *rettv;
|
||||||
argv[1] = li->li_tv;
|
|
||||||
rettv->v_type = VAR_UNKNOWN;
|
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);
|
r = eval_expr_typval(expr, argv, 2, rettv);
|
||||||
|
|
||||||
clear_tv(&argv[0]);
|
clear_tv(&argv[0]);
|
||||||
if (r == FAIL || called_emsg != called_emsg_start)
|
if (r == FAIL || called_emsg != called_emsg_start)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (range_list)
|
||||||
|
{
|
||||||
|
range_val += l->lv_u.nonmat.lv_stride;
|
||||||
|
++range_idx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
li = li->li_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
l->lv_lock = prev_locked;
|
l->lv_lock = prev_locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1015,6 +1015,12 @@ func Test_reduce()
|
|||||||
call assert_equal('x y z', reduce(['x', 'y', 'z'], LSTART acc, val LMIDDLE acc .. ' ' .. val LEND))
|
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(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, 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(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))
|
call assert_equal(2 * (2 * 1 + 0xaf) + 0xbf, 0zAFBF->reduce(LSTART acc, val LMIDDLE 2 * acc + val LEND, 1))
|
||||||
@@ -1038,6 +1044,7 @@ func Test_reduce()
|
|||||||
vim9 assert_equal({'x': 1, 'y': 1, 'z': 1 }, ['x', 'y', 'z']->reduce((acc, val) => extend(acc, {[val]: 1 }), {}))
|
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([], { 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(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(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')
|
call assert_fails("call reduce('', { acc, val -> acc + val })", 'E998: Reduce of an empty String with no initial value')
|
||||||
|
@@ -699,6 +699,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 */
|
||||||
|
/**/
|
||||||
|
615,
|
||||||
/**/
|
/**/
|
||||||
614,
|
614,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user