0
0
mirror of https://github.com/vim/vim.git synced 2025-10-22 08:34:29 -04:00

patch 8.2.3871: list.c contains code for dict and blob

Problem:    List.c contains code for dict and blob.
Solution:   Refactor to put code where it belongs. (Yegappan Lakshmanan,
            closes #9386)
This commit is contained in:
Yegappan Lakshmanan
2021-12-22 18:19:26 +00:00
committed by Bram Moolenaar
parent 1aeccdb464
commit f973eeb491
13 changed files with 976 additions and 873 deletions

View File

@@ -896,13 +896,11 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
int vim9script = in_vim9script();
int had_comma;
/*
* First check if it's not a curly-braces thing: {expr}.
* Must do this without evaluating, otherwise a function may be called
* twice. Unfortunately this means we need to call eval1() twice for the
* first item.
* But {} is an empty Dictionary.
*/
// First check if it's not a curly-braces thing: {expr}.
// Must do this without evaluating, otherwise a function may be called
// twice. Unfortunately this means we need to call eval1() twice for the
// first item.
// But {} is an empty Dictionary.
if (!vim9script
&& *curly_expr != '}'
&& eval1(&curly_expr, &tv, NULL) == OK
@@ -1183,6 +1181,251 @@ dict_equal(
return TRUE;
}
/*
* Count the number of times item "needle" occurs in Dict "d". Case is ignored
* if "ic" is TRUE.
*/
long
dict_count(dict_T *d, typval_T *needle, int ic)
{
int todo;
hashitem_T *hi;
long n = 0;
if (d == NULL)
return 0;
todo = (int)d->dv_hashtab.ht_used;
for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
{
if (!HASHITEM_EMPTY(hi))
{
--todo;
if (tv_equal(&HI2DI(hi)->di_tv, needle, ic, FALSE))
++n;
}
}
return n;
}
/*
* extend() a Dict. Append Dict argvars[1] to Dict argvars[0] and return the
* resulting Dict in "rettv". "is_new" is TRUE for extendnew().
*/
void
dict_extend_func(
typval_T *argvars,
type_T *type,
char *func_name,
char_u *arg_errmsg,
int is_new,
typval_T *rettv)
{
dict_T *d1, *d2;
char_u *action;
int i;
d1 = argvars[0].vval.v_dict;
if (d1 == NULL)
{
emsg(_(e_cannot_extend_null_dict));
return;
}
d2 = argvars[1].vval.v_dict;
if ((is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TRUE))
&& d2 != NULL)
{
if (is_new)
{
d1 = dict_copy(d1, FALSE, get_copyID());
if (d1 == NULL)
return;
}
// Check the third argument.
if (argvars[2].v_type != VAR_UNKNOWN)
{
static char *(av[]) = {"keep", "force", "error"};
action = tv_get_string_chk(&argvars[2]);
if (action == NULL)
return;
for (i = 0; i < 3; ++i)
if (STRCMP(action, av[i]) == 0)
break;
if (i == 3)
{
semsg(_(e_invarg2), action);
return;
}
}
else
action = (char_u *)"force";
if (type != NULL && check_typval_arg_type(type, &argvars[1],
func_name, 2) == FAIL)
return;
dict_extend(d1, d2, action, func_name);
if (is_new)
{
rettv->v_type = VAR_DICT;
rettv->vval.v_dict = d1;
rettv->v_lock = FALSE;
}
else
copy_tv(&argvars[0], rettv);
}
}
/*
* Implementation of map() and filter() for a Dict. Apply "expr" to every
* item in Dict "d" and return the result in "rettv".
*/
void
dict_filter_map(
dict_T *d,
filtermap_T filtermap,
type_T *argtype,
char *func_name,
char_u *arg_errmsg,
typval_T *expr,
typval_T *rettv)
{
int prev_lock;
dict_T *d_ret = NULL;
hashtab_T *ht;
hashitem_T *hi;
dictitem_T *di;
int todo;
int rem;
if (filtermap == FILTERMAP_MAPNEW)
{
rettv->v_type = VAR_DICT;
rettv->vval.v_dict = NULL;
}
if (d == NULL
|| (filtermap == FILTERMAP_FILTER
&& value_check_lock(d->dv_lock, arg_errmsg, TRUE)))
return;
prev_lock = d->dv_lock;
if (filtermap == FILTERMAP_MAPNEW)
{
if (rettv_dict_alloc(rettv) == FAIL)
return;
d_ret = rettv->vval.v_dict;
}
if (filtermap != FILTERMAP_FILTER && d->dv_lock == 0)
d->dv_lock = VAR_LOCKED;
ht = &d->dv_hashtab;
hash_lock(ht);
todo = (int)ht->ht_used;
for (hi = ht->ht_array; todo > 0; ++hi)
{
if (!HASHITEM_EMPTY(hi))
{
int r;
typval_T newtv;
--todo;
di = HI2DI(hi);
if (filtermap == FILTERMAP_MAP
&& (value_check_lock(di->di_tv.v_lock,
arg_errmsg, TRUE)
|| var_check_ro(di->di_flags,
arg_errmsg, TRUE)))
break;
set_vim_var_string(VV_KEY, di->di_key, -1);
newtv.v_type = VAR_UNKNOWN;
r = filter_map_one(&di->di_tv, expr, filtermap,
&newtv, &rem);
clear_tv(get_vim_var_tv(VV_KEY));
if (r == FAIL || did_emsg)
{
clear_tv(&newtv);
break;
}
if (filtermap == FILTERMAP_MAP)
{
if (argtype != NULL && check_typval_arg_type(
argtype->tt_member, &newtv,
func_name, 0) == FAIL)
{
clear_tv(&newtv);
break;
}
// map(): replace the dict item value
clear_tv(&di->di_tv);
newtv.v_lock = 0;
di->di_tv = newtv;
}
else if (filtermap == FILTERMAP_MAPNEW)
{
// mapnew(): add the item value to the new dict
r = dict_add_tv(d_ret, (char *)di->di_key, &newtv);
clear_tv(&newtv);
if (r == FAIL)
break;
}
else if (filtermap == FILTERMAP_FILTER && rem)
{
// filter(false): remove the item from the dict
if (var_check_fixed(di->di_flags, arg_errmsg, TRUE)
|| var_check_ro(di->di_flags, arg_errmsg, TRUE))
break;
dictitem_remove(d, di);
}
}
}
hash_unlock(ht);
d->dv_lock = prev_lock;
}
/*
* "remove({dict})" function
*/
void
dict_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
{
dict_T *d;
char_u *key;
dictitem_T *di;
if (argvars[2].v_type != VAR_UNKNOWN)
{
semsg(_(e_too_many_arguments_for_function_str), "remove()");
return;
}
d = argvars[0].vval.v_dict;
if (d == NULL || value_check_lock(d->dv_lock, arg_errmsg, TRUE))
return;
key = tv_get_string_chk(&argvars[1]);
if (key == NULL)
return;
di = dict_find(d, key, -1);
if (di == NULL)
{
semsg(_(e_dictkey), key);
return;
}
if (var_check_fixed(di->di_flags, arg_errmsg, TRUE)
|| var_check_ro(di->di_flags, arg_errmsg, TRUE))
return;
*rettv = di->di_tv;
init_tv(&di->di_tv);
dictitem_remove(d, di);
}
/*
* Turn a dict into a list:
* "what" == 0: list of keys
@@ -1338,36 +1581,4 @@ f_has_key(typval_T *argvars, typval_T *rettv)
tv_get_string(&argvars[1]), -1) != NULL;
}
/*
* "remove({dict})" function
*/
void
dict_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
{
dict_T *d;
char_u *key;
dictitem_T *di;
if (argvars[2].v_type != VAR_UNKNOWN)
semsg(_(e_too_many_arguments_for_function_str), "remove()");
else if ((d = argvars[0].vval.v_dict) != NULL
&& !value_check_lock(d->dv_lock, arg_errmsg, TRUE))
{
key = tv_get_string_chk(&argvars[1]);
if (key != NULL)
{
di = dict_find(d, key, -1);
if (di == NULL)
semsg(_(e_dictkey), key);
else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
&& !var_check_ro(di->di_flags, arg_errmsg, TRUE))
{
*rettv = di->di_tv;
init_tv(&di->di_tv);
dictitem_remove(d, di);
}
}
}
}
#endif // defined(FEAT_EVAL)