summaryrefslogtreecommitdiff
path: root/Cython/Compiler/MemoryView.py
diff options
context:
space:
mode:
authorMark Florisson <markflorisson88@gmail.com>2011-12-23 23:08:56 +0100
committerMark Florisson <markflorisson88@gmail.com>2012-01-22 19:04:19 +0000
commit4b9a1ff76fed95b708029ea32875c08a3707d1a9 (patch)
treef5da3737d66d10358ff7f6414475c4a84b51b5b2 /Cython/Compiler/MemoryView.py
parent50bd1a47df03637d15e1be45a39f8d915febda9c (diff)
downloadcython-4b9a1ff76fed95b708029ea32875c08a3707d1a9.tar.gz
Refactor memoryview copying + support overlapping memory
Diffstat (limited to 'Cython/Compiler/MemoryView.py')
-rw-r--r--Cython/Compiler/MemoryView.py270
1 files changed, 51 insertions, 219 deletions
diff --git a/Cython/Compiler/MemoryView.py b/Cython/Compiler/MemoryView.py
index 5b89b2268..a695856ed 100644
--- a/Cython/Compiler/MemoryView.py
+++ b/Cython/Compiler/MemoryView.py
@@ -384,235 +384,66 @@ def get_memoryview_flag(access, packing):
assert (access, packing) == ('direct', 'contig'), (access, packing)
return 'contiguous'
-def get_copy_func_name(to_memview):
- base = "__Pyx_BufferNew_%s_From_%s"
- if to_memview.is_c_contig:
- return base % ('C', to_memview.specialization_suffix())
+def get_is_contig_func_name(c_or_f, ndim):
+ return "__pyx_memviewslice_is_%s_contig%d" % (c_or_f, ndim)
+
+def get_is_contig_utility(c_contig, ndim):
+ C = dict(context, ndim=ndim)
+ if c_contig:
+ utility = load_memview_c_utility("MemviewSliceIsCContig", C,
+ requires=[is_contig_utility])
else:
- return base % ('F', to_memview.specialization_suffix())
-
-def get_copy_contents_name(from_mvs, to_mvs):
- assert from_mvs.dtype == to_mvs.dtype
- return '__Pyx_BufferCopyContents_%s_to_%s' % (from_mvs.specialization_suffix(),
- to_mvs.specialization_suffix())
-
-def get_is_contig_func_name(c_or_f):
- return "__pyx_memviewslice_is_%s_contig" % c_or_f
-
-copy_to_template = '''
-static int %(copy_to_name)s(const __Pyx_memviewslice from_mvs, __Pyx_memviewslice to_mvs) {
-
- /* ensure from_mvs & to_mvs have the same shape & dtype */
-
-}
-'''
-
-class CopyContentsFuncUtilCode(object):
-
- requires = None
-
- 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)
-
- def __eq__(self, other):
- if not isinstance(other, CopyContentsFuncUtilCode):
- return False
- return other.copy_contents_name == self.copy_contents_name
-
- def __hash__(self):
- return hash(self.copy_contents_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_copy_contents_func(self.from_memview, self.to_memview, self.copy_contents_name)
+ utility = load_memview_c_utility("MemviewSliceIsFContig", C,
+ requires=[is_contig_utility])
- proto.put(func_decl)
- code.put(func_impl)
+ return utility
-class CopyFuncUtilCode(object):
+def copy_src_to_dst_cname():
+ return "__pyx_memoryview_copy_contents"
- requires = None
-
- def __init__(self, from_memview, to_memview):
- if from_memview.dtype != to_memview.dtype:
- raise ValueError("dtypes must be the same!")
- if len(from_memview.axes) != len(to_memview.axes):
- raise ValueError("number of dimensions must be same")
- if not (to_memview.is_c_contig or to_memview.is_f_contig):
- raise ValueError("to_memview must be c or f contiguous.")
- for (access, packing) in from_memview.axes:
- if access != 'direct':
- 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)
-
- self.requires = [CopyContentsFuncUtilCode(from_memview, to_memview)]
-
- def __eq__(self, other):
- if not isinstance(other, CopyFuncUtilCode):
- return False
- return other.copy_func_name == self.copy_func_name
-
- def __hash__(self):
- return hash(self.copy_func_name)
-
- def get_tree(self): pass
-
- def put_code(self, output):
- code = output['utility_code_def']
- proto = output['utility_code_proto']
+def copy_c_or_fortran_cname(memview):
+ if memview.is_c_contig:
+ c_or_f = 'c'
+ else:
+ c_or_f = 'f'
- proto.put(Buffer.dedent("""\
- static __Pyx_memviewslice %s(const __Pyx_memviewslice from_mvs); /* proto */
- """ % self.copy_func_name))
+ return "__pyx_memoryview_copy_slice_%s_%s" % (
+ memview.specialization_suffix(), c_or_f)
- copy_contents_name = get_copy_contents_name(self.from_memview, self.to_memview)
+def get_copy_new_utility(pos, from_memview, to_memview):
+ if from_memview.dtype != to_memview.dtype:
+ return error(pos, "dtypes must be the same!")
+ if len(from_memview.axes) != len(to_memview.axes):
+ return error(pos, "number of dimensions must be same")
+ if not (to_memview.is_c_contig or to_memview.is_f_contig):
+ return error(pos, "to_memview must be c or f contiguous.")
- if self.to_memview.is_c_contig:
- mode = 'c'
- contig_flag = memview_c_contiguous
- elif self.to_memview.is_f_contig:
- mode = 'fortran'
- contig_flag = memview_f_contiguous
+ for (access, packing) in from_memview.axes:
+ if access != 'direct':
+ return error(
+ pos, "cannot handle 'full' or 'ptr' access at this time.")
- C = dict(
+ if to_memview.is_c_contig:
+ mode = 'c'
+ contig_flag = memview_c_contiguous
+ elif to_memview.is_f_contig:
+ mode = 'fortran'
+ contig_flag = memview_f_contiguous
+
+ return load_memview_c_utility(
+ "CopyContentsUtility",
+ context=dict(
context,
- copy_name=self.copy_func_name,
mode=mode,
- sizeof_dtype="sizeof(%s)" % self.from_memview.dtype.declaration_code(''),
+ dtype_decl=to_memview.dtype.declaration_code(''),
contig_flag=contig_flag,
- copy_contents_name=copy_contents_name
- )
-
- _, copy_code = TempitaUtilityCode.load_as_string(
- "MemviewSliceCopyTemplate",
- from_file="MemoryView_C.c",
- context=C)
- code.put(copy_code)
-
-
-def get_copy_contents_func(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("currently only direct access is supported.")
-
- code_decl = ("static int %(cfunc_name)s(const __Pyx_memviewslice *from_mvs,"
- "__Pyx_memviewslice *to_mvs); /* proto */" % {'cfunc_name' : cfunc_name})
-
- code_impl = '''
-
-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_memoryview_obj *temp_memview = 0;
- char *temp_data = 0;
-
- int ndim_idx = 0;
-
- for(ndim_idx=0; ndim_idx<%(ndim)d; ndim_idx++) {
- if(from_mvs->shape[ndim_idx] != to_mvs->shape[ndim_idx]) {
- PyErr_Format(PyExc_ValueError,
- "memoryview shapes not the same in dimension %%d", ndim_idx);
- return -1;
- }
- }
-
-''' % {'cfunc_name' : cfunc_name, 'ndim' : ndim}
-
- # raise NotImplementedError("put in shape checking code here!!!")
-
- INDENT = " "
- dtype_decl = from_mvs.dtype.declaration_code("")
- last_idx = ndim-1
-
- if to_mvs.is_c_contig or to_mvs.is_f_contig:
- 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
-
-
- 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_impl += INDENT+"Py_ssize_t i%d = 0, idx%d = 0;\n" % (i,i)
- code_impl += INDENT+"Py_ssize_t stride%(i)d = from_mvs->strides[%(idx)d];\n" % {'i':i, 'idx':idx}
- code_impl += INDENT+"Py_ssize_t shape%(i)d = from_mvs->shape[%(idx)d];\n" % {'i':i, 'idx':idx}
-
- code_impl += "\n"
-
- # put down the nested for-loop.
- for k in range(ndim):
-
- code_impl += INDENT*(k+1) + "for(i%(k)d=0; i%(k)d<shape%(k)d; i%(k)d++) {\n" % {'k' : k}
- if k >= 1:
- code_impl += INDENT*(k+2) + "idx%(k)d = i%(k)d * stride%(k)d + idx%(km1)d;\n" % {'k' : k, 'km1' : k-1}
- else:
- code_impl += INDENT*(k+2) + "idx%(k)d = i%(k)d * stride%(k)d;\n" % {'k' : k}
-
- # the inner part of the loop.
- code_impl += INDENT*(ndim+1)+"memcpy(to_buf, from_buf+idx%(last_idx)d, sizeof(%(dtype_decl)s));\n" % locals()
- code_impl += INDENT*(ndim+1)+"to_buf += sizeof(%(dtype_decl)s);\n" % locals()
-
-
- else:
-
- code_impl += INDENT+"/* 'f' prefix is for the 'from' memview, 't' prefix is for the 'to' memview */\n"
- for i in range(ndim):
- code_impl += INDENT+"char *fi%d = 0, *ti%d = 0, *end%d = 0;\n" % (i,i,i)
- code_impl += INDENT+"Py_ssize_t fstride%(i)d = from_mvs->strides[%(i)d];\n" % {'i':i}
- code_impl += INDENT+"Py_ssize_t fshape%(i)d = from_mvs->shape[%(i)d];\n" % {'i':i}
- code_impl += INDENT+"Py_ssize_t tstride%(i)d = to_mvs->strides[%(i)d];\n" % {'i':i}
- # code_impl += INDENT+"Py_ssize_t tshape%(i)d = to_mvs->shape[%(i)d];\n" % {'i':i}
-
- code_impl += INDENT+"end0 = fshape0 * fstride0 + from_mvs->data;\n"
- code_impl += INDENT+"for(fi0=from_buf, ti0=to_buf; fi0 < end0; fi0 += fstride0, ti0 += tstride0) {\n"
- for i in range(1, ndim):
- code_impl += INDENT*(i+1)+"end%(i)d = fshape%(i)d * fstride%(i)d + fi%(im1)d;\n" % {'i' : i, 'im1' : i-1}
- code_impl += INDENT*(i+1)+"for(fi%(i)d=fi%(im1)d, ti%(i)d=ti%(im1)d; fi%(i)d < end%(i)d; fi%(i)d += fstride%(i)d, ti%(i)d += tstride%(i)d) {\n" % {'i':i, 'im1':i-1}
-
- code_impl += INDENT*(ndim+1)+"*(%(dtype_decl)s*)(ti%(last_idx)d) = *(%(dtype_decl)s*)(fi%(last_idx)d);\n" % locals()
-
- # for-loop closing braces
- for k in range(ndim-1, -1, -1):
- code_impl += INDENT*(k+1)+"}\n"
-
- # init to_mvs->data and to_mvs shape/strides/suboffsets arrays.
- code_impl += INDENT+"temp_memview = to_mvs->memview;\n"
- code_impl += INDENT+"temp_data = to_mvs->data;\n"
- code_impl += INDENT+"to_mvs->memview = 0; to_mvs->data = 0;\n"
- code_impl += INDENT+"if(unlikely(-1 == __Pyx_init_memviewslice(temp_memview, %d, to_mvs))) {\n" % (ndim,)
- code_impl += INDENT*2+"return -1;\n"
- code_impl += INDENT+"}\n"
-
- code_impl += INDENT + "return 0;\n"
-
- code_impl += '}\n'
-
- return code_decl, code_impl
+ ndim=to_memview.ndim,
+ func_cname=copy_c_or_fortran_cname(to_memview)),
+ requires=[copy_contents_new_utility])
def get_axes_specs(env, axes):
'''
get_axes_specs(env, axes) -> list of (access, packing) specs for each axis.
-
access is one of 'full', 'ptr' or 'direct'
packing is one of 'contig', 'strided' or 'follow'
'''
@@ -905,10 +736,8 @@ typeinfo_to_format_code = load_memview_cy_utility(
"BufferFormatFromTypeInfo", requires=[Buffer._typeinfo_to_format_code])
is_contig_utility = load_memview_c_utility("MemviewSliceIsContig", context)
-is_c_contig_utility = load_memview_c_utility("MemviewSliceIsCContig", context,
- requires=[is_contig_utility])
-is_f_contig_utility = load_memview_c_utility("MemviewSliceIsFContig", context,
- requires=[is_contig_utility])
+overlapping_utility = load_memview_c_utility("OverlappingSlices", context)
+copy_contents_new_utility = load_memview_c_utility("MemviewSliceCopyTemplate", context)
view_utility_code = load_memview_cy_utility(
"View.MemoryView",
@@ -916,7 +745,10 @@ view_utility_code = load_memview_cy_utility(
requires=[Buffer.GetAndReleaseBufferUtilityCode(),
Buffer.buffer_struct_declare_code,
Buffer.empty_bufstruct_utility,
- memviewslice_init_code],
+ memviewslice_init_code,
+ is_contig_utility,
+ overlapping_utility,
+ copy_contents_new_utility],
)
cython_array_utility_code = load_memview_cy_utility(