mp.c: Use implicit-conversion rules in `coerce'.
[catacomb-python] / mp.c
diff --git a/mp.c b/mp.c
index 8f66d17..163e690 100644 (file)
--- a/mp.c
+++ b/mp.c
@@ -56,6 +56,12 @@ mp *mp_frompylong(PyObject *obj)
   mp *x;
   mpw *p;
 
+#ifdef PY3
+  int ov;
+  long j = PyLong_AsLongAndOverflow(obj, &ov);
+  if (!ov) return mp_fromlong(MP_NEW, j);
+#endif
+
   sz = Py_SIZE(l);
   if (sz < 0) sz = -sz;
   bits = (unsigned long)sz * PyLong_SHIFT;
@@ -199,7 +205,7 @@ static void mp_pydealloc(PyObject *o)
 }
 
 static PyObject *mp_pyrepr(PyObject *o)
-  { return mp_topystring(MP_X(o), 10, "MP(", 0, "L)"); }
+  { return mp_topystring(MP_X(o), 10, "MP(", 0, ")"); }
 
 static PyObject *mp_pystr(PyObject *o)
   { return mp_topystring(MP_X(o), 10, 0, 0, 0); }
@@ -228,8 +234,11 @@ mp *tomp(PyObject *o)
     if ((x = G_TOINT(GE_G(o), MP_NEW, GE_X(o))) == 0)
       return (0);
     return (x);
-  } else if (PyInt_Check(o))
+  }
+#ifdef PY2
+  else if (PyInt_Check(o))
     return (mp_fromlong(MP_NEW, PyInt_AS_LONG(o)));
+#endif
   else if ((l = PyNumber_Long(o)) != 0) {
     x = mp_frompylong(l);
     Py_DECREF(l);
@@ -278,7 +287,7 @@ int convgf(PyObject *o, void *p)
   return (1);
 }
 
-static mp *implicitmp(PyObject *o)
+mp *implicitmp(PyObject *o)
 {
   if (!o ||
       GF_PYCHECK(o) ||
@@ -289,7 +298,7 @@ static mp *implicitmp(PyObject *o)
   return (tomp(o));
 }
 
-static mp *implicitgf(PyObject *o)
+mp *implicitgf(PyObject *o)
 {
   if (!o ||
       MP_PYCHECK(o) ||
@@ -384,25 +393,24 @@ UNOP(mp, not2c)
 static PyObject *mp_pyid(PyObject *x) { RETURN_OBJ(x); }
 
 #define gf_lsr mp_lsr
-#define SHIFTOP(pre, name, rname)                                      \
+#define SHIFTOP(pre, PRE, name, rname)                                 \
   static PyObject *pre##_py##name(PyObject *x, PyObject *y) {          \
-    mp *xx, *yy;                                                       \
+    PyObject *yix = 0;                                                 \
     PyObject *z = 0;                                                   \
     long n;                                                            \
-    if (pre##binop(x, y, &xx, &yy)) RETURN_NOTIMPL;                    \
-    if (mp_tolong_checked(yy, &n, 1)) goto end;                                \
-    if (n < 0)                                                         \
-      z = pre##_pywrap(mp_##rname(MP_NEW, xx, -n));                    \
-    else                                                               \
-      z = pre##_pywrap(mp_##name(MP_NEW, xx, n));                      \
-  end:                                                                 \
-    MP_DROP(xx); MP_DROP(yy);                                          \
+    if (!PRE##_PYCHECK(x)) RETURN_NOTIMPL;                             \
+    if (GF_PYCHECK(y) || FE_PYCHECK(y)) RETURN_NOTIMPL;                        \
+    yix = PyNumber_Index(y); if (!yix) { PyErr_Clear(); RETURN_NOTIMPL; } \
+    n = PyInt_AsLong(yix); Py_DECREF(yix);                             \
+    if (n == -1 && PyErr_Occurred())  { PyErr_Clear(); RETURN_NOTIMPL; } \
+    if (n < 0) z = pre##_pywrap(mp_##rname(MP_NEW, MP_X(x), -n));      \
+    else z = pre##_pywrap(mp_##name(MP_NEW, MP_X(x), n));              \
     return (z);                                                                \
   }
-SHIFTOP(mp, lsl2c, lsr2c)
-SHIFTOP(mp, lsr2c, lsl2c)
-SHIFTOP(gf, lsl, lsr)
-SHIFTOP(gf, lsr, lsl)
+SHIFTOP(mp, MP, lsl2c, lsr2c)
+SHIFTOP(mp, MP, lsr2c, lsl2c)
+SHIFTOP(gf, GF, lsl, lsr)
+SHIFTOP(gf, GF, lsr, lsl)
 #undef SHIFTOP
 
 #define DIVOP(pre, name, qq, rr, gather)                               \
@@ -456,7 +464,7 @@ static PyObject *mp_pyexp(PyObject *x, PyObject *y, PyObject *z)
   PyObject *rc = 0;
 
   if ((xx = implicitmp(x)) == 0 || (yy = implicitmp(y)) == 0 ||
-      (z && z != Py_None && (zz = tomp(z)) == 0)) {
+      (z && z != Py_None && (zz = implicitmp(z)) == 0)) {
     mp_drop(xx); mp_drop(yy); mp_drop(zz);
     RETURN_NOTIMPL;
   }
@@ -502,7 +510,9 @@ static mp *gf_modinv_checked(mp *d, mp *x, mp *p)
 #define BASEOP(name, radix, pre)                                       \
   static PyObject *mp_py##name(PyObject *x)                            \
     { return mp_topystring(MP_X(x), radix, 0, pre, 0); }
+#ifdef PY2
 BASEOP(oct, 8, "0");
+#endif
 BASEOP(hex, 16, "0x");
 #undef BASEOP
 
@@ -514,8 +524,10 @@ static PyObject *mp_pyint(PyObject *x)
   if (!mp_tolong_checked(MP_X(x), &l, 0)) return (PyInt_FromLong(l));
   else return mp_topylong(MP_X(x));
 }
+#ifdef PY2
 static PyObject *mp_pylong(PyObject *x)
   { return (mp_topylong(MP_X(x))); }
+#endif
 static PyObject *mp_pyfloat(PyObject *x)
 {
   PyObject *l = mp_topylong(MP_X(x));
@@ -524,6 +536,7 @@ static PyObject *mp_pyfloat(PyObject *x)
   return (PyFloat_FromDouble(f));
 }
 
+#ifdef PY2
 #define COERCE(pre, PRE)                                               \
   static int pre##_pycoerce(PyObject **x, PyObject **y)                        \
   {                                                                    \
@@ -533,7 +546,7 @@ static PyObject *mp_pyfloat(PyObject *x)
       Py_INCREF(*x); Py_INCREF(*y);                                    \
       return (0);                                                      \
     }                                                                  \
-    if ((z = tomp(*y)) != 0) {                                         \
+    if ((z = implicit##pre(*y)) != 0) {                                        \
       Py_INCREF(*x);                                                   \
       *y = pre##_pywrap(z);                                            \
       return (0);                                                      \
@@ -543,6 +556,7 @@ static PyObject *mp_pyfloat(PyObject *x)
 COERCE(mp, MP)
 COERCE(gf, GF)
 #undef COERCE
+#endif
 
 static PyObject *mp_pyrichcompare(PyObject *x, PyObject *y, int op)
 {
@@ -558,8 +572,10 @@ static PyObject *mp_pyrichcompare(PyObject *x, PyObject *y, int op)
   return (rc);
 }
 
+#ifdef PY2
 static int mp_pycompare(PyObject *x, PyObject *y)
   { return mp_cmp(MP_X(x), MP_X(y)); }
+#endif
 
 static PyObject *mp_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
@@ -929,7 +945,9 @@ static const PyNumberMethods mp_pynumber = {
   mp_pyadd,                            /* @nb_add@ */
   mp_pysub,                            /* @nb_subtract@ */
   mp_pymul,                            /* @nb_multiply@ */
+#ifdef PY2
   0,                                   /* @nb_divide@ */
+#endif
   mp_pymod,                            /* @nb_remainder@ */
   mp_pydivmod,                         /* @nb_divmod@ */
   mp_pyexp,                            /* @nb_power@ */
@@ -943,17 +961,23 @@ static const PyNumberMethods mp_pynumber = {
   mp_pyand2c,                          /* @nb_and@ */
   mp_pyxor2c,                          /* @nb_xor@ */
   mp_pyor2c,                           /* @nb_or@ */
+#ifdef PY2
   mp_pycoerce,                         /* @nb_coerce@ */
+#endif
   mp_pyint,                            /* @nb_int@ */
-  mp_pylong,                           /* @nb_long@ */
+  PY23(mp_pylong, 0),                  /* @nb_long@ */
   mp_pyfloat,                          /* @nb_float@ */
+#ifdef PY2
   mp_pyoct,                            /* @nb_oct@ */
   mp_pyhex,                            /* @nb_hex@ */
+#endif
 
   0,                                   /* @nb_inplace_add@ */
   0,                                   /* @nb_inplace_subtract@ */
   0,                                   /* @nb_inplace_multiply@ */
+#ifdef PY2
   0,                                   /* @nb_inplace_divide@ */
+#endif
   0,                                   /* @nb_inplace_remainder@ */
   0,                                   /* @nb_inplace_power@ */
   0,                                   /* @nb_inplace_lshift@ */
@@ -966,6 +990,8 @@ static const PyNumberMethods mp_pynumber = {
   0,                                   /* @nb_true_divide@ */
   0,                                   /* @nb_inplace_floor_divide@ */
   0,                                   /* @nb_inplace_true_divide@ */
+
+  mp_pyint,                            /* @nb_index@ */
 };
 
 static const PyTypeObject mp_pytype_skel = {
@@ -978,7 +1004,7 @@ static const PyTypeObject mp_pytype_skel = {
   0,                                   /* @tp_print@ */
   0,                                   /* @tp_getattr@ */
   0,                                   /* @tp_setattr@ */
-  mp_pycompare,                                /* @tp_compare@ */
+  PY23(mp_pycompare, 0),               /* @tp_compare@/@tp_as_async@ */
   mp_pyrepr,                           /* @tp_repr@ */
   PYNUMBER(mp),                                /* @tp_as_number@ */
   0,                                   /* @tp_as_sequence@ */
@@ -997,13 +1023,16 @@ static const PyTypeObject mp_pytype_skel = {
   "Multiprecision integers, similar to `long' but more efficient and\n"
   "versatile.  Support all the standard arithmetic operations, with\n"
   "implicit conversions from `PrimeFilter', and other objects which\n"
-  "convert to `long'.\n"
+  "convert to `" PY23("long", "int") "'.\n"
   "\n"
   "Constructor MP(X, [radix = R]) attempts to convert X to an `MP'.  If\n"
   "X is a string, it's read in radix-R form, or we look for a prefix\n"
   "if R = 0.  Other acceptable things are field elements, elliptic curve\n"
+  PY23(
   "points, group elements, Python `int' and `long' objects, and anything\n"
-  "with an integer conversion.\n"
+  "with an integer conversion.\n",
+  "points, group elements, Python `int' objects, and anything with an\n"
+  "integer conversion.\n")
   "\n"
   "Notes:\n"
   "\n"
@@ -1902,7 +1931,7 @@ static const PyTypeObject mpcrt_pytype_skel = {
 /*----- Binary polynomials ------------------------------------------------*/
 
 static PyObject *gf_pyrepr(PyObject *o)
-  { return mp_topystring(MP_X(o), 16, "GF(", "0x", "L)"); }
+  { return mp_topystring(MP_X(o), 16, "GF(", "0x", ")"); }
 
 static PyObject *gf_pyrichcompare(PyObject *x, PyObject *y, int op)
 {
@@ -1963,8 +1992,8 @@ static PyObject *gf_pyexp(PyObject *x, PyObject *y, PyObject *z)
   mp *r = 0;
   PyObject *rc = 0;
 
-  if ((xx = tomp(x)) == 0 || (yy = tomp(y)) == 0 ||
-      (z && z != Py_None && (zz = tomp(z)) == 0)) {
+  if ((xx = implicitgf(x)) == 0 || (yy = implicitmp(y)) == 0 ||
+      (z && z != Py_None && (zz = implicitgf(z)) == 0)) {
     mp_drop(xx); mp_drop(yy); mp_drop(zz);
     RETURN_NOTIMPL;
   }
@@ -2112,7 +2141,9 @@ static const PyNumberMethods gf_pynumber = {
   gf_pyadd,                            /* @nb_add@ */
   gf_pysub,                            /* @nb_subtract@ */
   gf_pymul,                            /* @nb_multiply@ */
+#ifdef PY2
   0,                                   /* @nb_divide@ */
+#endif
   gf_pymod,                            /* @nb_remainder@ */
   gf_pydivmod,                         /* @nb_divmod@ */
   gf_pyexp,                            /* @nb_power@ */
@@ -2126,17 +2157,23 @@ static const PyNumberMethods gf_pynumber = {
   gf_pyand,                            /* @nb_and@ */
   gf_pyxor,                            /* @nb_xor@ */
   gf_pyor,                             /* @nb_or@ */
+#ifdef PY2
   gf_pycoerce,                         /* @nb_coerce@ */
+#endif
   mp_pyint,                            /* @nb_int@ */
-  mp_pylong,                           /* @nb_long@ */
+  PY23(mp_pylong, 0),                  /* @nb_long@ */
   0 /* doesn't make any sense */,      /* @nb_float@ */
+#ifdef PY2
   mp_pyoct,                            /* @nb_oct@ */
   mp_pyhex,                            /* @nb_hex@ */
+#endif
 
   0,                                   /* @nb_inplace_add@ */
   0,                                   /* @nb_inplace_subtract@ */
   0,                                   /* @nb_inplace_multiply@ */
+#ifdef PY2
   0,                                   /* @nb_inplace_divide@ */
+#endif
   0,                                   /* @nb_inplace_remainder@ */
   0,                                   /* @nb_inplace_power@ */
   0,                                   /* @nb_inplace_lshift@ */
@@ -2149,6 +2186,8 @@ static const PyNumberMethods gf_pynumber = {
   0,                                   /* @nb_true_divide@ */
   0,                                   /* @nb_inplace_floor_divide@ */
   0,                                   /* @nb_inplace_true_divide@ */
+
+  mp_pyint,                            /* @nb_index@ */
 };
 
 static const PyTypeObject gf_pytype_skel = {
@@ -2183,8 +2222,11 @@ static const PyTypeObject gf_pytype_skel = {
   "Constructor GF(X, [radix = R]) attempts to convert X to a `GF'.  If\n"
   "X is a string, it's read in radix-R form, or we look for a prefix\n"
   "if R = 0.  Other acceptable things are field elements, elliptic curve\n"
+  PY23(
   "points, group elements, Python `int' and `long' objects, and anything\n"
-  "with an integer conversion.\n"
+  "with an integer conversion.\n",
+  "points, group elements, Python `int' objects, and anything with an\n"
+  "integer conversion.\n")
   "\n"
   "The name is hopelessly wrong from a technical point of view, but\n"
   "but it's much easier to type than `p2' or `c2' or whatever.\n"