##// END OF EJS Templates
revlog: add a C implementation of `headrevsdiff`...
Arseniy Alekseyev -
r52289:3f37d80d default
parent child Browse files
Show More
@@ -1332,6 +1332,197 b' bail:'
1332 return NULL;
1332 return NULL;
1333 }
1333 }
1334
1334
1335 /* "rgs" stands for "reverse growable set".
1336 It is a representation of a set of integers that can't exceed, but
1337 tend to be close to `max`.
1338
1339 `body` is a growable bit array covering the range `max-len+1..max`,
1340 in reverse order.
1341 `sum` keeps track of the cardinality of the set.
1342 */
1343 typedef struct rgs {
1344 int max;
1345 int len;
1346 char *body;
1347 int sum;
1348 } rgs;
1349
1350 static int rgs_offset(rgs *rgs, int i)
1351 {
1352 return rgs->max - i;
1353 }
1354
1355 /* returns 1 on success, 0 on failure */
1356 static int rgs_alloc(rgs *rgs, int max)
1357 {
1358 int new_len = 64;
1359 char *new_body = calloc(new_len, 1);
1360 if (new_body == NULL)
1361 return 0;
1362 rgs->len = new_len;
1363 rgs->body = new_body;
1364 rgs->max = max;
1365 rgs->sum = 0;
1366 return 1;
1367 }
1368
1369 static bool rgs_get(rgs *rgs, int i)
1370 {
1371 int offset = rgs_offset(rgs, i);
1372 if (offset >= rgs->len) {
1373 return 0;
1374 }
1375 if (offset < 0) {
1376 abort();
1377 }
1378 return rgs->body[offset];
1379 }
1380
1381 /* Realloc `body` to length `new_len`.
1382 Returns -1 when out of memory. */
1383 static int rgs_realloc(rgs *rgs, int new_len)
1384 {
1385 int old_len = rgs->len;
1386 char *old_body = rgs->body;
1387 char *new_body = calloc(new_len, 1);
1388 assert(new_len >= old_len);
1389 if (new_body == NULL)
1390 return -1;
1391 memcpy(new_body, old_body, old_len);
1392 free(old_body);
1393 rgs->body = new_body;
1394 rgs->len = new_len;
1395 return 0;
1396 }
1397
1398 /* Realloc the rgs `body` to include the `offset` */
1399 static int rgs_realloc_amortized(rgs *rgs, int offset)
1400 {
1401 int old_len = rgs->len;
1402 int new_len = old_len * 4;
1403 if (offset >= new_len)
1404 new_len = offset + 1;
1405 return rgs_realloc(rgs, new_len);
1406 }
1407
1408 /* returns 0 on success, -1 on error */
1409 static int rgs_set(rgs *rgs, int i, bool v)
1410 {
1411 int offset = rgs_offset(rgs, i);
1412 if (offset >= rgs->len) {
1413 if (v == 0) {
1414 /* no-op change: no need to resize */
1415 return 0;
1416 }
1417 if (rgs_realloc_amortized(rgs, offset) == -1)
1418 return -1;
1419 }
1420 if (offset < 0) {
1421 abort();
1422 }
1423 rgs->sum -= rgs->body[offset];
1424 rgs->sum += v;
1425 rgs->body[offset] = v;
1426 return 0;
1427 }
1428
1429 /* Add a size_t value to a Python list. Return -1 on failure. */
1430 static inline int pylist_append_size_t(PyObject *list, size_t v)
1431 {
1432 return pylist_append_owned(list, PyLong_FromSsize_t(v));
1433 }
1434
1435 static PyObject *index_headrevsdiff(indexObject *self, PyObject *args)
1436 {
1437 int begin, end;
1438 Py_ssize_t i, j;
1439 PyObject *heads_added = NULL;
1440 PyObject *heads_removed = NULL;
1441 PyObject *res = NULL;
1442 rgs rgs;
1443 rgs.body = NULL;
1444
1445 if (!PyArg_ParseTuple(args, "ii", &begin, &end))
1446 goto bail;
1447
1448 if (!rgs_alloc(&rgs, end))
1449 goto bail;
1450
1451 heads_added = PyList_New(0);
1452 if (heads_added == NULL)
1453 goto bail;
1454 heads_removed = PyList_New(0);
1455 if (heads_removed == NULL)
1456 goto bail;
1457
1458 for (i = end - 1; i >= begin; i--) {
1459 int parents[2];
1460
1461 if (rgs_get(&rgs, i)) {
1462 if (rgs_set(&rgs, i, false) == -1) {
1463 goto bail;
1464 };
1465 } else {
1466 if (pylist_append_size_t(heads_added, i) == -1) {
1467 goto bail;
1468 }
1469 }
1470
1471 if (index_get_parents(self, i, parents, i) < 0)
1472 goto bail;
1473 for (j = 0; j < 2; j++) {
1474 if (parents[j] >= 0)
1475 if (rgs_set(&rgs, parents[j], true) == -1) {
1476 goto bail;
1477 }
1478 }
1479 }
1480
1481 while (rgs.sum) {
1482 int parents[2];
1483
1484 if (rgs_get(&rgs, i)) {
1485 if (rgs_set(&rgs, i, false) == -1) {
1486 goto bail;
1487 }
1488 if (pylist_append_size_t(heads_removed, i) == -1) {
1489 goto bail;
1490 }
1491 }
1492
1493 if (index_get_parents(self, i, parents, i) < 0)
1494 goto bail;
1495 for (j = 0; j < 2; j++) {
1496 if (parents[j] >= 0)
1497 if (rgs_set(&rgs, parents[j], false) == -1) {
1498 /* can't actually fail */
1499 goto bail;
1500 }
1501 }
1502 i--;
1503 }
1504
1505 if (begin == 0 && end > 0) {
1506 if (pylist_append_size_t(heads_removed, -1) == -1) {
1507 goto bail;
1508 }
1509 }
1510
1511 if (!(res = PyTuple_Pack(2, heads_removed, heads_added))) {
1512 goto bail;
1513 }
1514
1515 Py_XDECREF(heads_removed);
1516 Py_XDECREF(heads_added);
1517 free(rgs.body);
1518 return res;
1519 bail:
1520 Py_XDECREF(heads_added);
1521 Py_XDECREF(heads_removed);
1522 free(rgs.body);
1523 return NULL;
1524 }
1525
1335 /**
1526 /**
1336 * Obtain the base revision index entry.
1527 * Obtain the base revision index entry.
1337 *
1528 *
@@ -3141,6 +3332,8 b' static PyMappingMethods index_mapping_me'
3141 static PyMethodDef index_methods[] = {
3332 static PyMethodDef index_methods[] = {
3142 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
3333 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
3143 "return the gca set of the given revs"},
3334 "return the gca set of the given revs"},
3335 {"headrevsdiff", (PyCFunction)index_headrevsdiff, METH_VARARGS,
3336 "return the set of heads removed/added by a range of commits"},
3144 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
3337 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
3145 METH_VARARGS,
3338 METH_VARARGS,
3146 "return the heads of the common ancestors of the given revs"},
3339 "return the heads of the common ancestors of the given revs"},
General Comments 0
You need to be logged in to leave comments. Login now