@@@ py_buffer/freebin wip
[catacomb-python] / pgen.c
CommitLineData
d7ab1bab 1/* -*-c-*-
2 *
d7ab1bab 3 * Prime number generation
4 *
5 * (c) 2005 Straylight/Edgeware
6 */
7
b2687a0a 8/*----- Licensing notice --------------------------------------------------*
d7ab1bab 9 *
10 * This file is part of the Python interface to Catacomb.
11 *
12 * Catacomb/Python is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
b2687a0a 16 *
d7ab1bab 17 * Catacomb/Python is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
b2687a0a 21 *
d7ab1bab 22 * You should have received a copy of the GNU General Public License
23 * along with Catacomb/Python; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27/*----- Header files ------------------------------------------------------*/
28
29#include "catacomb-python.h"
30
31/*----- Filters -----------------------------------------------------------*/
32
33PyTypeObject *pfilt_pytype;
34
35static PyObject *pfilt_pywrap(pfilt *f)
36{
37 pfilt_pyobj *o = 0;
38 o = PyObject_New(pfilt_pyobj, pfilt_pytype);
39 o->f = *f;
40 o->st = pfilt_step(f, 0);
b2687a0a 41 return ((PyObject *)o);
d7ab1bab 42}
43
44static PyObject *pfilt_pymake(PyTypeObject *ty, PyObject *xobj)
45{
46 mp *x = 0;
47 pfilt_pyobj *o = 0;
48
49 if (PFILT_PYCHECK(xobj)) RETURN_OBJ(xobj);
50 if ((x = getmp(xobj)) == 0) goto end;
51 o = (pfilt_pyobj *)ty->tp_alloc(ty, 0);
52 o->st = pfilt_create(&o->f, x);
53end:
54 mp_drop(x);
55 return ((PyObject *)o);
56}
57
58static PyObject *pfilt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
59{
827f89d7 60 static const char *const kwlist[] = { "x", 0 };
d7ab1bab 61 PyObject *xobj;
62
827f89d7 63 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", KWLIST, &xobj))
d7ab1bab 64 return (0);
65 return (pfilt_pymake(ty, xobj));
66}
67
68static void pfilt_pydealloc(PyObject *me)
3aa33042 69 { pfilt_destroy(PFILT_F(me)); FREEOBJ(me); }
d7ab1bab 70
71static PyObject *pfmeth_step(PyObject *me, PyObject *arg)
72{
73 mpw x;
74
75 if (!PyArg_ParseTuple(arg, "O&:step", convmpw, &x)) return (0);
76 PFILT_ST(me) = pfilt_step(PFILT_F(me), x);
77 RETURN_ME;
78}
79
80static PyObject *pfmeth_muladd(PyObject *me, PyObject *arg)
81{
82 mpw m, a;
83 pfilt_pyobj *o = 0;
84
85 if (!PyArg_ParseTuple(arg, "O&O&:muladd", convmpw, &m, convmpw, &a))
86 return (0);
87 o = PyObject_New(pfilt_pyobj, pfilt_pytype);
88 o->st = pfilt_muladd(&o->f, PFILT_F(me), m, a);
89 return ((PyObject *)o);
90}
91
92static CONVFUNC(pfilt, pfilt *, PFILT_F)
93
94static PyObject *pfmeth_jump(PyObject *me, PyObject *arg)
95{
96 pfilt *f;
97
98 if (!PyArg_ParseTuple(arg, "O&:jump", convpfilt, &f)) return (0);
99 PFILT_ST(me) = pfilt_jump(PFILT_F(me), f);
100 RETURN_ME;
101}
102
a157093f 103static PyObject *pfmeth_smallfactor(PyObject *me, PyObject *arg)
d7ab1bab 104{
105 mp *x = 0;
106 PyObject *rc = 0;
107
a157093f 108 if (!PyArg_ParseTuple(arg, "O&:smallfactor", convmp, &x)) goto end;
d7ab1bab 109 rc = PyInt_FromLong(pfilt_smallfactor(x));
110end:
111 mp_drop(x);
112 return (rc);
113}
114
115static int pfilt_pynonzerop(PyObject *me)
116 { return (PFILT_ST(me) != PGEN_FAIL); }
117
118static PyObject *pfilt_pyint(PyObject *me)
119{
120 long l;
121 PyObject *rc = 0;
122
bc243788
MW
123 if (!mp_tolong_checked(PFILT_F(me)->m, &l, 0)) rc = PyInt_FromLong(l);
124 else rc = mp_topylong(PFILT_F(me)->m);
d7ab1bab 125 return (rc);
126}
127
f7623015 128#ifdef PY2
d7ab1bab 129static PyObject *pfilt_pylong(PyObject *me)
f368b46e 130 { return (mp_topylong(PFILT_F(me)->m)); }
f7623015 131#endif
d7ab1bab 132
133static PyObject *pfget_x(PyObject *me, void *hunoz)
134 { return (mp_pywrap(MP_COPY(PFILT_F(me)->m))); }
135
136static PyObject *pfget_status(PyObject *me, void *hunoz)
137 { return (PyInt_FromLong(PFILT_ST(me))); }
138
c90f712e 139static const PyGetSetDef pfilt_pygetset[] = {
d7ab1bab 140#define GETSETNAME(op, name) pf##op##_##name
141 GET (x, "F.x -> current position of filter")
142 GET (status, "F.status -> primality status of filter")
143#undef GETSETNAME
144 { 0 }
145};
146
c90f712e 147static const PyMethodDef pfilt_pymethods[] = {
d7ab1bab 148#define METHNAME(name) pfmeth_##name
149 METH (step, "F.step(N)")
150 METH (muladd, "F.muladd(M, A)")
151 METH (jump, "F.jump(FF)")
a157093f 152 SMTH (smallfactor, "smallfactor(X) -> PGST")
d7ab1bab 153#undef METHNAME
154 { 0 }
155};
156
c90f712e 157static const PyNumberMethods pfilt_pynumber = {
d7ab1bab 158 0, /* @nb_add@ */
159 0, /* @nb_subtract@ */
160 0, /* @nb_multiply@ */
f7623015 161#ifdef PY2
d7ab1bab 162 0, /* @nb_divide@ */
f7623015 163#endif
d7ab1bab 164 0, /* @nb_remainder@ */
165 0, /* @nb_divmod@ */
166 0, /* @nb_power@ */
167 0, /* @nb_negative@ */
168 0, /* @nb_positive@ */
169 0, /* @nb_absolute@ */
170 pfilt_pynonzerop, /* @nb_nonzero@ */
171 0, /* @nb_invert@ */
172 0, /* @nb_lshift@ */
173 0, /* @nb_rshift@ */
174 0, /* @nb_and@ */
175 0, /* @nb_xor@ */
176 0, /* @nb_or@ */
f7623015 177#ifdef PY2
d7ab1bab 178 0, /* @nb_coerce@ */
f7623015 179#endif
d7ab1bab 180 pfilt_pyint, /* @nb_int@ */
f7623015 181 PY23(pfilt_pylong, 0), /* @nb_long@ */
d7ab1bab 182 0, /* @nb_float@ */
f7623015 183#ifdef PY2
d7ab1bab 184 0, /* @nb_oct@ */
185 0, /* @nb_hex@ */
f7623015 186#endif
d7ab1bab 187
188 0, /* @nb_inplace_add@ */
189 0, /* @nb_inplace_subtract@ */
190 0, /* @nb_inplace_multiply@ */
f7623015 191#ifdef PY2
d7ab1bab 192 0, /* @nb_inplace_divide@ */
f7623015 193#endif
d7ab1bab 194 0, /* @nb_inplace_remainder@ */
195 0, /* @nb_inplace_power@ */
196 0, /* @nb_inplace_lshift@ */
197 0, /* @nb_inplace_rshift@ */
198 0, /* @nb_inplace_and@ */
199 0, /* @nb_inplace_xor@ */
200 0, /* @nb_inplace_or@ */
201
202 0, /* @nb_floor_divide@ */
203 0, /* @nb_true_divide@ */
204 0, /* @nb_inplace_floor_divide@ */
205 0, /* @nb_inplace_true_divide@ */
206};
207
c263b05c 208static const PyTypeObject pfilt_pytype_skel = {
591bf41b 209 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 210 "PrimeFilter", /* @tp_name@ */
d7ab1bab 211 sizeof(pfilt_pyobj), /* @tp_basicsize@ */
212 0, /* @tp_itemsize@ */
213
214 pfilt_pydealloc, /* @tp_dealloc@ */
215 0, /* @tp_print@ */
216 0, /* @tp_getattr@ */
217 0, /* @tp_setattr@ */
218 0, /* @tp_compare@ */
219 0, /* @tp_repr@ */
c90f712e 220 PYNUMBER(pfilt), /* @tp_as_number@ */
d7ab1bab 221 0, /* @tp_as_sequence@ */
222 0, /* @tp_as_mapping@ */
223 0, /* @tp_hash@ */
224 0, /* @tp_call@ */
225 0, /* @tp_str@ */
226 0, /* @tp_getattro@ */
227 0, /* @tp_setattro@ */
228 0, /* @tp_as_buffer@ */
229 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
230 Py_TPFLAGS_BASETYPE,
231
232 /* @tp_doc@ */
d96c882e 233 "PrimeFilter(X): small-primes filter.",
d7ab1bab 234
235 0, /* @tp_traverse@ */
236 0, /* @tp_clear@ */
237 0, /* @tp_richcompare@ */
238 0, /* @tp_weaklistoffset@ */
239 0, /* @tp_iter@ */
963a6148 240 0, /* @tp_iternext@ */
c90f712e 241 PYMETHODS(pfilt), /* @tp_methods@ */
d7ab1bab 242 0, /* @tp_members@ */
c90f712e 243 PYGETSET(pfilt), /* @tp_getset@ */
d7ab1bab 244 0, /* @tp_base@ */
245 0, /* @tp_dict@ */
246 0, /* @tp_descr_get@ */
247 0, /* @tp_descr_set@ */
248 0, /* @tp_dictoffset@ */
249 0, /* @tp_init@ */
250 PyType_GenericAlloc, /* @tp_alloc@ */
251 pfilt_pynew, /* @tp_new@ */
3aa33042 252 0, /* @tp_free@ */
d7ab1bab 253 0 /* @tp_is_gc@ */
254};
255
256/*----- Rabin-Miller testing ----------------------------------------------*/
257
258typedef struct rabin_pyobj {
259 PyObject_HEAD
260 rabin r;
261} rabin_pyobj;
262
263static PyTypeObject *rabin_pytype;
264#define RABIN_R(o) (&((rabin_pyobj *)(o))->r)
265
266static PyObject *rabin_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
267{
268 mp *x = 0;
269 rabin_pyobj *o = 0;
827f89d7 270 static const char *const kwlist[] = { "x", 0 };
d7ab1bab 271
827f89d7 272 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convmp, &x))
d7ab1bab 273 goto end;
274 if (!MP_POSP(x) || MP_EVENP(x)) VALERR("must be positive and odd");
275 o = (rabin_pyobj *)ty->tp_alloc(ty, 0);
276 rabin_create(&o->r, x);
277end:
278 return ((PyObject *)o);
279}
280
281static void rabin_pydealloc(PyObject *me)
282{
283 rabin_destroy(RABIN_R(me));
3aa33042 284 FREEOBJ(me);
d7ab1bab 285}
286
287static PyObject *rmeth_test(PyObject *me, PyObject *arg)
288{
289 mp *w = 0;
290 PyObject *rc = 0;
291
292 if (!PyArg_ParseTuple(arg, "O&:test", convmp, &w)) goto end;
293 rc = PyInt_FromLong(rabin_test(RABIN_R(me), w));
294end:
295 mp_drop(w);
296 return (rc);
297}
298
299static PyObject *rmeth_rtest(PyObject *me, PyObject *arg)
300{
301 mp *w = 0;
302 PyObject *rc = 0;
303
304 if (!PyArg_ParseTuple(arg, "O&:rtest", convmp, &w)) goto end;
305 rc = PyInt_FromLong(rabin_rtest(RABIN_R(me), w));
306end:
307 mp_drop(w);
308 return (rc);
309}
310
311static PyObject *rget_niters(PyObject *me, void *hunoz)
312 { return (PyInt_FromLong(rabin_iters(mp_bits(RABIN_R(me)->mm.m)))); }
313
314static PyObject *rget_x(PyObject *me, void *hunoz)
315 { return (mp_pywrap(MP_COPY(RABIN_R(me)->mm.m))); }
316
a157093f 317static PyObject *rmeth_iters(PyObject *me, PyObject *arg)
d7ab1bab 318{
319 unsigned n;
320
a157093f 321 if (!PyArg_ParseTuple(arg, "O&:iters", convuint, &n)) return (0);
d7ab1bab 322 return (PyInt_FromLong(rabin_iters(n)));
323}
324
c90f712e 325static const PyGetSetDef rabin_pygetset[] = {
d7ab1bab 326#define GETSETNAME(op, name) r##op##_##name
327 GET (x, "R.x -> number under test")
328 GET (niters, "R.niters -> suggested number of tests")
329#undef GETSETNAME
330 { 0 }
331};
332
c90f712e 333static const PyMethodDef rabin_pymethods[] = {
d7ab1bab 334#define METHNAME(name) rmeth_##name
335 METH (test, "R.test(W) -> PGST")
336 METH (rtest, "R.rtest(W) -> PGST")
a157093f 337 SMTH (iters, "iters(NBITS) -> NITERS")
d7ab1bab 338#undef METHNAME
339 { 0 }
340};
341
c263b05c 342static const PyTypeObject rabin_pytype_skel = {
591bf41b 343 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 344 "RabinMiller", /* @tp_name@ */
d7ab1bab 345 sizeof(rabin_pyobj), /* @tp_basicsize@ */
346 0, /* @tp_itemsize@ */
347
348 rabin_pydealloc, /* @tp_dealloc@ */
349 0, /* @tp_print@ */
350 0, /* @tp_getattr@ */
351 0, /* @tp_setattr@ */
352 0, /* @tp_compare@ */
353 0, /* @tp_repr@ */
354 0, /* @tp_as_number@ */
355 0, /* @tp_as_sequence@ */
356 0, /* @tp_as_mapping@ */
357 0, /* @tp_hash@ */
358 0, /* @tp_call@ */
359 0, /* @tp_str@ */
360 0, /* @tp_getattro@ */
361 0, /* @tp_setattro@ */
362 0, /* @tp_as_buffer@ */
363 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
364 Py_TPFLAGS_BASETYPE,
365
366 /* @tp_doc@ */
d96c882e 367 "RabinMiller(X): Rabin-Miller strong primality test.",
d7ab1bab 368
369 0, /* @tp_traverse@ */
370 0, /* @tp_clear@ */
371 0, /* @tp_richcompare@ */
372 0, /* @tp_weaklistoffset@ */
373 0, /* @tp_iter@ */
963a6148 374 0, /* @tp_iternext@ */
c90f712e 375 PYMETHODS(rabin), /* @tp_methods@ */
d7ab1bab 376 0, /* @tp_members@ */
c90f712e 377 PYGETSET(rabin), /* @tp_getset@ */
d7ab1bab 378 0, /* @tp_base@ */
379 0, /* @tp_dict@ */
380 0, /* @tp_descr_get@ */
381 0, /* @tp_descr_set@ */
382 0, /* @tp_dictoffset@ */
383 0, /* @tp_init@ */
384 PyType_GenericAlloc, /* @tp_alloc@ */
385 rabin_pynew, /* @tp_new@ */
3aa33042 386 0, /* @tp_free@ */
d7ab1bab 387 0 /* @tp_is_gc@ */
388};
389
390/*----- Events ------------------------------------------------------------*/
391
392typedef struct pgevent_pyobj {
393 PyObject_HEAD
d65d80d7 394 PyObject *r;
d7ab1bab 395 pgen_event *ev;
396} pgevent_pyobj;
397
398static PyTypeObject *pgevent_pytype;
399#define PGEVENT_EV(o) (((pgevent_pyobj *)(o))->ev)
400
401static PyObject *pgevent_pywrap(pgen_event *ev)
402{
403 pgevent_pyobj *o = PyObject_New(pgevent_pyobj, pgevent_pytype);
d65d80d7 404 o->ev = ev; o->r = 0;
d7ab1bab 405 return ((PyObject *)o);
406}
407
408static CONVFUNC(pgevent, pgen_event *, PGEVENT_EV)
409
d65d80d7
MW
410static void pgevent_kill(PyObject *me)
411{
412 pgevent_pyobj *ev = (pgevent_pyobj *)me;
413
414 ev->ev = 0;
415 if (ev->r) GRAND_R(ev->r) = 0;
416}
417
418static void pgevent_pydealloc(PyObject *me)
419{
420 pgevent_pyobj *ev = (pgevent_pyobj *)me;
19a4c416 421 Py_XDECREF(ev->r); FREEOBJ(me);
d65d80d7 422}
d7ab1bab 423
424#define PGEVENT_CHECK(me) do { \
425 if (!PGEVENT_EV(me)) { \
d65d80d7 426 PyErr_SetString(PyExc_ValueError, "event object is no longer valid"); \
d7ab1bab 427 return (0); \
428 } \
429} while (0)
430
431static PyObject *peget_name(PyObject *me, void *hunoz)
2135a6d3 432 { PGEVENT_CHECK(me); return (TEXT_FROMSTR(PGEVENT_EV(me)->name)); }
d7ab1bab 433
434static PyObject *peget_x(PyObject *me, void *hunoz)
435 { PGEVENT_CHECK(me); return (mp_pywrap(MP_COPY(PGEVENT_EV(me)->m))); }
436
437static PyObject *peget_steps(PyObject *me, void *hunoz)
438 { PGEVENT_CHECK(me); return (PyInt_FromLong(PGEVENT_EV(me)->steps)); }
439
440static PyObject *peget_tests(PyObject *me, void *hunoz)
441 { PGEVENT_CHECK(me); return (PyInt_FromLong(PGEVENT_EV(me)->tests)); }
442
443static PyObject *peget_rng(PyObject *me, void *hunoz)
d65d80d7
MW
444{
445 pgevent_pyobj *ev = (pgevent_pyobj *)me;
446
447 PGEVENT_CHECK(me);
448 if (!ev->r) ev->r = grand_pywrap(ev->ev->r, 0);
449 Py_INCREF(ev->r); return ((PyObject *)ev->r);
450}
d7ab1bab 451
452static int peset_x(PyObject *me, PyObject *xobj, void *hunoz)
453{
454 mp *x = 0;
455 pgen_event *ev = PGEVENT_EV(me);
456 int rc = -1;
03e1fedf 457 if (!xobj) NIERR("__del__");
d7ab1bab 458 PGEVENT_CHECK(me);
459 if ((x = getmp(xobj)) == 0) goto end;
460 mp_drop(ev->m);
461 ev->m = MP_COPY(x);
462 rc = 0;
463end:
464 mp_drop(x);
465 return (rc);
466}
467
c90f712e 468static const PyGetSetDef pgevent_pygetset[] = {
d7ab1bab 469#define GETSETNAME(op, name) pe##op##_##name
470 GET (name, "EV.name -> value being generated")
471 GETSET(x, "EV.x -> value under test")
472 GET (steps, "EV.steps -> number of steps left")
473 GET (tests, "EV.tests -> tests before passing")
474 GET (rng, "EV.rng -> (noncrypto) random number generator")
475#undef GETSETNAME
476 { 0 }
477};
478
c263b05c 479static const PyTypeObject pgevent_pytype_skel = {
591bf41b 480 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 481 "PrimeGenEvent", /* @tp_name@ */
d7ab1bab 482 sizeof(pgevent_pyobj), /* @tp_basicsize@ */
483 0, /* @tp_itemsize@ */
484
485 pgevent_pydealloc, /* @tp_dealloc@ */
486 0, /* @tp_print@ */
487 0, /* @tp_getattr@ */
488 0, /* @tp_setattr@ */
489 0, /* @tp_compare@ */
490 0, /* @tp_repr@ */
491 0, /* @tp_as_number@ */
492 0, /* @tp_as_sequence@ */
493 0, /* @tp_as_mapping@ */
494 0, /* @tp_hash@ */
495 0, /* @tp_call@ */
496 0, /* @tp_str@ */
497 0, /* @tp_getattro@ */
498 0, /* @tp_setattro@ */
499 0, /* @tp_as_buffer@ */
500 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
501 Py_TPFLAGS_BASETYPE,
502
503 /* @tp_doc@ */
d96c882e 504 "Prime-generation event.",
d7ab1bab 505
506 0, /* @tp_traverse@ */
507 0, /* @tp_clear@ */
508 0, /* @tp_richcompare@ */
509 0, /* @tp_weaklistoffset@ */
510 0, /* @tp_iter@ */
963a6148 511 0, /* @tp_iternext@ */
d7ab1bab 512 0, /* @tp_methods@ */
513 0, /* @tp_members@ */
c90f712e 514 PYGETSET(pgevent), /* @tp_getset@ */
d7ab1bab 515 0, /* @tp_base@ */
516 0, /* @tp_dict@ */
517 0, /* @tp_descr_get@ */
518 0, /* @tp_descr_set@ */
519 0, /* @tp_dictoffset@ */
520 0, /* @tp_init@ */
521 PyType_GenericAlloc, /* @tp_alloc@ */
522 abstract_pynew, /* @tp_new@ */
3aa33042 523 0, /* @tp_free@ */
d7ab1bab 524 0 /* @tp_is_gc@ */
525};
526
527/*----- Event handlers ----------------------------------------------------*/
528
529PyTypeObject *pgev_pytype;
530
531typedef struct pgstep_pyobj {
532 PGEV_HEAD
533 pgen_filterctx f;
534} pgstep_pyobj;
535
536static PyTypeObject *pgstep_pytype;
537#define PGSTEP_STEP(o) (((pgstep_pyobj *)(o))->f.step)
538
539typedef struct pgjump_pyobj {
540 PGEV_HEAD
541 PyObject *fobj;
542 pgen_jumpctx j;
543} pgjump_pyobj;
544
545static PyTypeObject *pgjump_pytype;
546#define PGJUMP_FOBJ(o) (((pgjump_pyobj *)(o))->fobj)
547#define PGJUMP_J(o) (&((pgjump_pyobj *)(o))->j)
548
549typedef struct pgtest_pyobj {
550 PGEV_HEAD
551 rabin r;
552} pgtest_pyobj;
553
554static PyTypeObject *pgtest_pytype;
555
556static int pgev_python(int rq, pgen_event *ev, void *p)
557{
930d78e3 558 pypgev *pg = p;
d7ab1bab 559 PyObject *pyev = 0;
560 PyObject *rc = 0;
561 int st = PGEN_ABORT;
562 long l;
827f89d7
MW
563 static const char *const meth[] =
564 { "pg_abort", "pg_done", "pg_begin", "pg_try", "pg_fail", "pg_pass" };
d7ab1bab 565
d7ab1bab 566 rq++;
567 if (rq > N(meth)) SYSERR("event code out of range");
568 pyev = pgevent_pywrap(ev);
7f38dc76 569 if ((rc = PyObject_CallMethod(pg->obj, (/*unconst*/ char *)meth[rq],
827f89d7 570 "(O)", pyev)) == 0)
d7ab1bab 571 goto end;
572 if (rc == Py_None)
573 st = PGEN_TRY;
574 else if ((l = PyInt_AsLong(rc)) == -1 && PyErr_Occurred())
575 goto end;
576 else if (l < PGEN_ABORT || l > PGEN_PASS)
577 VALERR("return code out of range");
b2687a0a 578 else
d7ab1bab 579 st = l;
580end:
930d78e3
MW
581 if (PyErr_Occurred())
582 stash_exception(pg->exc, "exception from `pgen' handler");
d7ab1bab 583 if (pyev) {
584 pgevent_kill(pyev);
585 Py_DECREF(pyev);
586 }
587 Py_XDECREF(rc);
d7ab1bab 588 return (st);
589}
590
591static PyObject *pgev_pywrap(const pgev *pg)
592{
593 pgev_pyobj *o;
594
595 o = PyObject_New(pgev_pyobj, pgev_pytype);
596 o->pg = *pg;
597 return ((PyObject *)o);
598}
599
600int convpgev(PyObject *o, void *p)
601{
930d78e3 602 pypgev *pg = p;
d7ab1bab 603
604 if (PGEV_PYCHECK(o))
930d78e3 605 pg->ev = *PGEV_PG(o);
d7ab1bab 606 else {
930d78e3
MW
607 pg->ev.proc = pgev_python;
608 pg->ev.ctx = pg;
609 pg->obj = o; Py_INCREF(o);
d7ab1bab 610 }
611 return (1);
612}
613
930d78e3 614void droppgev(pypgev *pg)
d7ab1bab 615{
930d78e3
MW
616 if (pg->ev.proc == pgev_python)
617 { assert(pg->ev.ctx == pg); Py_DECREF(pg->obj); }
d7ab1bab 618}
619
620static PyObject *pgmeth_common(PyObject *me, PyObject *arg, int rq)
621{
622 pgen_event *ev;
623 pgev *pg = PGEV_PG(me);
624 PyObject *rc = 0;
625
626 if (!PyArg_ParseTuple(arg, "O&", convpgevent, &ev)) goto end;
627 rc = PyInt_FromLong(!pg->proc ? rq : pg->proc(rq, ev, pg->ctx));
628end:
629 return (rc);
630}
631
632#define PGMETH(lc, uc) \
633 static PyObject *pgmeth_pg_##lc(PyObject *me, PyObject *arg) \
634 { return pgmeth_common(me, arg, PGEN_##uc); }
635PGMETH(abort, ABORT)
636PGMETH(done, DONE)
637PGMETH(begin, BEGIN)
638PGMETH(try, TRY)
639PGMETH(pass, PASS)
640PGMETH(fail, FAIL)
641#undef PGMETH
642
643static PyObject *pgev_stdev(pgen_proc *proc)
644 { pgev pg; pg.proc = proc; pg.ctx = 0; return (pgev_pywrap(&pg)); }
645
c90f712e 646static const PyMethodDef pgev_pymethods[] = {
d7ab1bab 647#define METHNAME(name) pgmeth_##name
fb23e96c
MW
648 METH (pg_abort, "E.pg_abort(EV) -> PGST -- prime generation aborted")
649 METH (pg_done, "E.pg_done(EV) -> PGST -- prime generation finished")
650 METH (pg_begin, "E.pg_begin(EV) -> PGST -- commence stepping/testing")
651 METH (pg_try, "E.pg_try(EV) -> PGST -- found new candidate")
652 METH (pg_pass, "E.pg_pass(EV) -> PGST -- passed primality test")
653 METH (pg_fail, "E.pg_fail(EV) -> PGST -- failed primality test")
d7ab1bab 654#undef METHNAME
655 { 0 }
656};
657
c263b05c 658static const PyTypeObject pgev_pytype_skel = {
591bf41b 659 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 660 "PrimeGenBuiltinHandler", /* @tp_name@ */
d7ab1bab 661 sizeof(pgev_pyobj), /* @tp_basicsize@ */
662 0, /* @tp_itemsize@ */
663
3aa33042 664 0, /* @tp_dealloc@ */
d7ab1bab 665 0, /* @tp_print@ */
666 0, /* @tp_getattr@ */
667 0, /* @tp_setattr@ */
668 0, /* @tp_compare@ */
669 0, /* @tp_repr@ */
670 0, /* @tp_as_number@ */
671 0, /* @tp_as_sequence@ */
672 0, /* @tp_as_mapping@ */
673 0, /* @tp_hash@ */
674 0, /* @tp_call@ */
675 0, /* @tp_str@ */
676 0, /* @tp_getattro@ */
677 0, /* @tp_setattro@ */
678 0, /* @tp_as_buffer@ */
679 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
680 Py_TPFLAGS_BASETYPE,
681
682 /* @tp_doc@ */
d96c882e 683 "Built-in prime-generation event handler, base class.",
d7ab1bab 684
685 0, /* @tp_traverse@ */
686 0, /* @tp_clear@ */
687 0, /* @tp_richcompare@ */
688 0, /* @tp_weaklistoffset@ */
689 0, /* @tp_iter@ */
963a6148 690 0, /* @tp_iternext@ */
c90f712e 691 PYMETHODS(pgev), /* @tp_methods@ */
d7ab1bab 692 0, /* @tp_members@ */
693 0, /* @tp_getset@ */
694 0, /* @tp_base@ */
695 0, /* @tp_dict@ */
696 0, /* @tp_descr_get@ */
697 0, /* @tp_descr_set@ */
698 0, /* @tp_dictoffset@ */
699 0, /* @tp_init@ */
700 PyType_GenericAlloc, /* @tp_alloc@ */
701 abstract_pynew, /* @tp_new@ */
3aa33042 702 0, /* @tp_free@ */
d7ab1bab 703 0 /* @tp_is_gc@ */
704};
705
706static PyObject *pgstep_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
707{
708 mpw s;
709 pgstep_pyobj *rc = 0;
827f89d7 710 static const char *const kwlist[] = { "step", 0 };
d7ab1bab 711
827f89d7 712 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convmpw, &s))
d7ab1bab 713 goto end;
714 rc = (pgstep_pyobj *)ty->tp_alloc(ty, 0);
715 rc->f.step = s;
716 rc->pg.proc = pgen_filter;
717 rc->pg.ctx = &rc->f;
718end:
719 return ((PyObject *)rc);
720}
721
722static PyObject *psget_step(PyObject *me, void *hunoz)
723 { return (PyInt_FromLong(PGSTEP_STEP(me))); }
724
c90f712e 725static const PyGetSetDef pgstep_pygetset[] = {
d7ab1bab 726#define GETSETNAME(op, name) ps##op##_##name
b2687a0a 727 GET (step, "S.step -> step size for the stepper")
d7ab1bab 728#undef GETSETNAME
729 { 0 }
730};
731
c263b05c 732static const PyTypeObject pgstep_pytype_skel = {
591bf41b 733 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 734 "PrimeGenStepper", /* @tp_name@ */
d7ab1bab 735 sizeof(pgstep_pyobj), /* @tp_basicsize@ */
736 0, /* @tp_itemsize@ */
737
738 0, /* @tp_dealloc@ */
739 0, /* @tp_print@ */
740 0, /* @tp_getattr@ */
741 0, /* @tp_setattr@ */
742 0, /* @tp_compare@ */
743 0, /* @tp_repr@ */
744 0, /* @tp_as_number@ */
745 0, /* @tp_as_sequence@ */
746 0, /* @tp_as_mapping@ */
747 0, /* @tp_hash@ */
748 0, /* @tp_call@ */
749 0, /* @tp_str@ */
750 0, /* @tp_getattro@ */
751 0, /* @tp_setattro@ */
752 0, /* @tp_as_buffer@ */
753 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
754 Py_TPFLAGS_BASETYPE,
755
756 /* @tp_doc@ */
d96c882e 757 "PrimeGenStepper(STEP): simple stepper with small-factors filter.",
d7ab1bab 758
759 0, /* @tp_traverse@ */
760 0, /* @tp_clear@ */
761 0, /* @tp_richcompare@ */
762 0, /* @tp_weaklistoffset@ */
763 0, /* @tp_iter@ */
963a6148 764 0, /* @tp_iternext@ */
d7ab1bab 765 0, /* @tp_methods@ */
766 0, /* @tp_members@ */
c90f712e 767 PYGETSET(pgstep), /* @tp_getset@ */
d7ab1bab 768 0, /* @tp_base@ */
769 0, /* @tp_dict@ */
770 0, /* @tp_descr_get@ */
771 0, /* @tp_descr_set@ */
772 0, /* @tp_dictoffset@ */
773 0, /* @tp_init@ */
774 PyType_GenericAlloc, /* @tp_alloc@ */
775 pgstep_pynew, /* @tp_new@ */
3aa33042 776 0, /* @tp_free@ */
d7ab1bab 777 0 /* @tp_is_gc@ */
778};
779
780static PyObject *pgjump_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
781{
782 PyObject *o, *fobj;
783 pgjump_pyobj *rc = 0;
827f89d7 784 static const char *const kwlist[] = { "jump", 0 };
d7ab1bab 785
827f89d7 786 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", KWLIST, &o) ||
d7ab1bab 787 (fobj = pfilt_pymake(pfilt_pytype, o)) == 0)
788 goto end;
789 rc = (pgjump_pyobj *)ty->tp_alloc(ty, 0);
790 rc->fobj = fobj;
791 rc->j.j = PFILT_F(fobj);
792 rc->pg.proc = pgen_jump;
793 rc->pg.ctx = &rc->j;
794end:
795 return ((PyObject *)rc);
796}
797
798static void pgjump_pydealloc(PyObject *me)
799{
800 Py_DECREF(PGJUMP_FOBJ(me));
3aa33042 801 FREEOBJ(me);
d7ab1bab 802}
803
804static PyObject *pjget_jump(PyObject *me, void *hunoz)
805 { RETURN_OBJ(PGJUMP_FOBJ(me)); }
806
c90f712e 807static const PyGetSetDef pgjump_pygetset[] = {
d7ab1bab 808#define GETSETNAME(op, name) pj##op##_##name
b2687a0a 809 GET (jump, "S.jump -> jump size for the stepper")
d7ab1bab 810#undef GETSETNAME
811 { 0 }
812};
813
c263b05c 814static const PyTypeObject pgjump_pytype_skel = {
591bf41b 815 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 816 "PrimeGenJumper", /* @tp_name@ */
d7ab1bab 817 sizeof(pgjump_pyobj), /* @tp_basicsize@ */
818 0, /* @tp_itemsize@ */
819
820 pgjump_pydealloc, /* @tp_dealloc@ */
821 0, /* @tp_print@ */
822 0, /* @tp_getattr@ */
823 0, /* @tp_setattr@ */
824 0, /* @tp_compare@ */
825 0, /* @tp_repr@ */
826 0, /* @tp_as_number@ */
827 0, /* @tp_as_sequence@ */
828 0, /* @tp_as_mapping@ */
829 0, /* @tp_hash@ */
830 0, /* @tp_call@ */
831 0, /* @tp_str@ */
832 0, /* @tp_getattro@ */
833 0, /* @tp_setattro@ */
834 0, /* @tp_as_buffer@ */
835 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
836 Py_TPFLAGS_BASETYPE,
837
838 /* @tp_doc@ */
d96c882e
MW
839 "PrimeGenJumper(JUMP): "
840 "stepper for larger steps with small-factors filter.",
d7ab1bab 841
842 0, /* @tp_traverse@ */
843 0, /* @tp_clear@ */
844 0, /* @tp_richcompare@ */
845 0, /* @tp_weaklistoffset@ */
846 0, /* @tp_iter@ */
963a6148 847 0, /* @tp_iternext@ */
d7ab1bab 848 0, /* @tp_methods@ */
849 0, /* @tp_members@ */
c90f712e 850 PYGETSET(pgjump), /* @tp_getset@ */
d7ab1bab 851 0, /* @tp_base@ */
852 0, /* @tp_dict@ */
853 0, /* @tp_descr_get@ */
854 0, /* @tp_descr_set@ */
855 0, /* @tp_dictoffset@ */
856 0, /* @tp_init@ */
857 PyType_GenericAlloc, /* @tp_alloc@ */
858 pgjump_pynew, /* @tp_new@ */
3aa33042 859 0, /* @tp_free@ */
d7ab1bab 860 0 /* @tp_is_gc@ */
861};
862
863static PyObject *pgtest_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
864{
865 pgtest_pyobj *rc = 0;
827f89d7 866 static const char *const kwlist[] = { 0 };
d7ab1bab 867
827f89d7 868 if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", KWLIST)) goto end;
d7ab1bab 869 rc = (pgtest_pyobj *)ty->tp_alloc(ty, 0);
870 rc->pg.proc = pgen_test;
871 rc->pg.ctx = &rc->r;
872end:
873 return ((PyObject *)rc);
874}
875
c263b05c 876static const PyTypeObject pgtest_pytype_skel = {
591bf41b 877 PyVarObject_HEAD_INIT(0, 0) /* Header */
c461c9b3 878 "PrimeGenTester", /* @tp_name@ */
d7ab1bab 879 sizeof(pgtest_pyobj), /* @tp_basicsize@ */
880 0, /* @tp_itemsize@ */
881
882 0, /* @tp_dealloc@ */
883 0, /* @tp_print@ */
884 0, /* @tp_getattr@ */
885 0, /* @tp_setattr@ */
886 0, /* @tp_compare@ */
887 0, /* @tp_repr@ */
888 0, /* @tp_as_number@ */
889 0, /* @tp_as_sequence@ */
890 0, /* @tp_as_mapping@ */
891 0, /* @tp_hash@ */
892 0, /* @tp_call@ */
893 0, /* @tp_str@ */
894 0, /* @tp_getattro@ */
895 0, /* @tp_setattro@ */
896 0, /* @tp_as_buffer@ */
897 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
898 Py_TPFLAGS_BASETYPE,
899
900 /* @tp_doc@ */
d96c882e 901 "PrimeGenTester(): Rabin-Miller tester.",
d7ab1bab 902
903 0, /* @tp_traverse@ */
904 0, /* @tp_clear@ */
905 0, /* @tp_richcompare@ */
906 0, /* @tp_weaklistoffset@ */
907 0, /* @tp_iter@ */
963a6148 908 0, /* @tp_iternext@ */
d7ab1bab 909 0, /* @tp_methods@ */
910 0, /* @tp_members@ */
911 0, /* @tp_getset@ */
912 0, /* @tp_base@ */
913 0, /* @tp_dict@ */
914 0, /* @tp_descr_get@ */
915 0, /* @tp_descr_set@ */
916 0, /* @tp_dictoffset@ */
917 0, /* @tp_init@ */
918 PyType_GenericAlloc, /* @tp_alloc@ */
919 pgtest_pynew, /* @tp_new@ */
3aa33042 920 0, /* @tp_free@ */
d7ab1bab 921 0 /* @tp_is_gc@ */
922};
923
2b08f130
MW
924/*----- Prime iteration ---------------------------------------------------*/
925
926static PyTypeObject *piter_pytype;
927
928typedef struct piter_pyobj {
929 PyObject_HEAD
930 primeiter i;
931} piter_pyobj;
932#define PITER_I(o) (&((piter_pyobj *)(o))->i)
933
934static PyObject *piter_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
935{
936 piter_pyobj *rc;
937 mp *n = 0;
938 static const char *const kwlist[] = { "start", 0 };
939
940 if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", KWLIST, convmp, &n))
941 return (0);
942 rc = (piter_pyobj *)ty->tp_alloc(ty, 0);
943 primeiter_create(&rc->i, n);
944 return ((PyObject *)rc);
945}
946
947static void piter_pydealloc(PyObject *me)
948 { primeiter_destroy(PITER_I(me)); FREEOBJ(me); }
949
950static PyObject *piter_pynext(PyObject *me)
951 { return (mp_pywrap(primeiter_next(PITER_I(me), 0))); }
952
953static const PyTypeObject piter_pytype_skel = {
954 PyVarObject_HEAD_INIT(0, 0) /* Header */
955 "PrimeIter", /* @tp_name@ */
956 sizeof(piter_pyobj), /* @tp_basicsize@ */
957 0, /* @tp_itemsize@ */
958
959 piter_pydealloc, /* @tp_dealloc@ */
960 0, /* @tp_print@ */
961 0, /* @tp_getattr@ */
962 0, /* @tp_setattr@ */
963 0, /* @tp_compare@ */
964 0, /* @tp_repr@ */
965 0, /* @tp_as_number@ */
966 0, /* @tp_as_sequence@ */
967 0, /* @tp_as_mapping@ */
968 0, /* @tp_hash@ */
969 0, /* @tp_call@ */
970 0, /* @tp_str@ */
971 0, /* @tp_getattro@ */
972 0, /* @tp_setattro@ */
973 0, /* @tp_as_buffer@ */
974 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
975 Py_TPFLAGS_BASETYPE,
976
977 /* @tp_doc@ */
978 "PrimeIter([start = N]): Prime-number iterator.",
979
980 0, /* @tp_traverse@ */
981 0, /* @tp_clear@ */
982 0, /* @tp_richcompare@ */
983 0, /* @tp_weaklistoffset@ */
984 PyObject_SelfIter, /* @tp_iter@ */
985 piter_pynext, /* @tp_iternext@ */
986 0, /* @tp_methods@ */
987 0, /* @tp_members@ */
988 0, /* @tp_getset@ */
989 0, /* @tp_base@ */
990 0, /* @tp_dict@ */
991 0, /* @tp_descr_get@ */
992 0, /* @tp_descr_set@ */
993 0, /* @tp_dictoffset@ */
994 0, /* @tp_init@ */
995 PyType_GenericAlloc, /* @tp_alloc@ */
996 piter_pynew, /* @tp_new@ */
997 0, /* @tp_free@ */
998 0 /* @tp_is_gc@ */
999};
1000
d7ab1bab 1001/*----- Prime generation functions ----------------------------------------*/
1002
930d78e3 1003void pgenerr(struct excinfo *exc)
d7ab1bab 1004{
930d78e3
MW
1005 if (exc->ty) RESTORE_EXCINFO(exc);
1006 else PyErr_SetString(PyExc_ValueError, "prime generation failed");
d7ab1bab 1007}
1008
1009static PyObject *meth_pgen(PyObject *me, PyObject *arg, PyObject *kw)
1010{
1011 mp *x = 0;
1012 mp *r = 0;
1013 PyObject *rc = 0;
1014 char *p = "p";
1015 pgen_filterctx fc = { 2 };
1016 rabin tc;
930d78e3
MW
1017 struct excinfo exc = EXCINFO_INIT;
1018 pypgev step = { { 0 } }, test = { { 0 } }, evt = { { 0 } };
d7ab1bab 1019 unsigned nsteps = 0, ntests = 0;
827f89d7
MW
1020 static const char *const kwlist[] =
1021 { "start", "name", "stepper", "tester", "event", "nsteps", "ntests", 0 };
d7ab1bab 1022
930d78e3
MW
1023 step.exc = &exc; step.ev.proc = pgen_filter; step.ev.ctx = &fc;
1024 test.exc = &exc; test.ev.proc = pgen_test; test.ev.ctx = &tc;
1025 evt.exc = &exc;
827f89d7 1026 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&O&O&:pgen", KWLIST,
d7ab1bab 1027 convmp, &x, &p, convpgev, &step,
1028 convpgev, &test, convpgev, &evt,
1029 convuint, &nsteps, convuint, &ntests))
1030 goto end;
1031 if (!ntests) ntests = rabin_iters(mp_bits(x));
930d78e3
MW
1032 if ((r = pgen(p, MP_NEW, x, evt.ev.proc, evt.ev.ctx,
1033 nsteps, step.ev.proc, step.ev.ctx,
1034 ntests, test.ev.proc, test.ev.ctx)) == 0)
1035 PGENERR(&exc);
1036 rc = mp_pywrap(r); r = 0;
d7ab1bab 1037end:
1038 mp_drop(r); mp_drop(x);
1039 droppgev(&step); droppgev(&test); droppgev(&evt);
b2687a0a 1040 return (rc);
d7ab1bab 1041}
1042
1043static PyObject *meth_strongprime_setup(PyObject *me,
1044 PyObject *arg, PyObject *kw)
1045{
1046 mp *x = 0;
1047 pfilt f;
1048 grand *r = &rand_global;
1049 unsigned nbits;
1050 char *name = "p";
1051 unsigned n = 0;
930d78e3
MW
1052 struct excinfo exc = EXCINFO_INIT;
1053 pypgev evt = { { 0 } };
d7ab1bab 1054 PyObject *rc = 0;
827f89d7
MW
1055 static const char *const kwlist[] =
1056 { "nbits", "name", "event", "rng", "nsteps", 0 };
d7ab1bab 1057
930d78e3 1058 evt.exc = &exc;
827f89d7 1059 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", KWLIST,
d7ab1bab 1060 convuint, &nbits, &name,
1061 convpgev, &evt, convgrand, &r,
1062 convuint, &n))
1063 goto end;
1064 if ((x = strongprime_setup(name, MP_NEW, &f, nbits,
930d78e3
MW
1065 r, n, evt.ev.proc, evt.ev.ctx)) == 0)
1066 PGENERR(&exc);
d7ab1bab 1067 rc = Py_BuildValue("(NN)", mp_pywrap(x), pfilt_pywrap(&f));
1068 x = 0;
1069end:
1070 mp_drop(x);
1071 droppgev(&evt);
1072 return (rc);
1073}
1074
1075static PyObject *meth_strongprime(PyObject *me, PyObject *arg, PyObject *kw)
1076{
1077 mp *x = 0;
1078 grand *r = &rand_global;
1079 unsigned nbits;
1080 char *name = "p";
1081 unsigned n = 0;
930d78e3
MW
1082 struct excinfo exc = EXCINFO_INIT;
1083 pypgev evt = { { 0 } };
d7ab1bab 1084 PyObject *rc = 0;
827f89d7
MW
1085 static const char *const kwlist[] =
1086 { "nbits", "name", "event", "rng", "nsteps", 0 };
d7ab1bab 1087
930d78e3 1088 evt.exc = &exc;
827f89d7 1089 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", KWLIST,
d7ab1bab 1090 convuint, &nbits, &name,
1091 convpgev, &evt, convgrand, &r,
1092 convuint, &n))
1093 goto end;
1094 if ((x = strongprime(name, MP_NEW, nbits,
930d78e3
MW
1095 r, n, evt.ev.proc, evt.ev.ctx)) == 0)
1096 PGENERR(&exc);
d7ab1bab 1097 rc = mp_pywrap(x);
1098 x = 0;
1099end:
1100 mp_drop(x);
1101 droppgev(&evt);
1102 return (rc);
1103}
1104
1105static PyObject *meth_limlee(PyObject *me, PyObject *arg, PyObject *kw)
1106{
1107 char *p = "p";
930d78e3
MW
1108 struct excinfo exc = EXCINFO_INIT;
1109 pypgev ie = { { 0 } }, oe = { { 0 } };
d7ab1bab 1110 unsigned ql, pl;
1111 grand *r = &rand_global;
1112 unsigned on = 0;
1113 size_t i, nf = 0;
1114 PyObject *rc = 0, *vec;
827f89d7
MW
1115 static const char *const kwlist[] =
1116 { "pbits", "qbits", "name", "event", "ievent", "rng", "nsteps", 0 };
d7ab1bab 1117 mp *x = 0, **v = 0;
1118
930d78e3 1119 ie.exc = oe.exc = &exc;
827f89d7 1120 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|sO&O&O&O&:limlee", KWLIST,
d7ab1bab 1121 convuint, &pl, convuint, &ql,
1122 &p, convpgev, &oe, convpgev, &ie,
1123 convgrand, &r, convuint, &on))
1124 goto end;
1125 if ((x = limlee(p, MP_NEW, MP_NEW, ql, pl, r, on,
930d78e3
MW
1126 oe.ev.proc, oe.ev.ctx, ie.ev.proc, ie.ev.ctx,
1127 &nf, &v)) == 0)
1128 PGENERR(&exc);;
d7ab1bab 1129 vec = PyList_New(nf);
1130 for (i = 0; i < nf; i++)
c51a597d 1131 PyList_SET_ITEM(vec, i, mp_pywrap(v[i]));
d7ab1bab 1132 xfree(v);
1133 rc = Py_BuildValue("(NN)", mp_pywrap(x), vec);
1134end:
1135 droppgev(&oe); droppgev(&ie);
1136 return (rc);
1137}
1138
1139/*----- Global stuff ------------------------------------------------------*/
1140
810542b0
MW
1141static const struct nameval consts[] = {
1142 CONST(PGEN_PASS), CONST(PGEN_FAIL), CONST(PGEN_BEGIN), CONST(PGEN_TRY),
1143 CONST(PGEN_DONE), CONST(PGEN_ABORT),
1144 { 0 }
1145};
1146
c90f712e 1147static const PyMethodDef methods[] = {
d7ab1bab 1148#define METHNAME(name) meth_##name
d96c882e
MW
1149 KWMETH(pgen,
1150 "pgen(START, [name = 'p'], [stepper = PrimeGenStepper(2)],\n"
1151 " [tester = PrimeGenTester()], [event = pgen_nullev],\n"
1152 " [nsteps = 0], [ntests = RabinMiller.iters(START.nbits)]) -> P")
1153 KWMETH(strongprime_setup,
1154 "strongprime_setup(NBITS, [name = 'p'], [event = pgen_nullev],\n"
1155 " [rng = rand], [nsteps = 0]) -> (START, JUMP)")
1156 KWMETH(strongprime,
1157 "strongprime(NBITS, [name = 'p'], [event = pgen_nullev],\n"
1158 " [rng = rand], [nsteps = 0]) -> P")
1159 KWMETH(limlee,
1160 "limlee(PBITS, QBITS, [name = 'p'], [event = pgen_nullev],\n"
1161 " [ievent = pgen_nullev], [rng = rand], [nsteps = 0]) "
1162 "-> (P, [Q, ...])")
d7ab1bab 1163#undef METHNAME
1164 { 0 }
1165};
1166
1167void pgen_pyinit(void)
1168{
1169 INITTYPE(pfilt, root);
1170 INITTYPE(rabin, root);
1171 INITTYPE(pgevent, root);
1172 INITTYPE(pgev, root);
1173 INITTYPE(pgstep, pgev);
1174 INITTYPE(pgjump, pgev);
1175 INITTYPE(pgtest, pgev);
2b08f130 1176 INITTYPE(piter, root);
d7ab1bab 1177 addmethods(methods);
1178}
1179
d7ab1bab 1180void pgen_pyinsert(PyObject *mod)
1181{
1182 INSERT("PrimeFilter", pfilt_pytype);
1183 INSERT("RabinMiller", rabin_pytype);
1184 INSERT("PrimeGenEvent", pgevent_pytype);
1185 INSERT("PrimeGenBuiltinHandler", pgev_pytype);
1186 INSERT("PrimeGenStepper", pgstep_pytype);
1187 INSERT("PrimeGenJumper", pgjump_pytype);
1188 INSERT("PrimeGenTester", pgtest_pytype);
416fd58f 1189 INSERT("pgen_nullev", pgev_stdev(0));
d7ab1bab 1190 INSERT("pgen_stdev", pgev_stdev(pgen_ev));
1191 INSERT("pgen_spinev", pgev_stdev(pgen_evspin));
1192 INSERT("pgen_subev", pgev_stdev(pgen_subev));
2b08f130 1193 INSERT("PrimeIter", piter_pytype);
810542b0 1194 setconstants(mod, consts);
d7ab1bab 1195}
1196
1197/*----- That's all, folks -------------------------------------------------*/