Show More
@@ -1163,6 +1163,366 b' static int index_contains(indexObject *s' | |||||
1163 | } |
|
1163 | } | |
1164 | } |
|
1164 | } | |
1165 |
|
1165 | |||
|
1166 | static inline void index_get_parents(indexObject *self, int rev, int *ps) | |||
|
1167 | { | |||
|
1168 | if (rev >= self->length - 1) { | |||
|
1169 | PyObject *tuple = PyList_GET_ITEM(self->added, | |||
|
1170 | rev - self->length + 1); | |||
|
1171 | ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5)); | |||
|
1172 | ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6)); | |||
|
1173 | } else { | |||
|
1174 | const char *data = index_deref(self, rev); | |||
|
1175 | ps[0] = getbe32(data + 24); | |||
|
1176 | ps[1] = getbe32(data + 28); | |||
|
1177 | } | |||
|
1178 | } | |||
|
1179 | ||||
|
1180 | typedef uint64_t bitmask; | |||
|
1181 | ||||
|
1182 | /* | |||
|
1183 | * Given a disjoint set of revs, return all candidates for the | |||
|
1184 | * greatest common ancestor. In revset notation, this is the set | |||
|
1185 | * "heads(::a and ::b and ...)" | |||
|
1186 | */ | |||
|
1187 | static PyObject *find_gca_candidates(indexObject *self, const int *revs, | |||
|
1188 | int revcount) | |||
|
1189 | { | |||
|
1190 | const bitmask allseen = (1ull << revcount) - 1; | |||
|
1191 | const bitmask poison = 1ull << revcount; | |||
|
1192 | PyObject *gca = PyList_New(0); | |||
|
1193 | int i, v, interesting, left; | |||
|
1194 | int maxrev = -1; | |||
|
1195 | bitmask *seen; | |||
|
1196 | ||||
|
1197 | for (i = 0; i < revcount; i++) { | |||
|
1198 | if (revs[i] > maxrev) | |||
|
1199 | maxrev = revs[i]; | |||
|
1200 | } | |||
|
1201 | ||||
|
1202 | seen = calloc(sizeof(*seen), maxrev + 1); | |||
|
1203 | if (seen == NULL) | |||
|
1204 | return PyErr_NoMemory(); | |||
|
1205 | ||||
|
1206 | for (i = 0; i < revcount; i++) | |||
|
1207 | seen[revs[i]] = 1ull << i; | |||
|
1208 | ||||
|
1209 | interesting = left = revcount; | |||
|
1210 | ||||
|
1211 | for (v = maxrev; v >= 0 && interesting; v--) { | |||
|
1212 | long sv = seen[v]; | |||
|
1213 | int parents[2]; | |||
|
1214 | ||||
|
1215 | if (!sv) | |||
|
1216 | continue; | |||
|
1217 | ||||
|
1218 | if (sv < poison) { | |||
|
1219 | interesting -= 1; | |||
|
1220 | if (sv == allseen) { | |||
|
1221 | PyObject *obj = PyInt_FromLong(v); | |||
|
1222 | if (obj == NULL) | |||
|
1223 | goto bail; | |||
|
1224 | if (PyList_Append(gca, obj) == -1) { | |||
|
1225 | Py_DECREF(obj); | |||
|
1226 | goto bail; | |||
|
1227 | } | |||
|
1228 | sv |= poison; | |||
|
1229 | for (i = 0; i < revcount; i++) { | |||
|
1230 | if (revs[i] == v) { | |||
|
1231 | if (--left <= 1) | |||
|
1232 | goto done; | |||
|
1233 | break; | |||
|
1234 | } | |||
|
1235 | } | |||
|
1236 | } | |||
|
1237 | } | |||
|
1238 | index_get_parents(self, v, parents); | |||
|
1239 | ||||
|
1240 | for (i = 0; i < 2; i++) { | |||
|
1241 | int p = parents[i]; | |||
|
1242 | if (p == -1) | |||
|
1243 | continue; | |||
|
1244 | const long sp = seen[p]; | |||
|
1245 | if (sv < poison) { | |||
|
1246 | if (sp == 0) { | |||
|
1247 | seen[p] = sv; | |||
|
1248 | interesting++; | |||
|
1249 | } | |||
|
1250 | else if (sp != sv) | |||
|
1251 | seen[p] |= sv; | |||
|
1252 | } else { | |||
|
1253 | if (sp && sp < poison) | |||
|
1254 | interesting--; | |||
|
1255 | seen[p] = sv; | |||
|
1256 | } | |||
|
1257 | } | |||
|
1258 | } | |||
|
1259 | ||||
|
1260 | done: | |||
|
1261 | free(seen); | |||
|
1262 | return gca; | |||
|
1263 | bail: | |||
|
1264 | free(seen); | |||
|
1265 | Py_XDECREF(gca); | |||
|
1266 | return NULL; | |||
|
1267 | } | |||
|
1268 | ||||
|
1269 | /* | |||
|
1270 | * Given a disjoint set of revs, return the subset with the longest | |||
|
1271 | * path to the root. | |||
|
1272 | */ | |||
|
1273 | static PyObject *find_deepest(indexObject *self, PyObject *revs) | |||
|
1274 | { | |||
|
1275 | const Py_ssize_t revcount = PyList_GET_SIZE(revs); | |||
|
1276 | static const Py_ssize_t capacity = 24; | |||
|
1277 | int *depth, *interesting = NULL; | |||
|
1278 | int i, j, v, ninteresting; | |||
|
1279 | PyObject *dict = NULL, *keys; | |||
|
1280 | long *seen = NULL; | |||
|
1281 | int maxrev = -1; | |||
|
1282 | long final; | |||
|
1283 | ||||
|
1284 | if (revcount > capacity) { | |||
|
1285 | PyErr_Format(PyExc_OverflowError, | |||
|
1286 | "bitset size (%ld) > capacity (%ld)", | |||
|
1287 | revcount, capacity); | |||
|
1288 | return NULL; | |||
|
1289 | } | |||
|
1290 | ||||
|
1291 | for (i = 0; i < revcount; i++) { | |||
|
1292 | int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i)); | |||
|
1293 | if (n > maxrev) | |||
|
1294 | maxrev = n; | |||
|
1295 | } | |||
|
1296 | ||||
|
1297 | depth = calloc(sizeof(*depth), maxrev + 1); | |||
|
1298 | if (depth == NULL) | |||
|
1299 | return PyErr_NoMemory(); | |||
|
1300 | ||||
|
1301 | seen = calloc(sizeof(*seen), maxrev + 1); | |||
|
1302 | if (seen == NULL) { | |||
|
1303 | PyErr_NoMemory(); | |||
|
1304 | goto bail; | |||
|
1305 | } | |||
|
1306 | ||||
|
1307 | interesting = calloc(sizeof(*interesting), 2 << revcount); | |||
|
1308 | if (interesting == NULL) { | |||
|
1309 | PyErr_NoMemory(); | |||
|
1310 | goto bail; | |||
|
1311 | } | |||
|
1312 | ||||
|
1313 | for (i = 0; i < revcount; i++) { | |||
|
1314 | int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i)); | |||
|
1315 | long b = 1l << i; | |||
|
1316 | depth[n] = 1; | |||
|
1317 | seen[n] = b; | |||
|
1318 | interesting[b] = 1; | |||
|
1319 | } | |||
|
1320 | ||||
|
1321 | ninteresting = (int)revcount; | |||
|
1322 | ||||
|
1323 | for (v = maxrev; v >= 0 && ninteresting > 1; v--) { | |||
|
1324 | int dv = depth[v]; | |||
|
1325 | int parents[2]; | |||
|
1326 | long sv; | |||
|
1327 | ||||
|
1328 | if (dv == 0) | |||
|
1329 | continue; | |||
|
1330 | ||||
|
1331 | sv = seen[v]; | |||
|
1332 | index_get_parents(self, v, parents); | |||
|
1333 | ||||
|
1334 | for (i = 0; i < 2; i++) { | |||
|
1335 | int p = parents[i]; | |||
|
1336 | long nsp, sp; | |||
|
1337 | int dp; | |||
|
1338 | ||||
|
1339 | if (p == -1) | |||
|
1340 | continue; | |||
|
1341 | ||||
|
1342 | dp = depth[p]; | |||
|
1343 | nsp = sp = seen[p]; | |||
|
1344 | if (dp <= dv) { | |||
|
1345 | depth[p] = dv + 1; | |||
|
1346 | if (sp != sv) { | |||
|
1347 | interesting[sv] += 1; | |||
|
1348 | nsp = seen[p] = sv; | |||
|
1349 | if (sp) { | |||
|
1350 | interesting[sp] -= 1; | |||
|
1351 | if (interesting[sp] == 0) | |||
|
1352 | ninteresting -= 1; | |||
|
1353 | } | |||
|
1354 | } | |||
|
1355 | } | |||
|
1356 | else if (dv == dp - 1) { | |||
|
1357 | nsp = sp | sv; | |||
|
1358 | if (nsp == sp) | |||
|
1359 | continue; | |||
|
1360 | seen[p] = nsp; | |||
|
1361 | interesting[nsp] += 1; | |||
|
1362 | interesting[sp] -= 1; | |||
|
1363 | if (interesting[sp] == 0) | |||
|
1364 | ninteresting -= 1; | |||
|
1365 | } | |||
|
1366 | } | |||
|
1367 | interesting[sv] -= 1; | |||
|
1368 | if (interesting[sv] == 0) | |||
|
1369 | ninteresting -= 1; | |||
|
1370 | } | |||
|
1371 | ||||
|
1372 | final = 0; | |||
|
1373 | j = ninteresting; | |||
|
1374 | for (i = 0; i < (int)(2 << revcount) && j > 0; i++) { | |||
|
1375 | if (interesting[i] == 0) | |||
|
1376 | continue; | |||
|
1377 | final |= i; | |||
|
1378 | j -= 1; | |||
|
1379 | } | |||
|
1380 | if (final == 0) | |||
|
1381 | return PyList_New(0); | |||
|
1382 | ||||
|
1383 | dict = PyDict_New(); | |||
|
1384 | if (dict == NULL) | |||
|
1385 | goto bail; | |||
|
1386 | ||||
|
1387 | j = ninteresting; | |||
|
1388 | for (i = 0; i < revcount && j > 0; i++) { | |||
|
1389 | PyObject *key; | |||
|
1390 | ||||
|
1391 | if ((final & (1 << i)) == 0) | |||
|
1392 | continue; | |||
|
1393 | ||||
|
1394 | key = PyList_GET_ITEM(revs, i); | |||
|
1395 | Py_INCREF(key); | |||
|
1396 | Py_INCREF(Py_None); | |||
|
1397 | if (PyDict_SetItem(dict, key, Py_None) == -1) { | |||
|
1398 | Py_DECREF(key); | |||
|
1399 | Py_DECREF(Py_None); | |||
|
1400 | goto bail; | |||
|
1401 | } | |||
|
1402 | j -= 1; | |||
|
1403 | } | |||
|
1404 | ||||
|
1405 | keys = PyDict_Keys(dict); | |||
|
1406 | ||||
|
1407 | free(depth); | |||
|
1408 | free(seen); | |||
|
1409 | free(interesting); | |||
|
1410 | Py_DECREF(dict); | |||
|
1411 | ||||
|
1412 | return keys; | |||
|
1413 | bail: | |||
|
1414 | free(depth); | |||
|
1415 | free(seen); | |||
|
1416 | free(interesting); | |||
|
1417 | Py_XDECREF(dict); | |||
|
1418 | ||||
|
1419 | return NULL; | |||
|
1420 | } | |||
|
1421 | ||||
|
1422 | /* | |||
|
1423 | * Given a (possibly overlapping) set of revs, return the greatest | |||
|
1424 | * common ancestors: those with the longest path to the root. | |||
|
1425 | */ | |||
|
1426 | static PyObject *index_ancestors(indexObject *self, PyObject *args) | |||
|
1427 | { | |||
|
1428 | PyObject *ret = NULL, *gca = NULL; | |||
|
1429 | Py_ssize_t argcount, i, len; | |||
|
1430 | bitmask repeat = 0; | |||
|
1431 | int revcount = 0; | |||
|
1432 | int *revs; | |||
|
1433 | ||||
|
1434 | argcount = PySequence_Length(args); | |||
|
1435 | revs = malloc(argcount * sizeof(*revs)); | |||
|
1436 | if (argcount > 0 && revs == NULL) | |||
|
1437 | return PyErr_NoMemory(); | |||
|
1438 | len = index_length(self) - 1; | |||
|
1439 | ||||
|
1440 | for (i = 0; i < argcount; i++) { | |||
|
1441 | static const int capacity = 24; | |||
|
1442 | PyObject *obj = PySequence_GetItem(args, i); | |||
|
1443 | bitmask x; | |||
|
1444 | long val; | |||
|
1445 | ||||
|
1446 | if (!PyInt_Check(obj)) { | |||
|
1447 | PyErr_SetString(PyExc_TypeError, | |||
|
1448 | "arguments must all be ints"); | |||
|
1449 | goto bail; | |||
|
1450 | } | |||
|
1451 | val = PyInt_AsLong(obj); | |||
|
1452 | if (val == -1) { | |||
|
1453 | ret = PyList_New(0); | |||
|
1454 | goto done; | |||
|
1455 | } | |||
|
1456 | if (val < 0 || val >= len) { | |||
|
1457 | PyErr_SetString(PyExc_IndexError, | |||
|
1458 | "index out of range"); | |||
|
1459 | goto bail; | |||
|
1460 | } | |||
|
1461 | /* this cheesy bloom filter lets us avoid some more | |||
|
1462 | * expensive duplicate checks in the common set-is-disjoint | |||
|
1463 | * case */ | |||
|
1464 | x = 1ull << (val & 0x3f); | |||
|
1465 | if (repeat & x) { | |||
|
1466 | int k; | |||
|
1467 | for (k = 0; k < revcount; k++) { | |||
|
1468 | if (val == revs[k]) | |||
|
1469 | goto duplicate; | |||
|
1470 | } | |||
|
1471 | } | |||
|
1472 | else repeat |= x; | |||
|
1473 | if (revcount >= capacity) { | |||
|
1474 | PyErr_Format(PyExc_OverflowError, | |||
|
1475 | "bitset size (%d) > capacity (%d)", | |||
|
1476 | revcount, capacity); | |||
|
1477 | goto bail; | |||
|
1478 | } | |||
|
1479 | revs[revcount++] = (int)val; | |||
|
1480 | duplicate:; | |||
|
1481 | } | |||
|
1482 | ||||
|
1483 | if (revcount == 0) { | |||
|
1484 | ret = PyList_New(0); | |||
|
1485 | goto done; | |||
|
1486 | } | |||
|
1487 | if (revcount == 1) { | |||
|
1488 | PyObject *obj; | |||
|
1489 | ret = PyList_New(1); | |||
|
1490 | if (ret == NULL) | |||
|
1491 | goto bail; | |||
|
1492 | obj = PyInt_FromLong(revs[0]); | |||
|
1493 | if (obj == NULL) | |||
|
1494 | goto bail; | |||
|
1495 | PyList_SET_ITEM(ret, 0, obj); | |||
|
1496 | goto done; | |||
|
1497 | } | |||
|
1498 | ||||
|
1499 | gca = find_gca_candidates(self, revs, revcount); | |||
|
1500 | if (gca == NULL) | |||
|
1501 | goto bail; | |||
|
1502 | ||||
|
1503 | if (PyList_GET_SIZE(gca) <= 1) { | |||
|
1504 | ret = gca; | |||
|
1505 | Py_INCREF(gca); | |||
|
1506 | } | |||
|
1507 | else if (PyList_GET_SIZE(gca) == 1) { | |||
|
1508 | ret = PyList_GET_ITEM(gca, 0); | |||
|
1509 | Py_INCREF(ret); | |||
|
1510 | } | |||
|
1511 | else ret = find_deepest(self, gca); | |||
|
1512 | ||||
|
1513 | done: | |||
|
1514 | free(revs); | |||
|
1515 | Py_XDECREF(gca); | |||
|
1516 | ||||
|
1517 | return ret; | |||
|
1518 | ||||
|
1519 | bail: | |||
|
1520 | free(revs); | |||
|
1521 | Py_XDECREF(gca); | |||
|
1522 | Py_XDECREF(ret); | |||
|
1523 | return NULL; | |||
|
1524 | } | |||
|
1525 | ||||
1166 | /* |
|
1526 | /* | |
1167 | * Invalidate any trie entries introduced by added revs. |
|
1527 | * Invalidate any trie entries introduced by added revs. | |
1168 | */ |
|
1528 | */ | |
@@ -1406,6 +1766,8 b' static PyMappingMethods index_mapping_me' | |||||
1406 | }; |
|
1766 | }; | |
1407 |
|
1767 | |||
1408 | static PyMethodDef index_methods[] = { |
|
1768 | static PyMethodDef index_methods[] = { | |
|
1769 | {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS, | |||
|
1770 | "return the gca set of the given revs"}, | |||
1409 | {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS, |
|
1771 | {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS, | |
1410 | "clear the index caches"}, |
|
1772 | "clear the index caches"}, | |
1411 | {"get", (PyCFunction)index_m_get, METH_VARARGS, |
|
1773 | {"get", (PyCFunction)index_m_get, METH_VARARGS, |
@@ -706,6 +706,12 b' class revlog(object):' | |||||
706 | """calculate the least common ancestor of nodes a and b""" |
|
706 | """calculate the least common ancestor of nodes a and b""" | |
707 |
|
707 | |||
708 | a, b = self.rev(a), self.rev(b) |
|
708 | a, b = self.rev(a), self.rev(b) | |
|
709 | try: | |||
|
710 | ancs = self.index.ancestors(a, b) | |||
|
711 | old = ancestor.ancestors(self.parentrevs, a, b) | |||
|
712 | assert set(ancs) == old, ('opinions differ over ancestor(%d, %d)' % | |||
|
713 | (a, b)) | |||
|
714 | except (AttributeError, OverflowError): | |||
709 | ancs = ancestor.ancestors(self.parentrevs, a, b) |
|
715 | ancs = ancestor.ancestors(self.parentrevs, a, b) | |
710 | if ancs: |
|
716 | if ancs: | |
711 | # choose a consistent winner when there's a tie |
|
717 | # choose a consistent winner when there's a tie |
General Comments 0
You need to be logged in to leave comments.
Login now