##// END OF EJS Templates
parsers._asciilower: use an explicit return object...
Siddharth Agarwal -
r24575:a62e9574 default
parent child Browse files
Show More
@@ -1,2524 +1,2526
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 #include <Python.h>
10 #include <Python.h>
11 #include <ctype.h>
11 #include <ctype.h>
12 #include <stddef.h>
12 #include <stddef.h>
13 #include <string.h>
13 #include <string.h>
14
14
15 #include "util.h"
15 #include "util.h"
16
16
17 static char *versionerrortext = "Python minor version mismatch";
17 static char *versionerrortext = "Python minor version mismatch";
18
18
19 static int8_t hextable[256] = {
19 static int8_t hextable[256] = {
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
36 };
36 };
37
37
38 static char lowertable[128] = {
38 static char lowertable[128] = {
39 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
39 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
40 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
40 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
41 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
41 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
42 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
42 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
43 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
43 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
44 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
44 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
45 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
45 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
46 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
46 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
47 '\x40',
47 '\x40',
48 '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', /* A-G */
48 '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', /* A-G */
49 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', /* H-O */
49 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', /* H-O */
50 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', /* P-W */
50 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', /* P-W */
51 '\x78', '\x79', '\x7a', /* X-Z */
51 '\x78', '\x79', '\x7a', /* X-Z */
52 '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
52 '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
53 '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
53 '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
54 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
54 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
55 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
55 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
56 '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
56 '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
57 };
57 };
58
58
59 static inline int hexdigit(const char *p, Py_ssize_t off)
59 static inline int hexdigit(const char *p, Py_ssize_t off)
60 {
60 {
61 int8_t val = hextable[(unsigned char)p[off]];
61 int8_t val = hextable[(unsigned char)p[off]];
62
62
63 if (val >= 0) {
63 if (val >= 0) {
64 return val;
64 return val;
65 }
65 }
66
66
67 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
67 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
68 return 0;
68 return 0;
69 }
69 }
70
70
71 /*
71 /*
72 * Turn a hex-encoded string into binary.
72 * Turn a hex-encoded string into binary.
73 */
73 */
74 PyObject *unhexlify(const char *str, int len)
74 PyObject *unhexlify(const char *str, int len)
75 {
75 {
76 PyObject *ret;
76 PyObject *ret;
77 char *d;
77 char *d;
78 int i;
78 int i;
79
79
80 ret = PyBytes_FromStringAndSize(NULL, len / 2);
80 ret = PyBytes_FromStringAndSize(NULL, len / 2);
81
81
82 if (!ret)
82 if (!ret)
83 return NULL;
83 return NULL;
84
84
85 d = PyBytes_AsString(ret);
85 d = PyBytes_AsString(ret);
86
86
87 for (i = 0; i < len;) {
87 for (i = 0; i < len;) {
88 int hi = hexdigit(str, i++);
88 int hi = hexdigit(str, i++);
89 int lo = hexdigit(str, i++);
89 int lo = hexdigit(str, i++);
90 *d++ = (hi << 4) | lo;
90 *d++ = (hi << 4) | lo;
91 }
91 }
92
92
93 return ret;
93 return ret;
94 }
94 }
95
95
96 static inline PyObject *_asciilower(PyObject *str_obj)
96 static inline PyObject *_asciilower(PyObject *str_obj)
97 {
97 {
98 char *str, *newstr;
98 char *str, *newstr;
99 Py_ssize_t i, len;
99 Py_ssize_t i, len;
100 PyObject *newobj = NULL;
100 PyObject *newobj = NULL;
101 PyObject *ret = NULL;
101
102
102 str = PyBytes_AS_STRING(str_obj);
103 str = PyBytes_AS_STRING(str_obj);
103 len = PyBytes_GET_SIZE(str_obj);
104 len = PyBytes_GET_SIZE(str_obj);
104
105
105 newobj = PyBytes_FromStringAndSize(NULL, len);
106 newobj = PyBytes_FromStringAndSize(NULL, len);
106 if (!newobj)
107 if (!newobj)
107 goto quit;
108 goto quit;
108
109
109 newstr = PyBytes_AS_STRING(newobj);
110 newstr = PyBytes_AS_STRING(newobj);
110
111
111 for (i = 0; i < len; i++) {
112 for (i = 0; i < len; i++) {
112 char c = str[i];
113 char c = str[i];
113 if (c & 0x80) {
114 if (c & 0x80) {
114 PyObject *err = PyUnicodeDecodeError_Create(
115 PyObject *err = PyUnicodeDecodeError_Create(
115 "ascii", str, len, i, (i + 1),
116 "ascii", str, len, i, (i + 1),
116 "unexpected code byte");
117 "unexpected code byte");
117 PyErr_SetObject(PyExc_UnicodeDecodeError, err);
118 PyErr_SetObject(PyExc_UnicodeDecodeError, err);
118 Py_XDECREF(err);
119 Py_XDECREF(err);
119 goto quit;
120 goto quit;
120 }
121 }
121 newstr[i] = lowertable[(unsigned char)c];
122 newstr[i] = lowertable[(unsigned char)c];
122 }
123 }
123
124
124 return newobj;
125 ret = newobj;
126 Py_INCREF(ret);
125 quit:
127 quit:
126 Py_XDECREF(newobj);
128 Py_XDECREF(newobj);
127 return NULL;
129 return ret;
128 }
130 }
129
131
130 static PyObject *asciilower(PyObject *self, PyObject *args)
132 static PyObject *asciilower(PyObject *self, PyObject *args)
131 {
133 {
132 PyObject *str_obj;
134 PyObject *str_obj;
133 if (!PyArg_ParseTuple(args, "O!:asciilower", &PyBytes_Type, &str_obj))
135 if (!PyArg_ParseTuple(args, "O!:asciilower", &PyBytes_Type, &str_obj))
134 return NULL;
136 return NULL;
135 return _asciilower(str_obj);
137 return _asciilower(str_obj);
136 }
138 }
137
139
138 /*
140 /*
139 * This code assumes that a manifest is stitched together with newline
141 * This code assumes that a manifest is stitched together with newline
140 * ('\n') characters.
142 * ('\n') characters.
141 */
143 */
142 static PyObject *parse_manifest(PyObject *self, PyObject *args)
144 static PyObject *parse_manifest(PyObject *self, PyObject *args)
143 {
145 {
144 PyObject *mfdict, *fdict;
146 PyObject *mfdict, *fdict;
145 char *str, *start, *end;
147 char *str, *start, *end;
146 int len;
148 int len;
147
149
148 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
150 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
149 &PyDict_Type, &mfdict,
151 &PyDict_Type, &mfdict,
150 &PyDict_Type, &fdict,
152 &PyDict_Type, &fdict,
151 &str, &len))
153 &str, &len))
152 goto quit;
154 goto quit;
153
155
154 start = str;
156 start = str;
155 end = str + len;
157 end = str + len;
156 while (start < end) {
158 while (start < end) {
157 PyObject *file = NULL, *node = NULL;
159 PyObject *file = NULL, *node = NULL;
158 PyObject *flags = NULL;
160 PyObject *flags = NULL;
159 char *zero = NULL, *newline = NULL;
161 char *zero = NULL, *newline = NULL;
160 ptrdiff_t nlen;
162 ptrdiff_t nlen;
161
163
162 zero = memchr(start, '\0', end - start);
164 zero = memchr(start, '\0', end - start);
163 if (!zero) {
165 if (!zero) {
164 PyErr_SetString(PyExc_ValueError,
166 PyErr_SetString(PyExc_ValueError,
165 "manifest entry has no separator");
167 "manifest entry has no separator");
166 goto quit;
168 goto quit;
167 }
169 }
168
170
169 newline = memchr(zero + 1, '\n', end - (zero + 1));
171 newline = memchr(zero + 1, '\n', end - (zero + 1));
170 if (!newline) {
172 if (!newline) {
171 PyErr_SetString(PyExc_ValueError,
173 PyErr_SetString(PyExc_ValueError,
172 "manifest contains trailing garbage");
174 "manifest contains trailing garbage");
173 goto quit;
175 goto quit;
174 }
176 }
175
177
176 file = PyBytes_FromStringAndSize(start, zero - start);
178 file = PyBytes_FromStringAndSize(start, zero - start);
177
179
178 if (!file)
180 if (!file)
179 goto bail;
181 goto bail;
180
182
181 nlen = newline - zero - 1;
183 nlen = newline - zero - 1;
182
184
183 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
185 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
184 if (!node)
186 if (!node)
185 goto bail;
187 goto bail;
186
188
187 if (nlen > 40) {
189 if (nlen > 40) {
188 flags = PyBytes_FromStringAndSize(zero + 41,
190 flags = PyBytes_FromStringAndSize(zero + 41,
189 nlen - 40);
191 nlen - 40);
190 if (!flags)
192 if (!flags)
191 goto bail;
193 goto bail;
192
194
193 if (PyDict_SetItem(fdict, file, flags) == -1)
195 if (PyDict_SetItem(fdict, file, flags) == -1)
194 goto bail;
196 goto bail;
195 }
197 }
196
198
197 if (PyDict_SetItem(mfdict, file, node) == -1)
199 if (PyDict_SetItem(mfdict, file, node) == -1)
198 goto bail;
200 goto bail;
199
201
200 start = newline + 1;
202 start = newline + 1;
201
203
202 Py_XDECREF(flags);
204 Py_XDECREF(flags);
203 Py_XDECREF(node);
205 Py_XDECREF(node);
204 Py_XDECREF(file);
206 Py_XDECREF(file);
205 continue;
207 continue;
206 bail:
208 bail:
207 Py_XDECREF(flags);
209 Py_XDECREF(flags);
208 Py_XDECREF(node);
210 Py_XDECREF(node);
209 Py_XDECREF(file);
211 Py_XDECREF(file);
210 goto quit;
212 goto quit;
211 }
213 }
212
214
213 Py_INCREF(Py_None);
215 Py_INCREF(Py_None);
214 return Py_None;
216 return Py_None;
215 quit:
217 quit:
216 return NULL;
218 return NULL;
217 }
219 }
218
220
219 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
221 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
220 int size, int mtime)
222 int size, int mtime)
221 {
223 {
222 dirstateTupleObject *t = PyObject_New(dirstateTupleObject,
224 dirstateTupleObject *t = PyObject_New(dirstateTupleObject,
223 &dirstateTupleType);
225 &dirstateTupleType);
224 if (!t)
226 if (!t)
225 return NULL;
227 return NULL;
226 t->state = state;
228 t->state = state;
227 t->mode = mode;
229 t->mode = mode;
228 t->size = size;
230 t->size = size;
229 t->mtime = mtime;
231 t->mtime = mtime;
230 return t;
232 return t;
231 }
233 }
232
234
233 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
235 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
234 PyObject *kwds)
236 PyObject *kwds)
235 {
237 {
236 /* We do all the initialization here and not a tp_init function because
238 /* We do all the initialization here and not a tp_init function because
237 * dirstate_tuple is immutable. */
239 * dirstate_tuple is immutable. */
238 dirstateTupleObject *t;
240 dirstateTupleObject *t;
239 char state;
241 char state;
240 int size, mode, mtime;
242 int size, mode, mtime;
241 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
243 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
242 return NULL;
244 return NULL;
243
245
244 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
246 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
245 if (!t)
247 if (!t)
246 return NULL;
248 return NULL;
247 t->state = state;
249 t->state = state;
248 t->mode = mode;
250 t->mode = mode;
249 t->size = size;
251 t->size = size;
250 t->mtime = mtime;
252 t->mtime = mtime;
251
253
252 return (PyObject *)t;
254 return (PyObject *)t;
253 }
255 }
254
256
255 static void dirstate_tuple_dealloc(PyObject *o)
257 static void dirstate_tuple_dealloc(PyObject *o)
256 {
258 {
257 PyObject_Del(o);
259 PyObject_Del(o);
258 }
260 }
259
261
260 static Py_ssize_t dirstate_tuple_length(PyObject *o)
262 static Py_ssize_t dirstate_tuple_length(PyObject *o)
261 {
263 {
262 return 4;
264 return 4;
263 }
265 }
264
266
265 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
267 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
266 {
268 {
267 dirstateTupleObject *t = (dirstateTupleObject *)o;
269 dirstateTupleObject *t = (dirstateTupleObject *)o;
268 switch (i) {
270 switch (i) {
269 case 0:
271 case 0:
270 return PyBytes_FromStringAndSize(&t->state, 1);
272 return PyBytes_FromStringAndSize(&t->state, 1);
271 case 1:
273 case 1:
272 return PyInt_FromLong(t->mode);
274 return PyInt_FromLong(t->mode);
273 case 2:
275 case 2:
274 return PyInt_FromLong(t->size);
276 return PyInt_FromLong(t->size);
275 case 3:
277 case 3:
276 return PyInt_FromLong(t->mtime);
278 return PyInt_FromLong(t->mtime);
277 default:
279 default:
278 PyErr_SetString(PyExc_IndexError, "index out of range");
280 PyErr_SetString(PyExc_IndexError, "index out of range");
279 return NULL;
281 return NULL;
280 }
282 }
281 }
283 }
282
284
283 static PySequenceMethods dirstate_tuple_sq = {
285 static PySequenceMethods dirstate_tuple_sq = {
284 dirstate_tuple_length, /* sq_length */
286 dirstate_tuple_length, /* sq_length */
285 0, /* sq_concat */
287 0, /* sq_concat */
286 0, /* sq_repeat */
288 0, /* sq_repeat */
287 dirstate_tuple_item, /* sq_item */
289 dirstate_tuple_item, /* sq_item */
288 0, /* sq_ass_item */
290 0, /* sq_ass_item */
289 0, /* sq_contains */
291 0, /* sq_contains */
290 0, /* sq_inplace_concat */
292 0, /* sq_inplace_concat */
291 0 /* sq_inplace_repeat */
293 0 /* sq_inplace_repeat */
292 };
294 };
293
295
294 PyTypeObject dirstateTupleType = {
296 PyTypeObject dirstateTupleType = {
295 PyVarObject_HEAD_INIT(NULL, 0)
297 PyVarObject_HEAD_INIT(NULL, 0)
296 "dirstate_tuple", /* tp_name */
298 "dirstate_tuple", /* tp_name */
297 sizeof(dirstateTupleObject),/* tp_basicsize */
299 sizeof(dirstateTupleObject),/* tp_basicsize */
298 0, /* tp_itemsize */
300 0, /* tp_itemsize */
299 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
301 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
300 0, /* tp_print */
302 0, /* tp_print */
301 0, /* tp_getattr */
303 0, /* tp_getattr */
302 0, /* tp_setattr */
304 0, /* tp_setattr */
303 0, /* tp_compare */
305 0, /* tp_compare */
304 0, /* tp_repr */
306 0, /* tp_repr */
305 0, /* tp_as_number */
307 0, /* tp_as_number */
306 &dirstate_tuple_sq, /* tp_as_sequence */
308 &dirstate_tuple_sq, /* tp_as_sequence */
307 0, /* tp_as_mapping */
309 0, /* tp_as_mapping */
308 0, /* tp_hash */
310 0, /* tp_hash */
309 0, /* tp_call */
311 0, /* tp_call */
310 0, /* tp_str */
312 0, /* tp_str */
311 0, /* tp_getattro */
313 0, /* tp_getattro */
312 0, /* tp_setattro */
314 0, /* tp_setattro */
313 0, /* tp_as_buffer */
315 0, /* tp_as_buffer */
314 Py_TPFLAGS_DEFAULT, /* tp_flags */
316 Py_TPFLAGS_DEFAULT, /* tp_flags */
315 "dirstate tuple", /* tp_doc */
317 "dirstate tuple", /* tp_doc */
316 0, /* tp_traverse */
318 0, /* tp_traverse */
317 0, /* tp_clear */
319 0, /* tp_clear */
318 0, /* tp_richcompare */
320 0, /* tp_richcompare */
319 0, /* tp_weaklistoffset */
321 0, /* tp_weaklistoffset */
320 0, /* tp_iter */
322 0, /* tp_iter */
321 0, /* tp_iternext */
323 0, /* tp_iternext */
322 0, /* tp_methods */
324 0, /* tp_methods */
323 0, /* tp_members */
325 0, /* tp_members */
324 0, /* tp_getset */
326 0, /* tp_getset */
325 0, /* tp_base */
327 0, /* tp_base */
326 0, /* tp_dict */
328 0, /* tp_dict */
327 0, /* tp_descr_get */
329 0, /* tp_descr_get */
328 0, /* tp_descr_set */
330 0, /* tp_descr_set */
329 0, /* tp_dictoffset */
331 0, /* tp_dictoffset */
330 0, /* tp_init */
332 0, /* tp_init */
331 0, /* tp_alloc */
333 0, /* tp_alloc */
332 dirstate_tuple_new, /* tp_new */
334 dirstate_tuple_new, /* tp_new */
333 };
335 };
334
336
335 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
337 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
336 {
338 {
337 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
339 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
338 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
340 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
339 char state, *cur, *str, *cpos;
341 char state, *cur, *str, *cpos;
340 int mode, size, mtime;
342 int mode, size, mtime;
341 unsigned int flen, len, pos = 40;
343 unsigned int flen, len, pos = 40;
342 int readlen;
344 int readlen;
343
345
344 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
346 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
345 &PyDict_Type, &dmap,
347 &PyDict_Type, &dmap,
346 &PyDict_Type, &cmap,
348 &PyDict_Type, &cmap,
347 &str, &readlen))
349 &str, &readlen))
348 goto quit;
350 goto quit;
349
351
350 if (readlen < 0)
352 if (readlen < 0)
351 goto quit;
353 goto quit;
352
354
353 len = readlen;
355 len = readlen;
354
356
355 /* read parents */
357 /* read parents */
356 if (len < 40)
358 if (len < 40)
357 goto quit;
359 goto quit;
358
360
359 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
361 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
360 if (!parents)
362 if (!parents)
361 goto quit;
363 goto quit;
362
364
363 /* read filenames */
365 /* read filenames */
364 while (pos >= 40 && pos < len) {
366 while (pos >= 40 && pos < len) {
365 cur = str + pos;
367 cur = str + pos;
366 /* unpack header */
368 /* unpack header */
367 state = *cur;
369 state = *cur;
368 mode = getbe32(cur + 1);
370 mode = getbe32(cur + 1);
369 size = getbe32(cur + 5);
371 size = getbe32(cur + 5);
370 mtime = getbe32(cur + 9);
372 mtime = getbe32(cur + 9);
371 flen = getbe32(cur + 13);
373 flen = getbe32(cur + 13);
372 pos += 17;
374 pos += 17;
373 cur += 17;
375 cur += 17;
374 if (flen > len - pos) {
376 if (flen > len - pos) {
375 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
377 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
376 goto quit;
378 goto quit;
377 }
379 }
378
380
379 entry = (PyObject *)make_dirstate_tuple(state, mode, size,
381 entry = (PyObject *)make_dirstate_tuple(state, mode, size,
380 mtime);
382 mtime);
381 cpos = memchr(cur, 0, flen);
383 cpos = memchr(cur, 0, flen);
382 if (cpos) {
384 if (cpos) {
383 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
385 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
384 cname = PyBytes_FromStringAndSize(cpos + 1,
386 cname = PyBytes_FromStringAndSize(cpos + 1,
385 flen - (cpos - cur) - 1);
387 flen - (cpos - cur) - 1);
386 if (!fname || !cname ||
388 if (!fname || !cname ||
387 PyDict_SetItem(cmap, fname, cname) == -1 ||
389 PyDict_SetItem(cmap, fname, cname) == -1 ||
388 PyDict_SetItem(dmap, fname, entry) == -1)
390 PyDict_SetItem(dmap, fname, entry) == -1)
389 goto quit;
391 goto quit;
390 Py_DECREF(cname);
392 Py_DECREF(cname);
391 } else {
393 } else {
392 fname = PyBytes_FromStringAndSize(cur, flen);
394 fname = PyBytes_FromStringAndSize(cur, flen);
393 if (!fname ||
395 if (!fname ||
394 PyDict_SetItem(dmap, fname, entry) == -1)
396 PyDict_SetItem(dmap, fname, entry) == -1)
395 goto quit;
397 goto quit;
396 }
398 }
397 Py_DECREF(fname);
399 Py_DECREF(fname);
398 Py_DECREF(entry);
400 Py_DECREF(entry);
399 fname = cname = entry = NULL;
401 fname = cname = entry = NULL;
400 pos += flen;
402 pos += flen;
401 }
403 }
402
404
403 ret = parents;
405 ret = parents;
404 Py_INCREF(ret);
406 Py_INCREF(ret);
405 quit:
407 quit:
406 Py_XDECREF(fname);
408 Py_XDECREF(fname);
407 Py_XDECREF(cname);
409 Py_XDECREF(cname);
408 Py_XDECREF(entry);
410 Py_XDECREF(entry);
409 Py_XDECREF(parents);
411 Py_XDECREF(parents);
410 return ret;
412 return ret;
411 }
413 }
412
414
413 /*
415 /*
414 * Efficiently pack a dirstate object into its on-disk format.
416 * Efficiently pack a dirstate object into its on-disk format.
415 */
417 */
416 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
418 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
417 {
419 {
418 PyObject *packobj = NULL;
420 PyObject *packobj = NULL;
419 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
421 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
420 Py_ssize_t nbytes, pos, l;
422 Py_ssize_t nbytes, pos, l;
421 PyObject *k, *v = NULL, *pn;
423 PyObject *k, *v = NULL, *pn;
422 char *p, *s;
424 char *p, *s;
423 double now;
425 double now;
424
426
425 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
427 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
426 &PyDict_Type, &map, &PyDict_Type, &copymap,
428 &PyDict_Type, &map, &PyDict_Type, &copymap,
427 &pl, &now))
429 &pl, &now))
428 return NULL;
430 return NULL;
429
431
430 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
432 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
431 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
433 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
432 return NULL;
434 return NULL;
433 }
435 }
434
436
435 /* Figure out how much we need to allocate. */
437 /* Figure out how much we need to allocate. */
436 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
438 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
437 PyObject *c;
439 PyObject *c;
438 if (!PyString_Check(k)) {
440 if (!PyString_Check(k)) {
439 PyErr_SetString(PyExc_TypeError, "expected string key");
441 PyErr_SetString(PyExc_TypeError, "expected string key");
440 goto bail;
442 goto bail;
441 }
443 }
442 nbytes += PyString_GET_SIZE(k) + 17;
444 nbytes += PyString_GET_SIZE(k) + 17;
443 c = PyDict_GetItem(copymap, k);
445 c = PyDict_GetItem(copymap, k);
444 if (c) {
446 if (c) {
445 if (!PyString_Check(c)) {
447 if (!PyString_Check(c)) {
446 PyErr_SetString(PyExc_TypeError,
448 PyErr_SetString(PyExc_TypeError,
447 "expected string key");
449 "expected string key");
448 goto bail;
450 goto bail;
449 }
451 }
450 nbytes += PyString_GET_SIZE(c) + 1;
452 nbytes += PyString_GET_SIZE(c) + 1;
451 }
453 }
452 }
454 }
453
455
454 packobj = PyString_FromStringAndSize(NULL, nbytes);
456 packobj = PyString_FromStringAndSize(NULL, nbytes);
455 if (packobj == NULL)
457 if (packobj == NULL)
456 goto bail;
458 goto bail;
457
459
458 p = PyString_AS_STRING(packobj);
460 p = PyString_AS_STRING(packobj);
459
461
460 pn = PySequence_ITEM(pl, 0);
462 pn = PySequence_ITEM(pl, 0);
461 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
463 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
462 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
464 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
463 goto bail;
465 goto bail;
464 }
466 }
465 memcpy(p, s, l);
467 memcpy(p, s, l);
466 p += 20;
468 p += 20;
467 pn = PySequence_ITEM(pl, 1);
469 pn = PySequence_ITEM(pl, 1);
468 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
470 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
469 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
471 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
470 goto bail;
472 goto bail;
471 }
473 }
472 memcpy(p, s, l);
474 memcpy(p, s, l);
473 p += 20;
475 p += 20;
474
476
475 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
477 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
476 dirstateTupleObject *tuple;
478 dirstateTupleObject *tuple;
477 char state;
479 char state;
478 uint32_t mode, size, mtime;
480 uint32_t mode, size, mtime;
479 Py_ssize_t len, l;
481 Py_ssize_t len, l;
480 PyObject *o;
482 PyObject *o;
481 char *t;
483 char *t;
482
484
483 if (!dirstate_tuple_check(v)) {
485 if (!dirstate_tuple_check(v)) {
484 PyErr_SetString(PyExc_TypeError,
486 PyErr_SetString(PyExc_TypeError,
485 "expected a dirstate tuple");
487 "expected a dirstate tuple");
486 goto bail;
488 goto bail;
487 }
489 }
488 tuple = (dirstateTupleObject *)v;
490 tuple = (dirstateTupleObject *)v;
489
491
490 state = tuple->state;
492 state = tuple->state;
491 mode = tuple->mode;
493 mode = tuple->mode;
492 size = tuple->size;
494 size = tuple->size;
493 mtime = tuple->mtime;
495 mtime = tuple->mtime;
494 if (state == 'n' && mtime == (uint32_t)now) {
496 if (state == 'n' && mtime == (uint32_t)now) {
495 /* See pure/parsers.py:pack_dirstate for why we do
497 /* See pure/parsers.py:pack_dirstate for why we do
496 * this. */
498 * this. */
497 mtime = -1;
499 mtime = -1;
498 mtime_unset = (PyObject *)make_dirstate_tuple(
500 mtime_unset = (PyObject *)make_dirstate_tuple(
499 state, mode, size, mtime);
501 state, mode, size, mtime);
500 if (!mtime_unset)
502 if (!mtime_unset)
501 goto bail;
503 goto bail;
502 if (PyDict_SetItem(map, k, mtime_unset) == -1)
504 if (PyDict_SetItem(map, k, mtime_unset) == -1)
503 goto bail;
505 goto bail;
504 Py_DECREF(mtime_unset);
506 Py_DECREF(mtime_unset);
505 mtime_unset = NULL;
507 mtime_unset = NULL;
506 }
508 }
507 *p++ = state;
509 *p++ = state;
508 putbe32(mode, p);
510 putbe32(mode, p);
509 putbe32(size, p + 4);
511 putbe32(size, p + 4);
510 putbe32(mtime, p + 8);
512 putbe32(mtime, p + 8);
511 t = p + 12;
513 t = p + 12;
512 p += 16;
514 p += 16;
513 len = PyString_GET_SIZE(k);
515 len = PyString_GET_SIZE(k);
514 memcpy(p, PyString_AS_STRING(k), len);
516 memcpy(p, PyString_AS_STRING(k), len);
515 p += len;
517 p += len;
516 o = PyDict_GetItem(copymap, k);
518 o = PyDict_GetItem(copymap, k);
517 if (o) {
519 if (o) {
518 *p++ = '\0';
520 *p++ = '\0';
519 l = PyString_GET_SIZE(o);
521 l = PyString_GET_SIZE(o);
520 memcpy(p, PyString_AS_STRING(o), l);
522 memcpy(p, PyString_AS_STRING(o), l);
521 p += l;
523 p += l;
522 len += l + 1;
524 len += l + 1;
523 }
525 }
524 putbe32((uint32_t)len, t);
526 putbe32((uint32_t)len, t);
525 }
527 }
526
528
527 pos = p - PyString_AS_STRING(packobj);
529 pos = p - PyString_AS_STRING(packobj);
528 if (pos != nbytes) {
530 if (pos != nbytes) {
529 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
531 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
530 (long)pos, (long)nbytes);
532 (long)pos, (long)nbytes);
531 goto bail;
533 goto bail;
532 }
534 }
533
535
534 return packobj;
536 return packobj;
535 bail:
537 bail:
536 Py_XDECREF(mtime_unset);
538 Py_XDECREF(mtime_unset);
537 Py_XDECREF(packobj);
539 Py_XDECREF(packobj);
538 Py_XDECREF(v);
540 Py_XDECREF(v);
539 return NULL;
541 return NULL;
540 }
542 }
541
543
542 /*
544 /*
543 * A base-16 trie for fast node->rev mapping.
545 * A base-16 trie for fast node->rev mapping.
544 *
546 *
545 * Positive value is index of the next node in the trie
547 * Positive value is index of the next node in the trie
546 * Negative value is a leaf: -(rev + 1)
548 * Negative value is a leaf: -(rev + 1)
547 * Zero is empty
549 * Zero is empty
548 */
550 */
549 typedef struct {
551 typedef struct {
550 int children[16];
552 int children[16];
551 } nodetree;
553 } nodetree;
552
554
553 /*
555 /*
554 * This class has two behaviours.
556 * This class has two behaviours.
555 *
557 *
556 * When used in a list-like way (with integer keys), we decode an
558 * When used in a list-like way (with integer keys), we decode an
557 * entry in a RevlogNG index file on demand. Our last entry is a
559 * entry in a RevlogNG index file on demand. Our last entry is a
558 * sentinel, always a nullid. We have limited support for
560 * sentinel, always a nullid. We have limited support for
559 * integer-keyed insert and delete, only at elements right before the
561 * integer-keyed insert and delete, only at elements right before the
560 * sentinel.
562 * sentinel.
561 *
563 *
562 * With string keys, we lazily perform a reverse mapping from node to
564 * With string keys, we lazily perform a reverse mapping from node to
563 * rev, using a base-16 trie.
565 * rev, using a base-16 trie.
564 */
566 */
565 typedef struct {
567 typedef struct {
566 PyObject_HEAD
568 PyObject_HEAD
567 /* Type-specific fields go here. */
569 /* Type-specific fields go here. */
568 PyObject *data; /* raw bytes of index */
570 PyObject *data; /* raw bytes of index */
569 PyObject **cache; /* cached tuples */
571 PyObject **cache; /* cached tuples */
570 const char **offsets; /* populated on demand */
572 const char **offsets; /* populated on demand */
571 Py_ssize_t raw_length; /* original number of elements */
573 Py_ssize_t raw_length; /* original number of elements */
572 Py_ssize_t length; /* current number of elements */
574 Py_ssize_t length; /* current number of elements */
573 PyObject *added; /* populated on demand */
575 PyObject *added; /* populated on demand */
574 PyObject *headrevs; /* cache, invalidated on changes */
576 PyObject *headrevs; /* cache, invalidated on changes */
575 PyObject *filteredrevs;/* filtered revs set */
577 PyObject *filteredrevs;/* filtered revs set */
576 nodetree *nt; /* base-16 trie */
578 nodetree *nt; /* base-16 trie */
577 int ntlength; /* # nodes in use */
579 int ntlength; /* # nodes in use */
578 int ntcapacity; /* # nodes allocated */
580 int ntcapacity; /* # nodes allocated */
579 int ntdepth; /* maximum depth of tree */
581 int ntdepth; /* maximum depth of tree */
580 int ntsplits; /* # splits performed */
582 int ntsplits; /* # splits performed */
581 int ntrev; /* last rev scanned */
583 int ntrev; /* last rev scanned */
582 int ntlookups; /* # lookups */
584 int ntlookups; /* # lookups */
583 int ntmisses; /* # lookups that miss the cache */
585 int ntmisses; /* # lookups that miss the cache */
584 int inlined;
586 int inlined;
585 } indexObject;
587 } indexObject;
586
588
587 static Py_ssize_t index_length(const indexObject *self)
589 static Py_ssize_t index_length(const indexObject *self)
588 {
590 {
589 if (self->added == NULL)
591 if (self->added == NULL)
590 return self->length;
592 return self->length;
591 return self->length + PyList_GET_SIZE(self->added);
593 return self->length + PyList_GET_SIZE(self->added);
592 }
594 }
593
595
594 static PyObject *nullentry;
596 static PyObject *nullentry;
595 static const char nullid[20];
597 static const char nullid[20];
596
598
597 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
599 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
598
600
599 #if LONG_MAX == 0x7fffffffL
601 #if LONG_MAX == 0x7fffffffL
600 static char *tuple_format = "Kiiiiiis#";
602 static char *tuple_format = "Kiiiiiis#";
601 #else
603 #else
602 static char *tuple_format = "kiiiiiis#";
604 static char *tuple_format = "kiiiiiis#";
603 #endif
605 #endif
604
606
605 /* A RevlogNG v1 index entry is 64 bytes long. */
607 /* A RevlogNG v1 index entry is 64 bytes long. */
606 static const long v1_hdrsize = 64;
608 static const long v1_hdrsize = 64;
607
609
608 /*
610 /*
609 * Return a pointer to the beginning of a RevlogNG record.
611 * Return a pointer to the beginning of a RevlogNG record.
610 */
612 */
611 static const char *index_deref(indexObject *self, Py_ssize_t pos)
613 static const char *index_deref(indexObject *self, Py_ssize_t pos)
612 {
614 {
613 if (self->inlined && pos > 0) {
615 if (self->inlined && pos > 0) {
614 if (self->offsets == NULL) {
616 if (self->offsets == NULL) {
615 self->offsets = malloc(self->raw_length *
617 self->offsets = malloc(self->raw_length *
616 sizeof(*self->offsets));
618 sizeof(*self->offsets));
617 if (self->offsets == NULL)
619 if (self->offsets == NULL)
618 return (const char *)PyErr_NoMemory();
620 return (const char *)PyErr_NoMemory();
619 inline_scan(self, self->offsets);
621 inline_scan(self, self->offsets);
620 }
622 }
621 return self->offsets[pos];
623 return self->offsets[pos];
622 }
624 }
623
625
624 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
626 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
625 }
627 }
626
628
627 /*
629 /*
628 * RevlogNG format (all in big endian, data may be inlined):
630 * RevlogNG format (all in big endian, data may be inlined):
629 * 6 bytes: offset
631 * 6 bytes: offset
630 * 2 bytes: flags
632 * 2 bytes: flags
631 * 4 bytes: compressed length
633 * 4 bytes: compressed length
632 * 4 bytes: uncompressed length
634 * 4 bytes: uncompressed length
633 * 4 bytes: base revision
635 * 4 bytes: base revision
634 * 4 bytes: link revision
636 * 4 bytes: link revision
635 * 4 bytes: parent 1 revision
637 * 4 bytes: parent 1 revision
636 * 4 bytes: parent 2 revision
638 * 4 bytes: parent 2 revision
637 * 32 bytes: nodeid (only 20 bytes used)
639 * 32 bytes: nodeid (only 20 bytes used)
638 */
640 */
639 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
641 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
640 {
642 {
641 uint64_t offset_flags;
643 uint64_t offset_flags;
642 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
644 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
643 const char *c_node_id;
645 const char *c_node_id;
644 const char *data;
646 const char *data;
645 Py_ssize_t length = index_length(self);
647 Py_ssize_t length = index_length(self);
646 PyObject *entry;
648 PyObject *entry;
647
649
648 if (pos < 0)
650 if (pos < 0)
649 pos += length;
651 pos += length;
650
652
651 if (pos < 0 || pos >= length) {
653 if (pos < 0 || pos >= length) {
652 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
654 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
653 return NULL;
655 return NULL;
654 }
656 }
655
657
656 if (pos == length - 1) {
658 if (pos == length - 1) {
657 Py_INCREF(nullentry);
659 Py_INCREF(nullentry);
658 return nullentry;
660 return nullentry;
659 }
661 }
660
662
661 if (pos >= self->length - 1) {
663 if (pos >= self->length - 1) {
662 PyObject *obj;
664 PyObject *obj;
663 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
665 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
664 Py_INCREF(obj);
666 Py_INCREF(obj);
665 return obj;
667 return obj;
666 }
668 }
667
669
668 if (self->cache) {
670 if (self->cache) {
669 if (self->cache[pos]) {
671 if (self->cache[pos]) {
670 Py_INCREF(self->cache[pos]);
672 Py_INCREF(self->cache[pos]);
671 return self->cache[pos];
673 return self->cache[pos];
672 }
674 }
673 } else {
675 } else {
674 self->cache = calloc(self->raw_length, sizeof(PyObject *));
676 self->cache = calloc(self->raw_length, sizeof(PyObject *));
675 if (self->cache == NULL)
677 if (self->cache == NULL)
676 return PyErr_NoMemory();
678 return PyErr_NoMemory();
677 }
679 }
678
680
679 data = index_deref(self, pos);
681 data = index_deref(self, pos);
680 if (data == NULL)
682 if (data == NULL)
681 return NULL;
683 return NULL;
682
684
683 offset_flags = getbe32(data + 4);
685 offset_flags = getbe32(data + 4);
684 if (pos == 0) /* mask out version number for the first entry */
686 if (pos == 0) /* mask out version number for the first entry */
685 offset_flags &= 0xFFFF;
687 offset_flags &= 0xFFFF;
686 else {
688 else {
687 uint32_t offset_high = getbe32(data);
689 uint32_t offset_high = getbe32(data);
688 offset_flags |= ((uint64_t)offset_high) << 32;
690 offset_flags |= ((uint64_t)offset_high) << 32;
689 }
691 }
690
692
691 comp_len = getbe32(data + 8);
693 comp_len = getbe32(data + 8);
692 uncomp_len = getbe32(data + 12);
694 uncomp_len = getbe32(data + 12);
693 base_rev = getbe32(data + 16);
695 base_rev = getbe32(data + 16);
694 link_rev = getbe32(data + 20);
696 link_rev = getbe32(data + 20);
695 parent_1 = getbe32(data + 24);
697 parent_1 = getbe32(data + 24);
696 parent_2 = getbe32(data + 28);
698 parent_2 = getbe32(data + 28);
697 c_node_id = data + 32;
699 c_node_id = data + 32;
698
700
699 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
701 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
700 uncomp_len, base_rev, link_rev,
702 uncomp_len, base_rev, link_rev,
701 parent_1, parent_2, c_node_id, 20);
703 parent_1, parent_2, c_node_id, 20);
702
704
703 if (entry) {
705 if (entry) {
704 PyObject_GC_UnTrack(entry);
706 PyObject_GC_UnTrack(entry);
705 Py_INCREF(entry);
707 Py_INCREF(entry);
706 }
708 }
707
709
708 self->cache[pos] = entry;
710 self->cache[pos] = entry;
709
711
710 return entry;
712 return entry;
711 }
713 }
712
714
713 /*
715 /*
714 * Return the 20-byte SHA of the node corresponding to the given rev.
716 * Return the 20-byte SHA of the node corresponding to the given rev.
715 */
717 */
716 static const char *index_node(indexObject *self, Py_ssize_t pos)
718 static const char *index_node(indexObject *self, Py_ssize_t pos)
717 {
719 {
718 Py_ssize_t length = index_length(self);
720 Py_ssize_t length = index_length(self);
719 const char *data;
721 const char *data;
720
722
721 if (pos == length - 1 || pos == INT_MAX)
723 if (pos == length - 1 || pos == INT_MAX)
722 return nullid;
724 return nullid;
723
725
724 if (pos >= length)
726 if (pos >= length)
725 return NULL;
727 return NULL;
726
728
727 if (pos >= self->length - 1) {
729 if (pos >= self->length - 1) {
728 PyObject *tuple, *str;
730 PyObject *tuple, *str;
729 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
731 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
730 str = PyTuple_GetItem(tuple, 7);
732 str = PyTuple_GetItem(tuple, 7);
731 return str ? PyString_AS_STRING(str) : NULL;
733 return str ? PyString_AS_STRING(str) : NULL;
732 }
734 }
733
735
734 data = index_deref(self, pos);
736 data = index_deref(self, pos);
735 return data ? data + 32 : NULL;
737 return data ? data + 32 : NULL;
736 }
738 }
737
739
738 static int nt_insert(indexObject *self, const char *node, int rev);
740 static int nt_insert(indexObject *self, const char *node, int rev);
739
741
740 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
742 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
741 {
743 {
742 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
744 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
743 return -1;
745 return -1;
744 if (*nodelen == 20)
746 if (*nodelen == 20)
745 return 0;
747 return 0;
746 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
748 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
747 return -1;
749 return -1;
748 }
750 }
749
751
750 static PyObject *index_insert(indexObject *self, PyObject *args)
752 static PyObject *index_insert(indexObject *self, PyObject *args)
751 {
753 {
752 PyObject *obj;
754 PyObject *obj;
753 char *node;
755 char *node;
754 int index;
756 int index;
755 Py_ssize_t len, nodelen;
757 Py_ssize_t len, nodelen;
756
758
757 if (!PyArg_ParseTuple(args, "iO", &index, &obj))
759 if (!PyArg_ParseTuple(args, "iO", &index, &obj))
758 return NULL;
760 return NULL;
759
761
760 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
762 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
761 PyErr_SetString(PyExc_TypeError, "8-tuple required");
763 PyErr_SetString(PyExc_TypeError, "8-tuple required");
762 return NULL;
764 return NULL;
763 }
765 }
764
766
765 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
767 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
766 return NULL;
768 return NULL;
767
769
768 len = index_length(self);
770 len = index_length(self);
769
771
770 if (index < 0)
772 if (index < 0)
771 index += len;
773 index += len;
772
774
773 if (index != len - 1) {
775 if (index != len - 1) {
774 PyErr_SetString(PyExc_IndexError,
776 PyErr_SetString(PyExc_IndexError,
775 "insert only supported at index -1");
777 "insert only supported at index -1");
776 return NULL;
778 return NULL;
777 }
779 }
778
780
779 if (self->added == NULL) {
781 if (self->added == NULL) {
780 self->added = PyList_New(0);
782 self->added = PyList_New(0);
781 if (self->added == NULL)
783 if (self->added == NULL)
782 return NULL;
784 return NULL;
783 }
785 }
784
786
785 if (PyList_Append(self->added, obj) == -1)
787 if (PyList_Append(self->added, obj) == -1)
786 return NULL;
788 return NULL;
787
789
788 if (self->nt)
790 if (self->nt)
789 nt_insert(self, node, index);
791 nt_insert(self, node, index);
790
792
791 Py_CLEAR(self->headrevs);
793 Py_CLEAR(self->headrevs);
792 Py_RETURN_NONE;
794 Py_RETURN_NONE;
793 }
795 }
794
796
795 static void _index_clearcaches(indexObject *self)
797 static void _index_clearcaches(indexObject *self)
796 {
798 {
797 if (self->cache) {
799 if (self->cache) {
798 Py_ssize_t i;
800 Py_ssize_t i;
799
801
800 for (i = 0; i < self->raw_length; i++)
802 for (i = 0; i < self->raw_length; i++)
801 Py_CLEAR(self->cache[i]);
803 Py_CLEAR(self->cache[i]);
802 free(self->cache);
804 free(self->cache);
803 self->cache = NULL;
805 self->cache = NULL;
804 }
806 }
805 if (self->offsets) {
807 if (self->offsets) {
806 free(self->offsets);
808 free(self->offsets);
807 self->offsets = NULL;
809 self->offsets = NULL;
808 }
810 }
809 if (self->nt) {
811 if (self->nt) {
810 free(self->nt);
812 free(self->nt);
811 self->nt = NULL;
813 self->nt = NULL;
812 }
814 }
813 Py_CLEAR(self->headrevs);
815 Py_CLEAR(self->headrevs);
814 }
816 }
815
817
816 static PyObject *index_clearcaches(indexObject *self)
818 static PyObject *index_clearcaches(indexObject *self)
817 {
819 {
818 _index_clearcaches(self);
820 _index_clearcaches(self);
819 self->ntlength = self->ntcapacity = 0;
821 self->ntlength = self->ntcapacity = 0;
820 self->ntdepth = self->ntsplits = 0;
822 self->ntdepth = self->ntsplits = 0;
821 self->ntrev = -1;
823 self->ntrev = -1;
822 self->ntlookups = self->ntmisses = 0;
824 self->ntlookups = self->ntmisses = 0;
823 Py_RETURN_NONE;
825 Py_RETURN_NONE;
824 }
826 }
825
827
826 static PyObject *index_stats(indexObject *self)
828 static PyObject *index_stats(indexObject *self)
827 {
829 {
828 PyObject *obj = PyDict_New();
830 PyObject *obj = PyDict_New();
829 PyObject *t = NULL;
831 PyObject *t = NULL;
830
832
831 if (obj == NULL)
833 if (obj == NULL)
832 return NULL;
834 return NULL;
833
835
834 #define istat(__n, __d) \
836 #define istat(__n, __d) \
835 t = PyInt_FromSsize_t(self->__n); \
837 t = PyInt_FromSsize_t(self->__n); \
836 if (!t) \
838 if (!t) \
837 goto bail; \
839 goto bail; \
838 if (PyDict_SetItemString(obj, __d, t) == -1) \
840 if (PyDict_SetItemString(obj, __d, t) == -1) \
839 goto bail; \
841 goto bail; \
840 Py_DECREF(t);
842 Py_DECREF(t);
841
843
842 if (self->added) {
844 if (self->added) {
843 Py_ssize_t len = PyList_GET_SIZE(self->added);
845 Py_ssize_t len = PyList_GET_SIZE(self->added);
844 t = PyInt_FromSsize_t(len);
846 t = PyInt_FromSsize_t(len);
845 if (!t)
847 if (!t)
846 goto bail;
848 goto bail;
847 if (PyDict_SetItemString(obj, "index entries added", t) == -1)
849 if (PyDict_SetItemString(obj, "index entries added", t) == -1)
848 goto bail;
850 goto bail;
849 Py_DECREF(t);
851 Py_DECREF(t);
850 }
852 }
851
853
852 if (self->raw_length != self->length - 1)
854 if (self->raw_length != self->length - 1)
853 istat(raw_length, "revs on disk");
855 istat(raw_length, "revs on disk");
854 istat(length, "revs in memory");
856 istat(length, "revs in memory");
855 istat(ntcapacity, "node trie capacity");
857 istat(ntcapacity, "node trie capacity");
856 istat(ntdepth, "node trie depth");
858 istat(ntdepth, "node trie depth");
857 istat(ntlength, "node trie count");
859 istat(ntlength, "node trie count");
858 istat(ntlookups, "node trie lookups");
860 istat(ntlookups, "node trie lookups");
859 istat(ntmisses, "node trie misses");
861 istat(ntmisses, "node trie misses");
860 istat(ntrev, "node trie last rev scanned");
862 istat(ntrev, "node trie last rev scanned");
861 istat(ntsplits, "node trie splits");
863 istat(ntsplits, "node trie splits");
862
864
863 #undef istat
865 #undef istat
864
866
865 return obj;
867 return obj;
866
868
867 bail:
869 bail:
868 Py_XDECREF(obj);
870 Py_XDECREF(obj);
869 Py_XDECREF(t);
871 Py_XDECREF(t);
870 return NULL;
872 return NULL;
871 }
873 }
872
874
873 /*
875 /*
874 * When we cache a list, we want to be sure the caller can't mutate
876 * When we cache a list, we want to be sure the caller can't mutate
875 * the cached copy.
877 * the cached copy.
876 */
878 */
877 static PyObject *list_copy(PyObject *list)
879 static PyObject *list_copy(PyObject *list)
878 {
880 {
879 Py_ssize_t len = PyList_GET_SIZE(list);
881 Py_ssize_t len = PyList_GET_SIZE(list);
880 PyObject *newlist = PyList_New(len);
882 PyObject *newlist = PyList_New(len);
881 Py_ssize_t i;
883 Py_ssize_t i;
882
884
883 if (newlist == NULL)
885 if (newlist == NULL)
884 return NULL;
886 return NULL;
885
887
886 for (i = 0; i < len; i++) {
888 for (i = 0; i < len; i++) {
887 PyObject *obj = PyList_GET_ITEM(list, i);
889 PyObject *obj = PyList_GET_ITEM(list, i);
888 Py_INCREF(obj);
890 Py_INCREF(obj);
889 PyList_SET_ITEM(newlist, i, obj);
891 PyList_SET_ITEM(newlist, i, obj);
890 }
892 }
891
893
892 return newlist;
894 return newlist;
893 }
895 }
894
896
895 /* arg should be Py_ssize_t but Python 2.4 do not support the n format */
897 /* arg should be Py_ssize_t but Python 2.4 do not support the n format */
896 static int check_filter(PyObject *filter, unsigned long arg) {
898 static int check_filter(PyObject *filter, unsigned long arg) {
897 if (filter) {
899 if (filter) {
898 PyObject *arglist, *result;
900 PyObject *arglist, *result;
899 int isfiltered;
901 int isfiltered;
900
902
901 arglist = Py_BuildValue("(k)", arg);
903 arglist = Py_BuildValue("(k)", arg);
902 if (!arglist) {
904 if (!arglist) {
903 return -1;
905 return -1;
904 }
906 }
905
907
906 result = PyEval_CallObject(filter, arglist);
908 result = PyEval_CallObject(filter, arglist);
907 Py_DECREF(arglist);
909 Py_DECREF(arglist);
908 if (!result) {
910 if (!result) {
909 return -1;
911 return -1;
910 }
912 }
911
913
912 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
914 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
913 * same as this function, so we can just return it directly.*/
915 * same as this function, so we can just return it directly.*/
914 isfiltered = PyObject_IsTrue(result);
916 isfiltered = PyObject_IsTrue(result);
915 Py_DECREF(result);
917 Py_DECREF(result);
916 return isfiltered;
918 return isfiltered;
917 } else {
919 } else {
918 return 0;
920 return 0;
919 }
921 }
920 }
922 }
921
923
922 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
924 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
923 Py_ssize_t marker, char *phases)
925 Py_ssize_t marker, char *phases)
924 {
926 {
925 PyObject *iter = NULL;
927 PyObject *iter = NULL;
926 PyObject *iter_item = NULL;
928 PyObject *iter_item = NULL;
927 Py_ssize_t min_idx = index_length(self) + 1;
929 Py_ssize_t min_idx = index_length(self) + 1;
928 long iter_item_long;
930 long iter_item_long;
929
931
930 if (PyList_GET_SIZE(list) != 0) {
932 if (PyList_GET_SIZE(list) != 0) {
931 iter = PyObject_GetIter(list);
933 iter = PyObject_GetIter(list);
932 if (iter == NULL)
934 if (iter == NULL)
933 return -2;
935 return -2;
934 while ((iter_item = PyIter_Next(iter)))
936 while ((iter_item = PyIter_Next(iter)))
935 {
937 {
936 iter_item_long = PyInt_AS_LONG(iter_item);
938 iter_item_long = PyInt_AS_LONG(iter_item);
937 Py_DECREF(iter_item);
939 Py_DECREF(iter_item);
938 if (iter_item_long < min_idx)
940 if (iter_item_long < min_idx)
939 min_idx = iter_item_long;
941 min_idx = iter_item_long;
940 phases[iter_item_long] = marker;
942 phases[iter_item_long] = marker;
941 }
943 }
942 Py_DECREF(iter);
944 Py_DECREF(iter);
943 }
945 }
944
946
945 return min_idx;
947 return min_idx;
946 }
948 }
947
949
948 static inline void set_phase_from_parents(char *phases, int parent_1,
950 static inline void set_phase_from_parents(char *phases, int parent_1,
949 int parent_2, Py_ssize_t i)
951 int parent_2, Py_ssize_t i)
950 {
952 {
951 if (parent_1 >= 0 && phases[parent_1] > phases[i])
953 if (parent_1 >= 0 && phases[parent_1] > phases[i])
952 phases[i] = phases[parent_1];
954 phases[i] = phases[parent_1];
953 if (parent_2 >= 0 && phases[parent_2] > phases[i])
955 if (parent_2 >= 0 && phases[parent_2] > phases[i])
954 phases[i] = phases[parent_2];
956 phases[i] = phases[parent_2];
955 }
957 }
956
958
957 static PyObject *compute_phases(indexObject *self, PyObject *args)
959 static PyObject *compute_phases(indexObject *self, PyObject *args)
958 {
960 {
959 PyObject *roots = Py_None;
961 PyObject *roots = Py_None;
960 PyObject *phaseslist = NULL;
962 PyObject *phaseslist = NULL;
961 PyObject *phaseroots = NULL;
963 PyObject *phaseroots = NULL;
962 PyObject *rev = NULL;
964 PyObject *rev = NULL;
963 PyObject *p1 = NULL;
965 PyObject *p1 = NULL;
964 PyObject *p2 = NULL;
966 PyObject *p2 = NULL;
965 Py_ssize_t addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
967 Py_ssize_t addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
966 Py_ssize_t len = index_length(self) - 1;
968 Py_ssize_t len = index_length(self) - 1;
967 Py_ssize_t numphase = 0;
969 Py_ssize_t numphase = 0;
968 Py_ssize_t minrevallphases = 0;
970 Py_ssize_t minrevallphases = 0;
969 Py_ssize_t minrevphase = 0;
971 Py_ssize_t minrevphase = 0;
970 Py_ssize_t i = 0;
972 Py_ssize_t i = 0;
971 int parent_1, parent_2;
973 int parent_1, parent_2;
972 char *phases = NULL;
974 char *phases = NULL;
973 const char *data;
975 const char *data;
974
976
975 if (!PyArg_ParseTuple(args, "O", &roots))
977 if (!PyArg_ParseTuple(args, "O", &roots))
976 goto release_none;
978 goto release_none;
977 if (roots == NULL || !PyList_Check(roots))
979 if (roots == NULL || !PyList_Check(roots))
978 goto release_none;
980 goto release_none;
979
981
980 phases = calloc(len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
982 phases = calloc(len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
981 if (phases == NULL)
983 if (phases == NULL)
982 goto release_none;
984 goto release_none;
983 /* Put the phase information of all the roots in phases */
985 /* Put the phase information of all the roots in phases */
984 numphase = PyList_GET_SIZE(roots)+1;
986 numphase = PyList_GET_SIZE(roots)+1;
985 minrevallphases = len + 1;
987 minrevallphases = len + 1;
986 for (i = 0; i < numphase-1; i++) {
988 for (i = 0; i < numphase-1; i++) {
987 phaseroots = PyList_GET_ITEM(roots, i);
989 phaseroots = PyList_GET_ITEM(roots, i);
988 if (!PyList_Check(phaseroots))
990 if (!PyList_Check(phaseroots))
989 goto release_phases;
991 goto release_phases;
990 minrevphase = add_roots_get_min(self, phaseroots, i+1, phases);
992 minrevphase = add_roots_get_min(self, phaseroots, i+1, phases);
991 if (minrevphase == -2) /* Error from add_roots_get_min */
993 if (minrevphase == -2) /* Error from add_roots_get_min */
992 goto release_phases;
994 goto release_phases;
993 minrevallphases = MIN(minrevallphases, minrevphase);
995 minrevallphases = MIN(minrevallphases, minrevphase);
994 }
996 }
995 /* Propagate the phase information from the roots to the revs */
997 /* Propagate the phase information from the roots to the revs */
996 if (minrevallphases != -1) {
998 if (minrevallphases != -1) {
997 for (i = minrevallphases; i < self->raw_length; i++) {
999 for (i = minrevallphases; i < self->raw_length; i++) {
998 data = index_deref(self, i);
1000 data = index_deref(self, i);
999 set_phase_from_parents(phases, getbe32(data+24), getbe32(data+28), i);
1001 set_phase_from_parents(phases, getbe32(data+24), getbe32(data+28), i);
1000 }
1002 }
1001 for (i = 0; i < addlen; i++) {
1003 for (i = 0; i < addlen; i++) {
1002 rev = PyList_GET_ITEM(self->added, i);
1004 rev = PyList_GET_ITEM(self->added, i);
1003 p1 = PyTuple_GET_ITEM(rev, 5);
1005 p1 = PyTuple_GET_ITEM(rev, 5);
1004 p2 = PyTuple_GET_ITEM(rev, 6);
1006 p2 = PyTuple_GET_ITEM(rev, 6);
1005 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1007 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1006 PyErr_SetString(PyExc_TypeError, "revlog parents are invalid");
1008 PyErr_SetString(PyExc_TypeError, "revlog parents are invalid");
1007 goto release_phases;
1009 goto release_phases;
1008 }
1010 }
1009 parent_1 = (int)PyInt_AS_LONG(p1);
1011 parent_1 = (int)PyInt_AS_LONG(p1);
1010 parent_2 = (int)PyInt_AS_LONG(p2);
1012 parent_2 = (int)PyInt_AS_LONG(p2);
1011 set_phase_from_parents(phases, parent_1, parent_2, i+self->raw_length);
1013 set_phase_from_parents(phases, parent_1, parent_2, i+self->raw_length);
1012 }
1014 }
1013 }
1015 }
1014 /* Transform phase list to a python list */
1016 /* Transform phase list to a python list */
1015 phaseslist = PyList_New(len);
1017 phaseslist = PyList_New(len);
1016 if (phaseslist == NULL)
1018 if (phaseslist == NULL)
1017 goto release_phases;
1019 goto release_phases;
1018 for (i = 0; i < len; i++)
1020 for (i = 0; i < len; i++)
1019 PyList_SET_ITEM(phaseslist, i, PyInt_FromLong(phases[i]));
1021 PyList_SET_ITEM(phaseslist, i, PyInt_FromLong(phases[i]));
1020
1022
1021 release_phases:
1023 release_phases:
1022 free(phases);
1024 free(phases);
1023 release_none:
1025 release_none:
1024 return phaseslist;
1026 return phaseslist;
1025 }
1027 }
1026
1028
1027 static PyObject *index_headrevs(indexObject *self, PyObject *args)
1029 static PyObject *index_headrevs(indexObject *self, PyObject *args)
1028 {
1030 {
1029 Py_ssize_t i, len, addlen;
1031 Py_ssize_t i, len, addlen;
1030 char *nothead = NULL;
1032 char *nothead = NULL;
1031 PyObject *heads = NULL;
1033 PyObject *heads = NULL;
1032 PyObject *filter = NULL;
1034 PyObject *filter = NULL;
1033 PyObject *filteredrevs = Py_None;
1035 PyObject *filteredrevs = Py_None;
1034
1036
1035 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
1037 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
1036 return NULL;
1038 return NULL;
1037 }
1039 }
1038
1040
1039 if (self->headrevs && filteredrevs == self->filteredrevs)
1041 if (self->headrevs && filteredrevs == self->filteredrevs)
1040 return list_copy(self->headrevs);
1042 return list_copy(self->headrevs);
1041
1043
1042 Py_DECREF(self->filteredrevs);
1044 Py_DECREF(self->filteredrevs);
1043 self->filteredrevs = filteredrevs;
1045 self->filteredrevs = filteredrevs;
1044 Py_INCREF(filteredrevs);
1046 Py_INCREF(filteredrevs);
1045
1047
1046 if (filteredrevs != Py_None) {
1048 if (filteredrevs != Py_None) {
1047 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
1049 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
1048 if (!filter) {
1050 if (!filter) {
1049 PyErr_SetString(PyExc_TypeError,
1051 PyErr_SetString(PyExc_TypeError,
1050 "filteredrevs has no attribute __contains__");
1052 "filteredrevs has no attribute __contains__");
1051 goto bail;
1053 goto bail;
1052 }
1054 }
1053 }
1055 }
1054
1056
1055 len = index_length(self) - 1;
1057 len = index_length(self) - 1;
1056 heads = PyList_New(0);
1058 heads = PyList_New(0);
1057 if (heads == NULL)
1059 if (heads == NULL)
1058 goto bail;
1060 goto bail;
1059 if (len == 0) {
1061 if (len == 0) {
1060 PyObject *nullid = PyInt_FromLong(-1);
1062 PyObject *nullid = PyInt_FromLong(-1);
1061 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
1063 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
1062 Py_XDECREF(nullid);
1064 Py_XDECREF(nullid);
1063 goto bail;
1065 goto bail;
1064 }
1066 }
1065 goto done;
1067 goto done;
1066 }
1068 }
1067
1069
1068 nothead = calloc(len, 1);
1070 nothead = calloc(len, 1);
1069 if (nothead == NULL)
1071 if (nothead == NULL)
1070 goto bail;
1072 goto bail;
1071
1073
1072 for (i = 0; i < self->raw_length; i++) {
1074 for (i = 0; i < self->raw_length; i++) {
1073 const char *data;
1075 const char *data;
1074 int parent_1, parent_2, isfiltered;
1076 int parent_1, parent_2, isfiltered;
1075
1077
1076 isfiltered = check_filter(filter, i);
1078 isfiltered = check_filter(filter, i);
1077 if (isfiltered == -1) {
1079 if (isfiltered == -1) {
1078 PyErr_SetString(PyExc_TypeError,
1080 PyErr_SetString(PyExc_TypeError,
1079 "unable to check filter");
1081 "unable to check filter");
1080 goto bail;
1082 goto bail;
1081 }
1083 }
1082
1084
1083 if (isfiltered) {
1085 if (isfiltered) {
1084 nothead[i] = 1;
1086 nothead[i] = 1;
1085 continue;
1087 continue;
1086 }
1088 }
1087
1089
1088 data = index_deref(self, i);
1090 data = index_deref(self, i);
1089 parent_1 = getbe32(data + 24);
1091 parent_1 = getbe32(data + 24);
1090 parent_2 = getbe32(data + 28);
1092 parent_2 = getbe32(data + 28);
1091
1093
1092 if (parent_1 >= 0)
1094 if (parent_1 >= 0)
1093 nothead[parent_1] = 1;
1095 nothead[parent_1] = 1;
1094 if (parent_2 >= 0)
1096 if (parent_2 >= 0)
1095 nothead[parent_2] = 1;
1097 nothead[parent_2] = 1;
1096 }
1098 }
1097
1099
1098 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
1100 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
1099
1101
1100 for (i = 0; i < addlen; i++) {
1102 for (i = 0; i < addlen; i++) {
1101 PyObject *rev = PyList_GET_ITEM(self->added, i);
1103 PyObject *rev = PyList_GET_ITEM(self->added, i);
1102 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
1104 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
1103 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
1105 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
1104 long parent_1, parent_2;
1106 long parent_1, parent_2;
1105 int isfiltered;
1107 int isfiltered;
1106
1108
1107 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1109 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1108 PyErr_SetString(PyExc_TypeError,
1110 PyErr_SetString(PyExc_TypeError,
1109 "revlog parents are invalid");
1111 "revlog parents are invalid");
1110 goto bail;
1112 goto bail;
1111 }
1113 }
1112
1114
1113 isfiltered = check_filter(filter, i);
1115 isfiltered = check_filter(filter, i);
1114 if (isfiltered == -1) {
1116 if (isfiltered == -1) {
1115 PyErr_SetString(PyExc_TypeError,
1117 PyErr_SetString(PyExc_TypeError,
1116 "unable to check filter");
1118 "unable to check filter");
1117 goto bail;
1119 goto bail;
1118 }
1120 }
1119
1121
1120 if (isfiltered) {
1122 if (isfiltered) {
1121 nothead[i] = 1;
1123 nothead[i] = 1;
1122 continue;
1124 continue;
1123 }
1125 }
1124
1126
1125 parent_1 = PyInt_AS_LONG(p1);
1127 parent_1 = PyInt_AS_LONG(p1);
1126 parent_2 = PyInt_AS_LONG(p2);
1128 parent_2 = PyInt_AS_LONG(p2);
1127 if (parent_1 >= 0)
1129 if (parent_1 >= 0)
1128 nothead[parent_1] = 1;
1130 nothead[parent_1] = 1;
1129 if (parent_2 >= 0)
1131 if (parent_2 >= 0)
1130 nothead[parent_2] = 1;
1132 nothead[parent_2] = 1;
1131 }
1133 }
1132
1134
1133 for (i = 0; i < len; i++) {
1135 for (i = 0; i < len; i++) {
1134 PyObject *head;
1136 PyObject *head;
1135
1137
1136 if (nothead[i])
1138 if (nothead[i])
1137 continue;
1139 continue;
1138 head = PyInt_FromSsize_t(i);
1140 head = PyInt_FromSsize_t(i);
1139 if (head == NULL || PyList_Append(heads, head) == -1) {
1141 if (head == NULL || PyList_Append(heads, head) == -1) {
1140 Py_XDECREF(head);
1142 Py_XDECREF(head);
1141 goto bail;
1143 goto bail;
1142 }
1144 }
1143 }
1145 }
1144
1146
1145 done:
1147 done:
1146 self->headrevs = heads;
1148 self->headrevs = heads;
1147 Py_XDECREF(filter);
1149 Py_XDECREF(filter);
1148 free(nothead);
1150 free(nothead);
1149 return list_copy(self->headrevs);
1151 return list_copy(self->headrevs);
1150 bail:
1152 bail:
1151 Py_XDECREF(filter);
1153 Py_XDECREF(filter);
1152 Py_XDECREF(heads);
1154 Py_XDECREF(heads);
1153 free(nothead);
1155 free(nothead);
1154 return NULL;
1156 return NULL;
1155 }
1157 }
1156
1158
1157 static inline int nt_level(const char *node, Py_ssize_t level)
1159 static inline int nt_level(const char *node, Py_ssize_t level)
1158 {
1160 {
1159 int v = node[level>>1];
1161 int v = node[level>>1];
1160 if (!(level & 1))
1162 if (!(level & 1))
1161 v >>= 4;
1163 v >>= 4;
1162 return v & 0xf;
1164 return v & 0xf;
1163 }
1165 }
1164
1166
1165 /*
1167 /*
1166 * Return values:
1168 * Return values:
1167 *
1169 *
1168 * -4: match is ambiguous (multiple candidates)
1170 * -4: match is ambiguous (multiple candidates)
1169 * -2: not found
1171 * -2: not found
1170 * rest: valid rev
1172 * rest: valid rev
1171 */
1173 */
1172 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
1174 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
1173 int hex)
1175 int hex)
1174 {
1176 {
1175 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1177 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1176 int level, maxlevel, off;
1178 int level, maxlevel, off;
1177
1179
1178 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1180 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1179 return -1;
1181 return -1;
1180
1182
1181 if (self->nt == NULL)
1183 if (self->nt == NULL)
1182 return -2;
1184 return -2;
1183
1185
1184 if (hex)
1186 if (hex)
1185 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1187 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1186 else
1188 else
1187 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1189 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1188
1190
1189 for (level = off = 0; level < maxlevel; level++) {
1191 for (level = off = 0; level < maxlevel; level++) {
1190 int k = getnybble(node, level);
1192 int k = getnybble(node, level);
1191 nodetree *n = &self->nt[off];
1193 nodetree *n = &self->nt[off];
1192 int v = n->children[k];
1194 int v = n->children[k];
1193
1195
1194 if (v < 0) {
1196 if (v < 0) {
1195 const char *n;
1197 const char *n;
1196 Py_ssize_t i;
1198 Py_ssize_t i;
1197
1199
1198 v = -v - 1;
1200 v = -v - 1;
1199 n = index_node(self, v);
1201 n = index_node(self, v);
1200 if (n == NULL)
1202 if (n == NULL)
1201 return -2;
1203 return -2;
1202 for (i = level; i < maxlevel; i++)
1204 for (i = level; i < maxlevel; i++)
1203 if (getnybble(node, i) != nt_level(n, i))
1205 if (getnybble(node, i) != nt_level(n, i))
1204 return -2;
1206 return -2;
1205 return v;
1207 return v;
1206 }
1208 }
1207 if (v == 0)
1209 if (v == 0)
1208 return -2;
1210 return -2;
1209 off = v;
1211 off = v;
1210 }
1212 }
1211 /* multiple matches against an ambiguous prefix */
1213 /* multiple matches against an ambiguous prefix */
1212 return -4;
1214 return -4;
1213 }
1215 }
1214
1216
1215 static int nt_new(indexObject *self)
1217 static int nt_new(indexObject *self)
1216 {
1218 {
1217 if (self->ntlength == self->ntcapacity) {
1219 if (self->ntlength == self->ntcapacity) {
1218 self->ntcapacity *= 2;
1220 self->ntcapacity *= 2;
1219 self->nt = realloc(self->nt,
1221 self->nt = realloc(self->nt,
1220 self->ntcapacity * sizeof(nodetree));
1222 self->ntcapacity * sizeof(nodetree));
1221 if (self->nt == NULL) {
1223 if (self->nt == NULL) {
1222 PyErr_SetString(PyExc_MemoryError, "out of memory");
1224 PyErr_SetString(PyExc_MemoryError, "out of memory");
1223 return -1;
1225 return -1;
1224 }
1226 }
1225 memset(&self->nt[self->ntlength], 0,
1227 memset(&self->nt[self->ntlength], 0,
1226 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
1228 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
1227 }
1229 }
1228 return self->ntlength++;
1230 return self->ntlength++;
1229 }
1231 }
1230
1232
1231 static int nt_insert(indexObject *self, const char *node, int rev)
1233 static int nt_insert(indexObject *self, const char *node, int rev)
1232 {
1234 {
1233 int level = 0;
1235 int level = 0;
1234 int off = 0;
1236 int off = 0;
1235
1237
1236 while (level < 40) {
1238 while (level < 40) {
1237 int k = nt_level(node, level);
1239 int k = nt_level(node, level);
1238 nodetree *n;
1240 nodetree *n;
1239 int v;
1241 int v;
1240
1242
1241 n = &self->nt[off];
1243 n = &self->nt[off];
1242 v = n->children[k];
1244 v = n->children[k];
1243
1245
1244 if (v == 0) {
1246 if (v == 0) {
1245 n->children[k] = -rev - 1;
1247 n->children[k] = -rev - 1;
1246 return 0;
1248 return 0;
1247 }
1249 }
1248 if (v < 0) {
1250 if (v < 0) {
1249 const char *oldnode = index_node(self, -v - 1);
1251 const char *oldnode = index_node(self, -v - 1);
1250 int noff;
1252 int noff;
1251
1253
1252 if (!oldnode || !memcmp(oldnode, node, 20)) {
1254 if (!oldnode || !memcmp(oldnode, node, 20)) {
1253 n->children[k] = -rev - 1;
1255 n->children[k] = -rev - 1;
1254 return 0;
1256 return 0;
1255 }
1257 }
1256 noff = nt_new(self);
1258 noff = nt_new(self);
1257 if (noff == -1)
1259 if (noff == -1)
1258 return -1;
1260 return -1;
1259 /* self->nt may have been changed by realloc */
1261 /* self->nt may have been changed by realloc */
1260 self->nt[off].children[k] = noff;
1262 self->nt[off].children[k] = noff;
1261 off = noff;
1263 off = noff;
1262 n = &self->nt[off];
1264 n = &self->nt[off];
1263 n->children[nt_level(oldnode, ++level)] = v;
1265 n->children[nt_level(oldnode, ++level)] = v;
1264 if (level > self->ntdepth)
1266 if (level > self->ntdepth)
1265 self->ntdepth = level;
1267 self->ntdepth = level;
1266 self->ntsplits += 1;
1268 self->ntsplits += 1;
1267 } else {
1269 } else {
1268 level += 1;
1270 level += 1;
1269 off = v;
1271 off = v;
1270 }
1272 }
1271 }
1273 }
1272
1274
1273 return -1;
1275 return -1;
1274 }
1276 }
1275
1277
1276 static int nt_init(indexObject *self)
1278 static int nt_init(indexObject *self)
1277 {
1279 {
1278 if (self->nt == NULL) {
1280 if (self->nt == NULL) {
1279 if (self->raw_length > INT_MAX) {
1281 if (self->raw_length > INT_MAX) {
1280 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1282 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1281 return -1;
1283 return -1;
1282 }
1284 }
1283 self->ntcapacity = self->raw_length < 4
1285 self->ntcapacity = self->raw_length < 4
1284 ? 4 : (int)self->raw_length / 2;
1286 ? 4 : (int)self->raw_length / 2;
1285
1287
1286 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1288 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1287 if (self->nt == NULL) {
1289 if (self->nt == NULL) {
1288 PyErr_NoMemory();
1290 PyErr_NoMemory();
1289 return -1;
1291 return -1;
1290 }
1292 }
1291 self->ntlength = 1;
1293 self->ntlength = 1;
1292 self->ntrev = (int)index_length(self) - 1;
1294 self->ntrev = (int)index_length(self) - 1;
1293 self->ntlookups = 1;
1295 self->ntlookups = 1;
1294 self->ntmisses = 0;
1296 self->ntmisses = 0;
1295 if (nt_insert(self, nullid, INT_MAX) == -1)
1297 if (nt_insert(self, nullid, INT_MAX) == -1)
1296 return -1;
1298 return -1;
1297 }
1299 }
1298 return 0;
1300 return 0;
1299 }
1301 }
1300
1302
1301 /*
1303 /*
1302 * Return values:
1304 * Return values:
1303 *
1305 *
1304 * -3: error (exception set)
1306 * -3: error (exception set)
1305 * -2: not found (no exception set)
1307 * -2: not found (no exception set)
1306 * rest: valid rev
1308 * rest: valid rev
1307 */
1309 */
1308 static int index_find_node(indexObject *self,
1310 static int index_find_node(indexObject *self,
1309 const char *node, Py_ssize_t nodelen)
1311 const char *node, Py_ssize_t nodelen)
1310 {
1312 {
1311 int rev;
1313 int rev;
1312
1314
1313 self->ntlookups++;
1315 self->ntlookups++;
1314 rev = nt_find(self, node, nodelen, 0);
1316 rev = nt_find(self, node, nodelen, 0);
1315 if (rev >= -1)
1317 if (rev >= -1)
1316 return rev;
1318 return rev;
1317
1319
1318 if (nt_init(self) == -1)
1320 if (nt_init(self) == -1)
1319 return -3;
1321 return -3;
1320
1322
1321 /*
1323 /*
1322 * For the first handful of lookups, we scan the entire index,
1324 * For the first handful of lookups, we scan the entire index,
1323 * and cache only the matching nodes. This optimizes for cases
1325 * and cache only the matching nodes. This optimizes for cases
1324 * like "hg tip", where only a few nodes are accessed.
1326 * like "hg tip", where only a few nodes are accessed.
1325 *
1327 *
1326 * After that, we cache every node we visit, using a single
1328 * After that, we cache every node we visit, using a single
1327 * scan amortized over multiple lookups. This gives the best
1329 * scan amortized over multiple lookups. This gives the best
1328 * bulk performance, e.g. for "hg log".
1330 * bulk performance, e.g. for "hg log".
1329 */
1331 */
1330 if (self->ntmisses++ < 4) {
1332 if (self->ntmisses++ < 4) {
1331 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1333 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1332 const char *n = index_node(self, rev);
1334 const char *n = index_node(self, rev);
1333 if (n == NULL)
1335 if (n == NULL)
1334 return -2;
1336 return -2;
1335 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1337 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1336 if (nt_insert(self, n, rev) == -1)
1338 if (nt_insert(self, n, rev) == -1)
1337 return -3;
1339 return -3;
1338 break;
1340 break;
1339 }
1341 }
1340 }
1342 }
1341 } else {
1343 } else {
1342 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1344 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1343 const char *n = index_node(self, rev);
1345 const char *n = index_node(self, rev);
1344 if (n == NULL) {
1346 if (n == NULL) {
1345 self->ntrev = rev + 1;
1347 self->ntrev = rev + 1;
1346 return -2;
1348 return -2;
1347 }
1349 }
1348 if (nt_insert(self, n, rev) == -1) {
1350 if (nt_insert(self, n, rev) == -1) {
1349 self->ntrev = rev + 1;
1351 self->ntrev = rev + 1;
1350 return -3;
1352 return -3;
1351 }
1353 }
1352 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1354 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1353 break;
1355 break;
1354 }
1356 }
1355 }
1357 }
1356 self->ntrev = rev;
1358 self->ntrev = rev;
1357 }
1359 }
1358
1360
1359 if (rev >= 0)
1361 if (rev >= 0)
1360 return rev;
1362 return rev;
1361 return -2;
1363 return -2;
1362 }
1364 }
1363
1365
1364 static PyObject *raise_revlog_error(void)
1366 static PyObject *raise_revlog_error(void)
1365 {
1367 {
1366 static PyObject *errclass;
1368 static PyObject *errclass;
1367 PyObject *mod = NULL, *errobj;
1369 PyObject *mod = NULL, *errobj;
1368
1370
1369 if (errclass == NULL) {
1371 if (errclass == NULL) {
1370 PyObject *dict;
1372 PyObject *dict;
1371
1373
1372 mod = PyImport_ImportModule("mercurial.error");
1374 mod = PyImport_ImportModule("mercurial.error");
1373 if (mod == NULL)
1375 if (mod == NULL)
1374 goto classfail;
1376 goto classfail;
1375
1377
1376 dict = PyModule_GetDict(mod);
1378 dict = PyModule_GetDict(mod);
1377 if (dict == NULL)
1379 if (dict == NULL)
1378 goto classfail;
1380 goto classfail;
1379
1381
1380 errclass = PyDict_GetItemString(dict, "RevlogError");
1382 errclass = PyDict_GetItemString(dict, "RevlogError");
1381 if (errclass == NULL) {
1383 if (errclass == NULL) {
1382 PyErr_SetString(PyExc_SystemError,
1384 PyErr_SetString(PyExc_SystemError,
1383 "could not find RevlogError");
1385 "could not find RevlogError");
1384 goto classfail;
1386 goto classfail;
1385 }
1387 }
1386 Py_INCREF(errclass);
1388 Py_INCREF(errclass);
1387 Py_DECREF(mod);
1389 Py_DECREF(mod);
1388 }
1390 }
1389
1391
1390 errobj = PyObject_CallFunction(errclass, NULL);
1392 errobj = PyObject_CallFunction(errclass, NULL);
1391 if (errobj == NULL)
1393 if (errobj == NULL)
1392 return NULL;
1394 return NULL;
1393 PyErr_SetObject(errclass, errobj);
1395 PyErr_SetObject(errclass, errobj);
1394 return errobj;
1396 return errobj;
1395
1397
1396 classfail:
1398 classfail:
1397 Py_XDECREF(mod);
1399 Py_XDECREF(mod);
1398 return NULL;
1400 return NULL;
1399 }
1401 }
1400
1402
1401 static PyObject *index_getitem(indexObject *self, PyObject *value)
1403 static PyObject *index_getitem(indexObject *self, PyObject *value)
1402 {
1404 {
1403 char *node;
1405 char *node;
1404 Py_ssize_t nodelen;
1406 Py_ssize_t nodelen;
1405 int rev;
1407 int rev;
1406
1408
1407 if (PyInt_Check(value))
1409 if (PyInt_Check(value))
1408 return index_get(self, PyInt_AS_LONG(value));
1410 return index_get(self, PyInt_AS_LONG(value));
1409
1411
1410 if (node_check(value, &node, &nodelen) == -1)
1412 if (node_check(value, &node, &nodelen) == -1)
1411 return NULL;
1413 return NULL;
1412 rev = index_find_node(self, node, nodelen);
1414 rev = index_find_node(self, node, nodelen);
1413 if (rev >= -1)
1415 if (rev >= -1)
1414 return PyInt_FromLong(rev);
1416 return PyInt_FromLong(rev);
1415 if (rev == -2)
1417 if (rev == -2)
1416 raise_revlog_error();
1418 raise_revlog_error();
1417 return NULL;
1419 return NULL;
1418 }
1420 }
1419
1421
1420 static int nt_partialmatch(indexObject *self, const char *node,
1422 static int nt_partialmatch(indexObject *self, const char *node,
1421 Py_ssize_t nodelen)
1423 Py_ssize_t nodelen)
1422 {
1424 {
1423 int rev;
1425 int rev;
1424
1426
1425 if (nt_init(self) == -1)
1427 if (nt_init(self) == -1)
1426 return -3;
1428 return -3;
1427
1429
1428 if (self->ntrev > 0) {
1430 if (self->ntrev > 0) {
1429 /* ensure that the radix tree is fully populated */
1431 /* ensure that the radix tree is fully populated */
1430 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1432 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1431 const char *n = index_node(self, rev);
1433 const char *n = index_node(self, rev);
1432 if (n == NULL)
1434 if (n == NULL)
1433 return -2;
1435 return -2;
1434 if (nt_insert(self, n, rev) == -1)
1436 if (nt_insert(self, n, rev) == -1)
1435 return -3;
1437 return -3;
1436 }
1438 }
1437 self->ntrev = rev;
1439 self->ntrev = rev;
1438 }
1440 }
1439
1441
1440 return nt_find(self, node, nodelen, 1);
1442 return nt_find(self, node, nodelen, 1);
1441 }
1443 }
1442
1444
1443 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1445 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1444 {
1446 {
1445 const char *fullnode;
1447 const char *fullnode;
1446 int nodelen;
1448 int nodelen;
1447 char *node;
1449 char *node;
1448 int rev, i;
1450 int rev, i;
1449
1451
1450 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1452 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1451 return NULL;
1453 return NULL;
1452
1454
1453 if (nodelen < 4) {
1455 if (nodelen < 4) {
1454 PyErr_SetString(PyExc_ValueError, "key too short");
1456 PyErr_SetString(PyExc_ValueError, "key too short");
1455 return NULL;
1457 return NULL;
1456 }
1458 }
1457
1459
1458 if (nodelen > 40) {
1460 if (nodelen > 40) {
1459 PyErr_SetString(PyExc_ValueError, "key too long");
1461 PyErr_SetString(PyExc_ValueError, "key too long");
1460 return NULL;
1462 return NULL;
1461 }
1463 }
1462
1464
1463 for (i = 0; i < nodelen; i++)
1465 for (i = 0; i < nodelen; i++)
1464 hexdigit(node, i);
1466 hexdigit(node, i);
1465 if (PyErr_Occurred()) {
1467 if (PyErr_Occurred()) {
1466 /* input contains non-hex characters */
1468 /* input contains non-hex characters */
1467 PyErr_Clear();
1469 PyErr_Clear();
1468 Py_RETURN_NONE;
1470 Py_RETURN_NONE;
1469 }
1471 }
1470
1472
1471 rev = nt_partialmatch(self, node, nodelen);
1473 rev = nt_partialmatch(self, node, nodelen);
1472
1474
1473 switch (rev) {
1475 switch (rev) {
1474 case -4:
1476 case -4:
1475 raise_revlog_error();
1477 raise_revlog_error();
1476 case -3:
1478 case -3:
1477 return NULL;
1479 return NULL;
1478 case -2:
1480 case -2:
1479 Py_RETURN_NONE;
1481 Py_RETURN_NONE;
1480 case -1:
1482 case -1:
1481 return PyString_FromStringAndSize(nullid, 20);
1483 return PyString_FromStringAndSize(nullid, 20);
1482 }
1484 }
1483
1485
1484 fullnode = index_node(self, rev);
1486 fullnode = index_node(self, rev);
1485 if (fullnode == NULL) {
1487 if (fullnode == NULL) {
1486 PyErr_Format(PyExc_IndexError,
1488 PyErr_Format(PyExc_IndexError,
1487 "could not access rev %d", rev);
1489 "could not access rev %d", rev);
1488 return NULL;
1490 return NULL;
1489 }
1491 }
1490 return PyString_FromStringAndSize(fullnode, 20);
1492 return PyString_FromStringAndSize(fullnode, 20);
1491 }
1493 }
1492
1494
1493 static PyObject *index_m_get(indexObject *self, PyObject *args)
1495 static PyObject *index_m_get(indexObject *self, PyObject *args)
1494 {
1496 {
1495 Py_ssize_t nodelen;
1497 Py_ssize_t nodelen;
1496 PyObject *val;
1498 PyObject *val;
1497 char *node;
1499 char *node;
1498 int rev;
1500 int rev;
1499
1501
1500 if (!PyArg_ParseTuple(args, "O", &val))
1502 if (!PyArg_ParseTuple(args, "O", &val))
1501 return NULL;
1503 return NULL;
1502 if (node_check(val, &node, &nodelen) == -1)
1504 if (node_check(val, &node, &nodelen) == -1)
1503 return NULL;
1505 return NULL;
1504 rev = index_find_node(self, node, nodelen);
1506 rev = index_find_node(self, node, nodelen);
1505 if (rev == -3)
1507 if (rev == -3)
1506 return NULL;
1508 return NULL;
1507 if (rev == -2)
1509 if (rev == -2)
1508 Py_RETURN_NONE;
1510 Py_RETURN_NONE;
1509 return PyInt_FromLong(rev);
1511 return PyInt_FromLong(rev);
1510 }
1512 }
1511
1513
1512 static int index_contains(indexObject *self, PyObject *value)
1514 static int index_contains(indexObject *self, PyObject *value)
1513 {
1515 {
1514 char *node;
1516 char *node;
1515 Py_ssize_t nodelen;
1517 Py_ssize_t nodelen;
1516
1518
1517 if (PyInt_Check(value)) {
1519 if (PyInt_Check(value)) {
1518 long rev = PyInt_AS_LONG(value);
1520 long rev = PyInt_AS_LONG(value);
1519 return rev >= -1 && rev < index_length(self);
1521 return rev >= -1 && rev < index_length(self);
1520 }
1522 }
1521
1523
1522 if (node_check(value, &node, &nodelen) == -1)
1524 if (node_check(value, &node, &nodelen) == -1)
1523 return -1;
1525 return -1;
1524
1526
1525 switch (index_find_node(self, node, nodelen)) {
1527 switch (index_find_node(self, node, nodelen)) {
1526 case -3:
1528 case -3:
1527 return -1;
1529 return -1;
1528 case -2:
1530 case -2:
1529 return 0;
1531 return 0;
1530 default:
1532 default:
1531 return 1;
1533 return 1;
1532 }
1534 }
1533 }
1535 }
1534
1536
1535 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1537 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1536 {
1538 {
1537 if (rev >= self->length - 1) {
1539 if (rev >= self->length - 1) {
1538 PyObject *tuple = PyList_GET_ITEM(self->added,
1540 PyObject *tuple = PyList_GET_ITEM(self->added,
1539 rev - self->length + 1);
1541 rev - self->length + 1);
1540 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1542 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1541 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1543 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1542 } else {
1544 } else {
1543 const char *data = index_deref(self, rev);
1545 const char *data = index_deref(self, rev);
1544 ps[0] = getbe32(data + 24);
1546 ps[0] = getbe32(data + 24);
1545 ps[1] = getbe32(data + 28);
1547 ps[1] = getbe32(data + 28);
1546 }
1548 }
1547 }
1549 }
1548
1550
1549 typedef uint64_t bitmask;
1551 typedef uint64_t bitmask;
1550
1552
1551 /*
1553 /*
1552 * Given a disjoint set of revs, return all candidates for the
1554 * Given a disjoint set of revs, return all candidates for the
1553 * greatest common ancestor. In revset notation, this is the set
1555 * greatest common ancestor. In revset notation, this is the set
1554 * "heads(::a and ::b and ...)"
1556 * "heads(::a and ::b and ...)"
1555 */
1557 */
1556 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1558 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1557 int revcount)
1559 int revcount)
1558 {
1560 {
1559 const bitmask allseen = (1ull << revcount) - 1;
1561 const bitmask allseen = (1ull << revcount) - 1;
1560 const bitmask poison = 1ull << revcount;
1562 const bitmask poison = 1ull << revcount;
1561 PyObject *gca = PyList_New(0);
1563 PyObject *gca = PyList_New(0);
1562 int i, v, interesting;
1564 int i, v, interesting;
1563 int maxrev = -1;
1565 int maxrev = -1;
1564 bitmask sp;
1566 bitmask sp;
1565 bitmask *seen;
1567 bitmask *seen;
1566
1568
1567 if (gca == NULL)
1569 if (gca == NULL)
1568 return PyErr_NoMemory();
1570 return PyErr_NoMemory();
1569
1571
1570 for (i = 0; i < revcount; i++) {
1572 for (i = 0; i < revcount; i++) {
1571 if (revs[i] > maxrev)
1573 if (revs[i] > maxrev)
1572 maxrev = revs[i];
1574 maxrev = revs[i];
1573 }
1575 }
1574
1576
1575 seen = calloc(sizeof(*seen), maxrev + 1);
1577 seen = calloc(sizeof(*seen), maxrev + 1);
1576 if (seen == NULL) {
1578 if (seen == NULL) {
1577 Py_DECREF(gca);
1579 Py_DECREF(gca);
1578 return PyErr_NoMemory();
1580 return PyErr_NoMemory();
1579 }
1581 }
1580
1582
1581 for (i = 0; i < revcount; i++)
1583 for (i = 0; i < revcount; i++)
1582 seen[revs[i]] = 1ull << i;
1584 seen[revs[i]] = 1ull << i;
1583
1585
1584 interesting = revcount;
1586 interesting = revcount;
1585
1587
1586 for (v = maxrev; v >= 0 && interesting; v--) {
1588 for (v = maxrev; v >= 0 && interesting; v--) {
1587 bitmask sv = seen[v];
1589 bitmask sv = seen[v];
1588 int parents[2];
1590 int parents[2];
1589
1591
1590 if (!sv)
1592 if (!sv)
1591 continue;
1593 continue;
1592
1594
1593 if (sv < poison) {
1595 if (sv < poison) {
1594 interesting -= 1;
1596 interesting -= 1;
1595 if (sv == allseen) {
1597 if (sv == allseen) {
1596 PyObject *obj = PyInt_FromLong(v);
1598 PyObject *obj = PyInt_FromLong(v);
1597 if (obj == NULL)
1599 if (obj == NULL)
1598 goto bail;
1600 goto bail;
1599 if (PyList_Append(gca, obj) == -1) {
1601 if (PyList_Append(gca, obj) == -1) {
1600 Py_DECREF(obj);
1602 Py_DECREF(obj);
1601 goto bail;
1603 goto bail;
1602 }
1604 }
1603 sv |= poison;
1605 sv |= poison;
1604 for (i = 0; i < revcount; i++) {
1606 for (i = 0; i < revcount; i++) {
1605 if (revs[i] == v)
1607 if (revs[i] == v)
1606 goto done;
1608 goto done;
1607 }
1609 }
1608 }
1610 }
1609 }
1611 }
1610 index_get_parents(self, v, parents);
1612 index_get_parents(self, v, parents);
1611
1613
1612 for (i = 0; i < 2; i++) {
1614 for (i = 0; i < 2; i++) {
1613 int p = parents[i];
1615 int p = parents[i];
1614 if (p == -1)
1616 if (p == -1)
1615 continue;
1617 continue;
1616 sp = seen[p];
1618 sp = seen[p];
1617 if (sv < poison) {
1619 if (sv < poison) {
1618 if (sp == 0) {
1620 if (sp == 0) {
1619 seen[p] = sv;
1621 seen[p] = sv;
1620 interesting++;
1622 interesting++;
1621 }
1623 }
1622 else if (sp != sv)
1624 else if (sp != sv)
1623 seen[p] |= sv;
1625 seen[p] |= sv;
1624 } else {
1626 } else {
1625 if (sp && sp < poison)
1627 if (sp && sp < poison)
1626 interesting--;
1628 interesting--;
1627 seen[p] = sv;
1629 seen[p] = sv;
1628 }
1630 }
1629 }
1631 }
1630 }
1632 }
1631
1633
1632 done:
1634 done:
1633 free(seen);
1635 free(seen);
1634 return gca;
1636 return gca;
1635 bail:
1637 bail:
1636 free(seen);
1638 free(seen);
1637 Py_XDECREF(gca);
1639 Py_XDECREF(gca);
1638 return NULL;
1640 return NULL;
1639 }
1641 }
1640
1642
1641 /*
1643 /*
1642 * Given a disjoint set of revs, return the subset with the longest
1644 * Given a disjoint set of revs, return the subset with the longest
1643 * path to the root.
1645 * path to the root.
1644 */
1646 */
1645 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1647 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1646 {
1648 {
1647 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1649 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1648 static const Py_ssize_t capacity = 24;
1650 static const Py_ssize_t capacity = 24;
1649 int *depth, *interesting = NULL;
1651 int *depth, *interesting = NULL;
1650 int i, j, v, ninteresting;
1652 int i, j, v, ninteresting;
1651 PyObject *dict = NULL, *keys = NULL;
1653 PyObject *dict = NULL, *keys = NULL;
1652 long *seen = NULL;
1654 long *seen = NULL;
1653 int maxrev = -1;
1655 int maxrev = -1;
1654 long final;
1656 long final;
1655
1657
1656 if (revcount > capacity) {
1658 if (revcount > capacity) {
1657 PyErr_Format(PyExc_OverflowError,
1659 PyErr_Format(PyExc_OverflowError,
1658 "bitset size (%ld) > capacity (%ld)",
1660 "bitset size (%ld) > capacity (%ld)",
1659 (long)revcount, (long)capacity);
1661 (long)revcount, (long)capacity);
1660 return NULL;
1662 return NULL;
1661 }
1663 }
1662
1664
1663 for (i = 0; i < revcount; i++) {
1665 for (i = 0; i < revcount; i++) {
1664 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1666 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1665 if (n > maxrev)
1667 if (n > maxrev)
1666 maxrev = n;
1668 maxrev = n;
1667 }
1669 }
1668
1670
1669 depth = calloc(sizeof(*depth), maxrev + 1);
1671 depth = calloc(sizeof(*depth), maxrev + 1);
1670 if (depth == NULL)
1672 if (depth == NULL)
1671 return PyErr_NoMemory();
1673 return PyErr_NoMemory();
1672
1674
1673 seen = calloc(sizeof(*seen), maxrev + 1);
1675 seen = calloc(sizeof(*seen), maxrev + 1);
1674 if (seen == NULL) {
1676 if (seen == NULL) {
1675 PyErr_NoMemory();
1677 PyErr_NoMemory();
1676 goto bail;
1678 goto bail;
1677 }
1679 }
1678
1680
1679 interesting = calloc(sizeof(*interesting), 2 << revcount);
1681 interesting = calloc(sizeof(*interesting), 2 << revcount);
1680 if (interesting == NULL) {
1682 if (interesting == NULL) {
1681 PyErr_NoMemory();
1683 PyErr_NoMemory();
1682 goto bail;
1684 goto bail;
1683 }
1685 }
1684
1686
1685 if (PyList_Sort(revs) == -1)
1687 if (PyList_Sort(revs) == -1)
1686 goto bail;
1688 goto bail;
1687
1689
1688 for (i = 0; i < revcount; i++) {
1690 for (i = 0; i < revcount; i++) {
1689 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1691 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1690 long b = 1l << i;
1692 long b = 1l << i;
1691 depth[n] = 1;
1693 depth[n] = 1;
1692 seen[n] = b;
1694 seen[n] = b;
1693 interesting[b] = 1;
1695 interesting[b] = 1;
1694 }
1696 }
1695
1697
1696 ninteresting = (int)revcount;
1698 ninteresting = (int)revcount;
1697
1699
1698 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1700 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1699 int dv = depth[v];
1701 int dv = depth[v];
1700 int parents[2];
1702 int parents[2];
1701 long sv;
1703 long sv;
1702
1704
1703 if (dv == 0)
1705 if (dv == 0)
1704 continue;
1706 continue;
1705
1707
1706 sv = seen[v];
1708 sv = seen[v];
1707 index_get_parents(self, v, parents);
1709 index_get_parents(self, v, parents);
1708
1710
1709 for (i = 0; i < 2; i++) {
1711 for (i = 0; i < 2; i++) {
1710 int p = parents[i];
1712 int p = parents[i];
1711 long nsp, sp;
1713 long nsp, sp;
1712 int dp;
1714 int dp;
1713
1715
1714 if (p == -1)
1716 if (p == -1)
1715 continue;
1717 continue;
1716
1718
1717 dp = depth[p];
1719 dp = depth[p];
1718 nsp = sp = seen[p];
1720 nsp = sp = seen[p];
1719 if (dp <= dv) {
1721 if (dp <= dv) {
1720 depth[p] = dv + 1;
1722 depth[p] = dv + 1;
1721 if (sp != sv) {
1723 if (sp != sv) {
1722 interesting[sv] += 1;
1724 interesting[sv] += 1;
1723 nsp = seen[p] = sv;
1725 nsp = seen[p] = sv;
1724 if (sp) {
1726 if (sp) {
1725 interesting[sp] -= 1;
1727 interesting[sp] -= 1;
1726 if (interesting[sp] == 0)
1728 if (interesting[sp] == 0)
1727 ninteresting -= 1;
1729 ninteresting -= 1;
1728 }
1730 }
1729 }
1731 }
1730 }
1732 }
1731 else if (dv == dp - 1) {
1733 else if (dv == dp - 1) {
1732 nsp = sp | sv;
1734 nsp = sp | sv;
1733 if (nsp == sp)
1735 if (nsp == sp)
1734 continue;
1736 continue;
1735 seen[p] = nsp;
1737 seen[p] = nsp;
1736 interesting[sp] -= 1;
1738 interesting[sp] -= 1;
1737 if (interesting[sp] == 0 && interesting[nsp] > 0)
1739 if (interesting[sp] == 0 && interesting[nsp] > 0)
1738 ninteresting -= 1;
1740 ninteresting -= 1;
1739 interesting[nsp] += 1;
1741 interesting[nsp] += 1;
1740 }
1742 }
1741 }
1743 }
1742 interesting[sv] -= 1;
1744 interesting[sv] -= 1;
1743 if (interesting[sv] == 0)
1745 if (interesting[sv] == 0)
1744 ninteresting -= 1;
1746 ninteresting -= 1;
1745 }
1747 }
1746
1748
1747 final = 0;
1749 final = 0;
1748 j = ninteresting;
1750 j = ninteresting;
1749 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1751 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1750 if (interesting[i] == 0)
1752 if (interesting[i] == 0)
1751 continue;
1753 continue;
1752 final |= i;
1754 final |= i;
1753 j -= 1;
1755 j -= 1;
1754 }
1756 }
1755 if (final == 0) {
1757 if (final == 0) {
1756 keys = PyList_New(0);
1758 keys = PyList_New(0);
1757 goto bail;
1759 goto bail;
1758 }
1760 }
1759
1761
1760 dict = PyDict_New();
1762 dict = PyDict_New();
1761 if (dict == NULL)
1763 if (dict == NULL)
1762 goto bail;
1764 goto bail;
1763
1765
1764 for (i = 0; i < revcount; i++) {
1766 for (i = 0; i < revcount; i++) {
1765 PyObject *key;
1767 PyObject *key;
1766
1768
1767 if ((final & (1 << i)) == 0)
1769 if ((final & (1 << i)) == 0)
1768 continue;
1770 continue;
1769
1771
1770 key = PyList_GET_ITEM(revs, i);
1772 key = PyList_GET_ITEM(revs, i);
1771 Py_INCREF(key);
1773 Py_INCREF(key);
1772 Py_INCREF(Py_None);
1774 Py_INCREF(Py_None);
1773 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1775 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1774 Py_DECREF(key);
1776 Py_DECREF(key);
1775 Py_DECREF(Py_None);
1777 Py_DECREF(Py_None);
1776 goto bail;
1778 goto bail;
1777 }
1779 }
1778 }
1780 }
1779
1781
1780 keys = PyDict_Keys(dict);
1782 keys = PyDict_Keys(dict);
1781
1783
1782 bail:
1784 bail:
1783 free(depth);
1785 free(depth);
1784 free(seen);
1786 free(seen);
1785 free(interesting);
1787 free(interesting);
1786 Py_XDECREF(dict);
1788 Py_XDECREF(dict);
1787
1789
1788 return keys;
1790 return keys;
1789 }
1791 }
1790
1792
1791 /*
1793 /*
1792 * Given a (possibly overlapping) set of revs, return all the
1794 * Given a (possibly overlapping) set of revs, return all the
1793 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1795 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1794 */
1796 */
1795 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1797 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1796 {
1798 {
1797 PyObject *ret = NULL;
1799 PyObject *ret = NULL;
1798 Py_ssize_t argcount, i, len;
1800 Py_ssize_t argcount, i, len;
1799 bitmask repeat = 0;
1801 bitmask repeat = 0;
1800 int revcount = 0;
1802 int revcount = 0;
1801 int *revs;
1803 int *revs;
1802
1804
1803 argcount = PySequence_Length(args);
1805 argcount = PySequence_Length(args);
1804 revs = malloc(argcount * sizeof(*revs));
1806 revs = malloc(argcount * sizeof(*revs));
1805 if (argcount > 0 && revs == NULL)
1807 if (argcount > 0 && revs == NULL)
1806 return PyErr_NoMemory();
1808 return PyErr_NoMemory();
1807 len = index_length(self) - 1;
1809 len = index_length(self) - 1;
1808
1810
1809 for (i = 0; i < argcount; i++) {
1811 for (i = 0; i < argcount; i++) {
1810 static const int capacity = 24;
1812 static const int capacity = 24;
1811 PyObject *obj = PySequence_GetItem(args, i);
1813 PyObject *obj = PySequence_GetItem(args, i);
1812 bitmask x;
1814 bitmask x;
1813 long val;
1815 long val;
1814
1816
1815 if (!PyInt_Check(obj)) {
1817 if (!PyInt_Check(obj)) {
1816 PyErr_SetString(PyExc_TypeError,
1818 PyErr_SetString(PyExc_TypeError,
1817 "arguments must all be ints");
1819 "arguments must all be ints");
1818 Py_DECREF(obj);
1820 Py_DECREF(obj);
1819 goto bail;
1821 goto bail;
1820 }
1822 }
1821 val = PyInt_AsLong(obj);
1823 val = PyInt_AsLong(obj);
1822 Py_DECREF(obj);
1824 Py_DECREF(obj);
1823 if (val == -1) {
1825 if (val == -1) {
1824 ret = PyList_New(0);
1826 ret = PyList_New(0);
1825 goto done;
1827 goto done;
1826 }
1828 }
1827 if (val < 0 || val >= len) {
1829 if (val < 0 || val >= len) {
1828 PyErr_SetString(PyExc_IndexError,
1830 PyErr_SetString(PyExc_IndexError,
1829 "index out of range");
1831 "index out of range");
1830 goto bail;
1832 goto bail;
1831 }
1833 }
1832 /* this cheesy bloom filter lets us avoid some more
1834 /* this cheesy bloom filter lets us avoid some more
1833 * expensive duplicate checks in the common set-is-disjoint
1835 * expensive duplicate checks in the common set-is-disjoint
1834 * case */
1836 * case */
1835 x = 1ull << (val & 0x3f);
1837 x = 1ull << (val & 0x3f);
1836 if (repeat & x) {
1838 if (repeat & x) {
1837 int k;
1839 int k;
1838 for (k = 0; k < revcount; k++) {
1840 for (k = 0; k < revcount; k++) {
1839 if (val == revs[k])
1841 if (val == revs[k])
1840 goto duplicate;
1842 goto duplicate;
1841 }
1843 }
1842 }
1844 }
1843 else repeat |= x;
1845 else repeat |= x;
1844 if (revcount >= capacity) {
1846 if (revcount >= capacity) {
1845 PyErr_Format(PyExc_OverflowError,
1847 PyErr_Format(PyExc_OverflowError,
1846 "bitset size (%d) > capacity (%d)",
1848 "bitset size (%d) > capacity (%d)",
1847 revcount, capacity);
1849 revcount, capacity);
1848 goto bail;
1850 goto bail;
1849 }
1851 }
1850 revs[revcount++] = (int)val;
1852 revs[revcount++] = (int)val;
1851 duplicate:;
1853 duplicate:;
1852 }
1854 }
1853
1855
1854 if (revcount == 0) {
1856 if (revcount == 0) {
1855 ret = PyList_New(0);
1857 ret = PyList_New(0);
1856 goto done;
1858 goto done;
1857 }
1859 }
1858 if (revcount == 1) {
1860 if (revcount == 1) {
1859 PyObject *obj;
1861 PyObject *obj;
1860 ret = PyList_New(1);
1862 ret = PyList_New(1);
1861 if (ret == NULL)
1863 if (ret == NULL)
1862 goto bail;
1864 goto bail;
1863 obj = PyInt_FromLong(revs[0]);
1865 obj = PyInt_FromLong(revs[0]);
1864 if (obj == NULL)
1866 if (obj == NULL)
1865 goto bail;
1867 goto bail;
1866 PyList_SET_ITEM(ret, 0, obj);
1868 PyList_SET_ITEM(ret, 0, obj);
1867 goto done;
1869 goto done;
1868 }
1870 }
1869
1871
1870 ret = find_gca_candidates(self, revs, revcount);
1872 ret = find_gca_candidates(self, revs, revcount);
1871 if (ret == NULL)
1873 if (ret == NULL)
1872 goto bail;
1874 goto bail;
1873
1875
1874 done:
1876 done:
1875 free(revs);
1877 free(revs);
1876 return ret;
1878 return ret;
1877
1879
1878 bail:
1880 bail:
1879 free(revs);
1881 free(revs);
1880 Py_XDECREF(ret);
1882 Py_XDECREF(ret);
1881 return NULL;
1883 return NULL;
1882 }
1884 }
1883
1885
1884 /*
1886 /*
1885 * Given a (possibly overlapping) set of revs, return the greatest
1887 * Given a (possibly overlapping) set of revs, return the greatest
1886 * common ancestors: those with the longest path to the root.
1888 * common ancestors: those with the longest path to the root.
1887 */
1889 */
1888 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1890 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1889 {
1891 {
1890 PyObject *gca = index_commonancestorsheads(self, args);
1892 PyObject *gca = index_commonancestorsheads(self, args);
1891 if (gca == NULL)
1893 if (gca == NULL)
1892 return NULL;
1894 return NULL;
1893
1895
1894 if (PyList_GET_SIZE(gca) <= 1) {
1896 if (PyList_GET_SIZE(gca) <= 1) {
1895 Py_INCREF(gca);
1897 Py_INCREF(gca);
1896 return gca;
1898 return gca;
1897 }
1899 }
1898
1900
1899 return find_deepest(self, gca);
1901 return find_deepest(self, gca);
1900 }
1902 }
1901
1903
1902 /*
1904 /*
1903 * Invalidate any trie entries introduced by added revs.
1905 * Invalidate any trie entries introduced by added revs.
1904 */
1906 */
1905 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1907 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1906 {
1908 {
1907 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1909 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1908
1910
1909 for (i = start; i < len; i++) {
1911 for (i = start; i < len; i++) {
1910 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1912 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1911 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1913 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1912
1914
1913 nt_insert(self, PyString_AS_STRING(node), -1);
1915 nt_insert(self, PyString_AS_STRING(node), -1);
1914 }
1916 }
1915
1917
1916 if (start == 0)
1918 if (start == 0)
1917 Py_CLEAR(self->added);
1919 Py_CLEAR(self->added);
1918 }
1920 }
1919
1921
1920 /*
1922 /*
1921 * Delete a numeric range of revs, which must be at the end of the
1923 * Delete a numeric range of revs, which must be at the end of the
1922 * range, but exclude the sentinel nullid entry.
1924 * range, but exclude the sentinel nullid entry.
1923 */
1925 */
1924 static int index_slice_del(indexObject *self, PyObject *item)
1926 static int index_slice_del(indexObject *self, PyObject *item)
1925 {
1927 {
1926 Py_ssize_t start, stop, step, slicelength;
1928 Py_ssize_t start, stop, step, slicelength;
1927 Py_ssize_t length = index_length(self);
1929 Py_ssize_t length = index_length(self);
1928 int ret = 0;
1930 int ret = 0;
1929
1931
1930 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1932 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1931 &start, &stop, &step, &slicelength) < 0)
1933 &start, &stop, &step, &slicelength) < 0)
1932 return -1;
1934 return -1;
1933
1935
1934 if (slicelength <= 0)
1936 if (slicelength <= 0)
1935 return 0;
1937 return 0;
1936
1938
1937 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1939 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1938 stop = start;
1940 stop = start;
1939
1941
1940 if (step < 0) {
1942 if (step < 0) {
1941 stop = start + 1;
1943 stop = start + 1;
1942 start = stop + step*(slicelength - 1) - 1;
1944 start = stop + step*(slicelength - 1) - 1;
1943 step = -step;
1945 step = -step;
1944 }
1946 }
1945
1947
1946 if (step != 1) {
1948 if (step != 1) {
1947 PyErr_SetString(PyExc_ValueError,
1949 PyErr_SetString(PyExc_ValueError,
1948 "revlog index delete requires step size of 1");
1950 "revlog index delete requires step size of 1");
1949 return -1;
1951 return -1;
1950 }
1952 }
1951
1953
1952 if (stop != length - 1) {
1954 if (stop != length - 1) {
1953 PyErr_SetString(PyExc_IndexError,
1955 PyErr_SetString(PyExc_IndexError,
1954 "revlog index deletion indices are invalid");
1956 "revlog index deletion indices are invalid");
1955 return -1;
1957 return -1;
1956 }
1958 }
1957
1959
1958 if (start < self->length - 1) {
1960 if (start < self->length - 1) {
1959 if (self->nt) {
1961 if (self->nt) {
1960 Py_ssize_t i;
1962 Py_ssize_t i;
1961
1963
1962 for (i = start + 1; i < self->length - 1; i++) {
1964 for (i = start + 1; i < self->length - 1; i++) {
1963 const char *node = index_node(self, i);
1965 const char *node = index_node(self, i);
1964
1966
1965 if (node)
1967 if (node)
1966 nt_insert(self, node, -1);
1968 nt_insert(self, node, -1);
1967 }
1969 }
1968 if (self->added)
1970 if (self->added)
1969 nt_invalidate_added(self, 0);
1971 nt_invalidate_added(self, 0);
1970 if (self->ntrev > start)
1972 if (self->ntrev > start)
1971 self->ntrev = (int)start;
1973 self->ntrev = (int)start;
1972 }
1974 }
1973 self->length = start + 1;
1975 self->length = start + 1;
1974 if (start < self->raw_length) {
1976 if (start < self->raw_length) {
1975 if (self->cache) {
1977 if (self->cache) {
1976 Py_ssize_t i;
1978 Py_ssize_t i;
1977 for (i = start; i < self->raw_length; i++)
1979 for (i = start; i < self->raw_length; i++)
1978 Py_CLEAR(self->cache[i]);
1980 Py_CLEAR(self->cache[i]);
1979 }
1981 }
1980 self->raw_length = start;
1982 self->raw_length = start;
1981 }
1983 }
1982 goto done;
1984 goto done;
1983 }
1985 }
1984
1986
1985 if (self->nt) {
1987 if (self->nt) {
1986 nt_invalidate_added(self, start - self->length + 1);
1988 nt_invalidate_added(self, start - self->length + 1);
1987 if (self->ntrev > start)
1989 if (self->ntrev > start)
1988 self->ntrev = (int)start;
1990 self->ntrev = (int)start;
1989 }
1991 }
1990 if (self->added)
1992 if (self->added)
1991 ret = PyList_SetSlice(self->added, start - self->length + 1,
1993 ret = PyList_SetSlice(self->added, start - self->length + 1,
1992 PyList_GET_SIZE(self->added), NULL);
1994 PyList_GET_SIZE(self->added), NULL);
1993 done:
1995 done:
1994 Py_CLEAR(self->headrevs);
1996 Py_CLEAR(self->headrevs);
1995 return ret;
1997 return ret;
1996 }
1998 }
1997
1999
1998 /*
2000 /*
1999 * Supported ops:
2001 * Supported ops:
2000 *
2002 *
2001 * slice deletion
2003 * slice deletion
2002 * string assignment (extend node->rev mapping)
2004 * string assignment (extend node->rev mapping)
2003 * string deletion (shrink node->rev mapping)
2005 * string deletion (shrink node->rev mapping)
2004 */
2006 */
2005 static int index_assign_subscript(indexObject *self, PyObject *item,
2007 static int index_assign_subscript(indexObject *self, PyObject *item,
2006 PyObject *value)
2008 PyObject *value)
2007 {
2009 {
2008 char *node;
2010 char *node;
2009 Py_ssize_t nodelen;
2011 Py_ssize_t nodelen;
2010 long rev;
2012 long rev;
2011
2013
2012 if (PySlice_Check(item) && value == NULL)
2014 if (PySlice_Check(item) && value == NULL)
2013 return index_slice_del(self, item);
2015 return index_slice_del(self, item);
2014
2016
2015 if (node_check(item, &node, &nodelen) == -1)
2017 if (node_check(item, &node, &nodelen) == -1)
2016 return -1;
2018 return -1;
2017
2019
2018 if (value == NULL)
2020 if (value == NULL)
2019 return self->nt ? nt_insert(self, node, -1) : 0;
2021 return self->nt ? nt_insert(self, node, -1) : 0;
2020 rev = PyInt_AsLong(value);
2022 rev = PyInt_AsLong(value);
2021 if (rev > INT_MAX || rev < 0) {
2023 if (rev > INT_MAX || rev < 0) {
2022 if (!PyErr_Occurred())
2024 if (!PyErr_Occurred())
2023 PyErr_SetString(PyExc_ValueError, "rev out of range");
2025 PyErr_SetString(PyExc_ValueError, "rev out of range");
2024 return -1;
2026 return -1;
2025 }
2027 }
2026
2028
2027 if (nt_init(self) == -1)
2029 if (nt_init(self) == -1)
2028 return -1;
2030 return -1;
2029 return nt_insert(self, node, (int)rev);
2031 return nt_insert(self, node, (int)rev);
2030 }
2032 }
2031
2033
2032 /*
2034 /*
2033 * Find all RevlogNG entries in an index that has inline data. Update
2035 * Find all RevlogNG entries in an index that has inline data. Update
2034 * the optional "offsets" table with those entries.
2036 * the optional "offsets" table with those entries.
2035 */
2037 */
2036 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2038 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2037 {
2039 {
2038 const char *data = PyString_AS_STRING(self->data);
2040 const char *data = PyString_AS_STRING(self->data);
2039 Py_ssize_t pos = 0;
2041 Py_ssize_t pos = 0;
2040 Py_ssize_t end = PyString_GET_SIZE(self->data);
2042 Py_ssize_t end = PyString_GET_SIZE(self->data);
2041 long incr = v1_hdrsize;
2043 long incr = v1_hdrsize;
2042 Py_ssize_t len = 0;
2044 Py_ssize_t len = 0;
2043
2045
2044 while (pos + v1_hdrsize <= end && pos >= 0) {
2046 while (pos + v1_hdrsize <= end && pos >= 0) {
2045 uint32_t comp_len;
2047 uint32_t comp_len;
2046 /* 3rd element of header is length of compressed inline data */
2048 /* 3rd element of header is length of compressed inline data */
2047 comp_len = getbe32(data + pos + 8);
2049 comp_len = getbe32(data + pos + 8);
2048 incr = v1_hdrsize + comp_len;
2050 incr = v1_hdrsize + comp_len;
2049 if (offsets)
2051 if (offsets)
2050 offsets[len] = data + pos;
2052 offsets[len] = data + pos;
2051 len++;
2053 len++;
2052 pos += incr;
2054 pos += incr;
2053 }
2055 }
2054
2056
2055 if (pos != end) {
2057 if (pos != end) {
2056 if (!PyErr_Occurred())
2058 if (!PyErr_Occurred())
2057 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2059 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2058 return -1;
2060 return -1;
2059 }
2061 }
2060
2062
2061 return len;
2063 return len;
2062 }
2064 }
2063
2065
2064 static int index_init(indexObject *self, PyObject *args)
2066 static int index_init(indexObject *self, PyObject *args)
2065 {
2067 {
2066 PyObject *data_obj, *inlined_obj;
2068 PyObject *data_obj, *inlined_obj;
2067 Py_ssize_t size;
2069 Py_ssize_t size;
2068
2070
2069 /* Initialize before argument-checking to avoid index_dealloc() crash. */
2071 /* Initialize before argument-checking to avoid index_dealloc() crash. */
2070 self->raw_length = 0;
2072 self->raw_length = 0;
2071 self->added = NULL;
2073 self->added = NULL;
2072 self->cache = NULL;
2074 self->cache = NULL;
2073 self->data = NULL;
2075 self->data = NULL;
2074 self->headrevs = NULL;
2076 self->headrevs = NULL;
2075 self->filteredrevs = Py_None;
2077 self->filteredrevs = Py_None;
2076 Py_INCREF(Py_None);
2078 Py_INCREF(Py_None);
2077 self->nt = NULL;
2079 self->nt = NULL;
2078 self->offsets = NULL;
2080 self->offsets = NULL;
2079
2081
2080 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2082 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2081 return -1;
2083 return -1;
2082 if (!PyString_Check(data_obj)) {
2084 if (!PyString_Check(data_obj)) {
2083 PyErr_SetString(PyExc_TypeError, "data is not a string");
2085 PyErr_SetString(PyExc_TypeError, "data is not a string");
2084 return -1;
2086 return -1;
2085 }
2087 }
2086 size = PyString_GET_SIZE(data_obj);
2088 size = PyString_GET_SIZE(data_obj);
2087
2089
2088 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2090 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2089 self->data = data_obj;
2091 self->data = data_obj;
2090
2092
2091 self->ntlength = self->ntcapacity = 0;
2093 self->ntlength = self->ntcapacity = 0;
2092 self->ntdepth = self->ntsplits = 0;
2094 self->ntdepth = self->ntsplits = 0;
2093 self->ntlookups = self->ntmisses = 0;
2095 self->ntlookups = self->ntmisses = 0;
2094 self->ntrev = -1;
2096 self->ntrev = -1;
2095 Py_INCREF(self->data);
2097 Py_INCREF(self->data);
2096
2098
2097 if (self->inlined) {
2099 if (self->inlined) {
2098 Py_ssize_t len = inline_scan(self, NULL);
2100 Py_ssize_t len = inline_scan(self, NULL);
2099 if (len == -1)
2101 if (len == -1)
2100 goto bail;
2102 goto bail;
2101 self->raw_length = len;
2103 self->raw_length = len;
2102 self->length = len + 1;
2104 self->length = len + 1;
2103 } else {
2105 } else {
2104 if (size % v1_hdrsize) {
2106 if (size % v1_hdrsize) {
2105 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2107 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2106 goto bail;
2108 goto bail;
2107 }
2109 }
2108 self->raw_length = size / v1_hdrsize;
2110 self->raw_length = size / v1_hdrsize;
2109 self->length = self->raw_length + 1;
2111 self->length = self->raw_length + 1;
2110 }
2112 }
2111
2113
2112 return 0;
2114 return 0;
2113 bail:
2115 bail:
2114 return -1;
2116 return -1;
2115 }
2117 }
2116
2118
2117 static PyObject *index_nodemap(indexObject *self)
2119 static PyObject *index_nodemap(indexObject *self)
2118 {
2120 {
2119 Py_INCREF(self);
2121 Py_INCREF(self);
2120 return (PyObject *)self;
2122 return (PyObject *)self;
2121 }
2123 }
2122
2124
2123 static void index_dealloc(indexObject *self)
2125 static void index_dealloc(indexObject *self)
2124 {
2126 {
2125 _index_clearcaches(self);
2127 _index_clearcaches(self);
2126 Py_XDECREF(self->filteredrevs);
2128 Py_XDECREF(self->filteredrevs);
2127 Py_XDECREF(self->data);
2129 Py_XDECREF(self->data);
2128 Py_XDECREF(self->added);
2130 Py_XDECREF(self->added);
2129 PyObject_Del(self);
2131 PyObject_Del(self);
2130 }
2132 }
2131
2133
2132 static PySequenceMethods index_sequence_methods = {
2134 static PySequenceMethods index_sequence_methods = {
2133 (lenfunc)index_length, /* sq_length */
2135 (lenfunc)index_length, /* sq_length */
2134 0, /* sq_concat */
2136 0, /* sq_concat */
2135 0, /* sq_repeat */
2137 0, /* sq_repeat */
2136 (ssizeargfunc)index_get, /* sq_item */
2138 (ssizeargfunc)index_get, /* sq_item */
2137 0, /* sq_slice */
2139 0, /* sq_slice */
2138 0, /* sq_ass_item */
2140 0, /* sq_ass_item */
2139 0, /* sq_ass_slice */
2141 0, /* sq_ass_slice */
2140 (objobjproc)index_contains, /* sq_contains */
2142 (objobjproc)index_contains, /* sq_contains */
2141 };
2143 };
2142
2144
2143 static PyMappingMethods index_mapping_methods = {
2145 static PyMappingMethods index_mapping_methods = {
2144 (lenfunc)index_length, /* mp_length */
2146 (lenfunc)index_length, /* mp_length */
2145 (binaryfunc)index_getitem, /* mp_subscript */
2147 (binaryfunc)index_getitem, /* mp_subscript */
2146 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2148 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2147 };
2149 };
2148
2150
2149 static PyMethodDef index_methods[] = {
2151 static PyMethodDef index_methods[] = {
2150 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2152 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2151 "return the gca set of the given revs"},
2153 "return the gca set of the given revs"},
2152 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2154 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2153 METH_VARARGS,
2155 METH_VARARGS,
2154 "return the heads of the common ancestors of the given revs"},
2156 "return the heads of the common ancestors of the given revs"},
2155 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2157 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2156 "clear the index caches"},
2158 "clear the index caches"},
2157 {"get", (PyCFunction)index_m_get, METH_VARARGS,
2159 {"get", (PyCFunction)index_m_get, METH_VARARGS,
2158 "get an index entry"},
2160 "get an index entry"},
2159 {"computephases", (PyCFunction)compute_phases, METH_VARARGS,
2161 {"computephases", (PyCFunction)compute_phases, METH_VARARGS,
2160 "compute phases"},
2162 "compute phases"},
2161 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2163 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2162 "get head revisions"}, /* Can do filtering since 3.2 */
2164 "get head revisions"}, /* Can do filtering since 3.2 */
2163 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2165 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2164 "get filtered head revisions"}, /* Can always do filtering */
2166 "get filtered head revisions"}, /* Can always do filtering */
2165 {"insert", (PyCFunction)index_insert, METH_VARARGS,
2167 {"insert", (PyCFunction)index_insert, METH_VARARGS,
2166 "insert an index entry"},
2168 "insert an index entry"},
2167 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2169 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2168 "match a potentially ambiguous node ID"},
2170 "match a potentially ambiguous node ID"},
2169 {"stats", (PyCFunction)index_stats, METH_NOARGS,
2171 {"stats", (PyCFunction)index_stats, METH_NOARGS,
2170 "stats for the index"},
2172 "stats for the index"},
2171 {NULL} /* Sentinel */
2173 {NULL} /* Sentinel */
2172 };
2174 };
2173
2175
2174 static PyGetSetDef index_getset[] = {
2176 static PyGetSetDef index_getset[] = {
2175 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2177 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2176 {NULL} /* Sentinel */
2178 {NULL} /* Sentinel */
2177 };
2179 };
2178
2180
2179 static PyTypeObject indexType = {
2181 static PyTypeObject indexType = {
2180 PyObject_HEAD_INIT(NULL)
2182 PyObject_HEAD_INIT(NULL)
2181 0, /* ob_size */
2183 0, /* ob_size */
2182 "parsers.index", /* tp_name */
2184 "parsers.index", /* tp_name */
2183 sizeof(indexObject), /* tp_basicsize */
2185 sizeof(indexObject), /* tp_basicsize */
2184 0, /* tp_itemsize */
2186 0, /* tp_itemsize */
2185 (destructor)index_dealloc, /* tp_dealloc */
2187 (destructor)index_dealloc, /* tp_dealloc */
2186 0, /* tp_print */
2188 0, /* tp_print */
2187 0, /* tp_getattr */
2189 0, /* tp_getattr */
2188 0, /* tp_setattr */
2190 0, /* tp_setattr */
2189 0, /* tp_compare */
2191 0, /* tp_compare */
2190 0, /* tp_repr */
2192 0, /* tp_repr */
2191 0, /* tp_as_number */
2193 0, /* tp_as_number */
2192 &index_sequence_methods, /* tp_as_sequence */
2194 &index_sequence_methods, /* tp_as_sequence */
2193 &index_mapping_methods, /* tp_as_mapping */
2195 &index_mapping_methods, /* tp_as_mapping */
2194 0, /* tp_hash */
2196 0, /* tp_hash */
2195 0, /* tp_call */
2197 0, /* tp_call */
2196 0, /* tp_str */
2198 0, /* tp_str */
2197 0, /* tp_getattro */
2199 0, /* tp_getattro */
2198 0, /* tp_setattro */
2200 0, /* tp_setattro */
2199 0, /* tp_as_buffer */
2201 0, /* tp_as_buffer */
2200 Py_TPFLAGS_DEFAULT, /* tp_flags */
2202 Py_TPFLAGS_DEFAULT, /* tp_flags */
2201 "revlog index", /* tp_doc */
2203 "revlog index", /* tp_doc */
2202 0, /* tp_traverse */
2204 0, /* tp_traverse */
2203 0, /* tp_clear */
2205 0, /* tp_clear */
2204 0, /* tp_richcompare */
2206 0, /* tp_richcompare */
2205 0, /* tp_weaklistoffset */
2207 0, /* tp_weaklistoffset */
2206 0, /* tp_iter */
2208 0, /* tp_iter */
2207 0, /* tp_iternext */
2209 0, /* tp_iternext */
2208 index_methods, /* tp_methods */
2210 index_methods, /* tp_methods */
2209 0, /* tp_members */
2211 0, /* tp_members */
2210 index_getset, /* tp_getset */
2212 index_getset, /* tp_getset */
2211 0, /* tp_base */
2213 0, /* tp_base */
2212 0, /* tp_dict */
2214 0, /* tp_dict */
2213 0, /* tp_descr_get */
2215 0, /* tp_descr_get */
2214 0, /* tp_descr_set */
2216 0, /* tp_descr_set */
2215 0, /* tp_dictoffset */
2217 0, /* tp_dictoffset */
2216 (initproc)index_init, /* tp_init */
2218 (initproc)index_init, /* tp_init */
2217 0, /* tp_alloc */
2219 0, /* tp_alloc */
2218 };
2220 };
2219
2221
2220 /*
2222 /*
2221 * returns a tuple of the form (index, index, cache) with elements as
2223 * returns a tuple of the form (index, index, cache) with elements as
2222 * follows:
2224 * follows:
2223 *
2225 *
2224 * index: an index object that lazily parses RevlogNG records
2226 * index: an index object that lazily parses RevlogNG records
2225 * cache: if data is inlined, a tuple (index_file_content, 0), else None
2227 * cache: if data is inlined, a tuple (index_file_content, 0), else None
2226 *
2228 *
2227 * added complications are for backwards compatibility
2229 * added complications are for backwards compatibility
2228 */
2230 */
2229 static PyObject *parse_index2(PyObject *self, PyObject *args)
2231 static PyObject *parse_index2(PyObject *self, PyObject *args)
2230 {
2232 {
2231 PyObject *tuple = NULL, *cache = NULL;
2233 PyObject *tuple = NULL, *cache = NULL;
2232 indexObject *idx;
2234 indexObject *idx;
2233 int ret;
2235 int ret;
2234
2236
2235 idx = PyObject_New(indexObject, &indexType);
2237 idx = PyObject_New(indexObject, &indexType);
2236 if (idx == NULL)
2238 if (idx == NULL)
2237 goto bail;
2239 goto bail;
2238
2240
2239 ret = index_init(idx, args);
2241 ret = index_init(idx, args);
2240 if (ret == -1)
2242 if (ret == -1)
2241 goto bail;
2243 goto bail;
2242
2244
2243 if (idx->inlined) {
2245 if (idx->inlined) {
2244 cache = Py_BuildValue("iO", 0, idx->data);
2246 cache = Py_BuildValue("iO", 0, idx->data);
2245 if (cache == NULL)
2247 if (cache == NULL)
2246 goto bail;
2248 goto bail;
2247 } else {
2249 } else {
2248 cache = Py_None;
2250 cache = Py_None;
2249 Py_INCREF(cache);
2251 Py_INCREF(cache);
2250 }
2252 }
2251
2253
2252 tuple = Py_BuildValue("NN", idx, cache);
2254 tuple = Py_BuildValue("NN", idx, cache);
2253 if (!tuple)
2255 if (!tuple)
2254 goto bail;
2256 goto bail;
2255 return tuple;
2257 return tuple;
2256
2258
2257 bail:
2259 bail:
2258 Py_XDECREF(idx);
2260 Py_XDECREF(idx);
2259 Py_XDECREF(cache);
2261 Py_XDECREF(cache);
2260 Py_XDECREF(tuple);
2262 Py_XDECREF(tuple);
2261 return NULL;
2263 return NULL;
2262 }
2264 }
2263
2265
2264 #define BUMPED_FIX 1
2266 #define BUMPED_FIX 1
2265 #define USING_SHA_256 2
2267 #define USING_SHA_256 2
2266
2268
2267 static PyObject *readshas(
2269 static PyObject *readshas(
2268 const char *source, unsigned char num, Py_ssize_t hashwidth)
2270 const char *source, unsigned char num, Py_ssize_t hashwidth)
2269 {
2271 {
2270 int i;
2272 int i;
2271 PyObject *list = PyTuple_New(num);
2273 PyObject *list = PyTuple_New(num);
2272 if (list == NULL) {
2274 if (list == NULL) {
2273 return NULL;
2275 return NULL;
2274 }
2276 }
2275 for (i = 0; i < num; i++) {
2277 for (i = 0; i < num; i++) {
2276 PyObject *hash = PyString_FromStringAndSize(source, hashwidth);
2278 PyObject *hash = PyString_FromStringAndSize(source, hashwidth);
2277 if (hash == NULL) {
2279 if (hash == NULL) {
2278 Py_DECREF(list);
2280 Py_DECREF(list);
2279 return NULL;
2281 return NULL;
2280 }
2282 }
2281 PyTuple_SetItem(list, i, hash);
2283 PyTuple_SetItem(list, i, hash);
2282 source += hashwidth;
2284 source += hashwidth;
2283 }
2285 }
2284 return list;
2286 return list;
2285 }
2287 }
2286
2288
2287 static PyObject *fm1readmarker(const char *data, uint32_t *msize)
2289 static PyObject *fm1readmarker(const char *data, uint32_t *msize)
2288 {
2290 {
2289 const char *meta;
2291 const char *meta;
2290
2292
2291 double mtime;
2293 double mtime;
2292 int16_t tz;
2294 int16_t tz;
2293 uint16_t flags;
2295 uint16_t flags;
2294 unsigned char nsuccs, nparents, nmetadata;
2296 unsigned char nsuccs, nparents, nmetadata;
2295 Py_ssize_t hashwidth = 20;
2297 Py_ssize_t hashwidth = 20;
2296
2298
2297 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
2299 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
2298 PyObject *metadata = NULL, *ret = NULL;
2300 PyObject *metadata = NULL, *ret = NULL;
2299 int i;
2301 int i;
2300
2302
2301 *msize = getbe32(data);
2303 *msize = getbe32(data);
2302 data += 4;
2304 data += 4;
2303 mtime = getbefloat64(data);
2305 mtime = getbefloat64(data);
2304 data += 8;
2306 data += 8;
2305 tz = getbeint16(data);
2307 tz = getbeint16(data);
2306 data += 2;
2308 data += 2;
2307 flags = getbeuint16(data);
2309 flags = getbeuint16(data);
2308 data += 2;
2310 data += 2;
2309
2311
2310 if (flags & USING_SHA_256) {
2312 if (flags & USING_SHA_256) {
2311 hashwidth = 32;
2313 hashwidth = 32;
2312 }
2314 }
2313
2315
2314 nsuccs = (unsigned char)(*data++);
2316 nsuccs = (unsigned char)(*data++);
2315 nparents = (unsigned char)(*data++);
2317 nparents = (unsigned char)(*data++);
2316 nmetadata = (unsigned char)(*data++);
2318 nmetadata = (unsigned char)(*data++);
2317
2319
2318 prec = PyString_FromStringAndSize(data, hashwidth);
2320 prec = PyString_FromStringAndSize(data, hashwidth);
2319 data += hashwidth;
2321 data += hashwidth;
2320 if (prec == NULL) {
2322 if (prec == NULL) {
2321 goto bail;
2323 goto bail;
2322 }
2324 }
2323
2325
2324 succs = readshas(data, nsuccs, hashwidth);
2326 succs = readshas(data, nsuccs, hashwidth);
2325 if (succs == NULL) {
2327 if (succs == NULL) {
2326 goto bail;
2328 goto bail;
2327 }
2329 }
2328 data += nsuccs * hashwidth;
2330 data += nsuccs * hashwidth;
2329
2331
2330 if (nparents == 1 || nparents == 2) {
2332 if (nparents == 1 || nparents == 2) {
2331 parents = readshas(data, nparents, hashwidth);
2333 parents = readshas(data, nparents, hashwidth);
2332 if (parents == NULL) {
2334 if (parents == NULL) {
2333 goto bail;
2335 goto bail;
2334 }
2336 }
2335 data += nparents * hashwidth;
2337 data += nparents * hashwidth;
2336 } else {
2338 } else {
2337 parents = Py_None;
2339 parents = Py_None;
2338 }
2340 }
2339
2341
2340 meta = data + (2 * nmetadata);
2342 meta = data + (2 * nmetadata);
2341 metadata = PyTuple_New(nmetadata);
2343 metadata = PyTuple_New(nmetadata);
2342 if (metadata == NULL) {
2344 if (metadata == NULL) {
2343 goto bail;
2345 goto bail;
2344 }
2346 }
2345 for (i = 0; i < nmetadata; i++) {
2347 for (i = 0; i < nmetadata; i++) {
2346 PyObject *tmp, *left = NULL, *right = NULL;
2348 PyObject *tmp, *left = NULL, *right = NULL;
2347 Py_ssize_t metasize = (unsigned char)(*data++);
2349 Py_ssize_t metasize = (unsigned char)(*data++);
2348 left = PyString_FromStringAndSize(meta, metasize);
2350 left = PyString_FromStringAndSize(meta, metasize);
2349 meta += metasize;
2351 meta += metasize;
2350 metasize = (unsigned char)(*data++);
2352 metasize = (unsigned char)(*data++);
2351 right = PyString_FromStringAndSize(meta, metasize);
2353 right = PyString_FromStringAndSize(meta, metasize);
2352 meta += metasize;
2354 meta += metasize;
2353 if (!left || !right) {
2355 if (!left || !right) {
2354 Py_XDECREF(left);
2356 Py_XDECREF(left);
2355 Py_XDECREF(right);
2357 Py_XDECREF(right);
2356 goto bail;
2358 goto bail;
2357 }
2359 }
2358 tmp = PyTuple_Pack(2, left, right);
2360 tmp = PyTuple_Pack(2, left, right);
2359 Py_DECREF(left);
2361 Py_DECREF(left);
2360 Py_DECREF(right);
2362 Py_DECREF(right);
2361 if (!tmp) {
2363 if (!tmp) {
2362 goto bail;
2364 goto bail;
2363 }
2365 }
2364 PyTuple_SetItem(metadata, i, tmp);
2366 PyTuple_SetItem(metadata, i, tmp);
2365 }
2367 }
2366 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags,
2368 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags,
2367 metadata, mtime, (int)tz * 60, parents);
2369 metadata, mtime, (int)tz * 60, parents);
2368 bail:
2370 bail:
2369 Py_XDECREF(prec);
2371 Py_XDECREF(prec);
2370 Py_XDECREF(succs);
2372 Py_XDECREF(succs);
2371 Py_XDECREF(metadata);
2373 Py_XDECREF(metadata);
2372 if (parents != Py_None)
2374 if (parents != Py_None)
2373 Py_XDECREF(parents);
2375 Py_XDECREF(parents);
2374 return ret;
2376 return ret;
2375 }
2377 }
2376
2378
2377
2379
2378 static PyObject *fm1readmarkers(PyObject *self, PyObject *args) {
2380 static PyObject *fm1readmarkers(PyObject *self, PyObject *args) {
2379 const char *data;
2381 const char *data;
2380 Py_ssize_t datalen;
2382 Py_ssize_t datalen;
2381 /* only unsigned long because python 2.4, should be Py_ssize_t */
2383 /* only unsigned long because python 2.4, should be Py_ssize_t */
2382 unsigned long offset, stop;
2384 unsigned long offset, stop;
2383 PyObject *markers = NULL;
2385 PyObject *markers = NULL;
2384
2386
2385 /* replace kk with nn when we drop Python 2.4 */
2387 /* replace kk with nn when we drop Python 2.4 */
2386 if (!PyArg_ParseTuple(args, "s#kk", &data, &datalen, &offset, &stop)) {
2388 if (!PyArg_ParseTuple(args, "s#kk", &data, &datalen, &offset, &stop)) {
2387 return NULL;
2389 return NULL;
2388 }
2390 }
2389 data += offset;
2391 data += offset;
2390 markers = PyList_New(0);
2392 markers = PyList_New(0);
2391 if (!markers) {
2393 if (!markers) {
2392 return NULL;
2394 return NULL;
2393 }
2395 }
2394 while (offset < stop) {
2396 while (offset < stop) {
2395 uint32_t msize;
2397 uint32_t msize;
2396 int error;
2398 int error;
2397 PyObject *record = fm1readmarker(data, &msize);
2399 PyObject *record = fm1readmarker(data, &msize);
2398 if (!record) {
2400 if (!record) {
2399 goto bail;
2401 goto bail;
2400 }
2402 }
2401 error = PyList_Append(markers, record);
2403 error = PyList_Append(markers, record);
2402 Py_DECREF(record);
2404 Py_DECREF(record);
2403 if (error) {
2405 if (error) {
2404 goto bail;
2406 goto bail;
2405 }
2407 }
2406 data += msize;
2408 data += msize;
2407 offset += msize;
2409 offset += msize;
2408 }
2410 }
2409 return markers;
2411 return markers;
2410 bail:
2412 bail:
2411 Py_DECREF(markers);
2413 Py_DECREF(markers);
2412 return NULL;
2414 return NULL;
2413 }
2415 }
2414
2416
2415 static char parsers_doc[] = "Efficient content parsing.";
2417 static char parsers_doc[] = "Efficient content parsing.";
2416
2418
2417 PyObject *encodedir(PyObject *self, PyObject *args);
2419 PyObject *encodedir(PyObject *self, PyObject *args);
2418 PyObject *pathencode(PyObject *self, PyObject *args);
2420 PyObject *pathencode(PyObject *self, PyObject *args);
2419 PyObject *lowerencode(PyObject *self, PyObject *args);
2421 PyObject *lowerencode(PyObject *self, PyObject *args);
2420
2422
2421 static PyMethodDef methods[] = {
2423 static PyMethodDef methods[] = {
2422 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
2424 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
2423 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2425 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2424 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2426 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2425 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2427 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2426 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
2428 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
2427 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2429 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2428 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2430 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2429 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2431 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2430 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
2432 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
2431 "parse v1 obsolete markers\n"},
2433 "parse v1 obsolete markers\n"},
2432 {NULL, NULL}
2434 {NULL, NULL}
2433 };
2435 };
2434
2436
2435 void dirs_module_init(PyObject *mod);
2437 void dirs_module_init(PyObject *mod);
2436 void manifest_module_init(PyObject *mod);
2438 void manifest_module_init(PyObject *mod);
2437
2439
2438 static void module_init(PyObject *mod)
2440 static void module_init(PyObject *mod)
2439 {
2441 {
2440 /* This module constant has two purposes. First, it lets us unit test
2442 /* This module constant has two purposes. First, it lets us unit test
2441 * the ImportError raised without hard-coding any error text. This
2443 * the ImportError raised without hard-coding any error text. This
2442 * means we can change the text in the future without breaking tests,
2444 * means we can change the text in the future without breaking tests,
2443 * even across changesets without a recompile. Second, its presence
2445 * even across changesets without a recompile. Second, its presence
2444 * can be used to determine whether the version-checking logic is
2446 * can be used to determine whether the version-checking logic is
2445 * present, which also helps in testing across changesets without a
2447 * present, which also helps in testing across changesets without a
2446 * recompile. Note that this means the pure-Python version of parsers
2448 * recompile. Note that this means the pure-Python version of parsers
2447 * should not have this module constant. */
2449 * should not have this module constant. */
2448 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2450 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2449
2451
2450 dirs_module_init(mod);
2452 dirs_module_init(mod);
2451 manifest_module_init(mod);
2453 manifest_module_init(mod);
2452
2454
2453 indexType.tp_new = PyType_GenericNew;
2455 indexType.tp_new = PyType_GenericNew;
2454 if (PyType_Ready(&indexType) < 0 ||
2456 if (PyType_Ready(&indexType) < 0 ||
2455 PyType_Ready(&dirstateTupleType) < 0)
2457 PyType_Ready(&dirstateTupleType) < 0)
2456 return;
2458 return;
2457 Py_INCREF(&indexType);
2459 Py_INCREF(&indexType);
2458 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2460 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2459 Py_INCREF(&dirstateTupleType);
2461 Py_INCREF(&dirstateTupleType);
2460 PyModule_AddObject(mod, "dirstatetuple",
2462 PyModule_AddObject(mod, "dirstatetuple",
2461 (PyObject *)&dirstateTupleType);
2463 (PyObject *)&dirstateTupleType);
2462
2464
2463 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2465 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2464 -1, -1, -1, -1, nullid, 20);
2466 -1, -1, -1, -1, nullid, 20);
2465 if (nullentry)
2467 if (nullentry)
2466 PyObject_GC_UnTrack(nullentry);
2468 PyObject_GC_UnTrack(nullentry);
2467 }
2469 }
2468
2470
2469 static int check_python_version(void)
2471 static int check_python_version(void)
2470 {
2472 {
2471 PyObject *sys = PyImport_ImportModule("sys"), *ver;
2473 PyObject *sys = PyImport_ImportModule("sys"), *ver;
2472 long hexversion;
2474 long hexversion;
2473 if (!sys)
2475 if (!sys)
2474 return -1;
2476 return -1;
2475 ver = PyObject_GetAttrString(sys, "hexversion");
2477 ver = PyObject_GetAttrString(sys, "hexversion");
2476 Py_DECREF(sys);
2478 Py_DECREF(sys);
2477 if (!ver)
2479 if (!ver)
2478 return -1;
2480 return -1;
2479 hexversion = PyInt_AsLong(ver);
2481 hexversion = PyInt_AsLong(ver);
2480 Py_DECREF(ver);
2482 Py_DECREF(ver);
2481 /* sys.hexversion is a 32-bit number by default, so the -1 case
2483 /* sys.hexversion is a 32-bit number by default, so the -1 case
2482 * should only occur in unusual circumstances (e.g. if sys.hexversion
2484 * should only occur in unusual circumstances (e.g. if sys.hexversion
2483 * is manually set to an invalid value). */
2485 * is manually set to an invalid value). */
2484 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2486 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2485 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2487 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2486 "modules were compiled with Python " PY_VERSION ", but "
2488 "modules were compiled with Python " PY_VERSION ", but "
2487 "Mercurial is currently using Python with sys.hexversion=%ld: "
2489 "Mercurial is currently using Python with sys.hexversion=%ld: "
2488 "Python %s\n at: %s", versionerrortext, hexversion,
2490 "Python %s\n at: %s", versionerrortext, hexversion,
2489 Py_GetVersion(), Py_GetProgramFullPath());
2491 Py_GetVersion(), Py_GetProgramFullPath());
2490 return -1;
2492 return -1;
2491 }
2493 }
2492 return 0;
2494 return 0;
2493 }
2495 }
2494
2496
2495 #ifdef IS_PY3K
2497 #ifdef IS_PY3K
2496 static struct PyModuleDef parsers_module = {
2498 static struct PyModuleDef parsers_module = {
2497 PyModuleDef_HEAD_INIT,
2499 PyModuleDef_HEAD_INIT,
2498 "parsers",
2500 "parsers",
2499 parsers_doc,
2501 parsers_doc,
2500 -1,
2502 -1,
2501 methods
2503 methods
2502 };
2504 };
2503
2505
2504 PyMODINIT_FUNC PyInit_parsers(void)
2506 PyMODINIT_FUNC PyInit_parsers(void)
2505 {
2507 {
2506 PyObject *mod;
2508 PyObject *mod;
2507
2509
2508 if (check_python_version() == -1)
2510 if (check_python_version() == -1)
2509 return;
2511 return;
2510 mod = PyModule_Create(&parsers_module);
2512 mod = PyModule_Create(&parsers_module);
2511 module_init(mod);
2513 module_init(mod);
2512 return mod;
2514 return mod;
2513 }
2515 }
2514 #else
2516 #else
2515 PyMODINIT_FUNC initparsers(void)
2517 PyMODINIT_FUNC initparsers(void)
2516 {
2518 {
2517 PyObject *mod;
2519 PyObject *mod;
2518
2520
2519 if (check_python_version() == -1)
2521 if (check_python_version() == -1)
2520 return;
2522 return;
2521 mod = Py_InitModule3("parsers", methods, parsers_doc);
2523 mod = Py_InitModule3("parsers", methods, parsers_doc);
2522 module_init(mod);
2524 module_init(mod);
2523 }
2525 }
2524 #endif
2526 #endif
General Comments 0
You need to be logged in to leave comments. Login now