Commit 3337102f authored by Stefan Behnel's avatar Stefan Behnel

Safely generate all used "is contiguous" helper macros even when they occur in the same scope.

Previously, using "is_f_contig" and "is_c_contig" together would leave one of them undeclared.
Closes #1872.
parent 5b9f3588
...@@ -99,6 +99,9 @@ Bugs fixed ...@@ -99,6 +99,9 @@ Bugs fixed
* Buffer type mismatches in the NumPy buffer support could leak a reference to the * Buffer type mismatches in the NumPy buffer support could leak a reference to the
buffer owner. buffer owner.
* Using the "is_f_contig" and "is_c_contig" memoryview methods together could leave
one of them undeclared. (Github issue #1872)
* Compilation failed if the for-in-range loop target was not a variable but a more * Compilation failed if the for-in-range loop target was not a variable but a more
complex expression, e.g. an item assignment. (Github issue #1831) complex expression, e.g. an item assignment. (Github issue #1831)
......
...@@ -390,19 +390,15 @@ def get_memoryview_flag(access, packing): ...@@ -390,19 +390,15 @@ def get_memoryview_flag(access, packing):
return 'contiguous' return 'contiguous'
def get_is_contig_func_name(c_or_f, ndim): def get_is_contig_func_name(contig_type, ndim):
return "__pyx_memviewslice_is_%s_contig%d" % (c_or_f, ndim) assert contig_type in ('C', 'F')
return "__pyx_memviewslice_is_contig_%s%d" % (contig_type, ndim)
def get_is_contig_utility(c_contig, ndim): def get_is_contig_utility(contig_type, ndim):
C = dict(context, ndim=ndim) assert contig_type in ('C', 'F')
if c_contig: C = dict(context, ndim=ndim, contig_type=contig_type)
utility = load_memview_c_utility("MemviewSliceIsCContig", C, utility = load_memview_c_utility("MemviewSliceCheckContig", C, requires=[is_contig_utility])
requires=[is_contig_utility])
else:
utility = load_memview_c_utility("MemviewSliceIsFContig", C,
requires=[is_contig_utility])
return utility return utility
......
...@@ -716,10 +716,9 @@ class MemoryViewSliceType(PyrexType): ...@@ -716,10 +716,9 @@ class MemoryViewSliceType(PyrexType):
elif attribute in ("is_c_contig", "is_f_contig"): elif attribute in ("is_c_contig", "is_f_contig"):
# is_c_contig and is_f_contig functions # is_c_contig and is_f_contig functions
for (c_or_f, cython_name) in (('c', 'is_c_contig'), ('f', 'is_f_contig')): for (c_or_f, cython_name) in (('C', 'is_c_contig'), ('F', 'is_f_contig')):
is_contig_name = \ is_contig_name = MemoryView.get_is_contig_func_name(c_or_f, self.ndim)
MemoryView.get_is_contig_func_name(c_or_f, self.ndim)
cfunctype = CFuncType( cfunctype = CFuncType(
return_type=c_bint_type, return_type=c_bint_type,
...@@ -733,8 +732,7 @@ class MemoryViewSliceType(PyrexType): ...@@ -733,8 +732,7 @@ class MemoryViewSliceType(PyrexType):
defining=1, defining=1,
cname=is_contig_name) cname=is_contig_name)
entry.utility_code_definition = MemoryView.get_is_contig_utility( entry.utility_code_definition = MemoryView.get_is_contig_utility(c_or_f, self.ndim)
attribute == 'is_c_contig', self.ndim)
return True return True
......
...@@ -699,29 +699,21 @@ __pyx_slices_overlap({{memviewslice_name}} *slice1, ...@@ -699,29 +699,21 @@ __pyx_slices_overlap({{memviewslice_name}} *slice1,
} }
////////// MemviewSliceIsCContig.proto ////////// ////////// MemviewSliceCheckContig.proto //////////
#define __pyx_memviewslice_is_c_contig{{ndim}}(slice) \ #define __pyx_memviewslice_is_contig_{{contig_type}}{{ndim}}(slice) \
__pyx_memviewslice_is_contig(slice, 'C', {{ndim}}) __pyx_memviewslice_is_contig(slice, '{{contig_type}}', {{ndim}})
////////// MemviewSliceIsFContig.proto //////////
#define __pyx_memviewslice_is_f_contig{{ndim}}(slice) \
__pyx_memviewslice_is_contig(slice, 'F', {{ndim}})
////////// MemviewSliceIsContig.proto ////////// ////////// MemviewSliceIsContig.proto //////////
static int __pyx_memviewslice_is_contig(const {{memviewslice_name}} mvs, static int __pyx_memviewslice_is_contig(const {{memviewslice_name}} mvs, char order, int ndim);/*proto*/
char order, int ndim);
////////// MemviewSliceIsContig ////////// ////////// MemviewSliceIsContig //////////
static int static int
__pyx_memviewslice_is_contig(const {{memviewslice_name}} mvs, __pyx_memviewslice_is_contig(const {{memviewslice_name}} mvs, char order, int ndim)
char order, int ndim)
{ {
int i, index, step, start; int i, index, step, start;
Py_ssize_t itemsize = mvs.memview->view.itemsize; Py_ssize_t itemsize = mvs.memview->view.itemsize;
......
# mode: run
# tag: numpy, memoryview
import numpy as np
# Cython used to forget the "is contig" helper functions when both are used.
def copy_fortran3(double[:, :, :] mat):
"""
>>> a = np.ones((1, 1, 1), dtype=np.float64)
>>> c = copy_fortran3(a)
>>> (a == c).all()
True
>>> a = np.ones((4, 6, 8), dtype=np.float64, order='F')
>>> c = copy_fortran3(a)
>>> (a == c).all()
True
>>> a = np.ones((4, 6, 8), dtype=np.float64, order='C')
>>> c = copy_fortran3(a)
>>> (a == c).all()
True
"""
cdef int x, y, z
x, y, z = np.shape(mat)
if 1 == x == y == z:
# C- or F- contiguous just means "contiguous".
if mat.is_c_contig() or mat.is_f_contig():
return mat.base
else:
return np.asarray(mat.copy_fortran())
elif mat.is_f_contig():
return mat.base
else:
return np.asarray(mat.copy_fortran())
def copy_fortran2(double[:, :] mat):
"""
>>> a = np.ones((1, 1), dtype=np.float64)
>>> c = copy_fortran2(a)
>>> (a == c).all()
True
>>> a = np.ones((4, 6), dtype=np.float64, order='F')
>>> c = copy_fortran2(a)
>>> (a == c).all()
True
>>> a = np.ones((4, 6), dtype=np.float64, order='C')
>>> c = copy_fortran2(a)
>>> (a == c).all()
True
"""
cdef int rows, cols
rows, cols = np.shape(mat)
if rows == 1 or cols == 1:
# C- or F- contiguous just means "contiguous".
if mat.is_c_contig() or mat.is_f_contig():
return mat.base
else:
return np.asarray(mat.copy_fortran())
elif mat.is_f_contig():
return mat.base
else:
return np.asarray(mat.copy_fortran())
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