Patch 8.2.0878
Problem:    No reduce() function.
Solution:   Add a reduce() function. (closes #5481)
Files:      runtime/doc/eval.txt, src/evalfunc.c, src/globals.h, src/list.c,
            src/proto/list.pro, src/testdir/test_listdict.vim


*** ../vim-8.2.0877/runtime/doc/eval.txt        2020-06-01 17:28:31.511939716 
+0200
--- runtime/doc/eval.txt        2020-06-01 18:17:26.377235687 +0200
***************
*** 2673,2678 ****
--- 2679,2686 ----
  readdirex({dir} [, {expr}])   List    file info in {dir} selected by {expr}
  readfile({fname} [, {type} [, {max}]])
                                List    get list of lines from file {fname}
+ reduce({object}, {func} [, {initial}])
+                               any     reduce {object} using {func}
  reg_executing()                       String  get the executing register name
  reg_recording()                       String  get the recording register name
  reltime([{start} [, {end}]])  List    get time value
***************
*** 7949,7954 ****
--- 7967,7992 ----
                Can also be used as a |method|: >
                        GetFileName()->readfile()
  
+ reduce({object}, {func} [, {initial}])                        *reduce()* 
*E998*
+               {func} is called for every item in {object}, which can be a
+               |List| or a |Blob|.  {func} is called with two arguments: the
+               result so far and current item.  After processing all items
+               the result is returned.
+ 
+               {initial} is the initial result.  When omitted, the first item
+               in {object} is used and {func} is first called for the second
+               item.  If {initial} is not given and {object} is empty no
+               result can be computed, an E998 error is given.
+ 
+               Examples: >
+                       echo reduce([1, 3, 5], { acc, val -> acc + val })
+                       echo reduce(['x', 'y'], { acc, val -> acc .. val }, 'a')
+                       echo reduce(0z1122, { acc, val -> 2 * acc + val })
+ <
+               Can also be used as a |method|: >
+                       echo mylist->reduce({ acc, val -> acc + val }, 0)
+ 
+ 
  reg_executing()                                               
*reg_executing()*
                Returns the single letter name of the register being executed.
                Returns an empty string when no register is being executed.
*** ../vim-8.2.0877/src/evalfunc.c      2020-06-01 17:28:31.511939716 +0200
--- src/evalfunc.c      2020-06-01 17:46:19.838945213 +0200
***************
*** 769,774 ****
--- 769,775 ----
      {"readdir",               1, 2, FEARG_1,    ret_list_string, f_readdir},
      {"readdirex",     1, 2, FEARG_1,    ret_list_dict_any, f_readdirex},
      {"readfile",      1, 3, FEARG_1,    ret_any,      f_readfile},
+     {"reduce",                2, 3, FEARG_1,    ret_any,      f_reduce},
      {"reg_executing", 0, 0, 0,          ret_string,   f_reg_executing},
      {"reg_recording", 0, 0, 0,          ret_string,   f_reg_recording},
      {"reltime",               0, 2, FEARG_1,    ret_list_any, f_reltime},
*** ../vim-8.2.0877/src/globals.h       2020-05-31 16:41:04.646603340 +0200
--- src/globals.h       2020-06-01 17:46:19.838945213 +0200
***************
*** 1690,1695 ****
--- 1690,1696 ----
  EXTERN char e_const_option[]  INIT(= N_("E996: Cannot lock an option"));
  EXTERN char e_unknown_option[]        INIT(= N_("E113: Unknown option: %s"));
  EXTERN char e_letunexp[]      INIT(= N_("E18: Unexpected characters in 
:let"));
+ EXTERN char e_reduceempty[]   INIT(= N_("E998: Reduce of an empty %s with no 
initial value"));
  #endif
  #ifdef FEAT_QUICKFIX
  EXTERN char e_readerrf[]      INIT(= N_("E47: Error while reading 
errorfile"));
*** ../vim-8.2.0877/src/list.c  2020-05-26 20:21:54.167611874 +0200
--- src/list.c  2020-06-01 18:36:56.572875472 +0200
***************
*** 2305,2308 ****
--- 2305,2413 ----
      }
  }
  
+ /*
+  * "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)
*** ../vim-8.2.0877/src/proto/list.pro  2020-04-05 18:56:02.233436590 +0200
--- src/proto/list.pro  2020-06-01 17:46:19.838945213 +0200
***************
*** 51,54 ****
--- 51,55 ----
  void f_insert(typval_T *argvars, typval_T *rettv);
  void f_remove(typval_T *argvars, typval_T *rettv);
  void f_reverse(typval_T *argvars, typval_T *rettv);
+ void f_reduce(typval_T *argvars, typval_T *rettv);
  /* vim: set ft=c : */
*** ../vim-8.2.0877/src/testdir/test_listdict.vim       2020-04-25 
15:24:40.551354115 +0200
--- src/testdir/test_listdict.vim       2020-06-01 17:53:56.392574568 +0200
***************
*** 680,685 ****
--- 680,716 ----
    call assert_fails("call sort([1, 2], function('min'))", "E702:")
  endfunc
  
+ " reduce a list or a blob
+ func Test_reduce()
+   call assert_equal(1, reduce([], { acc, val -> acc + val }, 1))
+   call assert_equal(10, reduce([1, 3, 5], { acc, val -> acc + val }, 1))
+   call assert_equal(2 * (2 * ((2 * 1) + 2) + 3) + 4, reduce([2, 3, 4], { acc, 
val -> 2 * acc + val }, 1))
+   call assert_equal('a x y z', ['x', 'y', 'z']->reduce({ acc, val -> acc .. ' 
' .. val}, 'a'))
+   call assert_equal(#{ x: 1, y: 1, z: 1 }, ['x', 'y', 'z']->reduce({ acc, val 
-> extend(acc, { val: 1 }) }, {}))
+   call assert_equal([0, 1, 2, 3], reduce([1, 2, 3], function('add'), [0]))
+ 
+   let l = ['x', 'y', 'z']
+   call assert_equal(42, reduce(l, function('get'), #{ x: #{ y: #{ z: 42 } } 
}))
+   call assert_equal(['x', 'y', 'z'], l)
+ 
+   call assert_equal(1, reduce([1], { acc, val -> acc + val }))
+   call assert_equal('x y z', reduce(['x', 'y', 'z'], { acc, val -> acc .. ' ' 
.. val }))
+   call assert_equal(120, range(1, 5)->reduce({ acc, val -> acc * val }))
+   call assert_fails("call reduce([], { acc, val -> acc + val })", 'E998: 
Reduce of an empty List with no initial value')
+ 
+   call assert_equal(1, reduce(0z, { acc, val -> acc + val }, 1))
+   call assert_equal(1 + 0xaf + 0xbf + 0xcf, reduce(0zAFBFCF, { acc, val -> 
acc + val }, 1))
+   call assert_equal(2 * (2 * 1 + 0xaf) + 0xbf, 0zAFBF->reduce({ acc, val -> 2 
* acc + val }, 1))
+ 
+   call assert_equal(0xff, reduce(0zff, { acc, val -> acc + val }))
+   call assert_equal(2 * (2 * 0xaf + 0xbf) + 0xcf, reduce(0zAFBFCF, { acc, val 
-> 2 * acc + val }))
+   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({}, { acc, val -> acc + val }, 1)", 'E897:')
+   call assert_fails("call reduce(0, { acc, val -> acc + val }, 1)", 'E897:')
+   call assert_fails("call reduce('', { acc, val -> acc + val }, 1)", 'E897:')
+ endfunc
+ 
  " splitting a string to a List using split()
  func Test_str_split()
    call assert_equal(['aa', 'bb'], split('  aa  bb '))
*** ../vim-8.2.0877/src/version.c       2020-06-01 17:28:31.515939699 +0200
--- src/version.c       2020-06-01 18:37:25.180752064 +0200
***************
*** 748,749 ****
--- 748,751 ----
  {   /* Add new patch number below this line */
+ /**/
+     878,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
243. You unsuccessfully try to download a pizza from www.dominos.com.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202006011639.051Gdp6q010726%40masaka.moolenaar.net.

Raspunde prin e-mail lui