Commit d7322d2f authored by Mark Florisson's avatar Mark Florisson

object -> struct conversion

parent 5197f5cf
......@@ -1598,9 +1598,13 @@ class CCodeWriter(object):
self.put_var_xdecref_clear(entry)
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)))
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)))
def put_xgiveref_memoryviewslice(self, slice_cname):
......
......@@ -778,7 +778,7 @@ memviewslice_declare_code = load_memview_c_utility(
memviewslice_init_code = load_memview_c_utility(
"MemviewSliceInit",
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")
\ No newline at end of file
......@@ -2,7 +2,7 @@
# Cython/Python language types
#
from Code import UtilityCode, LazyUtilityCode
from Code import UtilityCode, LazyUtilityCode, ContentHashingUtilityCode
import StringEncoding
import Naming
import copy
......@@ -518,7 +518,7 @@ class MemoryViewSliceType(PyrexType):
def lazy_utility_callback(code):
context['dtype_typeinfo'] = Buffer.get_type_information_cname(
code, self.dtype)
return Code.ContentHashingUtilityCode.load(
return ContentHashingUtilityCode.load(
"ObjectToMemviewSlice", "MemoryView_C.c", context)
env.use_utility_code(Buffer.acquire_utility_code)
......@@ -576,11 +576,17 @@ class MemoryViewSliceType(PyrexType):
if self.dtype.is_pyobject:
utility_name = "MemviewObjectToObject"
else:
if not (self.dtype.create_to_py_utility_code(env) and
self.dtype.create_from_py_utility_code(env)):
print "cannot convert %s" % self.dtype
to_py = self.dtype.create_to_py_utility_code(env)
from_py = self.dtype.create_from_py_utility_code(env)
if not (to_py or from_py):
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"
error_condition = (self.dtype.error_condition('value') or
'PyErr_Occurred()')
......@@ -591,7 +597,7 @@ class MemoryViewSliceType(PyrexType):
error_condition = error_condition,
)
utility = Code.ContentHashingUtilityCode.load(
utility = ContentHashingUtilityCode.load(
utility_name, "MemoryView_C.c", context=context)
env.use_utility_code(utility)
return get_function, set_function
......@@ -2329,17 +2335,19 @@ class CFuncTypeArg(object):
def specialize(self, values):
return CFuncTypeArg(self.name, self.type.specialize(values), self.pos, self.cname)
class StructUtilityCode(object):
class ToPyStructUtilityCode(object):
requires = None
def __init__(self, type, forward_decl):
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
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):
return hash(self.header)
......@@ -2389,6 +2397,7 @@ class CStructOrUnionType(CType):
is_struct_or_union = 1
has_attributes = 1
exception_check = True
def __init__(self, name, kind, scope, typedef_flag, cname, packed=False):
self.name = name
......@@ -2399,26 +2408,63 @@ class CStructOrUnionType(CType):
self.is_struct = kind == 'struct'
if self.is_struct:
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._convert_code = None
self._convert_to_py_code = None
self._convert_from_py_code = None
self.packed = packed
def create_to_py_utility_code(self, env):
if env.outer_scope is None:
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:
if not member.type.to_py_function or not member.type.create_to_py_utility_code(env):
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
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
def __repr__(self):
......
......@@ -421,16 +421,24 @@ static CYTHON_INLINE char *__pyx_memviewslice_index_full(const char *bufp, Py_ss
}
/////////////// MemviewDtypeToObject.proto ///////////////
{{if to_py_function}}
PyObject *{{get_function}}(const char *itemp); /* proto */
{{endif}}
{{if from_py_function}}
int {{set_function}}(const char *itemp, PyObject *obj); /* proto */
{{endif}}
/////////////// MemviewDtypeToObject ///////////////
{{#__pyx_memview_<dtype_name>_to_object}}
{{if to_py_function}}
PyObject *{{get_function}}(const char *itemp) {
return (PyObject *) {{to_py_function}}(*({{dtype}} *) itemp);
}
{{endif}}
{{if from_py_function}}
int {{set_function}}(const char *itemp, PyObject *obj) {
{{dtype}} value = {{from_py_function}}(obj);
if ({{error_condition}})
......@@ -438,6 +446,7 @@ int {{set_function}}(const char *itemp, PyObject *obj) {
*({{dtype}} *) itemp = value;
return 1;
}
{{endif}}
/////////////// MemviewObjectToObject.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():
print ExtClass().mview
'''
def basic_struct(MyStruct[:] mslice):
"""
See also buffmt.pyx
>>> 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"))
1 2 3 4 5
[('a', 1), ('b', 2), ('c', 3L), ('d', 4), ('e', 5)]
"""
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):
"""
......@@ -150,7 +150,8 @@ def nested_struct(NestedStruct[:] mslice):
1 2 3 4 5
"""
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):
"""
......@@ -165,7 +166,7 @@ def packed_struct(PackedStruct[:] mslice):
"""
buf = mslice
print buf[0].a, buf[0].b
print buf[0]['a'], buf[0]['b']
def nested_packed_struct(NestedPackedStruct[:] mslice):
"""
......@@ -179,7 +180,8 @@ def nested_packed_struct(NestedPackedStruct[:] mslice):
1 2 3 4 5
"""
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):
......@@ -207,18 +209,8 @@ def complex_struct_dtype(LongComplex[:] mslice):
0.0 -1.0
"""
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
#
......
......@@ -60,3 +60,49 @@ def test_pointers(int n, double x):
print a.data.n
print b.data.x
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