comparison src/typval.c @ 26644:2fc1e528e0e1 v8.2.3851

patch 8.2.3851: Vim9: overhead when comparing string, dict or function Commit: https://github.com/vim/vim/commit/265f811f5a2dac81d9698f5202a661a04ed095f1 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Dec 19 12:33:05 2021 +0000 patch 8.2.3851: Vim9: overhead when comparing string, dict or function Problem: Vim9: overhead when comparing string, dict or function. Solution: Call the intented compare function directly. Refactor to avoid duplicated code.
author Bram Moolenaar <Bram@vim.org>
date Sun, 19 Dec 2021 13:45:03 +0100
parents 6fd15d82e898
children 1cee572f2fd7
comparison
equal deleted inserted replaced
26643:c1613719988c 26644:2fc1e528e0e1
1118 break; 1118 break;
1119 } 1119 }
1120 } 1120 }
1121 1121
1122 /* 1122 /*
1123 * Compare "typ1" and "typ2". Put the result in "typ1". 1123 * Compare "tv1" and "tv2".
1124 * Put the result in "tv1". Caller should clear "tv2".
1124 */ 1125 */
1125 int 1126 int
1126 typval_compare( 1127 typval_compare(
1127 typval_T *typ1, // first operand 1128 typval_T *tv1, // first operand
1128 typval_T *typ2, // second operand 1129 typval_T *tv2, // second operand
1129 exprtype_T type, // operator 1130 exprtype_T type, // operator
1130 int ic) // ignore case 1131 int ic) // ignore case
1131 { 1132 {
1132 int i;
1133 varnumber_T n1, n2; 1133 varnumber_T n1, n2;
1134 char_u *s1, *s2; 1134 int res = 0;
1135 char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
1136 int type_is = type == EXPR_IS || type == EXPR_ISNOT; 1135 int type_is = type == EXPR_IS || type == EXPR_ISNOT;
1137 1136
1138 if (type_is && typ1->v_type != typ2->v_type) 1137 if (type_is && tv1->v_type != tv2->v_type)
1139 { 1138 {
1140 // For "is" a different type always means FALSE, for "notis" 1139 // For "is" a different type always means FALSE, for "notis"
1141 // it means TRUE. 1140 // it means TRUE.
1142 n1 = (type == EXPR_ISNOT); 1141 n1 = (type == EXPR_ISNOT);
1143 } 1142 }
1144 else if (typ1->v_type == VAR_BLOB || typ2->v_type == VAR_BLOB) 1143 else if (tv1->v_type == VAR_BLOB || tv2->v_type == VAR_BLOB)
1145 { 1144 {
1146 if (type_is) 1145 if (typval_compare_blob(tv1, tv2, type, &res) == FAIL)
1147 { 1146 {
1148 n1 = (typ1->v_type == typ2->v_type 1147 clear_tv(tv1);
1149 && typ1->vval.v_blob == typ2->vval.v_blob);
1150 if (type == EXPR_ISNOT)
1151 n1 = !n1;
1152 }
1153 else if (typ1->v_type != typ2->v_type
1154 || (type != EXPR_EQUAL && type != EXPR_NEQUAL))
1155 {
1156 if (typ1->v_type != typ2->v_type)
1157 emsg(_("E977: Can only compare Blob with Blob"));
1158 else
1159 emsg(_(e_invalblob));
1160 clear_tv(typ1);
1161 return FAIL; 1148 return FAIL;
1162 } 1149 }
1163 else 1150 n1 = res;
1164 { 1151 }
1165 // Compare two Blobs for being equal or unequal. 1152 else if (tv1->v_type == VAR_LIST || tv2->v_type == VAR_LIST)
1166 n1 = blob_equal(typ1->vval.v_blob, typ2->vval.v_blob); 1153 {
1167 if (type == EXPR_NEQUAL) 1154 if (typval_compare_list(tv1, tv2, type, ic, &res) == FAIL)
1168 n1 = !n1; 1155 {
1169 } 1156 clear_tv(tv1);
1170 }
1171 else if (typ1->v_type == VAR_LIST || typ2->v_type == VAR_LIST)
1172 {
1173 if (type_is)
1174 {
1175 n1 = (typ1->v_type == typ2->v_type
1176 && typ1->vval.v_list == typ2->vval.v_list);
1177 if (type == EXPR_ISNOT)
1178 n1 = !n1;
1179 }
1180 else if (typ1->v_type != typ2->v_type
1181 || (type != EXPR_EQUAL && type != EXPR_NEQUAL))
1182 {
1183 if (typ1->v_type != typ2->v_type)
1184 emsg(_("E691: Can only compare List with List"));
1185 else
1186 emsg(_("E692: Invalid operation for List"));
1187 clear_tv(typ1);
1188 return FAIL; 1157 return FAIL;
1189 } 1158 }
1190 else 1159 n1 = res;
1191 { 1160 }
1192 // Compare two Lists for being equal or unequal. 1161 else if (tv1->v_type == VAR_DICT || tv2->v_type == VAR_DICT)
1193 n1 = list_equal(typ1->vval.v_list, typ2->vval.v_list, 1162 {
1194 ic, FALSE); 1163 if (typval_compare_dict(tv1, tv2, type, ic, &res) == FAIL)
1195 if (type == EXPR_NEQUAL) 1164 {
1196 n1 = !n1; 1165 clear_tv(tv1);
1197 }
1198 }
1199
1200 else if (typ1->v_type == VAR_DICT || typ2->v_type == VAR_DICT)
1201 {
1202 if (type_is)
1203 {
1204 n1 = (typ1->v_type == typ2->v_type
1205 && typ1->vval.v_dict == typ2->vval.v_dict);
1206 if (type == EXPR_ISNOT)
1207 n1 = !n1;
1208 }
1209 else if (typ1->v_type != typ2->v_type
1210 || (type != EXPR_EQUAL && type != EXPR_NEQUAL))
1211 {
1212 if (typ1->v_type != typ2->v_type)
1213 emsg(_("E735: Can only compare Dictionary with Dictionary"));
1214 else
1215 emsg(_("E736: Invalid operation for Dictionary"));
1216 clear_tv(typ1);
1217 return FAIL; 1166 return FAIL;
1218 } 1167 }
1219 else 1168 n1 = res;
1220 { 1169 }
1221 // Compare two Dictionaries for being equal or unequal. 1170 else if (tv1->v_type == VAR_FUNC || tv2->v_type == VAR_FUNC
1222 n1 = dict_equal(typ1->vval.v_dict, typ2->vval.v_dict, 1171 || tv1->v_type == VAR_PARTIAL || tv2->v_type == VAR_PARTIAL)
1223 ic, FALSE); 1172 {
1224 if (type == EXPR_NEQUAL) 1173 if (typval_compare_func(tv1, tv2, type, ic, &res) == FAIL)
1225 n1 = !n1; 1174 {
1226 } 1175 clear_tv(tv1);
1227 }
1228
1229 else if (typ1->v_type == VAR_FUNC || typ2->v_type == VAR_FUNC
1230 || typ1->v_type == VAR_PARTIAL || typ2->v_type == VAR_PARTIAL)
1231 {
1232 if (type != EXPR_EQUAL && type != EXPR_NEQUAL
1233 && type != EXPR_IS && type != EXPR_ISNOT)
1234 {
1235 emsg(_("E694: Invalid operation for Funcrefs"));
1236 clear_tv(typ1);
1237 return FAIL; 1176 return FAIL;
1238 } 1177 }
1239 if ((typ1->v_type == VAR_PARTIAL 1178 n1 = res;
1240 && typ1->vval.v_partial == NULL)
1241 || (typ2->v_type == VAR_PARTIAL
1242 && typ2->vval.v_partial == NULL))
1243 // When both partials are NULL, then they are equal.
1244 // Otherwise they are not equal.
1245 n1 = (typ1->vval.v_partial == typ2->vval.v_partial);
1246 else if (type_is)
1247 {
1248 if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC)
1249 // strings are considered the same if their value is
1250 // the same
1251 n1 = tv_equal(typ1, typ2, ic, FALSE);
1252 else if (typ1->v_type == VAR_PARTIAL
1253 && typ2->v_type == VAR_PARTIAL)
1254 n1 = (typ1->vval.v_partial == typ2->vval.v_partial);
1255 else
1256 n1 = FALSE;
1257 }
1258 else
1259 n1 = tv_equal(typ1, typ2, ic, FALSE);
1260 if (type == EXPR_NEQUAL || type == EXPR_ISNOT)
1261 n1 = !n1;
1262 } 1179 }
1263 1180
1264 #ifdef FEAT_FLOAT 1181 #ifdef FEAT_FLOAT
1265 // If one of the two variables is a float, compare as a float. 1182 // If one of the two variables is a float, compare as a float.
1266 // When using "=~" or "!~", always compare as string. 1183 // When using "=~" or "!~", always compare as string.
1267 else if ((typ1->v_type == VAR_FLOAT || typ2->v_type == VAR_FLOAT) 1184 else if ((tv1->v_type == VAR_FLOAT || tv2->v_type == VAR_FLOAT)
1268 && type != EXPR_MATCH && type != EXPR_NOMATCH) 1185 && type != EXPR_MATCH && type != EXPR_NOMATCH)
1269 { 1186 {
1270 float_T f1, f2; 1187 float_T f1, f2;
1271 1188
1272 f1 = tv_get_float(typ1); 1189 f1 = tv_get_float(tv1);
1273 f2 = tv_get_float(typ2); 1190 f2 = tv_get_float(tv2);
1274 n1 = FALSE; 1191 n1 = FALSE;
1275 switch (type) 1192 switch (type)
1276 { 1193 {
1277 case EXPR_IS: 1194 case EXPR_IS:
1278 case EXPR_EQUAL: n1 = (f1 == f2); break; 1195 case EXPR_EQUAL: n1 = (f1 == f2); break;
1289 } 1206 }
1290 #endif 1207 #endif
1291 1208
1292 // If one of the two variables is a number, compare as a number. 1209 // If one of the two variables is a number, compare as a number.
1293 // When using "=~" or "!~", always compare as string. 1210 // When using "=~" or "!~", always compare as string.
1294 else if ((typ1->v_type == VAR_NUMBER || typ2->v_type == VAR_NUMBER) 1211 else if ((tv1->v_type == VAR_NUMBER || tv2->v_type == VAR_NUMBER)
1295 && type != EXPR_MATCH && type != EXPR_NOMATCH) 1212 && type != EXPR_MATCH && type != EXPR_NOMATCH)
1296 { 1213 {
1297 n1 = tv_get_number(typ1); 1214 n1 = tv_get_number(tv1);
1298 n2 = tv_get_number(typ2); 1215 n2 = tv_get_number(tv2);
1299 switch (type) 1216 switch (type)
1300 { 1217 {
1301 case EXPR_IS: 1218 case EXPR_IS:
1302 case EXPR_EQUAL: n1 = (n1 == n2); break; 1219 case EXPR_EQUAL: n1 = (n1 == n2); break;
1303 case EXPR_ISNOT: 1220 case EXPR_ISNOT:
1309 case EXPR_UNKNOWN: 1226 case EXPR_UNKNOWN:
1310 case EXPR_MATCH: 1227 case EXPR_MATCH:
1311 default: break; // avoid gcc warning 1228 default: break; // avoid gcc warning
1312 } 1229 }
1313 } 1230 }
1314 else if (in_vim9script() && (typ1->v_type == VAR_BOOL 1231 else if (in_vim9script() && (tv1->v_type == VAR_BOOL
1315 || typ2->v_type == VAR_BOOL 1232 || tv2->v_type == VAR_BOOL
1316 || (typ1->v_type == VAR_SPECIAL 1233 || (tv1->v_type == VAR_SPECIAL
1317 && typ2->v_type == VAR_SPECIAL))) 1234 && tv2->v_type == VAR_SPECIAL)))
1318 { 1235 {
1319 if (typ1->v_type != typ2->v_type) 1236 if (tv1->v_type != tv2->v_type)
1320 { 1237 {
1321 semsg(_(e_cannot_compare_str_with_str), 1238 semsg(_(e_cannot_compare_str_with_str),
1322 vartype_name(typ1->v_type), vartype_name(typ2->v_type)); 1239 vartype_name(tv1->v_type), vartype_name(tv2->v_type));
1323 clear_tv(typ1); 1240 clear_tv(tv1);
1324 return FAIL; 1241 return FAIL;
1325 } 1242 }
1326 n1 = typ1->vval.v_number; 1243 n1 = tv1->vval.v_number;
1327 n2 = typ2->vval.v_number; 1244 n2 = tv2->vval.v_number;
1328 switch (type) 1245 switch (type)
1329 { 1246 {
1330 case EXPR_IS: 1247 case EXPR_IS:
1331 case EXPR_EQUAL: n1 = (n1 == n2); break; 1248 case EXPR_EQUAL: n1 = (n1 == n2); break;
1332 case EXPR_ISNOT: 1249 case EXPR_ISNOT:
1333 case EXPR_NEQUAL: n1 = (n1 != n2); break; 1250 case EXPR_NEQUAL: n1 = (n1 != n2); break;
1334 default: 1251 default:
1335 semsg(_(e_invalid_operation_for_str), 1252 semsg(_(e_invalid_operation_for_str),
1336 vartype_name(typ1->v_type)); 1253 vartype_name(tv1->v_type));
1337 clear_tv(typ1); 1254 clear_tv(tv1);
1338 return FAIL; 1255 return FAIL;
1339 } 1256 }
1340 } 1257 }
1341 else 1258 else
1342 { 1259 {
1343 if (in_vim9script() 1260 if (typval_compare_string(tv1, tv2, type, ic, &res) == FAIL)
1344 && ((typ1->v_type != VAR_STRING && typ1->v_type != VAR_SPECIAL) 1261 {
1345 || (typ2->v_type != VAR_STRING && typ2->v_type != VAR_SPECIAL))) 1262 clear_tv(tv1);
1346 {
1347 semsg(_(e_cannot_compare_str_with_str),
1348 vartype_name(typ1->v_type), vartype_name(typ2->v_type));
1349 clear_tv(typ1);
1350 return FAIL; 1263 return FAIL;
1351 } 1264 }
1352 s1 = tv_get_string_buf(typ1, buf1); 1265 n1 = res;
1353 s2 = tv_get_string_buf(typ2, buf2); 1266 }
1354 if (type != EXPR_MATCH && type != EXPR_NOMATCH) 1267 clear_tv(tv1);
1355 i = ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2); 1268 if (in_vim9script())
1269 {
1270 tv1->v_type = VAR_BOOL;
1271 tv1->vval.v_number = n1 ? VVAL_TRUE : VVAL_FALSE;
1272 }
1273 else
1274 {
1275 tv1->v_type = VAR_NUMBER;
1276 tv1->vval.v_number = n1;
1277 }
1278
1279 return OK;
1280 }
1281
1282 /*
1283 * Compare "tv1" to "tv2" as lists acording to "type" and "ic".
1284 * Put the result, false or true, in "res".
1285 * Return FAIL and give an error message when the comparison can't be done.
1286 */
1287 int
1288 typval_compare_list(
1289 typval_T *tv1,
1290 typval_T *tv2,
1291 exprtype_T type,
1292 int ic,
1293 int *res)
1294 {
1295 int val = 0;
1296
1297 if (type == EXPR_IS || type == EXPR_ISNOT)
1298 {
1299 val = (tv1->v_type == tv2->v_type
1300 && tv1->vval.v_list == tv2->vval.v_list);
1301 if (type == EXPR_ISNOT)
1302 val = !val;
1303 }
1304 else if (tv1->v_type != tv2->v_type
1305 || (type != EXPR_EQUAL && type != EXPR_NEQUAL))
1306 {
1307 if (tv1->v_type != tv2->v_type)
1308 emsg(_("E691: Can only compare List with List"));
1356 else 1309 else
1357 i = 0; 1310 emsg(_("E692: Invalid operation for List"));
1358 n1 = FALSE; 1311 return FAIL;
1359 switch (type)
1360 {
1361 case EXPR_IS:
1362 case EXPR_EQUAL: n1 = (i == 0); break;
1363 case EXPR_ISNOT:
1364 case EXPR_NEQUAL: n1 = (i != 0); break;
1365 case EXPR_GREATER: n1 = (i > 0); break;
1366 case EXPR_GEQUAL: n1 = (i >= 0); break;
1367 case EXPR_SMALLER: n1 = (i < 0); break;
1368 case EXPR_SEQUAL: n1 = (i <= 0); break;
1369
1370 case EXPR_MATCH:
1371 case EXPR_NOMATCH:
1372 n1 = pattern_match(s2, s1, ic);
1373 if (type == EXPR_NOMATCH)
1374 n1 = !n1;
1375 break;
1376
1377 default: break; // avoid gcc warning
1378 }
1379 }
1380 clear_tv(typ1);
1381 if (in_vim9script())
1382 {
1383 typ1->v_type = VAR_BOOL;
1384 typ1->vval.v_number = n1 ? VVAL_TRUE : VVAL_FALSE;
1385 } 1312 }
1386 else 1313 else
1387 { 1314 {
1388 typ1->v_type = VAR_NUMBER; 1315 val = list_equal(tv1->vval.v_list, tv2->vval.v_list,
1389 typ1->vval.v_number = n1; 1316 ic, FALSE);
1390 } 1317 if (type == EXPR_NEQUAL)
1391 1318 val = !val;
1392 return OK; 1319 }
1393 } 1320 *res = val;
1394 1321 return OK;
1322 }
1323
1324 /*
1325 * Compare "tv1" to "tv2" as blobs acording to "type".
1326 * Put the result, false or true, in "res".
1327 * Return FAIL and give an error message when the comparison can't be done.
1328 */
1329 int
1330 typval_compare_blob(
1331 typval_T *tv1,
1332 typval_T *tv2,
1333 exprtype_T type,
1334 int *res)
1335 {
1336 int val = 0;
1337
1338 if (type == EXPR_IS || type == EXPR_ISNOT)
1339 {
1340 val = (tv1->v_type == tv2->v_type
1341 && tv1->vval.v_blob == tv2->vval.v_blob);
1342 if (type == EXPR_ISNOT)
1343 val = !val;
1344 }
1345 else if (tv1->v_type != tv2->v_type
1346 || (type != EXPR_EQUAL && type != EXPR_NEQUAL))
1347 {
1348 if (tv1->v_type != tv2->v_type)
1349 emsg(_("E977: Can only compare Blob with Blob"));
1350 else
1351 emsg(_(e_invalblob));
1352 return FAIL;
1353 }
1354 else
1355 {
1356 val = blob_equal(tv1->vval.v_blob, tv2->vval.v_blob);
1357 if (type == EXPR_NEQUAL)
1358 val = !val;
1359 }
1360 *res = val;
1361 return OK;
1362 }
1363
1364 /*
1365 * Compare "tv1" to "tv2" as dictionaries acording to "type" and "ic".
1366 * Put the result, false or true, in "res".
1367 * Return FAIL and give an error message when the comparison can't be done.
1368 */
1369 int
1370 typval_compare_dict(
1371 typval_T *tv1,
1372 typval_T *tv2,
1373 exprtype_T type,
1374 int ic,
1375 int *res)
1376 {
1377 int val;
1378
1379 if (type == EXPR_IS || type == EXPR_ISNOT)
1380 {
1381 val = (tv1->v_type == tv2->v_type
1382 && tv1->vval.v_dict == tv2->vval.v_dict);
1383 if (type == EXPR_ISNOT)
1384 val = !val;
1385 }
1386 else if (tv1->v_type != tv2->v_type
1387 || (type != EXPR_EQUAL && type != EXPR_NEQUAL))
1388 {
1389 if (tv1->v_type != tv2->v_type)
1390 emsg(_("E735: Can only compare Dictionary with Dictionary"));
1391 else
1392 emsg(_("E736: Invalid operation for Dictionary"));
1393 return FAIL;
1394 }
1395 else
1396 {
1397 val = dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic, FALSE);
1398 if (type == EXPR_NEQUAL)
1399 val = !val;
1400 }
1401 *res = val;
1402 return OK;
1403 }
1404
1405 /*
1406 * Compare "tv1" to "tv2" as funcrefs acording to "type" and "ic".
1407 * Put the result, false or true, in "res".
1408 * Return FAIL and give an error message when the comparison can't be done.
1409 */
1410 int
1411 typval_compare_func(
1412 typval_T *tv1,
1413 typval_T *tv2,
1414 exprtype_T type,
1415 int ic,
1416 int *res)
1417 {
1418 int val = 0;
1419
1420 if (type != EXPR_EQUAL && type != EXPR_NEQUAL
1421 && type != EXPR_IS && type != EXPR_ISNOT)
1422 {
1423 emsg(_("E694: Invalid operation for Funcrefs"));
1424 return FAIL;
1425 }
1426 if ((tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial == NULL)
1427 || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial == NULL))
1428 // When both partials are NULL, then they are equal.
1429 // Otherwise they are not equal.
1430 val = (tv1->vval.v_partial == tv2->vval.v_partial);
1431 else if (type == EXPR_IS || type == EXPR_ISNOT)
1432 {
1433 if (tv1->v_type == VAR_FUNC && tv2->v_type == VAR_FUNC)
1434 // strings are considered the same if their value is
1435 // the same
1436 val = tv_equal(tv1, tv2, ic, FALSE);
1437 else if (tv1->v_type == VAR_PARTIAL && tv2->v_type == VAR_PARTIAL)
1438 val = (tv1->vval.v_partial == tv2->vval.v_partial);
1439 else
1440 val = FALSE;
1441 }
1442 else
1443 val = tv_equal(tv1, tv2, ic, FALSE);
1444 if (type == EXPR_NEQUAL || type == EXPR_ISNOT)
1445 val = !val;
1446 *res = val;
1447 return OK;
1448 }
1449
1450 /*
1451 * Compare "tv1" to "tv2" as strings according to "type" and "ic".
1452 * Put the result, false or true, in "res".
1453 * Return FAIL and give an error message when the comparison can't be done.
1454 */
1455 int
1456 typval_compare_string(
1457 typval_T *tv1,
1458 typval_T *tv2,
1459 exprtype_T type,
1460 int ic,
1461 int *res)
1462 {
1463 int i = 0;
1464 int val = FALSE;
1465 char_u *s1, *s2;
1466 char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
1467
1468 if (in_vim9script()
1469 && ((tv1->v_type != VAR_STRING && tv1->v_type != VAR_SPECIAL)
1470 || (tv2->v_type != VAR_STRING && tv2->v_type != VAR_SPECIAL)))
1471 {
1472 semsg(_(e_cannot_compare_str_with_str),
1473 vartype_name(tv1->v_type), vartype_name(tv2->v_type));
1474 return FAIL;
1475 }
1476 s1 = tv_get_string_buf(tv1, buf1);
1477 s2 = tv_get_string_buf(tv2, buf2);
1478 if (type != EXPR_MATCH && type != EXPR_NOMATCH)
1479 i = ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2);
1480 switch (type)
1481 {
1482 case EXPR_IS:
1483 case EXPR_EQUAL: val = (i == 0); break;
1484 case EXPR_ISNOT:
1485 case EXPR_NEQUAL: val = (i != 0); break;
1486 case EXPR_GREATER: val = (i > 0); break;
1487 case EXPR_GEQUAL: val = (i >= 0); break;
1488 case EXPR_SMALLER: val = (i < 0); break;
1489 case EXPR_SEQUAL: val = (i <= 0); break;
1490
1491 case EXPR_MATCH:
1492 case EXPR_NOMATCH:
1493 val = pattern_match(s2, s1, ic);
1494 if (type == EXPR_NOMATCH)
1495 val = !val;
1496 break;
1497
1498 default: break; // avoid gcc warning
1499 }
1500 *res = val;
1501 return OK;
1502 }
1395 /* 1503 /*
1396 * Convert any type to a string, never give an error. 1504 * Convert any type to a string, never give an error.
1397 * When "quotes" is TRUE add quotes to a string. 1505 * When "quotes" is TRUE add quotes to a string.
1398 * Returns an allocated string. 1506 * Returns an allocated string.
1399 */ 1507 */