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)" % (
......
...@@ -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