comparison src/dict.c @ 26684:2126feddeda6 v8.2.3871

patch 8.2.3871: list.c contains code for dict and blob Commit: https://github.com/vim/vim/commit/f973eeb4911de09258e84cb2248dc0f9392824b4 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Wed Dec 22 18:19:26 2021 +0000 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)
author Bram Moolenaar <Bram@vim.org>
date Wed, 22 Dec 2021 19:30:04 +0100
parents fac6673086df
children de714c98c9b8
comparison
equal deleted inserted replaced
26683:d267ab922b57 26684:2126feddeda6
894 char_u *curly_expr = skipwhite(*arg + 1); 894 char_u *curly_expr = skipwhite(*arg + 1);
895 char_u buf[NUMBUFLEN]; 895 char_u buf[NUMBUFLEN];
896 int vim9script = in_vim9script(); 896 int vim9script = in_vim9script();
897 int had_comma; 897 int had_comma;
898 898
899 /* 899 // First check if it's not a curly-braces thing: {expr}.
900 * First check if it's not a curly-braces thing: {expr}. 900 // Must do this without evaluating, otherwise a function may be called
901 * Must do this without evaluating, otherwise a function may be called 901 // twice. Unfortunately this means we need to call eval1() twice for the
902 * twice. Unfortunately this means we need to call eval1() twice for the 902 // first item.
903 * first item. 903 // But {} is an empty Dictionary.
904 * But {} is an empty Dictionary.
905 */
906 if (!vim9script 904 if (!vim9script
907 && *curly_expr != '}' 905 && *curly_expr != '}'
908 && eval1(&curly_expr, &tv, NULL) == OK 906 && eval1(&curly_expr, &tv, NULL) == OK
909 && *skipwhite(curly_expr) == '}') 907 && *skipwhite(curly_expr) == '}')
910 return NOTDONE; 908 return NOTDONE;
1182 } 1180 }
1183 return TRUE; 1181 return TRUE;
1184 } 1182 }
1185 1183
1186 /* 1184 /*
1185 * Count the number of times item "needle" occurs in Dict "d". Case is ignored
1186 * if "ic" is TRUE.
1187 */
1188 long
1189 dict_count(dict_T *d, typval_T *needle, int ic)
1190 {
1191 int todo;
1192 hashitem_T *hi;
1193 long n = 0;
1194
1195 if (d == NULL)
1196 return 0;
1197
1198 todo = (int)d->dv_hashtab.ht_used;
1199 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
1200 {
1201 if (!HASHITEM_EMPTY(hi))
1202 {
1203 --todo;
1204 if (tv_equal(&HI2DI(hi)->di_tv, needle, ic, FALSE))
1205 ++n;
1206 }
1207 }
1208
1209 return n;
1210 }
1211
1212 /*
1213 * extend() a Dict. Append Dict argvars[1] to Dict argvars[0] and return the
1214 * resulting Dict in "rettv". "is_new" is TRUE for extendnew().
1215 */
1216 void
1217 dict_extend_func(
1218 typval_T *argvars,
1219 type_T *type,
1220 char *func_name,
1221 char_u *arg_errmsg,
1222 int is_new,
1223 typval_T *rettv)
1224 {
1225 dict_T *d1, *d2;
1226 char_u *action;
1227 int i;
1228
1229 d1 = argvars[0].vval.v_dict;
1230 if (d1 == NULL)
1231 {
1232 emsg(_(e_cannot_extend_null_dict));
1233 return;
1234 }
1235 d2 = argvars[1].vval.v_dict;
1236 if ((is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TRUE))
1237 && d2 != NULL)
1238 {
1239 if (is_new)
1240 {
1241 d1 = dict_copy(d1, FALSE, get_copyID());
1242 if (d1 == NULL)
1243 return;
1244 }
1245
1246 // Check the third argument.
1247 if (argvars[2].v_type != VAR_UNKNOWN)
1248 {
1249 static char *(av[]) = {"keep", "force", "error"};
1250
1251 action = tv_get_string_chk(&argvars[2]);
1252 if (action == NULL)
1253 return;
1254 for (i = 0; i < 3; ++i)
1255 if (STRCMP(action, av[i]) == 0)
1256 break;
1257 if (i == 3)
1258 {
1259 semsg(_(e_invarg2), action);
1260 return;
1261 }
1262 }
1263 else
1264 action = (char_u *)"force";
1265
1266 if (type != NULL && check_typval_arg_type(type, &argvars[1],
1267 func_name, 2) == FAIL)
1268 return;
1269 dict_extend(d1, d2, action, func_name);
1270
1271 if (is_new)
1272 {
1273 rettv->v_type = VAR_DICT;
1274 rettv->vval.v_dict = d1;
1275 rettv->v_lock = FALSE;
1276 }
1277 else
1278 copy_tv(&argvars[0], rettv);
1279 }
1280 }
1281
1282 /*
1283 * Implementation of map() and filter() for a Dict. Apply "expr" to every
1284 * item in Dict "d" and return the result in "rettv".
1285 */
1286 void
1287 dict_filter_map(
1288 dict_T *d,
1289 filtermap_T filtermap,
1290 type_T *argtype,
1291 char *func_name,
1292 char_u *arg_errmsg,
1293 typval_T *expr,
1294 typval_T *rettv)
1295 {
1296 int prev_lock;
1297 dict_T *d_ret = NULL;
1298 hashtab_T *ht;
1299 hashitem_T *hi;
1300 dictitem_T *di;
1301 int todo;
1302 int rem;
1303
1304 if (filtermap == FILTERMAP_MAPNEW)
1305 {
1306 rettv->v_type = VAR_DICT;
1307 rettv->vval.v_dict = NULL;
1308 }
1309 if (d == NULL
1310 || (filtermap == FILTERMAP_FILTER
1311 && value_check_lock(d->dv_lock, arg_errmsg, TRUE)))
1312 return;
1313
1314 prev_lock = d->dv_lock;
1315
1316 if (filtermap == FILTERMAP_MAPNEW)
1317 {
1318 if (rettv_dict_alloc(rettv) == FAIL)
1319 return;
1320 d_ret = rettv->vval.v_dict;
1321 }
1322
1323 if (filtermap != FILTERMAP_FILTER && d->dv_lock == 0)
1324 d->dv_lock = VAR_LOCKED;
1325 ht = &d->dv_hashtab;
1326 hash_lock(ht);
1327 todo = (int)ht->ht_used;
1328 for (hi = ht->ht_array; todo > 0; ++hi)
1329 {
1330 if (!HASHITEM_EMPTY(hi))
1331 {
1332 int r;
1333 typval_T newtv;
1334
1335 --todo;
1336 di = HI2DI(hi);
1337 if (filtermap == FILTERMAP_MAP
1338 && (value_check_lock(di->di_tv.v_lock,
1339 arg_errmsg, TRUE)
1340 || var_check_ro(di->di_flags,
1341 arg_errmsg, TRUE)))
1342 break;
1343 set_vim_var_string(VV_KEY, di->di_key, -1);
1344 newtv.v_type = VAR_UNKNOWN;
1345 r = filter_map_one(&di->di_tv, expr, filtermap,
1346 &newtv, &rem);
1347 clear_tv(get_vim_var_tv(VV_KEY));
1348 if (r == FAIL || did_emsg)
1349 {
1350 clear_tv(&newtv);
1351 break;
1352 }
1353 if (filtermap == FILTERMAP_MAP)
1354 {
1355 if (argtype != NULL && check_typval_arg_type(
1356 argtype->tt_member, &newtv,
1357 func_name, 0) == FAIL)
1358 {
1359 clear_tv(&newtv);
1360 break;
1361 }
1362 // map(): replace the dict item value
1363 clear_tv(&di->di_tv);
1364 newtv.v_lock = 0;
1365 di->di_tv = newtv;
1366 }
1367 else if (filtermap == FILTERMAP_MAPNEW)
1368 {
1369 // mapnew(): add the item value to the new dict
1370 r = dict_add_tv(d_ret, (char *)di->di_key, &newtv);
1371 clear_tv(&newtv);
1372 if (r == FAIL)
1373 break;
1374 }
1375 else if (filtermap == FILTERMAP_FILTER && rem)
1376 {
1377 // filter(false): remove the item from the dict
1378 if (var_check_fixed(di->di_flags, arg_errmsg, TRUE)
1379 || var_check_ro(di->di_flags, arg_errmsg, TRUE))
1380 break;
1381 dictitem_remove(d, di);
1382 }
1383 }
1384 }
1385 hash_unlock(ht);
1386 d->dv_lock = prev_lock;
1387 }
1388
1389 /*
1390 * "remove({dict})" function
1391 */
1392 void
1393 dict_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
1394 {
1395 dict_T *d;
1396 char_u *key;
1397 dictitem_T *di;
1398
1399 if (argvars[2].v_type != VAR_UNKNOWN)
1400 {
1401 semsg(_(e_too_many_arguments_for_function_str), "remove()");
1402 return;
1403 }
1404
1405 d = argvars[0].vval.v_dict;
1406 if (d == NULL || value_check_lock(d->dv_lock, arg_errmsg, TRUE))
1407 return;
1408
1409 key = tv_get_string_chk(&argvars[1]);
1410 if (key == NULL)
1411 return;
1412
1413 di = dict_find(d, key, -1);
1414 if (di == NULL)
1415 {
1416 semsg(_(e_dictkey), key);
1417 return;
1418 }
1419
1420 if (var_check_fixed(di->di_flags, arg_errmsg, TRUE)
1421 || var_check_ro(di->di_flags, arg_errmsg, TRUE))
1422 return;
1423
1424 *rettv = di->di_tv;
1425 init_tv(&di->di_tv);
1426 dictitem_remove(d, di);
1427 }
1428
1429 /*
1187 * Turn a dict into a list: 1430 * Turn a dict into a list:
1188 * "what" == 0: list of keys 1431 * "what" == 0: list of keys
1189 * "what" == 1: list of values 1432 * "what" == 1: list of values
1190 * "what" == 2: list of items 1433 * "what" == 2: list of items
1191 */ 1434 */
1336 1579
1337 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict, 1580 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
1338 tv_get_string(&argvars[1]), -1) != NULL; 1581 tv_get_string(&argvars[1]), -1) != NULL;
1339 } 1582 }
1340 1583
1341 /*
1342 * "remove({dict})" function
1343 */
1344 void
1345 dict_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
1346 {
1347 dict_T *d;
1348 char_u *key;
1349 dictitem_T *di;
1350
1351 if (argvars[2].v_type != VAR_UNKNOWN)
1352 semsg(_(e_too_many_arguments_for_function_str), "remove()");
1353 else if ((d = argvars[0].vval.v_dict) != NULL
1354 && !value_check_lock(d->dv_lock, arg_errmsg, TRUE))
1355 {
1356 key = tv_get_string_chk(&argvars[1]);
1357 if (key != NULL)
1358 {
1359 di = dict_find(d, key, -1);
1360 if (di == NULL)
1361 semsg(_(e_dictkey), key);
1362 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
1363 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
1364 {
1365 *rettv = di->di_tv;
1366 init_tv(&di->di_tv);
1367 dictitem_remove(d, di);
1368 }
1369 }
1370 }
1371 }
1372
1373 #endif // defined(FEAT_EVAL) 1584 #endif // defined(FEAT_EVAL)