diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-06-01 18:39:20 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-06-01 18:39:20 +0200 |
commit | 85629985b71035608a37ba3bde86968481490d46 (patch) | |
tree | 5970b7cc5eb33369ad8ee0337884e781fba1dfea /src/list.c | |
parent | e8f5ec0d30b629d7166f0ad03434065d8bc822df (diff) | |
download | vim-git-85629985b71035608a37ba3bde86968481490d46.tar.gz |
patch 8.2.0878: no reduce() functionv8.2.0878
Problem: No reduce() function.
Solution: Add a reduce() function. (closes #5481)
Diffstat (limited to 'src/list.c')
-rw-r--r-- | src/list.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/list.c b/src/list.c index 7c06cfce5..40a910b1e 100644 --- a/src/list.c +++ b/src/list.c @@ -2305,4 +2305,109 @@ f_reverse(typval_T *argvars, typval_T *rettv) } } +/* + * "reduce(list, { accumlator, element -> value } [, initial])" function + */ + void +f_reduce(typval_T *argvars, typval_T *rettv) +{ + typval_T accum; + char_u *func_name; + partial_T *partial = NULL; + funcexe_T funcexe; + typval_T argv[3]; + + if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) + { + emsg(_(e_listblobreq)); + return; + } + + if (argvars[1].v_type == VAR_FUNC) + func_name = argvars[1].vval.v_string; + else if (argvars[1].v_type == VAR_PARTIAL) + { + partial = argvars[1].vval.v_partial; + func_name = partial_name(partial); + } + else + func_name = tv_get_string(&argvars[1]); + if (*func_name == NUL) + return; // type error or empty name + + vim_memset(&funcexe, 0, sizeof(funcexe)); + funcexe.evaluate = TRUE; + funcexe.partial = partial; + + if (argvars[0].v_type == VAR_LIST) + { + list_T *l = argvars[0].vval.v_list; + listitem_T *li = NULL; + + CHECK_LIST_MATERIALIZE(l); + if (argvars[2].v_type == VAR_UNKNOWN) + { + if (l == NULL || l->lv_first == NULL) + { + semsg(_(e_reduceempty), "List"); + return; + } + accum = l->lv_first->li_tv; + li = l->lv_first->li_next; + } + else + { + accum = argvars[2]; + if (l != NULL) + li = l->lv_first; + } + + copy_tv(&accum, rettv); + for ( ; li != NULL; li = li->li_next) + { + argv[0] = accum; + argv[1] = li->li_tv; + if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL) + return; + accum = *rettv; + } + } + else + { + blob_T *b = argvars[0].vval.v_blob; + int i; + + if (argvars[2].v_type == VAR_UNKNOWN) + { + if (b == NULL || b->bv_ga.ga_len == 0) + { + semsg(_(e_reduceempty), "Blob"); + return; + } + accum.v_type = VAR_NUMBER; + accum.vval.v_number = blob_get(b, 0); + i = 1; + } + else + { + accum = argvars[2]; + i = 0; + } + + copy_tv(&accum, rettv); + if (b != NULL) + { + for ( ; i < b->bv_ga.ga_len; i++) + { + argv[0] = accum; + argv[1].v_type = VAR_NUMBER; + argv[1].vval.v_number = blob_get(b, i); + if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL) + return; + accum = *rettv; + } + } + } +} + #endif // defined(FEAT_EVAL) |