Mercurial > vim
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) |