summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKurt Smith <kwsmith1@wisc.edu>2009-08-10 22:39:13 -0500
committerKurt Smith <kwsmith1@wisc.edu>2009-08-10 22:39:13 -0500
commit59cc6a61fbb6034bc853150a5d4e486fb3c7bea1 (patch)
treeb8d953aac7b943e7cfc0fe4023c42fb004c2f941
parent095a925f40109de4d22a3a869a4184b1ec4f8c3a (diff)
downloadcython-59cc6a61fbb6034bc853150a5d4e486fb3c7bea1.tar.gz
memviewslice copy implementation.
-rw-r--r--Cython/Compiler/CythonScope.py15
-rw-r--r--Cython/Compiler/MemoryView.py179
-rw-r--r--Cython/Compiler/PyrexTypes.py107
3 files changed, 262 insertions, 39 deletions
diff --git a/Cython/Compiler/CythonScope.py b/Cython/Compiler/CythonScope.py
index 41f7bd1b5..931843f96 100644
--- a/Cython/Compiler/CythonScope.py
+++ b/Cython/Compiler/CythonScope.py
@@ -177,13 +177,16 @@ cdef extern from *:
cdef class memoryview(object):
+ cdef object obj
cdef Py_buffer view
cdef int gotbuf_flag
def __cinit__(memoryview self, object obj, int flags):
- __Pyx_GetBuffer(obj, &self.view, flags)
+ self.obj = obj
+ __Pyx_GetBuffer(self.obj, &self.view, flags)
def __dealloc__(memoryview self):
+ self.obj = None
__Pyx_ReleaseBuffer(&self.view)
cdef memoryview memoryview_cwrapper(object o, int flags):
@@ -215,7 +218,7 @@ cdef class array:
Py_ssize_t itemsize
str mode
- def __cinit__(array self, tuple shape, Py_ssize_t itemsize, char *format, mode="c"):
+ def __cinit__(array self, tuple shape, Py_ssize_t itemsize, char *format, str mode="c"):
self.ndim = len(shape)
self.itemsize = itemsize
@@ -245,7 +248,7 @@ cdef class array:
idx += 1
assert idx == self.ndim
- if mode == "fortran":
+ if mode == "f":
idx = 0; stride = 1
for dim in shape:
self.strides[idx] = stride*itemsize
@@ -264,7 +267,7 @@ cdef class array:
assert idx == -1
self.len = stride * itemsize
else:
- raise ValueError("Invalid mode, expected 'c' or 'fortran', got %s" % mode)
+ raise ValueError("Invalid mode, expected 'c' or 'f', got %s" % mode)
self.mode = mode
@@ -277,7 +280,7 @@ cdef class array:
cdef int bufmode = -1
if self.mode == "c":
bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS
- elif self.mode == "fortran":
+ elif self.mode == "f":
bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS
if not (flags & bufmode):
raise ValueError("Can only create a buffer that is contiguous in memory.")
@@ -310,7 +313,7 @@ cdef class array:
self.format = NULL
self.itemsize = 0
-cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char mode):
+cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char *mode):
return array(shape, itemsize, format, mode)
''', prefix=cyarray_prefix)
diff --git a/Cython/Compiler/MemoryView.py b/Cython/Compiler/MemoryView.py
index f04dbb573..4f960dab4 100644
--- a/Cython/Compiler/MemoryView.py
+++ b/Cython/Compiler/MemoryView.py
@@ -69,6 +69,14 @@ def put_init_entry(mv_cname, code):
code.putln("%s.data = NULL;" % mv_cname)
code.putln("%s.memview = NULL;" % mv_cname)
+def mangle_dtype_name(dtype):
+ # a dumb wrapper for now; move Buffer.mangle_dtype_name in here later?
+ import Buffer
+ return Buffer.mangle_dtype_name(dtype)
+
+def axes_to_str(axes):
+ return "".join([access[0]+packing[0] for (access, packing) in axes])
+
def gen_acquire_memoryviewslice(rhs, lhs_type, lhs_is_cglobal, lhs_result, lhs_pos, code):
# import MemoryView
assert rhs.type.is_memoryviewslice
@@ -79,6 +87,7 @@ def gen_acquire_memoryviewslice(rhs, lhs_type, lhs_is_cglobal, lhs_result, lhs_p
else:
rhstmp = code.funcstate.allocate_temp(lhs_type, manage_ref=False)
code.putln("%s = %s;" % (rhstmp, rhs.result_as(lhs_type)))
+ code.putln(code.error_goto_if_null("%s.memview" % rhstmp, lhs_pos))
if not rhs.result_in_temp():
code.put_incref("%s.memview" % rhstmp, cython_memoryview_ptr_type)
@@ -184,6 +193,157 @@ def src_conforms_to_dst(src, dst):
return True
+def get_copy_contents_name(from_mvs, to_mvs):
+ dtype = from_mvs.dtype
+ assert dtype == to_mvs.dtype
+ return ('__Pyx_BufferCopyContents_%s_%s_%s' %
+ (axes_to_str(from_mvs.axes),
+ axes_to_str(to_mvs.axes),
+ mangle_dtype_name(dtype)))
+
+
+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;
+
+}
+'''
+
+def get_copy_contents_code(from_mvs, to_mvs, cfunc_name):
+ assert from_mvs.dtype == to_mvs.dtype
+ assert len(from_mvs.axes) == len(to_mvs.axes)
+
+ ndim = len(from_mvs.axes)
+
+ # XXX: we only support direct access for now.
+ for (access, packing) in from_mvs.axes:
+ if access != 'direct':
+ raise NotImplementedError("only direct access supported currently.")
+
+ code = '''
+
+static int %(cfunc_name)s(const __Pyx_memviewslice *from_mvs, __Pyx_memviewslice *to_mvs) {
+
+ char *to_buf = (char *)to_mvs->data;
+ char *from_buf = (char *)from_mvs->data;
+ struct __pyx_obj_memoryview *temp_memview = 0;
+ char *temp_data = 0;
+
+''' % {'cfunc_name' : cfunc_name}
+
+ if to_mvs.is_c_contig:
+ start, stop, step = 0, ndim, 1
+ elif to_mvs.is_f_contig:
+ start, stop, step = ndim-1, -1, -1
+ else:
+ assert False
+
+ INDENT = " "
+
+ for i, idx in enumerate(range(start, stop, step)):
+ # the crazy indexing is to account for the fortran indexing.
+ # 'i' always goes up from zero to ndim-1.
+ # 'idx' is the same as 'i' for c_contig, and goes from ndim-1 to 0 for f_contig.
+ # this makes the loop code below identical in both cases.
+ code += INDENT+"Py_ssize_t i%d = 0, idx%d = 0;\n" % (i,i)
+ code += INDENT+"Py_ssize_t stride%(i)d = from_mvs->diminfo[%(idx)d].strides;\n" % {'i':i, 'idx':idx}
+ code += INDENT+"Py_ssize_t shape%(i)d = from_mvs->diminfo[%(idx)d].shape;\n" % {'i':i, 'idx':idx}
+
+ code += "\n"
+
+ # put down the nested for-loop.
+ for k in range(ndim):
+
+ code += INDENT*(k+1) + "for(i%(k)d=0; i%(k)d<shape%(k)d; i%(k)d++) {\n" % {'k' : k}
+ code += INDENT*(k+2) + "idx%(k)d = i%(k)d * stride%(k)d;\n" % {'k' : k}
+
+ # the inner part of the loop.
+ dtype_decl = from_mvs.dtype.declaration_code("")
+ last_idx = ndim-1
+ code += INDENT*ndim+"memcpy(to_buf, from_buf+idx%(last_idx)d, sizeof(%(dtype_decl)s));\n" % locals()
+ code += INDENT*ndim+"to_buf += sizeof(%(dtype_decl)s);\n" % locals()
+
+ # for-loop closing braces
+ for k in range(ndim-1, -1, -1):
+ code += INDENT*(k+1)+"}\n"
+
+ # init to_mvs->data and to_mvs->diminfo.
+ code += INDENT+"temp_memview = to_mvs->memview;\n"
+ code += INDENT+"temp_data = to_mvs->data;\n"
+ code += INDENT+"to_mvs->memview = 0; to_mvs->data = 0;\n"
+ code += INDENT+"if(unlikely(-1 == __Pyx_init_memviewslice(temp_memview, %d, to_mvs))) {\n" % (ndim,)
+ code += INDENT*2+"return -1;\n"
+ code += INDENT+"}\n"
+
+ code += INDENT + "return 0;\n"
+
+ code += '}\n'
+
+ return code
def get_axes_specs(env, axes):
'''
@@ -288,16 +448,17 @@ def get_axes_specs(env, axes):
def is_cf_contig(specs):
is_c_contig = is_f_contig = False
- packing_idx = 1
+ if (len(specs) == 1 and specs == [('direct', 'contig')]):
+ is_c_contig = True
- if (specs[-1][packing_idx] == 'contig' and
- all(axis[packing_idx] == 'follow' for axis in specs[:-1])):
+ elif (specs[-1] == ('direct','contig') and
+ all(axis == ('direct','follow') for axis in specs[:-1])):
# c_contiguous: 'follow', 'follow', ..., 'follow', 'contig'
is_c_contig = True
elif (len(specs) > 1 and
- specs[0][packing_idx] == 'contig' and
- all(axis[packing_idx] == 'follow' for axis in specs[1:])):
+ specs[0] == ('direct','contig') and
+ all(axis == ('direct','follow') for axis in specs[1:])):
# f_contiguous: 'contig', 'follow', 'follow', ..., 'follow'
is_f_contig = True
@@ -596,7 +757,13 @@ static int __Pyx_init_memviewslice(
int i, retval=-1;
Py_buffer *buf = &memview->view;
- if(!buf || memviewslice->memview || memviewslice->data) {
+ if(!buf) {
+ PyErr_SetString(PyExc_ValueError,
+ "buf is NULL.");
+ goto fail;
+ } else if(memviewslice->memview || memviewslice->data) {
+ PyErr_SetString(PyExc_ValueError,
+ "memviewslice is already initialized!");
goto fail;
}
diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py
index d97dd497d..40ce7e6c2 100644
--- a/Cython/Compiler/PyrexTypes.py
+++ b/Cython/Compiler/PyrexTypes.py
@@ -294,6 +294,7 @@ class MemoryViewSliceType(PyrexType):
if self.scope is None:
import Symtab, MemoryView
+ from MemoryView import axes_to_str
self.scope = scope = Symtab.CClassScope(
'mvs_class_'+self.specialization_suffix(),
@@ -302,41 +303,90 @@ class MemoryViewSliceType(PyrexType):
scope.parent_type = self
- # the C copy method
- c_copy_name = '__Pyx_CopyBuffer_C_'+self.specialization_suffix()
- scope.declare_cfunction('copy',
- CFuncType(cython_memoryview_ptr_type,
- [CFuncTypeArg("memviewslice", self, None)]),
- pos = None,
- defining = 1,
- cname = c_copy_name)
-
- # the Fortran copy method
- f_copy_name = '__Pyx_CopyBuffer_F_'+self.specialization_suffix()
- scope.declare_cfunction('copy_fortran',
- CFuncType(cython_memoryview_ptr_type,
- [CFuncTypeArg("memviewslice", self, None)]),
- pos = None,
- defining = 1,
- cname = f_copy_name)
+ scope.declare_var('_data', c_char_ptr_type, None, cname='data', is_cdef=1)
- # ensure the right util code is used
- MemoryView.use_cython_array(self.env)
- MemoryView.use_memview_util_code(self.env)
+ mangle_dtype = MemoryView.mangle_dtype_name(self.dtype)
+ ndim = len(self.axes)
- # C copy method implementation.
- ccopy_util_code = UtilityCode()
- # ccopy_util_code.proto =#XXX
+ to_axes_c = [('direct', 'contig')]
+ to_axes_f = [('direct', 'contig')]
+ if ndim-1:
+ to_axes_c = [('direct', 'follow')*(ndim-1)] + to_axes_c
+ to_axes_f = to_axes_f + [('direct', 'follow')*(ndim-1)]
+ to_memview_c = MemoryViewSliceType(self.dtype, to_axes_c, self.env)
+ to_memview_f = MemoryViewSliceType(self.dtype, to_axes_f, self.env)
+ copy_name_c = '__Pyx_BufferNew_C_From_'+self.specialization_suffix()
+ copy_name_f = '__Pyx_BufferNew_F_From_'+self.specialization_suffix()
- return True
+ cython_name_c = 'copy'
+ cython_name_f = 'copy_fortran'
+
+ c_copy_util_code = UtilityCode()
+ f_copy_util_code = UtilityCode()
+
+ for (to_memview, copy_name, cython_name, mode, contig_flag, util_code) in (
+ (to_memview_c, copy_name_c, cython_name_c, 'c', 'PyBUF_C_CONTIGUOUS', c_copy_util_code),
+ (to_memview_f, copy_name_f, cython_name_f, 'f', 'PyBUF_F_CONTIGUOUS', f_copy_util_code)):
+
+ copy_contents_name = MemoryView.get_copy_contents_name(self, to_memview)
+
+ scope.declare_cfunction(cython_name,
+ CFuncType(self,
+ [CFuncTypeArg("memviewslice", self, None)]),
+ pos = None,
+ defining = 1,
+ cname = copy_name)
+
+ copy_impl = MemoryView.copy_template %\
+ dict(copy_name=copy_name,
+ mode=mode,
+ sizeof_dtype="sizeof(%s)" % self.dtype.declaration_code(''),
+ contig_flag=contig_flag,
+ copy_contents_name=copy_contents_name)
+
+ copy_decl = '''\
+static __Pyx_memviewslice %s(const __Pyx_memviewslice); /* proto */
+ ''' % (copy_name,)
+
+ util_code.proto = copy_decl
+ util_code.impl = copy_impl
+
+ copy_contents_name_c = MemoryView.get_copy_contents_name(self, to_memview_c)
+ copy_contents_name_f = MemoryView.get_copy_contents_name(self, to_memview_f)
- def axes_to_str(self):
- return "".join([access[0]+packing[0] for (access, packing) in self.axes])
+ c_copy_util_code.proto += ('static int %s'
+ '(const __Pyx_memviewslice *,'
+ ' __Pyx_memviewslice *); /* proto */\n' %
+ (copy_contents_name_c,))
+
+ c_copy_util_code.impl += \
+ MemoryView.get_copy_contents_code(self, to_memview_c, copy_contents_name_c)
+
+ if (MemoryView.get_copy_contents_code(self, to_memview_c, copy_contents_name_c) !=
+ MemoryView.get_copy_contents_code(self, to_memview_f, copy_contents_name_f)):
+
+ f_copy_util_code.proto += ('static int %s'
+ '(const __Pyx_memviewslice *,'
+ ' __Pyx_memviewslice *); /* proto */\n' %
+ (copy_contents_name_f,))
+
+ f_copy_util_code.impl += \
+ MemoryView.get_copy_contents_code(self, to_memview_f, copy_contents_name_f)
+
+ self.env.use_utility_code(c_copy_util_code)
+ self.env.use_utility_code(c_copy_util_code)
+
+ # ensure the right util code is used
+ MemoryView.use_cython_array(self.env)
+ MemoryView.use_memview_util_code(self.env)
+
+ return True
def specialization_suffix(self):
- return self.axes_to_str() + '_' + self.dtype.specalization_name()
+ import MemoryView
+ return MemoryView.axes_to_str(self.axes) + '_' + MemoryView.mangle_dtype_name(self.dtype)
def global_init_code(self, entry, code):
code.putln("%s.data = NULL;" % entry.cname)
@@ -1702,6 +1752,9 @@ cython_memoryview_type = CStructOrUnionType("__pyx_obj_memoryview", "struct",
cython_memoryview_ptr_type = CPtrType(cython_memoryview_type)
+memoryviewslice_type = CStructOrUnionType("__Pyx_memviewslice", "struct",
+ None, 1, "__Pyx_memviewslice")
+
error_type = ErrorType()
unspecified_type = UnspecifiedType()