diff -r 5c9ad50fd62f -r 6d678ab1b10d mercurial/cext/revlog.c --- a/mercurial/cext/revlog.c Wed Jun 28 13:32:36 2017 +0200 +++ b/mercurial/cext/revlog.c Sun Jun 25 12:41:34 2017 -0700 @@ -816,6 +816,139 @@ return NULL; } +static inline int index_baserev(indexObject *self, int rev) +{ + const char *data; + + if (rev >= self->length - 1) { + PyObject *tuple = PyList_GET_ITEM(self->added, + rev - self->length + 1); + return (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 3)); + } + else { + data = index_deref(self, rev); + if (data == NULL) { + return -2; + } + + return getbe32(data + 16); + } +} + +static PyObject *index_deltachain(indexObject *self, PyObject *args) +{ + int rev, generaldelta; + PyObject *stoparg; + int stoprev, iterrev, baserev = -1; + int stopped; + PyObject *chain = NULL, *value = NULL, *result = NULL; + const Py_ssize_t length = index_length(self); + + if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) { + return NULL; + } + + if (PyInt_Check(stoparg)) { + stoprev = (int)PyInt_AsLong(stoparg); + if (stoprev == -1 && PyErr_Occurred()) { + return NULL; + } + } + else if (stoparg == Py_None) { + stoprev = -2; + } + else { + PyErr_SetString(PyExc_ValueError, + "stoprev must be integer or None"); + return NULL; + } + + if (rev < 0 || rev >= length - 1) { + PyErr_SetString(PyExc_ValueError, "revlog index out of range"); + return NULL; + } + + chain = PyList_New(0); + if (chain == NULL) { + return NULL; + } + + baserev = index_baserev(self, rev); + + /* This should never happen. */ + if (baserev == -2) { + PyErr_SetString(PyExc_IndexError, "unable to resolve data"); + goto bail; + } + + iterrev = rev; + + while (iterrev != baserev && iterrev != stoprev) { + value = PyInt_FromLong(iterrev); + if (value == NULL) { + goto bail; + } + if (PyList_Append(chain, value)) { + Py_DECREF(value); + goto bail; + } + Py_DECREF(value); + + if (generaldelta) { + iterrev = baserev; + } + else { + iterrev--; + } + + if (iterrev < 0) { + break; + } + + if (iterrev >= length - 1) { + PyErr_SetString(PyExc_IndexError, "revision outside index"); + return NULL; + } + + baserev = index_baserev(self, iterrev); + + /* This should never happen. */ + if (baserev == -2) { + PyErr_SetString(PyExc_IndexError, "unable to resolve data"); + goto bail; + } + } + + if (iterrev == stoprev) { + stopped = 1; + } + else { + value = PyInt_FromLong(iterrev); + if (value == NULL) { + goto bail; + } + if (PyList_Append(chain, value)) { + Py_DECREF(value); + goto bail; + } + Py_DECREF(value); + + stopped = 0; + } + + if (PyList_Reverse(chain)) { + goto bail; + } + + result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False); + Py_DECREF(chain); + return result; + +bail: + Py_DECREF(chain); + return NULL; +} + static inline int nt_level(const char *node, Py_ssize_t level) { int v = node[level>>1]; @@ -1828,6 +1961,8 @@ "get head revisions"}, /* Can do filtering since 3.2 */ {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS, "get filtered head revisions"}, /* Can always do filtering */ + {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS, + "determine revisions with deltas to reconstruct fulltext"}, {"insert", (PyCFunction)index_insert, METH_VARARGS, "insert an index entry"}, {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,