Commit 021488a5 authored by Lisandro Dalcin's avatar Lisandro Dalcin

extern ctypedef integral <-> python object conversion (ticket #333)

parent e02c1b0b
...@@ -3933,8 +3933,7 @@ class TypecastNode(NewTempExprNode): ...@@ -3933,8 +3933,7 @@ class TypecastNode(NewTempExprNode):
if from_py and not to_py and self.operand.is_ephemeral() and not self.type.is_numeric: if from_py and not to_py and self.operand.is_ephemeral() and not self.type.is_numeric:
error(self.pos, "Casting temporary Python object to non-numeric non-Python type") error(self.pos, "Casting temporary Python object to non-numeric non-Python type")
if to_py and not from_py: if to_py and not from_py:
if (self.operand.type.to_py_function and if self.operand.type.create_to_py_utility_code(env):
self.operand.type.create_to_py_utility_code(env)):
self.result_ctype = py_object_type self.result_ctype = py_object_type
self.operand = self.operand.coerce_to_pyobject(env) self.operand = self.operand.coerce_to_pyobject(env)
else: else:
...@@ -3942,7 +3941,7 @@ class TypecastNode(NewTempExprNode): ...@@ -3942,7 +3941,7 @@ class TypecastNode(NewTempExprNode):
warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.operand.type, self.type)) warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.operand.type, self.type))
self.operand = self.operand.coerce_to_simple(env) self.operand = self.operand.coerce_to_simple(env)
elif from_py and not to_py: elif from_py and not to_py:
if self.type.from_py_function: if self.type.create_from_py_utility_code(env):
self.operand = self.operand.coerce_to(self.type, env) self.operand = self.operand.coerce_to(self.type, env)
elif self.type.is_ptr and not (self.type.base_type.is_void or self.type.base_type.is_struct): elif self.type.is_ptr and not (self.type.base_type.is_void or self.type.base_type.is_struct):
error(self.pos, "Python objects cannot be casted to pointers of primitive types") error(self.pos, "Python objects cannot be casted to pointers of primitive types")
......
...@@ -1964,8 +1964,9 @@ class DefNode(FuncDefNode): ...@@ -1964,8 +1964,9 @@ class DefNode(FuncDefNode):
or self.starstar_arg is not None or has_kwonly_args or self.starstar_arg is not None or has_kwonly_args
for arg in self.args: for arg in self.args:
if not arg.type.is_pyobject and arg.type.from_py_function is None: if not arg.type.is_pyobject:
arg.type.create_from_py_utility_code(env) done = arg.type.create_from_py_utility_code(env)
if not done: pass # will fail later
if not self.signature_has_generic_args(): if not self.signature_has_generic_args():
if has_star_or_kw_args: if has_star_or_kw_args:
......
...@@ -164,11 +164,14 @@ class CTypedefType(BaseType): ...@@ -164,11 +164,14 @@ class CTypedefType(BaseType):
is_typedef = 1 is_typedef = 1
typedef_is_external = 0 typedef_is_external = 0
to_py_utility_code = None
from_py_utility_code = None
def __init__(self, cname, base_type, is_external=0): def __init__(self, cname, base_type, is_external=0):
self.typedef_cname = cname self.typedef_cname = cname
self.typedef_base_type = base_type self.typedef_base_type = base_type
self.typedef_is_external = is_external self.typedef_is_external = is_external
# Make typecodes in external typedefs use typesize-neutral macros # Make typecodes in external typedefs use typesize-neutral macros
if is_external: if is_external:
typecode = None typecode = None
...@@ -213,6 +216,63 @@ class CTypedefType(BaseType): ...@@ -213,6 +216,63 @@ class CTypedefType(BaseType):
def __str__(self): def __str__(self):
return self.declaration_name(for_display = 1) return self.declaration_name(for_display = 1)
def _create_utility_code(self, template_utility_code,
template_function_name):
type_name = self.typedef_cname.replace(" ","_")
utility_code = template_utility_code.specialize(
type = self.typedef_cname,
TypeName = type_name)
function_name = template_function_name % type_name
return utility_code, function_name
def create_to_py_utility_code(self, env):
if self.typedef_is_external:
if not self.to_py_utility_code:
base_type = self.typedef_base_type
if base_type.is_int:
self.to_py_utility_code, self.to_py_function = \
self._create_utility_code(c_typedef_int_to_py_function,
'__Pyx_PyInt_to_py_%s')
elif base_type.is_float:
pass # XXX implement!
elif base_type.is_complex:
pass # XXX implement!
pass
if self.to_py_utility_code:
env.use_utility_code(self.to_py_utility_code)
return True
# delegation
return self.typedef_base_type.create_to_py_utility_code(env)
def create_from_py_utility_code(self, env):
if self.typedef_is_external:
if not self.from_py_utility_code:
base_type = self.typedef_base_type
if base_type.is_int:
self.from_py_utility_code, self.from_py_function = \
self._create_utility_code(c_typedef_int_from_py_function,
'__Pyx_PyInt_from_py_%s')
elif base_type.is_float:
pass # XXX implement!
elif base_type.is_complex:
pass # XXX implement!
if self.from_py_utility_code:
env.use_utility_code(self.from_py_utility_code)
return True
# delegation
return self.typedef_base_type.create_from_py_utility_code(env)
def error_condition(self, result_code):
if self.typedef_is_external:
if self.exception_value:
condition = "(%s == (%s)%s)" % (
result_code, self.typedef_cname, self.exception_value)
if self.exception_check:
condition += " && PyErr_Occurred()"
return condition
# delegation
return self.typedef_base_type.error_condition(result_code)
def __getattr__(self, name): def __getattr__(self, name):
return getattr(self.typedef_base_type, name) return getattr(self.typedef_base_type, name)
...@@ -540,9 +600,12 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) { ...@@ -540,9 +600,12 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) {
long val = __Pyx_PyInt_AsLong(x); long val = __Pyx_PyInt_AsLong(x);
if (unlikely(val != (long)(%(type)s)val)) { if (unlikely(val != (long)(%(type)s)val)) {
if (unlikely(val == -1 && PyErr_Occurred())) if (unlikely(val == -1 && PyErr_Occurred()))
return (%(type)s)-1;""" + \ return (%(type)s)-1;
"%(IntValSignTest)s" + \ if (((%(type)s)-1) > ((%(type)s)0) && unlikely(val < 0)) {
""" PyErr_SetString(PyExc_OverflowError,
"can't convert negative value to %(type)s");
return (%(type)s)-1;
}
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"value too large to convert to %(type)s"); "value too large to convert to %(type)s");
return (%(type)s)-1; return (%(type)s)-1;
...@@ -552,12 +615,6 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) { ...@@ -552,12 +615,6 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) {
return (%(type)s)__Pyx_PyInt_As%(SignWord)sLong(x); return (%(type)s)__Pyx_PyInt_As%(SignWord)sLong(x);
} }
""") """)
intval_signtest = """
if (unlikely(%(var)s < 0)) {
PyErr_SetString(PyExc_OverflowError,
"can't convert negative value to %(type)s");
return (%(type)s)-1;
}"""
c_long_from_py_function = UtilityCode( c_long_from_py_function = UtilityCode(
proto=""" proto="""
...@@ -566,17 +623,25 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject *); ...@@ -566,17 +623,25 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject *);
impl=""" impl="""
static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) { static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) {
#if PY_VERSION_HEX < 0x03000000 #if PY_VERSION_HEX < 0x03000000
if (likely(PyInt_CheckExact(x) || PyInt_Check(x))) { if (likely(PyInt_Check(x))) {
long val = PyInt_AS_LONG(x);""" + \ long val = PyInt_AS_LONG(x);
"%(IntValSignTest)s" + \ if (((%(type)s)-1) > ((%(type)s)0) && unlikely(val < 0)) {
""" PyErr_SetString(PyExc_OverflowError,
"can't convert negative value to %(type)s");
return (%(type)s)-1;
}
return (%(type)s)val; return (%(type)s)val;
} else } else
#endif #endif
if (likely(PyLong_CheckExact(x) || PyLong_Check(x))) {""" +\ if (likely(PyLong_Check(x))) {
"%(PyLongSignTest)s" + \ if (((%(type)s)-1) > ((%(type)s)0) && unlikely(Py_SIZE(x) < 0)) {
""" PyErr_SetString(PyExc_OverflowError,
return %(PyLongConvert)s(x); "can't convert negative value to %(type)s");
return (%(type)s)-1;
}
return (((%(type)s)-1) < ((%(type)s)0)) ?
PyLong_As%(TypeName)s(x) :
PyLong_AsUnsigned%(TypeName)s(x);
} else { } else {
%(type)s val; %(type)s val;
PyObject *tmp = __Pyx_PyNumber_Int(x); PyObject *tmp = __Pyx_PyNumber_Int(x);
...@@ -587,14 +652,63 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) { ...@@ -587,14 +652,63 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) {
} }
} }
""") """)
pylong_signtest = """
if (unlikely(Py_SIZE(%(var)s) < 0)) {
PyErr_SetString(PyExc_OverflowError,
"can't convert negative value to %(type)s");
return (%(type)s)-1;
}"""
c_typedef_int_from_py_function = UtilityCode(
proto="""
static INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject *);
""",
impl="""
static INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject* x) {
/**/ if (sizeof(%(type)s) == sizeof(char))
return (((%(type)s)-1) < ((%(type)s)0)) ?
(%(type)s)__Pyx_PyInt_AsSignedChar(x) :
(%(type)s)__Pyx_PyInt_AsUnsignedChar(x);
else if (sizeof(%(type)s) == sizeof(short))
return (((%(type)s)-1) < ((%(type)s)0)) ?
(%(type)s)__Pyx_PyInt_AsSignedShort(x) :
(%(type)s)__Pyx_PyInt_AsUnsignedShort(x);
else if (sizeof(%(type)s) == sizeof(int))
return (((%(type)s)-1) < ((%(type)s)0)) ?
(%(type)s)__Pyx_PyInt_AsSignedInt(x) :
(%(type)s)__Pyx_PyInt_AsUnsignedInt(x);
else if (sizeof(%(type)s) == sizeof(long))
return (((%(type)s)-1) < ((%(type)s)0)) ?
(%(type)s)__Pyx_PyInt_AsSignedLong(x) :
(%(type)s)__Pyx_PyInt_AsUnsignedLong(x);
else if (sizeof(%(type)s) == sizeof(PY_LONG_LONG))
return (((%(type)s)-1) < ((%(type)s)0)) ?
(%(type)s)__Pyx_PyInt_AsSignedLongLong(x) :
(%(type)s)__Pyx_PyInt_AsUnsignedLongLong(x);
#if 0
else if (sizeof(%(type)s) > sizeof(short) &&
sizeof(%(type)s) < sizeof(int)) /* __int32 ILP64 ? */
return (((%(type)s)-1) < ((%(type)s)0)) ?
(%(type)s)__Pyx_PyInt_AsSignedInt(x) :
(%(type)s)__Pyx_PyInt_AsUnsignedInt(x);
#endif
PyErr_SetString(PyExc_TypeError, "%(TypeName)s");
return (%(type)s)-1;
}
""")
c_typedef_int_to_py_function = UtilityCode(
proto="""
static INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s);
""",
impl="""
static INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s val) {
/**/ if (sizeof(%(type)s) < sizeof(long))
return PyInt_FromLong((long)val);
else if (sizeof(%(type)s) == sizeof(long))
return (((%(type)s)-1) < ((%(type)s)0)) ?
PyInt_FromLong((long)val) :
PyLong_FromUnsignedLong((unsigned long)val);
else /* (sizeof(%(type)s) > sizeof(long)) */
return (((%(type)s)-1) < ((%(type)s)0)) ?
PyLong_FromLongLong((PY_LONG_LONG)val) :
PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val);
}
""")
class CIntType(CNumericType): class CIntType(CNumericType):
...@@ -620,27 +734,13 @@ class CIntType(CNumericType): ...@@ -620,27 +734,13 @@ class CIntType(CNumericType):
type_name = type_name.replace("PY_LONG_LONG","long long") type_name = type_name.replace("PY_LONG_LONG","long long")
SignWord = sign_word.title() SignWord = sign_word.title()
TypeName = type_name.title().replace(" ", "") TypeName = type_name.title().replace(" ", "")
data = {'IntValSignTest' : "",
'PyLongSignTest' : "",
'PyLongConvert' : "",
}
if not self.signed:
data['IntValSignTest'] = intval_signtest % {'var':"val", 'type':ctype}
data['PyLongSignTest'] = pylong_signtest % {'var':"x", 'type':ctype}
if "Long" in TypeName: if "Long" in TypeName:
data['PyLongConvert'] = \
"PyLong_As" + SignWord.replace("Signed", "") + TypeName
# the replaces below are just for generating well indented C code
data['IntValSignTest'] = "\n".join(
[ln.replace(" "*4, "", 1) for ln in data['IntValSignTest'].split('\n')]
)
utility_code = c_long_from_py_function utility_code = c_long_from_py_function
else: else:
utility_code = c_int_from_py_function utility_code = c_int_from_py_function
utility_code.specialize(self, utility_code.specialize(self,
SignWord=SignWord, SignWord=SignWord,
TypeName=TypeName, TypeName=TypeName)
**data)
func_name = "__Pyx_PyInt_As%s%s" % (SignWord, TypeName) func_name = "__Pyx_PyInt_As%s%s" % (SignWord, TypeName)
return func_name return func_name
......
This diff is collapsed.
typedef signed char SChar;
typedef unsigned char UChar;
typedef signed short SShort;
typedef unsigned short UShort;
typedef signed int SInt;
typedef unsigned int UInt;
typedef signed long SLong;
typedef unsigned long ULong;
typedef signed long long SLongLong;
typedef unsigned long long ULongLong;
cdef extern from "ctypedef_int_types_chdr_T333.h":
ctypedef int SChar ## "signed char"
ctypedef int UChar ## "unsigned char"
ctypedef int SShort ## "signed short"
ctypedef int UShort ## "unsigned short"
ctypedef int SInt ## "signed int"
ctypedef int UInt ## "unsigned int"
ctypedef int SLong ## "signed long"
ctypedef int ULong ## "unsigned long"
ctypedef int SLongLong ## "signed PY_LONG_LONG"
ctypedef int ULongLong ## "unsigned PY_LONG_LONG"
cdef extern from *:
ctypedef int ExtSInt "signed short"
ctypedef int ExtUInt "unsigned short"
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