comparison src/list.c @ 17530:ef23ec1eee54 v8.1.1763

patch 8.1.1763: evalfunc.c is still too big commit https://github.com/vim/vim/commit/9f9fe37f6750f342255a51f158a7bb372c827f7f Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jul 27 23:12:12 2019 +0200 patch 8.1.1763: evalfunc.c is still too big Problem: Evalfunc.c is still too big. Solution: Move dict and list functions to a better place.
author Bram Moolenaar <Bram@vim.org>
date Sat, 27 Jul 2019 23:15:05 +0200
parents 041156ce1d22
children ff097edaae89
comparison
equal deleted inserted replaced
17529:4bd2e3339ba3 17530:ef23ec1eee54
873 873
874 return retval; 874 return retval;
875 } 875 }
876 876
877 /* 877 /*
878 * "join()" function
879 */
880 void
881 f_join(typval_T *argvars, typval_T *rettv)
882 {
883 garray_T ga;
884 char_u *sep;
885
886 if (argvars[0].v_type != VAR_LIST)
887 {
888 emsg(_(e_listreq));
889 return;
890 }
891 if (argvars[0].vval.v_list == NULL)
892 return;
893 if (argvars[1].v_type == VAR_UNKNOWN)
894 sep = (char_u *)" ";
895 else
896 sep = tv_get_string_chk(&argvars[1]);
897
898 rettv->v_type = VAR_STRING;
899
900 if (sep != NULL)
901 {
902 ga_init2(&ga, (int)sizeof(char), 80);
903 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
904 ga_append(&ga, NUL);
905 rettv->vval.v_string = (char_u *)ga.ga_data;
906 }
907 else
908 rettv->vval.v_string = NULL;
909 }
910
911 /*
878 * Allocate a variable for a List and fill it from "*arg". 912 * Allocate a variable for a List and fill it from "*arg".
879 * Return OK or FAIL. 913 * Return OK or FAIL.
880 */ 914 */
881 int 915 int
882 get_list_tv(char_u **arg, typval_T *rettv, int evaluate) 916 get_list_tv(char_u **arg, typval_T *rettv, int evaluate)
1005 else 1039 else
1006 li->li_next = li + 1; 1040 li->li_next = li + 1;
1007 } 1041 }
1008 } 1042 }
1009 1043
1044 /*
1045 * "list2str()" function
1046 */
1047 void
1048 f_list2str(typval_T *argvars, typval_T *rettv)
1049 {
1050 list_T *l;
1051 listitem_T *li;
1052 garray_T ga;
1053 int utf8 = FALSE;
1054
1055 rettv->v_type = VAR_STRING;
1056 rettv->vval.v_string = NULL;
1057 if (argvars[0].v_type != VAR_LIST)
1058 {
1059 emsg(_(e_invarg));
1060 return;
1061 }
1062
1063 l = argvars[0].vval.v_list;
1064 if (l == NULL)
1065 return; // empty list results in empty string
1066
1067 if (argvars[1].v_type != VAR_UNKNOWN)
1068 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
1069
1070 ga_init2(&ga, 1, 80);
1071 if (has_mbyte || utf8)
1072 {
1073 char_u buf[MB_MAXBYTES + 1];
1074 int (*char2bytes)(int, char_u *);
1075
1076 if (utf8 || enc_utf8)
1077 char2bytes = utf_char2bytes;
1078 else
1079 char2bytes = mb_char2bytes;
1080
1081 for (li = l->lv_first; li != NULL; li = li->li_next)
1082 {
1083 buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL;
1084 ga_concat(&ga, buf);
1085 }
1086 ga_append(&ga, NUL);
1087 }
1088 else if (ga_grow(&ga, list_len(l) + 1) == OK)
1089 {
1090 for (li = l->lv_first; li != NULL; li = li->li_next)
1091 ga_append(&ga, tv_get_number(&li->li_tv));
1092 ga_append(&ga, NUL);
1093 }
1094
1095 rettv->v_type = VAR_STRING;
1096 rettv->vval.v_string = ga.ga_data;
1097 }
1098
1099 void
1100 list_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
1101 {
1102 list_T *l;
1103 listitem_T *item, *item2;
1104 listitem_T *li;
1105 int error = FALSE;
1106 int idx;
1107
1108 if ((l = argvars[0].vval.v_list) == NULL
1109 || var_check_lock(l->lv_lock, arg_errmsg, TRUE))
1110 return;
1111
1112 idx = (long)tv_get_number_chk(&argvars[1], &error);
1113 if (error)
1114 ; // type error: do nothing, errmsg already given
1115 else if ((item = list_find(l, idx)) == NULL)
1116 semsg(_(e_listidx), idx);
1117 else
1118 {
1119 if (argvars[2].v_type == VAR_UNKNOWN)
1120 {
1121 /* Remove one item, return its value. */
1122 vimlist_remove(l, item, item);
1123 *rettv = item->li_tv;
1124 vim_free(item);
1125 }
1126 else
1127 {
1128 // Remove range of items, return list with values.
1129 int end = (long)tv_get_number_chk(&argvars[2], &error);
1130
1131 if (error)
1132 ; // type error: do nothing
1133 else if ((item2 = list_find(l, end)) == NULL)
1134 semsg(_(e_listidx), end);
1135 else
1136 {
1137 int cnt = 0;
1138
1139 for (li = item; li != NULL; li = li->li_next)
1140 {
1141 ++cnt;
1142 if (li == item2)
1143 break;
1144 }
1145 if (li == NULL) /* didn't find "item2" after "item" */
1146 emsg(_(e_invrange));
1147 else
1148 {
1149 vimlist_remove(l, item, item2);
1150 if (rettv_list_alloc(rettv) == OK)
1151 {
1152 l = rettv->vval.v_list;
1153 l->lv_first = item;
1154 l->lv_last = item2;
1155 item->li_prev = NULL;
1156 item2->li_next = NULL;
1157 l->lv_len = cnt;
1158 }
1159 }
1160 }
1161 }
1162 }
1163 }
1164
1165 static int item_compare(const void *s1, const void *s2);
1166 static int item_compare2(const void *s1, const void *s2);
1167
1168 /* struct used in the array that's given to qsort() */
1169 typedef struct
1170 {
1171 listitem_T *item;
1172 int idx;
1173 } sortItem_T;
1174
1175 /* struct storing information about current sort */
1176 typedef struct
1177 {
1178 int item_compare_ic;
1179 int item_compare_numeric;
1180 int item_compare_numbers;
1181 #ifdef FEAT_FLOAT
1182 int item_compare_float;
1183 #endif
1184 char_u *item_compare_func;
1185 partial_T *item_compare_partial;
1186 dict_T *item_compare_selfdict;
1187 int item_compare_func_err;
1188 int item_compare_keep_zero;
1189 } sortinfo_T;
1190 static sortinfo_T *sortinfo = NULL;
1191 #define ITEM_COMPARE_FAIL 999
1192
1193 /*
1194 * Compare functions for f_sort() and f_uniq() below.
1195 */
1196 static int
1197 item_compare(const void *s1, const void *s2)
1198 {
1199 sortItem_T *si1, *si2;
1200 typval_T *tv1, *tv2;
1201 char_u *p1, *p2;
1202 char_u *tofree1 = NULL, *tofree2 = NULL;
1203 int res;
1204 char_u numbuf1[NUMBUFLEN];
1205 char_u numbuf2[NUMBUFLEN];
1206
1207 si1 = (sortItem_T *)s1;
1208 si2 = (sortItem_T *)s2;
1209 tv1 = &si1->item->li_tv;
1210 tv2 = &si2->item->li_tv;
1211
1212 if (sortinfo->item_compare_numbers)
1213 {
1214 varnumber_T v1 = tv_get_number(tv1);
1215 varnumber_T v2 = tv_get_number(tv2);
1216
1217 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
1218 }
1219
1220 #ifdef FEAT_FLOAT
1221 if (sortinfo->item_compare_float)
1222 {
1223 float_T v1 = tv_get_float(tv1);
1224 float_T v2 = tv_get_float(tv2);
1225
1226 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
1227 }
1228 #endif
1229
1230 /* tv2string() puts quotes around a string and allocates memory. Don't do
1231 * that for string variables. Use a single quote when comparing with a
1232 * non-string to do what the docs promise. */
1233 if (tv1->v_type == VAR_STRING)
1234 {
1235 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
1236 p1 = (char_u *)"'";
1237 else
1238 p1 = tv1->vval.v_string;
1239 }
1240 else
1241 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
1242 if (tv2->v_type == VAR_STRING)
1243 {
1244 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
1245 p2 = (char_u *)"'";
1246 else
1247 p2 = tv2->vval.v_string;
1248 }
1249 else
1250 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
1251 if (p1 == NULL)
1252 p1 = (char_u *)"";
1253 if (p2 == NULL)
1254 p2 = (char_u *)"";
1255 if (!sortinfo->item_compare_numeric)
1256 {
1257 if (sortinfo->item_compare_ic)
1258 res = STRICMP(p1, p2);
1259 else
1260 res = STRCMP(p1, p2);
1261 }
1262 else
1263 {
1264 double n1, n2;
1265 n1 = strtod((char *)p1, (char **)&p1);
1266 n2 = strtod((char *)p2, (char **)&p2);
1267 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
1268 }
1269
1270 /* When the result would be zero, compare the item indexes. Makes the
1271 * sort stable. */
1272 if (res == 0 && !sortinfo->item_compare_keep_zero)
1273 res = si1->idx > si2->idx ? 1 : -1;
1274
1275 vim_free(tofree1);
1276 vim_free(tofree2);
1277 return res;
1278 }
1279
1280 static int
1281 item_compare2(const void *s1, const void *s2)
1282 {
1283 sortItem_T *si1, *si2;
1284 int res;
1285 typval_T rettv;
1286 typval_T argv[3];
1287 int dummy;
1288 char_u *func_name;
1289 partial_T *partial = sortinfo->item_compare_partial;
1290
1291 /* shortcut after failure in previous call; compare all items equal */
1292 if (sortinfo->item_compare_func_err)
1293 return 0;
1294
1295 si1 = (sortItem_T *)s1;
1296 si2 = (sortItem_T *)s2;
1297
1298 if (partial == NULL)
1299 func_name = sortinfo->item_compare_func;
1300 else
1301 func_name = partial_name(partial);
1302
1303 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
1304 * in the copy without changing the original list items. */
1305 copy_tv(&si1->item->li_tv, &argv[0]);
1306 copy_tv(&si2->item->li_tv, &argv[1]);
1307
1308 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
1309 res = call_func(func_name, -1, &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
1310 partial, sortinfo->item_compare_selfdict);
1311 clear_tv(&argv[0]);
1312 clear_tv(&argv[1]);
1313
1314 if (res == FAIL)
1315 res = ITEM_COMPARE_FAIL;
1316 else
1317 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
1318 if (sortinfo->item_compare_func_err)
1319 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
1320 clear_tv(&rettv);
1321
1322 /* When the result would be zero, compare the pointers themselves. Makes
1323 * the sort stable. */
1324 if (res == 0 && !sortinfo->item_compare_keep_zero)
1325 res = si1->idx > si2->idx ? 1 : -1;
1326
1327 return res;
1328 }
1329
1330 /*
1331 * "sort()" or "uniq()" function
1332 */
1333 static void
1334 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
1335 {
1336 list_T *l;
1337 listitem_T *li;
1338 sortItem_T *ptrs;
1339 sortinfo_T *old_sortinfo;
1340 sortinfo_T info;
1341 long len;
1342 long i;
1343
1344 /* Pointer to current info struct used in compare function. Save and
1345 * restore the current one for nested calls. */
1346 old_sortinfo = sortinfo;
1347 sortinfo = &info;
1348
1349 if (argvars[0].v_type != VAR_LIST)
1350 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
1351 else
1352 {
1353 l = argvars[0].vval.v_list;
1354 if (l == NULL || var_check_lock(l->lv_lock,
1355 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
1356 TRUE))
1357 goto theend;
1358 rettv_list_set(rettv, l);
1359
1360 len = list_len(l);
1361 if (len <= 1)
1362 goto theend; /* short list sorts pretty quickly */
1363
1364 info.item_compare_ic = FALSE;
1365 info.item_compare_numeric = FALSE;
1366 info.item_compare_numbers = FALSE;
1367 #ifdef FEAT_FLOAT
1368 info.item_compare_float = FALSE;
1369 #endif
1370 info.item_compare_func = NULL;
1371 info.item_compare_partial = NULL;
1372 info.item_compare_selfdict = NULL;
1373 if (argvars[1].v_type != VAR_UNKNOWN)
1374 {
1375 /* optional second argument: {func} */
1376 if (argvars[1].v_type == VAR_FUNC)
1377 info.item_compare_func = argvars[1].vval.v_string;
1378 else if (argvars[1].v_type == VAR_PARTIAL)
1379 info.item_compare_partial = argvars[1].vval.v_partial;
1380 else
1381 {
1382 int error = FALSE;
1383
1384 i = (long)tv_get_number_chk(&argvars[1], &error);
1385 if (error)
1386 goto theend; /* type error; errmsg already given */
1387 if (i == 1)
1388 info.item_compare_ic = TRUE;
1389 else if (argvars[1].v_type != VAR_NUMBER)
1390 info.item_compare_func = tv_get_string(&argvars[1]);
1391 else if (i != 0)
1392 {
1393 emsg(_(e_invarg));
1394 goto theend;
1395 }
1396 if (info.item_compare_func != NULL)
1397 {
1398 if (*info.item_compare_func == NUL)
1399 {
1400 /* empty string means default sort */
1401 info.item_compare_func = NULL;
1402 }
1403 else if (STRCMP(info.item_compare_func, "n") == 0)
1404 {
1405 info.item_compare_func = NULL;
1406 info.item_compare_numeric = TRUE;
1407 }
1408 else if (STRCMP(info.item_compare_func, "N") == 0)
1409 {
1410 info.item_compare_func = NULL;
1411 info.item_compare_numbers = TRUE;
1412 }
1413 #ifdef FEAT_FLOAT
1414 else if (STRCMP(info.item_compare_func, "f") == 0)
1415 {
1416 info.item_compare_func = NULL;
1417 info.item_compare_float = TRUE;
1418 }
1419 #endif
1420 else if (STRCMP(info.item_compare_func, "i") == 0)
1421 {
1422 info.item_compare_func = NULL;
1423 info.item_compare_ic = TRUE;
1424 }
1425 }
1426 }
1427
1428 if (argvars[2].v_type != VAR_UNKNOWN)
1429 {
1430 /* optional third argument: {dict} */
1431 if (argvars[2].v_type != VAR_DICT)
1432 {
1433 emsg(_(e_dictreq));
1434 goto theend;
1435 }
1436 info.item_compare_selfdict = argvars[2].vval.v_dict;
1437 }
1438 }
1439
1440 /* Make an array with each entry pointing to an item in the List. */
1441 ptrs = ALLOC_MULT(sortItem_T, len);
1442 if (ptrs == NULL)
1443 goto theend;
1444
1445 i = 0;
1446 if (sort)
1447 {
1448 /* sort(): ptrs will be the list to sort */
1449 for (li = l->lv_first; li != NULL; li = li->li_next)
1450 {
1451 ptrs[i].item = li;
1452 ptrs[i].idx = i;
1453 ++i;
1454 }
1455
1456 info.item_compare_func_err = FALSE;
1457 info.item_compare_keep_zero = FALSE;
1458 /* test the compare function */
1459 if ((info.item_compare_func != NULL
1460 || info.item_compare_partial != NULL)
1461 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
1462 == ITEM_COMPARE_FAIL)
1463 emsg(_("E702: Sort compare function failed"));
1464 else
1465 {
1466 /* Sort the array with item pointers. */
1467 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
1468 info.item_compare_func == NULL
1469 && info.item_compare_partial == NULL
1470 ? item_compare : item_compare2);
1471
1472 if (!info.item_compare_func_err)
1473 {
1474 /* Clear the List and append the items in sorted order. */
1475 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
1476 l->lv_len = 0;
1477 for (i = 0; i < len; ++i)
1478 list_append(l, ptrs[i].item);
1479 }
1480 }
1481 }
1482 else
1483 {
1484 int (*item_compare_func_ptr)(const void *, const void *);
1485
1486 /* f_uniq(): ptrs will be a stack of items to remove */
1487 info.item_compare_func_err = FALSE;
1488 info.item_compare_keep_zero = TRUE;
1489 item_compare_func_ptr = info.item_compare_func != NULL
1490 || info.item_compare_partial != NULL
1491 ? item_compare2 : item_compare;
1492
1493 for (li = l->lv_first; li != NULL && li->li_next != NULL;
1494 li = li->li_next)
1495 {
1496 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
1497 == 0)
1498 ptrs[i++].item = li;
1499 if (info.item_compare_func_err)
1500 {
1501 emsg(_("E882: Uniq compare function failed"));
1502 break;
1503 }
1504 }
1505
1506 if (!info.item_compare_func_err)
1507 {
1508 while (--i >= 0)
1509 {
1510 li = ptrs[i].item->li_next;
1511 ptrs[i].item->li_next = li->li_next;
1512 if (li->li_next != NULL)
1513 li->li_next->li_prev = ptrs[i].item;
1514 else
1515 l->lv_last = ptrs[i].item;
1516 list_fix_watch(l, li);
1517 listitem_free(li);
1518 l->lv_len--;
1519 }
1520 }
1521 }
1522
1523 vim_free(ptrs);
1524 }
1525 theend:
1526 sortinfo = old_sortinfo;
1527 }
1528
1529 /*
1530 * "sort({list})" function
1531 */
1532 void
1533 f_sort(typval_T *argvars, typval_T *rettv)
1534 {
1535 do_sort_uniq(argvars, rettv, TRUE);
1536 }
1537
1538 /*
1539 * "uniq({list})" function
1540 */
1541 void
1542 f_uniq(typval_T *argvars, typval_T *rettv)
1543 {
1544 do_sort_uniq(argvars, rettv, FALSE);
1545 }
1546
1010 #endif /* defined(FEAT_EVAL) */ 1547 #endif /* defined(FEAT_EVAL) */