Commit 42777129 authored by Robert Bradshaw's avatar Robert Bradshaw

Generate custom conversion code for enums.

This not only fixes bugs like auto-conversion of std::map[enum, enum] but also
fixes a bug where the compiler-chosen type of int for the enum may not have been
long.
parent 8d073443
...@@ -3600,8 +3600,6 @@ class CEnumType(CType): ...@@ -3600,8 +3600,6 @@ class CEnumType(CType):
is_enum = 1 is_enum = 1
signed = 1 signed = 1
rank = -1 # Ranks below any integer type rank = -1 # Ranks below any integer type
to_py_function = "PyInt_FromLong"
from_py_function = "PyInt_AsLong"
def __init__(self, name, cname, typedef_flag): def __init__(self, name, cname, typedef_flag):
self.name = name self.name = name
...@@ -3629,6 +3627,22 @@ class CEnumType(CType): ...@@ -3629,6 +3627,22 @@ class CEnumType(CType):
base_code = public_decl(base_code, dll_linkage) base_code = public_decl(base_code, dll_linkage)
return self.base_declaration_code(base_code, entity_code) return self.base_declaration_code(base_code, entity_code)
def create_to_py_utility_code(self, env):
self.to_py_function = "__Pyx_PyInt_From_" + self.specialization_name()
env.use_utility_code(TempitaUtilityCode.load_cached(
"CIntToPy", "TypeConversion.c",
context={"TYPE": self.empty_declaration_code(),
"TO_PY_FUNCTION": self.to_py_function}))
return True
def create_from_py_utility_code(self, env):
self.from_py_function = "__Pyx_PyInt_As_" + self.specialization_name()
env.use_utility_code(TempitaUtilityCode.load_cached(
"CIntFromPy", "TypeConversion.c",
context={"TYPE": self.empty_declaration_code(),
"FROM_PY_FUNCTION": self.from_py_function}))
return True
def from_py_call_code(self, source_code, result_code, error_pos, code, def from_py_call_code(self, source_code, result_code, error_pos, code,
from_py_function=None, error_condition=None): from_py_function=None, error_condition=None):
rhs = "%s(%s)" % ( rhs = "%s(%s)" % (
......
...@@ -138,7 +138,7 @@ bad: ...@@ -138,7 +138,7 @@ bad:
Py_XDECREF(ascii_chars_b); Py_XDECREF(ascii_chars_b);
return -1; return -1;
} }
#endif #endif
#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 #if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3
#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL)
...@@ -192,7 +192,7 @@ static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_ ...@@ -192,7 +192,7 @@ static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_
#if CYTHON_COMPILING_IN_CPYTHON && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) #if CYTHON_COMPILING_IN_CPYTHON && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT)
if ( if (
#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII #if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII
__Pyx_sys_getdefaultencoding_not_ascii && __Pyx_sys_getdefaultencoding_not_ascii &&
#endif #endif
PyUnicode_Check(o)) { PyUnicode_Check(o)) {
#if PY_VERSION_HEX < 0x03030000 #if PY_VERSION_HEX < 0x03030000
...@@ -353,8 +353,8 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { ...@@ -353,8 +353,8 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) {
return PyInt_FromSize_t(ival); return PyInt_FromSize_t(ival);
} }
/////////////// ToPyCTupleUtility.proto /////////////// /////////////// ToPyCTupleUtility.proto ///////////////
static PyObject* {{funcname}}({{struct_type_decl}}); static PyObject* {{funcname}}({{struct_type_decl}});
...@@ -370,27 +370,27 @@ static PyObject* {{funcname}}({{struct_type_decl}} value) { ...@@ -370,27 +370,27 @@ static PyObject* {{funcname}}({{struct_type_decl}} value) {
if (!item) goto bad; if (!item) goto bad;
PyTuple_SET_ITEM(result, {{ix}}, item); PyTuple_SET_ITEM(result, {{ix}}, item);
{{endfor}} {{endfor}}
return result; return result;
bad: bad:
Py_XDECREF(item); Py_XDECREF(item);
Py_XDECREF(result); Py_XDECREF(result);
return NULL; return NULL;
} }
/////////////// FromPyCTupleUtility.proto /////////////// /////////////// FromPyCTupleUtility.proto ///////////////
static {{struct_type_decl}} {{funcname}}(PyObject *); static {{struct_type_decl}} {{funcname}}(PyObject *);
/////////////// FromPyCTupleUtility /////////////// /////////////// FromPyCTupleUtility ///////////////
static {{struct_type_decl}} {{funcname}}(PyObject * o) { static {{struct_type_decl}} {{funcname}}(PyObject * o) {
{{struct_type_decl}} result; {{struct_type_decl}} result;
if (!PyTuple_Check(o) || PyTuple_GET_SIZE(o) != {{size}}) { if (!PyTuple_Check(o) || PyTuple_GET_SIZE(o) != {{size}}) {
PyErr_Format(PyExc_TypeError, "Expected %.16s of size %d, got %.200s", "a tuple", {{size}}, Py_TYPE(o)->tp_name); PyErr_Format(PyExc_TypeError, "Expected %.16s of size %d, got %.200s", "a tuple", {{size}}, Py_TYPE(o)->tp_name);
goto bad; goto bad;
} }
#if CYTHON_COMPILING_IN_CPYTHON #if CYTHON_COMPILING_IN_CPYTHON
{{for ix, component in enumerate(components):}} {{for ix, component in enumerate(components):}}
{{py:attr = "result.f%s" % ix}} {{py:attr = "result.f%s" % ix}}
...@@ -536,7 +536,7 @@ static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value); ...@@ -536,7 +536,7 @@ static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value);
/////////////// CIntToPy /////////////// /////////////// CIntToPy ///////////////
static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value) { static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value) {
const {{TYPE}} neg_one = ({{TYPE}}) -1, const_zero = 0; const {{TYPE}} neg_one = ({{TYPE}}) -1, const_zero = ({{TYPE}}) 0;
const int is_unsigned = neg_one > const_zero; const int is_unsigned = neg_one > const_zero;
if (is_unsigned) { if (is_unsigned) {
if (sizeof({{TYPE}}) < sizeof(long)) { if (sizeof({{TYPE}}) < sizeof(long)) {
...@@ -607,7 +607,7 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *); ...@@ -607,7 +607,7 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *);
{{py: from Cython.Utility import pylong_join }} {{py: from Cython.Utility import pylong_join }}
static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) { static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) {
const {{TYPE}} neg_one = ({{TYPE}}) -1, const_zero = 0; const {{TYPE}} neg_one = ({{TYPE}}) -1, const_zero = ({{TYPE}}) 0;
const int is_unsigned = neg_one > const_zero; const int is_unsigned = neg_one > const_zero;
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
if (likely(PyInt_Check(x))) { if (likely(PyInt_Check(x))) {
...@@ -627,7 +627,7 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) { ...@@ -627,7 +627,7 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) {
#if CYTHON_USE_PYLONG_INTERNALS #if CYTHON_USE_PYLONG_INTERNALS
const digit* digits = ((PyLongObject*)x)->ob_digit; const digit* digits = ((PyLongObject*)x)->ob_digit;
switch (Py_SIZE(x)) { switch (Py_SIZE(x)) {
case 0: return 0; case 0: return ({{TYPE}}) 0;
case 1: __PYX_VERIFY_RETURN_INT({{TYPE}}, digit, digits[0]) case 1: __PYX_VERIFY_RETURN_INT({{TYPE}}, digit, digits[0])
{{for _size in (2, 3, 4)}} {{for _size in (2, 3, 4)}}
case {{_size}}: case {{_size}}:
...@@ -635,7 +635,7 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) { ...@@ -635,7 +635,7 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) {
if (8 * sizeof(unsigned long) > {{_size}} * PyLong_SHIFT) { if (8 * sizeof(unsigned long) > {{_size}} * PyLong_SHIFT) {
__PYX_VERIFY_RETURN_INT({{TYPE}}, unsigned long, {{pylong_join(_size, 'digits')}}) __PYX_VERIFY_RETURN_INT({{TYPE}}, unsigned long, {{pylong_join(_size, 'digits')}})
} else if (8 * sizeof({{TYPE}}) >= {{_size}} * PyLong_SHIFT) { } else if (8 * sizeof({{TYPE}}) >= {{_size}} * PyLong_SHIFT) {
return {{pylong_join(_size, 'digits', TYPE)}}; return ({{TYPE}}) {{pylong_join(_size, 'digits', TYPE)}};
} }
} }
break; break;
...@@ -666,7 +666,7 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) { ...@@ -666,7 +666,7 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) {
#if CYTHON_USE_PYLONG_INTERNALS #if CYTHON_USE_PYLONG_INTERNALS
const digit* digits = ((PyLongObject*)x)->ob_digit; const digit* digits = ((PyLongObject*)x)->ob_digit;
switch (Py_SIZE(x)) { switch (Py_SIZE(x)) {
case 0: return 0; case 0: return ({{TYPE}}) 0;
case -1: __PYX_VERIFY_RETURN_INT({{TYPE}}, sdigit, -(sdigit) digits[0]) case -1: __PYX_VERIFY_RETURN_INT({{TYPE}}, sdigit, -(sdigit) digits[0])
case 1: __PYX_VERIFY_RETURN_INT({{TYPE}}, digit, +digits[0]) case 1: __PYX_VERIFY_RETURN_INT({{TYPE}}, digit, +digits[0])
{{for _size in (2, 3, 4)}} {{for _size in (2, 3, 4)}}
...@@ -676,7 +676,7 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) { ...@@ -676,7 +676,7 @@ static CYTHON_INLINE {{TYPE}} {{FROM_PY_FUNCTION}}(PyObject *x) {
if (8 * sizeof(unsigned long) > {{_size}} * PyLong_SHIFT) { if (8 * sizeof(unsigned long) > {{_size}} * PyLong_SHIFT) {
__PYX_VERIFY_RETURN_INT({{TYPE}}, {{'long' if _case < 0 else 'unsigned long'}}, {{'-(long) ' if _case < 0 else ''}}{{pylong_join(_size, 'digits')}}) __PYX_VERIFY_RETURN_INT({{TYPE}}, {{'long' if _case < 0 else 'unsigned long'}}, {{'-(long) ' if _case < 0 else ''}}{{pylong_join(_size, 'digits')}})
} else if (8 * sizeof({{TYPE}}) - 1 > {{_size}} * PyLong_SHIFT) { } else if (8 * sizeof({{TYPE}}) - 1 > {{_size}} * PyLong_SHIFT) {
return {{'-' if _case < 0 else ''}}{{pylong_join(_size, 'digits', TYPE)}}; return ({{TYPE}}) {{'-' if _case < 0 else ''}}{{pylong_join(_size, 'digits', TYPE)}};
} }
} }
break; break;
......
...@@ -207,3 +207,16 @@ def test_nested(o): ...@@ -207,3 +207,16 @@ def test_nested(o):
""" """
cdef map[pair[double, double], vector[int]] m = o cdef map[pair[double, double], vector[int]] m = o
return m return m
cpdef enum Color:
RED = 0
GREEN
BLUE
def test_enum_map(o):
"""
>>> test_enum_map({RED: GREEN})
{0: 1}
"""
cdef map[Color, Color] m = o
return m
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment