chiark / gitweb /
mp: Replace MP.product() by an MPMul class. Much more useful.
authorMark Wooding <mdw@distorted.org.uk>
Sat, 28 Jan 2006 19:07:27 +0000 (19:07 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 28 Jan 2006 19:07:27 +0000 (19:07 +0000)
mp.c

diff --git a/mp.c b/mp.c
index 0a0e206113edd7dbfebb4a982a150bce3e695a5c..4b73223c4cf57beaf6e2b2978d82facef3ceab38 100644 (file)
--- a/mp.c
+++ b/mp.c
@@ -898,53 +898,165 @@ end:
   return (z);
 }
 
-static PyObject *meth__MP_product(PyObject *me, PyObject *arg)
+#define LOADOP(pre, py, name)                                          \
+  static PyObject *meth__##py##_##name(PyObject *me, PyObject *arg)    \
+  {                                                                    \
+    char *p;                                                           \
+    int len;                                                           \
+    if (!PyArg_ParseTuple(arg, "Os#:" #name, &me, &p, &len)) return (0); \
+    return (pre##_pywrap(mp_##name(MP_NEW, p, len)));                  \
+  }
+LOADOP(mp, MP, loadl)
+LOADOP(mp, MP, loadb)
+LOADOP(mp, MP, loadl2c)
+LOADOP(mp, MP, loadb2c)
+LOADOP(gf, GF, loadl)
+LOADOP(gf, GF, loadb)
+#undef LOADOP
+
+/*----- Products of small integers ----------------------------------------*/
+
+typedef struct mpmul_pyobj {
+  PyObject_HEAD
+  int livep;
+  mpmul mm;
+} mpmul_pyobj;
+
+#define MPMUL_LIVEP(o) (((mpmul_pyobj *)(o))->livep)
+#define MPMUL_PY(o) (&((mpmul_pyobj *)(o))->mm)
+
+static void mpmul_pydealloc(PyObject *me)
+{
+  if (MPMUL_LIVEP(me))
+    mp_drop(mpmul_done(MPMUL_PY(me)));
+  FREEOBJ(me);
+}
+
+static PyObject *mmmeth_factor(PyObject *me, PyObject *arg)
 {
-  mpmul m;
   PyObject *q, *i;
   mp *x;
 
-  if (PyTuple_Size(arg) != 2) {
+  if (!MPMUL_LIVEP(me)) VALERR("MPMul object invalid");
+  if (PyTuple_Size(arg) != 1)
     i = PyObject_GetIter(arg);
-    PyIter_Next(i);
-  } else {
-    if ((q = PyTuple_GetItem(arg, 1)) == 0) return (0);
+  else {
+    if ((q = PyTuple_GetItem(arg, 0)) == 0) goto end;
     if ((i = PyObject_GetIter(q)) == 0) {
       PyErr_Clear(); /* that's ok */
       i = PyObject_GetIter(arg);
     }
   }
-  if (!i) return (0);
-  mpmul_init(&m);
+  if (!i) goto end;
   while ((q = PyIter_Next(i)) != 0) {
     x = getmp(q); Py_DECREF(q); if (!x) {
-      MP_DROP(mpmul_done(&m));
       Py_DECREF(i);
-      return (0);
+      goto end;
     }
-    mpmul_add(&m, x);
+    mpmul_add(MPMUL_PY(me), x);
     MP_DROP(x);
   }
-  x = mpmul_done(&m);
   Py_DECREF(i);
+  RETURN_ME;
+end:
+  return (0);
+}
+
+static PyObject *mmmeth_done(PyObject *me, PyObject *arg)
+{
+  mp *x;
+
+  if (!PyArg_ParseTuple(arg, ":done")) goto end;
+  if (!MPMUL_LIVEP(me)) VALERR("MPMul object invalid");
+  x = mpmul_done(MPMUL_PY(me));
+  MPMUL_LIVEP(me) = 0;
   return (mp_pywrap(x));
+end:
+  return (0);
 }
 
-#define LOADOP(pre, py, name)                                          \
-  static PyObject *meth__##py##_##name(PyObject *me, PyObject *arg)    \
-  {                                                                    \
-    char *p;                                                           \
-    int len;                                                           \
-    if (!PyArg_ParseTuple(arg, "Os#:" #name, &me, &p, &len)) return (0); \
-    return (pre##_pywrap(mp_##name(MP_NEW, p, len)));                  \
+static PyObject *mpmul_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+  mpmul_pyobj *mm;
+
+  if (kw) TYERR("keyword arguments not allowed here");
+  mm = (mpmul_pyobj *)ty->tp_alloc(ty, 0);
+  mpmul_init(&mm->mm);
+  mm->livep = 1;
+  if (mmmeth_factor((PyObject *)mm, arg) == 0) {
+    Py_DECREF(mm);
+    goto end;
   }
-LOADOP(mp, MP, loadl)
-LOADOP(mp, MP, loadb)
-LOADOP(mp, MP, loadl2c)
-LOADOP(mp, MP, loadb2c)
-LOADOP(gf, GF, loadl)
-LOADOP(gf, GF, loadb)
-#undef LOADOP
+  return ((PyObject *)mm);
+end:
+  return (0);
+}
+
+static PyObject *mmget_livep(PyObject *me, void *hunoz)
+  { return (getbool(MPMUL_LIVEP(me))); }
+
+static PyGetSetDef mpmul_pygetset[] = {
+#define GETSETNAME(op, name) mm##op##_##name
+  GET  (livep,                 "MM.livep -> flag: object still valid?")
+#undef GETSETNAME
+  { 0 }
+};
+
+static PyMethodDef mpmul_pymethods[] = {
+#define METHNAME(name) mmmeth_##name
+  METH (factor,                "MM.factor(ITERABLE) or MM.factor(I, ...)")
+  METH (done,                  "MM.done() -> PRODUCT")
+#undef METHNAME
+  { 0 }
+};
+
+static PyTypeObject *mpmul_pytype, mpmul_pytype_skel = {
+  PyObject_HEAD_INIT(0) 0,             /* Header */
+  "catacomb.MPMul",                    /* @tp_name@ */
+  sizeof(mpmul_pyobj),                 /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  mpmul_pydealloc,                     /* @tp_dealloc@ */
+  0,                                   /* @tp_print@ */
+  0,                                   /* @tp_getattr@ */
+  0,                                   /* @tp_setattr@ */
+  0,                                   /* @tp_compare@ */
+  0,                                   /* @tp_repr@ */
+  0,                                   /* @tp_as_number@ */
+  0,                                   /* @tp_as_sequence@ */
+  0,                                   /* @tp_as_mapping@ */
+  0,                                   /* @tp_hash@ */
+  0,                                   /* @tp_call@ */
+  0,                                   /* @tp_str@ */
+  0,                                   /* @tp_getattro@ */
+  0,                                   /* @tp_setattro@ */
+  0,                                   /* @tp_as_buffer@ */
+  Py_TPFLAGS_DEFAULT |                 /* @tp_flags@ */
+    Py_TPFLAGS_BASETYPE,
+
+  /* @tp_doc@ */
+"An object for multiplying many small integers.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternext@ */
+  mpmul_pymethods,                     /* @tp_methods@ */
+  0,                                   /* @tp_members@ */
+  mpmul_pygetset,                      /* @tp_getset@ */
+  0,                                   /* @tp_base@ */
+  0,                                   /* @tp_dict@ */
+  0,                                   /* @tp_descr_get@ */
+  0,                                   /* @tp_descr_set@ */
+  0,                                   /* @tp_dictoffset@ */
+  0,                                   /* @tp_init@ */
+  PyType_GenericAlloc,                 /* @tp_alloc@ */
+  mpmul_pynew,                         /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
 
 /*----- Montgomery reduction ----------------------------------------------*/
 
@@ -2258,8 +2370,6 @@ loadl2c(STR) -> X: read little-endian bytes, two's complement")
 loadb2c(STR) -> X: read big-endian bytes, two's complement")
   METH (_MP_frombuf,           "\
 frombuf(STR) -> (X, REST): read buffer format")
-  METH (_MP_product,           "\
-product(ITER) -> X: product of things iterated over")
   METH (_GF_loadl,             "\
 loadl(STR) -> X: read little-endian bytes")
   METH (_GF_loadb,             "\
@@ -2274,6 +2384,7 @@ void mp_pyinit(void)
 {
   INITTYPE(mp, root);
   INITTYPE(gf, root);
+  INITTYPE(mpmul, root);
   INITTYPE(mpmont, root);
   INITTYPE(mpbarrett, root);
   INITTYPE(mpreduce, root);
@@ -2286,6 +2397,7 @@ void mp_pyinit(void)
 void mp_pyinsert(PyObject *mod)
 {
   INSERT("MP", mp_pytype);
+  INSERT("MPMul", mpmul_pytype);
   INSERT("MPMont", mpmont_pytype);
   INSERT("MPBarrett", mpbarrett_pytype);
   INSERT("MPReduce", mpreduce_pytype);