##// END OF EJS Templates
cext: cast s# arguments of Py_BuildValue() to Py_ssize_t...
Yuya Nishihara -
r42265:509a0477 default
parent child Browse files
Show More
@@ -1,754 +1,755 b''
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 #define PY_SSIZE_T_CLEAN
10 #define PY_SSIZE_T_CLEAN
11 #include <Python.h>
11 #include <Python.h>
12 #include <ctype.h>
12 #include <ctype.h>
13 #include <stddef.h>
13 #include <stddef.h>
14 #include <string.h>
14 #include <string.h>
15
15
16 #include "bitmanipulation.h"
16 #include "bitmanipulation.h"
17 #include "charencode.h"
17 #include "charencode.h"
18 #include "util.h"
18 #include "util.h"
19
19
20 #ifdef IS_PY3K
20 #ifdef IS_PY3K
21 /* The mapping of Python types is meant to be temporary to get Python
21 /* The mapping of Python types is meant to be temporary to get Python
22 * 3 to compile. We should remove this once Python 3 support is fully
22 * 3 to compile. We should remove this once Python 3 support is fully
23 * supported and proper types are used in the extensions themselves. */
23 * supported and proper types are used in the extensions themselves. */
24 #define PyInt_Check PyLong_Check
24 #define PyInt_Check PyLong_Check
25 #define PyInt_FromLong PyLong_FromLong
25 #define PyInt_FromLong PyLong_FromLong
26 #define PyInt_FromSsize_t PyLong_FromSsize_t
26 #define PyInt_FromSsize_t PyLong_FromSsize_t
27 #define PyInt_AsLong PyLong_AsLong
27 #define PyInt_AsLong PyLong_AsLong
28 #endif
28 #endif
29
29
30 static const char *const versionerrortext = "Python minor version mismatch";
30 static const char *const versionerrortext = "Python minor version mismatch";
31
31
32 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
32 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
33 {
33 {
34 Py_ssize_t expected_size;
34 Py_ssize_t expected_size;
35
35
36 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size)) {
36 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size)) {
37 return NULL;
37 return NULL;
38 }
38 }
39
39
40 return _dict_new_presized(expected_size);
40 return _dict_new_presized(expected_size);
41 }
41 }
42
42
43 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
43 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
44 int size, int mtime)
44 int size, int mtime)
45 {
45 {
46 dirstateTupleObject *t =
46 dirstateTupleObject *t =
47 PyObject_New(dirstateTupleObject, &dirstateTupleType);
47 PyObject_New(dirstateTupleObject, &dirstateTupleType);
48 if (!t) {
48 if (!t) {
49 return NULL;
49 return NULL;
50 }
50 }
51 t->state = state;
51 t->state = state;
52 t->mode = mode;
52 t->mode = mode;
53 t->size = size;
53 t->size = size;
54 t->mtime = mtime;
54 t->mtime = mtime;
55 return t;
55 return t;
56 }
56 }
57
57
58 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
58 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
59 PyObject *kwds)
59 PyObject *kwds)
60 {
60 {
61 /* We do all the initialization here and not a tp_init function because
61 /* We do all the initialization here and not a tp_init function because
62 * dirstate_tuple is immutable. */
62 * dirstate_tuple is immutable. */
63 dirstateTupleObject *t;
63 dirstateTupleObject *t;
64 char state;
64 char state;
65 int size, mode, mtime;
65 int size, mode, mtime;
66 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
66 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
67 return NULL;
67 return NULL;
68 }
68 }
69
69
70 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
70 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
71 if (!t) {
71 if (!t) {
72 return NULL;
72 return NULL;
73 }
73 }
74 t->state = state;
74 t->state = state;
75 t->mode = mode;
75 t->mode = mode;
76 t->size = size;
76 t->size = size;
77 t->mtime = mtime;
77 t->mtime = mtime;
78
78
79 return (PyObject *)t;
79 return (PyObject *)t;
80 }
80 }
81
81
82 static void dirstate_tuple_dealloc(PyObject *o)
82 static void dirstate_tuple_dealloc(PyObject *o)
83 {
83 {
84 PyObject_Del(o);
84 PyObject_Del(o);
85 }
85 }
86
86
87 static Py_ssize_t dirstate_tuple_length(PyObject *o)
87 static Py_ssize_t dirstate_tuple_length(PyObject *o)
88 {
88 {
89 return 4;
89 return 4;
90 }
90 }
91
91
92 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
92 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
93 {
93 {
94 dirstateTupleObject *t = (dirstateTupleObject *)o;
94 dirstateTupleObject *t = (dirstateTupleObject *)o;
95 switch (i) {
95 switch (i) {
96 case 0:
96 case 0:
97 return PyBytes_FromStringAndSize(&t->state, 1);
97 return PyBytes_FromStringAndSize(&t->state, 1);
98 case 1:
98 case 1:
99 return PyInt_FromLong(t->mode);
99 return PyInt_FromLong(t->mode);
100 case 2:
100 case 2:
101 return PyInt_FromLong(t->size);
101 return PyInt_FromLong(t->size);
102 case 3:
102 case 3:
103 return PyInt_FromLong(t->mtime);
103 return PyInt_FromLong(t->mtime);
104 default:
104 default:
105 PyErr_SetString(PyExc_IndexError, "index out of range");
105 PyErr_SetString(PyExc_IndexError, "index out of range");
106 return NULL;
106 return NULL;
107 }
107 }
108 }
108 }
109
109
110 static PySequenceMethods dirstate_tuple_sq = {
110 static PySequenceMethods dirstate_tuple_sq = {
111 dirstate_tuple_length, /* sq_length */
111 dirstate_tuple_length, /* sq_length */
112 0, /* sq_concat */
112 0, /* sq_concat */
113 0, /* sq_repeat */
113 0, /* sq_repeat */
114 dirstate_tuple_item, /* sq_item */
114 dirstate_tuple_item, /* sq_item */
115 0, /* sq_ass_item */
115 0, /* sq_ass_item */
116 0, /* sq_contains */
116 0, /* sq_contains */
117 0, /* sq_inplace_concat */
117 0, /* sq_inplace_concat */
118 0 /* sq_inplace_repeat */
118 0 /* sq_inplace_repeat */
119 };
119 };
120
120
121 PyTypeObject dirstateTupleType = {
121 PyTypeObject dirstateTupleType = {
122 PyVarObject_HEAD_INIT(NULL, 0) /* header */
122 PyVarObject_HEAD_INIT(NULL, 0) /* header */
123 "dirstate_tuple", /* tp_name */
123 "dirstate_tuple", /* tp_name */
124 sizeof(dirstateTupleObject), /* tp_basicsize */
124 sizeof(dirstateTupleObject), /* tp_basicsize */
125 0, /* tp_itemsize */
125 0, /* tp_itemsize */
126 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
126 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
127 0, /* tp_print */
127 0, /* tp_print */
128 0, /* tp_getattr */
128 0, /* tp_getattr */
129 0, /* tp_setattr */
129 0, /* tp_setattr */
130 0, /* tp_compare */
130 0, /* tp_compare */
131 0, /* tp_repr */
131 0, /* tp_repr */
132 0, /* tp_as_number */
132 0, /* tp_as_number */
133 &dirstate_tuple_sq, /* tp_as_sequence */
133 &dirstate_tuple_sq, /* tp_as_sequence */
134 0, /* tp_as_mapping */
134 0, /* tp_as_mapping */
135 0, /* tp_hash */
135 0, /* tp_hash */
136 0, /* tp_call */
136 0, /* tp_call */
137 0, /* tp_str */
137 0, /* tp_str */
138 0, /* tp_getattro */
138 0, /* tp_getattro */
139 0, /* tp_setattro */
139 0, /* tp_setattro */
140 0, /* tp_as_buffer */
140 0, /* tp_as_buffer */
141 Py_TPFLAGS_DEFAULT, /* tp_flags */
141 Py_TPFLAGS_DEFAULT, /* tp_flags */
142 "dirstate tuple", /* tp_doc */
142 "dirstate tuple", /* tp_doc */
143 0, /* tp_traverse */
143 0, /* tp_traverse */
144 0, /* tp_clear */
144 0, /* tp_clear */
145 0, /* tp_richcompare */
145 0, /* tp_richcompare */
146 0, /* tp_weaklistoffset */
146 0, /* tp_weaklistoffset */
147 0, /* tp_iter */
147 0, /* tp_iter */
148 0, /* tp_iternext */
148 0, /* tp_iternext */
149 0, /* tp_methods */
149 0, /* tp_methods */
150 0, /* tp_members */
150 0, /* tp_members */
151 0, /* tp_getset */
151 0, /* tp_getset */
152 0, /* tp_base */
152 0, /* tp_base */
153 0, /* tp_dict */
153 0, /* tp_dict */
154 0, /* tp_descr_get */
154 0, /* tp_descr_get */
155 0, /* tp_descr_set */
155 0, /* tp_descr_set */
156 0, /* tp_dictoffset */
156 0, /* tp_dictoffset */
157 0, /* tp_init */
157 0, /* tp_init */
158 0, /* tp_alloc */
158 0, /* tp_alloc */
159 dirstate_tuple_new, /* tp_new */
159 dirstate_tuple_new, /* tp_new */
160 };
160 };
161
161
162 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
162 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
163 {
163 {
164 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
164 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
165 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
165 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
166 char state, *cur, *str, *cpos;
166 char state, *cur, *str, *cpos;
167 int mode, size, mtime;
167 int mode, size, mtime;
168 unsigned int flen, pos = 40;
168 unsigned int flen, pos = 40;
169 Py_ssize_t len = 40;
169 Py_ssize_t len = 40;
170 Py_ssize_t readlen;
170 Py_ssize_t readlen;
171
171
172 if (!PyArg_ParseTuple(
172 if (!PyArg_ParseTuple(
173 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
173 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
174 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen)) {
174 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen)) {
175 goto quit;
175 goto quit;
176 }
176 }
177
177
178 len = readlen;
178 len = readlen;
179
179
180 /* read parents */
180 /* read parents */
181 if (len < 40) {
181 if (len < 40) {
182 PyErr_SetString(PyExc_ValueError,
182 PyErr_SetString(PyExc_ValueError,
183 "too little data for parents");
183 "too little data for parents");
184 goto quit;
184 goto quit;
185 }
185 }
186
186
187 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, 20, str + 20, 20);
187 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, (Py_ssize_t)20,
188 str + 20, (Py_ssize_t)20);
188 if (!parents) {
189 if (!parents) {
189 goto quit;
190 goto quit;
190 }
191 }
191
192
192 /* read filenames */
193 /* read filenames */
193 while (pos >= 40 && pos < len) {
194 while (pos >= 40 && pos < len) {
194 if (pos + 17 > len) {
195 if (pos + 17 > len) {
195 PyErr_SetString(PyExc_ValueError,
196 PyErr_SetString(PyExc_ValueError,
196 "overflow in dirstate");
197 "overflow in dirstate");
197 goto quit;
198 goto quit;
198 }
199 }
199 cur = str + pos;
200 cur = str + pos;
200 /* unpack header */
201 /* unpack header */
201 state = *cur;
202 state = *cur;
202 mode = getbe32(cur + 1);
203 mode = getbe32(cur + 1);
203 size = getbe32(cur + 5);
204 size = getbe32(cur + 5);
204 mtime = getbe32(cur + 9);
205 mtime = getbe32(cur + 9);
205 flen = getbe32(cur + 13);
206 flen = getbe32(cur + 13);
206 pos += 17;
207 pos += 17;
207 cur += 17;
208 cur += 17;
208 if (flen > len - pos) {
209 if (flen > len - pos) {
209 PyErr_SetString(PyExc_ValueError,
210 PyErr_SetString(PyExc_ValueError,
210 "overflow in dirstate");
211 "overflow in dirstate");
211 goto quit;
212 goto quit;
212 }
213 }
213
214
214 entry =
215 entry =
215 (PyObject *)make_dirstate_tuple(state, mode, size, mtime);
216 (PyObject *)make_dirstate_tuple(state, mode, size, mtime);
216 cpos = memchr(cur, 0, flen);
217 cpos = memchr(cur, 0, flen);
217 if (cpos) {
218 if (cpos) {
218 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
219 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
219 cname = PyBytes_FromStringAndSize(
220 cname = PyBytes_FromStringAndSize(
220 cpos + 1, flen - (cpos - cur) - 1);
221 cpos + 1, flen - (cpos - cur) - 1);
221 if (!fname || !cname ||
222 if (!fname || !cname ||
222 PyDict_SetItem(cmap, fname, cname) == -1 ||
223 PyDict_SetItem(cmap, fname, cname) == -1 ||
223 PyDict_SetItem(dmap, fname, entry) == -1) {
224 PyDict_SetItem(dmap, fname, entry) == -1) {
224 goto quit;
225 goto quit;
225 }
226 }
226 Py_DECREF(cname);
227 Py_DECREF(cname);
227 } else {
228 } else {
228 fname = PyBytes_FromStringAndSize(cur, flen);
229 fname = PyBytes_FromStringAndSize(cur, flen);
229 if (!fname ||
230 if (!fname ||
230 PyDict_SetItem(dmap, fname, entry) == -1) {
231 PyDict_SetItem(dmap, fname, entry) == -1) {
231 goto quit;
232 goto quit;
232 }
233 }
233 }
234 }
234 Py_DECREF(fname);
235 Py_DECREF(fname);
235 Py_DECREF(entry);
236 Py_DECREF(entry);
236 fname = cname = entry = NULL;
237 fname = cname = entry = NULL;
237 pos += flen;
238 pos += flen;
238 }
239 }
239
240
240 ret = parents;
241 ret = parents;
241 Py_INCREF(ret);
242 Py_INCREF(ret);
242 quit:
243 quit:
243 Py_XDECREF(fname);
244 Py_XDECREF(fname);
244 Py_XDECREF(cname);
245 Py_XDECREF(cname);
245 Py_XDECREF(entry);
246 Py_XDECREF(entry);
246 Py_XDECREF(parents);
247 Py_XDECREF(parents);
247 return ret;
248 return ret;
248 }
249 }
249
250
250 /*
251 /*
251 * Build a set of non-normal and other parent entries from the dirstate dmap
252 * Build a set of non-normal and other parent entries from the dirstate dmap
252 */
253 */
253 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
254 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
254 {
255 {
255 PyObject *dmap, *fname, *v;
256 PyObject *dmap, *fname, *v;
256 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
257 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
257 Py_ssize_t pos;
258 Py_ssize_t pos;
258
259
259 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type,
260 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type,
260 &dmap)) {
261 &dmap)) {
261 goto bail;
262 goto bail;
262 }
263 }
263
264
264 nonnset = PySet_New(NULL);
265 nonnset = PySet_New(NULL);
265 if (nonnset == NULL) {
266 if (nonnset == NULL) {
266 goto bail;
267 goto bail;
267 }
268 }
268
269
269 otherpset = PySet_New(NULL);
270 otherpset = PySet_New(NULL);
270 if (otherpset == NULL) {
271 if (otherpset == NULL) {
271 goto bail;
272 goto bail;
272 }
273 }
273
274
274 pos = 0;
275 pos = 0;
275 while (PyDict_Next(dmap, &pos, &fname, &v)) {
276 while (PyDict_Next(dmap, &pos, &fname, &v)) {
276 dirstateTupleObject *t;
277 dirstateTupleObject *t;
277 if (!dirstate_tuple_check(v)) {
278 if (!dirstate_tuple_check(v)) {
278 PyErr_SetString(PyExc_TypeError,
279 PyErr_SetString(PyExc_TypeError,
279 "expected a dirstate tuple");
280 "expected a dirstate tuple");
280 goto bail;
281 goto bail;
281 }
282 }
282 t = (dirstateTupleObject *)v;
283 t = (dirstateTupleObject *)v;
283
284
284 if (t->state == 'n' && t->size == -2) {
285 if (t->state == 'n' && t->size == -2) {
285 if (PySet_Add(otherpset, fname) == -1) {
286 if (PySet_Add(otherpset, fname) == -1) {
286 goto bail;
287 goto bail;
287 }
288 }
288 }
289 }
289
290
290 if (t->state == 'n' && t->mtime != -1) {
291 if (t->state == 'n' && t->mtime != -1) {
291 continue;
292 continue;
292 }
293 }
293 if (PySet_Add(nonnset, fname) == -1) {
294 if (PySet_Add(nonnset, fname) == -1) {
294 goto bail;
295 goto bail;
295 }
296 }
296 }
297 }
297
298
298 result = Py_BuildValue("(OO)", nonnset, otherpset);
299 result = Py_BuildValue("(OO)", nonnset, otherpset);
299 if (result == NULL) {
300 if (result == NULL) {
300 goto bail;
301 goto bail;
301 }
302 }
302 Py_DECREF(nonnset);
303 Py_DECREF(nonnset);
303 Py_DECREF(otherpset);
304 Py_DECREF(otherpset);
304 return result;
305 return result;
305 bail:
306 bail:
306 Py_XDECREF(nonnset);
307 Py_XDECREF(nonnset);
307 Py_XDECREF(otherpset);
308 Py_XDECREF(otherpset);
308 Py_XDECREF(result);
309 Py_XDECREF(result);
309 return NULL;
310 return NULL;
310 }
311 }
311
312
312 /*
313 /*
313 * Efficiently pack a dirstate object into its on-disk format.
314 * Efficiently pack a dirstate object into its on-disk format.
314 */
315 */
315 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
316 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
316 {
317 {
317 PyObject *packobj = NULL;
318 PyObject *packobj = NULL;
318 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
319 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
319 Py_ssize_t nbytes, pos, l;
320 Py_ssize_t nbytes, pos, l;
320 PyObject *k, *v = NULL, *pn;
321 PyObject *k, *v = NULL, *pn;
321 char *p, *s;
322 char *p, *s;
322 int now;
323 int now;
323
324
324 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
325 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
325 &PyDict_Type, &copymap, &PyTuple_Type, &pl,
326 &PyDict_Type, &copymap, &PyTuple_Type, &pl,
326 &now)) {
327 &now)) {
327 return NULL;
328 return NULL;
328 }
329 }
329
330
330 if (PyTuple_Size(pl) != 2) {
331 if (PyTuple_Size(pl) != 2) {
331 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
332 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
332 return NULL;
333 return NULL;
333 }
334 }
334
335
335 /* Figure out how much we need to allocate. */
336 /* Figure out how much we need to allocate. */
336 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
337 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
337 PyObject *c;
338 PyObject *c;
338 if (!PyBytes_Check(k)) {
339 if (!PyBytes_Check(k)) {
339 PyErr_SetString(PyExc_TypeError, "expected string key");
340 PyErr_SetString(PyExc_TypeError, "expected string key");
340 goto bail;
341 goto bail;
341 }
342 }
342 nbytes += PyBytes_GET_SIZE(k) + 17;
343 nbytes += PyBytes_GET_SIZE(k) + 17;
343 c = PyDict_GetItem(copymap, k);
344 c = PyDict_GetItem(copymap, k);
344 if (c) {
345 if (c) {
345 if (!PyBytes_Check(c)) {
346 if (!PyBytes_Check(c)) {
346 PyErr_SetString(PyExc_TypeError,
347 PyErr_SetString(PyExc_TypeError,
347 "expected string key");
348 "expected string key");
348 goto bail;
349 goto bail;
349 }
350 }
350 nbytes += PyBytes_GET_SIZE(c) + 1;
351 nbytes += PyBytes_GET_SIZE(c) + 1;
351 }
352 }
352 }
353 }
353
354
354 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
355 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
355 if (packobj == NULL) {
356 if (packobj == NULL) {
356 goto bail;
357 goto bail;
357 }
358 }
358
359
359 p = PyBytes_AS_STRING(packobj);
360 p = PyBytes_AS_STRING(packobj);
360
361
361 pn = PyTuple_GET_ITEM(pl, 0);
362 pn = PyTuple_GET_ITEM(pl, 0);
362 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
363 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
363 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
364 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
364 goto bail;
365 goto bail;
365 }
366 }
366 memcpy(p, s, l);
367 memcpy(p, s, l);
367 p += 20;
368 p += 20;
368 pn = PyTuple_GET_ITEM(pl, 1);
369 pn = PyTuple_GET_ITEM(pl, 1);
369 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
370 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
370 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
371 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
371 goto bail;
372 goto bail;
372 }
373 }
373 memcpy(p, s, l);
374 memcpy(p, s, l);
374 p += 20;
375 p += 20;
375
376
376 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
377 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
377 dirstateTupleObject *tuple;
378 dirstateTupleObject *tuple;
378 char state;
379 char state;
379 int mode, size, mtime;
380 int mode, size, mtime;
380 Py_ssize_t len, l;
381 Py_ssize_t len, l;
381 PyObject *o;
382 PyObject *o;
382 char *t;
383 char *t;
383
384
384 if (!dirstate_tuple_check(v)) {
385 if (!dirstate_tuple_check(v)) {
385 PyErr_SetString(PyExc_TypeError,
386 PyErr_SetString(PyExc_TypeError,
386 "expected a dirstate tuple");
387 "expected a dirstate tuple");
387 goto bail;
388 goto bail;
388 }
389 }
389 tuple = (dirstateTupleObject *)v;
390 tuple = (dirstateTupleObject *)v;
390
391
391 state = tuple->state;
392 state = tuple->state;
392 mode = tuple->mode;
393 mode = tuple->mode;
393 size = tuple->size;
394 size = tuple->size;
394 mtime = tuple->mtime;
395 mtime = tuple->mtime;
395 if (state == 'n' && mtime == now) {
396 if (state == 'n' && mtime == now) {
396 /* See pure/parsers.py:pack_dirstate for why we do
397 /* See pure/parsers.py:pack_dirstate for why we do
397 * this. */
398 * this. */
398 mtime = -1;
399 mtime = -1;
399 mtime_unset = (PyObject *)make_dirstate_tuple(
400 mtime_unset = (PyObject *)make_dirstate_tuple(
400 state, mode, size, mtime);
401 state, mode, size, mtime);
401 if (!mtime_unset) {
402 if (!mtime_unset) {
402 goto bail;
403 goto bail;
403 }
404 }
404 if (PyDict_SetItem(map, k, mtime_unset) == -1) {
405 if (PyDict_SetItem(map, k, mtime_unset) == -1) {
405 goto bail;
406 goto bail;
406 }
407 }
407 Py_DECREF(mtime_unset);
408 Py_DECREF(mtime_unset);
408 mtime_unset = NULL;
409 mtime_unset = NULL;
409 }
410 }
410 *p++ = state;
411 *p++ = state;
411 putbe32((uint32_t)mode, p);
412 putbe32((uint32_t)mode, p);
412 putbe32((uint32_t)size, p + 4);
413 putbe32((uint32_t)size, p + 4);
413 putbe32((uint32_t)mtime, p + 8);
414 putbe32((uint32_t)mtime, p + 8);
414 t = p + 12;
415 t = p + 12;
415 p += 16;
416 p += 16;
416 len = PyBytes_GET_SIZE(k);
417 len = PyBytes_GET_SIZE(k);
417 memcpy(p, PyBytes_AS_STRING(k), len);
418 memcpy(p, PyBytes_AS_STRING(k), len);
418 p += len;
419 p += len;
419 o = PyDict_GetItem(copymap, k);
420 o = PyDict_GetItem(copymap, k);
420 if (o) {
421 if (o) {
421 *p++ = '\0';
422 *p++ = '\0';
422 l = PyBytes_GET_SIZE(o);
423 l = PyBytes_GET_SIZE(o);
423 memcpy(p, PyBytes_AS_STRING(o), l);
424 memcpy(p, PyBytes_AS_STRING(o), l);
424 p += l;
425 p += l;
425 len += l + 1;
426 len += l + 1;
426 }
427 }
427 putbe32((uint32_t)len, t);
428 putbe32((uint32_t)len, t);
428 }
429 }
429
430
430 pos = p - PyBytes_AS_STRING(packobj);
431 pos = p - PyBytes_AS_STRING(packobj);
431 if (pos != nbytes) {
432 if (pos != nbytes) {
432 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
433 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
433 (long)pos, (long)nbytes);
434 (long)pos, (long)nbytes);
434 goto bail;
435 goto bail;
435 }
436 }
436
437
437 return packobj;
438 return packobj;
438 bail:
439 bail:
439 Py_XDECREF(mtime_unset);
440 Py_XDECREF(mtime_unset);
440 Py_XDECREF(packobj);
441 Py_XDECREF(packobj);
441 Py_XDECREF(v);
442 Py_XDECREF(v);
442 return NULL;
443 return NULL;
443 }
444 }
444
445
445 #define BUMPED_FIX 1
446 #define BUMPED_FIX 1
446 #define USING_SHA_256 2
447 #define USING_SHA_256 2
447 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
448 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
448
449
449 static PyObject *readshas(const char *source, unsigned char num,
450 static PyObject *readshas(const char *source, unsigned char num,
450 Py_ssize_t hashwidth)
451 Py_ssize_t hashwidth)
451 {
452 {
452 int i;
453 int i;
453 PyObject *list = PyTuple_New(num);
454 PyObject *list = PyTuple_New(num);
454 if (list == NULL) {
455 if (list == NULL) {
455 return NULL;
456 return NULL;
456 }
457 }
457 for (i = 0; i < num; i++) {
458 for (i = 0; i < num; i++) {
458 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
459 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
459 if (hash == NULL) {
460 if (hash == NULL) {
460 Py_DECREF(list);
461 Py_DECREF(list);
461 return NULL;
462 return NULL;
462 }
463 }
463 PyTuple_SET_ITEM(list, i, hash);
464 PyTuple_SET_ITEM(list, i, hash);
464 source += hashwidth;
465 source += hashwidth;
465 }
466 }
466 return list;
467 return list;
467 }
468 }
468
469
469 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
470 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
470 uint32_t *msize)
471 uint32_t *msize)
471 {
472 {
472 const char *data = databegin;
473 const char *data = databegin;
473 const char *meta;
474 const char *meta;
474
475
475 double mtime;
476 double mtime;
476 int16_t tz;
477 int16_t tz;
477 uint16_t flags;
478 uint16_t flags;
478 unsigned char nsuccs, nparents, nmetadata;
479 unsigned char nsuccs, nparents, nmetadata;
479 Py_ssize_t hashwidth = 20;
480 Py_ssize_t hashwidth = 20;
480
481
481 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
482 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
482 PyObject *metadata = NULL, *ret = NULL;
483 PyObject *metadata = NULL, *ret = NULL;
483 int i;
484 int i;
484
485
485 if (data + FM1_HEADER_SIZE > dataend) {
486 if (data + FM1_HEADER_SIZE > dataend) {
486 goto overflow;
487 goto overflow;
487 }
488 }
488
489
489 *msize = getbe32(data);
490 *msize = getbe32(data);
490 data += 4;
491 data += 4;
491 mtime = getbefloat64(data);
492 mtime = getbefloat64(data);
492 data += 8;
493 data += 8;
493 tz = getbeint16(data);
494 tz = getbeint16(data);
494 data += 2;
495 data += 2;
495 flags = getbeuint16(data);
496 flags = getbeuint16(data);
496 data += 2;
497 data += 2;
497
498
498 if (flags & USING_SHA_256) {
499 if (flags & USING_SHA_256) {
499 hashwidth = 32;
500 hashwidth = 32;
500 }
501 }
501
502
502 nsuccs = (unsigned char)(*data++);
503 nsuccs = (unsigned char)(*data++);
503 nparents = (unsigned char)(*data++);
504 nparents = (unsigned char)(*data++);
504 nmetadata = (unsigned char)(*data++);
505 nmetadata = (unsigned char)(*data++);
505
506
506 if (databegin + *msize > dataend) {
507 if (databegin + *msize > dataend) {
507 goto overflow;
508 goto overflow;
508 }
509 }
509 dataend = databegin + *msize; /* narrow down to marker size */
510 dataend = databegin + *msize; /* narrow down to marker size */
510
511
511 if (data + hashwidth > dataend) {
512 if (data + hashwidth > dataend) {
512 goto overflow;
513 goto overflow;
513 }
514 }
514 prec = PyBytes_FromStringAndSize(data, hashwidth);
515 prec = PyBytes_FromStringAndSize(data, hashwidth);
515 data += hashwidth;
516 data += hashwidth;
516 if (prec == NULL) {
517 if (prec == NULL) {
517 goto bail;
518 goto bail;
518 }
519 }
519
520
520 if (data + nsuccs * hashwidth > dataend) {
521 if (data + nsuccs * hashwidth > dataend) {
521 goto overflow;
522 goto overflow;
522 }
523 }
523 succs = readshas(data, nsuccs, hashwidth);
524 succs = readshas(data, nsuccs, hashwidth);
524 if (succs == NULL) {
525 if (succs == NULL) {
525 goto bail;
526 goto bail;
526 }
527 }
527 data += nsuccs * hashwidth;
528 data += nsuccs * hashwidth;
528
529
529 if (nparents == 1 || nparents == 2) {
530 if (nparents == 1 || nparents == 2) {
530 if (data + nparents * hashwidth > dataend) {
531 if (data + nparents * hashwidth > dataend) {
531 goto overflow;
532 goto overflow;
532 }
533 }
533 parents = readshas(data, nparents, hashwidth);
534 parents = readshas(data, nparents, hashwidth);
534 if (parents == NULL) {
535 if (parents == NULL) {
535 goto bail;
536 goto bail;
536 }
537 }
537 data += nparents * hashwidth;
538 data += nparents * hashwidth;
538 } else {
539 } else {
539 parents = Py_None;
540 parents = Py_None;
540 Py_INCREF(parents);
541 Py_INCREF(parents);
541 }
542 }
542
543
543 if (data + 2 * nmetadata > dataend) {
544 if (data + 2 * nmetadata > dataend) {
544 goto overflow;
545 goto overflow;
545 }
546 }
546 meta = data + (2 * nmetadata);
547 meta = data + (2 * nmetadata);
547 metadata = PyTuple_New(nmetadata);
548 metadata = PyTuple_New(nmetadata);
548 if (metadata == NULL) {
549 if (metadata == NULL) {
549 goto bail;
550 goto bail;
550 }
551 }
551 for (i = 0; i < nmetadata; i++) {
552 for (i = 0; i < nmetadata; i++) {
552 PyObject *tmp, *left = NULL, *right = NULL;
553 PyObject *tmp, *left = NULL, *right = NULL;
553 Py_ssize_t leftsize = (unsigned char)(*data++);
554 Py_ssize_t leftsize = (unsigned char)(*data++);
554 Py_ssize_t rightsize = (unsigned char)(*data++);
555 Py_ssize_t rightsize = (unsigned char)(*data++);
555 if (meta + leftsize + rightsize > dataend) {
556 if (meta + leftsize + rightsize > dataend) {
556 goto overflow;
557 goto overflow;
557 }
558 }
558 left = PyBytes_FromStringAndSize(meta, leftsize);
559 left = PyBytes_FromStringAndSize(meta, leftsize);
559 meta += leftsize;
560 meta += leftsize;
560 right = PyBytes_FromStringAndSize(meta, rightsize);
561 right = PyBytes_FromStringAndSize(meta, rightsize);
561 meta += rightsize;
562 meta += rightsize;
562 tmp = PyTuple_New(2);
563 tmp = PyTuple_New(2);
563 if (!left || !right || !tmp) {
564 if (!left || !right || !tmp) {
564 Py_XDECREF(left);
565 Py_XDECREF(left);
565 Py_XDECREF(right);
566 Py_XDECREF(right);
566 Py_XDECREF(tmp);
567 Py_XDECREF(tmp);
567 goto bail;
568 goto bail;
568 }
569 }
569 PyTuple_SET_ITEM(tmp, 0, left);
570 PyTuple_SET_ITEM(tmp, 0, left);
570 PyTuple_SET_ITEM(tmp, 1, right);
571 PyTuple_SET_ITEM(tmp, 1, right);
571 PyTuple_SET_ITEM(metadata, i, tmp);
572 PyTuple_SET_ITEM(metadata, i, tmp);
572 }
573 }
573 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
574 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
574 (int)tz * 60, parents);
575 (int)tz * 60, parents);
575 goto bail; /* return successfully */
576 goto bail; /* return successfully */
576
577
577 overflow:
578 overflow:
578 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
579 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
579 bail:
580 bail:
580 Py_XDECREF(prec);
581 Py_XDECREF(prec);
581 Py_XDECREF(succs);
582 Py_XDECREF(succs);
582 Py_XDECREF(metadata);
583 Py_XDECREF(metadata);
583 Py_XDECREF(parents);
584 Py_XDECREF(parents);
584 return ret;
585 return ret;
585 }
586 }
586
587
587 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
588 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
588 {
589 {
589 const char *data, *dataend;
590 const char *data, *dataend;
590 Py_ssize_t datalen, offset, stop;
591 Py_ssize_t datalen, offset, stop;
591 PyObject *markers = NULL;
592 PyObject *markers = NULL;
592
593
593 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
594 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
594 &offset, &stop)) {
595 &offset, &stop)) {
595 return NULL;
596 return NULL;
596 }
597 }
597 if (offset < 0) {
598 if (offset < 0) {
598 PyErr_SetString(PyExc_ValueError,
599 PyErr_SetString(PyExc_ValueError,
599 "invalid negative offset in fm1readmarkers");
600 "invalid negative offset in fm1readmarkers");
600 return NULL;
601 return NULL;
601 }
602 }
602 if (stop > datalen) {
603 if (stop > datalen) {
603 PyErr_SetString(
604 PyErr_SetString(
604 PyExc_ValueError,
605 PyExc_ValueError,
605 "stop longer than data length in fm1readmarkers");
606 "stop longer than data length in fm1readmarkers");
606 return NULL;
607 return NULL;
607 }
608 }
608 dataend = data + datalen;
609 dataend = data + datalen;
609 data += offset;
610 data += offset;
610 markers = PyList_New(0);
611 markers = PyList_New(0);
611 if (!markers) {
612 if (!markers) {
612 return NULL;
613 return NULL;
613 }
614 }
614 while (offset < stop) {
615 while (offset < stop) {
615 uint32_t msize;
616 uint32_t msize;
616 int error;
617 int error;
617 PyObject *record = fm1readmarker(data, dataend, &msize);
618 PyObject *record = fm1readmarker(data, dataend, &msize);
618 if (!record) {
619 if (!record) {
619 goto bail;
620 goto bail;
620 }
621 }
621 error = PyList_Append(markers, record);
622 error = PyList_Append(markers, record);
622 Py_DECREF(record);
623 Py_DECREF(record);
623 if (error) {
624 if (error) {
624 goto bail;
625 goto bail;
625 }
626 }
626 data += msize;
627 data += msize;
627 offset += msize;
628 offset += msize;
628 }
629 }
629 return markers;
630 return markers;
630 bail:
631 bail:
631 Py_DECREF(markers);
632 Py_DECREF(markers);
632 return NULL;
633 return NULL;
633 }
634 }
634
635
635 static char parsers_doc[] = "Efficient content parsing.";
636 static char parsers_doc[] = "Efficient content parsing.";
636
637
637 PyObject *encodedir(PyObject *self, PyObject *args);
638 PyObject *encodedir(PyObject *self, PyObject *args);
638 PyObject *pathencode(PyObject *self, PyObject *args);
639 PyObject *pathencode(PyObject *self, PyObject *args);
639 PyObject *lowerencode(PyObject *self, PyObject *args);
640 PyObject *lowerencode(PyObject *self, PyObject *args);
640 PyObject *parse_index2(PyObject *self, PyObject *args);
641 PyObject *parse_index2(PyObject *self, PyObject *args);
641
642
642 static PyMethodDef methods[] = {
643 static PyMethodDef methods[] = {
643 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
644 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
644 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
645 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
645 "create a set containing non-normal and other parent entries of given "
646 "create a set containing non-normal and other parent entries of given "
646 "dirstate\n"},
647 "dirstate\n"},
647 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
648 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
648 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
649 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
649 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
650 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
650 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
651 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
651 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
652 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
652 {"dict_new_presized", dict_new_presized, METH_VARARGS,
653 {"dict_new_presized", dict_new_presized, METH_VARARGS,
653 "construct a dict with an expected size\n"},
654 "construct a dict with an expected size\n"},
654 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
655 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
655 "make file foldmap\n"},
656 "make file foldmap\n"},
656 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
657 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
657 "escape a UTF-8 byte string to JSON (fast path)\n"},
658 "escape a UTF-8 byte string to JSON (fast path)\n"},
658 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
659 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
659 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
660 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
660 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
661 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
661 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
662 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
662 "parse v1 obsolete markers\n"},
663 "parse v1 obsolete markers\n"},
663 {NULL, NULL}};
664 {NULL, NULL}};
664
665
665 void dirs_module_init(PyObject *mod);
666 void dirs_module_init(PyObject *mod);
666 void manifest_module_init(PyObject *mod);
667 void manifest_module_init(PyObject *mod);
667 void revlog_module_init(PyObject *mod);
668 void revlog_module_init(PyObject *mod);
668
669
669 static const int version = 12;
670 static const int version = 12;
670
671
671 static void module_init(PyObject *mod)
672 static void module_init(PyObject *mod)
672 {
673 {
673 PyModule_AddIntConstant(mod, "version", version);
674 PyModule_AddIntConstant(mod, "version", version);
674
675
675 /* This module constant has two purposes. First, it lets us unit test
676 /* This module constant has two purposes. First, it lets us unit test
676 * the ImportError raised without hard-coding any error text. This
677 * the ImportError raised without hard-coding any error text. This
677 * means we can change the text in the future without breaking tests,
678 * means we can change the text in the future without breaking tests,
678 * even across changesets without a recompile. Second, its presence
679 * even across changesets without a recompile. Second, its presence
679 * can be used to determine whether the version-checking logic is
680 * can be used to determine whether the version-checking logic is
680 * present, which also helps in testing across changesets without a
681 * present, which also helps in testing across changesets without a
681 * recompile. Note that this means the pure-Python version of parsers
682 * recompile. Note that this means the pure-Python version of parsers
682 * should not have this module constant. */
683 * should not have this module constant. */
683 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
684 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
684
685
685 dirs_module_init(mod);
686 dirs_module_init(mod);
686 manifest_module_init(mod);
687 manifest_module_init(mod);
687 revlog_module_init(mod);
688 revlog_module_init(mod);
688
689
689 if (PyType_Ready(&dirstateTupleType) < 0) {
690 if (PyType_Ready(&dirstateTupleType) < 0) {
690 return;
691 return;
691 }
692 }
692 Py_INCREF(&dirstateTupleType);
693 Py_INCREF(&dirstateTupleType);
693 PyModule_AddObject(mod, "dirstatetuple",
694 PyModule_AddObject(mod, "dirstatetuple",
694 (PyObject *)&dirstateTupleType);
695 (PyObject *)&dirstateTupleType);
695 }
696 }
696
697
697 static int check_python_version(void)
698 static int check_python_version(void)
698 {
699 {
699 PyObject *sys = PyImport_ImportModule("sys"), *ver;
700 PyObject *sys = PyImport_ImportModule("sys"), *ver;
700 long hexversion;
701 long hexversion;
701 if (!sys) {
702 if (!sys) {
702 return -1;
703 return -1;
703 }
704 }
704 ver = PyObject_GetAttrString(sys, "hexversion");
705 ver = PyObject_GetAttrString(sys, "hexversion");
705 Py_DECREF(sys);
706 Py_DECREF(sys);
706 if (!ver) {
707 if (!ver) {
707 return -1;
708 return -1;
708 }
709 }
709 hexversion = PyInt_AsLong(ver);
710 hexversion = PyInt_AsLong(ver);
710 Py_DECREF(ver);
711 Py_DECREF(ver);
711 /* sys.hexversion is a 32-bit number by default, so the -1 case
712 /* sys.hexversion is a 32-bit number by default, so the -1 case
712 * should only occur in unusual circumstances (e.g. if sys.hexversion
713 * should only occur in unusual circumstances (e.g. if sys.hexversion
713 * is manually set to an invalid value). */
714 * is manually set to an invalid value). */
714 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
715 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
715 PyErr_Format(PyExc_ImportError,
716 PyErr_Format(PyExc_ImportError,
716 "%s: The Mercurial extension "
717 "%s: The Mercurial extension "
717 "modules were compiled with Python " PY_VERSION
718 "modules were compiled with Python " PY_VERSION
718 ", but "
719 ", but "
719 "Mercurial is currently using Python with "
720 "Mercurial is currently using Python with "
720 "sys.hexversion=%ld: "
721 "sys.hexversion=%ld: "
721 "Python %s\n at: %s",
722 "Python %s\n at: %s",
722 versionerrortext, hexversion, Py_GetVersion(),
723 versionerrortext, hexversion, Py_GetVersion(),
723 Py_GetProgramFullPath());
724 Py_GetProgramFullPath());
724 return -1;
725 return -1;
725 }
726 }
726 return 0;
727 return 0;
727 }
728 }
728
729
729 #ifdef IS_PY3K
730 #ifdef IS_PY3K
730 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
731 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
731 parsers_doc, -1, methods};
732 parsers_doc, -1, methods};
732
733
733 PyMODINIT_FUNC PyInit_parsers(void)
734 PyMODINIT_FUNC PyInit_parsers(void)
734 {
735 {
735 PyObject *mod;
736 PyObject *mod;
736
737
737 if (check_python_version() == -1)
738 if (check_python_version() == -1)
738 return NULL;
739 return NULL;
739 mod = PyModule_Create(&parsers_module);
740 mod = PyModule_Create(&parsers_module);
740 module_init(mod);
741 module_init(mod);
741 return mod;
742 return mod;
742 }
743 }
743 #else
744 #else
744 PyMODINIT_FUNC initparsers(void)
745 PyMODINIT_FUNC initparsers(void)
745 {
746 {
746 PyObject *mod;
747 PyObject *mod;
747
748
748 if (check_python_version() == -1) {
749 if (check_python_version() == -1) {
749 return;
750 return;
750 }
751 }
751 mod = Py_InitModule3("parsers", methods, parsers_doc);
752 mod = Py_InitModule3("parsers", methods, parsers_doc);
752 module_init(mod);
753 module_init(mod);
753 }
754 }
754 #endif
755 #endif
@@ -1,3040 +1,3041 b''
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 #define PY_SSIZE_T_CLEAN
10 #define PY_SSIZE_T_CLEAN
11 #include <Python.h>
11 #include <Python.h>
12 #include <assert.h>
12 #include <assert.h>
13 #include <ctype.h>
13 #include <ctype.h>
14 #include <limits.h>
14 #include <limits.h>
15 #include <stddef.h>
15 #include <stddef.h>
16 #include <stdlib.h>
16 #include <stdlib.h>
17 #include <string.h>
17 #include <string.h>
18
18
19 #include "bitmanipulation.h"
19 #include "bitmanipulation.h"
20 #include "charencode.h"
20 #include "charencode.h"
21 #include "revlog.h"
21 #include "revlog.h"
22 #include "util.h"
22 #include "util.h"
23
23
24 #ifdef IS_PY3K
24 #ifdef IS_PY3K
25 /* The mapping of Python types is meant to be temporary to get Python
25 /* The mapping of Python types is meant to be temporary to get Python
26 * 3 to compile. We should remove this once Python 3 support is fully
26 * 3 to compile. We should remove this once Python 3 support is fully
27 * supported and proper types are used in the extensions themselves. */
27 * supported and proper types are used in the extensions themselves. */
28 #define PyInt_Check PyLong_Check
28 #define PyInt_Check PyLong_Check
29 #define PyInt_FromLong PyLong_FromLong
29 #define PyInt_FromLong PyLong_FromLong
30 #define PyInt_FromSsize_t PyLong_FromSsize_t
30 #define PyInt_FromSsize_t PyLong_FromSsize_t
31 #define PyInt_AsLong PyLong_AsLong
31 #define PyInt_AsLong PyLong_AsLong
32 #endif
32 #endif
33
33
34 typedef struct indexObjectStruct indexObject;
34 typedef struct indexObjectStruct indexObject;
35
35
36 typedef struct {
36 typedef struct {
37 int children[16];
37 int children[16];
38 } nodetreenode;
38 } nodetreenode;
39
39
40 /*
40 /*
41 * A base-16 trie for fast node->rev mapping.
41 * A base-16 trie for fast node->rev mapping.
42 *
42 *
43 * Positive value is index of the next node in the trie
43 * Positive value is index of the next node in the trie
44 * Negative value is a leaf: -(rev + 2)
44 * Negative value is a leaf: -(rev + 2)
45 * Zero is empty
45 * Zero is empty
46 */
46 */
47 typedef struct {
47 typedef struct {
48 indexObject *index;
48 indexObject *index;
49 nodetreenode *nodes;
49 nodetreenode *nodes;
50 unsigned length; /* # nodes in use */
50 unsigned length; /* # nodes in use */
51 unsigned capacity; /* # nodes allocated */
51 unsigned capacity; /* # nodes allocated */
52 int depth; /* maximum depth of tree */
52 int depth; /* maximum depth of tree */
53 int splits; /* # splits performed */
53 int splits; /* # splits performed */
54 } nodetree;
54 } nodetree;
55
55
56 typedef struct {
56 typedef struct {
57 PyObject_HEAD /* ; */
57 PyObject_HEAD /* ; */
58 nodetree nt;
58 nodetree nt;
59 } nodetreeObject;
59 } nodetreeObject;
60
60
61 /*
61 /*
62 * This class has two behaviors.
62 * This class has two behaviors.
63 *
63 *
64 * When used in a list-like way (with integer keys), we decode an
64 * When used in a list-like way (with integer keys), we decode an
65 * entry in a RevlogNG index file on demand. Our last entry is a
65 * entry in a RevlogNG index file on demand. Our last entry is a
66 * sentinel, always a nullid. We have limited support for
66 * sentinel, always a nullid. We have limited support for
67 * integer-keyed insert and delete, only at elements right before the
67 * integer-keyed insert and delete, only at elements right before the
68 * sentinel.
68 * sentinel.
69 *
69 *
70 * With string keys, we lazily perform a reverse mapping from node to
70 * With string keys, we lazily perform a reverse mapping from node to
71 * rev, using a base-16 trie.
71 * rev, using a base-16 trie.
72 */
72 */
73 struct indexObjectStruct {
73 struct indexObjectStruct {
74 PyObject_HEAD
74 PyObject_HEAD
75 /* Type-specific fields go here. */
75 /* Type-specific fields go here. */
76 PyObject *data; /* raw bytes of index */
76 PyObject *data; /* raw bytes of index */
77 Py_buffer buf; /* buffer of data */
77 Py_buffer buf; /* buffer of data */
78 PyObject **cache; /* cached tuples */
78 PyObject **cache; /* cached tuples */
79 const char **offsets; /* populated on demand */
79 const char **offsets; /* populated on demand */
80 Py_ssize_t raw_length; /* original number of elements */
80 Py_ssize_t raw_length; /* original number of elements */
81 Py_ssize_t length; /* current number of elements */
81 Py_ssize_t length; /* current number of elements */
82 PyObject *added; /* populated on demand */
82 PyObject *added; /* populated on demand */
83 PyObject *headrevs; /* cache, invalidated on changes */
83 PyObject *headrevs; /* cache, invalidated on changes */
84 PyObject *filteredrevs; /* filtered revs set */
84 PyObject *filteredrevs; /* filtered revs set */
85 nodetree nt; /* base-16 trie */
85 nodetree nt; /* base-16 trie */
86 int ntinitialized; /* 0 or 1 */
86 int ntinitialized; /* 0 or 1 */
87 int ntrev; /* last rev scanned */
87 int ntrev; /* last rev scanned */
88 int ntlookups; /* # lookups */
88 int ntlookups; /* # lookups */
89 int ntmisses; /* # lookups that miss the cache */
89 int ntmisses; /* # lookups that miss the cache */
90 int inlined;
90 int inlined;
91 };
91 };
92
92
93 static Py_ssize_t index_length(const indexObject *self)
93 static Py_ssize_t index_length(const indexObject *self)
94 {
94 {
95 if (self->added == NULL)
95 if (self->added == NULL)
96 return self->length;
96 return self->length;
97 return self->length + PyList_GET_SIZE(self->added);
97 return self->length + PyList_GET_SIZE(self->added);
98 }
98 }
99
99
100 static PyObject *nullentry = NULL;
100 static PyObject *nullentry = NULL;
101 static const char nullid[20] = {0};
101 static const char nullid[20] = {0};
102 static const Py_ssize_t nullrev = -1;
102 static const Py_ssize_t nullrev = -1;
103
103
104 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
104 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
105
105
106 #if LONG_MAX == 0x7fffffffL
106 #if LONG_MAX == 0x7fffffffL
107 static const char *const tuple_format = PY23("Kiiiiiis#", "Kiiiiiiy#");
107 static const char *const tuple_format = PY23("Kiiiiiis#", "Kiiiiiiy#");
108 #else
108 #else
109 static const char *const tuple_format = PY23("kiiiiiis#", "kiiiiiiy#");
109 static const char *const tuple_format = PY23("kiiiiiis#", "kiiiiiiy#");
110 #endif
110 #endif
111
111
112 /* A RevlogNG v1 index entry is 64 bytes long. */
112 /* A RevlogNG v1 index entry is 64 bytes long. */
113 static const long v1_hdrsize = 64;
113 static const long v1_hdrsize = 64;
114
114
115 static void raise_revlog_error(void)
115 static void raise_revlog_error(void)
116 {
116 {
117 PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
117 PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
118
118
119 mod = PyImport_ImportModule("mercurial.error");
119 mod = PyImport_ImportModule("mercurial.error");
120 if (mod == NULL) {
120 if (mod == NULL) {
121 goto cleanup;
121 goto cleanup;
122 }
122 }
123
123
124 dict = PyModule_GetDict(mod);
124 dict = PyModule_GetDict(mod);
125 if (dict == NULL) {
125 if (dict == NULL) {
126 goto cleanup;
126 goto cleanup;
127 }
127 }
128 Py_INCREF(dict);
128 Py_INCREF(dict);
129
129
130 errclass = PyDict_GetItemString(dict, "RevlogError");
130 errclass = PyDict_GetItemString(dict, "RevlogError");
131 if (errclass == NULL) {
131 if (errclass == NULL) {
132 PyErr_SetString(PyExc_SystemError,
132 PyErr_SetString(PyExc_SystemError,
133 "could not find RevlogError");
133 "could not find RevlogError");
134 goto cleanup;
134 goto cleanup;
135 }
135 }
136
136
137 /* value of exception is ignored by callers */
137 /* value of exception is ignored by callers */
138 PyErr_SetString(errclass, "RevlogError");
138 PyErr_SetString(errclass, "RevlogError");
139
139
140 cleanup:
140 cleanup:
141 Py_XDECREF(dict);
141 Py_XDECREF(dict);
142 Py_XDECREF(mod);
142 Py_XDECREF(mod);
143 }
143 }
144
144
145 /*
145 /*
146 * Return a pointer to the beginning of a RevlogNG record.
146 * Return a pointer to the beginning of a RevlogNG record.
147 */
147 */
148 static const char *index_deref(indexObject *self, Py_ssize_t pos)
148 static const char *index_deref(indexObject *self, Py_ssize_t pos)
149 {
149 {
150 if (self->inlined && pos > 0) {
150 if (self->inlined && pos > 0) {
151 if (self->offsets == NULL) {
151 if (self->offsets == NULL) {
152 self->offsets = PyMem_Malloc(self->raw_length *
152 self->offsets = PyMem_Malloc(self->raw_length *
153 sizeof(*self->offsets));
153 sizeof(*self->offsets));
154 if (self->offsets == NULL)
154 if (self->offsets == NULL)
155 return (const char *)PyErr_NoMemory();
155 return (const char *)PyErr_NoMemory();
156 inline_scan(self, self->offsets);
156 inline_scan(self, self->offsets);
157 }
157 }
158 return self->offsets[pos];
158 return self->offsets[pos];
159 }
159 }
160
160
161 return (const char *)(self->buf.buf) + pos * v1_hdrsize;
161 return (const char *)(self->buf.buf) + pos * v1_hdrsize;
162 }
162 }
163
163
164 /*
164 /*
165 * Get parents of the given rev.
165 * Get parents of the given rev.
166 *
166 *
167 * The specified rev must be valid and must not be nullrev. A returned
167 * The specified rev must be valid and must not be nullrev. A returned
168 * parent revision may be nullrev, but is guaranteed to be in valid range.
168 * parent revision may be nullrev, but is guaranteed to be in valid range.
169 */
169 */
170 static inline int index_get_parents(indexObject *self, Py_ssize_t rev, int *ps,
170 static inline int index_get_parents(indexObject *self, Py_ssize_t rev, int *ps,
171 int maxrev)
171 int maxrev)
172 {
172 {
173 if (rev >= self->length) {
173 if (rev >= self->length) {
174 long tmp;
174 long tmp;
175 PyObject *tuple =
175 PyObject *tuple =
176 PyList_GET_ITEM(self->added, rev - self->length);
176 PyList_GET_ITEM(self->added, rev - self->length);
177 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 5), &tmp)) {
177 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 5), &tmp)) {
178 return -1;
178 return -1;
179 }
179 }
180 ps[0] = (int)tmp;
180 ps[0] = (int)tmp;
181 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 6), &tmp)) {
181 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 6), &tmp)) {
182 return -1;
182 return -1;
183 }
183 }
184 ps[1] = (int)tmp;
184 ps[1] = (int)tmp;
185 } else {
185 } else {
186 const char *data = index_deref(self, rev);
186 const char *data = index_deref(self, rev);
187 ps[0] = getbe32(data + 24);
187 ps[0] = getbe32(data + 24);
188 ps[1] = getbe32(data + 28);
188 ps[1] = getbe32(data + 28);
189 }
189 }
190 /* If index file is corrupted, ps[] may point to invalid revisions. So
190 /* If index file is corrupted, ps[] may point to invalid revisions. So
191 * there is a risk of buffer overflow to trust them unconditionally. */
191 * there is a risk of buffer overflow to trust them unconditionally. */
192 if (ps[0] < -1 || ps[0] > maxrev || ps[1] < -1 || ps[1] > maxrev) {
192 if (ps[0] < -1 || ps[0] > maxrev || ps[1] < -1 || ps[1] > maxrev) {
193 PyErr_SetString(PyExc_ValueError, "parent out of range");
193 PyErr_SetString(PyExc_ValueError, "parent out of range");
194 return -1;
194 return -1;
195 }
195 }
196 return 0;
196 return 0;
197 }
197 }
198
198
199 /*
199 /*
200 * Get parents of the given rev.
200 * Get parents of the given rev.
201 *
201 *
202 * If the specified rev is out of range, IndexError will be raised. If the
202 * If the specified rev is out of range, IndexError will be raised. If the
203 * revlog entry is corrupted, ValueError may be raised.
203 * revlog entry is corrupted, ValueError may be raised.
204 *
204 *
205 * Returns 0 on success or -1 on failure.
205 * Returns 0 on success or -1 on failure.
206 */
206 */
207 int HgRevlogIndex_GetParents(PyObject *op, int rev, int *ps)
207 int HgRevlogIndex_GetParents(PyObject *op, int rev, int *ps)
208 {
208 {
209 int tiprev;
209 int tiprev;
210 if (!op || !HgRevlogIndex_Check(op) || !ps) {
210 if (!op || !HgRevlogIndex_Check(op) || !ps) {
211 PyErr_BadInternalCall();
211 PyErr_BadInternalCall();
212 return -1;
212 return -1;
213 }
213 }
214 tiprev = (int)index_length((indexObject *)op) - 1;
214 tiprev = (int)index_length((indexObject *)op) - 1;
215 if (rev < -1 || rev > tiprev) {
215 if (rev < -1 || rev > tiprev) {
216 PyErr_Format(PyExc_IndexError, "rev out of range: %d", rev);
216 PyErr_Format(PyExc_IndexError, "rev out of range: %d", rev);
217 return -1;
217 return -1;
218 } else if (rev == -1) {
218 } else if (rev == -1) {
219 ps[0] = ps[1] = -1;
219 ps[0] = ps[1] = -1;
220 return 0;
220 return 0;
221 } else {
221 } else {
222 return index_get_parents((indexObject *)op, rev, ps, tiprev);
222 return index_get_parents((indexObject *)op, rev, ps, tiprev);
223 }
223 }
224 }
224 }
225
225
226 static inline int64_t index_get_start(indexObject *self, Py_ssize_t rev)
226 static inline int64_t index_get_start(indexObject *self, Py_ssize_t rev)
227 {
227 {
228 uint64_t offset;
228 uint64_t offset;
229 if (rev == nullrev) {
229 if (rev == nullrev) {
230 return 0;
230 return 0;
231 }
231 }
232 if (rev >= self->length) {
232 if (rev >= self->length) {
233 PyObject *tuple;
233 PyObject *tuple;
234 PyObject *pylong;
234 PyObject *pylong;
235 PY_LONG_LONG tmp;
235 PY_LONG_LONG tmp;
236 tuple = PyList_GET_ITEM(self->added, rev - self->length);
236 tuple = PyList_GET_ITEM(self->added, rev - self->length);
237 pylong = PyTuple_GET_ITEM(tuple, 0);
237 pylong = PyTuple_GET_ITEM(tuple, 0);
238 tmp = PyLong_AsLongLong(pylong);
238 tmp = PyLong_AsLongLong(pylong);
239 if (tmp == -1 && PyErr_Occurred()) {
239 if (tmp == -1 && PyErr_Occurred()) {
240 return -1;
240 return -1;
241 }
241 }
242 if (tmp < 0) {
242 if (tmp < 0) {
243 PyErr_Format(PyExc_OverflowError,
243 PyErr_Format(PyExc_OverflowError,
244 "revlog entry size out of bound (%lld)",
244 "revlog entry size out of bound (%lld)",
245 (long long)tmp);
245 (long long)tmp);
246 return -1;
246 return -1;
247 }
247 }
248 offset = (uint64_t)tmp;
248 offset = (uint64_t)tmp;
249 } else {
249 } else {
250 const char *data = index_deref(self, rev);
250 const char *data = index_deref(self, rev);
251 offset = getbe32(data + 4);
251 offset = getbe32(data + 4);
252 if (rev == 0) {
252 if (rev == 0) {
253 /* mask out version number for the first entry */
253 /* mask out version number for the first entry */
254 offset &= 0xFFFF;
254 offset &= 0xFFFF;
255 } else {
255 } else {
256 uint32_t offset_high = getbe32(data);
256 uint32_t offset_high = getbe32(data);
257 offset |= ((uint64_t)offset_high) << 32;
257 offset |= ((uint64_t)offset_high) << 32;
258 }
258 }
259 }
259 }
260 return (int64_t)(offset >> 16);
260 return (int64_t)(offset >> 16);
261 }
261 }
262
262
263 static inline int index_get_length(indexObject *self, Py_ssize_t rev)
263 static inline int index_get_length(indexObject *self, Py_ssize_t rev)
264 {
264 {
265 if (rev == nullrev) {
265 if (rev == nullrev) {
266 return 0;
266 return 0;
267 }
267 }
268 if (rev >= self->length) {
268 if (rev >= self->length) {
269 PyObject *tuple;
269 PyObject *tuple;
270 PyObject *pylong;
270 PyObject *pylong;
271 long ret;
271 long ret;
272 tuple = PyList_GET_ITEM(self->added, rev - self->length);
272 tuple = PyList_GET_ITEM(self->added, rev - self->length);
273 pylong = PyTuple_GET_ITEM(tuple, 1);
273 pylong = PyTuple_GET_ITEM(tuple, 1);
274 ret = PyInt_AsLong(pylong);
274 ret = PyInt_AsLong(pylong);
275 if (ret == -1 && PyErr_Occurred()) {
275 if (ret == -1 && PyErr_Occurred()) {
276 return -1;
276 return -1;
277 }
277 }
278 if (ret < 0 || ret > (long)INT_MAX) {
278 if (ret < 0 || ret > (long)INT_MAX) {
279 PyErr_Format(PyExc_OverflowError,
279 PyErr_Format(PyExc_OverflowError,
280 "revlog entry size out of bound (%ld)",
280 "revlog entry size out of bound (%ld)",
281 ret);
281 ret);
282 return -1;
282 return -1;
283 }
283 }
284 return (int)ret;
284 return (int)ret;
285 } else {
285 } else {
286 const char *data = index_deref(self, rev);
286 const char *data = index_deref(self, rev);
287 int tmp = (int)getbe32(data + 8);
287 int tmp = (int)getbe32(data + 8);
288 if (tmp < 0) {
288 if (tmp < 0) {
289 PyErr_Format(PyExc_OverflowError,
289 PyErr_Format(PyExc_OverflowError,
290 "revlog entry size out of bound (%d)",
290 "revlog entry size out of bound (%d)",
291 tmp);
291 tmp);
292 return -1;
292 return -1;
293 }
293 }
294 return tmp;
294 return tmp;
295 }
295 }
296 }
296 }
297
297
298 /*
298 /*
299 * RevlogNG format (all in big endian, data may be inlined):
299 * RevlogNG format (all in big endian, data may be inlined):
300 * 6 bytes: offset
300 * 6 bytes: offset
301 * 2 bytes: flags
301 * 2 bytes: flags
302 * 4 bytes: compressed length
302 * 4 bytes: compressed length
303 * 4 bytes: uncompressed length
303 * 4 bytes: uncompressed length
304 * 4 bytes: base revision
304 * 4 bytes: base revision
305 * 4 bytes: link revision
305 * 4 bytes: link revision
306 * 4 bytes: parent 1 revision
306 * 4 bytes: parent 1 revision
307 * 4 bytes: parent 2 revision
307 * 4 bytes: parent 2 revision
308 * 32 bytes: nodeid (only 20 bytes used)
308 * 32 bytes: nodeid (only 20 bytes used)
309 */
309 */
310 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
310 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
311 {
311 {
312 uint64_t offset_flags;
312 uint64_t offset_flags;
313 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
313 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
314 const char *c_node_id;
314 const char *c_node_id;
315 const char *data;
315 const char *data;
316 Py_ssize_t length = index_length(self);
316 Py_ssize_t length = index_length(self);
317 PyObject *entry;
317 PyObject *entry;
318
318
319 if (pos == nullrev) {
319 if (pos == nullrev) {
320 Py_INCREF(nullentry);
320 Py_INCREF(nullentry);
321 return nullentry;
321 return nullentry;
322 }
322 }
323
323
324 if (pos < 0 || pos >= length) {
324 if (pos < 0 || pos >= length) {
325 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
325 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
326 return NULL;
326 return NULL;
327 }
327 }
328
328
329 if (pos >= self->length) {
329 if (pos >= self->length) {
330 PyObject *obj;
330 PyObject *obj;
331 obj = PyList_GET_ITEM(self->added, pos - self->length);
331 obj = PyList_GET_ITEM(self->added, pos - self->length);
332 Py_INCREF(obj);
332 Py_INCREF(obj);
333 return obj;
333 return obj;
334 }
334 }
335
335
336 if (self->cache) {
336 if (self->cache) {
337 if (self->cache[pos]) {
337 if (self->cache[pos]) {
338 Py_INCREF(self->cache[pos]);
338 Py_INCREF(self->cache[pos]);
339 return self->cache[pos];
339 return self->cache[pos];
340 }
340 }
341 } else {
341 } else {
342 self->cache = calloc(self->raw_length, sizeof(PyObject *));
342 self->cache = calloc(self->raw_length, sizeof(PyObject *));
343 if (self->cache == NULL)
343 if (self->cache == NULL)
344 return PyErr_NoMemory();
344 return PyErr_NoMemory();
345 }
345 }
346
346
347 data = index_deref(self, pos);
347 data = index_deref(self, pos);
348 if (data == NULL)
348 if (data == NULL)
349 return NULL;
349 return NULL;
350
350
351 offset_flags = getbe32(data + 4);
351 offset_flags = getbe32(data + 4);
352 if (pos == 0) /* mask out version number for the first entry */
352 if (pos == 0) /* mask out version number for the first entry */
353 offset_flags &= 0xFFFF;
353 offset_flags &= 0xFFFF;
354 else {
354 else {
355 uint32_t offset_high = getbe32(data);
355 uint32_t offset_high = getbe32(data);
356 offset_flags |= ((uint64_t)offset_high) << 32;
356 offset_flags |= ((uint64_t)offset_high) << 32;
357 }
357 }
358
358
359 comp_len = getbe32(data + 8);
359 comp_len = getbe32(data + 8);
360 uncomp_len = getbe32(data + 12);
360 uncomp_len = getbe32(data + 12);
361 base_rev = getbe32(data + 16);
361 base_rev = getbe32(data + 16);
362 link_rev = getbe32(data + 20);
362 link_rev = getbe32(data + 20);
363 parent_1 = getbe32(data + 24);
363 parent_1 = getbe32(data + 24);
364 parent_2 = getbe32(data + 28);
364 parent_2 = getbe32(data + 28);
365 c_node_id = data + 32;
365 c_node_id = data + 32;
366
366
367 entry = Py_BuildValue(tuple_format, offset_flags, comp_len, uncomp_len,
367 entry = Py_BuildValue(tuple_format, offset_flags, comp_len, uncomp_len,
368 base_rev, link_rev, parent_1, parent_2, c_node_id,
368 base_rev, link_rev, parent_1, parent_2, c_node_id,
369 20);
369 (Py_ssize_t)20);
370
370
371 if (entry) {
371 if (entry) {
372 PyObject_GC_UnTrack(entry);
372 PyObject_GC_UnTrack(entry);
373 Py_INCREF(entry);
373 Py_INCREF(entry);
374 }
374 }
375
375
376 self->cache[pos] = entry;
376 self->cache[pos] = entry;
377
377
378 return entry;
378 return entry;
379 }
379 }
380
380
381 /*
381 /*
382 * Return the 20-byte SHA of the node corresponding to the given rev.
382 * Return the 20-byte SHA of the node corresponding to the given rev.
383 */
383 */
384 static const char *index_node(indexObject *self, Py_ssize_t pos)
384 static const char *index_node(indexObject *self, Py_ssize_t pos)
385 {
385 {
386 Py_ssize_t length = index_length(self);
386 Py_ssize_t length = index_length(self);
387 const char *data;
387 const char *data;
388
388
389 if (pos == nullrev)
389 if (pos == nullrev)
390 return nullid;
390 return nullid;
391
391
392 if (pos >= length)
392 if (pos >= length)
393 return NULL;
393 return NULL;
394
394
395 if (pos >= self->length) {
395 if (pos >= self->length) {
396 PyObject *tuple, *str;
396 PyObject *tuple, *str;
397 tuple = PyList_GET_ITEM(self->added, pos - self->length);
397 tuple = PyList_GET_ITEM(self->added, pos - self->length);
398 str = PyTuple_GetItem(tuple, 7);
398 str = PyTuple_GetItem(tuple, 7);
399 return str ? PyBytes_AS_STRING(str) : NULL;
399 return str ? PyBytes_AS_STRING(str) : NULL;
400 }
400 }
401
401
402 data = index_deref(self, pos);
402 data = index_deref(self, pos);
403 return data ? data + 32 : NULL;
403 return data ? data + 32 : NULL;
404 }
404 }
405
405
406 /*
406 /*
407 * Return the 20-byte SHA of the node corresponding to the given rev. The
407 * Return the 20-byte SHA of the node corresponding to the given rev. The
408 * rev is assumed to be existing. If not, an exception is set.
408 * rev is assumed to be existing. If not, an exception is set.
409 */
409 */
410 static const char *index_node_existing(indexObject *self, Py_ssize_t pos)
410 static const char *index_node_existing(indexObject *self, Py_ssize_t pos)
411 {
411 {
412 const char *node = index_node(self, pos);
412 const char *node = index_node(self, pos);
413 if (node == NULL) {
413 if (node == NULL) {
414 PyErr_Format(PyExc_IndexError, "could not access rev %d",
414 PyErr_Format(PyExc_IndexError, "could not access rev %d",
415 (int)pos);
415 (int)pos);
416 }
416 }
417 return node;
417 return node;
418 }
418 }
419
419
420 static int nt_insert(nodetree *self, const char *node, int rev);
420 static int nt_insert(nodetree *self, const char *node, int rev);
421
421
422 static int node_check(PyObject *obj, char **node)
422 static int node_check(PyObject *obj, char **node)
423 {
423 {
424 Py_ssize_t nodelen;
424 Py_ssize_t nodelen;
425 if (PyBytes_AsStringAndSize(obj, node, &nodelen) == -1)
425 if (PyBytes_AsStringAndSize(obj, node, &nodelen) == -1)
426 return -1;
426 return -1;
427 if (nodelen == 20)
427 if (nodelen == 20)
428 return 0;
428 return 0;
429 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
429 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
430 return -1;
430 return -1;
431 }
431 }
432
432
433 static PyObject *index_append(indexObject *self, PyObject *obj)
433 static PyObject *index_append(indexObject *self, PyObject *obj)
434 {
434 {
435 char *node;
435 char *node;
436 Py_ssize_t len;
436 Py_ssize_t len;
437
437
438 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
438 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
439 PyErr_SetString(PyExc_TypeError, "8-tuple required");
439 PyErr_SetString(PyExc_TypeError, "8-tuple required");
440 return NULL;
440 return NULL;
441 }
441 }
442
442
443 if (node_check(PyTuple_GET_ITEM(obj, 7), &node) == -1)
443 if (node_check(PyTuple_GET_ITEM(obj, 7), &node) == -1)
444 return NULL;
444 return NULL;
445
445
446 len = index_length(self);
446 len = index_length(self);
447
447
448 if (self->added == NULL) {
448 if (self->added == NULL) {
449 self->added = PyList_New(0);
449 self->added = PyList_New(0);
450 if (self->added == NULL)
450 if (self->added == NULL)
451 return NULL;
451 return NULL;
452 }
452 }
453
453
454 if (PyList_Append(self->added, obj) == -1)
454 if (PyList_Append(self->added, obj) == -1)
455 return NULL;
455 return NULL;
456
456
457 if (self->ntinitialized)
457 if (self->ntinitialized)
458 nt_insert(&self->nt, node, (int)len);
458 nt_insert(&self->nt, node, (int)len);
459
459
460 Py_CLEAR(self->headrevs);
460 Py_CLEAR(self->headrevs);
461 Py_RETURN_NONE;
461 Py_RETURN_NONE;
462 }
462 }
463
463
464 static PyObject *index_stats(indexObject *self)
464 static PyObject *index_stats(indexObject *self)
465 {
465 {
466 PyObject *obj = PyDict_New();
466 PyObject *obj = PyDict_New();
467 PyObject *s = NULL;
467 PyObject *s = NULL;
468 PyObject *t = NULL;
468 PyObject *t = NULL;
469
469
470 if (obj == NULL)
470 if (obj == NULL)
471 return NULL;
471 return NULL;
472
472
473 #define istat(__n, __d) \
473 #define istat(__n, __d) \
474 do { \
474 do { \
475 s = PyBytes_FromString(__d); \
475 s = PyBytes_FromString(__d); \
476 t = PyInt_FromSsize_t(self->__n); \
476 t = PyInt_FromSsize_t(self->__n); \
477 if (!s || !t) \
477 if (!s || !t) \
478 goto bail; \
478 goto bail; \
479 if (PyDict_SetItem(obj, s, t) == -1) \
479 if (PyDict_SetItem(obj, s, t) == -1) \
480 goto bail; \
480 goto bail; \
481 Py_CLEAR(s); \
481 Py_CLEAR(s); \
482 Py_CLEAR(t); \
482 Py_CLEAR(t); \
483 } while (0)
483 } while (0)
484
484
485 if (self->added) {
485 if (self->added) {
486 Py_ssize_t len = PyList_GET_SIZE(self->added);
486 Py_ssize_t len = PyList_GET_SIZE(self->added);
487 s = PyBytes_FromString("index entries added");
487 s = PyBytes_FromString("index entries added");
488 t = PyInt_FromSsize_t(len);
488 t = PyInt_FromSsize_t(len);
489 if (!s || !t)
489 if (!s || !t)
490 goto bail;
490 goto bail;
491 if (PyDict_SetItem(obj, s, t) == -1)
491 if (PyDict_SetItem(obj, s, t) == -1)
492 goto bail;
492 goto bail;
493 Py_CLEAR(s);
493 Py_CLEAR(s);
494 Py_CLEAR(t);
494 Py_CLEAR(t);
495 }
495 }
496
496
497 if (self->raw_length != self->length)
497 if (self->raw_length != self->length)
498 istat(raw_length, "revs on disk");
498 istat(raw_length, "revs on disk");
499 istat(length, "revs in memory");
499 istat(length, "revs in memory");
500 istat(ntlookups, "node trie lookups");
500 istat(ntlookups, "node trie lookups");
501 istat(ntmisses, "node trie misses");
501 istat(ntmisses, "node trie misses");
502 istat(ntrev, "node trie last rev scanned");
502 istat(ntrev, "node trie last rev scanned");
503 if (self->ntinitialized) {
503 if (self->ntinitialized) {
504 istat(nt.capacity, "node trie capacity");
504 istat(nt.capacity, "node trie capacity");
505 istat(nt.depth, "node trie depth");
505 istat(nt.depth, "node trie depth");
506 istat(nt.length, "node trie count");
506 istat(nt.length, "node trie count");
507 istat(nt.splits, "node trie splits");
507 istat(nt.splits, "node trie splits");
508 }
508 }
509
509
510 #undef istat
510 #undef istat
511
511
512 return obj;
512 return obj;
513
513
514 bail:
514 bail:
515 Py_XDECREF(obj);
515 Py_XDECREF(obj);
516 Py_XDECREF(s);
516 Py_XDECREF(s);
517 Py_XDECREF(t);
517 Py_XDECREF(t);
518 return NULL;
518 return NULL;
519 }
519 }
520
520
521 /*
521 /*
522 * When we cache a list, we want to be sure the caller can't mutate
522 * When we cache a list, we want to be sure the caller can't mutate
523 * the cached copy.
523 * the cached copy.
524 */
524 */
525 static PyObject *list_copy(PyObject *list)
525 static PyObject *list_copy(PyObject *list)
526 {
526 {
527 Py_ssize_t len = PyList_GET_SIZE(list);
527 Py_ssize_t len = PyList_GET_SIZE(list);
528 PyObject *newlist = PyList_New(len);
528 PyObject *newlist = PyList_New(len);
529 Py_ssize_t i;
529 Py_ssize_t i;
530
530
531 if (newlist == NULL)
531 if (newlist == NULL)
532 return NULL;
532 return NULL;
533
533
534 for (i = 0; i < len; i++) {
534 for (i = 0; i < len; i++) {
535 PyObject *obj = PyList_GET_ITEM(list, i);
535 PyObject *obj = PyList_GET_ITEM(list, i);
536 Py_INCREF(obj);
536 Py_INCREF(obj);
537 PyList_SET_ITEM(newlist, i, obj);
537 PyList_SET_ITEM(newlist, i, obj);
538 }
538 }
539
539
540 return newlist;
540 return newlist;
541 }
541 }
542
542
543 static int check_filter(PyObject *filter, Py_ssize_t arg)
543 static int check_filter(PyObject *filter, Py_ssize_t arg)
544 {
544 {
545 if (filter) {
545 if (filter) {
546 PyObject *arglist, *result;
546 PyObject *arglist, *result;
547 int isfiltered;
547 int isfiltered;
548
548
549 arglist = Py_BuildValue("(n)", arg);
549 arglist = Py_BuildValue("(n)", arg);
550 if (!arglist) {
550 if (!arglist) {
551 return -1;
551 return -1;
552 }
552 }
553
553
554 result = PyEval_CallObject(filter, arglist);
554 result = PyEval_CallObject(filter, arglist);
555 Py_DECREF(arglist);
555 Py_DECREF(arglist);
556 if (!result) {
556 if (!result) {
557 return -1;
557 return -1;
558 }
558 }
559
559
560 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
560 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
561 * same as this function, so we can just return it directly.*/
561 * same as this function, so we can just return it directly.*/
562 isfiltered = PyObject_IsTrue(result);
562 isfiltered = PyObject_IsTrue(result);
563 Py_DECREF(result);
563 Py_DECREF(result);
564 return isfiltered;
564 return isfiltered;
565 } else {
565 } else {
566 return 0;
566 return 0;
567 }
567 }
568 }
568 }
569
569
570 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
570 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
571 Py_ssize_t marker, char *phases)
571 Py_ssize_t marker, char *phases)
572 {
572 {
573 PyObject *iter = NULL;
573 PyObject *iter = NULL;
574 PyObject *iter_item = NULL;
574 PyObject *iter_item = NULL;
575 Py_ssize_t min_idx = index_length(self) + 2;
575 Py_ssize_t min_idx = index_length(self) + 2;
576 long iter_item_long;
576 long iter_item_long;
577
577
578 if (PyList_GET_SIZE(list) != 0) {
578 if (PyList_GET_SIZE(list) != 0) {
579 iter = PyObject_GetIter(list);
579 iter = PyObject_GetIter(list);
580 if (iter == NULL)
580 if (iter == NULL)
581 return -2;
581 return -2;
582 while ((iter_item = PyIter_Next(iter))) {
582 while ((iter_item = PyIter_Next(iter))) {
583 if (!pylong_to_long(iter_item, &iter_item_long)) {
583 if (!pylong_to_long(iter_item, &iter_item_long)) {
584 Py_DECREF(iter_item);
584 Py_DECREF(iter_item);
585 return -2;
585 return -2;
586 }
586 }
587 Py_DECREF(iter_item);
587 Py_DECREF(iter_item);
588 if (iter_item_long < min_idx)
588 if (iter_item_long < min_idx)
589 min_idx = iter_item_long;
589 min_idx = iter_item_long;
590 phases[iter_item_long] = (char)marker;
590 phases[iter_item_long] = (char)marker;
591 }
591 }
592 Py_DECREF(iter);
592 Py_DECREF(iter);
593 }
593 }
594
594
595 return min_idx;
595 return min_idx;
596 }
596 }
597
597
598 static inline void set_phase_from_parents(char *phases, int parent_1,
598 static inline void set_phase_from_parents(char *phases, int parent_1,
599 int parent_2, Py_ssize_t i)
599 int parent_2, Py_ssize_t i)
600 {
600 {
601 if (parent_1 >= 0 && phases[parent_1] > phases[i])
601 if (parent_1 >= 0 && phases[parent_1] > phases[i])
602 phases[i] = phases[parent_1];
602 phases[i] = phases[parent_1];
603 if (parent_2 >= 0 && phases[parent_2] > phases[i])
603 if (parent_2 >= 0 && phases[parent_2] > phases[i])
604 phases[i] = phases[parent_2];
604 phases[i] = phases[parent_2];
605 }
605 }
606
606
607 static PyObject *reachableroots2(indexObject *self, PyObject *args)
607 static PyObject *reachableroots2(indexObject *self, PyObject *args)
608 {
608 {
609
609
610 /* Input */
610 /* Input */
611 long minroot;
611 long minroot;
612 PyObject *includepatharg = NULL;
612 PyObject *includepatharg = NULL;
613 int includepath = 0;
613 int includepath = 0;
614 /* heads and roots are lists */
614 /* heads and roots are lists */
615 PyObject *heads = NULL;
615 PyObject *heads = NULL;
616 PyObject *roots = NULL;
616 PyObject *roots = NULL;
617 PyObject *reachable = NULL;
617 PyObject *reachable = NULL;
618
618
619 PyObject *val;
619 PyObject *val;
620 Py_ssize_t len = index_length(self);
620 Py_ssize_t len = index_length(self);
621 long revnum;
621 long revnum;
622 Py_ssize_t k;
622 Py_ssize_t k;
623 Py_ssize_t i;
623 Py_ssize_t i;
624 Py_ssize_t l;
624 Py_ssize_t l;
625 int r;
625 int r;
626 int parents[2];
626 int parents[2];
627
627
628 /* Internal data structure:
628 /* Internal data structure:
629 * tovisit: array of length len+1 (all revs + nullrev), filled upto
629 * tovisit: array of length len+1 (all revs + nullrev), filled upto
630 * lentovisit
630 * lentovisit
631 *
631 *
632 * revstates: array of length len+1 (all revs + nullrev) */
632 * revstates: array of length len+1 (all revs + nullrev) */
633 int *tovisit = NULL;
633 int *tovisit = NULL;
634 long lentovisit = 0;
634 long lentovisit = 0;
635 enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
635 enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
636 char *revstates = NULL;
636 char *revstates = NULL;
637
637
638 /* Get arguments */
638 /* Get arguments */
639 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
639 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
640 &PyList_Type, &roots, &PyBool_Type,
640 &PyList_Type, &roots, &PyBool_Type,
641 &includepatharg))
641 &includepatharg))
642 goto bail;
642 goto bail;
643
643
644 if (includepatharg == Py_True)
644 if (includepatharg == Py_True)
645 includepath = 1;
645 includepath = 1;
646
646
647 /* Initialize return set */
647 /* Initialize return set */
648 reachable = PyList_New(0);
648 reachable = PyList_New(0);
649 if (reachable == NULL)
649 if (reachable == NULL)
650 goto bail;
650 goto bail;
651
651
652 /* Initialize internal datastructures */
652 /* Initialize internal datastructures */
653 tovisit = (int *)malloc((len + 1) * sizeof(int));
653 tovisit = (int *)malloc((len + 1) * sizeof(int));
654 if (tovisit == NULL) {
654 if (tovisit == NULL) {
655 PyErr_NoMemory();
655 PyErr_NoMemory();
656 goto bail;
656 goto bail;
657 }
657 }
658
658
659 revstates = (char *)calloc(len + 1, 1);
659 revstates = (char *)calloc(len + 1, 1);
660 if (revstates == NULL) {
660 if (revstates == NULL) {
661 PyErr_NoMemory();
661 PyErr_NoMemory();
662 goto bail;
662 goto bail;
663 }
663 }
664
664
665 l = PyList_GET_SIZE(roots);
665 l = PyList_GET_SIZE(roots);
666 for (i = 0; i < l; i++) {
666 for (i = 0; i < l; i++) {
667 revnum = PyInt_AsLong(PyList_GET_ITEM(roots, i));
667 revnum = PyInt_AsLong(PyList_GET_ITEM(roots, i));
668 if (revnum == -1 && PyErr_Occurred())
668 if (revnum == -1 && PyErr_Occurred())
669 goto bail;
669 goto bail;
670 /* If root is out of range, e.g. wdir(), it must be unreachable
670 /* If root is out of range, e.g. wdir(), it must be unreachable
671 * from heads. So we can just ignore it. */
671 * from heads. So we can just ignore it. */
672 if (revnum + 1 < 0 || revnum + 1 >= len + 1)
672 if (revnum + 1 < 0 || revnum + 1 >= len + 1)
673 continue;
673 continue;
674 revstates[revnum + 1] |= RS_ROOT;
674 revstates[revnum + 1] |= RS_ROOT;
675 }
675 }
676
676
677 /* Populate tovisit with all the heads */
677 /* Populate tovisit with all the heads */
678 l = PyList_GET_SIZE(heads);
678 l = PyList_GET_SIZE(heads);
679 for (i = 0; i < l; i++) {
679 for (i = 0; i < l; i++) {
680 revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i));
680 revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i));
681 if (revnum == -1 && PyErr_Occurred())
681 if (revnum == -1 && PyErr_Occurred())
682 goto bail;
682 goto bail;
683 if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
683 if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
684 PyErr_SetString(PyExc_IndexError, "head out of range");
684 PyErr_SetString(PyExc_IndexError, "head out of range");
685 goto bail;
685 goto bail;
686 }
686 }
687 if (!(revstates[revnum + 1] & RS_SEEN)) {
687 if (!(revstates[revnum + 1] & RS_SEEN)) {
688 tovisit[lentovisit++] = (int)revnum;
688 tovisit[lentovisit++] = (int)revnum;
689 revstates[revnum + 1] |= RS_SEEN;
689 revstates[revnum + 1] |= RS_SEEN;
690 }
690 }
691 }
691 }
692
692
693 /* Visit the tovisit list and find the reachable roots */
693 /* Visit the tovisit list and find the reachable roots */
694 k = 0;
694 k = 0;
695 while (k < lentovisit) {
695 while (k < lentovisit) {
696 /* Add the node to reachable if it is a root*/
696 /* Add the node to reachable if it is a root*/
697 revnum = tovisit[k++];
697 revnum = tovisit[k++];
698 if (revstates[revnum + 1] & RS_ROOT) {
698 if (revstates[revnum + 1] & RS_ROOT) {
699 revstates[revnum + 1] |= RS_REACHABLE;
699 revstates[revnum + 1] |= RS_REACHABLE;
700 val = PyInt_FromLong(revnum);
700 val = PyInt_FromLong(revnum);
701 if (val == NULL)
701 if (val == NULL)
702 goto bail;
702 goto bail;
703 r = PyList_Append(reachable, val);
703 r = PyList_Append(reachable, val);
704 Py_DECREF(val);
704 Py_DECREF(val);
705 if (r < 0)
705 if (r < 0)
706 goto bail;
706 goto bail;
707 if (includepath == 0)
707 if (includepath == 0)
708 continue;
708 continue;
709 }
709 }
710
710
711 /* Add its parents to the list of nodes to visit */
711 /* Add its parents to the list of nodes to visit */
712 if (revnum == nullrev)
712 if (revnum == nullrev)
713 continue;
713 continue;
714 r = index_get_parents(self, revnum, parents, (int)len - 1);
714 r = index_get_parents(self, revnum, parents, (int)len - 1);
715 if (r < 0)
715 if (r < 0)
716 goto bail;
716 goto bail;
717 for (i = 0; i < 2; i++) {
717 for (i = 0; i < 2; i++) {
718 if (!(revstates[parents[i] + 1] & RS_SEEN) &&
718 if (!(revstates[parents[i] + 1] & RS_SEEN) &&
719 parents[i] >= minroot) {
719 parents[i] >= minroot) {
720 tovisit[lentovisit++] = parents[i];
720 tovisit[lentovisit++] = parents[i];
721 revstates[parents[i] + 1] |= RS_SEEN;
721 revstates[parents[i] + 1] |= RS_SEEN;
722 }
722 }
723 }
723 }
724 }
724 }
725
725
726 /* Find all the nodes in between the roots we found and the heads
726 /* Find all the nodes in between the roots we found and the heads
727 * and add them to the reachable set */
727 * and add them to the reachable set */
728 if (includepath == 1) {
728 if (includepath == 1) {
729 long minidx = minroot;
729 long minidx = minroot;
730 if (minidx < 0)
730 if (minidx < 0)
731 minidx = 0;
731 minidx = 0;
732 for (i = minidx; i < len; i++) {
732 for (i = minidx; i < len; i++) {
733 if (!(revstates[i + 1] & RS_SEEN))
733 if (!(revstates[i + 1] & RS_SEEN))
734 continue;
734 continue;
735 r = index_get_parents(self, i, parents, (int)len - 1);
735 r = index_get_parents(self, i, parents, (int)len - 1);
736 /* Corrupted index file, error is set from
736 /* Corrupted index file, error is set from
737 * index_get_parents */
737 * index_get_parents */
738 if (r < 0)
738 if (r < 0)
739 goto bail;
739 goto bail;
740 if (((revstates[parents[0] + 1] |
740 if (((revstates[parents[0] + 1] |
741 revstates[parents[1] + 1]) &
741 revstates[parents[1] + 1]) &
742 RS_REACHABLE) &&
742 RS_REACHABLE) &&
743 !(revstates[i + 1] & RS_REACHABLE)) {
743 !(revstates[i + 1] & RS_REACHABLE)) {
744 revstates[i + 1] |= RS_REACHABLE;
744 revstates[i + 1] |= RS_REACHABLE;
745 val = PyInt_FromSsize_t(i);
745 val = PyInt_FromSsize_t(i);
746 if (val == NULL)
746 if (val == NULL)
747 goto bail;
747 goto bail;
748 r = PyList_Append(reachable, val);
748 r = PyList_Append(reachable, val);
749 Py_DECREF(val);
749 Py_DECREF(val);
750 if (r < 0)
750 if (r < 0)
751 goto bail;
751 goto bail;
752 }
752 }
753 }
753 }
754 }
754 }
755
755
756 free(revstates);
756 free(revstates);
757 free(tovisit);
757 free(tovisit);
758 return reachable;
758 return reachable;
759 bail:
759 bail:
760 Py_XDECREF(reachable);
760 Py_XDECREF(reachable);
761 free(revstates);
761 free(revstates);
762 free(tovisit);
762 free(tovisit);
763 return NULL;
763 return NULL;
764 }
764 }
765
765
766 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
766 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
767 {
767 {
768 PyObject *roots = Py_None;
768 PyObject *roots = Py_None;
769 PyObject *ret = NULL;
769 PyObject *ret = NULL;
770 PyObject *phasessize = NULL;
770 PyObject *phasessize = NULL;
771 PyObject *phaseroots = NULL;
771 PyObject *phaseroots = NULL;
772 PyObject *phaseset = NULL;
772 PyObject *phaseset = NULL;
773 PyObject *phasessetlist = NULL;
773 PyObject *phasessetlist = NULL;
774 PyObject *rev = NULL;
774 PyObject *rev = NULL;
775 Py_ssize_t len = index_length(self);
775 Py_ssize_t len = index_length(self);
776 Py_ssize_t numphase = 0;
776 Py_ssize_t numphase = 0;
777 Py_ssize_t minrevallphases = 0;
777 Py_ssize_t minrevallphases = 0;
778 Py_ssize_t minrevphase = 0;
778 Py_ssize_t minrevphase = 0;
779 Py_ssize_t i = 0;
779 Py_ssize_t i = 0;
780 char *phases = NULL;
780 char *phases = NULL;
781 long phase;
781 long phase;
782
782
783 if (!PyArg_ParseTuple(args, "O", &roots))
783 if (!PyArg_ParseTuple(args, "O", &roots))
784 goto done;
784 goto done;
785 if (roots == NULL || !PyList_Check(roots)) {
785 if (roots == NULL || !PyList_Check(roots)) {
786 PyErr_SetString(PyExc_TypeError, "roots must be a list");
786 PyErr_SetString(PyExc_TypeError, "roots must be a list");
787 goto done;
787 goto done;
788 }
788 }
789
789
790 phases = calloc(
790 phases = calloc(
791 len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
791 len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
792 if (phases == NULL) {
792 if (phases == NULL) {
793 PyErr_NoMemory();
793 PyErr_NoMemory();
794 goto done;
794 goto done;
795 }
795 }
796 /* Put the phase information of all the roots in phases */
796 /* Put the phase information of all the roots in phases */
797 numphase = PyList_GET_SIZE(roots) + 1;
797 numphase = PyList_GET_SIZE(roots) + 1;
798 minrevallphases = len + 1;
798 minrevallphases = len + 1;
799 phasessetlist = PyList_New(numphase);
799 phasessetlist = PyList_New(numphase);
800 if (phasessetlist == NULL)
800 if (phasessetlist == NULL)
801 goto done;
801 goto done;
802
802
803 PyList_SET_ITEM(phasessetlist, 0, Py_None);
803 PyList_SET_ITEM(phasessetlist, 0, Py_None);
804 Py_INCREF(Py_None);
804 Py_INCREF(Py_None);
805
805
806 for (i = 0; i < numphase - 1; i++) {
806 for (i = 0; i < numphase - 1; i++) {
807 phaseroots = PyList_GET_ITEM(roots, i);
807 phaseroots = PyList_GET_ITEM(roots, i);
808 phaseset = PySet_New(NULL);
808 phaseset = PySet_New(NULL);
809 if (phaseset == NULL)
809 if (phaseset == NULL)
810 goto release;
810 goto release;
811 PyList_SET_ITEM(phasessetlist, i + 1, phaseset);
811 PyList_SET_ITEM(phasessetlist, i + 1, phaseset);
812 if (!PyList_Check(phaseroots)) {
812 if (!PyList_Check(phaseroots)) {
813 PyErr_SetString(PyExc_TypeError,
813 PyErr_SetString(PyExc_TypeError,
814 "roots item must be a list");
814 "roots item must be a list");
815 goto release;
815 goto release;
816 }
816 }
817 minrevphase =
817 minrevphase =
818 add_roots_get_min(self, phaseroots, i + 1, phases);
818 add_roots_get_min(self, phaseroots, i + 1, phases);
819 if (minrevphase == -2) /* Error from add_roots_get_min */
819 if (minrevphase == -2) /* Error from add_roots_get_min */
820 goto release;
820 goto release;
821 minrevallphases = MIN(minrevallphases, minrevphase);
821 minrevallphases = MIN(minrevallphases, minrevphase);
822 }
822 }
823 /* Propagate the phase information from the roots to the revs */
823 /* Propagate the phase information from the roots to the revs */
824 if (minrevallphases != -1) {
824 if (minrevallphases != -1) {
825 int parents[2];
825 int parents[2];
826 for (i = minrevallphases; i < len; i++) {
826 for (i = minrevallphases; i < len; i++) {
827 if (index_get_parents(self, i, parents, (int)len - 1) <
827 if (index_get_parents(self, i, parents, (int)len - 1) <
828 0)
828 0)
829 goto release;
829 goto release;
830 set_phase_from_parents(phases, parents[0], parents[1],
830 set_phase_from_parents(phases, parents[0], parents[1],
831 i);
831 i);
832 }
832 }
833 }
833 }
834 /* Transform phase list to a python list */
834 /* Transform phase list to a python list */
835 phasessize = PyInt_FromSsize_t(len);
835 phasessize = PyInt_FromSsize_t(len);
836 if (phasessize == NULL)
836 if (phasessize == NULL)
837 goto release;
837 goto release;
838 for (i = 0; i < len; i++) {
838 for (i = 0; i < len; i++) {
839 phase = phases[i];
839 phase = phases[i];
840 /* We only store the sets of phase for non public phase, the
840 /* We only store the sets of phase for non public phase, the
841 * public phase is computed as a difference */
841 * public phase is computed as a difference */
842 if (phase != 0) {
842 if (phase != 0) {
843 phaseset = PyList_GET_ITEM(phasessetlist, phase);
843 phaseset = PyList_GET_ITEM(phasessetlist, phase);
844 rev = PyInt_FromSsize_t(i);
844 rev = PyInt_FromSsize_t(i);
845 if (rev == NULL)
845 if (rev == NULL)
846 goto release;
846 goto release;
847 PySet_Add(phaseset, rev);
847 PySet_Add(phaseset, rev);
848 Py_XDECREF(rev);
848 Py_XDECREF(rev);
849 }
849 }
850 }
850 }
851 ret = PyTuple_Pack(2, phasessize, phasessetlist);
851 ret = PyTuple_Pack(2, phasessize, phasessetlist);
852
852
853 release:
853 release:
854 Py_XDECREF(phasessize);
854 Py_XDECREF(phasessize);
855 Py_XDECREF(phasessetlist);
855 Py_XDECREF(phasessetlist);
856 done:
856 done:
857 free(phases);
857 free(phases);
858 return ret;
858 return ret;
859 }
859 }
860
860
861 static PyObject *index_headrevs(indexObject *self, PyObject *args)
861 static PyObject *index_headrevs(indexObject *self, PyObject *args)
862 {
862 {
863 Py_ssize_t i, j, len;
863 Py_ssize_t i, j, len;
864 char *nothead = NULL;
864 char *nothead = NULL;
865 PyObject *heads = NULL;
865 PyObject *heads = NULL;
866 PyObject *filter = NULL;
866 PyObject *filter = NULL;
867 PyObject *filteredrevs = Py_None;
867 PyObject *filteredrevs = Py_None;
868
868
869 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
869 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
870 return NULL;
870 return NULL;
871 }
871 }
872
872
873 if (self->headrevs && filteredrevs == self->filteredrevs)
873 if (self->headrevs && filteredrevs == self->filteredrevs)
874 return list_copy(self->headrevs);
874 return list_copy(self->headrevs);
875
875
876 Py_DECREF(self->filteredrevs);
876 Py_DECREF(self->filteredrevs);
877 self->filteredrevs = filteredrevs;
877 self->filteredrevs = filteredrevs;
878 Py_INCREF(filteredrevs);
878 Py_INCREF(filteredrevs);
879
879
880 if (filteredrevs != Py_None) {
880 if (filteredrevs != Py_None) {
881 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
881 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
882 if (!filter) {
882 if (!filter) {
883 PyErr_SetString(
883 PyErr_SetString(
884 PyExc_TypeError,
884 PyExc_TypeError,
885 "filteredrevs has no attribute __contains__");
885 "filteredrevs has no attribute __contains__");
886 goto bail;
886 goto bail;
887 }
887 }
888 }
888 }
889
889
890 len = index_length(self);
890 len = index_length(self);
891 heads = PyList_New(0);
891 heads = PyList_New(0);
892 if (heads == NULL)
892 if (heads == NULL)
893 goto bail;
893 goto bail;
894 if (len == 0) {
894 if (len == 0) {
895 PyObject *nullid = PyInt_FromLong(-1);
895 PyObject *nullid = PyInt_FromLong(-1);
896 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
896 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
897 Py_XDECREF(nullid);
897 Py_XDECREF(nullid);
898 goto bail;
898 goto bail;
899 }
899 }
900 goto done;
900 goto done;
901 }
901 }
902
902
903 nothead = calloc(len, 1);
903 nothead = calloc(len, 1);
904 if (nothead == NULL) {
904 if (nothead == NULL) {
905 PyErr_NoMemory();
905 PyErr_NoMemory();
906 goto bail;
906 goto bail;
907 }
907 }
908
908
909 for (i = len - 1; i >= 0; i--) {
909 for (i = len - 1; i >= 0; i--) {
910 int isfiltered;
910 int isfiltered;
911 int parents[2];
911 int parents[2];
912
912
913 /* If nothead[i] == 1, it means we've seen an unfiltered child
913 /* If nothead[i] == 1, it means we've seen an unfiltered child
914 * of this node already, and therefore this node is not
914 * of this node already, and therefore this node is not
915 * filtered. So we can skip the expensive check_filter step.
915 * filtered. So we can skip the expensive check_filter step.
916 */
916 */
917 if (nothead[i] != 1) {
917 if (nothead[i] != 1) {
918 isfiltered = check_filter(filter, i);
918 isfiltered = check_filter(filter, i);
919 if (isfiltered == -1) {
919 if (isfiltered == -1) {
920 PyErr_SetString(PyExc_TypeError,
920 PyErr_SetString(PyExc_TypeError,
921 "unable to check filter");
921 "unable to check filter");
922 goto bail;
922 goto bail;
923 }
923 }
924
924
925 if (isfiltered) {
925 if (isfiltered) {
926 nothead[i] = 1;
926 nothead[i] = 1;
927 continue;
927 continue;
928 }
928 }
929 }
929 }
930
930
931 if (index_get_parents(self, i, parents, (int)len - 1) < 0)
931 if (index_get_parents(self, i, parents, (int)len - 1) < 0)
932 goto bail;
932 goto bail;
933 for (j = 0; j < 2; j++) {
933 for (j = 0; j < 2; j++) {
934 if (parents[j] >= 0)
934 if (parents[j] >= 0)
935 nothead[parents[j]] = 1;
935 nothead[parents[j]] = 1;
936 }
936 }
937 }
937 }
938
938
939 for (i = 0; i < len; i++) {
939 for (i = 0; i < len; i++) {
940 PyObject *head;
940 PyObject *head;
941
941
942 if (nothead[i])
942 if (nothead[i])
943 continue;
943 continue;
944 head = PyInt_FromSsize_t(i);
944 head = PyInt_FromSsize_t(i);
945 if (head == NULL || PyList_Append(heads, head) == -1) {
945 if (head == NULL || PyList_Append(heads, head) == -1) {
946 Py_XDECREF(head);
946 Py_XDECREF(head);
947 goto bail;
947 goto bail;
948 }
948 }
949 }
949 }
950
950
951 done:
951 done:
952 self->headrevs = heads;
952 self->headrevs = heads;
953 Py_XDECREF(filter);
953 Py_XDECREF(filter);
954 free(nothead);
954 free(nothead);
955 return list_copy(self->headrevs);
955 return list_copy(self->headrevs);
956 bail:
956 bail:
957 Py_XDECREF(filter);
957 Py_XDECREF(filter);
958 Py_XDECREF(heads);
958 Py_XDECREF(heads);
959 free(nothead);
959 free(nothead);
960 return NULL;
960 return NULL;
961 }
961 }
962
962
963 /**
963 /**
964 * Obtain the base revision index entry.
964 * Obtain the base revision index entry.
965 *
965 *
966 * Callers must ensure that rev >= 0 or illegal memory access may occur.
966 * Callers must ensure that rev >= 0 or illegal memory access may occur.
967 */
967 */
968 static inline int index_baserev(indexObject *self, int rev)
968 static inline int index_baserev(indexObject *self, int rev)
969 {
969 {
970 const char *data;
970 const char *data;
971 int result;
971 int result;
972
972
973 if (rev >= self->length) {
973 if (rev >= self->length) {
974 PyObject *tuple =
974 PyObject *tuple =
975 PyList_GET_ITEM(self->added, rev - self->length);
975 PyList_GET_ITEM(self->added, rev - self->length);
976 long ret;
976 long ret;
977 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 3), &ret)) {
977 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 3), &ret)) {
978 return -2;
978 return -2;
979 }
979 }
980 result = (int)ret;
980 result = (int)ret;
981 } else {
981 } else {
982 data = index_deref(self, rev);
982 data = index_deref(self, rev);
983 if (data == NULL) {
983 if (data == NULL) {
984 return -2;
984 return -2;
985 }
985 }
986
986
987 result = getbe32(data + 16);
987 result = getbe32(data + 16);
988 }
988 }
989 if (result > rev) {
989 if (result > rev) {
990 PyErr_Format(
990 PyErr_Format(
991 PyExc_ValueError,
991 PyExc_ValueError,
992 "corrupted revlog, revision base above revision: %d, %d",
992 "corrupted revlog, revision base above revision: %d, %d",
993 rev, result);
993 rev, result);
994 return -2;
994 return -2;
995 }
995 }
996 if (result < -1) {
996 if (result < -1) {
997 PyErr_Format(
997 PyErr_Format(
998 PyExc_ValueError,
998 PyExc_ValueError,
999 "corrupted revlog, revision base out of range: %d, %d", rev,
999 "corrupted revlog, revision base out of range: %d, %d", rev,
1000 result);
1000 result);
1001 return -2;
1001 return -2;
1002 }
1002 }
1003 return result;
1003 return result;
1004 }
1004 }
1005
1005
1006 /**
1006 /**
1007 * Find if a revision is a snapshot or not
1007 * Find if a revision is a snapshot or not
1008 *
1008 *
1009 * Only relevant for sparse-revlog case.
1009 * Only relevant for sparse-revlog case.
1010 * Callers must ensure that rev is in a valid range.
1010 * Callers must ensure that rev is in a valid range.
1011 */
1011 */
1012 static int index_issnapshotrev(indexObject *self, Py_ssize_t rev)
1012 static int index_issnapshotrev(indexObject *self, Py_ssize_t rev)
1013 {
1013 {
1014 int ps[2];
1014 int ps[2];
1015 Py_ssize_t base;
1015 Py_ssize_t base;
1016 while (rev >= 0) {
1016 while (rev >= 0) {
1017 base = (Py_ssize_t)index_baserev(self, rev);
1017 base = (Py_ssize_t)index_baserev(self, rev);
1018 if (base == rev) {
1018 if (base == rev) {
1019 base = -1;
1019 base = -1;
1020 }
1020 }
1021 if (base == -2) {
1021 if (base == -2) {
1022 assert(PyErr_Occurred());
1022 assert(PyErr_Occurred());
1023 return -1;
1023 return -1;
1024 }
1024 }
1025 if (base == -1) {
1025 if (base == -1) {
1026 return 1;
1026 return 1;
1027 }
1027 }
1028 if (index_get_parents(self, rev, ps, (int)rev) < 0) {
1028 if (index_get_parents(self, rev, ps, (int)rev) < 0) {
1029 assert(PyErr_Occurred());
1029 assert(PyErr_Occurred());
1030 return -1;
1030 return -1;
1031 };
1031 };
1032 if (base == ps[0] || base == ps[1]) {
1032 if (base == ps[0] || base == ps[1]) {
1033 return 0;
1033 return 0;
1034 }
1034 }
1035 rev = base;
1035 rev = base;
1036 }
1036 }
1037 return rev == -1;
1037 return rev == -1;
1038 }
1038 }
1039
1039
1040 static PyObject *index_issnapshot(indexObject *self, PyObject *value)
1040 static PyObject *index_issnapshot(indexObject *self, PyObject *value)
1041 {
1041 {
1042 long rev;
1042 long rev;
1043 int issnap;
1043 int issnap;
1044 Py_ssize_t length = index_length(self);
1044 Py_ssize_t length = index_length(self);
1045
1045
1046 if (!pylong_to_long(value, &rev)) {
1046 if (!pylong_to_long(value, &rev)) {
1047 return NULL;
1047 return NULL;
1048 }
1048 }
1049 if (rev < -1 || rev >= length) {
1049 if (rev < -1 || rev >= length) {
1050 PyErr_Format(PyExc_ValueError, "revlog index out of range: %ld",
1050 PyErr_Format(PyExc_ValueError, "revlog index out of range: %ld",
1051 rev);
1051 rev);
1052 return NULL;
1052 return NULL;
1053 };
1053 };
1054 issnap = index_issnapshotrev(self, (Py_ssize_t)rev);
1054 issnap = index_issnapshotrev(self, (Py_ssize_t)rev);
1055 if (issnap < 0) {
1055 if (issnap < 0) {
1056 return NULL;
1056 return NULL;
1057 };
1057 };
1058 return PyBool_FromLong((long)issnap);
1058 return PyBool_FromLong((long)issnap);
1059 }
1059 }
1060
1060
1061 static PyObject *index_findsnapshots(indexObject *self, PyObject *args)
1061 static PyObject *index_findsnapshots(indexObject *self, PyObject *args)
1062 {
1062 {
1063 Py_ssize_t start_rev;
1063 Py_ssize_t start_rev;
1064 PyObject *cache;
1064 PyObject *cache;
1065 Py_ssize_t base;
1065 Py_ssize_t base;
1066 Py_ssize_t rev;
1066 Py_ssize_t rev;
1067 PyObject *key = NULL;
1067 PyObject *key = NULL;
1068 PyObject *value = NULL;
1068 PyObject *value = NULL;
1069 const Py_ssize_t length = index_length(self);
1069 const Py_ssize_t length = index_length(self);
1070 if (!PyArg_ParseTuple(args, "O!n", &PyDict_Type, &cache, &start_rev)) {
1070 if (!PyArg_ParseTuple(args, "O!n", &PyDict_Type, &cache, &start_rev)) {
1071 return NULL;
1071 return NULL;
1072 }
1072 }
1073 for (rev = start_rev; rev < length; rev++) {
1073 for (rev = start_rev; rev < length; rev++) {
1074 int issnap;
1074 int issnap;
1075 PyObject *allvalues = NULL;
1075 PyObject *allvalues = NULL;
1076 issnap = index_issnapshotrev(self, rev);
1076 issnap = index_issnapshotrev(self, rev);
1077 if (issnap < 0) {
1077 if (issnap < 0) {
1078 goto bail;
1078 goto bail;
1079 }
1079 }
1080 if (issnap == 0) {
1080 if (issnap == 0) {
1081 continue;
1081 continue;
1082 }
1082 }
1083 base = (Py_ssize_t)index_baserev(self, rev);
1083 base = (Py_ssize_t)index_baserev(self, rev);
1084 if (base == rev) {
1084 if (base == rev) {
1085 base = -1;
1085 base = -1;
1086 }
1086 }
1087 if (base == -2) {
1087 if (base == -2) {
1088 assert(PyErr_Occurred());
1088 assert(PyErr_Occurred());
1089 goto bail;
1089 goto bail;
1090 }
1090 }
1091 key = PyInt_FromSsize_t(base);
1091 key = PyInt_FromSsize_t(base);
1092 allvalues = PyDict_GetItem(cache, key);
1092 allvalues = PyDict_GetItem(cache, key);
1093 if (allvalues == NULL && PyErr_Occurred()) {
1093 if (allvalues == NULL && PyErr_Occurred()) {
1094 goto bail;
1094 goto bail;
1095 }
1095 }
1096 if (allvalues == NULL) {
1096 if (allvalues == NULL) {
1097 int r;
1097 int r;
1098 allvalues = PyList_New(0);
1098 allvalues = PyList_New(0);
1099 if (!allvalues) {
1099 if (!allvalues) {
1100 goto bail;
1100 goto bail;
1101 }
1101 }
1102 r = PyDict_SetItem(cache, key, allvalues);
1102 r = PyDict_SetItem(cache, key, allvalues);
1103 Py_DECREF(allvalues);
1103 Py_DECREF(allvalues);
1104 if (r < 0) {
1104 if (r < 0) {
1105 goto bail;
1105 goto bail;
1106 }
1106 }
1107 }
1107 }
1108 value = PyInt_FromSsize_t(rev);
1108 value = PyInt_FromSsize_t(rev);
1109 if (PyList_Append(allvalues, value)) {
1109 if (PyList_Append(allvalues, value)) {
1110 goto bail;
1110 goto bail;
1111 }
1111 }
1112 Py_CLEAR(key);
1112 Py_CLEAR(key);
1113 Py_CLEAR(value);
1113 Py_CLEAR(value);
1114 }
1114 }
1115 Py_RETURN_NONE;
1115 Py_RETURN_NONE;
1116 bail:
1116 bail:
1117 Py_XDECREF(key);
1117 Py_XDECREF(key);
1118 Py_XDECREF(value);
1118 Py_XDECREF(value);
1119 return NULL;
1119 return NULL;
1120 }
1120 }
1121
1121
1122 static PyObject *index_deltachain(indexObject *self, PyObject *args)
1122 static PyObject *index_deltachain(indexObject *self, PyObject *args)
1123 {
1123 {
1124 int rev, generaldelta;
1124 int rev, generaldelta;
1125 PyObject *stoparg;
1125 PyObject *stoparg;
1126 int stoprev, iterrev, baserev = -1;
1126 int stoprev, iterrev, baserev = -1;
1127 int stopped;
1127 int stopped;
1128 PyObject *chain = NULL, *result = NULL;
1128 PyObject *chain = NULL, *result = NULL;
1129 const Py_ssize_t length = index_length(self);
1129 const Py_ssize_t length = index_length(self);
1130
1130
1131 if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
1131 if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
1132 return NULL;
1132 return NULL;
1133 }
1133 }
1134
1134
1135 if (PyInt_Check(stoparg)) {
1135 if (PyInt_Check(stoparg)) {
1136 stoprev = (int)PyInt_AsLong(stoparg);
1136 stoprev = (int)PyInt_AsLong(stoparg);
1137 if (stoprev == -1 && PyErr_Occurred()) {
1137 if (stoprev == -1 && PyErr_Occurred()) {
1138 return NULL;
1138 return NULL;
1139 }
1139 }
1140 } else if (stoparg == Py_None) {
1140 } else if (stoparg == Py_None) {
1141 stoprev = -2;
1141 stoprev = -2;
1142 } else {
1142 } else {
1143 PyErr_SetString(PyExc_ValueError,
1143 PyErr_SetString(PyExc_ValueError,
1144 "stoprev must be integer or None");
1144 "stoprev must be integer or None");
1145 return NULL;
1145 return NULL;
1146 }
1146 }
1147
1147
1148 if (rev < 0 || rev >= length) {
1148 if (rev < 0 || rev >= length) {
1149 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1149 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1150 return NULL;
1150 return NULL;
1151 }
1151 }
1152
1152
1153 chain = PyList_New(0);
1153 chain = PyList_New(0);
1154 if (chain == NULL) {
1154 if (chain == NULL) {
1155 return NULL;
1155 return NULL;
1156 }
1156 }
1157
1157
1158 baserev = index_baserev(self, rev);
1158 baserev = index_baserev(self, rev);
1159
1159
1160 /* This should never happen. */
1160 /* This should never happen. */
1161 if (baserev <= -2) {
1161 if (baserev <= -2) {
1162 /* Error should be set by index_deref() */
1162 /* Error should be set by index_deref() */
1163 assert(PyErr_Occurred());
1163 assert(PyErr_Occurred());
1164 goto bail;
1164 goto bail;
1165 }
1165 }
1166
1166
1167 iterrev = rev;
1167 iterrev = rev;
1168
1168
1169 while (iterrev != baserev && iterrev != stoprev) {
1169 while (iterrev != baserev && iterrev != stoprev) {
1170 PyObject *value = PyInt_FromLong(iterrev);
1170 PyObject *value = PyInt_FromLong(iterrev);
1171 if (value == NULL) {
1171 if (value == NULL) {
1172 goto bail;
1172 goto bail;
1173 }
1173 }
1174 if (PyList_Append(chain, value)) {
1174 if (PyList_Append(chain, value)) {
1175 Py_DECREF(value);
1175 Py_DECREF(value);
1176 goto bail;
1176 goto bail;
1177 }
1177 }
1178 Py_DECREF(value);
1178 Py_DECREF(value);
1179
1179
1180 if (generaldelta) {
1180 if (generaldelta) {
1181 iterrev = baserev;
1181 iterrev = baserev;
1182 } else {
1182 } else {
1183 iterrev--;
1183 iterrev--;
1184 }
1184 }
1185
1185
1186 if (iterrev < 0) {
1186 if (iterrev < 0) {
1187 break;
1187 break;
1188 }
1188 }
1189
1189
1190 if (iterrev >= length) {
1190 if (iterrev >= length) {
1191 PyErr_SetString(PyExc_IndexError,
1191 PyErr_SetString(PyExc_IndexError,
1192 "revision outside index");
1192 "revision outside index");
1193 return NULL;
1193 return NULL;
1194 }
1194 }
1195
1195
1196 baserev = index_baserev(self, iterrev);
1196 baserev = index_baserev(self, iterrev);
1197
1197
1198 /* This should never happen. */
1198 /* This should never happen. */
1199 if (baserev <= -2) {
1199 if (baserev <= -2) {
1200 /* Error should be set by index_deref() */
1200 /* Error should be set by index_deref() */
1201 assert(PyErr_Occurred());
1201 assert(PyErr_Occurred());
1202 goto bail;
1202 goto bail;
1203 }
1203 }
1204 }
1204 }
1205
1205
1206 if (iterrev == stoprev) {
1206 if (iterrev == stoprev) {
1207 stopped = 1;
1207 stopped = 1;
1208 } else {
1208 } else {
1209 PyObject *value = PyInt_FromLong(iterrev);
1209 PyObject *value = PyInt_FromLong(iterrev);
1210 if (value == NULL) {
1210 if (value == NULL) {
1211 goto bail;
1211 goto bail;
1212 }
1212 }
1213 if (PyList_Append(chain, value)) {
1213 if (PyList_Append(chain, value)) {
1214 Py_DECREF(value);
1214 Py_DECREF(value);
1215 goto bail;
1215 goto bail;
1216 }
1216 }
1217 Py_DECREF(value);
1217 Py_DECREF(value);
1218
1218
1219 stopped = 0;
1219 stopped = 0;
1220 }
1220 }
1221
1221
1222 if (PyList_Reverse(chain)) {
1222 if (PyList_Reverse(chain)) {
1223 goto bail;
1223 goto bail;
1224 }
1224 }
1225
1225
1226 result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False);
1226 result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False);
1227 Py_DECREF(chain);
1227 Py_DECREF(chain);
1228 return result;
1228 return result;
1229
1229
1230 bail:
1230 bail:
1231 Py_DECREF(chain);
1231 Py_DECREF(chain);
1232 return NULL;
1232 return NULL;
1233 }
1233 }
1234
1234
1235 static inline int64_t
1235 static inline int64_t
1236 index_segment_span(indexObject *self, Py_ssize_t start_rev, Py_ssize_t end_rev)
1236 index_segment_span(indexObject *self, Py_ssize_t start_rev, Py_ssize_t end_rev)
1237 {
1237 {
1238 int64_t start_offset;
1238 int64_t start_offset;
1239 int64_t end_offset;
1239 int64_t end_offset;
1240 int end_size;
1240 int end_size;
1241 start_offset = index_get_start(self, start_rev);
1241 start_offset = index_get_start(self, start_rev);
1242 if (start_offset < 0) {
1242 if (start_offset < 0) {
1243 return -1;
1243 return -1;
1244 }
1244 }
1245 end_offset = index_get_start(self, end_rev);
1245 end_offset = index_get_start(self, end_rev);
1246 if (end_offset < 0) {
1246 if (end_offset < 0) {
1247 return -1;
1247 return -1;
1248 }
1248 }
1249 end_size = index_get_length(self, end_rev);
1249 end_size = index_get_length(self, end_rev);
1250 if (end_size < 0) {
1250 if (end_size < 0) {
1251 return -1;
1251 return -1;
1252 }
1252 }
1253 if (end_offset < start_offset) {
1253 if (end_offset < start_offset) {
1254 PyErr_Format(PyExc_ValueError,
1254 PyErr_Format(PyExc_ValueError,
1255 "corrupted revlog index: inconsistent offset "
1255 "corrupted revlog index: inconsistent offset "
1256 "between revisions (%zd) and (%zd)",
1256 "between revisions (%zd) and (%zd)",
1257 start_rev, end_rev);
1257 start_rev, end_rev);
1258 return -1;
1258 return -1;
1259 }
1259 }
1260 return (end_offset - start_offset) + (int64_t)end_size;
1260 return (end_offset - start_offset) + (int64_t)end_size;
1261 }
1261 }
1262
1262
1263 /* returns endidx so that revs[startidx:endidx] has no empty trailing revs */
1263 /* returns endidx so that revs[startidx:endidx] has no empty trailing revs */
1264 static Py_ssize_t trim_endidx(indexObject *self, const Py_ssize_t *revs,
1264 static Py_ssize_t trim_endidx(indexObject *self, const Py_ssize_t *revs,
1265 Py_ssize_t startidx, Py_ssize_t endidx)
1265 Py_ssize_t startidx, Py_ssize_t endidx)
1266 {
1266 {
1267 int length;
1267 int length;
1268 while (endidx > 1 && endidx > startidx) {
1268 while (endidx > 1 && endidx > startidx) {
1269 length = index_get_length(self, revs[endidx - 1]);
1269 length = index_get_length(self, revs[endidx - 1]);
1270 if (length < 0) {
1270 if (length < 0) {
1271 return -1;
1271 return -1;
1272 }
1272 }
1273 if (length != 0) {
1273 if (length != 0) {
1274 break;
1274 break;
1275 }
1275 }
1276 endidx -= 1;
1276 endidx -= 1;
1277 }
1277 }
1278 return endidx;
1278 return endidx;
1279 }
1279 }
1280
1280
1281 struct Gap {
1281 struct Gap {
1282 int64_t size;
1282 int64_t size;
1283 Py_ssize_t idx;
1283 Py_ssize_t idx;
1284 };
1284 };
1285
1285
1286 static int gap_compare(const void *left, const void *right)
1286 static int gap_compare(const void *left, const void *right)
1287 {
1287 {
1288 const struct Gap *l_left = ((const struct Gap *)left);
1288 const struct Gap *l_left = ((const struct Gap *)left);
1289 const struct Gap *l_right = ((const struct Gap *)right);
1289 const struct Gap *l_right = ((const struct Gap *)right);
1290 if (l_left->size < l_right->size) {
1290 if (l_left->size < l_right->size) {
1291 return -1;
1291 return -1;
1292 } else if (l_left->size > l_right->size) {
1292 } else if (l_left->size > l_right->size) {
1293 return 1;
1293 return 1;
1294 }
1294 }
1295 return 0;
1295 return 0;
1296 }
1296 }
1297 static int Py_ssize_t_compare(const void *left, const void *right)
1297 static int Py_ssize_t_compare(const void *left, const void *right)
1298 {
1298 {
1299 const Py_ssize_t l_left = *(const Py_ssize_t *)left;
1299 const Py_ssize_t l_left = *(const Py_ssize_t *)left;
1300 const Py_ssize_t l_right = *(const Py_ssize_t *)right;
1300 const Py_ssize_t l_right = *(const Py_ssize_t *)right;
1301 if (l_left < l_right) {
1301 if (l_left < l_right) {
1302 return -1;
1302 return -1;
1303 } else if (l_left > l_right) {
1303 } else if (l_left > l_right) {
1304 return 1;
1304 return 1;
1305 }
1305 }
1306 return 0;
1306 return 0;
1307 }
1307 }
1308
1308
1309 static PyObject *index_slicechunktodensity(indexObject *self, PyObject *args)
1309 static PyObject *index_slicechunktodensity(indexObject *self, PyObject *args)
1310 {
1310 {
1311 /* method arguments */
1311 /* method arguments */
1312 PyObject *list_revs = NULL; /* revisions in the chain */
1312 PyObject *list_revs = NULL; /* revisions in the chain */
1313 double targetdensity = 0; /* min density to achieve */
1313 double targetdensity = 0; /* min density to achieve */
1314 Py_ssize_t mingapsize = 0; /* threshold to ignore gaps */
1314 Py_ssize_t mingapsize = 0; /* threshold to ignore gaps */
1315
1315
1316 /* other core variables */
1316 /* other core variables */
1317 Py_ssize_t idxlen = index_length(self);
1317 Py_ssize_t idxlen = index_length(self);
1318 Py_ssize_t i; /* used for various iteration */
1318 Py_ssize_t i; /* used for various iteration */
1319 PyObject *result = NULL; /* the final return of the function */
1319 PyObject *result = NULL; /* the final return of the function */
1320
1320
1321 /* generic information about the delta chain being slice */
1321 /* generic information about the delta chain being slice */
1322 Py_ssize_t num_revs = 0; /* size of the full delta chain */
1322 Py_ssize_t num_revs = 0; /* size of the full delta chain */
1323 Py_ssize_t *revs = NULL; /* native array of revision in the chain */
1323 Py_ssize_t *revs = NULL; /* native array of revision in the chain */
1324 int64_t chainpayload = 0; /* sum of all delta in the chain */
1324 int64_t chainpayload = 0; /* sum of all delta in the chain */
1325 int64_t deltachainspan = 0; /* distance from first byte to last byte */
1325 int64_t deltachainspan = 0; /* distance from first byte to last byte */
1326
1326
1327 /* variable used for slicing the delta chain */
1327 /* variable used for slicing the delta chain */
1328 int64_t readdata = 0; /* amount of data currently planned to be read */
1328 int64_t readdata = 0; /* amount of data currently planned to be read */
1329 double density = 0; /* ration of payload data compared to read ones */
1329 double density = 0; /* ration of payload data compared to read ones */
1330 int64_t previous_end;
1330 int64_t previous_end;
1331 struct Gap *gaps = NULL; /* array of notable gap in the chain */
1331 struct Gap *gaps = NULL; /* array of notable gap in the chain */
1332 Py_ssize_t num_gaps =
1332 Py_ssize_t num_gaps =
1333 0; /* total number of notable gap recorded so far */
1333 0; /* total number of notable gap recorded so far */
1334 Py_ssize_t *selected_indices = NULL; /* indices of gap skipped over */
1334 Py_ssize_t *selected_indices = NULL; /* indices of gap skipped over */
1335 Py_ssize_t num_selected = 0; /* number of gaps skipped */
1335 Py_ssize_t num_selected = 0; /* number of gaps skipped */
1336 PyObject *chunk = NULL; /* individual slice */
1336 PyObject *chunk = NULL; /* individual slice */
1337 PyObject *allchunks = NULL; /* all slices */
1337 PyObject *allchunks = NULL; /* all slices */
1338 Py_ssize_t previdx;
1338 Py_ssize_t previdx;
1339
1339
1340 /* parsing argument */
1340 /* parsing argument */
1341 if (!PyArg_ParseTuple(args, "O!dn", &PyList_Type, &list_revs,
1341 if (!PyArg_ParseTuple(args, "O!dn", &PyList_Type, &list_revs,
1342 &targetdensity, &mingapsize)) {
1342 &targetdensity, &mingapsize)) {
1343 goto bail;
1343 goto bail;
1344 }
1344 }
1345
1345
1346 /* If the delta chain contains a single element, we do not need slicing
1346 /* If the delta chain contains a single element, we do not need slicing
1347 */
1347 */
1348 num_revs = PyList_GET_SIZE(list_revs);
1348 num_revs = PyList_GET_SIZE(list_revs);
1349 if (num_revs <= 1) {
1349 if (num_revs <= 1) {
1350 result = PyTuple_Pack(1, list_revs);
1350 result = PyTuple_Pack(1, list_revs);
1351 goto done;
1351 goto done;
1352 }
1352 }
1353
1353
1354 /* Turn the python list into a native integer array (for efficiency) */
1354 /* Turn the python list into a native integer array (for efficiency) */
1355 revs = (Py_ssize_t *)calloc(num_revs, sizeof(Py_ssize_t));
1355 revs = (Py_ssize_t *)calloc(num_revs, sizeof(Py_ssize_t));
1356 if (revs == NULL) {
1356 if (revs == NULL) {
1357 PyErr_NoMemory();
1357 PyErr_NoMemory();
1358 goto bail;
1358 goto bail;
1359 }
1359 }
1360 for (i = 0; i < num_revs; i++) {
1360 for (i = 0; i < num_revs; i++) {
1361 Py_ssize_t revnum = PyInt_AsLong(PyList_GET_ITEM(list_revs, i));
1361 Py_ssize_t revnum = PyInt_AsLong(PyList_GET_ITEM(list_revs, i));
1362 if (revnum == -1 && PyErr_Occurred()) {
1362 if (revnum == -1 && PyErr_Occurred()) {
1363 goto bail;
1363 goto bail;
1364 }
1364 }
1365 if (revnum < nullrev || revnum >= idxlen) {
1365 if (revnum < nullrev || revnum >= idxlen) {
1366 PyErr_Format(PyExc_IndexError,
1366 PyErr_Format(PyExc_IndexError,
1367 "index out of range: %zd", revnum);
1367 "index out of range: %zd", revnum);
1368 goto bail;
1368 goto bail;
1369 }
1369 }
1370 revs[i] = revnum;
1370 revs[i] = revnum;
1371 }
1371 }
1372
1372
1373 /* Compute and check various property of the unsliced delta chain */
1373 /* Compute and check various property of the unsliced delta chain */
1374 deltachainspan = index_segment_span(self, revs[0], revs[num_revs - 1]);
1374 deltachainspan = index_segment_span(self, revs[0], revs[num_revs - 1]);
1375 if (deltachainspan < 0) {
1375 if (deltachainspan < 0) {
1376 goto bail;
1376 goto bail;
1377 }
1377 }
1378
1378
1379 if (deltachainspan <= mingapsize) {
1379 if (deltachainspan <= mingapsize) {
1380 result = PyTuple_Pack(1, list_revs);
1380 result = PyTuple_Pack(1, list_revs);
1381 goto done;
1381 goto done;
1382 }
1382 }
1383 chainpayload = 0;
1383 chainpayload = 0;
1384 for (i = 0; i < num_revs; i++) {
1384 for (i = 0; i < num_revs; i++) {
1385 int tmp = index_get_length(self, revs[i]);
1385 int tmp = index_get_length(self, revs[i]);
1386 if (tmp < 0) {
1386 if (tmp < 0) {
1387 goto bail;
1387 goto bail;
1388 }
1388 }
1389 chainpayload += tmp;
1389 chainpayload += tmp;
1390 }
1390 }
1391
1391
1392 readdata = deltachainspan;
1392 readdata = deltachainspan;
1393 density = 1.0;
1393 density = 1.0;
1394
1394
1395 if (0 < deltachainspan) {
1395 if (0 < deltachainspan) {
1396 density = (double)chainpayload / (double)deltachainspan;
1396 density = (double)chainpayload / (double)deltachainspan;
1397 }
1397 }
1398
1398
1399 if (density >= targetdensity) {
1399 if (density >= targetdensity) {
1400 result = PyTuple_Pack(1, list_revs);
1400 result = PyTuple_Pack(1, list_revs);
1401 goto done;
1401 goto done;
1402 }
1402 }
1403
1403
1404 /* if chain is too sparse, look for relevant gaps */
1404 /* if chain is too sparse, look for relevant gaps */
1405 gaps = (struct Gap *)calloc(num_revs, sizeof(struct Gap));
1405 gaps = (struct Gap *)calloc(num_revs, sizeof(struct Gap));
1406 if (gaps == NULL) {
1406 if (gaps == NULL) {
1407 PyErr_NoMemory();
1407 PyErr_NoMemory();
1408 goto bail;
1408 goto bail;
1409 }
1409 }
1410
1410
1411 previous_end = -1;
1411 previous_end = -1;
1412 for (i = 0; i < num_revs; i++) {
1412 for (i = 0; i < num_revs; i++) {
1413 int64_t revstart;
1413 int64_t revstart;
1414 int revsize;
1414 int revsize;
1415 revstart = index_get_start(self, revs[i]);
1415 revstart = index_get_start(self, revs[i]);
1416 if (revstart < 0) {
1416 if (revstart < 0) {
1417 goto bail;
1417 goto bail;
1418 };
1418 };
1419 revsize = index_get_length(self, revs[i]);
1419 revsize = index_get_length(self, revs[i]);
1420 if (revsize < 0) {
1420 if (revsize < 0) {
1421 goto bail;
1421 goto bail;
1422 };
1422 };
1423 if (revsize == 0) {
1423 if (revsize == 0) {
1424 continue;
1424 continue;
1425 }
1425 }
1426 if (previous_end >= 0) {
1426 if (previous_end >= 0) {
1427 int64_t gapsize = revstart - previous_end;
1427 int64_t gapsize = revstart - previous_end;
1428 if (gapsize > mingapsize) {
1428 if (gapsize > mingapsize) {
1429 gaps[num_gaps].size = gapsize;
1429 gaps[num_gaps].size = gapsize;
1430 gaps[num_gaps].idx = i;
1430 gaps[num_gaps].idx = i;
1431 num_gaps += 1;
1431 num_gaps += 1;
1432 }
1432 }
1433 }
1433 }
1434 previous_end = revstart + revsize;
1434 previous_end = revstart + revsize;
1435 }
1435 }
1436 if (num_gaps == 0) {
1436 if (num_gaps == 0) {
1437 result = PyTuple_Pack(1, list_revs);
1437 result = PyTuple_Pack(1, list_revs);
1438 goto done;
1438 goto done;
1439 }
1439 }
1440 qsort(gaps, num_gaps, sizeof(struct Gap), &gap_compare);
1440 qsort(gaps, num_gaps, sizeof(struct Gap), &gap_compare);
1441
1441
1442 /* Slice the largest gap first, they improve the density the most */
1442 /* Slice the largest gap first, they improve the density the most */
1443 selected_indices =
1443 selected_indices =
1444 (Py_ssize_t *)malloc((num_gaps + 1) * sizeof(Py_ssize_t));
1444 (Py_ssize_t *)malloc((num_gaps + 1) * sizeof(Py_ssize_t));
1445 if (selected_indices == NULL) {
1445 if (selected_indices == NULL) {
1446 PyErr_NoMemory();
1446 PyErr_NoMemory();
1447 goto bail;
1447 goto bail;
1448 }
1448 }
1449
1449
1450 for (i = num_gaps - 1; i >= 0; i--) {
1450 for (i = num_gaps - 1; i >= 0; i--) {
1451 selected_indices[num_selected] = gaps[i].idx;
1451 selected_indices[num_selected] = gaps[i].idx;
1452 readdata -= gaps[i].size;
1452 readdata -= gaps[i].size;
1453 num_selected += 1;
1453 num_selected += 1;
1454 if (readdata <= 0) {
1454 if (readdata <= 0) {
1455 density = 1.0;
1455 density = 1.0;
1456 } else {
1456 } else {
1457 density = (double)chainpayload / (double)readdata;
1457 density = (double)chainpayload / (double)readdata;
1458 }
1458 }
1459 if (density >= targetdensity) {
1459 if (density >= targetdensity) {
1460 break;
1460 break;
1461 }
1461 }
1462 }
1462 }
1463 qsort(selected_indices, num_selected, sizeof(Py_ssize_t),
1463 qsort(selected_indices, num_selected, sizeof(Py_ssize_t),
1464 &Py_ssize_t_compare);
1464 &Py_ssize_t_compare);
1465
1465
1466 /* create the resulting slice */
1466 /* create the resulting slice */
1467 allchunks = PyList_New(0);
1467 allchunks = PyList_New(0);
1468 if (allchunks == NULL) {
1468 if (allchunks == NULL) {
1469 goto bail;
1469 goto bail;
1470 }
1470 }
1471 previdx = 0;
1471 previdx = 0;
1472 selected_indices[num_selected] = num_revs;
1472 selected_indices[num_selected] = num_revs;
1473 for (i = 0; i <= num_selected; i++) {
1473 for (i = 0; i <= num_selected; i++) {
1474 Py_ssize_t idx = selected_indices[i];
1474 Py_ssize_t idx = selected_indices[i];
1475 Py_ssize_t endidx = trim_endidx(self, revs, previdx, idx);
1475 Py_ssize_t endidx = trim_endidx(self, revs, previdx, idx);
1476 if (endidx < 0) {
1476 if (endidx < 0) {
1477 goto bail;
1477 goto bail;
1478 }
1478 }
1479 if (previdx < endidx) {
1479 if (previdx < endidx) {
1480 chunk = PyList_GetSlice(list_revs, previdx, endidx);
1480 chunk = PyList_GetSlice(list_revs, previdx, endidx);
1481 if (chunk == NULL) {
1481 if (chunk == NULL) {
1482 goto bail;
1482 goto bail;
1483 }
1483 }
1484 if (PyList_Append(allchunks, chunk) == -1) {
1484 if (PyList_Append(allchunks, chunk) == -1) {
1485 goto bail;
1485 goto bail;
1486 }
1486 }
1487 Py_DECREF(chunk);
1487 Py_DECREF(chunk);
1488 chunk = NULL;
1488 chunk = NULL;
1489 }
1489 }
1490 previdx = idx;
1490 previdx = idx;
1491 }
1491 }
1492 result = allchunks;
1492 result = allchunks;
1493 goto done;
1493 goto done;
1494
1494
1495 bail:
1495 bail:
1496 Py_XDECREF(allchunks);
1496 Py_XDECREF(allchunks);
1497 Py_XDECREF(chunk);
1497 Py_XDECREF(chunk);
1498 done:
1498 done:
1499 free(revs);
1499 free(revs);
1500 free(gaps);
1500 free(gaps);
1501 free(selected_indices);
1501 free(selected_indices);
1502 return result;
1502 return result;
1503 }
1503 }
1504
1504
1505 static inline int nt_level(const char *node, Py_ssize_t level)
1505 static inline int nt_level(const char *node, Py_ssize_t level)
1506 {
1506 {
1507 int v = node[level >> 1];
1507 int v = node[level >> 1];
1508 if (!(level & 1))
1508 if (!(level & 1))
1509 v >>= 4;
1509 v >>= 4;
1510 return v & 0xf;
1510 return v & 0xf;
1511 }
1511 }
1512
1512
1513 /*
1513 /*
1514 * Return values:
1514 * Return values:
1515 *
1515 *
1516 * -4: match is ambiguous (multiple candidates)
1516 * -4: match is ambiguous (multiple candidates)
1517 * -2: not found
1517 * -2: not found
1518 * rest: valid rev
1518 * rest: valid rev
1519 */
1519 */
1520 static int nt_find(nodetree *self, const char *node, Py_ssize_t nodelen,
1520 static int nt_find(nodetree *self, const char *node, Py_ssize_t nodelen,
1521 int hex)
1521 int hex)
1522 {
1522 {
1523 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1523 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1524 int level, maxlevel, off;
1524 int level, maxlevel, off;
1525
1525
1526 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1526 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1527 return -1;
1527 return -1;
1528
1528
1529 if (hex)
1529 if (hex)
1530 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1530 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1531 else
1531 else
1532 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1532 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1533
1533
1534 for (level = off = 0; level < maxlevel; level++) {
1534 for (level = off = 0; level < maxlevel; level++) {
1535 int k = getnybble(node, level);
1535 int k = getnybble(node, level);
1536 nodetreenode *n = &self->nodes[off];
1536 nodetreenode *n = &self->nodes[off];
1537 int v = n->children[k];
1537 int v = n->children[k];
1538
1538
1539 if (v < 0) {
1539 if (v < 0) {
1540 const char *n;
1540 const char *n;
1541 Py_ssize_t i;
1541 Py_ssize_t i;
1542
1542
1543 v = -(v + 2);
1543 v = -(v + 2);
1544 n = index_node(self->index, v);
1544 n = index_node(self->index, v);
1545 if (n == NULL)
1545 if (n == NULL)
1546 return -2;
1546 return -2;
1547 for (i = level; i < maxlevel; i++)
1547 for (i = level; i < maxlevel; i++)
1548 if (getnybble(node, i) != nt_level(n, i))
1548 if (getnybble(node, i) != nt_level(n, i))
1549 return -2;
1549 return -2;
1550 return v;
1550 return v;
1551 }
1551 }
1552 if (v == 0)
1552 if (v == 0)
1553 return -2;
1553 return -2;
1554 off = v;
1554 off = v;
1555 }
1555 }
1556 /* multiple matches against an ambiguous prefix */
1556 /* multiple matches against an ambiguous prefix */
1557 return -4;
1557 return -4;
1558 }
1558 }
1559
1559
1560 static int nt_new(nodetree *self)
1560 static int nt_new(nodetree *self)
1561 {
1561 {
1562 if (self->length == self->capacity) {
1562 if (self->length == self->capacity) {
1563 unsigned newcapacity;
1563 unsigned newcapacity;
1564 nodetreenode *newnodes;
1564 nodetreenode *newnodes;
1565 newcapacity = self->capacity * 2;
1565 newcapacity = self->capacity * 2;
1566 if (newcapacity >= INT_MAX / sizeof(nodetreenode)) {
1566 if (newcapacity >= INT_MAX / sizeof(nodetreenode)) {
1567 PyErr_SetString(PyExc_MemoryError,
1567 PyErr_SetString(PyExc_MemoryError,
1568 "overflow in nt_new");
1568 "overflow in nt_new");
1569 return -1;
1569 return -1;
1570 }
1570 }
1571 newnodes =
1571 newnodes =
1572 realloc(self->nodes, newcapacity * sizeof(nodetreenode));
1572 realloc(self->nodes, newcapacity * sizeof(nodetreenode));
1573 if (newnodes == NULL) {
1573 if (newnodes == NULL) {
1574 PyErr_SetString(PyExc_MemoryError, "out of memory");
1574 PyErr_SetString(PyExc_MemoryError, "out of memory");
1575 return -1;
1575 return -1;
1576 }
1576 }
1577 self->capacity = newcapacity;
1577 self->capacity = newcapacity;
1578 self->nodes = newnodes;
1578 self->nodes = newnodes;
1579 memset(&self->nodes[self->length], 0,
1579 memset(&self->nodes[self->length], 0,
1580 sizeof(nodetreenode) * (self->capacity - self->length));
1580 sizeof(nodetreenode) * (self->capacity - self->length));
1581 }
1581 }
1582 return self->length++;
1582 return self->length++;
1583 }
1583 }
1584
1584
1585 static int nt_insert(nodetree *self, const char *node, int rev)
1585 static int nt_insert(nodetree *self, const char *node, int rev)
1586 {
1586 {
1587 int level = 0;
1587 int level = 0;
1588 int off = 0;
1588 int off = 0;
1589
1589
1590 while (level < 40) {
1590 while (level < 40) {
1591 int k = nt_level(node, level);
1591 int k = nt_level(node, level);
1592 nodetreenode *n;
1592 nodetreenode *n;
1593 int v;
1593 int v;
1594
1594
1595 n = &self->nodes[off];
1595 n = &self->nodes[off];
1596 v = n->children[k];
1596 v = n->children[k];
1597
1597
1598 if (v == 0) {
1598 if (v == 0) {
1599 n->children[k] = -rev - 2;
1599 n->children[k] = -rev - 2;
1600 return 0;
1600 return 0;
1601 }
1601 }
1602 if (v < 0) {
1602 if (v < 0) {
1603 const char *oldnode =
1603 const char *oldnode =
1604 index_node_existing(self->index, -(v + 2));
1604 index_node_existing(self->index, -(v + 2));
1605 int noff;
1605 int noff;
1606
1606
1607 if (oldnode == NULL)
1607 if (oldnode == NULL)
1608 return -1;
1608 return -1;
1609 if (!memcmp(oldnode, node, 20)) {
1609 if (!memcmp(oldnode, node, 20)) {
1610 n->children[k] = -rev - 2;
1610 n->children[k] = -rev - 2;
1611 return 0;
1611 return 0;
1612 }
1612 }
1613 noff = nt_new(self);
1613 noff = nt_new(self);
1614 if (noff == -1)
1614 if (noff == -1)
1615 return -1;
1615 return -1;
1616 /* self->nodes may have been changed by realloc */
1616 /* self->nodes may have been changed by realloc */
1617 self->nodes[off].children[k] = noff;
1617 self->nodes[off].children[k] = noff;
1618 off = noff;
1618 off = noff;
1619 n = &self->nodes[off];
1619 n = &self->nodes[off];
1620 n->children[nt_level(oldnode, ++level)] = v;
1620 n->children[nt_level(oldnode, ++level)] = v;
1621 if (level > self->depth)
1621 if (level > self->depth)
1622 self->depth = level;
1622 self->depth = level;
1623 self->splits += 1;
1623 self->splits += 1;
1624 } else {
1624 } else {
1625 level += 1;
1625 level += 1;
1626 off = v;
1626 off = v;
1627 }
1627 }
1628 }
1628 }
1629
1629
1630 return -1;
1630 return -1;
1631 }
1631 }
1632
1632
1633 static PyObject *ntobj_insert(nodetreeObject *self, PyObject *args)
1633 static PyObject *ntobj_insert(nodetreeObject *self, PyObject *args)
1634 {
1634 {
1635 Py_ssize_t rev;
1635 Py_ssize_t rev;
1636 const char *node;
1636 const char *node;
1637 Py_ssize_t length;
1637 Py_ssize_t length;
1638 if (!PyArg_ParseTuple(args, "n", &rev))
1638 if (!PyArg_ParseTuple(args, "n", &rev))
1639 return NULL;
1639 return NULL;
1640 length = index_length(self->nt.index);
1640 length = index_length(self->nt.index);
1641 if (rev < 0 || rev >= length) {
1641 if (rev < 0 || rev >= length) {
1642 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1642 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1643 return NULL;
1643 return NULL;
1644 }
1644 }
1645 node = index_node_existing(self->nt.index, rev);
1645 node = index_node_existing(self->nt.index, rev);
1646 if (nt_insert(&self->nt, node, (int)rev) == -1)
1646 if (nt_insert(&self->nt, node, (int)rev) == -1)
1647 return NULL;
1647 return NULL;
1648 Py_RETURN_NONE;
1648 Py_RETURN_NONE;
1649 }
1649 }
1650
1650
1651 static int nt_delete_node(nodetree *self, const char *node)
1651 static int nt_delete_node(nodetree *self, const char *node)
1652 {
1652 {
1653 /* rev==-2 happens to get encoded as 0, which is interpreted as not set
1653 /* rev==-2 happens to get encoded as 0, which is interpreted as not set
1654 */
1654 */
1655 return nt_insert(self, node, -2);
1655 return nt_insert(self, node, -2);
1656 }
1656 }
1657
1657
1658 static int nt_init(nodetree *self, indexObject *index, unsigned capacity)
1658 static int nt_init(nodetree *self, indexObject *index, unsigned capacity)
1659 {
1659 {
1660 /* Initialize before overflow-checking to avoid nt_dealloc() crash. */
1660 /* Initialize before overflow-checking to avoid nt_dealloc() crash. */
1661 self->nodes = NULL;
1661 self->nodes = NULL;
1662
1662
1663 self->index = index;
1663 self->index = index;
1664 /* The input capacity is in terms of revisions, while the field is in
1664 /* The input capacity is in terms of revisions, while the field is in
1665 * terms of nodetree nodes. */
1665 * terms of nodetree nodes. */
1666 self->capacity = (capacity < 4 ? 4 : capacity / 2);
1666 self->capacity = (capacity < 4 ? 4 : capacity / 2);
1667 self->depth = 0;
1667 self->depth = 0;
1668 self->splits = 0;
1668 self->splits = 0;
1669 if ((size_t)self->capacity > INT_MAX / sizeof(nodetreenode)) {
1669 if ((size_t)self->capacity > INT_MAX / sizeof(nodetreenode)) {
1670 PyErr_SetString(PyExc_ValueError, "overflow in init_nt");
1670 PyErr_SetString(PyExc_ValueError, "overflow in init_nt");
1671 return -1;
1671 return -1;
1672 }
1672 }
1673 self->nodes = calloc(self->capacity, sizeof(nodetreenode));
1673 self->nodes = calloc(self->capacity, sizeof(nodetreenode));
1674 if (self->nodes == NULL) {
1674 if (self->nodes == NULL) {
1675 PyErr_NoMemory();
1675 PyErr_NoMemory();
1676 return -1;
1676 return -1;
1677 }
1677 }
1678 self->length = 1;
1678 self->length = 1;
1679 return 0;
1679 return 0;
1680 }
1680 }
1681
1681
1682 static int ntobj_init(nodetreeObject *self, PyObject *args)
1682 static int ntobj_init(nodetreeObject *self, PyObject *args)
1683 {
1683 {
1684 PyObject *index;
1684 PyObject *index;
1685 unsigned capacity;
1685 unsigned capacity;
1686 if (!PyArg_ParseTuple(args, "O!I", &HgRevlogIndex_Type, &index,
1686 if (!PyArg_ParseTuple(args, "O!I", &HgRevlogIndex_Type, &index,
1687 &capacity))
1687 &capacity))
1688 return -1;
1688 return -1;
1689 Py_INCREF(index);
1689 Py_INCREF(index);
1690 return nt_init(&self->nt, (indexObject *)index, capacity);
1690 return nt_init(&self->nt, (indexObject *)index, capacity);
1691 }
1691 }
1692
1692
1693 static int nt_partialmatch(nodetree *self, const char *node, Py_ssize_t nodelen)
1693 static int nt_partialmatch(nodetree *self, const char *node, Py_ssize_t nodelen)
1694 {
1694 {
1695 return nt_find(self, node, nodelen, 1);
1695 return nt_find(self, node, nodelen, 1);
1696 }
1696 }
1697
1697
1698 /*
1698 /*
1699 * Find the length of the shortest unique prefix of node.
1699 * Find the length of the shortest unique prefix of node.
1700 *
1700 *
1701 * Return values:
1701 * Return values:
1702 *
1702 *
1703 * -3: error (exception set)
1703 * -3: error (exception set)
1704 * -2: not found (no exception set)
1704 * -2: not found (no exception set)
1705 * rest: length of shortest prefix
1705 * rest: length of shortest prefix
1706 */
1706 */
1707 static int nt_shortest(nodetree *self, const char *node)
1707 static int nt_shortest(nodetree *self, const char *node)
1708 {
1708 {
1709 int level, off;
1709 int level, off;
1710
1710
1711 for (level = off = 0; level < 40; level++) {
1711 for (level = off = 0; level < 40; level++) {
1712 int k, v;
1712 int k, v;
1713 nodetreenode *n = &self->nodes[off];
1713 nodetreenode *n = &self->nodes[off];
1714 k = nt_level(node, level);
1714 k = nt_level(node, level);
1715 v = n->children[k];
1715 v = n->children[k];
1716 if (v < 0) {
1716 if (v < 0) {
1717 const char *n;
1717 const char *n;
1718 v = -(v + 2);
1718 v = -(v + 2);
1719 n = index_node_existing(self->index, v);
1719 n = index_node_existing(self->index, v);
1720 if (n == NULL)
1720 if (n == NULL)
1721 return -3;
1721 return -3;
1722 if (memcmp(node, n, 20) != 0)
1722 if (memcmp(node, n, 20) != 0)
1723 /*
1723 /*
1724 * Found a unique prefix, but it wasn't for the
1724 * Found a unique prefix, but it wasn't for the
1725 * requested node (i.e the requested node does
1725 * requested node (i.e the requested node does
1726 * not exist).
1726 * not exist).
1727 */
1727 */
1728 return -2;
1728 return -2;
1729 return level + 1;
1729 return level + 1;
1730 }
1730 }
1731 if (v == 0)
1731 if (v == 0)
1732 return -2;
1732 return -2;
1733 off = v;
1733 off = v;
1734 }
1734 }
1735 /*
1735 /*
1736 * The node was still not unique after 40 hex digits, so this won't
1736 * The node was still not unique after 40 hex digits, so this won't
1737 * happen. Also, if we get here, then there's a programming error in
1737 * happen. Also, if we get here, then there's a programming error in
1738 * this file that made us insert a node longer than 40 hex digits.
1738 * this file that made us insert a node longer than 40 hex digits.
1739 */
1739 */
1740 PyErr_SetString(PyExc_Exception, "broken node tree");
1740 PyErr_SetString(PyExc_Exception, "broken node tree");
1741 return -3;
1741 return -3;
1742 }
1742 }
1743
1743
1744 static PyObject *ntobj_shortest(nodetreeObject *self, PyObject *args)
1744 static PyObject *ntobj_shortest(nodetreeObject *self, PyObject *args)
1745 {
1745 {
1746 PyObject *val;
1746 PyObject *val;
1747 char *node;
1747 char *node;
1748 int length;
1748 int length;
1749
1749
1750 if (!PyArg_ParseTuple(args, "O", &val))
1750 if (!PyArg_ParseTuple(args, "O", &val))
1751 return NULL;
1751 return NULL;
1752 if (node_check(val, &node) == -1)
1752 if (node_check(val, &node) == -1)
1753 return NULL;
1753 return NULL;
1754
1754
1755 length = nt_shortest(&self->nt, node);
1755 length = nt_shortest(&self->nt, node);
1756 if (length == -3)
1756 if (length == -3)
1757 return NULL;
1757 return NULL;
1758 if (length == -2) {
1758 if (length == -2) {
1759 raise_revlog_error();
1759 raise_revlog_error();
1760 return NULL;
1760 return NULL;
1761 }
1761 }
1762 return PyInt_FromLong(length);
1762 return PyInt_FromLong(length);
1763 }
1763 }
1764
1764
1765 static void nt_dealloc(nodetree *self)
1765 static void nt_dealloc(nodetree *self)
1766 {
1766 {
1767 free(self->nodes);
1767 free(self->nodes);
1768 self->nodes = NULL;
1768 self->nodes = NULL;
1769 }
1769 }
1770
1770
1771 static void ntobj_dealloc(nodetreeObject *self)
1771 static void ntobj_dealloc(nodetreeObject *self)
1772 {
1772 {
1773 Py_XDECREF(self->nt.index);
1773 Py_XDECREF(self->nt.index);
1774 nt_dealloc(&self->nt);
1774 nt_dealloc(&self->nt);
1775 PyObject_Del(self);
1775 PyObject_Del(self);
1776 }
1776 }
1777
1777
1778 static PyMethodDef ntobj_methods[] = {
1778 static PyMethodDef ntobj_methods[] = {
1779 {"insert", (PyCFunction)ntobj_insert, METH_VARARGS,
1779 {"insert", (PyCFunction)ntobj_insert, METH_VARARGS,
1780 "insert an index entry"},
1780 "insert an index entry"},
1781 {"shortest", (PyCFunction)ntobj_shortest, METH_VARARGS,
1781 {"shortest", (PyCFunction)ntobj_shortest, METH_VARARGS,
1782 "find length of shortest hex nodeid of a binary ID"},
1782 "find length of shortest hex nodeid of a binary ID"},
1783 {NULL} /* Sentinel */
1783 {NULL} /* Sentinel */
1784 };
1784 };
1785
1785
1786 static PyTypeObject nodetreeType = {
1786 static PyTypeObject nodetreeType = {
1787 PyVarObject_HEAD_INIT(NULL, 0) /* header */
1787 PyVarObject_HEAD_INIT(NULL, 0) /* header */
1788 "parsers.nodetree", /* tp_name */
1788 "parsers.nodetree", /* tp_name */
1789 sizeof(nodetreeObject), /* tp_basicsize */
1789 sizeof(nodetreeObject), /* tp_basicsize */
1790 0, /* tp_itemsize */
1790 0, /* tp_itemsize */
1791 (destructor)ntobj_dealloc, /* tp_dealloc */
1791 (destructor)ntobj_dealloc, /* tp_dealloc */
1792 0, /* tp_print */
1792 0, /* tp_print */
1793 0, /* tp_getattr */
1793 0, /* tp_getattr */
1794 0, /* tp_setattr */
1794 0, /* tp_setattr */
1795 0, /* tp_compare */
1795 0, /* tp_compare */
1796 0, /* tp_repr */
1796 0, /* tp_repr */
1797 0, /* tp_as_number */
1797 0, /* tp_as_number */
1798 0, /* tp_as_sequence */
1798 0, /* tp_as_sequence */
1799 0, /* tp_as_mapping */
1799 0, /* tp_as_mapping */
1800 0, /* tp_hash */
1800 0, /* tp_hash */
1801 0, /* tp_call */
1801 0, /* tp_call */
1802 0, /* tp_str */
1802 0, /* tp_str */
1803 0, /* tp_getattro */
1803 0, /* tp_getattro */
1804 0, /* tp_setattro */
1804 0, /* tp_setattro */
1805 0, /* tp_as_buffer */
1805 0, /* tp_as_buffer */
1806 Py_TPFLAGS_DEFAULT, /* tp_flags */
1806 Py_TPFLAGS_DEFAULT, /* tp_flags */
1807 "nodetree", /* tp_doc */
1807 "nodetree", /* tp_doc */
1808 0, /* tp_traverse */
1808 0, /* tp_traverse */
1809 0, /* tp_clear */
1809 0, /* tp_clear */
1810 0, /* tp_richcompare */
1810 0, /* tp_richcompare */
1811 0, /* tp_weaklistoffset */
1811 0, /* tp_weaklistoffset */
1812 0, /* tp_iter */
1812 0, /* tp_iter */
1813 0, /* tp_iternext */
1813 0, /* tp_iternext */
1814 ntobj_methods, /* tp_methods */
1814 ntobj_methods, /* tp_methods */
1815 0, /* tp_members */
1815 0, /* tp_members */
1816 0, /* tp_getset */
1816 0, /* tp_getset */
1817 0, /* tp_base */
1817 0, /* tp_base */
1818 0, /* tp_dict */
1818 0, /* tp_dict */
1819 0, /* tp_descr_get */
1819 0, /* tp_descr_get */
1820 0, /* tp_descr_set */
1820 0, /* tp_descr_set */
1821 0, /* tp_dictoffset */
1821 0, /* tp_dictoffset */
1822 (initproc)ntobj_init, /* tp_init */
1822 (initproc)ntobj_init, /* tp_init */
1823 0, /* tp_alloc */
1823 0, /* tp_alloc */
1824 };
1824 };
1825
1825
1826 static int index_init_nt(indexObject *self)
1826 static int index_init_nt(indexObject *self)
1827 {
1827 {
1828 if (!self->ntinitialized) {
1828 if (!self->ntinitialized) {
1829 if (nt_init(&self->nt, self, (int)self->raw_length) == -1) {
1829 if (nt_init(&self->nt, self, (int)self->raw_length) == -1) {
1830 nt_dealloc(&self->nt);
1830 nt_dealloc(&self->nt);
1831 return -1;
1831 return -1;
1832 }
1832 }
1833 if (nt_insert(&self->nt, nullid, -1) == -1) {
1833 if (nt_insert(&self->nt, nullid, -1) == -1) {
1834 nt_dealloc(&self->nt);
1834 nt_dealloc(&self->nt);
1835 return -1;
1835 return -1;
1836 }
1836 }
1837 self->ntinitialized = 1;
1837 self->ntinitialized = 1;
1838 self->ntrev = (int)index_length(self);
1838 self->ntrev = (int)index_length(self);
1839 self->ntlookups = 1;
1839 self->ntlookups = 1;
1840 self->ntmisses = 0;
1840 self->ntmisses = 0;
1841 }
1841 }
1842 return 0;
1842 return 0;
1843 }
1843 }
1844
1844
1845 /*
1845 /*
1846 * Return values:
1846 * Return values:
1847 *
1847 *
1848 * -3: error (exception set)
1848 * -3: error (exception set)
1849 * -2: not found (no exception set)
1849 * -2: not found (no exception set)
1850 * rest: valid rev
1850 * rest: valid rev
1851 */
1851 */
1852 static int index_find_node(indexObject *self, const char *node,
1852 static int index_find_node(indexObject *self, const char *node,
1853 Py_ssize_t nodelen)
1853 Py_ssize_t nodelen)
1854 {
1854 {
1855 int rev;
1855 int rev;
1856
1856
1857 if (index_init_nt(self) == -1)
1857 if (index_init_nt(self) == -1)
1858 return -3;
1858 return -3;
1859
1859
1860 self->ntlookups++;
1860 self->ntlookups++;
1861 rev = nt_find(&self->nt, node, nodelen, 0);
1861 rev = nt_find(&self->nt, node, nodelen, 0);
1862 if (rev >= -1)
1862 if (rev >= -1)
1863 return rev;
1863 return rev;
1864
1864
1865 /*
1865 /*
1866 * For the first handful of lookups, we scan the entire index,
1866 * For the first handful of lookups, we scan the entire index,
1867 * and cache only the matching nodes. This optimizes for cases
1867 * and cache only the matching nodes. This optimizes for cases
1868 * like "hg tip", where only a few nodes are accessed.
1868 * like "hg tip", where only a few nodes are accessed.
1869 *
1869 *
1870 * After that, we cache every node we visit, using a single
1870 * After that, we cache every node we visit, using a single
1871 * scan amortized over multiple lookups. This gives the best
1871 * scan amortized over multiple lookups. This gives the best
1872 * bulk performance, e.g. for "hg log".
1872 * bulk performance, e.g. for "hg log".
1873 */
1873 */
1874 if (self->ntmisses++ < 4) {
1874 if (self->ntmisses++ < 4) {
1875 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1875 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1876 const char *n = index_node_existing(self, rev);
1876 const char *n = index_node_existing(self, rev);
1877 if (n == NULL)
1877 if (n == NULL)
1878 return -3;
1878 return -3;
1879 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1879 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1880 if (nt_insert(&self->nt, n, rev) == -1)
1880 if (nt_insert(&self->nt, n, rev) == -1)
1881 return -3;
1881 return -3;
1882 break;
1882 break;
1883 }
1883 }
1884 }
1884 }
1885 } else {
1885 } else {
1886 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1886 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1887 const char *n = index_node_existing(self, rev);
1887 const char *n = index_node_existing(self, rev);
1888 if (n == NULL)
1888 if (n == NULL)
1889 return -3;
1889 return -3;
1890 if (nt_insert(&self->nt, n, rev) == -1) {
1890 if (nt_insert(&self->nt, n, rev) == -1) {
1891 self->ntrev = rev + 1;
1891 self->ntrev = rev + 1;
1892 return -3;
1892 return -3;
1893 }
1893 }
1894 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1894 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1895 break;
1895 break;
1896 }
1896 }
1897 }
1897 }
1898 self->ntrev = rev;
1898 self->ntrev = rev;
1899 }
1899 }
1900
1900
1901 if (rev >= 0)
1901 if (rev >= 0)
1902 return rev;
1902 return rev;
1903 return -2;
1903 return -2;
1904 }
1904 }
1905
1905
1906 static PyObject *index_getitem(indexObject *self, PyObject *value)
1906 static PyObject *index_getitem(indexObject *self, PyObject *value)
1907 {
1907 {
1908 char *node;
1908 char *node;
1909 int rev;
1909 int rev;
1910
1910
1911 if (PyInt_Check(value)) {
1911 if (PyInt_Check(value)) {
1912 long idx;
1912 long idx;
1913 if (!pylong_to_long(value, &idx)) {
1913 if (!pylong_to_long(value, &idx)) {
1914 return NULL;
1914 return NULL;
1915 }
1915 }
1916 return index_get(self, idx);
1916 return index_get(self, idx);
1917 }
1917 }
1918
1918
1919 if (node_check(value, &node) == -1)
1919 if (node_check(value, &node) == -1)
1920 return NULL;
1920 return NULL;
1921 rev = index_find_node(self, node, 20);
1921 rev = index_find_node(self, node, 20);
1922 if (rev >= -1)
1922 if (rev >= -1)
1923 return PyInt_FromLong(rev);
1923 return PyInt_FromLong(rev);
1924 if (rev == -2)
1924 if (rev == -2)
1925 raise_revlog_error();
1925 raise_revlog_error();
1926 return NULL;
1926 return NULL;
1927 }
1927 }
1928
1928
1929 /*
1929 /*
1930 * Fully populate the radix tree.
1930 * Fully populate the radix tree.
1931 */
1931 */
1932 static int index_populate_nt(indexObject *self)
1932 static int index_populate_nt(indexObject *self)
1933 {
1933 {
1934 int rev;
1934 int rev;
1935 if (self->ntrev > 0) {
1935 if (self->ntrev > 0) {
1936 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1936 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1937 const char *n = index_node_existing(self, rev);
1937 const char *n = index_node_existing(self, rev);
1938 if (n == NULL)
1938 if (n == NULL)
1939 return -1;
1939 return -1;
1940 if (nt_insert(&self->nt, n, rev) == -1)
1940 if (nt_insert(&self->nt, n, rev) == -1)
1941 return -1;
1941 return -1;
1942 }
1942 }
1943 self->ntrev = -1;
1943 self->ntrev = -1;
1944 }
1944 }
1945 return 0;
1945 return 0;
1946 }
1946 }
1947
1947
1948 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1948 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1949 {
1949 {
1950 const char *fullnode;
1950 const char *fullnode;
1951 Py_ssize_t nodelen;
1951 Py_ssize_t nodelen;
1952 char *node;
1952 char *node;
1953 int rev, i;
1953 int rev, i;
1954
1954
1955 if (!PyArg_ParseTuple(args, PY23("s#", "y#"), &node, &nodelen))
1955 if (!PyArg_ParseTuple(args, PY23("s#", "y#"), &node, &nodelen))
1956 return NULL;
1956 return NULL;
1957
1957
1958 if (nodelen < 1) {
1958 if (nodelen < 1) {
1959 PyErr_SetString(PyExc_ValueError, "key too short");
1959 PyErr_SetString(PyExc_ValueError, "key too short");
1960 return NULL;
1960 return NULL;
1961 }
1961 }
1962
1962
1963 if (nodelen > 40) {
1963 if (nodelen > 40) {
1964 PyErr_SetString(PyExc_ValueError, "key too long");
1964 PyErr_SetString(PyExc_ValueError, "key too long");
1965 return NULL;
1965 return NULL;
1966 }
1966 }
1967
1967
1968 for (i = 0; i < nodelen; i++)
1968 for (i = 0; i < nodelen; i++)
1969 hexdigit(node, i);
1969 hexdigit(node, i);
1970 if (PyErr_Occurred()) {
1970 if (PyErr_Occurred()) {
1971 /* input contains non-hex characters */
1971 /* input contains non-hex characters */
1972 PyErr_Clear();
1972 PyErr_Clear();
1973 Py_RETURN_NONE;
1973 Py_RETURN_NONE;
1974 }
1974 }
1975
1975
1976 if (index_init_nt(self) == -1)
1976 if (index_init_nt(self) == -1)
1977 return NULL;
1977 return NULL;
1978 if (index_populate_nt(self) == -1)
1978 if (index_populate_nt(self) == -1)
1979 return NULL;
1979 return NULL;
1980 rev = nt_partialmatch(&self->nt, node, nodelen);
1980 rev = nt_partialmatch(&self->nt, node, nodelen);
1981
1981
1982 switch (rev) {
1982 switch (rev) {
1983 case -4:
1983 case -4:
1984 raise_revlog_error();
1984 raise_revlog_error();
1985 return NULL;
1985 return NULL;
1986 case -2:
1986 case -2:
1987 Py_RETURN_NONE;
1987 Py_RETURN_NONE;
1988 case -1:
1988 case -1:
1989 return PyBytes_FromStringAndSize(nullid, 20);
1989 return PyBytes_FromStringAndSize(nullid, 20);
1990 }
1990 }
1991
1991
1992 fullnode = index_node_existing(self, rev);
1992 fullnode = index_node_existing(self, rev);
1993 if (fullnode == NULL) {
1993 if (fullnode == NULL) {
1994 return NULL;
1994 return NULL;
1995 }
1995 }
1996 return PyBytes_FromStringAndSize(fullnode, 20);
1996 return PyBytes_FromStringAndSize(fullnode, 20);
1997 }
1997 }
1998
1998
1999 static PyObject *index_shortest(indexObject *self, PyObject *args)
1999 static PyObject *index_shortest(indexObject *self, PyObject *args)
2000 {
2000 {
2001 PyObject *val;
2001 PyObject *val;
2002 char *node;
2002 char *node;
2003 int length;
2003 int length;
2004
2004
2005 if (!PyArg_ParseTuple(args, "O", &val))
2005 if (!PyArg_ParseTuple(args, "O", &val))
2006 return NULL;
2006 return NULL;
2007 if (node_check(val, &node) == -1)
2007 if (node_check(val, &node) == -1)
2008 return NULL;
2008 return NULL;
2009
2009
2010 self->ntlookups++;
2010 self->ntlookups++;
2011 if (index_init_nt(self) == -1)
2011 if (index_init_nt(self) == -1)
2012 return NULL;
2012 return NULL;
2013 if (index_populate_nt(self) == -1)
2013 if (index_populate_nt(self) == -1)
2014 return NULL;
2014 return NULL;
2015 length = nt_shortest(&self->nt, node);
2015 length = nt_shortest(&self->nt, node);
2016 if (length == -3)
2016 if (length == -3)
2017 return NULL;
2017 return NULL;
2018 if (length == -2) {
2018 if (length == -2) {
2019 raise_revlog_error();
2019 raise_revlog_error();
2020 return NULL;
2020 return NULL;
2021 }
2021 }
2022 return PyInt_FromLong(length);
2022 return PyInt_FromLong(length);
2023 }
2023 }
2024
2024
2025 static PyObject *index_m_get(indexObject *self, PyObject *args)
2025 static PyObject *index_m_get(indexObject *self, PyObject *args)
2026 {
2026 {
2027 PyObject *val;
2027 PyObject *val;
2028 char *node;
2028 char *node;
2029 int rev;
2029 int rev;
2030
2030
2031 if (!PyArg_ParseTuple(args, "O", &val))
2031 if (!PyArg_ParseTuple(args, "O", &val))
2032 return NULL;
2032 return NULL;
2033 if (node_check(val, &node) == -1)
2033 if (node_check(val, &node) == -1)
2034 return NULL;
2034 return NULL;
2035 rev = index_find_node(self, node, 20);
2035 rev = index_find_node(self, node, 20);
2036 if (rev == -3)
2036 if (rev == -3)
2037 return NULL;
2037 return NULL;
2038 if (rev == -2)
2038 if (rev == -2)
2039 Py_RETURN_NONE;
2039 Py_RETURN_NONE;
2040 return PyInt_FromLong(rev);
2040 return PyInt_FromLong(rev);
2041 }
2041 }
2042
2042
2043 static int index_contains(indexObject *self, PyObject *value)
2043 static int index_contains(indexObject *self, PyObject *value)
2044 {
2044 {
2045 char *node;
2045 char *node;
2046
2046
2047 if (PyInt_Check(value)) {
2047 if (PyInt_Check(value)) {
2048 long rev;
2048 long rev;
2049 if (!pylong_to_long(value, &rev)) {
2049 if (!pylong_to_long(value, &rev)) {
2050 return -1;
2050 return -1;
2051 }
2051 }
2052 return rev >= -1 && rev < index_length(self);
2052 return rev >= -1 && rev < index_length(self);
2053 }
2053 }
2054
2054
2055 if (node_check(value, &node) == -1)
2055 if (node_check(value, &node) == -1)
2056 return -1;
2056 return -1;
2057
2057
2058 switch (index_find_node(self, node, 20)) {
2058 switch (index_find_node(self, node, 20)) {
2059 case -3:
2059 case -3:
2060 return -1;
2060 return -1;
2061 case -2:
2061 case -2:
2062 return 0;
2062 return 0;
2063 default:
2063 default:
2064 return 1;
2064 return 1;
2065 }
2065 }
2066 }
2066 }
2067
2067
2068 typedef uint64_t bitmask;
2068 typedef uint64_t bitmask;
2069
2069
2070 /*
2070 /*
2071 * Given a disjoint set of revs, return all candidates for the
2071 * Given a disjoint set of revs, return all candidates for the
2072 * greatest common ancestor. In revset notation, this is the set
2072 * greatest common ancestor. In revset notation, this is the set
2073 * "heads(::a and ::b and ...)"
2073 * "heads(::a and ::b and ...)"
2074 */
2074 */
2075 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
2075 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
2076 int revcount)
2076 int revcount)
2077 {
2077 {
2078 const bitmask allseen = (1ull << revcount) - 1;
2078 const bitmask allseen = (1ull << revcount) - 1;
2079 const bitmask poison = 1ull << revcount;
2079 const bitmask poison = 1ull << revcount;
2080 PyObject *gca = PyList_New(0);
2080 PyObject *gca = PyList_New(0);
2081 int i, v, interesting;
2081 int i, v, interesting;
2082 int maxrev = -1;
2082 int maxrev = -1;
2083 bitmask sp;
2083 bitmask sp;
2084 bitmask *seen;
2084 bitmask *seen;
2085
2085
2086 if (gca == NULL)
2086 if (gca == NULL)
2087 return PyErr_NoMemory();
2087 return PyErr_NoMemory();
2088
2088
2089 for (i = 0; i < revcount; i++) {
2089 for (i = 0; i < revcount; i++) {
2090 if (revs[i] > maxrev)
2090 if (revs[i] > maxrev)
2091 maxrev = revs[i];
2091 maxrev = revs[i];
2092 }
2092 }
2093
2093
2094 seen = calloc(sizeof(*seen), maxrev + 1);
2094 seen = calloc(sizeof(*seen), maxrev + 1);
2095 if (seen == NULL) {
2095 if (seen == NULL) {
2096 Py_DECREF(gca);
2096 Py_DECREF(gca);
2097 return PyErr_NoMemory();
2097 return PyErr_NoMemory();
2098 }
2098 }
2099
2099
2100 for (i = 0; i < revcount; i++)
2100 for (i = 0; i < revcount; i++)
2101 seen[revs[i]] = 1ull << i;
2101 seen[revs[i]] = 1ull << i;
2102
2102
2103 interesting = revcount;
2103 interesting = revcount;
2104
2104
2105 for (v = maxrev; v >= 0 && interesting; v--) {
2105 for (v = maxrev; v >= 0 && interesting; v--) {
2106 bitmask sv = seen[v];
2106 bitmask sv = seen[v];
2107 int parents[2];
2107 int parents[2];
2108
2108
2109 if (!sv)
2109 if (!sv)
2110 continue;
2110 continue;
2111
2111
2112 if (sv < poison) {
2112 if (sv < poison) {
2113 interesting -= 1;
2113 interesting -= 1;
2114 if (sv == allseen) {
2114 if (sv == allseen) {
2115 PyObject *obj = PyInt_FromLong(v);
2115 PyObject *obj = PyInt_FromLong(v);
2116 if (obj == NULL)
2116 if (obj == NULL)
2117 goto bail;
2117 goto bail;
2118 if (PyList_Append(gca, obj) == -1) {
2118 if (PyList_Append(gca, obj) == -1) {
2119 Py_DECREF(obj);
2119 Py_DECREF(obj);
2120 goto bail;
2120 goto bail;
2121 }
2121 }
2122 sv |= poison;
2122 sv |= poison;
2123 for (i = 0; i < revcount; i++) {
2123 for (i = 0; i < revcount; i++) {
2124 if (revs[i] == v)
2124 if (revs[i] == v)
2125 goto done;
2125 goto done;
2126 }
2126 }
2127 }
2127 }
2128 }
2128 }
2129 if (index_get_parents(self, v, parents, maxrev) < 0)
2129 if (index_get_parents(self, v, parents, maxrev) < 0)
2130 goto bail;
2130 goto bail;
2131
2131
2132 for (i = 0; i < 2; i++) {
2132 for (i = 0; i < 2; i++) {
2133 int p = parents[i];
2133 int p = parents[i];
2134 if (p == -1)
2134 if (p == -1)
2135 continue;
2135 continue;
2136 sp = seen[p];
2136 sp = seen[p];
2137 if (sv < poison) {
2137 if (sv < poison) {
2138 if (sp == 0) {
2138 if (sp == 0) {
2139 seen[p] = sv;
2139 seen[p] = sv;
2140 interesting++;
2140 interesting++;
2141 } else if (sp != sv)
2141 } else if (sp != sv)
2142 seen[p] |= sv;
2142 seen[p] |= sv;
2143 } else {
2143 } else {
2144 if (sp && sp < poison)
2144 if (sp && sp < poison)
2145 interesting--;
2145 interesting--;
2146 seen[p] = sv;
2146 seen[p] = sv;
2147 }
2147 }
2148 }
2148 }
2149 }
2149 }
2150
2150
2151 done:
2151 done:
2152 free(seen);
2152 free(seen);
2153 return gca;
2153 return gca;
2154 bail:
2154 bail:
2155 free(seen);
2155 free(seen);
2156 Py_XDECREF(gca);
2156 Py_XDECREF(gca);
2157 return NULL;
2157 return NULL;
2158 }
2158 }
2159
2159
2160 /*
2160 /*
2161 * Given a disjoint set of revs, return the subset with the longest
2161 * Given a disjoint set of revs, return the subset with the longest
2162 * path to the root.
2162 * path to the root.
2163 */
2163 */
2164 static PyObject *find_deepest(indexObject *self, PyObject *revs)
2164 static PyObject *find_deepest(indexObject *self, PyObject *revs)
2165 {
2165 {
2166 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
2166 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
2167 static const Py_ssize_t capacity = 24;
2167 static const Py_ssize_t capacity = 24;
2168 int *depth, *interesting = NULL;
2168 int *depth, *interesting = NULL;
2169 int i, j, v, ninteresting;
2169 int i, j, v, ninteresting;
2170 PyObject *dict = NULL, *keys = NULL;
2170 PyObject *dict = NULL, *keys = NULL;
2171 long *seen = NULL;
2171 long *seen = NULL;
2172 int maxrev = -1;
2172 int maxrev = -1;
2173 long final;
2173 long final;
2174
2174
2175 if (revcount > capacity) {
2175 if (revcount > capacity) {
2176 PyErr_Format(PyExc_OverflowError,
2176 PyErr_Format(PyExc_OverflowError,
2177 "bitset size (%ld) > capacity (%ld)",
2177 "bitset size (%ld) > capacity (%ld)",
2178 (long)revcount, (long)capacity);
2178 (long)revcount, (long)capacity);
2179 return NULL;
2179 return NULL;
2180 }
2180 }
2181
2181
2182 for (i = 0; i < revcount; i++) {
2182 for (i = 0; i < revcount; i++) {
2183 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
2183 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
2184 if (n > maxrev)
2184 if (n > maxrev)
2185 maxrev = n;
2185 maxrev = n;
2186 }
2186 }
2187
2187
2188 depth = calloc(sizeof(*depth), maxrev + 1);
2188 depth = calloc(sizeof(*depth), maxrev + 1);
2189 if (depth == NULL)
2189 if (depth == NULL)
2190 return PyErr_NoMemory();
2190 return PyErr_NoMemory();
2191
2191
2192 seen = calloc(sizeof(*seen), maxrev + 1);
2192 seen = calloc(sizeof(*seen), maxrev + 1);
2193 if (seen == NULL) {
2193 if (seen == NULL) {
2194 PyErr_NoMemory();
2194 PyErr_NoMemory();
2195 goto bail;
2195 goto bail;
2196 }
2196 }
2197
2197
2198 interesting = calloc(sizeof(*interesting), ((size_t)1) << revcount);
2198 interesting = calloc(sizeof(*interesting), ((size_t)1) << revcount);
2199 if (interesting == NULL) {
2199 if (interesting == NULL) {
2200 PyErr_NoMemory();
2200 PyErr_NoMemory();
2201 goto bail;
2201 goto bail;
2202 }
2202 }
2203
2203
2204 if (PyList_Sort(revs) == -1)
2204 if (PyList_Sort(revs) == -1)
2205 goto bail;
2205 goto bail;
2206
2206
2207 for (i = 0; i < revcount; i++) {
2207 for (i = 0; i < revcount; i++) {
2208 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
2208 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
2209 long b = 1l << i;
2209 long b = 1l << i;
2210 depth[n] = 1;
2210 depth[n] = 1;
2211 seen[n] = b;
2211 seen[n] = b;
2212 interesting[b] = 1;
2212 interesting[b] = 1;
2213 }
2213 }
2214
2214
2215 /* invariant: ninteresting is the number of non-zero entries in
2215 /* invariant: ninteresting is the number of non-zero entries in
2216 * interesting. */
2216 * interesting. */
2217 ninteresting = (int)revcount;
2217 ninteresting = (int)revcount;
2218
2218
2219 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
2219 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
2220 int dv = depth[v];
2220 int dv = depth[v];
2221 int parents[2];
2221 int parents[2];
2222 long sv;
2222 long sv;
2223
2223
2224 if (dv == 0)
2224 if (dv == 0)
2225 continue;
2225 continue;
2226
2226
2227 sv = seen[v];
2227 sv = seen[v];
2228 if (index_get_parents(self, v, parents, maxrev) < 0)
2228 if (index_get_parents(self, v, parents, maxrev) < 0)
2229 goto bail;
2229 goto bail;
2230
2230
2231 for (i = 0; i < 2; i++) {
2231 for (i = 0; i < 2; i++) {
2232 int p = parents[i];
2232 int p = parents[i];
2233 long sp;
2233 long sp;
2234 int dp;
2234 int dp;
2235
2235
2236 if (p == -1)
2236 if (p == -1)
2237 continue;
2237 continue;
2238
2238
2239 dp = depth[p];
2239 dp = depth[p];
2240 sp = seen[p];
2240 sp = seen[p];
2241 if (dp <= dv) {
2241 if (dp <= dv) {
2242 depth[p] = dv + 1;
2242 depth[p] = dv + 1;
2243 if (sp != sv) {
2243 if (sp != sv) {
2244 interesting[sv] += 1;
2244 interesting[sv] += 1;
2245 seen[p] = sv;
2245 seen[p] = sv;
2246 if (sp) {
2246 if (sp) {
2247 interesting[sp] -= 1;
2247 interesting[sp] -= 1;
2248 if (interesting[sp] == 0)
2248 if (interesting[sp] == 0)
2249 ninteresting -= 1;
2249 ninteresting -= 1;
2250 }
2250 }
2251 }
2251 }
2252 } else if (dv == dp - 1) {
2252 } else if (dv == dp - 1) {
2253 long nsp = sp | sv;
2253 long nsp = sp | sv;
2254 if (nsp == sp)
2254 if (nsp == sp)
2255 continue;
2255 continue;
2256 seen[p] = nsp;
2256 seen[p] = nsp;
2257 interesting[sp] -= 1;
2257 interesting[sp] -= 1;
2258 if (interesting[sp] == 0)
2258 if (interesting[sp] == 0)
2259 ninteresting -= 1;
2259 ninteresting -= 1;
2260 if (interesting[nsp] == 0)
2260 if (interesting[nsp] == 0)
2261 ninteresting += 1;
2261 ninteresting += 1;
2262 interesting[nsp] += 1;
2262 interesting[nsp] += 1;
2263 }
2263 }
2264 }
2264 }
2265 interesting[sv] -= 1;
2265 interesting[sv] -= 1;
2266 if (interesting[sv] == 0)
2266 if (interesting[sv] == 0)
2267 ninteresting -= 1;
2267 ninteresting -= 1;
2268 }
2268 }
2269
2269
2270 final = 0;
2270 final = 0;
2271 j = ninteresting;
2271 j = ninteresting;
2272 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
2272 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
2273 if (interesting[i] == 0)
2273 if (interesting[i] == 0)
2274 continue;
2274 continue;
2275 final |= i;
2275 final |= i;
2276 j -= 1;
2276 j -= 1;
2277 }
2277 }
2278 if (final == 0) {
2278 if (final == 0) {
2279 keys = PyList_New(0);
2279 keys = PyList_New(0);
2280 goto bail;
2280 goto bail;
2281 }
2281 }
2282
2282
2283 dict = PyDict_New();
2283 dict = PyDict_New();
2284 if (dict == NULL)
2284 if (dict == NULL)
2285 goto bail;
2285 goto bail;
2286
2286
2287 for (i = 0; i < revcount; i++) {
2287 for (i = 0; i < revcount; i++) {
2288 PyObject *key;
2288 PyObject *key;
2289
2289
2290 if ((final & (1 << i)) == 0)
2290 if ((final & (1 << i)) == 0)
2291 continue;
2291 continue;
2292
2292
2293 key = PyList_GET_ITEM(revs, i);
2293 key = PyList_GET_ITEM(revs, i);
2294 Py_INCREF(key);
2294 Py_INCREF(key);
2295 Py_INCREF(Py_None);
2295 Py_INCREF(Py_None);
2296 if (PyDict_SetItem(dict, key, Py_None) == -1) {
2296 if (PyDict_SetItem(dict, key, Py_None) == -1) {
2297 Py_DECREF(key);
2297 Py_DECREF(key);
2298 Py_DECREF(Py_None);
2298 Py_DECREF(Py_None);
2299 goto bail;
2299 goto bail;
2300 }
2300 }
2301 }
2301 }
2302
2302
2303 keys = PyDict_Keys(dict);
2303 keys = PyDict_Keys(dict);
2304
2304
2305 bail:
2305 bail:
2306 free(depth);
2306 free(depth);
2307 free(seen);
2307 free(seen);
2308 free(interesting);
2308 free(interesting);
2309 Py_XDECREF(dict);
2309 Py_XDECREF(dict);
2310
2310
2311 return keys;
2311 return keys;
2312 }
2312 }
2313
2313
2314 /*
2314 /*
2315 * Given a (possibly overlapping) set of revs, return all the
2315 * Given a (possibly overlapping) set of revs, return all the
2316 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
2316 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
2317 */
2317 */
2318 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
2318 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
2319 {
2319 {
2320 PyObject *ret = NULL;
2320 PyObject *ret = NULL;
2321 Py_ssize_t argcount, i, len;
2321 Py_ssize_t argcount, i, len;
2322 bitmask repeat = 0;
2322 bitmask repeat = 0;
2323 int revcount = 0;
2323 int revcount = 0;
2324 int *revs;
2324 int *revs;
2325
2325
2326 argcount = PySequence_Length(args);
2326 argcount = PySequence_Length(args);
2327 revs = PyMem_Malloc(argcount * sizeof(*revs));
2327 revs = PyMem_Malloc(argcount * sizeof(*revs));
2328 if (argcount > 0 && revs == NULL)
2328 if (argcount > 0 && revs == NULL)
2329 return PyErr_NoMemory();
2329 return PyErr_NoMemory();
2330 len = index_length(self);
2330 len = index_length(self);
2331
2331
2332 for (i = 0; i < argcount; i++) {
2332 for (i = 0; i < argcount; i++) {
2333 static const int capacity = 24;
2333 static const int capacity = 24;
2334 PyObject *obj = PySequence_GetItem(args, i);
2334 PyObject *obj = PySequence_GetItem(args, i);
2335 bitmask x;
2335 bitmask x;
2336 long val;
2336 long val;
2337
2337
2338 if (!PyInt_Check(obj)) {
2338 if (!PyInt_Check(obj)) {
2339 PyErr_SetString(PyExc_TypeError,
2339 PyErr_SetString(PyExc_TypeError,
2340 "arguments must all be ints");
2340 "arguments must all be ints");
2341 Py_DECREF(obj);
2341 Py_DECREF(obj);
2342 goto bail;
2342 goto bail;
2343 }
2343 }
2344 val = PyInt_AsLong(obj);
2344 val = PyInt_AsLong(obj);
2345 Py_DECREF(obj);
2345 Py_DECREF(obj);
2346 if (val == -1) {
2346 if (val == -1) {
2347 ret = PyList_New(0);
2347 ret = PyList_New(0);
2348 goto done;
2348 goto done;
2349 }
2349 }
2350 if (val < 0 || val >= len) {
2350 if (val < 0 || val >= len) {
2351 PyErr_SetString(PyExc_IndexError, "index out of range");
2351 PyErr_SetString(PyExc_IndexError, "index out of range");
2352 goto bail;
2352 goto bail;
2353 }
2353 }
2354 /* this cheesy bloom filter lets us avoid some more
2354 /* this cheesy bloom filter lets us avoid some more
2355 * expensive duplicate checks in the common set-is-disjoint
2355 * expensive duplicate checks in the common set-is-disjoint
2356 * case */
2356 * case */
2357 x = 1ull << (val & 0x3f);
2357 x = 1ull << (val & 0x3f);
2358 if (repeat & x) {
2358 if (repeat & x) {
2359 int k;
2359 int k;
2360 for (k = 0; k < revcount; k++) {
2360 for (k = 0; k < revcount; k++) {
2361 if (val == revs[k])
2361 if (val == revs[k])
2362 goto duplicate;
2362 goto duplicate;
2363 }
2363 }
2364 } else
2364 } else
2365 repeat |= x;
2365 repeat |= x;
2366 if (revcount >= capacity) {
2366 if (revcount >= capacity) {
2367 PyErr_Format(PyExc_OverflowError,
2367 PyErr_Format(PyExc_OverflowError,
2368 "bitset size (%d) > capacity (%d)",
2368 "bitset size (%d) > capacity (%d)",
2369 revcount, capacity);
2369 revcount, capacity);
2370 goto bail;
2370 goto bail;
2371 }
2371 }
2372 revs[revcount++] = (int)val;
2372 revs[revcount++] = (int)val;
2373 duplicate:;
2373 duplicate:;
2374 }
2374 }
2375
2375
2376 if (revcount == 0) {
2376 if (revcount == 0) {
2377 ret = PyList_New(0);
2377 ret = PyList_New(0);
2378 goto done;
2378 goto done;
2379 }
2379 }
2380 if (revcount == 1) {
2380 if (revcount == 1) {
2381 PyObject *obj;
2381 PyObject *obj;
2382 ret = PyList_New(1);
2382 ret = PyList_New(1);
2383 if (ret == NULL)
2383 if (ret == NULL)
2384 goto bail;
2384 goto bail;
2385 obj = PyInt_FromLong(revs[0]);
2385 obj = PyInt_FromLong(revs[0]);
2386 if (obj == NULL)
2386 if (obj == NULL)
2387 goto bail;
2387 goto bail;
2388 PyList_SET_ITEM(ret, 0, obj);
2388 PyList_SET_ITEM(ret, 0, obj);
2389 goto done;
2389 goto done;
2390 }
2390 }
2391
2391
2392 ret = find_gca_candidates(self, revs, revcount);
2392 ret = find_gca_candidates(self, revs, revcount);
2393 if (ret == NULL)
2393 if (ret == NULL)
2394 goto bail;
2394 goto bail;
2395
2395
2396 done:
2396 done:
2397 PyMem_Free(revs);
2397 PyMem_Free(revs);
2398 return ret;
2398 return ret;
2399
2399
2400 bail:
2400 bail:
2401 PyMem_Free(revs);
2401 PyMem_Free(revs);
2402 Py_XDECREF(ret);
2402 Py_XDECREF(ret);
2403 return NULL;
2403 return NULL;
2404 }
2404 }
2405
2405
2406 /*
2406 /*
2407 * Given a (possibly overlapping) set of revs, return the greatest
2407 * Given a (possibly overlapping) set of revs, return the greatest
2408 * common ancestors: those with the longest path to the root.
2408 * common ancestors: those with the longest path to the root.
2409 */
2409 */
2410 static PyObject *index_ancestors(indexObject *self, PyObject *args)
2410 static PyObject *index_ancestors(indexObject *self, PyObject *args)
2411 {
2411 {
2412 PyObject *ret;
2412 PyObject *ret;
2413 PyObject *gca = index_commonancestorsheads(self, args);
2413 PyObject *gca = index_commonancestorsheads(self, args);
2414 if (gca == NULL)
2414 if (gca == NULL)
2415 return NULL;
2415 return NULL;
2416
2416
2417 if (PyList_GET_SIZE(gca) <= 1) {
2417 if (PyList_GET_SIZE(gca) <= 1) {
2418 return gca;
2418 return gca;
2419 }
2419 }
2420
2420
2421 ret = find_deepest(self, gca);
2421 ret = find_deepest(self, gca);
2422 Py_DECREF(gca);
2422 Py_DECREF(gca);
2423 return ret;
2423 return ret;
2424 }
2424 }
2425
2425
2426 /*
2426 /*
2427 * Invalidate any trie entries introduced by added revs.
2427 * Invalidate any trie entries introduced by added revs.
2428 */
2428 */
2429 static void index_invalidate_added(indexObject *self, Py_ssize_t start)
2429 static void index_invalidate_added(indexObject *self, Py_ssize_t start)
2430 {
2430 {
2431 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
2431 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
2432
2432
2433 for (i = start; i < len; i++) {
2433 for (i = start; i < len; i++) {
2434 PyObject *tuple = PyList_GET_ITEM(self->added, i);
2434 PyObject *tuple = PyList_GET_ITEM(self->added, i);
2435 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
2435 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
2436
2436
2437 nt_delete_node(&self->nt, PyBytes_AS_STRING(node));
2437 nt_delete_node(&self->nt, PyBytes_AS_STRING(node));
2438 }
2438 }
2439
2439
2440 if (start == 0)
2440 if (start == 0)
2441 Py_CLEAR(self->added);
2441 Py_CLEAR(self->added);
2442 }
2442 }
2443
2443
2444 /*
2444 /*
2445 * Delete a numeric range of revs, which must be at the end of the
2445 * Delete a numeric range of revs, which must be at the end of the
2446 * range, but exclude the sentinel nullid entry.
2446 * range, but exclude the sentinel nullid entry.
2447 */
2447 */
2448 static int index_slice_del(indexObject *self, PyObject *item)
2448 static int index_slice_del(indexObject *self, PyObject *item)
2449 {
2449 {
2450 Py_ssize_t start, stop, step, slicelength;
2450 Py_ssize_t start, stop, step, slicelength;
2451 Py_ssize_t length = index_length(self) + 1;
2451 Py_ssize_t length = index_length(self) + 1;
2452 int ret = 0;
2452 int ret = 0;
2453
2453
2454 /* Argument changed from PySliceObject* to PyObject* in Python 3. */
2454 /* Argument changed from PySliceObject* to PyObject* in Python 3. */
2455 #ifdef IS_PY3K
2455 #ifdef IS_PY3K
2456 if (PySlice_GetIndicesEx(item, length, &start, &stop, &step,
2456 if (PySlice_GetIndicesEx(item, length, &start, &stop, &step,
2457 &slicelength) < 0)
2457 &slicelength) < 0)
2458 #else
2458 #else
2459 if (PySlice_GetIndicesEx((PySliceObject *)item, length, &start, &stop,
2459 if (PySlice_GetIndicesEx((PySliceObject *)item, length, &start, &stop,
2460 &step, &slicelength) < 0)
2460 &step, &slicelength) < 0)
2461 #endif
2461 #endif
2462 return -1;
2462 return -1;
2463
2463
2464 if (slicelength <= 0)
2464 if (slicelength <= 0)
2465 return 0;
2465 return 0;
2466
2466
2467 if ((step < 0 && start < stop) || (step > 0 && start > stop))
2467 if ((step < 0 && start < stop) || (step > 0 && start > stop))
2468 stop = start;
2468 stop = start;
2469
2469
2470 if (step < 0) {
2470 if (step < 0) {
2471 stop = start + 1;
2471 stop = start + 1;
2472 start = stop + step * (slicelength - 1) - 1;
2472 start = stop + step * (slicelength - 1) - 1;
2473 step = -step;
2473 step = -step;
2474 }
2474 }
2475
2475
2476 if (step != 1) {
2476 if (step != 1) {
2477 PyErr_SetString(PyExc_ValueError,
2477 PyErr_SetString(PyExc_ValueError,
2478 "revlog index delete requires step size of 1");
2478 "revlog index delete requires step size of 1");
2479 return -1;
2479 return -1;
2480 }
2480 }
2481
2481
2482 if (stop != length - 1) {
2482 if (stop != length - 1) {
2483 PyErr_SetString(PyExc_IndexError,
2483 PyErr_SetString(PyExc_IndexError,
2484 "revlog index deletion indices are invalid");
2484 "revlog index deletion indices are invalid");
2485 return -1;
2485 return -1;
2486 }
2486 }
2487
2487
2488 if (start < self->length) {
2488 if (start < self->length) {
2489 if (self->ntinitialized) {
2489 if (self->ntinitialized) {
2490 Py_ssize_t i;
2490 Py_ssize_t i;
2491
2491
2492 for (i = start + 1; i < self->length; i++) {
2492 for (i = start + 1; i < self->length; i++) {
2493 const char *node = index_node_existing(self, i);
2493 const char *node = index_node_existing(self, i);
2494 if (node == NULL)
2494 if (node == NULL)
2495 return -1;
2495 return -1;
2496
2496
2497 nt_delete_node(&self->nt, node);
2497 nt_delete_node(&self->nt, node);
2498 }
2498 }
2499 if (self->added)
2499 if (self->added)
2500 index_invalidate_added(self, 0);
2500 index_invalidate_added(self, 0);
2501 if (self->ntrev > start)
2501 if (self->ntrev > start)
2502 self->ntrev = (int)start;
2502 self->ntrev = (int)start;
2503 }
2503 }
2504 self->length = start;
2504 self->length = start;
2505 if (start < self->raw_length) {
2505 if (start < self->raw_length) {
2506 if (self->cache) {
2506 if (self->cache) {
2507 Py_ssize_t i;
2507 Py_ssize_t i;
2508 for (i = start; i < self->raw_length; i++)
2508 for (i = start; i < self->raw_length; i++)
2509 Py_CLEAR(self->cache[i]);
2509 Py_CLEAR(self->cache[i]);
2510 }
2510 }
2511 self->raw_length = start;
2511 self->raw_length = start;
2512 }
2512 }
2513 goto done;
2513 goto done;
2514 }
2514 }
2515
2515
2516 if (self->ntinitialized) {
2516 if (self->ntinitialized) {
2517 index_invalidate_added(self, start - self->length);
2517 index_invalidate_added(self, start - self->length);
2518 if (self->ntrev > start)
2518 if (self->ntrev > start)
2519 self->ntrev = (int)start;
2519 self->ntrev = (int)start;
2520 }
2520 }
2521 if (self->added)
2521 if (self->added)
2522 ret = PyList_SetSlice(self->added, start - self->length,
2522 ret = PyList_SetSlice(self->added, start - self->length,
2523 PyList_GET_SIZE(self->added), NULL);
2523 PyList_GET_SIZE(self->added), NULL);
2524 done:
2524 done:
2525 Py_CLEAR(self->headrevs);
2525 Py_CLEAR(self->headrevs);
2526 return ret;
2526 return ret;
2527 }
2527 }
2528
2528
2529 /*
2529 /*
2530 * Supported ops:
2530 * Supported ops:
2531 *
2531 *
2532 * slice deletion
2532 * slice deletion
2533 * string assignment (extend node->rev mapping)
2533 * string assignment (extend node->rev mapping)
2534 * string deletion (shrink node->rev mapping)
2534 * string deletion (shrink node->rev mapping)
2535 */
2535 */
2536 static int index_assign_subscript(indexObject *self, PyObject *item,
2536 static int index_assign_subscript(indexObject *self, PyObject *item,
2537 PyObject *value)
2537 PyObject *value)
2538 {
2538 {
2539 char *node;
2539 char *node;
2540 long rev;
2540 long rev;
2541
2541
2542 if (PySlice_Check(item) && value == NULL)
2542 if (PySlice_Check(item) && value == NULL)
2543 return index_slice_del(self, item);
2543 return index_slice_del(self, item);
2544
2544
2545 if (node_check(item, &node) == -1)
2545 if (node_check(item, &node) == -1)
2546 return -1;
2546 return -1;
2547
2547
2548 if (value == NULL)
2548 if (value == NULL)
2549 return self->ntinitialized ? nt_delete_node(&self->nt, node)
2549 return self->ntinitialized ? nt_delete_node(&self->nt, node)
2550 : 0;
2550 : 0;
2551 rev = PyInt_AsLong(value);
2551 rev = PyInt_AsLong(value);
2552 if (rev > INT_MAX || rev < 0) {
2552 if (rev > INT_MAX || rev < 0) {
2553 if (!PyErr_Occurred())
2553 if (!PyErr_Occurred())
2554 PyErr_SetString(PyExc_ValueError, "rev out of range");
2554 PyErr_SetString(PyExc_ValueError, "rev out of range");
2555 return -1;
2555 return -1;
2556 }
2556 }
2557
2557
2558 if (index_init_nt(self) == -1)
2558 if (index_init_nt(self) == -1)
2559 return -1;
2559 return -1;
2560 return nt_insert(&self->nt, node, (int)rev);
2560 return nt_insert(&self->nt, node, (int)rev);
2561 }
2561 }
2562
2562
2563 /*
2563 /*
2564 * Find all RevlogNG entries in an index that has inline data. Update
2564 * Find all RevlogNG entries in an index that has inline data. Update
2565 * the optional "offsets" table with those entries.
2565 * the optional "offsets" table with those entries.
2566 */
2566 */
2567 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2567 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2568 {
2568 {
2569 const char *data = (const char *)self->buf.buf;
2569 const char *data = (const char *)self->buf.buf;
2570 Py_ssize_t pos = 0;
2570 Py_ssize_t pos = 0;
2571 Py_ssize_t end = self->buf.len;
2571 Py_ssize_t end = self->buf.len;
2572 long incr = v1_hdrsize;
2572 long incr = v1_hdrsize;
2573 Py_ssize_t len = 0;
2573 Py_ssize_t len = 0;
2574
2574
2575 while (pos + v1_hdrsize <= end && pos >= 0) {
2575 while (pos + v1_hdrsize <= end && pos >= 0) {
2576 uint32_t comp_len;
2576 uint32_t comp_len;
2577 /* 3rd element of header is length of compressed inline data */
2577 /* 3rd element of header is length of compressed inline data */
2578 comp_len = getbe32(data + pos + 8);
2578 comp_len = getbe32(data + pos + 8);
2579 incr = v1_hdrsize + comp_len;
2579 incr = v1_hdrsize + comp_len;
2580 if (offsets)
2580 if (offsets)
2581 offsets[len] = data + pos;
2581 offsets[len] = data + pos;
2582 len++;
2582 len++;
2583 pos += incr;
2583 pos += incr;
2584 }
2584 }
2585
2585
2586 if (pos != end) {
2586 if (pos != end) {
2587 if (!PyErr_Occurred())
2587 if (!PyErr_Occurred())
2588 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2588 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2589 return -1;
2589 return -1;
2590 }
2590 }
2591
2591
2592 return len;
2592 return len;
2593 }
2593 }
2594
2594
2595 static int index_init(indexObject *self, PyObject *args)
2595 static int index_init(indexObject *self, PyObject *args)
2596 {
2596 {
2597 PyObject *data_obj, *inlined_obj;
2597 PyObject *data_obj, *inlined_obj;
2598 Py_ssize_t size;
2598 Py_ssize_t size;
2599
2599
2600 /* Initialize before argument-checking to avoid index_dealloc() crash.
2600 /* Initialize before argument-checking to avoid index_dealloc() crash.
2601 */
2601 */
2602 self->raw_length = 0;
2602 self->raw_length = 0;
2603 self->added = NULL;
2603 self->added = NULL;
2604 self->cache = NULL;
2604 self->cache = NULL;
2605 self->data = NULL;
2605 self->data = NULL;
2606 memset(&self->buf, 0, sizeof(self->buf));
2606 memset(&self->buf, 0, sizeof(self->buf));
2607 self->headrevs = NULL;
2607 self->headrevs = NULL;
2608 self->filteredrevs = Py_None;
2608 self->filteredrevs = Py_None;
2609 Py_INCREF(Py_None);
2609 Py_INCREF(Py_None);
2610 self->ntinitialized = 0;
2610 self->ntinitialized = 0;
2611 self->offsets = NULL;
2611 self->offsets = NULL;
2612
2612
2613 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2613 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2614 return -1;
2614 return -1;
2615 if (!PyObject_CheckBuffer(data_obj)) {
2615 if (!PyObject_CheckBuffer(data_obj)) {
2616 PyErr_SetString(PyExc_TypeError,
2616 PyErr_SetString(PyExc_TypeError,
2617 "data does not support buffer interface");
2617 "data does not support buffer interface");
2618 return -1;
2618 return -1;
2619 }
2619 }
2620
2620
2621 if (PyObject_GetBuffer(data_obj, &self->buf, PyBUF_SIMPLE) == -1)
2621 if (PyObject_GetBuffer(data_obj, &self->buf, PyBUF_SIMPLE) == -1)
2622 return -1;
2622 return -1;
2623 size = self->buf.len;
2623 size = self->buf.len;
2624
2624
2625 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2625 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2626 self->data = data_obj;
2626 self->data = data_obj;
2627
2627
2628 self->ntlookups = self->ntmisses = 0;
2628 self->ntlookups = self->ntmisses = 0;
2629 self->ntrev = -1;
2629 self->ntrev = -1;
2630 Py_INCREF(self->data);
2630 Py_INCREF(self->data);
2631
2631
2632 if (self->inlined) {
2632 if (self->inlined) {
2633 Py_ssize_t len = inline_scan(self, NULL);
2633 Py_ssize_t len = inline_scan(self, NULL);
2634 if (len == -1)
2634 if (len == -1)
2635 goto bail;
2635 goto bail;
2636 self->raw_length = len;
2636 self->raw_length = len;
2637 self->length = len;
2637 self->length = len;
2638 } else {
2638 } else {
2639 if (size % v1_hdrsize) {
2639 if (size % v1_hdrsize) {
2640 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2640 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2641 goto bail;
2641 goto bail;
2642 }
2642 }
2643 self->raw_length = size / v1_hdrsize;
2643 self->raw_length = size / v1_hdrsize;
2644 self->length = self->raw_length;
2644 self->length = self->raw_length;
2645 }
2645 }
2646
2646
2647 return 0;
2647 return 0;
2648 bail:
2648 bail:
2649 return -1;
2649 return -1;
2650 }
2650 }
2651
2651
2652 static PyObject *index_nodemap(indexObject *self)
2652 static PyObject *index_nodemap(indexObject *self)
2653 {
2653 {
2654 Py_INCREF(self);
2654 Py_INCREF(self);
2655 return (PyObject *)self;
2655 return (PyObject *)self;
2656 }
2656 }
2657
2657
2658 static void _index_clearcaches(indexObject *self)
2658 static void _index_clearcaches(indexObject *self)
2659 {
2659 {
2660 if (self->cache) {
2660 if (self->cache) {
2661 Py_ssize_t i;
2661 Py_ssize_t i;
2662
2662
2663 for (i = 0; i < self->raw_length; i++)
2663 for (i = 0; i < self->raw_length; i++)
2664 Py_CLEAR(self->cache[i]);
2664 Py_CLEAR(self->cache[i]);
2665 free(self->cache);
2665 free(self->cache);
2666 self->cache = NULL;
2666 self->cache = NULL;
2667 }
2667 }
2668 if (self->offsets) {
2668 if (self->offsets) {
2669 PyMem_Free((void *)self->offsets);
2669 PyMem_Free((void *)self->offsets);
2670 self->offsets = NULL;
2670 self->offsets = NULL;
2671 }
2671 }
2672 if (self->ntinitialized) {
2672 if (self->ntinitialized) {
2673 nt_dealloc(&self->nt);
2673 nt_dealloc(&self->nt);
2674 }
2674 }
2675 self->ntinitialized = 0;
2675 self->ntinitialized = 0;
2676 Py_CLEAR(self->headrevs);
2676 Py_CLEAR(self->headrevs);
2677 }
2677 }
2678
2678
2679 static PyObject *index_clearcaches(indexObject *self)
2679 static PyObject *index_clearcaches(indexObject *self)
2680 {
2680 {
2681 _index_clearcaches(self);
2681 _index_clearcaches(self);
2682 self->ntrev = -1;
2682 self->ntrev = -1;
2683 self->ntlookups = self->ntmisses = 0;
2683 self->ntlookups = self->ntmisses = 0;
2684 Py_RETURN_NONE;
2684 Py_RETURN_NONE;
2685 }
2685 }
2686
2686
2687 static void index_dealloc(indexObject *self)
2687 static void index_dealloc(indexObject *self)
2688 {
2688 {
2689 _index_clearcaches(self);
2689 _index_clearcaches(self);
2690 Py_XDECREF(self->filteredrevs);
2690 Py_XDECREF(self->filteredrevs);
2691 if (self->buf.buf) {
2691 if (self->buf.buf) {
2692 PyBuffer_Release(&self->buf);
2692 PyBuffer_Release(&self->buf);
2693 memset(&self->buf, 0, sizeof(self->buf));
2693 memset(&self->buf, 0, sizeof(self->buf));
2694 }
2694 }
2695 Py_XDECREF(self->data);
2695 Py_XDECREF(self->data);
2696 Py_XDECREF(self->added);
2696 Py_XDECREF(self->added);
2697 PyObject_Del(self);
2697 PyObject_Del(self);
2698 }
2698 }
2699
2699
2700 static PySequenceMethods index_sequence_methods = {
2700 static PySequenceMethods index_sequence_methods = {
2701 (lenfunc)index_length, /* sq_length */
2701 (lenfunc)index_length, /* sq_length */
2702 0, /* sq_concat */
2702 0, /* sq_concat */
2703 0, /* sq_repeat */
2703 0, /* sq_repeat */
2704 (ssizeargfunc)index_get, /* sq_item */
2704 (ssizeargfunc)index_get, /* sq_item */
2705 0, /* sq_slice */
2705 0, /* sq_slice */
2706 0, /* sq_ass_item */
2706 0, /* sq_ass_item */
2707 0, /* sq_ass_slice */
2707 0, /* sq_ass_slice */
2708 (objobjproc)index_contains, /* sq_contains */
2708 (objobjproc)index_contains, /* sq_contains */
2709 };
2709 };
2710
2710
2711 static PyMappingMethods index_mapping_methods = {
2711 static PyMappingMethods index_mapping_methods = {
2712 (lenfunc)index_length, /* mp_length */
2712 (lenfunc)index_length, /* mp_length */
2713 (binaryfunc)index_getitem, /* mp_subscript */
2713 (binaryfunc)index_getitem, /* mp_subscript */
2714 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2714 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2715 };
2715 };
2716
2716
2717 static PyMethodDef index_methods[] = {
2717 static PyMethodDef index_methods[] = {
2718 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2718 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2719 "return the gca set of the given revs"},
2719 "return the gca set of the given revs"},
2720 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2720 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2721 METH_VARARGS,
2721 METH_VARARGS,
2722 "return the heads of the common ancestors of the given revs"},
2722 "return the heads of the common ancestors of the given revs"},
2723 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2723 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2724 "clear the index caches"},
2724 "clear the index caches"},
2725 {"get", (PyCFunction)index_m_get, METH_VARARGS, "get an index entry"},
2725 {"get", (PyCFunction)index_m_get, METH_VARARGS, "get an index entry"},
2726 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets, METH_VARARGS,
2726 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets, METH_VARARGS,
2727 "compute phases"},
2727 "compute phases"},
2728 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
2728 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
2729 "reachableroots"},
2729 "reachableroots"},
2730 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2730 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2731 "get head revisions"}, /* Can do filtering since 3.2 */
2731 "get head revisions"}, /* Can do filtering since 3.2 */
2732 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2732 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2733 "get filtered head revisions"}, /* Can always do filtering */
2733 "get filtered head revisions"}, /* Can always do filtering */
2734 {"issnapshot", (PyCFunction)index_issnapshot, METH_O,
2734 {"issnapshot", (PyCFunction)index_issnapshot, METH_O,
2735 "True if the object is a snapshot"},
2735 "True if the object is a snapshot"},
2736 {"findsnapshots", (PyCFunction)index_findsnapshots, METH_VARARGS,
2736 {"findsnapshots", (PyCFunction)index_findsnapshots, METH_VARARGS,
2737 "Gather snapshot data in a cache dict"},
2737 "Gather snapshot data in a cache dict"},
2738 {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
2738 {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
2739 "determine revisions with deltas to reconstruct fulltext"},
2739 "determine revisions with deltas to reconstruct fulltext"},
2740 {"slicechunktodensity", (PyCFunction)index_slicechunktodensity,
2740 {"slicechunktodensity", (PyCFunction)index_slicechunktodensity,
2741 METH_VARARGS, "determine revisions with deltas to reconstruct fulltext"},
2741 METH_VARARGS, "determine revisions with deltas to reconstruct fulltext"},
2742 {"append", (PyCFunction)index_append, METH_O, "append an index entry"},
2742 {"append", (PyCFunction)index_append, METH_O, "append an index entry"},
2743 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2743 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2744 "match a potentially ambiguous node ID"},
2744 "match a potentially ambiguous node ID"},
2745 {"shortest", (PyCFunction)index_shortest, METH_VARARGS,
2745 {"shortest", (PyCFunction)index_shortest, METH_VARARGS,
2746 "find length of shortest hex nodeid of a binary ID"},
2746 "find length of shortest hex nodeid of a binary ID"},
2747 {"stats", (PyCFunction)index_stats, METH_NOARGS, "stats for the index"},
2747 {"stats", (PyCFunction)index_stats, METH_NOARGS, "stats for the index"},
2748 {NULL} /* Sentinel */
2748 {NULL} /* Sentinel */
2749 };
2749 };
2750
2750
2751 static PyGetSetDef index_getset[] = {
2751 static PyGetSetDef index_getset[] = {
2752 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2752 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2753 {NULL} /* Sentinel */
2753 {NULL} /* Sentinel */
2754 };
2754 };
2755
2755
2756 PyTypeObject HgRevlogIndex_Type = {
2756 PyTypeObject HgRevlogIndex_Type = {
2757 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2757 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2758 "parsers.index", /* tp_name */
2758 "parsers.index", /* tp_name */
2759 sizeof(indexObject), /* tp_basicsize */
2759 sizeof(indexObject), /* tp_basicsize */
2760 0, /* tp_itemsize */
2760 0, /* tp_itemsize */
2761 (destructor)index_dealloc, /* tp_dealloc */
2761 (destructor)index_dealloc, /* tp_dealloc */
2762 0, /* tp_print */
2762 0, /* tp_print */
2763 0, /* tp_getattr */
2763 0, /* tp_getattr */
2764 0, /* tp_setattr */
2764 0, /* tp_setattr */
2765 0, /* tp_compare */
2765 0, /* tp_compare */
2766 0, /* tp_repr */
2766 0, /* tp_repr */
2767 0, /* tp_as_number */
2767 0, /* tp_as_number */
2768 &index_sequence_methods, /* tp_as_sequence */
2768 &index_sequence_methods, /* tp_as_sequence */
2769 &index_mapping_methods, /* tp_as_mapping */
2769 &index_mapping_methods, /* tp_as_mapping */
2770 0, /* tp_hash */
2770 0, /* tp_hash */
2771 0, /* tp_call */
2771 0, /* tp_call */
2772 0, /* tp_str */
2772 0, /* tp_str */
2773 0, /* tp_getattro */
2773 0, /* tp_getattro */
2774 0, /* tp_setattro */
2774 0, /* tp_setattro */
2775 0, /* tp_as_buffer */
2775 0, /* tp_as_buffer */
2776 Py_TPFLAGS_DEFAULT, /* tp_flags */
2776 Py_TPFLAGS_DEFAULT, /* tp_flags */
2777 "revlog index", /* tp_doc */
2777 "revlog index", /* tp_doc */
2778 0, /* tp_traverse */
2778 0, /* tp_traverse */
2779 0, /* tp_clear */
2779 0, /* tp_clear */
2780 0, /* tp_richcompare */
2780 0, /* tp_richcompare */
2781 0, /* tp_weaklistoffset */
2781 0, /* tp_weaklistoffset */
2782 0, /* tp_iter */
2782 0, /* tp_iter */
2783 0, /* tp_iternext */
2783 0, /* tp_iternext */
2784 index_methods, /* tp_methods */
2784 index_methods, /* tp_methods */
2785 0, /* tp_members */
2785 0, /* tp_members */
2786 index_getset, /* tp_getset */
2786 index_getset, /* tp_getset */
2787 0, /* tp_base */
2787 0, /* tp_base */
2788 0, /* tp_dict */
2788 0, /* tp_dict */
2789 0, /* tp_descr_get */
2789 0, /* tp_descr_get */
2790 0, /* tp_descr_set */
2790 0, /* tp_descr_set */
2791 0, /* tp_dictoffset */
2791 0, /* tp_dictoffset */
2792 (initproc)index_init, /* tp_init */
2792 (initproc)index_init, /* tp_init */
2793 0, /* tp_alloc */
2793 0, /* tp_alloc */
2794 };
2794 };
2795
2795
2796 /*
2796 /*
2797 * returns a tuple of the form (index, index, cache) with elements as
2797 * returns a tuple of the form (index, index, cache) with elements as
2798 * follows:
2798 * follows:
2799 *
2799 *
2800 * index: an index object that lazily parses RevlogNG records
2800 * index: an index object that lazily parses RevlogNG records
2801 * cache: if data is inlined, a tuple (0, index_file_content), else None
2801 * cache: if data is inlined, a tuple (0, index_file_content), else None
2802 * index_file_content could be a string, or a buffer
2802 * index_file_content could be a string, or a buffer
2803 *
2803 *
2804 * added complications are for backwards compatibility
2804 * added complications are for backwards compatibility
2805 */
2805 */
2806 PyObject *parse_index2(PyObject *self, PyObject *args)
2806 PyObject *parse_index2(PyObject *self, PyObject *args)
2807 {
2807 {
2808 PyObject *tuple = NULL, *cache = NULL;
2808 PyObject *tuple = NULL, *cache = NULL;
2809 indexObject *idx;
2809 indexObject *idx;
2810 int ret;
2810 int ret;
2811
2811
2812 idx = PyObject_New(indexObject, &HgRevlogIndex_Type);
2812 idx = PyObject_New(indexObject, &HgRevlogIndex_Type);
2813 if (idx == NULL)
2813 if (idx == NULL)
2814 goto bail;
2814 goto bail;
2815
2815
2816 ret = index_init(idx, args);
2816 ret = index_init(idx, args);
2817 if (ret == -1)
2817 if (ret == -1)
2818 goto bail;
2818 goto bail;
2819
2819
2820 if (idx->inlined) {
2820 if (idx->inlined) {
2821 cache = Py_BuildValue("iO", 0, idx->data);
2821 cache = Py_BuildValue("iO", 0, idx->data);
2822 if (cache == NULL)
2822 if (cache == NULL)
2823 goto bail;
2823 goto bail;
2824 } else {
2824 } else {
2825 cache = Py_None;
2825 cache = Py_None;
2826 Py_INCREF(cache);
2826 Py_INCREF(cache);
2827 }
2827 }
2828
2828
2829 tuple = Py_BuildValue("NN", idx, cache);
2829 tuple = Py_BuildValue("NN", idx, cache);
2830 if (!tuple)
2830 if (!tuple)
2831 goto bail;
2831 goto bail;
2832 return tuple;
2832 return tuple;
2833
2833
2834 bail:
2834 bail:
2835 Py_XDECREF(idx);
2835 Py_XDECREF(idx);
2836 Py_XDECREF(cache);
2836 Py_XDECREF(cache);
2837 Py_XDECREF(tuple);
2837 Py_XDECREF(tuple);
2838 return NULL;
2838 return NULL;
2839 }
2839 }
2840
2840
2841 #ifdef WITH_RUST
2841 #ifdef WITH_RUST
2842
2842
2843 /* rustlazyancestors: iteration over ancestors implemented in Rust
2843 /* rustlazyancestors: iteration over ancestors implemented in Rust
2844 *
2844 *
2845 * This class holds a reference to an index and to the Rust iterator.
2845 * This class holds a reference to an index and to the Rust iterator.
2846 */
2846 */
2847 typedef struct rustlazyancestorsObjectStruct rustlazyancestorsObject;
2847 typedef struct rustlazyancestorsObjectStruct rustlazyancestorsObject;
2848
2848
2849 struct rustlazyancestorsObjectStruct {
2849 struct rustlazyancestorsObjectStruct {
2850 PyObject_HEAD
2850 PyObject_HEAD
2851 /* Type-specific fields go here. */
2851 /* Type-specific fields go here. */
2852 indexObject *index; /* Ref kept to avoid GC'ing the index */
2852 indexObject *index; /* Ref kept to avoid GC'ing the index */
2853 void *iter; /* Rust iterator */
2853 void *iter; /* Rust iterator */
2854 };
2854 };
2855
2855
2856 /* FFI exposed from Rust code */
2856 /* FFI exposed from Rust code */
2857 rustlazyancestorsObject *rustlazyancestors_init(indexObject *index,
2857 rustlazyancestorsObject *rustlazyancestors_init(indexObject *index,
2858 /* intrevs vector */
2858 /* intrevs vector */
2859 Py_ssize_t initrevslen,
2859 Py_ssize_t initrevslen,
2860 long *initrevs, long stoprev,
2860 long *initrevs, long stoprev,
2861 int inclusive);
2861 int inclusive);
2862 void rustlazyancestors_drop(rustlazyancestorsObject *self);
2862 void rustlazyancestors_drop(rustlazyancestorsObject *self);
2863 int rustlazyancestors_next(rustlazyancestorsObject *self);
2863 int rustlazyancestors_next(rustlazyancestorsObject *self);
2864 int rustlazyancestors_contains(rustlazyancestorsObject *self, long rev);
2864 int rustlazyancestors_contains(rustlazyancestorsObject *self, long rev);
2865
2865
2866 /* CPython instance methods */
2866 /* CPython instance methods */
2867 static int rustla_init(rustlazyancestorsObject *self, PyObject *args)
2867 static int rustla_init(rustlazyancestorsObject *self, PyObject *args)
2868 {
2868 {
2869 PyObject *initrevsarg = NULL;
2869 PyObject *initrevsarg = NULL;
2870 PyObject *inclusivearg = NULL;
2870 PyObject *inclusivearg = NULL;
2871 long stoprev = 0;
2871 long stoprev = 0;
2872 long *initrevs = NULL;
2872 long *initrevs = NULL;
2873 int inclusive = 0;
2873 int inclusive = 0;
2874 Py_ssize_t i;
2874 Py_ssize_t i;
2875
2875
2876 indexObject *index;
2876 indexObject *index;
2877 if (!PyArg_ParseTuple(args, "O!O!lO!", &HgRevlogIndex_Type, &index,
2877 if (!PyArg_ParseTuple(args, "O!O!lO!", &HgRevlogIndex_Type, &index,
2878 &PyList_Type, &initrevsarg, &stoprev,
2878 &PyList_Type, &initrevsarg, &stoprev,
2879 &PyBool_Type, &inclusivearg))
2879 &PyBool_Type, &inclusivearg))
2880 return -1;
2880 return -1;
2881
2881
2882 Py_INCREF(index);
2882 Py_INCREF(index);
2883 self->index = index;
2883 self->index = index;
2884
2884
2885 if (inclusivearg == Py_True)
2885 if (inclusivearg == Py_True)
2886 inclusive = 1;
2886 inclusive = 1;
2887
2887
2888 Py_ssize_t linit = PyList_GET_SIZE(initrevsarg);
2888 Py_ssize_t linit = PyList_GET_SIZE(initrevsarg);
2889
2889
2890 initrevs = (long *)calloc(linit, sizeof(long));
2890 initrevs = (long *)calloc(linit, sizeof(long));
2891
2891
2892 if (initrevs == NULL) {
2892 if (initrevs == NULL) {
2893 PyErr_NoMemory();
2893 PyErr_NoMemory();
2894 goto bail;
2894 goto bail;
2895 }
2895 }
2896
2896
2897 for (i = 0; i < linit; i++) {
2897 for (i = 0; i < linit; i++) {
2898 initrevs[i] = PyInt_AsLong(PyList_GET_ITEM(initrevsarg, i));
2898 initrevs[i] = PyInt_AsLong(PyList_GET_ITEM(initrevsarg, i));
2899 }
2899 }
2900 if (PyErr_Occurred())
2900 if (PyErr_Occurred())
2901 goto bail;
2901 goto bail;
2902
2902
2903 self->iter =
2903 self->iter =
2904 rustlazyancestors_init(index, linit, initrevs, stoprev, inclusive);
2904 rustlazyancestors_init(index, linit, initrevs, stoprev, inclusive);
2905 if (self->iter == NULL) {
2905 if (self->iter == NULL) {
2906 /* if this is because of GraphError::ParentOutOfRange
2906 /* if this is because of GraphError::ParentOutOfRange
2907 * HgRevlogIndex_GetParents() has already set the proper
2907 * HgRevlogIndex_GetParents() has already set the proper
2908 * exception */
2908 * exception */
2909 goto bail;
2909 goto bail;
2910 }
2910 }
2911
2911
2912 free(initrevs);
2912 free(initrevs);
2913 return 0;
2913 return 0;
2914
2914
2915 bail:
2915 bail:
2916 free(initrevs);
2916 free(initrevs);
2917 return -1;
2917 return -1;
2918 };
2918 };
2919
2919
2920 static void rustla_dealloc(rustlazyancestorsObject *self)
2920 static void rustla_dealloc(rustlazyancestorsObject *self)
2921 {
2921 {
2922 Py_XDECREF(self->index);
2922 Py_XDECREF(self->index);
2923 if (self->iter != NULL) { /* can happen if rustla_init failed */
2923 if (self->iter != NULL) { /* can happen if rustla_init failed */
2924 rustlazyancestors_drop(self->iter);
2924 rustlazyancestors_drop(self->iter);
2925 }
2925 }
2926 PyObject_Del(self);
2926 PyObject_Del(self);
2927 }
2927 }
2928
2928
2929 static PyObject *rustla_next(rustlazyancestorsObject *self)
2929 static PyObject *rustla_next(rustlazyancestorsObject *self)
2930 {
2930 {
2931 int res = rustlazyancestors_next(self->iter);
2931 int res = rustlazyancestors_next(self->iter);
2932 if (res == -1) {
2932 if (res == -1) {
2933 /* Setting an explicit exception seems unnecessary
2933 /* Setting an explicit exception seems unnecessary
2934 * as examples from Python source code (Objects/rangeobjets.c
2934 * as examples from Python source code (Objects/rangeobjets.c
2935 * and Modules/_io/stringio.c) seem to demonstrate.
2935 * and Modules/_io/stringio.c) seem to demonstrate.
2936 */
2936 */
2937 return NULL;
2937 return NULL;
2938 }
2938 }
2939 return PyInt_FromLong(res);
2939 return PyInt_FromLong(res);
2940 }
2940 }
2941
2941
2942 static int rustla_contains(rustlazyancestorsObject *self, PyObject *rev)
2942 static int rustla_contains(rustlazyancestorsObject *self, PyObject *rev)
2943 {
2943 {
2944 long lrev;
2944 long lrev;
2945 if (!pylong_to_long(rev, &lrev)) {
2945 if (!pylong_to_long(rev, &lrev)) {
2946 PyErr_Clear();
2946 PyErr_Clear();
2947 return 0;
2947 return 0;
2948 }
2948 }
2949 return rustlazyancestors_contains(self->iter, lrev);
2949 return rustlazyancestors_contains(self->iter, lrev);
2950 }
2950 }
2951
2951
2952 static PySequenceMethods rustla_sequence_methods = {
2952 static PySequenceMethods rustla_sequence_methods = {
2953 0, /* sq_length */
2953 0, /* sq_length */
2954 0, /* sq_concat */
2954 0, /* sq_concat */
2955 0, /* sq_repeat */
2955 0, /* sq_repeat */
2956 0, /* sq_item */
2956 0, /* sq_item */
2957 0, /* sq_slice */
2957 0, /* sq_slice */
2958 0, /* sq_ass_item */
2958 0, /* sq_ass_item */
2959 0, /* sq_ass_slice */
2959 0, /* sq_ass_slice */
2960 (objobjproc)rustla_contains, /* sq_contains */
2960 (objobjproc)rustla_contains, /* sq_contains */
2961 };
2961 };
2962
2962
2963 static PyTypeObject rustlazyancestorsType = {
2963 static PyTypeObject rustlazyancestorsType = {
2964 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2964 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2965 "parsers.rustlazyancestors", /* tp_name */
2965 "parsers.rustlazyancestors", /* tp_name */
2966 sizeof(rustlazyancestorsObject), /* tp_basicsize */
2966 sizeof(rustlazyancestorsObject), /* tp_basicsize */
2967 0, /* tp_itemsize */
2967 0, /* tp_itemsize */
2968 (destructor)rustla_dealloc, /* tp_dealloc */
2968 (destructor)rustla_dealloc, /* tp_dealloc */
2969 0, /* tp_print */
2969 0, /* tp_print */
2970 0, /* tp_getattr */
2970 0, /* tp_getattr */
2971 0, /* tp_setattr */
2971 0, /* tp_setattr */
2972 0, /* tp_compare */
2972 0, /* tp_compare */
2973 0, /* tp_repr */
2973 0, /* tp_repr */
2974 0, /* tp_as_number */
2974 0, /* tp_as_number */
2975 &rustla_sequence_methods, /* tp_as_sequence */
2975 &rustla_sequence_methods, /* tp_as_sequence */
2976 0, /* tp_as_mapping */
2976 0, /* tp_as_mapping */
2977 0, /* tp_hash */
2977 0, /* tp_hash */
2978 0, /* tp_call */
2978 0, /* tp_call */
2979 0, /* tp_str */
2979 0, /* tp_str */
2980 0, /* tp_getattro */
2980 0, /* tp_getattro */
2981 0, /* tp_setattro */
2981 0, /* tp_setattro */
2982 0, /* tp_as_buffer */
2982 0, /* tp_as_buffer */
2983 Py_TPFLAGS_DEFAULT, /* tp_flags */
2983 Py_TPFLAGS_DEFAULT, /* tp_flags */
2984 "Iterator over ancestors, implemented in Rust", /* tp_doc */
2984 "Iterator over ancestors, implemented in Rust", /* tp_doc */
2985 0, /* tp_traverse */
2985 0, /* tp_traverse */
2986 0, /* tp_clear */
2986 0, /* tp_clear */
2987 0, /* tp_richcompare */
2987 0, /* tp_richcompare */
2988 0, /* tp_weaklistoffset */
2988 0, /* tp_weaklistoffset */
2989 0, /* tp_iter */
2989 0, /* tp_iter */
2990 (iternextfunc)rustla_next, /* tp_iternext */
2990 (iternextfunc)rustla_next, /* tp_iternext */
2991 0, /* tp_methods */
2991 0, /* tp_methods */
2992 0, /* tp_members */
2992 0, /* tp_members */
2993 0, /* tp_getset */
2993 0, /* tp_getset */
2994 0, /* tp_base */
2994 0, /* tp_base */
2995 0, /* tp_dict */
2995 0, /* tp_dict */
2996 0, /* tp_descr_get */
2996 0, /* tp_descr_get */
2997 0, /* tp_descr_set */
2997 0, /* tp_descr_set */
2998 0, /* tp_dictoffset */
2998 0, /* tp_dictoffset */
2999 (initproc)rustla_init, /* tp_init */
2999 (initproc)rustla_init, /* tp_init */
3000 0, /* tp_alloc */
3000 0, /* tp_alloc */
3001 };
3001 };
3002 #endif /* WITH_RUST */
3002 #endif /* WITH_RUST */
3003
3003
3004 void revlog_module_init(PyObject *mod)
3004 void revlog_module_init(PyObject *mod)
3005 {
3005 {
3006 PyObject *caps = NULL;
3006 PyObject *caps = NULL;
3007 HgRevlogIndex_Type.tp_new = PyType_GenericNew;
3007 HgRevlogIndex_Type.tp_new = PyType_GenericNew;
3008 if (PyType_Ready(&HgRevlogIndex_Type) < 0)
3008 if (PyType_Ready(&HgRevlogIndex_Type) < 0)
3009 return;
3009 return;
3010 Py_INCREF(&HgRevlogIndex_Type);
3010 Py_INCREF(&HgRevlogIndex_Type);
3011 PyModule_AddObject(mod, "index", (PyObject *)&HgRevlogIndex_Type);
3011 PyModule_AddObject(mod, "index", (PyObject *)&HgRevlogIndex_Type);
3012
3012
3013 nodetreeType.tp_new = PyType_GenericNew;
3013 nodetreeType.tp_new = PyType_GenericNew;
3014 if (PyType_Ready(&nodetreeType) < 0)
3014 if (PyType_Ready(&nodetreeType) < 0)
3015 return;
3015 return;
3016 Py_INCREF(&nodetreeType);
3016 Py_INCREF(&nodetreeType);
3017 PyModule_AddObject(mod, "nodetree", (PyObject *)&nodetreeType);
3017 PyModule_AddObject(mod, "nodetree", (PyObject *)&nodetreeType);
3018
3018
3019 if (!nullentry) {
3019 if (!nullentry) {
3020 nullentry = Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0,
3020 nullentry =
3021 0, -1, -1, -1, -1, nullid, 20);
3021 Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0, 0, -1,
3022 -1, -1, -1, nullid, (Py_ssize_t)20);
3022 }
3023 }
3023 if (nullentry)
3024 if (nullentry)
3024 PyObject_GC_UnTrack(nullentry);
3025 PyObject_GC_UnTrack(nullentry);
3025
3026
3026 caps = PyCapsule_New(HgRevlogIndex_GetParents,
3027 caps = PyCapsule_New(HgRevlogIndex_GetParents,
3027 "mercurial.cext.parsers.index_get_parents_CAPI",
3028 "mercurial.cext.parsers.index_get_parents_CAPI",
3028 NULL);
3029 NULL);
3029 if (caps != NULL)
3030 if (caps != NULL)
3030 PyModule_AddObject(mod, "index_get_parents_CAPI", caps);
3031 PyModule_AddObject(mod, "index_get_parents_CAPI", caps);
3031
3032
3032 #ifdef WITH_RUST
3033 #ifdef WITH_RUST
3033 rustlazyancestorsType.tp_new = PyType_GenericNew;
3034 rustlazyancestorsType.tp_new = PyType_GenericNew;
3034 if (PyType_Ready(&rustlazyancestorsType) < 0)
3035 if (PyType_Ready(&rustlazyancestorsType) < 0)
3035 return;
3036 return;
3036 Py_INCREF(&rustlazyancestorsType);
3037 Py_INCREF(&rustlazyancestorsType);
3037 PyModule_AddObject(mod, "rustlazyancestors",
3038 PyModule_AddObject(mod, "rustlazyancestors",
3038 (PyObject *)&rustlazyancestorsType);
3039 (PyObject *)&rustlazyancestorsType);
3039 #endif
3040 #endif
3040 }
3041 }
General Comments 0
You need to be logged in to leave comments. Login now