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