chiark / gitweb /
Split 'pyke/' into commit 'e5aa77d831ad8b42167f3205ee290f238003e20a'
[catacomb-python] / pgen.c
1 /* -*-c-*-
2  *
3  * Prime number generation
4  *
5  * (c) 2005 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
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.
16  *
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.
21  *
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
33 PyTypeObject *pfilt_pytype;
34
35 static 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);
41   return ((PyObject *)o);
42 }
43
44 static 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);
53 end:
54   mp_drop(x);
55   return ((PyObject *)o);
56 }
57
58 static PyObject *pfilt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
59 {
60   static const char *const kwlist[] = { "x", 0 };
61   PyObject *xobj;
62
63   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", KWLIST, &xobj))
64     return (0);
65   return (pfilt_pymake(ty, xobj));
66 }
67
68 static void pfilt_pydealloc(PyObject *me)
69   { pfilt_destroy(PFILT_F(me)); FREEOBJ(me); }
70
71 static 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
80 static 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
92 static CONVFUNC(pfilt, pfilt *, PFILT_F)
93
94 static 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
103 static PyObject *pfmeth_smallfactor(PyObject *me, PyObject *arg)
104 {
105   mp *x = 0;
106   PyObject *rc = 0;
107
108   if (!PyArg_ParseTuple(arg, "O&:smallfactor", convmp, &x)) goto end;
109   rc = PyInt_FromLong(pfilt_smallfactor(x));
110 end:
111   mp_drop(x);
112   return (rc);
113 }
114
115 static int pfilt_pynonzerop(PyObject *me)
116   { return (PFILT_ST(me) != PGEN_FAIL); }
117
118 static PyObject *pfilt_pyint(PyObject *me)
119 {
120   long l;
121   PyObject *rc = 0;
122
123   if (!mp_tolong_checked(PFILT_F(me)->m, &l, 0)) rc = PyInt_FromLong(l);
124   else rc = mp_topylong(PFILT_F(me)->m);
125   return (rc);
126 }
127
128 #ifdef PY2
129 static PyObject *pfilt_pylong(PyObject *me)
130   { return (mp_topylong(PFILT_F(me)->m)); }
131 #endif
132
133 static PyObject *pfget_x(PyObject *me, void *hunoz)
134   { return (mp_pywrap(MP_COPY(PFILT_F(me)->m))); }
135
136 static PyObject *pfget_status(PyObject *me, void *hunoz)
137   { return (PyInt_FromLong(PFILT_ST(me))); }
138
139 static const PyGetSetDef pfilt_pygetset[] = {
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
147 static const PyMethodDef pfilt_pymethods[] = {
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)")
152   SMTH  (smallfactor,   "smallfactor(X) -> PGST")
153 #undef METHNAME
154   { 0 }
155 };
156
157 static const PyNumberMethods pfilt_pynumber = {
158   0,                                    /* @nb_add@ */
159   0,                                    /* @nb_subtract@ */
160   0,                                    /* @nb_multiply@ */
161 #ifdef PY2
162   0,                                    /* @nb_divide@ */
163 #endif
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@ */
177 #ifdef PY2
178   0,                                    /* @nb_coerce@ */
179 #endif
180   pfilt_pyint,                          /* @nb_int@ */
181   PY23(pfilt_pylong, 0),                /* @nb_long@ */
182   0,                                    /* @nb_float@ */
183 #ifdef PY2
184   0,                                    /* @nb_oct@ */
185   0,                                    /* @nb_hex@ */
186 #endif
187
188   0,                                    /* @nb_inplace_add@ */
189   0,                                    /* @nb_inplace_subtract@ */
190   0,                                    /* @nb_inplace_multiply@ */
191 #ifdef PY2
192   0,                                    /* @nb_inplace_divide@ */
193 #endif
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
208 static const PyTypeObject pfilt_pytype_skel = {
209   PyVarObject_HEAD_INIT(0, 0)           /* Header */
210   "PrimeFilter",                        /* @tp_name@ */
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@ */
220   PYNUMBER(pfilt),                      /* @tp_as_number@ */
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@ */
233   "PrimeFilter(X): small-primes filter.",
234
235   0,                                    /* @tp_traverse@ */
236   0,                                    /* @tp_clear@ */
237   0,                                    /* @tp_richcompare@ */
238   0,                                    /* @tp_weaklistoffset@ */
239   0,                                    /* @tp_iter@ */
240   0,                                    /* @tp_iternext@ */
241   PYMETHODS(pfilt),                     /* @tp_methods@ */
242   0,                                    /* @tp_members@ */
243   PYGETSET(pfilt),                      /* @tp_getset@ */
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@ */
252   0,                                    /* @tp_free@ */
253   0                                     /* @tp_is_gc@ */
254 };
255
256 /*----- Rabin-Miller testing ----------------------------------------------*/
257
258 typedef struct rabin_pyobj {
259   PyObject_HEAD
260   rabin r;
261 } rabin_pyobj;
262
263 static PyTypeObject *rabin_pytype;
264 #define RABIN_R(o) (&((rabin_pyobj *)(o))->r)
265
266 static PyObject *rabin_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
267 {
268   mp *x = 0;
269   rabin_pyobj *o = 0;
270   static const char *const kwlist[] = { "x", 0 };
271
272   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convmp, &x))
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);
277 end:
278   return ((PyObject *)o);
279 }
280
281 static void rabin_pydealloc(PyObject *me)
282 {
283   rabin_destroy(RABIN_R(me));
284   FREEOBJ(me);
285 }
286
287 static 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));
294 end:
295   mp_drop(w);
296   return (rc);
297 }
298
299 static 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));
306 end:
307   mp_drop(w);
308   return (rc);
309 }
310
311 static PyObject *rget_niters(PyObject *me, void *hunoz)
312   { return (PyInt_FromLong(rabin_iters(mp_bits(RABIN_R(me)->mm.m)))); }
313
314 static PyObject *rget_x(PyObject *me, void *hunoz)
315   { return (mp_pywrap(MP_COPY(RABIN_R(me)->mm.m))); }
316
317 static PyObject *rmeth_iters(PyObject *me, PyObject *arg)
318 {
319   unsigned n;
320
321   if (!PyArg_ParseTuple(arg, "O&:iters", convuint, &n)) return (0);
322   return (PyInt_FromLong(rabin_iters(n)));
323 }
324
325 static const PyGetSetDef rabin_pygetset[] = {
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
333 static const PyMethodDef rabin_pymethods[] = {
334 #define METHNAME(name) rmeth_##name
335   METH  (test,          "R.test(W) -> PGST")
336   METH  (rtest,         "R.rtest(W) -> PGST")
337   SMTH  (iters,         "iters(NBITS) -> NITERS")
338 #undef METHNAME
339   { 0 }
340 };
341
342 static const PyTypeObject rabin_pytype_skel = {
343   PyVarObject_HEAD_INIT(0, 0)           /* Header */
344   "RabinMiller",                        /* @tp_name@ */
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@ */
367   "RabinMiller(X): Rabin-Miller strong primality test.",
368
369   0,                                    /* @tp_traverse@ */
370   0,                                    /* @tp_clear@ */
371   0,                                    /* @tp_richcompare@ */
372   0,                                    /* @tp_weaklistoffset@ */
373   0,                                    /* @tp_iter@ */
374   0,                                    /* @tp_iternext@ */
375   PYMETHODS(rabin),                     /* @tp_methods@ */
376   0,                                    /* @tp_members@ */
377   PYGETSET(rabin),                      /* @tp_getset@ */
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@ */
386   0,                                    /* @tp_free@ */
387   0                                     /* @tp_is_gc@ */
388 };
389
390 /*----- Events ------------------------------------------------------------*/
391
392 typedef struct pgevent_pyobj {
393   PyObject_HEAD
394   PyObject *r;
395   pgen_event *ev;
396 } pgevent_pyobj;
397
398 static PyTypeObject *pgevent_pytype;
399 #define PGEVENT_EV(o) (((pgevent_pyobj *)(o))->ev)
400
401 static PyObject *pgevent_pywrap(pgen_event *ev)
402 {
403   pgevent_pyobj *o = PyObject_New(pgevent_pyobj, pgevent_pytype);
404   o->ev = ev; o->r = 0;
405   return ((PyObject *)o);
406 }
407
408 static CONVFUNC(pgevent, pgen_event *, PGEVENT_EV)
409
410 static 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
418 static void pgevent_pydealloc(PyObject *me)
419 {
420   pgevent_pyobj *ev = (pgevent_pyobj *)me;
421   Py_XDECREF(ev->r); FREEOBJ(me);
422 }
423
424 #define PGEVENT_CHECK(me) do {                                          \
425   if (!PGEVENT_EV(me)) {                                                \
426     PyErr_SetString(PyExc_ValueError, "event object is no longer valid"); \
427     return (0);                                                         \
428   }                                                                     \
429 } while (0)
430
431 static PyObject *peget_name(PyObject *me, void *hunoz)
432   { PGEVENT_CHECK(me); return (TEXT_FROMSTR(PGEVENT_EV(me)->name)); }
433
434 static PyObject *peget_x(PyObject *me, void *hunoz)
435   { PGEVENT_CHECK(me); return (mp_pywrap(MP_COPY(PGEVENT_EV(me)->m))); }
436
437 static PyObject *peget_steps(PyObject *me, void *hunoz)
438   { PGEVENT_CHECK(me); return (PyInt_FromLong(PGEVENT_EV(me)->steps)); }
439
440 static PyObject *peget_tests(PyObject *me, void *hunoz)
441   { PGEVENT_CHECK(me); return (PyInt_FromLong(PGEVENT_EV(me)->tests)); }
442
443 static PyObject *peget_rng(PyObject *me, void *hunoz)
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 }
451
452 static 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;
457   if (!xobj) NIERR("__del__");
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;
463 end:
464   mp_drop(x);
465   return (rc);
466 }
467
468 static const PyGetSetDef pgevent_pygetset[] = {
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
479 static const PyTypeObject pgevent_pytype_skel = {
480   PyVarObject_HEAD_INIT(0, 0)           /* Header */
481   "PrimeGenEvent",                      /* @tp_name@ */
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@ */
504   "Prime-generation event.",
505
506   0,                                    /* @tp_traverse@ */
507   0,                                    /* @tp_clear@ */
508   0,                                    /* @tp_richcompare@ */
509   0,                                    /* @tp_weaklistoffset@ */
510   0,                                    /* @tp_iter@ */
511   0,                                    /* @tp_iternext@ */
512   0,                                    /* @tp_methods@ */
513   0,                                    /* @tp_members@ */
514   PYGETSET(pgevent),                    /* @tp_getset@ */
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@ */
523   0,                                    /* @tp_free@ */
524   0                                     /* @tp_is_gc@ */
525 };
526
527 /*----- Event handlers ----------------------------------------------------*/
528
529 PyTypeObject *pgev_pytype;
530
531 typedef struct pgstep_pyobj {
532   PGEV_HEAD
533   pgen_filterctx f;
534 } pgstep_pyobj;
535
536 static PyTypeObject *pgstep_pytype;
537 #define PGSTEP_STEP(o) (((pgstep_pyobj *)(o))->f.step)
538
539 typedef struct pgjump_pyobj {
540   PGEV_HEAD
541   PyObject *fobj;
542   pgen_jumpctx j;
543 } pgjump_pyobj;
544
545 static PyTypeObject *pgjump_pytype;
546 #define PGJUMP_FOBJ(o) (((pgjump_pyobj *)(o))->fobj)
547 #define PGJUMP_J(o) (&((pgjump_pyobj *)(o))->j)
548
549 typedef struct pgtest_pyobj {
550   PGEV_HEAD
551   rabin r;
552 } pgtest_pyobj;
553
554 static PyTypeObject *pgtest_pytype;
555
556 static int pgev_python(int rq, pgen_event *ev, void *p)
557 {
558   pypgev *pg = p;
559   PyObject *pyev = 0;
560   PyObject *rc = 0;
561   int st = PGEN_ABORT;
562   long l;
563   static const char *const meth[] =
564     { "pg_abort", "pg_done", "pg_begin", "pg_try", "pg_fail", "pg_pass" };
565
566   rq++;
567   if (rq > N(meth)) SYSERR("event code out of range");
568   pyev = pgevent_pywrap(ev);
569   if ((rc = PyObject_CallMethod(pg->obj, (/*unconst*/ char *)meth[rq],
570                                 "(O)", pyev)) == 0)
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");
578   else
579     st = l;
580 end:
581   if (PyErr_Occurred())
582     stash_exception(pg->exc, "exception from `pgen' handler");
583   if (pyev) {
584     pgevent_kill(pyev);
585     Py_DECREF(pyev);
586   }
587   Py_XDECREF(rc);
588   return (st);
589 }
590
591 static 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
600 int convpgev(PyObject *o, void *p)
601 {
602   pypgev *pg = p;
603
604   if (PGEV_PYCHECK(o))
605     pg->ev = *PGEV_PG(o);
606   else {
607     pg->ev.proc = pgev_python;
608     pg->ev.ctx = pg;
609     pg->obj = o; Py_INCREF(o);
610   }
611   return (1);
612 }
613
614 void droppgev(pypgev *pg)
615 {
616   if (pg->ev.proc == pgev_python)
617     { assert(pg->ev.ctx == pg); Py_DECREF(pg->obj); }
618 }
619
620 static 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));
628 end:
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); }
635 PGMETH(abort,   ABORT)
636 PGMETH(done,    DONE)
637 PGMETH(begin,   BEGIN)
638 PGMETH(try,     TRY)
639 PGMETH(pass,    PASS)
640 PGMETH(fail,    FAIL)
641 #undef PGMETH
642
643 static PyObject *pgev_stdev(pgen_proc *proc)
644   { pgev pg; pg.proc = proc; pg.ctx = 0; return (pgev_pywrap(&pg)); }
645
646 static const PyMethodDef pgev_pymethods[] = {
647 #define METHNAME(name) pgmeth_##name
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")
654 #undef METHNAME
655   { 0 }
656 };
657
658 static const PyTypeObject pgev_pytype_skel = {
659   PyVarObject_HEAD_INIT(0, 0)           /* Header */
660   "PrimeGenBuiltinHandler",             /* @tp_name@ */
661   sizeof(pgev_pyobj),                   /* @tp_basicsize@ */
662   0,                                    /* @tp_itemsize@ */
663
664   0,                                    /* @tp_dealloc@ */
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@ */
683   "Built-in prime-generation event handler, base class.",
684
685   0,                                    /* @tp_traverse@ */
686   0,                                    /* @tp_clear@ */
687   0,                                    /* @tp_richcompare@ */
688   0,                                    /* @tp_weaklistoffset@ */
689   0,                                    /* @tp_iter@ */
690   0,                                    /* @tp_iternext@ */
691   PYMETHODS(pgev),                      /* @tp_methods@ */
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@ */
702   0,                                    /* @tp_free@ */
703   0                                     /* @tp_is_gc@ */
704 };
705
706 static PyObject *pgstep_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
707 {
708   mpw s;
709   pgstep_pyobj *rc = 0;
710   static const char *const kwlist[] = { "step", 0 };
711
712   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convmpw, &s))
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;
718 end:
719   return ((PyObject *)rc);
720 }
721
722 static PyObject *psget_step(PyObject *me, void *hunoz)
723   { return (PyInt_FromLong(PGSTEP_STEP(me))); }
724
725 static const PyGetSetDef pgstep_pygetset[] = {
726 #define GETSETNAME(op, name) ps##op##_##name
727   GET   (step,          "S.step -> step size for the stepper")
728 #undef GETSETNAME
729   { 0 }
730 };
731
732 static const PyTypeObject pgstep_pytype_skel = {
733   PyVarObject_HEAD_INIT(0, 0)           /* Header */
734   "PrimeGenStepper",                    /* @tp_name@ */
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@ */
757   "PrimeGenStepper(STEP): simple stepper with small-factors filter.",
758
759   0,                                    /* @tp_traverse@ */
760   0,                                    /* @tp_clear@ */
761   0,                                    /* @tp_richcompare@ */
762   0,                                    /* @tp_weaklistoffset@ */
763   0,                                    /* @tp_iter@ */
764   0,                                    /* @tp_iternext@ */
765   0,                                    /* @tp_methods@ */
766   0,                                    /* @tp_members@ */
767   PYGETSET(pgstep),                     /* @tp_getset@ */
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@ */
776   0,                                    /* @tp_free@ */
777   0                                     /* @tp_is_gc@ */
778 };
779
780 static PyObject *pgjump_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
781 {
782   PyObject *o, *fobj;
783   pgjump_pyobj *rc = 0;
784   static const char *const kwlist[] = { "jump", 0 };
785
786   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", KWLIST, &o) ||
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;
794 end:
795   return ((PyObject *)rc);
796 }
797
798 static void pgjump_pydealloc(PyObject *me)
799 {
800   Py_DECREF(PGJUMP_FOBJ(me));
801   FREEOBJ(me);
802 }
803
804 static PyObject *pjget_jump(PyObject *me, void *hunoz)
805   { RETURN_OBJ(PGJUMP_FOBJ(me)); }
806
807 static const PyGetSetDef pgjump_pygetset[] = {
808 #define GETSETNAME(op, name) pj##op##_##name
809   GET   (jump,          "S.jump -> jump size for the stepper")
810 #undef GETSETNAME
811   { 0 }
812 };
813
814 static const PyTypeObject pgjump_pytype_skel = {
815   PyVarObject_HEAD_INIT(0, 0)           /* Header */
816   "PrimeGenJumper",                     /* @tp_name@ */
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@ */
839   "PrimeGenJumper(JUMP): "
840                        "stepper for larger steps with small-factors filter.",
841
842   0,                                    /* @tp_traverse@ */
843   0,                                    /* @tp_clear@ */
844   0,                                    /* @tp_richcompare@ */
845   0,                                    /* @tp_weaklistoffset@ */
846   0,                                    /* @tp_iter@ */
847   0,                                    /* @tp_iternext@ */
848   0,                                    /* @tp_methods@ */
849   0,                                    /* @tp_members@ */
850   PYGETSET(pgjump),                     /* @tp_getset@ */
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@ */
859   0,                                    /* @tp_free@ */
860   0                                     /* @tp_is_gc@ */
861 };
862
863 static PyObject *pgtest_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
864 {
865   pgtest_pyobj *rc = 0;
866   static const char *const kwlist[] = { 0 };
867
868   if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", KWLIST)) goto end;
869   rc = (pgtest_pyobj *)ty->tp_alloc(ty, 0);
870   rc->pg.proc = pgen_test;
871   rc->pg.ctx = &rc->r;
872 end:
873   return ((PyObject *)rc);
874 }
875
876 static const PyTypeObject pgtest_pytype_skel = {
877   PyVarObject_HEAD_INIT(0, 0)           /* Header */
878   "PrimeGenTester",                     /* @tp_name@ */
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@ */
901   "PrimeGenTester(): Rabin-Miller tester.",
902
903   0,                                    /* @tp_traverse@ */
904   0,                                    /* @tp_clear@ */
905   0,                                    /* @tp_richcompare@ */
906   0,                                    /* @tp_weaklistoffset@ */
907   0,                                    /* @tp_iter@ */
908   0,                                    /* @tp_iternext@ */
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@ */
920   0,                                    /* @tp_free@ */
921   0                                     /* @tp_is_gc@ */
922 };
923
924 /*----- Prime iteration ---------------------------------------------------*/
925
926 static PyTypeObject *piter_pytype;
927
928 typedef struct piter_pyobj {
929   PyObject_HEAD
930   primeiter i;
931 } piter_pyobj;
932 #define PITER_I(o) (&((piter_pyobj *)(o))->i)
933
934 static 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
947 static void piter_pydealloc(PyObject *me)
948   { primeiter_destroy(PITER_I(me)); FREEOBJ(me); }
949
950 static PyObject *piter_pynext(PyObject *me)
951   { return (mp_pywrap(primeiter_next(PITER_I(me), 0))); }
952
953 static 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
1001 /*----- Prime generation functions ----------------------------------------*/
1002
1003 void pgenerr(struct excinfo *exc)
1004 {
1005   if (exc->ty) RESTORE_EXCINFO(exc);
1006   else PyErr_SetString(PyExc_ValueError, "prime generation failed");
1007 }
1008
1009 static 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;
1017   struct excinfo exc = EXCINFO_INIT;
1018   pypgev step = { { 0 } }, test = { { 0 } }, evt = { { 0 } };
1019   unsigned nsteps = 0, ntests = 0;
1020   static const char *const kwlist[] =
1021     { "start", "name", "stepper", "tester", "event", "nsteps", "ntests", 0 };
1022
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;
1026   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&O&O&:pgen", KWLIST,
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));
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;
1037 end:
1038   mp_drop(r); mp_drop(x);
1039   droppgev(&step); droppgev(&test); droppgev(&evt);
1040   return (rc);
1041 }
1042
1043 static 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;
1052   struct excinfo exc = EXCINFO_INIT;
1053   pypgev evt = { { 0 } };
1054   PyObject *rc = 0;
1055   static const char *const kwlist[] =
1056     { "nbits", "name", "event", "rng", "nsteps", 0 };
1057
1058   evt.exc = &exc;
1059   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", KWLIST,
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,
1065                              r, n, evt.ev.proc, evt.ev.ctx)) == 0)
1066     PGENERR(&exc);
1067   rc = Py_BuildValue("(NN)", mp_pywrap(x), pfilt_pywrap(&f));
1068   x = 0;
1069 end:
1070   mp_drop(x);
1071   droppgev(&evt);
1072   return (rc);
1073 }
1074
1075 static 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;
1082   struct excinfo exc = EXCINFO_INIT;
1083   pypgev evt = { { 0 } };
1084   PyObject *rc = 0;
1085   static const char *const kwlist[] =
1086     { "nbits", "name", "event", "rng", "nsteps", 0 };
1087
1088   evt.exc = &exc;
1089   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", KWLIST,
1090                                    convuint, &nbits, &name,
1091                                    convpgev, &evt, convgrand, &r,
1092                                    convuint, &n))
1093     goto end;
1094   if ((x = strongprime(name, MP_NEW, nbits,
1095                        r, n, evt.ev.proc, evt.ev.ctx)) == 0)
1096     PGENERR(&exc);
1097   rc = mp_pywrap(x);
1098   x = 0;
1099 end:
1100   mp_drop(x);
1101   droppgev(&evt);
1102   return (rc);
1103 }
1104
1105 static PyObject *meth_limlee(PyObject *me, PyObject *arg, PyObject *kw)
1106 {
1107   char *p = "p";
1108   struct excinfo exc = EXCINFO_INIT;
1109   pypgev ie = { { 0 } }, oe = { { 0 } };
1110   unsigned ql, pl;
1111   grand *r = &rand_global;
1112   unsigned on = 0;
1113   size_t i, nf = 0;
1114   PyObject *rc = 0, *vec;
1115   static const char *const kwlist[] =
1116     { "pbits", "qbits", "name", "event", "ievent", "rng", "nsteps", 0 };
1117   mp *x = 0, **v = 0;
1118
1119   ie.exc = oe.exc = &exc;
1120   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|sO&O&O&O&:limlee", KWLIST,
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,
1126                   oe.ev.proc, oe.ev.ctx, ie.ev.proc, ie.ev.ctx,
1127                   &nf, &v)) == 0)
1128     PGENERR(&exc);;
1129   vec = PyList_New(nf);
1130   for (i = 0; i < nf; i++)
1131     PyList_SET_ITEM(vec, i, mp_pywrap(v[i]));
1132   xfree(v);
1133   rc = Py_BuildValue("(NN)", mp_pywrap(x), vec);
1134 end:
1135   droppgev(&oe); droppgev(&ie);
1136   return (rc);
1137 }
1138
1139 /*----- Global stuff ------------------------------------------------------*/
1140
1141 static 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
1147 static const PyMethodDef methods[] = {
1148 #define METHNAME(name) meth_##name
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, ...])")
1163 #undef METHNAME
1164   { 0 }
1165 };
1166
1167 void 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);
1176   INITTYPE(piter, root);
1177   addmethods(methods);
1178 }
1179
1180 static PyObject *obj;
1181
1182 void pgen_pyinsert(PyObject *mod)
1183 {
1184   INSERT("PrimeFilter", pfilt_pytype);
1185   INSERT("RabinMiller", rabin_pytype);
1186   INSERT("PrimeGenEvent", pgevent_pytype);
1187   INSERT("PrimeGenBuiltinHandler", pgev_pytype);
1188   INSERT("PrimeGenStepper", pgstep_pytype);
1189   INSERT("PrimeGenJumper", pgjump_pytype);
1190   INSERT("PrimeGenTester", pgtest_pytype);
1191   INSERT("pgen_nullev", obj = pgev_stdev(0));
1192   INSERT("pgen_stdev", pgev_stdev(pgen_ev));
1193   INSERT("pgen_spinev", pgev_stdev(pgen_evspin));
1194   INSERT("pgen_subev", pgev_stdev(pgen_subev));
1195   INSERT("PrimeIter", piter_pytype);
1196   setconstants(mod, consts);
1197 }
1198
1199 /*----- That's all, folks -------------------------------------------------*/