Commit b3d32712 authored by Mark's avatar Mark

Merge pull request #82 from markflorisson88/copy2

Atomic acquisition counting, slice assignment (+scalars), overlapping memory, broadcasting, more memoryview object methods, optimized with gil block
parents 50bd1a47 beb90546
...@@ -748,7 +748,7 @@ def get_type_information_cname(code, dtype, maxdepth=None): ...@@ -748,7 +748,7 @@ def get_type_information_cname(code, dtype, maxdepth=None):
typeinfo = ('static __Pyx_TypeInfo %s = ' typeinfo = ('static __Pyx_TypeInfo %s = '
'{ "%s", %s, sizeof(%s), { %s }, %s, \'%s\', %s, %s };') '{ "%s", %s, sizeof(%s), { %s }, %s, \'%s\', %s, %s };')
tup = (name, rep, structinfo_name, declcode, tup = (name, rep, structinfo_name, declcode,
', '.join([str(x) for x in arraysizes]), len(arraysizes), ', '.join([str(x) for x in arraysizes]) or '0', len(arraysizes),
typegroup, is_unsigned, flags) typegroup, is_unsigned, flags)
typecode.putln(typeinfo % tup, safe=True) typecode.putln(typeinfo % tup, safe=True)
......
This diff is collapsed.
This diff is collapsed.
...@@ -1460,7 +1460,8 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1460,7 +1460,8 @@ class FuncDefNode(StatNode, BlockNode):
if self.return_type.is_pyobject: if self.return_type.is_pyobject:
init = " = NULL" init = " = NULL"
elif self.return_type.is_memoryviewslice: elif self.return_type.is_memoryviewslice:
init = "= {0, 0}" import MemoryView
init = ' = ' + MemoryView.memslice_entry_init
code.putln( code.putln(
"%s%s;" % "%s%s;" %
...@@ -1479,20 +1480,47 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1479,20 +1480,47 @@ class FuncDefNode(StatNode, BlockNode):
# ----- GIL acquisition # ----- GIL acquisition
acquire_gil = self.acquire_gil acquire_gil = self.acquire_gil
# See if we need to acquire the GIL for variable declarations and # See if we need to acquire the GIL for variable declarations, or for
acquire_gil_for_var_decls_only = (lenv.nogil and # refnanny only
lenv.has_with_gil_block)
# Profiling or closures are not currently possible for cdef nogil
# functions, but check them anyway
have_object_args = (self.needs_closure or self.needs_outer_scope or
profile)
for arg in lenv.arg_entries:
if arg.type.is_pyobject:
have_object_args = True
break
acquire_gil_for_var_decls_only = (
lenv.nogil and lenv.has_with_gil_block and
(have_object_args or lenv.buffer_entries))
use_refnanny = not lenv.nogil or acquire_gil_for_var_decls_only acquire_gil_for_refnanny_only = (
lenv.nogil and lenv.has_with_gil_block and not
acquire_gil_for_var_decls_only)
use_refnanny = not lenv.nogil or lenv.has_with_gil_block
if acquire_gil or acquire_gil_for_var_decls_only: if acquire_gil or acquire_gil_for_var_decls_only:
code.put_ensure_gil() code.put_ensure_gil()
# ----- set up refnanny # ----- set up refnanny
if use_refnanny: if use_refnanny:
if acquire_gil_for_refnanny_only:
code.declare_gilstate()
code.putln("#if CYTHON_REFNANNY")
code.put_ensure_gil(declare_gilstate=False)
code.putln("#endif /* CYTHON_REFNANNY */")
tempvardecl_code.put_declare_refcount_context() tempvardecl_code.put_declare_refcount_context()
code.put_setup_refcount_context(self.entry.name) code.put_setup_refcount_context(self.entry.name)
if acquire_gil_for_refnanny_only:
code.putln("#if CYTHON_REFNANNY")
code.put_release_ensured_gil()
code.putln("#endif /* CYTHON_REFNANNY */")
# ----- Automatic lead-ins for certain special functions # ----- Automatic lead-ins for certain special functions
if is_getbuffer_slot: if is_getbuffer_slot:
self.getbuffer_init(code) self.getbuffer_init(code)
...@@ -1510,7 +1538,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1510,7 +1538,7 @@ class FuncDefNode(StatNode, BlockNode):
if use_refnanny: if use_refnanny:
code.put_finish_refcount_context() code.put_finish_refcount_context()
if acquire_gil_for_var_decls_only: if acquire_gil or acquire_gil_for_var_decls_only:
code.put_release_ensured_gil() code.put_release_ensured_gil()
# FIXME: what if the error return value is a Python value? # FIXME: what if the error return value is a Python value?
...@@ -1551,11 +1579,12 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1551,11 +1579,12 @@ class FuncDefNode(StatNode, BlockNode):
not entry.in_closure): not entry.in_closure):
code.put_var_incref(entry) code.put_var_incref(entry)
# Note: defaults are always increffed. For def functions, we # Note: defaults are always incref-ed. For def functions, we
# we aquire arguments from object converstion, so we have # we aquire arguments from object converstion, so we have
# new references. If we are a cdef function, we need to # new references. If we are a cdef function, we need to
# incref our arguments # incref our arguments
if is_cdef and entry.type.is_memoryviewslice: elif (is_cdef and entry.type.is_memoryviewslice and
len(entry.cf_assignments) > 1):
code.put_incref_memoryviewslice(entry.cname, code.put_incref_memoryviewslice(entry.cname,
have_gil=not lenv.nogil) have_gil=not lenv.nogil)
for entry in lenv.var_entries: for entry in lenv.var_entries:
...@@ -1566,10 +1595,6 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1566,10 +1595,6 @@ class FuncDefNode(StatNode, BlockNode):
for entry in lenv.var_entries + lenv.arg_entries: for entry in lenv.var_entries + lenv.arg_entries:
if entry.type.is_buffer and entry.buffer_aux.buflocal_nd_var.used: if entry.type.is_buffer and entry.buffer_aux.buflocal_nd_var.used:
Buffer.put_init_vars(entry, code) Buffer.put_init_vars(entry, code)
# ----- Initialise local memoryviewslices
for entry in lenv.var_entries:
if entry.visibility == "private" and not entry.used:
continue
# ----- Check and convert arguments # ----- Check and convert arguments
self.generate_argument_type_tests(code) self.generate_argument_type_tests(code)
...@@ -1631,13 +1656,13 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1631,13 +1656,13 @@ class FuncDefNode(StatNode, BlockNode):
# code.globalstate.use_utility_code(get_exception_tuple_utility_code) # code.globalstate.use_utility_code(get_exception_tuple_utility_code)
# code.put_trace_exception() # code.put_trace_exception()
if lenv.nogil: if lenv.nogil and not lenv.has_with_gil_block:
code.putln("{") code.putln("{")
code.put_ensure_gil() code.put_ensure_gil()
code.put_add_traceback(self.entry.qualified_name) code.put_add_traceback(self.entry.qualified_name)
if lenv.nogil: if lenv.nogil and not lenv.has_with_gil_block:
code.put_release_ensured_gil() code.put_release_ensured_gil()
code.putln("}") code.putln("}")
else: else:
...@@ -1715,7 +1740,10 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1715,7 +1740,10 @@ class FuncDefNode(StatNode, BlockNode):
if ((acquire_gil or len(entry.cf_assignments) > 1) and if ((acquire_gil or len(entry.cf_assignments) > 1) and
not entry.in_closure): not entry.in_closure):
code.put_var_decref(entry) code.put_var_decref(entry)
if entry.type.is_memoryviewslice: elif (entry.type.is_memoryviewslice and
(not is_cdef or len(entry.cf_assignments) > 1)):
# decref slices of def functions and acquired slices from cdef
# functions, but not borrowed slices from cdef functions.
code.put_xdecref_memoryviewslice(entry.cname, code.put_xdecref_memoryviewslice(entry.cname,
have_gil=not lenv.nogil) have_gil=not lenv.nogil)
if self.needs_closure: if self.needs_closure:
...@@ -1747,7 +1775,8 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1747,7 +1775,8 @@ class FuncDefNode(StatNode, BlockNode):
# GIL holding funcion # GIL holding funcion
code.put_finish_refcount_context() code.put_finish_refcount_context()
if acquire_gil or acquire_gil_for_var_decls_only: if (acquire_gil or acquire_gil_for_var_decls_only or
acquire_gil_for_refnanny_only):
code.put_release_ensured_gil() code.put_release_ensured_gil()
if not self.return_type.is_void: if not self.return_type.is_void:
...@@ -3152,7 +3181,7 @@ class DefNodeWrapper(FuncDefNode): ...@@ -3152,7 +3181,7 @@ class DefNodeWrapper(FuncDefNode):
if self.signature.has_dummy_arg: if self.signature.has_dummy_arg:
args.append(Naming.self_cname) args.append(Naming.self_cname)
for arg in self.args: for arg in self.args:
if arg.hdr_type: if arg.hdr_type and not (arg.type.is_memoryviewslice or arg.type.is_struct):
args.append(arg.type.cast_code(arg.entry.cname)) args.append(arg.type.cast_code(arg.entry.cname))
else: else:
args.append(arg.entry.cname) args.append(arg.entry.cname)
...@@ -4724,10 +4753,28 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -4724,10 +4753,28 @@ class SingleAssignmentNode(AssignmentNode):
self.lhs.analyse_target_declaration(env) self.lhs.analyse_target_declaration(env)
def analyse_types(self, env, use_temp = 0): def analyse_types(self, env, use_temp = 0):
import ExprNodes
self.rhs.analyse_types(env) self.rhs.analyse_types(env)
self.lhs.analyse_target_types(env) self.lhs.analyse_target_types(env)
self.lhs.gil_assignment_check(env) self.lhs.gil_assignment_check(env)
self.rhs = self.rhs.coerce_to(self.lhs.type, env)
if self.lhs.memslice_broadcast or self.rhs.memslice_broadcast:
self.lhs.memslice_broadcast = True
self.rhs.memslice_broadcast = True
is_index_node = isinstance(self.lhs, ExprNodes.IndexNode)
if (is_index_node and not self.rhs.type.is_memoryviewslice and
(self.lhs.memslice_slice or self.lhs.is_memslice_copy) and
(self.lhs.type.dtype.assignable_from(self.rhs.type) or
self.rhs.type.is_pyobject)):
# scalar slice assignment
self.lhs.is_memslice_scalar_assignment = True
dtype = self.lhs.type.dtype
else:
dtype = self.lhs.type
self.rhs = self.rhs.coerce_to(dtype, env)
if use_temp: if use_temp:
self.rhs = self.rhs.coerce_to_temp(env) self.rhs = self.rhs.coerce_to_temp(env)
...@@ -5168,7 +5215,6 @@ class ReturnStatNode(StatNode): ...@@ -5168,7 +5215,6 @@ class ReturnStatNode(StatNode):
lhs_pos=self.value.pos, lhs_pos=self.value.pos,
rhs=self.value, rhs=self.value,
code=code, code=code,
incref_rhs=self.value.is_name,
have_gil=self.in_nogil_context) have_gil=self.in_nogil_context)
else: else:
self.value.make_owned_reference(code) self.value.make_owned_reference(code)
......
...@@ -67,9 +67,9 @@ old_style_globals = False ...@@ -67,9 +67,9 @@ old_style_globals = False
cimport_from_pyx = False cimport_from_pyx = False
# max # of dims for buffers -- set to same value as max # of dims for numpy # max # of dims for buffers -- set lower than number of dimensions in numpy, as
# arrays. # slices are passed by value and involve a lot of copying
buffer_max_dims = 32 buffer_max_dims = 8
# Declare compiler directives # Declare compiler directives
directive_defaults = { directive_defaults = {
......
...@@ -1778,6 +1778,9 @@ class AnalyseExpressionsTransform(CythonTransform): ...@@ -1778,6 +1778,9 @@ class AnalyseExpressionsTransform(CythonTransform):
if node.is_fused_index and node.type is not PyrexTypes.error_type: if node.is_fused_index and node.type is not PyrexTypes.error_type:
node = node.base node = node.base
elif node.memslice_ellipsis_noop:
# memoryviewslice[...] expression, drop the IndexNode
node = node.base
return node return node
......
...@@ -510,7 +510,7 @@ class MemoryViewSliceType(PyrexType): ...@@ -510,7 +510,7 @@ class MemoryViewSliceType(PyrexType):
return True return True
def declare_attribute(self, attribute, env): def declare_attribute(self, attribute, env, pos):
import MemoryView, Options import MemoryView, Options
scope = self.scope scope = self.scope
...@@ -518,24 +518,24 @@ class MemoryViewSliceType(PyrexType): ...@@ -518,24 +518,24 @@ class MemoryViewSliceType(PyrexType):
if attribute == 'shape': if attribute == 'shape':
scope.declare_var('shape', scope.declare_var('shape',
c_array_type(c_py_ssize_t_type, c_array_type(c_py_ssize_t_type,
Options.buffer_max_dims), Options.buffer_max_dims),
None, pos,
cname='shape', cname='shape',
is_cdef=1) is_cdef=1)
elif attribute == 'strides': elif attribute == 'strides':
scope.declare_var('strides', scope.declare_var('strides',
c_array_type(c_py_ssize_t_type, c_array_type(c_py_ssize_t_type,
Options.buffer_max_dims), Options.buffer_max_dims),
None, pos,
cname='strides', cname='strides',
is_cdef=1) is_cdef=1)
elif attribute == 'suboffsets': elif attribute == 'suboffsets':
scope.declare_var('suboffsets', scope.declare_var('suboffsets',
c_array_type(c_py_ssize_t_type, c_array_type(c_py_ssize_t_type,
Options.buffer_max_dims), Options.buffer_max_dims),
None, pos,
cname='suboffsets', cname='suboffsets',
is_cdef=1) is_cdef=1)
...@@ -544,40 +544,32 @@ class MemoryViewSliceType(PyrexType): ...@@ -544,40 +544,32 @@ class MemoryViewSliceType(PyrexType):
to_axes_c = [('direct', 'contig')] to_axes_c = [('direct', 'contig')]
to_axes_f = [('direct', 'contig')] to_axes_f = [('direct', 'contig')]
if ndim-1: if ndim - 1:
to_axes_c = [('direct', 'follow')]*(ndim-1) + to_axes_c to_axes_c = [('direct', 'follow')]*(ndim-1) + to_axes_c
to_axes_f = to_axes_f + [('direct', 'follow')]*(ndim-1) to_axes_f = to_axes_f + [('direct', 'follow')]*(ndim-1)
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)
cython_name_c, cython_name_f = "copy", "copy_fortran" for to_memview, cython_name in [(to_memview_c, "copy"),
copy_name_c, copy_name_f = ( (to_memview_f, "copy_fortran")]:
MemoryView.get_copy_func_name(to_memview_c),
MemoryView.get_copy_func_name(to_memview_f))
for (to_memview, cython_name, copy_name) in ((to_memview_c, cython_name_c, copy_name_c),
(to_memview_f, cython_name_f, copy_name_f)):
entry = scope.declare_cfunction(cython_name, entry = scope.declare_cfunction(cython_name,
CFuncType(self, CFuncType(self, [CFuncTypeArg("memviewslice", self, None)]),
[CFuncTypeArg("memviewslice", self, None)]), pos=pos,
pos = None, defining=1,
defining = 1, cname=MemoryView.copy_c_or_fortran_cname(to_memview))
cname = copy_name)
entry.utility_code_definition = \ #entry.utility_code_definition = \
MemoryView.CopyFuncUtilCode(self, to_memview) env.use_utility_code(MemoryView.get_copy_new_utility(pos, self, to_memview))
MemoryView.use_cython_array_utility_code(env) MemoryView.use_cython_array_utility_code(env)
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'), ('fortran', '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) MemoryView.get_is_contig_func_name(c_or_f, self.ndim)
cfunctype = CFuncType( cfunctype = CFuncType(
return_type=c_int_type, return_type=c_int_type,
...@@ -587,14 +579,12 @@ class MemoryViewSliceType(PyrexType): ...@@ -587,14 +579,12 @@ class MemoryViewSliceType(PyrexType):
entry = scope.declare_cfunction(cython_name, entry = scope.declare_cfunction(cython_name,
cfunctype, cfunctype,
pos = None, pos=pos,
defining = 1, defining=1,
cname = is_contig_name) cname=is_contig_name)
if attribute == 'is_c_contig': entry.utility_code_definition = MemoryView.get_is_contig_utility(
entry.utility_code_definition = MemoryView.is_c_contig_utility attribute == 'is_c_contig', self.ndim)
else:
entry.utility_code_definition = MemoryView.is_f_contig_utility
return True return True
...@@ -604,10 +594,6 @@ class MemoryViewSliceType(PyrexType): ...@@ -604,10 +594,6 @@ class MemoryViewSliceType(PyrexType):
def can_coerce_to_pyobject(self, env): def can_coerce_to_pyobject(self, env):
return True return True
#def global_init_code(self, entry, code):
# code.putln("%s.data = NULL;" % entry.cname)
# code.putln("%s.memview = NULL;" % entry.cname)
def check_for_null_code(self, cname): def check_for_null_code(self, cname):
return cname + '.memview' return cname + '.memview'
...@@ -657,8 +643,9 @@ class MemoryViewSliceType(PyrexType): ...@@ -657,8 +643,9 @@ class MemoryViewSliceType(PyrexType):
to_py_func = "(PyObject *(*)(char *)) " + to_py_func to_py_func = "(PyObject *(*)(char *)) " + to_py_func
from_py_func = "(int (*)(char *, PyObject *)) " + from_py_func from_py_func = "(int (*)(char *, PyObject *)) " + from_py_func
tup = (obj.result(), self.ndim, to_py_func, from_py_func) tup = (obj.result(), self.ndim, to_py_func, from_py_func,
return "__pyx_memoryview_fromslice(&%s, %s, %s, %s);" % tup self.dtype.is_pyobject)
return "__pyx_memoryview_fromslice(&%s, %s, %s, %s, %d);" % tup
def dtype_object_conversion_funcs(self, env): def dtype_object_conversion_funcs(self, env):
import MemoryView, Code import MemoryView, Code
......
This diff is collapsed.
This diff is collapsed.
...@@ -71,6 +71,8 @@ ...@@ -71,6 +71,8 @@
#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) #define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES)
#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) #define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES)
#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) #define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES)
#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_FORMAT | PyBUF_WRITABLE)
#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_FORMAT | PyBUF_WRITABLE)
#endif #endif
......
...@@ -652,6 +652,11 @@ def test_indirect_slicing(arg): ...@@ -652,6 +652,11 @@ def test_indirect_slicing(arg):
(5, 3, 2) (5, 3, 2)
0 0 -1 0 0 -1
58 58
56
58
58
58
58
released A released A
>>> test_indirect_slicing(IntMockBuffer("A", shape_9_14_21_list, shape=(9, 14, 21))) >>> test_indirect_slicing(IntMockBuffer("A", shape_9_14_21_list, shape=(9, 14, 21)))
...@@ -659,6 +664,11 @@ def test_indirect_slicing(arg): ...@@ -659,6 +664,11 @@ def test_indirect_slicing(arg):
(5, 14, 3) (5, 14, 3)
0 16 -1 0 16 -1
2412 2412
2410
2412
2412
2412
2412
released A released A
""" """
cdef int[::view.indirect, ::view.indirect, :] _a = arg cdef int[::view.indirect, ::view.indirect, :] _a = arg
...@@ -669,6 +679,11 @@ def test_indirect_slicing(arg): ...@@ -669,6 +679,11 @@ def test_indirect_slicing(arg):
print_int_offsets(*b.suboffsets) print_int_offsets(*b.suboffsets)
print b[4, 2, 1] print b[4, 2, 1]
print b[..., 0][4, 2]
print b[..., 1][4, 2]
print b[..., 1][4][2]
print b[4][2][1]
print b[4, 2][1]
def test_direct_slicing(arg): def test_direct_slicing(arg):
""" """
......
...@@ -74,6 +74,37 @@ def test_copy_to(): ...@@ -74,6 +74,37 @@ def test_copy_to():
print to_data[i], print to_data[i],
print print
@testcase
def test_overlapping_copy():
"""
>>> test_overlapping_copy()
"""
cdef int i, array[10]
for i in range(10):
array[i] = i
cdef int[:] slice = array
slice[...] = slice[::-1]
for i in range(10):
assert slice[i] == 10 - 1 - i
@testcase
def test_partly_overlapping():
"""
>>> test_partly_overlapping()
"""
cdef int i, array[10]
for i in range(10):
array[i] = i
cdef int[:] slice = array
cdef int[:] slice2 = slice[:5]
slice2[...] = slice[4:9]
for i in range(5):
assert slice2[i] == i + 4
@testcase @testcase
@cython.nonecheck(True) @cython.nonecheck(True)
def test_nonecheck1(): def test_nonecheck1():
...@@ -139,11 +170,11 @@ def test_copy_mismatch(): ...@@ -139,11 +170,11 @@ def test_copy_mismatch():
u''' u'''
>>> test_copy_mismatch() >>> test_copy_mismatch()
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: memoryview shapes not the same in dimension 0 ValueError: got differing extents in dimension 0 (got 2 and 3)
''' '''
cdef int[:,:,::1] mv1 = array((2,2,3), sizeof(int), 'i') cdef int[:,:,::1] mv1 = array((2,2,3), sizeof(int), 'i')
cdef int[:,:,::1] mv2 = array((1,2,3), sizeof(int), 'i') cdef int[:,:,::1] mv2 = array((3,2,3), sizeof(int), 'i')
mv1[...] = mv2 mv1[...] = mv2
......
This diff is collapsed.
...@@ -189,24 +189,46 @@ def test_transpose(): ...@@ -189,24 +189,46 @@ def test_transpose():
print a[3, 2], a.T[2, 3], a_obj[3, 2], a_obj.T[2, 3], numpy_obj[3, 2], numpy_obj.T[2, 3] print a[3, 2], a.T[2, 3], a_obj[3, 2], a_obj.T[2, 3], numpy_obj[3, 2], numpy_obj.T[2, 3]
@testcase @testcase_numpy_1_5
def test_numpy_like_attributes(cyarray): def test_numpy_like_attributes(cyarray):
""" """
For some reason this fails in numpy 1.4, with shape () and strides (40, 8)
instead of 20, 4 on my machine. Investigate this.
>>> cyarray = create_array(shape=(8, 5), mode="c") >>> cyarray = create_array(shape=(8, 5), mode="c")
>>> test_numpy_like_attributes(cyarray) >>> test_numpy_like_attributes(cyarray)
>>> test_numpy_like_attributes(cyarray.memview) >>> test_numpy_like_attributes(cyarray.memview)
""" """
numarray = np.asarray(cyarray) numarray = np.asarray(cyarray)
assert cyarray.shape == numarray.shape assert cyarray.shape == numarray.shape, (cyarray.shape, numarray.shape)
assert cyarray.strides == numarray.strides assert cyarray.strides == numarray.strides, (cyarray.strides, numarray.strides)
assert cyarray.ndim == numarray.ndim assert cyarray.ndim == numarray.ndim, (cyarray.ndim, numarray.ndim)
assert cyarray.size == numarray.size assert cyarray.size == numarray.size, (cyarray.size, numarray.size)
assert cyarray.nbytes == numarray.nbytes assert cyarray.nbytes == numarray.nbytes, (cyarray.nbytes, numarray.nbytes)
cdef int[:, :] mslice = numarray cdef int[:, :] mslice = numarray
assert (<object> mslice).base is numarray assert (<object> mslice).base is numarray
@testcase_numpy_1_5
def test_copy_and_contig_attributes(a):
"""
>>> a = np.arange(20, dtype=np.int32).reshape(5, 4)
>>> test_copy_and_contig_attributes(a)
"""
cdef np.int32_t[:, :] mslice = a
m = mslice
# Test object copy attributes
assert np.all(a == np.array(m.copy()))
assert a.strides == m.strides == m.copy().strides
assert np.all(a == np.array(m.copy_fortran()))
assert m.copy_fortran().strides == (4, 20)
# Test object is_*_contig attributes
assert m.is_c_contig() and m.copy().is_c_contig()
assert m.copy_fortran().is_f_contig() and not m.is_f_contig()
ctypedef int td_cy_int ctypedef int td_cy_int
cdef extern from "bufaccess.h": cdef extern from "bufaccess.h":
......
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