Commit a5953c6c authored by Kurt Smith's avatar Kurt Smith Committed by Mark Florisson

refactoring of MemoryViewSliceType utility code.

parent c041335f
...@@ -592,7 +592,6 @@ class ExprNode(Node): ...@@ -592,7 +592,6 @@ class ExprNode(Node):
error(self.pos, "Memoryview '%s' not conformable to memoryview '%s'." % error(self.pos, "Memoryview '%s' not conformable to memoryview '%s'." %
(src.type, dst_type)) (src.type, dst_type))
elif dst_type.is_pyobject: elif dst_type.is_pyobject:
if not src.type.is_pyobject: if not src.type.is_pyobject:
if dst_type is bytes_type and src.type.is_int: if dst_type is bytes_type and src.type.is_int:
......
...@@ -6,6 +6,8 @@ import CythonScope ...@@ -6,6 +6,8 @@ import CythonScope
from Code import UtilityCode from Code import UtilityCode
from UtilityCode import CythonUtilityCode from UtilityCode import CythonUtilityCode
from PyrexTypes import py_object_type, cython_memoryview_ptr_type from PyrexTypes import py_object_type, cython_memoryview_ptr_type
import Buffer
START_ERR = "there must be nothing or the value 0 (zero) in the start slot." START_ERR = "there must be nothing or the value 0 (zero) in the start slot."
STOP_ERR = "Axis specification only allowed in the 'stop' slot." STOP_ERR = "Axis specification only allowed in the 'stop' slot."
...@@ -158,6 +160,14 @@ def src_conforms_to_dst(src, dst): ...@@ -158,6 +160,14 @@ def src_conforms_to_dst(src, dst):
return True return True
def get_copy_func_name(to_memview):
base = "__Pyx_BufferNew_%s_From_%s_%s"
if to_memview.is_c_contig:
return base % ('C', axes_to_str(to_memview.axes), mangle_dtype_name(to_memview.dtype))
else:
return base % ('F', axes_to_str(to_memview.axes), mangle_dtype_name(to_memview.dtype))
def get_copy_contents_name(from_mvs, to_mvs): def get_copy_contents_name(from_mvs, to_mvs):
dtype = from_mvs.dtype dtype = from_mvs.dtype
assert dtype == to_mvs.dtype assert dtype == to_mvs.dtype
...@@ -166,6 +176,33 @@ def get_copy_contents_name(from_mvs, to_mvs): ...@@ -166,6 +176,33 @@ def get_copy_contents_name(from_mvs, to_mvs):
axes_to_str(to_mvs.axes), axes_to_str(to_mvs.axes),
mangle_dtype_name(dtype))) mangle_dtype_name(dtype)))
class IsContigFuncUtilCode(object):
requires = None
def __init__(self, c_or_f):
self.c_or_f = c_or_f
self.is_contig_func_name = get_is_contig_func_name(self.c_or_f)
def __eq__(self, other):
if not isinstance(other, IsContigFuncUtilCode):
return False
return self.is_contig_func_name == other.is_contig_func_name
def __hash__(self):
return hash(self.is_contig_func_name)
def get_tree(self): pass
def put_code(self, output):
code = output['utility_code_def']
proto = output['utility_code_proto']
func_decl, func_impl = get_is_contiguous_func(self.c_or_f)
proto.put(func_decl)
code.put(func_impl)
def get_is_contig_func_name(c_or_f): def get_is_contig_func_name(c_or_f):
return "__Pyx_Buffer_is_%s_contiguous" % c_or_f return "__Pyx_Buffer_is_%s_contiguous" % c_or_f
...@@ -226,111 +263,91 @@ static int %(copy_to_name)s(const __Pyx_memviewslice from_mvs, __Pyx_memviewslic ...@@ -226,111 +263,91 @@ static int %(copy_to_name)s(const __Pyx_memviewslice from_mvs, __Pyx_memviewslic
} }
''' '''
copy_template = ''' class CopyContentsFuncUtilCode(object):
static __Pyx_memviewslice %(copy_name)s(const __Pyx_memviewslice from_mvs) {
int i; requires = None
__Pyx_memviewslice new_mvs = {0, 0};
struct __pyx_obj_memoryview *from_memview = from_mvs.memview;
Py_buffer *buf = &from_memview->view;
PyObject *shape_tuple = 0;
PyObject *temp_int = 0;
struct __pyx_obj_array *array_obj = 0;
struct __pyx_obj_memoryview *memview_obj = 0;
char mode[] = "%(mode)s";
__Pyx_SetupRefcountContext("%(copy_name)s"); def __init__(self, from_memview, to_memview):
self.from_memview = from_memview
self.to_memview = to_memview
self.copy_contents_name = get_copy_contents_name(from_memview, to_memview)
shape_tuple = PyTuple_New((Py_ssize_t)(buf->ndim)); def __eq__(self, other):
if(unlikely(!shape_tuple)) { if not isinstance(other, CopyContentsFuncUtilCode):
goto fail; return False
} return other.copy_contents_name == self.copy_contents_name
__Pyx_GOTREF(shape_tuple);
def __hash__(self):
return hash(self.copy_contents_name)
for(i=0; i<buf->ndim; i++) { def get_tree(self): pass
temp_int = PyInt_FromLong(buf->shape[i]);
if(unlikely(!temp_int)) {
goto fail;
} else {
PyTuple_SET_ITEM(shape_tuple, i, temp_int);
}
}
array_obj = __pyx_cythonarray_array_cwrapper(shape_tuple, %(sizeof_dtype)s, buf->format, mode); def put_code(self, output):
if (unlikely(!array_obj)) { code = output['utility_code_def']
goto fail; proto = output['utility_code_proto']
}
__Pyx_GOTREF(array_obj);
memview_obj = __pyx_viewaxis_memoryview_cwrapper((PyObject *)array_obj, %(contig_flag)s); func_decl, func_impl = \
if (unlikely(!memview_obj)) { get_copy_contents_func(self.from_memview, self.to_memview, self.copy_contents_name)
goto fail;
}
/* initialize new_mvs */ proto.put(func_decl)
if (unlikely(-1 == __Pyx_init_memviewslice(memview_obj, buf->ndim, &new_mvs))) { code.put(func_impl)
PyErr_SetString(PyExc_RuntimeError,
"Could not initialize new memoryviewslice object.");
goto fail;
}
if (unlikely(-1 == %(copy_contents_name)s(&from_mvs, &new_mvs))) { class CopyFuncUtilCode(object):
/* PyErr_SetString(PyExc_RuntimeError,
"Could not copy contents of memoryview slice."); */
goto fail;
}
goto no_fail; requires = None
fail: def __init__(self, from_memview, to_memview):
__Pyx_XDECREF(new_mvs.memview); new_mvs.memview = 0; if from_memview.dtype != to_memview.dtype:
new_mvs.data = 0; raise ValueError("dtypes must be the same!")
no_fail: if len(from_memview.axes) != len(to_memview.axes):
__Pyx_XDECREF(shape_tuple); shape_tuple = 0; raise ValueError("number of dimensions must be same")
__Pyx_GOTREF(temp_int); if not (to_memview.is_c_contig or to_memview.is_f_contig):
__Pyx_XDECREF(temp_int); temp_int = 0; raise ValueError("to_memview must be c or f contiguous.")
__Pyx_XDECREF(array_obj); array_obj = 0; for (access, packing) in from_memview.axes:
__Pyx_FinishRefcountContext(); if access != 'direct':
return new_mvs; raise NotImplementedError("cannot handle 'full' or 'ptr' access at this time.")
} self.from_memview = from_memview
''' self.to_memview = to_memview
self.copy_func_name = get_copy_func_name(to_memview)
def memoryviewslice_get_copy_func(from_memview, to_memview, mode, scope): self.requires = [CopyContentsFuncUtilCode(from_memview, to_memview)]
from PyrexTypes import CFuncType, CFuncTypeArg
if mode == 'c': def __eq__(self, other):
cython_name = "copy" if not isinstance(other, CopyFuncUtilCode):
copy_name = '__Pyx_BufferNew_C_From_'+from_memview.specialization_suffix() return False
contig_flag = 'PyBUF_C_CONTIGUOUS' return other.copy_func_name == self.copy_func_name
elif mode == 'fortran':
cython_name = "copy_fortran"
copy_name = "__Pyx_BufferNew_F_From_"+from_memview.specialization_suffix()
contig_flag = 'PyBUF_F_CONTIGUOUS'
else:
assert False
copy_contents_name = get_copy_contents_name(from_memview, to_memview) def __hash__(self):
return hash(self.copy_func_name)
entry = scope.declare_cfunction(cython_name, def get_tree(self): pass
CFuncType(from_memview,
[CFuncTypeArg("memviewslice", from_memview, None)]),
pos = None,
defining = 1,
cname = copy_name)
copy_impl = copy_template % dict( def put_code(self, output):
copy_name=copy_name, code = output['utility_code_def']
proto = output['utility_code_proto']
proto.put(Buffer.dedent("""\
static __Pyx_memviewslice %s(const __Pyx_memviewslice from_mvs); /* proto */
""" % self.copy_func_name))
copy_contents_name = get_copy_contents_name(self.from_memview, self.to_memview)
if self.to_memview.is_c_contig:
mode = 'c'
contig_flag = 'PyBUF_C_CONTIGUOUS'
elif self.to_memview.is_f_contig:
mode = 'fortran'
contig_flag = "PyBUF_F_CONTIGUOUS"
code.put(copy_template %
dict(
copy_name=self.copy_func_name,
mode=mode, mode=mode,
sizeof_dtype="sizeof(%s)" % from_memview.dtype.declaration_code(''), sizeof_dtype="sizeof(%s)" % self.from_memview.dtype.declaration_code(''),
contig_flag=contig_flag, contig_flag=contig_flag,
copy_contents_name=copy_contents_name) copy_contents_name=copy_contents_name))
copy_decl = ("static __Pyx_memviewslice "
"%s(const __Pyx_memviewslice); /* proto */\n" % (copy_name,))
return (copy_decl, copy_impl, entry)
def get_copy_contents_func(from_mvs, to_mvs, cfunc_name): def get_copy_contents_func(from_mvs, to_mvs, cfunc_name):
assert from_mvs.dtype == to_mvs.dtype assert from_mvs.dtype == to_mvs.dtype
...@@ -631,6 +648,77 @@ class MemoryViewSliceTransform(CythonTransform): ...@@ -631,6 +648,77 @@ class MemoryViewSliceTransform(CythonTransform):
def visit_SingleAssignmentNode(self, node): def visit_SingleAssignmentNode(self, node):
return node return node
copy_template = '''
static __Pyx_memviewslice %(copy_name)s(const __Pyx_memviewslice from_mvs) {
int i;
__Pyx_memviewslice new_mvs = {0, 0};
struct __pyx_obj_memoryview *from_memview = from_mvs.memview;
Py_buffer *buf = &from_memview->view;
PyObject *shape_tuple = 0;
PyObject *temp_int = 0;
struct __pyx_obj_array *array_obj = 0;
struct __pyx_obj_memoryview *memview_obj = 0;
char mode[] = "%(mode)s";
__Pyx_SetupRefcountContext("%(copy_name)s");
shape_tuple = PyTuple_New((Py_ssize_t)(buf->ndim));
if(unlikely(!shape_tuple)) {
goto fail;
}
__Pyx_GOTREF(shape_tuple);
for(i=0; i<buf->ndim; i++) {
temp_int = PyInt_FromLong(buf->shape[i]);
if(unlikely(!temp_int)) {
goto fail;
} else {
PyTuple_SET_ITEM(shape_tuple, i, temp_int);
}
}
array_obj = __pyx_cythonarray_array_cwrapper(shape_tuple, %(sizeof_dtype)s, buf->format, mode);
if (unlikely(!array_obj)) {
goto fail;
}
__Pyx_GOTREF(array_obj);
memview_obj = __pyx_viewaxis_memoryview_cwrapper((PyObject *)array_obj, %(contig_flag)s);
if (unlikely(!memview_obj)) {
goto fail;
}
/* initialize new_mvs */
if (unlikely(-1 == __Pyx_init_memviewslice(memview_obj, buf->ndim, &new_mvs))) {
PyErr_SetString(PyExc_RuntimeError,
"Could not initialize new memoryviewslice object.");
goto fail;
}
if (unlikely(-1 == %(copy_contents_name)s(&from_mvs, &new_mvs))) {
/* PyErr_SetString(PyExc_RuntimeError,
"Could not copy contents of memoryview slice."); */
goto fail;
}
goto no_fail;
fail:
__Pyx_XDECREF(new_mvs.memview); new_mvs.memview = 0;
new_mvs.data = 0;
no_fail:
__Pyx_XDECREF(shape_tuple); shape_tuple = 0;
__Pyx_GOTREF(temp_int);
__Pyx_XDECREF(temp_int); temp_int = 0;
__Pyx_XDECREF(array_obj); array_obj = 0;
__Pyx_FinishRefcountContext();
return new_mvs;
}
'''
spec_constants_code = UtilityCode(proto=""" spec_constants_code = UtilityCode(proto="""
#define __Pyx_MEMVIEW_DIRECT 1 #define __Pyx_MEMVIEW_DIRECT 1
#define __Pyx_MEMVIEW_PTR 2 #define __Pyx_MEMVIEW_PTR 2
......
...@@ -387,6 +387,7 @@ class MemoryViewSliceType(PyrexType): ...@@ -387,6 +387,7 @@ class MemoryViewSliceType(PyrexType):
import Symtab, MemoryView import Symtab, MemoryView
from MemoryView import axes_to_str from MemoryView import axes_to_str
self.scope = scope = Symtab.CClassScope( self.scope = scope = Symtab.CClassScope(
'mvs_class_'+self.specialization_suffix(), 'mvs_class_'+self.specialization_suffix(),
None, None,
...@@ -408,53 +409,41 @@ class MemoryViewSliceType(PyrexType): ...@@ -408,53 +409,41 @@ class MemoryViewSliceType(PyrexType):
to_memview_c = MemoryViewSliceType(self.dtype, to_axes_c) to_memview_c = MemoryViewSliceType(self.dtype, to_axes_c)
to_memview_f = MemoryViewSliceType(self.dtype, to_axes_f) to_memview_f = MemoryViewSliceType(self.dtype, to_axes_f)
copy_contents_name_c =\ cython_name_c, cython_name_f = "copy", "copy_fortran"
MemoryView.get_copy_contents_name(self, to_memview_c) copy_name_c, copy_name_f = (
copy_contents_name_f =\ MemoryView.get_copy_func_name(to_memview_c),
MemoryView.get_copy_contents_name(self, to_memview_f) MemoryView.get_copy_func_name(to_memview_f))
c_copy_decl, c_copy_impl, c_entry = \
MemoryView.memoryviewslice_get_copy_func(self, to_memview_c, 'c', self.scope)
f_copy_decl, f_copy_impl, f_entry = \
MemoryView.memoryviewslice_get_copy_func(self, to_memview_f, 'fortran', self.scope)
c_copy_contents_decl, c_copy_contents_impl = \
MemoryView.get_copy_contents_func(
self, to_memview_c, copy_contents_name_c)
f_copy_contents_decl, f_copy_contents_impl = \
MemoryView.get_copy_contents_func(
self, to_memview_f, copy_contents_name_f)
c_util_code = UtilityCode( for (to_memview, cython_name, copy_name) in ((to_memview_c, cython_name_c, copy_name_c),
proto = "%s%s" % (c_copy_decl, c_copy_contents_decl), (to_memview_f, cython_name_f, copy_name_f)):
impl = "%s%s" % (c_copy_impl, c_copy_contents_impl))
f_util_code = UtilityCode(
proto = f_copy_decl,
impl = f_copy_impl)
c_entry.utility_code_definition = c_util_code entry = scope.declare_cfunction(cython_name,
f_entry.utility_code_definition = f_util_code CFuncType(self,
[CFuncTypeArg("memviewslice", self, None)]),
pos = None,
defining = 1,
cname = copy_name)
if copy_contents_name_c != copy_contents_name_f: entry.utility_code_definition = \
f_util_code.proto += f_copy_contents_decl MemoryView.CopyFuncUtilCode(self, to_memview)
f_util_code.impl += f_copy_contents_impl
# is_c_contiguous and is_f_contiguous functions # is_c_contig and is_f_contig functions
for (c_or_f, cython_name) in (('c', 'is_c_contig'), ('fortran', 'is_f_contig')):
for c_or_f, cython_name in (('c', 'is_c_contig'), ('fortran', 'is_f_contig')): is_contig_name = \
MemoryView.get_is_contig_func_name(c_or_f)
is_contig_name = MemoryView.get_is_contig_func_name(c_or_f) entry = scope.declare_cfunction(cython_name,
scope.declare_cfunction(cython_name,
CFuncType(c_int_type, CFuncType(c_int_type,
[CFuncTypeArg("memviewslice", self, None)]), [CFuncTypeArg("memviewslice", self, None)]),
pos = None, pos = None,
defining = 1, defining = 1,
cname = is_contig_name) cname = is_contig_name)
contig_decl, contig_impl = MemoryView.get_is_contiguous_func(c_or_f) entry.utility_code_definition = \
MemoryView.IsContigFuncUtilCode(c_or_f)
contig_util_code = UtilityCode(
proto = contig_decl, impl = contig_impl)
return True return True
......
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