--- a/mercurial/changelog.py Tue Sep 16 23:47:34 2014 -0700
+++ b/mercurial/changelog.py Tue Sep 16 16:03:21 2014 -0700
@@ -171,8 +171,13 @@
def headrevs(self):
if self.filteredrevs:
- # XXX we should fix and use the C version
- return self._headrevs()
+ try:
+ return self.index.headrevs(self.filteredrevs)
+ # AttributeError covers non-c-extension environments.
+ # TypeError allows us work with old c extensions.
+ except (AttributeError, TypeError):
+ return self._headrevs()
+
return super(changelog, self).headrevs()
def strip(self, *args, **kwargs):
--- a/mercurial/parsers.c Tue Sep 16 23:47:34 2014 -0700
+++ b/mercurial/parsers.c Tue Sep 16 16:03:21 2014 -0700
@@ -508,6 +508,7 @@
Py_ssize_t length; /* current number of elements */
PyObject *added; /* populated on demand */
PyObject *headrevs; /* cache, invalidated on changes */
+ PyObject *filteredrevs;/* filtered revs set */
nodetree *nt; /* base-16 trie */
int ntlength; /* # nodes in use */
int ntcapacity; /* # nodes allocated */
@@ -823,15 +824,60 @@
return newlist;
}
-static PyObject *index_headrevs(indexObject *self)
+static int check_filter(PyObject *filter, Py_ssize_t arg) {
+ if (filter) {
+ PyObject *arglist, *result;
+ int isfiltered;
+
+ arglist = Py_BuildValue("(n)", arg);
+ if (!arglist) {
+ return -1;
+ }
+
+ result = PyEval_CallObject(filter, arglist);
+ Py_DECREF(arglist);
+ if (!result) {
+ return -1;
+ }
+
+ /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
+ * same as this function, so we can just return it directly.*/
+ isfiltered = PyObject_IsTrue(result);
+ Py_DECREF(result);
+ return isfiltered;
+ } else {
+ return 0;
+ }
+}
+
+static PyObject *index_headrevs(indexObject *self, PyObject *args)
{
Py_ssize_t i, len, addlen;
char *nothead = NULL;
PyObject *heads;
+ PyObject *filter = NULL;
+ PyObject *filteredrevs = Py_None;
- if (self->headrevs)
+ if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
+ return NULL;
+ }
+
+ if (self->headrevs && filteredrevs == self->filteredrevs)
return list_copy(self->headrevs);
+ Py_DECREF(self->filteredrevs);
+ self->filteredrevs = filteredrevs;
+ Py_INCREF(filteredrevs);
+
+ if (filteredrevs != Py_None) {
+ filter = PyObject_GetAttrString(filteredrevs, "__contains__");
+ if (!filter) {
+ PyErr_SetString(PyExc_TypeError,
+ "filteredrevs has no attribute __contains__");
+ goto bail;
+ }
+ }
+
len = index_length(self) - 1;
heads = PyList_New(0);
if (heads == NULL)
@@ -850,9 +896,25 @@
goto bail;
for (i = 0; i < self->raw_length; i++) {
- const char *data = index_deref(self, i);
- int parent_1 = getbe32(data + 24);
- int parent_2 = getbe32(data + 28);
+ const char *data;
+ int parent_1, parent_2, isfiltered;
+
+ isfiltered = check_filter(filter, i);
+ if (isfiltered == -1) {
+ PyErr_SetString(PyExc_TypeError,
+ "unable to check filter");
+ goto bail;
+ }
+
+ if (isfiltered) {
+ nothead[i] = 1;
+ continue;
+ }
+
+ data = index_deref(self, i);
+ parent_1 = getbe32(data + 24);
+ parent_2 = getbe32(data + 28);
+
if (parent_1 >= 0)
nothead[parent_1] = 1;
if (parent_2 >= 0)
@@ -866,12 +928,26 @@
PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
long parent_1, parent_2;
+ int isfiltered;
if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
PyErr_SetString(PyExc_TypeError,
"revlog parents are invalid");
goto bail;
}
+
+ isfiltered = check_filter(filter, i);
+ if (isfiltered == -1) {
+ PyErr_SetString(PyExc_TypeError,
+ "unable to check filter");
+ goto bail;
+ }
+
+ if (isfiltered) {
+ nothead[i] = 1;
+ continue;
+ }
+
parent_1 = PyInt_AS_LONG(p1);
parent_2 = PyInt_AS_LONG(p2);
if (parent_1 >= 0)
@@ -894,9 +970,11 @@
done:
self->headrevs = heads;
+ Py_XDECREF(filter);
free(nothead);
return list_copy(self->headrevs);
bail:
+ Py_XDECREF(filter);
Py_XDECREF(heads);
free(nothead);
return NULL;
@@ -1896,6 +1974,8 @@
self->cache = NULL;
self->data = NULL;
self->headrevs = NULL;
+ self->filteredrevs = Py_None;
+ Py_INCREF(Py_None);
self->nt = NULL;
self->offsets = NULL;
@@ -1945,6 +2025,7 @@
static void index_dealloc(indexObject *self)
{
_index_clearcaches(self);
+ Py_XDECREF(self->filteredrevs);
Py_XDECREF(self->data);
Py_XDECREF(self->added);
PyObject_Del(self);
@@ -1977,7 +2058,7 @@
"clear the index caches"},
{"get", (PyCFunction)index_m_get, METH_VARARGS,
"get an index entry"},
- {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS,
+ {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
"get head revisions"},
{"insert", (PyCFunction)index_insert, METH_VARARGS,
"insert an index entry"},