From d5370b4b19f54580184f392894f7e4f2e1cf8a02 Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Sat, 24 Aug 2013 12:57:42 -0700 Subject: [PATCH] Refactor conversion utility code. --- Cython/Compiler/PyrexTypes.py | 10 +++- Cython/Compiler/Visitor.py | 2 +- Cython/Utility/TypeConversion.c | 127 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 2 deletions(-) diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 1e169ee..9041997 100755 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -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'): diff --git a/Cython/Compiler/Visitor.py b/Cython/Compiler/Visitor.py index df468c4..bac02a6 100644 --- a/Cython/Compiler/Visitor.py +++ b/Cython/Compiler/Visitor.py @@ -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 = [] diff --git a/Cython/Utility/TypeConversion.c b/Cython/Utility/TypeConversion.c index 20acbb7..78968fa 100644 --- a/Cython/Utility/TypeConversion.c +++ b/Cython/Utility/TypeConversion.c @@ -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; + } +} + -- 2.7.4