Commit d7322d2f authored by Mark Florisson's avatar Mark Florisson

object -> struct conversion

parent 5197f5cf
...@@ -1598,9 +1598,13 @@ class CCodeWriter(object): ...@@ -1598,9 +1598,13 @@ class CCodeWriter(object):
self.put_var_xdecref_clear(entry) self.put_var_xdecref_clear(entry)
def put_incref_memoryviewslice(self, slice_cname, have_gil=False): def put_incref_memoryviewslice(self, slice_cname, have_gil=False):
import MemoryView
self.globalstate.use_utility_code(MemoryView.memviewslice_init_code)
self.putln("__PYX_INC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil))) self.putln("__PYX_INC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil)))
def put_xdecref_memoryviewslice(self, slice_cname, have_gil=False): def put_xdecref_memoryviewslice(self, slice_cname, have_gil=False):
import MemoryView
self.globalstate.use_utility_code(MemoryView.memviewslice_init_code)
self.putln("__PYX_XDEC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil))) self.putln("__PYX_XDEC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil)))
def put_xgiveref_memoryviewslice(self, slice_cname): def put_xgiveref_memoryviewslice(self, slice_cname):
......
...@@ -778,7 +778,7 @@ memviewslice_declare_code = load_memview_c_utility( ...@@ -778,7 +778,7 @@ memviewslice_declare_code = load_memview_c_utility(
memviewslice_init_code = load_memview_c_utility( memviewslice_init_code = load_memview_c_utility(
"MemviewSliceInit", "MemviewSliceInit",
context=dict(context, BUF_MAX_NDIMS=Options.buffer_max_dims), context=dict(context, BUF_MAX_NDIMS=Options.buffer_max_dims),
requires=[memviewslice_declare_code], requires=[memviewslice_declare_code, Buffer.acquire_utility_code],
) )
memviewslice_index_helpers = load_memview_c_utility("MemviewSliceIndex") memviewslice_index_helpers = load_memview_c_utility("MemviewSliceIndex")
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Cython/Python language types # Cython/Python language types
# #
from Code import UtilityCode, LazyUtilityCode from Code import UtilityCode, LazyUtilityCode, ContentHashingUtilityCode
import StringEncoding import StringEncoding
import Naming import Naming
import copy import copy
...@@ -518,7 +518,7 @@ class MemoryViewSliceType(PyrexType): ...@@ -518,7 +518,7 @@ class MemoryViewSliceType(PyrexType):
def lazy_utility_callback(code): def lazy_utility_callback(code):
context['dtype_typeinfo'] = Buffer.get_type_information_cname( context['dtype_typeinfo'] = Buffer.get_type_information_cname(
code, self.dtype) code, self.dtype)
return Code.ContentHashingUtilityCode.load( return ContentHashingUtilityCode.load(
"ObjectToMemviewSlice", "MemoryView_C.c", context) "ObjectToMemviewSlice", "MemoryView_C.c", context)
env.use_utility_code(Buffer.acquire_utility_code) env.use_utility_code(Buffer.acquire_utility_code)
...@@ -576,11 +576,17 @@ class MemoryViewSliceType(PyrexType): ...@@ -576,11 +576,17 @@ class MemoryViewSliceType(PyrexType):
if self.dtype.is_pyobject: if self.dtype.is_pyobject:
utility_name = "MemviewObjectToObject" utility_name = "MemviewObjectToObject"
else: else:
if not (self.dtype.create_to_py_utility_code(env) and to_py = self.dtype.create_to_py_utility_code(env)
self.dtype.create_from_py_utility_code(env)): from_py = self.dtype.create_from_py_utility_code(env)
print "cannot convert %s" % self.dtype if not (to_py or from_py):
return "NULL", "NULL" return "NULL", "NULL"
if not self.dtype.to_py_function:
get_function = "NULL"
if not self.dtype.from_py_function:
set_function = "NULL"
utility_name = "MemviewDtypeToObject" utility_name = "MemviewDtypeToObject"
error_condition = (self.dtype.error_condition('value') or error_condition = (self.dtype.error_condition('value') or
'PyErr_Occurred()') 'PyErr_Occurred()')
...@@ -591,7 +597,7 @@ class MemoryViewSliceType(PyrexType): ...@@ -591,7 +597,7 @@ class MemoryViewSliceType(PyrexType):
error_condition = error_condition, error_condition = error_condition,
) )
utility = Code.ContentHashingUtilityCode.load( utility = ContentHashingUtilityCode.load(
utility_name, "MemoryView_C.c", context=context) utility_name, "MemoryView_C.c", context=context)
env.use_utility_code(utility) env.use_utility_code(utility)
return get_function, set_function return get_function, set_function
...@@ -2329,17 +2335,19 @@ class CFuncTypeArg(object): ...@@ -2329,17 +2335,19 @@ class CFuncTypeArg(object):
def specialize(self, values): def specialize(self, values):
return CFuncTypeArg(self.name, self.type.specialize(values), self.pos, self.cname) return CFuncTypeArg(self.name, self.type.specialize(values), self.pos, self.cname)
class StructUtilityCode(object): class ToPyStructUtilityCode(object):
requires = None requires = None
def __init__(self, type, forward_decl): def __init__(self, type, forward_decl):
self.type = type self.type = type
self.header = "static PyObject* %s(%s)" % (type.to_py_function, type.declaration_code('s')) self.header = "static PyObject* %s(%s)" % (type.to_py_function,
type.declaration_code('s'))
self.forward_decl = forward_decl self.forward_decl = forward_decl
def __eq__(self, other): def __eq__(self, other):
return isinstance(other, StructUtilityCode) and self.header == other.header return isinstance(other, ToPyStructUtilityCode) and self.header == other.header
def __hash__(self): def __hash__(self):
return hash(self.header) return hash(self.header)
...@@ -2389,6 +2397,7 @@ class CStructOrUnionType(CType): ...@@ -2389,6 +2397,7 @@ class CStructOrUnionType(CType):
is_struct_or_union = 1 is_struct_or_union = 1
has_attributes = 1 has_attributes = 1
exception_check = True
def __init__(self, name, kind, scope, typedef_flag, cname, packed=False): def __init__(self, name, kind, scope, typedef_flag, cname, packed=False):
self.name = name self.name = name
...@@ -2399,26 +2408,63 @@ class CStructOrUnionType(CType): ...@@ -2399,26 +2408,63 @@ class CStructOrUnionType(CType):
self.is_struct = kind == 'struct' self.is_struct = kind == 'struct'
if self.is_struct: if self.is_struct:
self.to_py_function = "%s_to_py_%s" % (Naming.convert_func_prefix, self.cname) self.to_py_function = "%s_to_py_%s" % (Naming.convert_func_prefix, self.cname)
self.from_py_function = "%s_from_py_%s" % (Naming.convert_func_prefix, self.cname)
self.exception_check = True self.exception_check = True
self._convert_code = None self._convert_to_py_code = None
self._convert_from_py_code = None
self.packed = packed self.packed = packed
def create_to_py_utility_code(self, env): def create_to_py_utility_code(self, env):
if env.outer_scope is None: if env.outer_scope is None:
return False return False
if self._convert_code is False: return # tri-state-ish if self._convert_to_py_code is False: return # tri-state-ish
if self._convert_code is None: if self._convert_to_py_code is None:
for member in self.scope.var_entries: for member in self.scope.var_entries:
if not member.type.to_py_function or not member.type.create_to_py_utility_code(env): if not member.type.to_py_function or not member.type.create_to_py_utility_code(env):
self.to_py_function = None self.to_py_function = None
self._convert_code = False self._convert_to_py_code = False
return False
forward_decl = (self.entry.visibility != 'extern')
self._convert_to_py_code = ToPyStructUtilityCode(self, forward_decl)
env.use_utility_code(self._convert_to_py_code)
return True
def create_from_py_utility_code(self, env):
if env.outer_scope is None:
return False
if self._convert_from_py_code is False: return # tri-state-ish
if self._convert_from_py_code is None:
for member in self.scope.var_entries:
if (not member.type.from_py_function or not
member.type.create_from_py_utility_code(env)):
self.from_py_function = None
self._convert_from_py_code = False
return False return False
forward_decl = (self.entry.visibility != 'extern') forward_decl = (self.entry.visibility != 'extern')
self._convert_code = StructUtilityCode(self, forward_decl)
env.use_utility_code(self._convert_code) # Avoid C compiler warnings
nesting_depth = 0
type = self
while type.is_struct_or_union:
type = type.scope.var_entries[0].type
nesting_depth += 1
context = dict(
struct_type_decl = self.declaration_code(""),
var_entries = self.scope.var_entries,
funcname = self.from_py_function,
init = '%s 0 %s' % ('{' * nesting_depth, '}' * nesting_depth)
)
self._convert_from_py_code = ContentHashingUtilityCode.load(
"FromPyStructUtility", "TypeConversion.c", context)
env.use_utility_code(self._convert_from_py_code)
return True return True
def __repr__(self): def __repr__(self):
......
...@@ -421,16 +421,24 @@ static CYTHON_INLINE char *__pyx_memviewslice_index_full(const char *bufp, Py_ss ...@@ -421,16 +421,24 @@ static CYTHON_INLINE char *__pyx_memviewslice_index_full(const char *bufp, Py_ss
} }
/////////////// MemviewDtypeToObject.proto /////////////// /////////////// MemviewDtypeToObject.proto ///////////////
{{if to_py_function}}
PyObject *{{get_function}}(const char *itemp); /* proto */ PyObject *{{get_function}}(const char *itemp); /* proto */
{{endif}}
{{if from_py_function}}
int {{set_function}}(const char *itemp, PyObject *obj); /* proto */ int {{set_function}}(const char *itemp, PyObject *obj); /* proto */
{{endif}}
/////////////// MemviewDtypeToObject /////////////// /////////////// MemviewDtypeToObject ///////////////
{{#__pyx_memview_<dtype_name>_to_object}} {{#__pyx_memview_<dtype_name>_to_object}}
{{if to_py_function}}
PyObject *{{get_function}}(const char *itemp) { PyObject *{{get_function}}(const char *itemp) {
return (PyObject *) {{to_py_function}}(*({{dtype}} *) itemp); return (PyObject *) {{to_py_function}}(*({{dtype}} *) itemp);
} }
{{endif}}
{{if from_py_function}}
int {{set_function}}(const char *itemp, PyObject *obj) { int {{set_function}}(const char *itemp, PyObject *obj) {
{{dtype}} value = {{from_py_function}}(obj); {{dtype}} value = {{from_py_function}}(obj);
if ({{error_condition}}) if ({{error_condition}})
...@@ -438,6 +446,7 @@ int {{set_function}}(const char *itemp, PyObject *obj) { ...@@ -438,6 +446,7 @@ int {{set_function}}(const char *itemp, PyObject *obj) {
*({{dtype}} *) itemp = value; *({{dtype}} *) itemp = value;
return 1; return 1;
} }
{{endif}}
/////////////// MemviewObjectToObject.proto /////////////// /////////////// MemviewObjectToObject.proto ///////////////
PyObject *{{get_function}}(const char *itemp); /* proto */ PyObject *{{get_function}}(const char *itemp); /* proto */
......
/////////////// FromPyStructUtility.proto ///////////////
{{struct_type_decl}};
static {{struct_type_decl}} {{funcname}}(PyObject *);
/////////////// FromPyStructUtility ///////////////
static {{struct_type_decl}} {{funcname}}(PyObject * o) {
{{struct_type_decl}} result = {{init}};
PyObject *value = NULL;
if (!PyMapping_Check(o)) {
PyErr_Format(PyExc_TypeError, "Expected a mapping, not %s", o->ob_type->tp_name);
goto bad;
}
{{for member in var_entries:}}
{{py:attr = "result." + member.cname}}
value = PyMapping_GetItemString(o, "{{member.name}}");
if (!value) {
PyErr_SetString(PyExc_ValueError, "No value specified for struct "
"attribute '{{member.name}}'");
goto bad;
}
{{attr}} = {{member.type.from_py_function}}(value);
if ({{member.type.error_condition(attr)}})
goto bad;
Py_DECREF(value);
{{endfor}}
return result;
bad:
Py_XDECREF(value);
return result;
}
...@@ -127,18 +127,18 @@ def test_cdef_attribute(): ...@@ -127,18 +127,18 @@ def test_cdef_attribute():
print ExtClass().mview print ExtClass().mview
'''
def basic_struct(MyStruct[:] mslice): def basic_struct(MyStruct[:] mslice):
""" """
See also buffmt.pyx See also buffmt.pyx
>>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)])) >>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
1 2 3 4 5 [('a', 1), ('b', 2), ('c', 3L), ('d', 4), ('e', 5)]
>>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="bbqii")) >>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="bbqii"))
1 2 3 4 5 [('a', 1), ('b', 2), ('c', 3L), ('d', 4), ('e', 5)]
""" """
buf = mslice buf = mslice
print buf[0].a, buf[0].b, buf[0].c, buf[0].d, buf[0].e print sorted(buf[0].items())
def nested_struct(NestedStruct[:] mslice): def nested_struct(NestedStruct[:] mslice):
""" """
...@@ -150,7 +150,8 @@ def nested_struct(NestedStruct[:] mslice): ...@@ -150,7 +150,8 @@ def nested_struct(NestedStruct[:] mslice):
1 2 3 4 5 1 2 3 4 5
""" """
buf = mslice buf = mslice
print buf[0].x.a, buf[0].x.b, buf[0].y.a, buf[0].y.b, buf[0].z d = buf[0]
print d['x']['a'], d['x']['b'], d['y']['a'], d['y']['b'], d['z']
def packed_struct(PackedStruct[:] mslice): def packed_struct(PackedStruct[:] mslice):
""" """
...@@ -165,7 +166,7 @@ def packed_struct(PackedStruct[:] mslice): ...@@ -165,7 +166,7 @@ def packed_struct(PackedStruct[:] mslice):
""" """
buf = mslice buf = mslice
print buf[0].a, buf[0].b print buf[0]['a'], buf[0]['b']
def nested_packed_struct(NestedPackedStruct[:] mslice): def nested_packed_struct(NestedPackedStruct[:] mslice):
""" """
...@@ -179,7 +180,8 @@ def nested_packed_struct(NestedPackedStruct[:] mslice): ...@@ -179,7 +180,8 @@ def nested_packed_struct(NestedPackedStruct[:] mslice):
1 2 3 4 5 1 2 3 4 5
""" """
buf = mslice buf = mslice
print buf[0].a, buf[0].b, buf[0].sub.a, buf[0].sub.b, buf[0].c d = buf[0]
print d['a'], d['b'], d['sub']['a'], d['sub']['b'], d['c']
def complex_dtype(long double complex[:] mslice): def complex_dtype(long double complex[:] mslice):
...@@ -207,18 +209,8 @@ def complex_struct_dtype(LongComplex[:] mslice): ...@@ -207,18 +209,8 @@ def complex_struct_dtype(LongComplex[:] mslice):
0.0 -1.0 0.0 -1.0
""" """
buf = mslice buf = mslice
print buf[0].real, buf[0].imag print buf[0]['real'], buf[0]['imag']
def complex_struct_inplace(LongComplex[:] mslice):
"""
>>> complex_struct_inplace(LongComplexMockBuffer(None, [(0, -1)]))
1.0 1.0
"""
buf = mslice
buf[0].real += 1
buf[0].imag += 2
print buf[0].real, buf[0].imag
'''
# #
# Getting items and index bounds checking # Getting items and index bounds checking
# #
......
...@@ -60,3 +60,49 @@ def test_pointers(int n, double x): ...@@ -60,3 +60,49 @@ def test_pointers(int n, double x):
print a.data.n print a.data.n
print b.data.x print b.data.x
print a.ptr == b.ptr == NULL print a.ptr == b.ptr == NULL
cdef struct MyStruct:
char c
int i
float f
char *s
def test_obj_to_struct(MyStruct mystruct):
"""
>>> test_obj_to_struct(dict(c=10, i=20, f=6.7, s="hello"))
c=10 i=20 f=6.70 s=hello
>>> test_obj_to_struct(None)
Traceback (most recent call last):
...
TypeError: Expected a mapping, not NoneType
>>> test_obj_to_struct(dict(s="world"))
Traceback (most recent call last):
...
ValueError: No value specified for struct attribute 'c'
>>> test_obj_to_struct(dict(c="world"))
Traceback (most recent call last):
...
TypeError: an integer is required
"""
print 'c=%d i=%d f=%.2f s=%s' % (mystruct.c, mystruct.i, mystruct.f, mystruct.s)
cdef struct NestedStruct:
MyStruct mystruct
double d
def test_nested_obj_to_struct(NestedStruct nested):
"""
>>> test_nested_obj_to_struct(dict(mystruct=dict(c=10, i=20, f=6.7, s="hello"), d=4.5))
c=10 i=20 f=6.70 s=hello d=4.50
>>> test_nested_obj_to_struct(dict(d=7.6))
Traceback (most recent call last):
...
ValueError: No value specified for struct attribute 'mystruct'
>>> test_nested_obj_to_struct(dict(mystruct={}, d=7.6))
Traceback (most recent call last):
...
ValueError: No value specified for struct attribute 'c'
"""
print 'c=%d i=%d f=%.2f s=%s d=%.2f' % (nested.mystruct.c, nested.mystruct.i,
nested.mystruct.f, nested.mystruct.s, nested.d)
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