comparison src/list.c @ 30566:b3de17181c19 v9.0.0618

patch 9.0.0618: calling function for reduce() has too much overhead Commit: https://github.com/vim/vim/commit/82418263fa91792e851cb0de879d1595327d5531 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Sep 28 16:16:15 2022 +0100 patch 9.0.0618: calling function for reduce() has too much overhead Problem: Calling function for reduce() has too much overhead. Solution: Do not create a funccall_T every time.
author Bram Moolenaar <Bram@vim.org>
date Wed, 28 Sep 2022 17:30:04 +0200
parents 30025bbc1705
children b1c66bff0a66
comparison
equal deleted inserted replaced
30565:ce8e4c9cc95a 30566:b3de17181c19
2318 int 2318 int
2319 filter_map_one( 2319 filter_map_one(
2320 typval_T *tv, // original value 2320 typval_T *tv, // original value
2321 typval_T *expr, // callback 2321 typval_T *expr, // callback
2322 filtermap_T filtermap, 2322 filtermap_T filtermap,
2323 funccall_T *fc, // from eval_expr_get_funccal()
2323 typval_T *newtv, // for map() and mapnew(): new value 2324 typval_T *newtv, // for map() and mapnew(): new value
2324 int *remp) // for filter(): remove flag 2325 int *remp) // for filter(): remove flag
2325 { 2326 {
2326 typval_T argv[3]; 2327 typval_T argv[3];
2327 int retval = FAIL; 2328 int retval = FAIL;
2328 2329
2329 copy_tv(tv, get_vim_var_tv(VV_VAL)); 2330 copy_tv(tv, get_vim_var_tv(VV_VAL));
2330 argv[0] = *get_vim_var_tv(VV_KEY); 2331 argv[0] = *get_vim_var_tv(VV_KEY);
2331 argv[1] = *get_vim_var_tv(VV_VAL); 2332 argv[1] = *get_vim_var_tv(VV_VAL);
2332 if (eval_expr_typval(expr, argv, 2, newtv) == FAIL) 2333 if (eval_expr_typval(expr, argv, 2, fc, newtv) == FAIL)
2333 goto theend; 2334 goto theend;
2334 if (filtermap == FILTERMAP_FILTER) 2335 if (filtermap == FILTERMAP_FILTER)
2335 { 2336 {
2336 int error = FALSE; 2337 int error = FALSE;
2337 2338
2369 int prev_lock; 2370 int prev_lock;
2370 list_T *l_ret = NULL; 2371 list_T *l_ret = NULL;
2371 int idx = 0; 2372 int idx = 0;
2372 int rem; 2373 int rem;
2373 listitem_T *li, *nli; 2374 listitem_T *li, *nli;
2375 typval_T newtv;
2376 funccall_T *fc;
2374 2377
2375 if (filtermap == FILTERMAP_MAPNEW) 2378 if (filtermap == FILTERMAP_MAPNEW)
2376 { 2379 {
2377 rettv->v_type = VAR_LIST; 2380 rettv->v_type = VAR_LIST;
2378 rettv->vval.v_list = NULL; 2381 rettv->vval.v_list = NULL;
2392 // set_vim_var_nr() doesn't set the type 2395 // set_vim_var_nr() doesn't set the type
2393 set_vim_var_type(VV_KEY, VAR_NUMBER); 2396 set_vim_var_type(VV_KEY, VAR_NUMBER);
2394 2397
2395 if (filtermap != FILTERMAP_FILTER && l->lv_lock == 0) 2398 if (filtermap != FILTERMAP_FILTER && l->lv_lock == 0)
2396 l->lv_lock = VAR_LOCKED; 2399 l->lv_lock = VAR_LOCKED;
2400
2401 // Create one funccal_T for all eval_expr_typval() calls.
2402 fc = eval_expr_get_funccal(expr, &newtv);
2397 2403
2398 if (l->lv_first == &range_list_item) 2404 if (l->lv_first == &range_list_item)
2399 { 2405 {
2400 varnumber_T val = l->lv_u.nonmat.lv_start; 2406 varnumber_T val = l->lv_u.nonmat.lv_start;
2401 int len = l->lv_len; 2407 int len = l->lv_len;
2411 } 2417 }
2412 2418
2413 for (idx = 0; idx < len; ++idx) 2419 for (idx = 0; idx < len; ++idx)
2414 { 2420 {
2415 typval_T tv; 2421 typval_T tv;
2416 typval_T newtv;
2417 2422
2418 tv.v_type = VAR_NUMBER; 2423 tv.v_type = VAR_NUMBER;
2419 tv.v_lock = 0; 2424 tv.v_lock = 0;
2420 tv.vval.v_number = val; 2425 tv.vval.v_number = val;
2421 set_vim_var_nr(VV_KEY, idx); 2426 set_vim_var_nr(VV_KEY, idx);
2422 if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL) 2427 if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL)
2423 break; 2428 break;
2424 if (did_emsg) 2429 if (did_emsg)
2425 { 2430 {
2426 clear_tv(&newtv); 2431 clear_tv(&newtv);
2427 break; 2432 break;
2455 else 2460 else
2456 { 2461 {
2457 // Materialized list: loop over the items 2462 // Materialized list: loop over the items
2458 for (li = l->lv_first; li != NULL; li = nli) 2463 for (li = l->lv_first; li != NULL; li = nli)
2459 { 2464 {
2460 typval_T newtv;
2461
2462 if (filtermap == FILTERMAP_MAP && value_check_lock( 2465 if (filtermap == FILTERMAP_MAP && value_check_lock(
2463 li->li_tv.v_lock, arg_errmsg, TRUE)) 2466 li->li_tv.v_lock, arg_errmsg, TRUE))
2464 break; 2467 break;
2465 nli = li->li_next; 2468 nli = li->li_next;
2466 set_vim_var_nr(VV_KEY, idx); 2469 set_vim_var_nr(VV_KEY, idx);
2467 if (filter_map_one(&li->li_tv, expr, filtermap, 2470 if (filter_map_one(&li->li_tv, expr, filtermap, fc,
2468 &newtv, &rem) == FAIL) 2471 &newtv, &rem) == FAIL)
2469 break; 2472 break;
2470 if (did_emsg) 2473 if (did_emsg)
2471 { 2474 {
2472 clear_tv(&newtv); 2475 clear_tv(&newtv);
2473 break; 2476 break;
2496 ++idx; 2499 ++idx;
2497 } 2500 }
2498 } 2501 }
2499 2502
2500 l->lv_lock = prev_lock; 2503 l->lv_lock = prev_lock;
2504 if (fc != NULL)
2505 remove_funccal();
2501 } 2506 }
2502 2507
2503 /* 2508 /*
2504 * Implementation of map() and filter(). 2509 * Implementation of map() and filter().
2505 */ 2510 */
3016 typval_T initial; 3021 typval_T initial;
3017 typval_T argv[3]; 3022 typval_T argv[3];
3018 int r; 3023 int r;
3019 int called_emsg_start = called_emsg; 3024 int called_emsg_start = called_emsg;
3020 int prev_locked; 3025 int prev_locked;
3026 funccall_T *fc;
3021 3027
3022 // Using reduce on a range() uses "range_idx" and "range_val". 3028 // Using reduce on a range() uses "range_idx" and "range_val".
3023 range_list = l != NULL && l->lv_first == &range_list_item; 3029 range_list = l != NULL && l->lv_first == &range_list_item;
3024 if (range_list) 3030 if (range_list)
3025 range_val = l->lv_u.nonmat.lv_start; 3031 range_val = l->lv_u.nonmat.lv_start;
3053 copy_tv(&initial, rettv); 3059 copy_tv(&initial, rettv);
3054 3060
3055 if (l == NULL) 3061 if (l == NULL)
3056 return; 3062 return;
3057 3063
3064 // Create one funccal_T for all eval_expr_typval() calls.
3065 fc = eval_expr_get_funccal(expr, rettv);
3066
3058 prev_locked = l->lv_lock; 3067 prev_locked = l->lv_lock;
3059 l->lv_lock = VAR_FIXED; // disallow the list changing here 3068 l->lv_lock = VAR_FIXED; // disallow the list changing here
3060 3069
3061 while (range_list ? range_idx < l->lv_len : li != NULL) 3070 while (range_list ? range_idx < l->lv_len : li != NULL)
3062 { 3071 {
3069 argv[1].vval.v_number = range_val; 3078 argv[1].vval.v_number = range_val;
3070 } 3079 }
3071 else 3080 else
3072 argv[1] = li->li_tv; 3081 argv[1] = li->li_tv;
3073 3082
3074 r = eval_expr_typval(expr, argv, 2, rettv); 3083 r = eval_expr_typval(expr, argv, 2, fc, rettv);
3075 3084
3076 if (argv[0].v_type != VAR_NUMBER && argv[0].v_type != VAR_UNKNOWN) 3085 if (argv[0].v_type != VAR_NUMBER && argv[0].v_type != VAR_UNKNOWN)
3077 clear_tv(&argv[0]); 3086 clear_tv(&argv[0]);
3078 if (r == FAIL || called_emsg != called_emsg_start) 3087 if (r == FAIL || called_emsg != called_emsg_start)
3079 break; 3088 break;
3086 } 3095 }
3087 else 3096 else
3088 li = li->li_next; 3097 li = li->li_next;
3089 } 3098 }
3090 3099
3100 if (fc != NULL)
3101 remove_funccal();
3102
3091 l->lv_lock = prev_locked; 3103 l->lv_lock = prev_locked;
3092 } 3104 }
3093 3105
3094 /* 3106 /*
3095 * "reduce(list, { accumulator, element -> value } [, initial])" function 3107 * "reduce(list, { accumulator, element -> value } [, initial])" function