Mercurial > public > mercurial-scm > hg
comparison mercurial/parsers.c @ 26053:b68c9d232db6
reachableroots: use internal "revstates" array to test if rev is a root
The main goal of this patch series is to reduce the use of PyXxx() function
that is likely to require ugly error handling and inc/decref. Plus, this is
faster than using PySet_Contains().
revset #0: 0::tip
0) 0.004168
1) 0.003678 88%
This patch ignores out-of-range roots as they are in the pure implementation.
Because reachable sets are calculated from heads, and out-of-range heads raise
IndexError, we can just take out-of-range roots as unreachable. Otherwise,
the test of "hg log -Gr '. + wdir()'" would fail.
"heads" argument is changed to a list. Should we have to rename the C function
as its signature is changed?
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Fri, 14 Aug 2015 15:43:29 +0900 |
parents | b970418bbafe |
children | 5049e10fed14 |
comparison
equal
deleted
inserted
replaced
26052:b970418bbafe | 26053:b68c9d232db6 |
---|---|
1106 phases[i] = phases[parent_1]; | 1106 phases[i] = phases[parent_1]; |
1107 if (parent_2 >= 0 && phases[parent_2] > phases[i]) | 1107 if (parent_2 >= 0 && phases[parent_2] > phases[i]) |
1108 phases[i] = phases[parent_2]; | 1108 phases[i] = phases[parent_2]; |
1109 } | 1109 } |
1110 | 1110 |
1111 static PyObject *reachableroots(indexObject *self, PyObject *args) | 1111 static PyObject *reachableroots2(indexObject *self, PyObject *args) |
1112 { | 1112 { |
1113 | 1113 |
1114 /* Input */ | 1114 /* Input */ |
1115 long minroot; | 1115 long minroot; |
1116 PyObject *includepatharg = NULL; | 1116 PyObject *includepatharg = NULL; |
1117 int includepath = 0; | 1117 int includepath = 0; |
1118 /* heads is a list */ | 1118 /* heads and roots are lists */ |
1119 PyObject *heads = NULL; | 1119 PyObject *heads = NULL; |
1120 /* roots is a set */ | |
1121 PyObject *roots = NULL; | 1120 PyObject *roots = NULL; |
1122 PyObject *reachable = NULL; | 1121 PyObject *reachable = NULL; |
1123 | 1122 |
1124 PyObject *val; | 1123 PyObject *val; |
1125 Py_ssize_t len = index_length(self) - 1; | 1124 Py_ssize_t len = index_length(self) - 1; |
1134 /* Internal data structure: | 1133 /* Internal data structure: |
1135 * tovisit: array of length len+1 (all revs + nullrev), filled upto lentovisit | 1134 * tovisit: array of length len+1 (all revs + nullrev), filled upto lentovisit |
1136 * revstates: array of length len+1 (all revs + nullrev) */ | 1135 * revstates: array of length len+1 (all revs + nullrev) */ |
1137 int *tovisit = NULL; | 1136 int *tovisit = NULL; |
1138 long lentovisit = 0; | 1137 long lentovisit = 0; |
1139 enum { RS_SEEN = 1 }; | 1138 enum { RS_SEEN = 1, RS_ROOT = 2 }; |
1140 char *revstates = NULL; | 1139 char *revstates = NULL; |
1141 | 1140 |
1142 /* Get arguments */ | 1141 /* Get arguments */ |
1143 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads, | 1142 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads, |
1144 &PySet_Type, &roots, &PyBool_Type, &includepatharg)) | 1143 &PyList_Type, &roots, |
1144 &PyBool_Type, &includepatharg)) | |
1145 goto bail; | 1145 goto bail; |
1146 | 1146 |
1147 if (includepatharg == Py_True) | 1147 if (includepatharg == Py_True) |
1148 includepath = 1; | 1148 includepath = 1; |
1149 | 1149 |
1165 if (revstates == NULL) { | 1165 if (revstates == NULL) { |
1166 PyErr_NoMemory(); | 1166 PyErr_NoMemory(); |
1167 goto bail; | 1167 goto bail; |
1168 } | 1168 } |
1169 | 1169 |
1170 l = PyList_GET_SIZE(roots); | |
1171 for (i = 0; i < l; i++) { | |
1172 revnum = PyInt_AsLong(PyList_GET_ITEM(roots, i)); | |
1173 if (revnum == -1 && PyErr_Occurred()) | |
1174 goto bail; | |
1175 /* If root is out of range, e.g. wdir(), it must be unreachable | |
1176 * from heads. So we can just ignore it. */ | |
1177 if (revnum + 1 < 0 || revnum + 1 >= len + 1) | |
1178 continue; | |
1179 revstates[revnum + 1] |= RS_ROOT; | |
1180 } | |
1181 | |
1170 /* Populate tovisit with all the heads */ | 1182 /* Populate tovisit with all the heads */ |
1171 l = PyList_GET_SIZE(heads); | 1183 l = PyList_GET_SIZE(heads); |
1172 for (i = 0; i < l; i++) { | 1184 for (i = 0; i < l; i++) { |
1173 revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i)); | 1185 revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i)); |
1174 if (revnum == -1 && PyErr_Occurred()) | 1186 if (revnum == -1 && PyErr_Occurred()) |
1186 /* Visit the tovisit list and find the reachable roots */ | 1198 /* Visit the tovisit list and find the reachable roots */ |
1187 k = 0; | 1199 k = 0; |
1188 while (k < lentovisit) { | 1200 while (k < lentovisit) { |
1189 /* Add the node to reachable if it is a root*/ | 1201 /* Add the node to reachable if it is a root*/ |
1190 revnum = tovisit[k++]; | 1202 revnum = tovisit[k++]; |
1191 val = PyInt_FromLong(revnum); | 1203 if (revstates[revnum + 1] & RS_ROOT) { |
1192 if (val == NULL) | 1204 val = PyInt_FromLong(revnum); |
1193 goto bail; | 1205 if (val == NULL) |
1194 if (PySet_Contains(roots, val) == 1) { | 1206 goto bail; |
1195 PySet_Add(reachable, val); | 1207 PySet_Add(reachable, val); |
1196 if (includepath == 0) { | 1208 Py_DECREF(val); |
1197 Py_DECREF(val); | 1209 if (includepath == 0) |
1198 continue; | 1210 continue; |
1199 } | 1211 } |
1200 } | |
1201 Py_DECREF(val); | |
1202 | 1212 |
1203 /* Add its parents to the list of nodes to visit */ | 1213 /* Add its parents to the list of nodes to visit */ |
1204 if (revnum == -1) | 1214 if (revnum == -1) |
1205 continue; | 1215 continue; |
1206 r = index_get_parents(self, revnum, parents, (int)len - 1); | 1216 r = index_get_parents(self, revnum, parents, (int)len - 1); |
2432 "clear the index caches"}, | 2442 "clear the index caches"}, |
2433 {"get", (PyCFunction)index_m_get, METH_VARARGS, | 2443 {"get", (PyCFunction)index_m_get, METH_VARARGS, |
2434 "get an index entry"}, | 2444 "get an index entry"}, |
2435 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets, | 2445 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets, |
2436 METH_VARARGS, "compute phases"}, | 2446 METH_VARARGS, "compute phases"}, |
2437 {"reachableroots", (PyCFunction)reachableroots, METH_VARARGS, | 2447 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS, |
2438 "reachableroots"}, | 2448 "reachableroots"}, |
2439 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS, | 2449 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS, |
2440 "get head revisions"}, /* Can do filtering since 3.2 */ | 2450 "get head revisions"}, /* Can do filtering since 3.2 */ |
2441 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS, | 2451 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS, |
2442 "get filtered head revisions"}, /* Can always do filtering */ | 2452 "get filtered head revisions"}, /* Can always do filtering */ |