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