2288 Py_XDECREF(cache); |
2288 Py_XDECREF(cache); |
2289 Py_XDECREF(tuple); |
2289 Py_XDECREF(tuple); |
2290 return NULL; |
2290 return NULL; |
2291 } |
2291 } |
2292 |
2292 |
|
2293 #ifdef WITH_RUST |
|
2294 |
|
2295 /* rustlazyancestors: iteration over ancestors implemented in Rust |
|
2296 * |
|
2297 * This class holds a reference to an index and to the Rust iterator. |
|
2298 */ |
|
2299 typedef struct rustlazyancestorsObjectStruct rustlazyancestorsObject; |
|
2300 |
|
2301 struct rustlazyancestorsObjectStruct { |
|
2302 PyObject_HEAD |
|
2303 /* Type-specific fields go here. */ |
|
2304 indexObject *index; /* Ref kept to avoid GC'ing the index */ |
|
2305 void *iter; /* Rust iterator */ |
|
2306 }; |
|
2307 |
|
2308 /* FFI exposed from Rust code */ |
|
2309 rustlazyancestorsObject *rustlazyancestors_init( |
|
2310 indexObject *index, |
|
2311 /* to pass index_get_parents() */ |
|
2312 int (*)(indexObject *, Py_ssize_t, int*, int), |
|
2313 /* intrevs vector */ |
|
2314 int initrevslen, long *initrevs, |
|
2315 long stoprev, |
|
2316 int inclusive); |
|
2317 void rustlazyancestors_drop(rustlazyancestorsObject *self); |
|
2318 int rustlazyancestors_next(rustlazyancestorsObject *self); |
|
2319 |
|
2320 /* CPython instance methods */ |
|
2321 static int rustla_init(rustlazyancestorsObject *self, |
|
2322 PyObject *args) { |
|
2323 PyObject *initrevsarg = NULL; |
|
2324 PyObject *inclusivearg = NULL; |
|
2325 long stoprev = 0; |
|
2326 long *initrevs = NULL; |
|
2327 int inclusive = 0; |
|
2328 Py_ssize_t i; |
|
2329 |
|
2330 indexObject *index; |
|
2331 if (!PyArg_ParseTuple(args, "O!O!lO!", |
|
2332 &indexType, &index, |
|
2333 &PyList_Type, &initrevsarg, |
|
2334 &stoprev, |
|
2335 &PyBool_Type, &inclusivearg)) |
|
2336 return -1; |
|
2337 |
|
2338 Py_INCREF(index); |
|
2339 self->index = index; |
|
2340 |
|
2341 if (inclusivearg == Py_True) |
|
2342 inclusive = 1; |
|
2343 |
|
2344 Py_ssize_t linit = PyList_GET_SIZE(initrevsarg); |
|
2345 |
|
2346 initrevs = (long*)calloc(linit, sizeof(long)); |
|
2347 |
|
2348 if (initrevs == NULL) { |
|
2349 PyErr_NoMemory(); |
|
2350 goto bail; |
|
2351 } |
|
2352 |
|
2353 for (i=0; i<linit; i++) { |
|
2354 initrevs[i] = PyInt_AsLong(PyList_GET_ITEM(initrevsarg, i)); |
|
2355 } |
|
2356 if (PyErr_Occurred()) |
|
2357 goto bail; |
|
2358 |
|
2359 self->iter = rustlazyancestors_init(index, |
|
2360 index_get_parents, |
|
2361 linit, initrevs, |
|
2362 stoprev, inclusive); |
|
2363 if (self->iter == NULL) { |
|
2364 /* if this is because of GraphError::ParentOutOfRange |
|
2365 * index_get_parents() has already set the proper ValueError */ |
|
2366 goto bail; |
|
2367 } |
|
2368 |
|
2369 free(initrevs); |
|
2370 return 0; |
|
2371 |
|
2372 bail: |
|
2373 free(initrevs); |
|
2374 return -1; |
|
2375 }; |
|
2376 |
|
2377 static void rustla_dealloc(rustlazyancestorsObject *self) |
|
2378 { |
|
2379 Py_XDECREF(self->index); |
|
2380 if (self->iter != NULL) { /* can happen if rustla_init failed */ |
|
2381 rustlazyancestors_drop(self->iter); |
|
2382 } |
|
2383 PyObject_Del(self); |
|
2384 } |
|
2385 |
|
2386 static PyObject *rustla_next(rustlazyancestorsObject *self) { |
|
2387 int res = rustlazyancestors_next(self->iter); |
|
2388 if (res == -1) { |
|
2389 /* Setting an explicit exception seems unnecessary |
|
2390 * as examples from Python source code (Objects/rangeobjets.c and |
|
2391 * Modules/_io/stringio.c) seem to demonstrate. |
|
2392 */ |
|
2393 return NULL; |
|
2394 } |
|
2395 return PyInt_FromLong(res); |
|
2396 } |
|
2397 |
|
2398 static PyTypeObject rustlazyancestorsType = { |
|
2399 PyVarObject_HEAD_INIT(NULL, 0) /* header */ |
|
2400 "parsers.rustlazyancestors", /* tp_name */ |
|
2401 sizeof(rustlazyancestorsObject), /* tp_basicsize */ |
|
2402 0, /* tp_itemsize */ |
|
2403 (destructor)rustla_dealloc, /* tp_dealloc */ |
|
2404 0, /* tp_print */ |
|
2405 0, /* tp_getattr */ |
|
2406 0, /* tp_setattr */ |
|
2407 0, /* tp_compare */ |
|
2408 0, /* tp_repr */ |
|
2409 0, /* tp_as_number */ |
|
2410 0, /* tp_as_sequence */ |
|
2411 0, /* tp_as_mapping */ |
|
2412 0, /* tp_hash */ |
|
2413 0, /* tp_call */ |
|
2414 0, /* tp_str */ |
|
2415 0, /* tp_getattro */ |
|
2416 0, /* tp_setattro */ |
|
2417 0, /* tp_as_buffer */ |
|
2418 Py_TPFLAGS_DEFAULT, /* tp_flags */ |
|
2419 "Iterator over ancestors, implemented in Rust", /* tp_doc */ |
|
2420 0, /* tp_traverse */ |
|
2421 0, /* tp_clear */ |
|
2422 0, /* tp_richcompare */ |
|
2423 0, /* tp_weaklistoffset */ |
|
2424 0, /* tp_iter */ |
|
2425 (iternextfunc)rustla_next, /* tp_iternext */ |
|
2426 0, /* tp_methods */ |
|
2427 0, /* tp_members */ |
|
2428 0, /* tp_getset */ |
|
2429 0, /* tp_base */ |
|
2430 0, /* tp_dict */ |
|
2431 0, /* tp_descr_get */ |
|
2432 0, /* tp_descr_set */ |
|
2433 0, /* tp_dictoffset */ |
|
2434 (initproc)rustla_init, /* tp_init */ |
|
2435 0, /* tp_alloc */ |
|
2436 }; |
|
2437 #endif /* WITH_RUST */ |
|
2438 |
2293 void revlog_module_init(PyObject *mod) |
2439 void revlog_module_init(PyObject *mod) |
2294 { |
2440 { |
2295 indexType.tp_new = PyType_GenericNew; |
2441 indexType.tp_new = PyType_GenericNew; |
2296 if (PyType_Ready(&indexType) < 0) |
2442 if (PyType_Ready(&indexType) < 0) |
2297 return; |
2443 return; |
2308 nullentry = Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0, 0, |
2454 nullentry = Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0, 0, |
2309 -1, -1, -1, -1, nullid, 20); |
2455 -1, -1, -1, -1, nullid, 20); |
2310 } |
2456 } |
2311 if (nullentry) |
2457 if (nullentry) |
2312 PyObject_GC_UnTrack(nullentry); |
2458 PyObject_GC_UnTrack(nullentry); |
2313 } |
2459 |
|
2460 #ifdef WITH_RUST |
|
2461 rustlazyancestorsType.tp_new = PyType_GenericNew; |
|
2462 if (PyType_Ready(&rustlazyancestorsType) < 0) |
|
2463 return; |
|
2464 Py_INCREF(&rustlazyancestorsType); |
|
2465 PyModule_AddObject(mod, "rustlazyancestors", |
|
2466 (PyObject *)&rustlazyancestorsType); |
|
2467 #endif |
|
2468 |
|
2469 } |