Problem: Calling function for reduce() has too much overhead.
Solution: Do not create a funccall_T every time.
blob_T *b_ret;
int idx = 0;
int rem;
+ typval_T newtv;
+ funccall_T *fc;
if (filtermap == FILTERMAP_MAPNEW)
{
// set_vim_var_nr() doesn't set the type
set_vim_var_type(VV_KEY, VAR_NUMBER);
+ // Create one funccal_T for all eval_expr_typval() calls.
+ fc = eval_expr_get_funccal(expr, &newtv);
+
for (i = 0; i < b->bv_ga.ga_len; i++)
{
- typval_T newtv;
-
tv.v_type = VAR_NUMBER;
val = blob_get(b, i);
tv.vval.v_number = val;
set_vim_var_nr(VV_KEY, idx);
- if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL
+ if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL
|| did_emsg)
break;
if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL)
}
++idx;
}
+
+ if (fc != NULL)
+ remove_funccal();
}
/*
argv[1].v_type = VAR_NUMBER;
argv[1].vval.v_number = blob_get(b, i);
- r = eval_expr_typval(expr, argv, 2, rettv);
+ r = eval_expr_typval(expr, argv, 2, NULL, rettv);
clear_tv(&argv[0]);
if (r == FAIL || called_emsg != called_emsg_start)
dictitem_T *di;
int todo;
int rem;
+ typval_T newtv;
+ funccall_T *fc;
if (filtermap == FILTERMAP_MAPNEW)
{
d_ret = rettv->vval.v_dict;
}
+ // Create one funccal_T for all eval_expr_typval() calls.
+ fc = eval_expr_get_funccal(expr, &newtv);
+
if (filtermap != FILTERMAP_FILTER && d->dv_lock == 0)
d->dv_lock = VAR_LOCKED;
ht = &d->dv_hashtab;
if (!HASHITEM_EMPTY(hi))
{
int r;
- typval_T newtv;
--todo;
di = HI2DI(hi);
break;
set_vim_var_string(VV_KEY, di->di_key, -1);
newtv.v_type = VAR_UNKNOWN;
- r = filter_map_one(&di->di_tv, expr, filtermap,
- &newtv, &rem);
+ r = filter_map_one(&di->di_tv, expr, filtermap, fc, &newtv, &rem);
clear_tv(get_vim_var_tv(VV_KEY));
if (r == FAIL || did_emsg)
{
}
hash_unlock(ht);
d->dv_lock = prev_lock;
+ if (fc != NULL)
+ remove_funccal();
}
/*
|| (tv->vval.v_string != NULL && *tv->vval.v_string != NUL));
}
+/*
+ * When calling eval_expr_typval() many times we only need one funccall_T.
+ * Returns NULL when no funccall_T is to be used.
+ * When returning non-NULL remove_funccal() must be called later.
+ */
+ funccall_T *
+eval_expr_get_funccal(typval_T *expr, typval_T *rettv)
+{
+ if (expr->v_type != VAR_PARTIAL)
+ return NULL;
+
+ partial_T *partial = expr->vval.v_partial;
+ if (partial == NULL)
+ return NULL;
+ if (partial->pt_func == NULL
+ || partial->pt_func->uf_def_status == UF_NOT_COMPILED)
+ return NULL;
+
+ return create_funccal(partial->pt_func, rettv);
+}
+
/*
* Evaluate an expression, which can be a function, partial or string.
* Pass arguments "argv[argc]".
+ * "fc_arg" is from eval_expr_get_funccal() or NULL;
* Return the result in "rettv" and OK or FAIL.
*/
int
-eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
+eval_expr_typval(
+ typval_T *expr,
+ typval_T *argv,
+ int argc,
+ funccall_T *fc_arg,
+ typval_T *rettv)
{
char_u *s;
char_u buf[NUMBUFLEN];
if (partial->pt_func != NULL
&& partial->pt_func->uf_def_status != UF_NOT_COMPILED)
{
- funccall_T *fc = create_funccal(partial->pt_func, rettv);
+ funccall_T *fc = fc_arg != NULL ? fc_arg
+ : create_funccal(partial->pt_func, rettv);
int r;
if (fc == NULL)
// Shortcut to call a compiled function with minimal overhead.
r = call_def_function(partial->pt_func, argc, argv,
DEF_USE_PT_ARGV, partial, fc, rettv);
- remove_funccal();
+ if (fc_arg == NULL)
+ remove_funccal();
if (r == FAIL)
return FAIL;
}
typval_T rettv;
int res;
- if (eval_expr_typval(expr, NULL, 0, &rettv) == FAIL)
+ if (eval_expr_typval(expr, NULL, 0, NULL, &rettv) == FAIL)
{
*error = TRUE;
return FALSE;
argv[1] = *get_vim_var_tv(VV_VAL);
newtv.v_type = VAR_UNKNOWN;
- if (eval_expr_typval(expr, argv, 2, &newtv) == FAIL)
+ if (eval_expr_typval(expr, argv, 2, NULL, &newtv) == FAIL)
return FALSE;
found = tv_get_bool_chk(&newtv, &error);
argv[0].vval.v_dict = dict;
}
- if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
+ if (eval_expr_typval(expr, argv, 1, NULL, &rettv) == FAIL)
goto theend;
// We want to use -1, but also true/false should be allowed.
typval_T *tv, // original value
typval_T *expr, // callback
filtermap_T filtermap,
+ funccall_T *fc, // from eval_expr_get_funccal()
typval_T *newtv, // for map() and mapnew(): new value
int *remp) // for filter(): remove flag
{
copy_tv(tv, get_vim_var_tv(VV_VAL));
argv[0] = *get_vim_var_tv(VV_KEY);
argv[1] = *get_vim_var_tv(VV_VAL);
- if (eval_expr_typval(expr, argv, 2, newtv) == FAIL)
+ if (eval_expr_typval(expr, argv, 2, fc, newtv) == FAIL)
goto theend;
if (filtermap == FILTERMAP_FILTER)
{
int idx = 0;
int rem;
listitem_T *li, *nli;
+ typval_T newtv;
+ funccall_T *fc;
if (filtermap == FILTERMAP_MAPNEW)
{
if (filtermap != FILTERMAP_FILTER && l->lv_lock == 0)
l->lv_lock = VAR_LOCKED;
+ // Create one funccal_T for all eval_expr_typval() calls.
+ fc = eval_expr_get_funccal(expr, &newtv);
+
if (l->lv_first == &range_list_item)
{
varnumber_T val = l->lv_u.nonmat.lv_start;
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)
+ if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL)
break;
if (did_emsg)
{
// Materialized list: loop over the items
for (li = l->lv_first; li != NULL; li = nli)
{
- typval_T newtv;
-
if (filtermap == FILTERMAP_MAP && 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)
+ if (filter_map_one(&li->li_tv, expr, filtermap, fc,
+ &newtv, &rem) == FAIL)
break;
if (did_emsg)
{
}
l->lv_lock = prev_lock;
+ if (fc != NULL)
+ remove_funccal();
}
/*
int r;
int called_emsg_start = called_emsg;
int prev_locked;
+ funccall_T *fc;
// Using reduce on a range() uses "range_idx" and "range_val".
range_list = l != NULL && l->lv_first == &range_list_item;
if (l == NULL)
return;
+ // Create one funccal_T for all eval_expr_typval() calls.
+ fc = eval_expr_get_funccal(expr, rettv);
+
prev_locked = l->lv_lock;
l->lv_lock = VAR_FIXED; // disallow the list changing here
else
argv[1] = li->li_tv;
- r = eval_expr_typval(expr, argv, 2, rettv);
+ r = eval_expr_typval(expr, argv, 2, fc, rettv);
if (argv[0].v_type != VAR_NUMBER && argv[0].v_type != VAR_UNKNOWN)
clear_tv(&argv[0]);
li = li->li_next;
}
+ if (fc != NULL)
+ remove_funccal();
+
l->lv_lock = prev_locked;
}
void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip);
int eval_to_bool(char_u *arg, int *error, exarg_T *eap, int skip);
int eval_expr_valid_arg(typval_T *tv);
-int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv);
+funccall_T *eval_expr_get_funccal(typval_T *expr, typval_T *rettv);
+int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, funccall_T *fc_arg, typval_T *rettv);
int eval_expr_to_bool(typval_T *expr, int *error);
char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
void init_evalarg(evalarg_T *evalarg);
void f_list2str(typval_T *argvars, typval_T *rettv);
void f_sort(typval_T *argvars, typval_T *rettv);
void f_uniq(typval_T *argvars, typval_T *rettv);
-int filter_map_one(typval_T *tv, typval_T *expr, filtermap_T filtermap, typval_T *newtv, int *remp);
+int filter_map_one(typval_T *tv, typval_T *expr, filtermap_T filtermap, funccall_T *fc, typval_T *newtv, int *remp);
void f_filter(typval_T *argvars, typval_T *rettv);
void f_map(typval_T *argvars, typval_T *rettv);
void f_mapnew(typval_T *argvars, typval_T *rettv);
int len = 0;
int idx = 0;
int rem;
+ typval_T newtv;
+ funccall_T *fc;
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
// set_vim_var_nr() doesn't set the type
set_vim_var_type(VV_KEY, VAR_NUMBER);
+ // Create one funccal_T for all eval_expr_typval() calls.
+ fc = eval_expr_get_funccal(expr, &newtv);
+
ga_init2(&ga, sizeof(char), 80);
for (p = str; *p != NUL; p += len)
{
- typval_T newtv;
-
if (copy_first_char_to_tv(p, &tv) == FAIL)
break;
len = (int)STRLEN(tv.vval.v_string);
newtv.v_type = VAR_UNKNOWN;
set_vim_var_nr(VV_KEY, idx);
- if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL
+ if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL
|| did_emsg)
{
clear_tv(&newtv);
}
ga_append(&ga, NUL);
rettv->vval.v_string = ga.ga_data;
+ if (fc != NULL)
+ remove_funccal();
}
/*
typval_T argv[3];
int r;
int called_emsg_start = called_emsg;
+ funccall_T *fc;
if (argvars[2].v_type == VAR_UNKNOWN)
{
else
copy_tv(&argvars[2], rettv);
+ // Create one funccal_T for all eval_expr_typval() calls.
+ fc = eval_expr_get_funccal(expr, rettv);
+
for ( ; *p != NUL; p += len)
{
argv[0] = *rettv;
break;
len = (int)STRLEN(argv[1].vval.v_string);
- r = eval_expr_typval(expr, argv, 2, rettv);
+ r = eval_expr_typval(expr, argv, 2, fc, rettv);
clear_tv(&argv[0]);
clear_tv(&argv[1]);
if (r == FAIL || called_emsg != called_emsg_start)
return;
}
+
+ if (fc != NULL)
+ remove_funccal();
}
static void
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 618,
/**/
617,
/**/