chiark / gitweb /
Return `long' objects when `int' is requested but the value won't fit.
authorMark Wooding <mdw@distorted.org.uk>
Wed, 3 May 2017 11:48:27 +0000 (12:48 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 13 May 2017 14:40:07 +0000 (15:40 +0100)
Mostly, Python handles the error from the `int' conversion and falls
back to long, but there's something weird in iteration, where if you say

for i in ...:
  print '%d' % x

then the loop finishes and /then/ you get an exception for the overflow
from the failed conversion of x to an `int'.

Follow Python's actual behaviour: have `mp_tolong_checked' take an extra
argument indicating whether to throw an exception, and modify most of
the call sites to fall back to a conversion based on `mp_topylong'.

catacomb-python.h
ec.c
field.c
group.c
mp.c
pgen.c

index a379e1d4d02cb74214dd5a56e75ae2aa3d1f9ed8..bed97d548c0e54f63acfcd7113c5efd8ee15c7f8 100644 (file)
@@ -317,7 +317,7 @@ extern PyObject *gf_pywrap(mp *);
 extern mp *mp_frompyobject(PyObject *, int);
 extern PyObject *mp_topystring(mp *, int,
                               const char *, const char *, const char *);
-extern int mp_tolong_checked(mp *, long *);
+extern int mp_tolong_checked(mp *, long *, int);
 
 /*----- Abstract fields ---------------------------------------------------*/
 
diff --git a/ec.c b/ec.c
index 9d4d6e75faeb742858d9e75b63b1a661178f79fb..63d97d8c26438db8e8d7e106823f7c769e745bc2 100644 (file)
--- a/ec.c
+++ b/ec.c
@@ -525,8 +525,8 @@ static PyObject *ecpt_pyint(PyObject *me)
   PyObject *rc = 0;
   if (EC_ATINF(ECPT_P(me))) VALERR("point at infinity");
   getecptout(&p, me);
-  if (mp_tolong_checked(p.x, &l)) goto end;
-  rc = PyInt_FromLong(l);
+  if (!mp_tolong_checked(p.x, &l, 0)) rc = PyInt_FromLong(l);
+  else rc = mp_topylong(p.x);
 end:
   EC_DESTROY(&p);
   return (rc);
diff --git a/field.c b/field.c
index 2807c1ccbfb6cb491fb5902868548af47f6b203a..0a5d908f805dcff2ffe04b2f8d29899bcc14fcec 100644 (file)
--- a/field.c
+++ b/field.c
@@ -263,10 +263,12 @@ end:
 static PyObject *fe_pyint(PyObject *x)
 {
   long l;
+  PyObject *rc;
   mp *xx = F_OUT(FE_F(x), MP_NEW, FE_X(x));
-  if (mp_tolong_checked(xx, &l)) { MP_DROP(xx); return (0); }
+  if (!mp_tolong_checked(xx, &l, 0)) rc = PyInt_FromLong(l);
+  else rc = mp_topylong(xx);
   MP_DROP(xx);
-  return (PyInt_FromLong(l));
+  return (rc);
 }
 
 static PyObject *fe_pylong(PyObject *x)
diff --git a/group.c b/group.c
index 5cc40e54a364cecb0028ca35329e9afc5fb0c792..7d5b2576d7c29b092601b0cde461cbb9eb025d0a 100644 (file)
--- a/group.c
+++ b/group.c
@@ -695,8 +695,8 @@ static PyObject *ge_pyint(PyObject *me)
 
   if ((x = G_TOINT(GE_G(me), MP_NEW, GE_X(me))) == 0)
     TYERR("can't convert to integer");
-  if (mp_tolong_checked(x, &l)) goto end;
-  rc = PyInt_FromLong(l);
+  if (!mp_tolong_checked(x, &l, 0)) rc = PyInt_FromLong(l);
+  else rc = mp_topylong(x);
 end:
   mp_drop(x);
   return (rc);
diff --git a/mp.c b/mp.c
index 8f57ad12ec251dc8e56b848077d354687bfe6e6f..f5f43204a718256abc288f93db7c4aa7907e7804 100644 (file)
--- a/mp.c
+++ b/mp.c
@@ -163,7 +163,7 @@ PyObject *gf_pywrap(mp *x)
   return ((PyObject *)z);
 }
 
-int mp_tolong_checked(mp *x, long *l)
+int mp_tolong_checked(mp *x, long *l, int must)
 {
   static mp *longmin = 0, *longmax = 0;
   int rc = -1;
@@ -172,8 +172,10 @@ int mp_tolong_checked(mp *x, long *l)
     longmin = mp_fromlong(MP_NEW, LONG_MIN);
     longmax = mp_fromlong(MP_NEW, LONG_MAX);
   }
-  if (MP_CMP(x, <, longmin) || MP_CMP(x, >, longmax))
-    VALERR("mp out of range for int");
+  if (MP_CMP(x, <, longmin) || MP_CMP(x, >, longmax)) {
+    if (must) VALERR("mp out of range for int");
+    else goto end;
+  }
   *l = mp_tolong(x);
   rc = 0;
 end:
@@ -362,7 +364,7 @@ static PyObject *mp_pyid(PyObject *x) { RETURN_OBJ(x); }
     PyObject *z = 0;                                                   \
     long n;                                                            \
     if (pre##binop(x, y, &xx, &yy)) RETURN_NOTIMPL;                    \
-    if (mp_tolong_checked(yy, &n)) goto end;                           \
+    if (mp_tolong_checked(yy, &n, 1)) goto end;                                \
     if (n < 0)                                                         \
       z = pre##_pywrap(mp_##rname(MP_NEW, xx, -n));                    \
     else                                                               \
@@ -483,8 +485,8 @@ static int mp_pynonzerop(PyObject *x) { return !MP_ZEROP(MP_X(x)); }
 static PyObject *mp_pyint(PyObject *x)
 {
   long l;
-  if (mp_tolong_checked(MP_X(x), &l)) return (0);
-  return (PyInt_FromLong(l));
+  if (!mp_tolong_checked(MP_X(x), &l, 0)) return (PyInt_FromLong(l));
+  else return mp_topylong(MP_X(x));
 }
 static PyObject *mp_pylong(PyObject *x)
   { return (mp_topylong(MP_X(x))); }
diff --git a/pgen.c b/pgen.c
index 24639ecff96dfa95c11b4e729597b1717522a9c8..108fa31a5168c19cac5aaa03b59c8752dc6d9da5 100644 (file)
--- a/pgen.c
+++ b/pgen.c
@@ -120,9 +120,8 @@ static PyObject *pfilt_pyint(PyObject *me)
   long l;
   PyObject *rc = 0;
 
-  if (mp_tolong_checked(PFILT_F(me)->m, &l)) goto end;
-  rc = PyInt_FromLong(l);
-end:
+  if (!mp_tolong_checked(PFILT_F(me)->m, &l, 0)) rc = PyInt_FromLong(l);
+  else rc = mp_topylong(PFILT_F(me)->m);
   return (rc);
 }