diff src/list.c @ 20649:1fa0ace0ba65 v8.2.0878

patch 8.2.0878: no reduce() function Commit: https://github.com/vim/vim/commit/85629985b71035608a37ba3bde86968481490d46 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Jun 1 18:39:20 2020 +0200 patch 8.2.0878: no reduce() function Problem: No reduce() function. Solution: Add a reduce() function. (closes https://github.com/vim/vim/issues/5481)
author Bram Moolenaar <Bram@vim.org>
date Mon, 01 Jun 2020 18:45:03 +0200
parents 09143ab0fbbd
children a1e6d9353736
line wrap: on
line diff
--- a/src/list.c
+++ b/src/list.c
@@ -2305,4 +2305,109 @@ f_reverse(typval_T *argvars, typval_T *r
     }
 }
 
+/*
+ * "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)