Refactor conversion utility code.
authorRobert Bradshaw <robertwb@gmail.com>
Sat, 24 Aug 2013 19:57:42 +0000 (12:57 -0700)
committerRobert Bradshaw <robertwb@gmail.com>
Sat, 24 Aug 2013 19:57:42 +0000 (12:57 -0700)
Cython/Compiler/PyrexTypes.py
Cython/Compiler/Visitor.py
Cython/Utility/TypeConversion.c

index 1e169ee..9041997 100755 (executable)
@@ -1562,7 +1562,15 @@ class CIntType(CNumericType):
         if self.to_py_function is None:
             self.to_py_function = self.get_to_py_type_conversion()
         if self.from_py_function is None:
-            self.from_py_function = self.get_from_py_type_conversion()
+            # Inject specializatioin used elsewhere.
+            self.get_from_py_type_conversion()
+
+    def create_from_py_utility_code(self, env):
+        self.from_py_function = "__Pyx_PyInt_As" + self.specialization_name()
+        env.use_utility_code(TempitaUtilityCode.load(
+            "CIntFromPy", "TypeConversion.c",
+            context={"TYPE": self.declaration_code(''), "FROM_PY_FUNCTION": self.from_py_function}))
+        return True
 
     def get_to_py_type_conversion(self):
         if self.rank < list(rank_to_type_name).index('int'):
index df468c4..bac02a6 100644 (file)
@@ -64,7 +64,7 @@ class TreeVisitor(object):
         self.access_path = []
 
     def dump_node(self, node, indent=0):
-        ignored = list(node.child_attrs) + [u'child_attrs', u'pos',
+        ignored = list(node.child_attrs or []) + [u'child_attrs', u'pos',
                                             u'gil_message', u'cpp_message',
                                             u'subexprs']
         values = []
index 20acbb7..78968fa 100644 (file)
@@ -448,3 +448,130 @@ static CYTHON_INLINE Py_UNICODE __Pyx_PyObject_AsPy_UNICODE(PyObject* x) {
     }
     return (Py_UNICODE)ival;
 }
+
+/////////////// CIntToPy.proto ///////////////
+
+/////////////// CIntToPy ///////////////
+
+/////////////// CIntFromPy.proto ///////////////
+
+static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *);
+
+/////////////// CIntFromPy ///////////////
+
+#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
+#if CYTHON_USE_PYLONG_INTERNALS
+#include "longintrepr.h"
+#endif
+#endif
+static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) {
+    const {{TYPE}} neg_one = ({{TYPE}}) -1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_MAJOR_VERSION < 3
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (sizeof({{TYPE}}) < sizeof(long)) {
+            if (unlikely(val != ({{TYPE}}) val)) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to {{TYPE}}" :
+                    "value too large to convert to {{TYPE}}");
+                return ({{TYPE}}) -1;
+            } else {
+                return ({{TYPE}}) val;
+            }
+        } else {
+            if (is_unsigned && unlikely(val < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to {{TYPE}}");
+                return ({{TYPE}}) -1;
+            } else {
+                return ({{TYPE}}) val;
+            }
+        }
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
+#if CYTHON_USE_PYLONG_INTERNALS
+            if (sizeof(digit) <= sizeof({{TYPE}})) {
+                switch (Py_SIZE(x)) {
+                    case  0: return 0;
+                    case  1: return (%(type)s) ((PyLongObject*)x)->ob_digit[0];
+                }
+            }
+#endif
+#endif
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to {{TYPE}}");
+                return ({{TYPE}}) -1;
+            }
+            if (sizeof({{TYPE}}) <= sizeof(unsigned long)) {
+                unsigned long val = PyLong_AsUnsignedLong(x);
+                if (sizeof({{TYPE}}) < sizeof(unsigned long)
+                    && unlikely(val != ({{TYPE}}) val)) {
+                    PyErr_SetString(PyExc_OverflowError,
+                                    "value too large to convert to {{TYPE}}");
+                    return ({{TYPE}}) -1;
+                }
+                return ({{TYPE}}) val;
+            } else if (sizeof({{TYPE}}) <= sizeof(unsigned long long)) {
+                unsigned long long val = PyLong_AsUnsignedLongLong(x);
+                if (sizeof({{TYPE}}) < sizeof(unsigned long long)
+                    && unlikely(val != ({{TYPE}}) val)) {
+                    PyErr_SetString(PyExc_OverflowError,
+                                    "value too large to convert to {{TYPE}}");
+                    return ({{TYPE}}) -1;
+                }
+                return ({{TYPE}}) val;
+            } else {
+                // Huh?
+                return ({{TYPE}}) PyLong_AsUnsignedLongLong(x);
+            }
+        } else {
+#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
+#if CYTHON_USE_PYLONG_INTERNALS
+            if (sizeof(digit) <= sizeof({{TYPE}}) {
+                switch (Py_SIZE(x)) {
+                    case  0: return 0;
+                    case  1: return +({{TYPE}}) ((PyLongObject*)x)->ob_digit[0];
+                    case -1: return -({{TYPE}}) ((PyLongObject*)x)->ob_digit[0];
+                }
+            }
+#endif
+#endif
+            if (sizeof({{TYPE}}) <= sizeof(long)) {
+                long val = PyLong_AsLong(x);
+                if (sizeof({{TYPE}}) < sizeof(long)
+                    && unlikely(val != ({{TYPE}}) val)) {
+                    PyErr_SetString(PyExc_OverflowError,
+                                    "value too large to convert to {{TYPE}}");
+                    return ({{TYPE}}) -1;
+                }
+                return ({{TYPE}}) val;
+            } else if (sizeof({{TYPE}}) <= sizeof(long long)) {
+                long long val = PyLong_AsLongLong(x);
+                if (sizeof({{TYPE}}) < sizeof(long long)
+                    && unlikely(val != ({{TYPE}}) val)) {
+                    PyErr_SetString(PyExc_OverflowError,
+                                    "value too large to convert to {{TYPE}}");
+                    return ({{TYPE}}) -1;
+                }
+                return ({{TYPE}}) val;
+            } else {
+                // Huh?
+                return ({{TYPE}}) PyLong_AsLongLong(x);
+            }
+        }
+    } else {
+        {{TYPE}} val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return ({{TYPE}}) -1;
+        val = {{FROM_PY_FUNCTION}}(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+