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