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:
committed by
Bram Moolenaar
parent
1aeccdb464
commit
f973eeb491
289
src/dict.c
289
src/dict.c
@@ -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)
|
||||
|
Reference in New Issue
Block a user