diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-08-17 14:12:24 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2023-08-17 15:37:32 +0800 |
commit | b193674b4a1dce1b348489fa13dd42254b9a3ebb (patch) | |
tree | 0f2ba228c173892c16b082236f0eb124ad02fab8 /src/nvim/eval/funcs.c | |
parent | c5576fcc8003280489c0aa0323a966e6de33e31f (diff) | |
download | rneovim-b193674b4a1dce1b348489fa13dd42254b9a3ebb.tar.gz rneovim-b193674b4a1dce1b348489fa13dd42254b9a3ebb.tar.bz2 rneovim-b193674b4a1dce1b348489fa13dd42254b9a3ebb.zip |
vim-patch:partial:8.2.3849: functions implementing reduce and map are too long
Problem: Functions implementing reduce and map are too long.
Solution: Use a function for each type of value. Add a few more test cases
and add to the help. (Yegappan Lakshmanan, closes vim/vim#9370)
https://github.com/vim/vim/commit/389b72196e6aaeafe3f907c73d271f2c6b931140
Partial port as this doesn't include handling for non-materialized List.
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Diffstat (limited to 'src/nvim/eval/funcs.c')
-rw-r--r-- | src/nvim/eval/funcs.c | 241 |
1 files changed, 138 insertions, 103 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index bf11fdf029..d5d9726397 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6171,17 +6171,150 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } +/// reduce() on a List +static void reduce_list(typval_T *argvars, const char *func_name, funcexe_T *funcexe, + typval_T *rettv) +{ + list_T *const l = argvars[0].vval.v_list; + const int called_emsg_start = called_emsg; + + typval_T initial; + const listitem_T *li = NULL; + if (argvars[2].v_type == VAR_UNKNOWN) { + if (tv_list_len(l) == 0) { + semsg(_(e_reduceempty), "List"); + return; + } + const listitem_T *const first = tv_list_first(l); + initial = *TV_LIST_ITEM_TV(first); + li = TV_LIST_ITEM_NEXT(l, first); + } else { + initial = argvars[2]; + li = tv_list_first(l); + } + + tv_copy(&initial, rettv); + + if (l == NULL) { + return; + } + + const VarLockStatus prev_locked = tv_list_locked(l); + + tv_list_set_lock(l, VAR_FIXED); // disallow the list changing here + for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) { + typval_T argv[3]; + argv[0] = *rettv; + argv[1] = *TV_LIST_ITEM_TV(li); + rettv->v_type = VAR_UNKNOWN; + const int r = call_func(func_name, -1, rettv, 2, argv, funcexe); + tv_clear(&argv[0]); + if (r == FAIL || called_emsg != called_emsg_start) { + break; + } + } + tv_list_set_lock(l, prev_locked); +} + +/// reduce() on a String +static void reduce_string(typval_T *argvars, const char *func_name, funcexe_T *funcexe, + typval_T *rettv) +{ + const char *p = tv_get_string(&argvars[0]); + int len; + const int called_emsg_start = called_emsg; + + if (argvars[2].v_type == VAR_UNKNOWN) { + if (*p == NUL) { + semsg(_(e_reduceempty), "String"); + return; + } + len = utfc_ptr2len(p); + *rettv = (typval_T){ + .v_type = VAR_STRING, + .v_lock = VAR_UNLOCKED, + .vval.v_string = xstrnsave(p, (size_t)len), + }; + p += len; + } else if (argvars[2].v_type != VAR_STRING) { + semsg(_(e_string_expected_for_argument_nr), 3); + return; + } else { + tv_copy(&argvars[2], rettv); + } + + for (; *p != NUL; p += len) { + typval_T argv[3]; + argv[0] = *rettv; + len = utfc_ptr2len(p); + argv[1] = (typval_T){ + .v_type = VAR_STRING, + .v_lock = VAR_UNLOCKED, + .vval.v_string = xstrnsave(p, (size_t)len), + }; + const int r = call_func(func_name, -1, rettv, 2, argv, funcexe); + tv_clear(&argv[0]); + tv_clear(&argv[1]); + if (r == FAIL || called_emsg != called_emsg_start) { + break; + } + } +} + +/// reduce() on a Blob +static void reduce_blob(typval_T *argvars, const char *func_name, funcexe_T *funcexe, + typval_T *rettv) +{ + const blob_T *const b = argvars[0].vval.v_blob; + const int called_emsg_start = called_emsg; + + typval_T initial; + int i; + if (argvars[2].v_type == VAR_UNKNOWN) { + if (tv_blob_len(b) == 0) { + semsg(_(e_reduceempty), "Blob"); + return; + } + initial = (typval_T){ + .v_type = VAR_NUMBER, + .v_lock = VAR_UNLOCKED, + .vval.v_number = tv_blob_get(b, 0), + }; + i = 1; + } else if (argvars[2].v_type != VAR_NUMBER) { + emsg(_(e_number_exp)); + return; + } else { + initial = argvars[2]; + i = 0; + } + + tv_copy(&initial, rettv); + for (; i < tv_blob_len(b); i++) { + typval_T argv[3]; + argv[0] = *rettv; + argv[1] = (typval_T){ + .v_type = VAR_NUMBER, + .v_lock = VAR_UNLOCKED, + .vval.v_number = tv_blob_get(b, i), + }; + const int r = call_func(func_name, -1, rettv, 2, argv, funcexe); + if (r == FAIL || called_emsg != called_emsg_start) { + return; + } + } +} + /// "reduce(list, { accumulator, element -> value } [, initial])" function /// "reduce(blob, { accumulator, element -> value } [, initial])" function /// "reduce(string, { accumulator, element -> value } [, initial])" function static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - const int called_emsg_start = called_emsg; - if (argvars[0].v_type != VAR_STRING && argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) { emsg(_(e_string_list_or_blob_required)); + return; } const char *func_name; @@ -6203,110 +6336,12 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) funcexe.fe_evaluate = true; funcexe.fe_partial = partial; - typval_T initial; - typval_T argv[3]; if (argvars[0].v_type == VAR_LIST) { - list_T *const l = argvars[0].vval.v_list; - const listitem_T *li; - - if (argvars[2].v_type == VAR_UNKNOWN) { - if (tv_list_len(l) == 0) { - semsg(_(e_reduceempty), "List"); - return; - } - const listitem_T *const first = tv_list_first(l); - initial = *TV_LIST_ITEM_TV(first); - li = TV_LIST_ITEM_NEXT(l, first); - } else { - initial = argvars[2]; - li = tv_list_first(l); - } - - tv_copy(&initial, rettv); - - if (l != NULL) { - const VarLockStatus prev_locked = tv_list_locked(l); - - tv_list_set_lock(l, VAR_FIXED); // disallow the list changing here - for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) { - argv[0] = *rettv; - argv[1] = *TV_LIST_ITEM_TV(li); - rettv->v_type = VAR_UNKNOWN; - const int r = call_func(func_name, -1, rettv, 2, argv, &funcexe); - tv_clear(&argv[0]); - if (r == FAIL || called_emsg != called_emsg_start) { - break; - } - } - tv_list_set_lock(l, prev_locked); - } + reduce_list(argvars, func_name, &funcexe, rettv); } else if (argvars[0].v_type == VAR_STRING) { - const char *p = tv_get_string(&argvars[0]); - int len; - - if (argvars[2].v_type == VAR_UNKNOWN) { - if (*p == NUL) { - semsg(_(e_reduceempty), "String"); - return; - } - len = utfc_ptr2len(p); - *rettv = (typval_T){ - .v_type = VAR_STRING, - .v_lock = VAR_UNLOCKED, - .vval.v_string = xstrnsave(p, (size_t)len), - }; - p += len; - } else if (argvars[2].v_type != VAR_STRING) { - semsg(_(e_string_expected_for_argument_nr), 3); - return; - } else { - tv_copy(&argvars[2], rettv); - } - - for (; *p != NUL; p += len) { - argv[0] = *rettv; - len = utfc_ptr2len(p); - argv[1] = (typval_T){ - .v_type = VAR_STRING, - .v_lock = VAR_UNLOCKED, - .vval.v_string = xstrnsave(p, (size_t)len), - }; - const int r = call_func(func_name, -1, rettv, 2, argv, &funcexe); - tv_clear(&argv[0]); - tv_clear(&argv[1]); - if (r == FAIL || called_emsg != called_emsg_start) { - break; - } - } + reduce_string(argvars, func_name, &funcexe, rettv); } else { - const blob_T *const b = argvars[0].vval.v_blob; - int i; - - if (argvars[2].v_type == VAR_UNKNOWN) { - if (tv_blob_len(b) == 0) { - semsg(_(e_reduceempty), "Blob"); - return; - } - initial.v_type = VAR_NUMBER; - initial.vval.v_number = tv_blob_get(b, 0); - i = 1; - } else if (argvars[2].v_type != VAR_NUMBER) { - emsg(_(e_number_exp)); - return; - } else { - initial = argvars[2]; - i = 0; - } - - tv_copy(&initial, rettv); - for (; i < tv_blob_len(b); i++) { - argv[0] = *rettv; - argv[1].v_type = VAR_NUMBER; - argv[1].vval.v_number = tv_blob_get(b, i); - if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL) { - return; - } - } + reduce_blob(argvars, func_name, &funcexe, rettv); } } |