Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
cython
Commits
4b9a1ff7
Commit
4b9a1ff7
authored
Dec 23, 2011
by
Mark Florisson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor memoryview copying + support overlapping memory
parent
50bd1a47
Changes
6
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
465 additions
and
323 deletions
+465
-323
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+8
-7
Cython/Compiler/MemoryView.py
Cython/Compiler/MemoryView.py
+51
-219
Cython/Compiler/PyrexTypes.py
Cython/Compiler/PyrexTypes.py
+23
-37
Cython/Utility/MemoryView.pyx
Cython/Utility/MemoryView.pyx
+226
-0
Cython/Utility/MemoryView_C.c
Cython/Utility/MemoryView_C.c
+125
-59
tests/run/memoryviewattrs.pyx
tests/run/memoryviewattrs.pyx
+32
-1
No files found.
Cython/Compiler/ExprNodes.py
View file @
4b9a1ff7
...
...
@@ -2954,13 +2954,14 @@ class IndexNode(ExprNode):
self
.
extra_index_params
(),
code
.
error_goto
(
self
.
pos
)))
def
generate_memoryviewslice_copy_code
(
self
,
rhs
,
code
,
op
=
""
):
assert
isinstance
(
self
.
index
,
EllipsisNode
)
def
generate_memoryviewslice_copy_code
(
self
,
rhs
,
code
):
import
MemoryView
util_code
=
MemoryView
.
CopyContentsFuncUtilCode
(
rhs
.
type
,
self
.
type
)
func_name
=
util_code
.
copy_contents_name
code
.
putln
(
code
.
error_goto_if_neg
(
"%s(&%s, &%s)"
%
(
func_name
,
rhs
.
result
(),
self
.
base
.
result
()),
self
.
pos
))
code
.
globalstate
.
use_utility_code
(
util_code
)
code
.
putln
(
code
.
error_goto_if_neg
(
"%s(&%s, &%s, %d)"
%
(
MemoryView
.
copy_src_to_dst_cname
(),
rhs
.
result
(),
self
.
base
.
result
(),
self
.
type
.
ndim
),
self
.
pos
))
def
generate_buffer_setitem_code
(
self
,
rhs
,
code
,
op
=
""
):
# Used from generate_assignment_code and InPlaceAssignmentNode
...
...
@@ -4347,7 +4348,7 @@ class AttributeNode(ExprNode):
self
.
type
=
self
.
obj
.
type
return
else
:
obj_type
.
declare_attribute
(
self
.
attribute
,
env
)
obj_type
.
declare_attribute
(
self
.
attribute
,
env
,
self
.
pos
)
entry
=
obj_type
.
scope
.
lookup_here
(
self
.
attribute
)
if
entry
and
entry
.
is_member
:
entry
=
None
...
...
Cython/Compiler/MemoryView.py
View file @
4b9a1ff7
This diff is collapsed.
Click to expand it.
Cython/Compiler/PyrexTypes.py
View file @
4b9a1ff7
...
...
@@ -510,7 +510,7 @@ class MemoryViewSliceType(PyrexType):
return
True
def
declare_attribute
(
self
,
attribute
,
env
):
def
declare_attribute
(
self
,
attribute
,
env
,
pos
):
import
MemoryView
,
Options
scope
=
self
.
scope
...
...
@@ -519,7 +519,7 @@ class MemoryViewSliceType(PyrexType):
scope
.
declare_var
(
'shape'
,
c_array_type
(
c_py_ssize_t_type
,
Options
.
buffer_max_dims
),
None
,
pos
,
cname
=
'shape'
,
is_cdef
=
1
)
...
...
@@ -527,7 +527,7 @@ class MemoryViewSliceType(PyrexType):
scope
.
declare_var
(
'strides'
,
c_array_type
(
c_py_ssize_t_type
,
Options
.
buffer_max_dims
),
None
,
pos
,
cname
=
'strides'
,
is_cdef
=
1
)
...
...
@@ -535,7 +535,7 @@ class MemoryViewSliceType(PyrexType):
scope
.
declare_var
(
'suboffsets'
,
c_array_type
(
c_py_ssize_t_type
,
Options
.
buffer_max_dims
),
None
,
pos
,
cname
=
'suboffsets'
,
is_cdef
=
1
)
...
...
@@ -544,40 +544,32 @@ class MemoryViewSliceType(PyrexType):
to_axes_c
=
[(
'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_f
=
to_axes_f
+
[(
'direct'
,
'follow'
)]
*
(
ndim
-
1
)
to_memview_c
=
MemoryViewSliceType
(
self
.
dtype
,
to_axes_c
)
to_memview_f
=
MemoryViewSliceType
(
self
.
dtype
,
to_axes_f
)
cython_name_c
,
cython_name_f
=
"copy"
,
"copy_fortran"
copy_name_c
,
copy_name_f
=
(
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
)):
for
to_memview
,
cython_name
in
[(
to_memview_c
,
"copy"
),
(
to_memview_f
,
"copy_fortran"
)]:
entry
=
scope
.
declare_cfunction
(
cython_name
,
CFuncType
(
self
,
[
CFuncTypeArg
(
"memviewslice"
,
self
,
None
)]),
pos
=
None
,
defining
=
1
,
cname
=
copy_name
)
CFuncType
(
self
,
[
CFuncTypeArg
(
"memviewslice"
,
self
,
None
)]),
pos
=
pos
,
defining
=
1
,
cname
=
MemoryView
.
copy_c_or_fortran_cname
(
to_memview
))
entry
.
utility_code_definition
=
\
MemoryView
.
CopyFuncUtilCode
(
self
,
to_memview
)
#
entry.utility_code_definition = \
env
.
use_utility_code
(
MemoryView
.
get_copy_new_utility
(
pos
,
self
,
to_memview
)
)
MemoryView
.
use_cython_array_utility_code
(
env
)
elif
attribute
in
(
"is_c_contig"
,
"is_f_contig"
):
# is_c_contig and is_f_contig functions
for
(
c_or_f
,
cython_name
)
in
((
'c'
,
'is_c_contig'
),
(
'f
ortran
'
,
'is_f_contig'
)):
for
(
c_or_f
,
cython_name
)
in
((
'c'
,
'is_c_contig'
),
(
'f'
,
'is_f_contig'
)):
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
(
return_type
=
c_int_type
,
...
...
@@ -587,14 +579,12 @@ class MemoryViewSliceType(PyrexType):
entry
=
scope
.
declare_cfunction
(
cython_name
,
cfunctype
,
pos
=
None
,
defining
=
1
,
cname
=
is_contig_name
)
pos
=
pos
,
defining
=
1
,
cname
=
is_contig_name
)
if
attribute
==
'is_c_contig'
:
entry
.
utility_code_definition
=
MemoryView
.
is_c_contig_utility
else
:
entry
.
utility_code_definition
=
MemoryView
.
is_f_contig_utility
entry
.
utility_code_definition
=
MemoryView
.
get_is_contig_utility
(
attribute
==
'is_c_contig'
,
self
.
ndim
)
return
True
...
...
@@ -604,10 +594,6 @@ class MemoryViewSliceType(PyrexType):
def
can_coerce_to_pyobject
(
self
,
env
):
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
):
return
cname
+
'.memview'
...
...
Cython/Utility/MemoryView.pyx
View file @
4b9a1ff7
...
...
@@ -237,6 +237,11 @@ cdef extern from *:
PyBUF_STRIDES
PyBUF_INDIRECT
cdef
extern
from
"stdlib.h"
:
void
*
malloc
(
size_t
)
nogil
void
free
(
void
*
)
nogil
void
*
memcpy
(
void
*
dest
,
void
*
src
,
size_t
n
)
nogil
@
cname
(
'__pyx_MemviewEnum'
)
cdef
class
Enum
(
object
):
cdef
object
name
...
...
@@ -891,6 +896,7 @@ cdef void slice_copy(memoryview memview, {{memviewslice_name}} *dst):
@
cname
(
'__pyx_memoryview_copy'
)
cdef
memoryview_copy
(
memoryview
memview
):
"Create a new memoryview object"
cdef
{{
memviewslice_name
}}
memviewslice
cdef
object
(
*
to_object_func
)(
char
*
)
cdef
int
(
*
to_dtype_func
)(
char
*
,
object
)
except
0
...
...
@@ -907,6 +913,226 @@ cdef memoryview_copy(memoryview memview):
return
memoryview_fromslice
(
&
memviewslice
,
memview
.
view
.
ndim
,
to_object_func
,
to_dtype_func
)
#
### Copy the contents of a memoryview slices
#
cdef
extern
from
*
:
int
slice_is_contig
"__pyx_memviewslice_is_contig"
(
{{
memviewslice_name
}}
*
mvs
,
char
order
,
int
ndim
)
nogil
int
slices_overlap
"__pyx_slices_overlap"
({{
memviewslice_name
}}
*
slice1
,
{{
memviewslice_name
}}
*
slice2
,
int
ndim
,
size_t
itemsize
)
nogil
cdef
Py_ssize_t
abs_py_ssize_t
(
Py_ssize_t
arg
)
nogil
:
if
arg
<
0
:
return
-
arg
else
:
return
arg
@
cname
(
'__pyx_get_best_slice_order'
)
cdef
char
get_best_order
({{
memviewslice_name
}}
*
mslice
,
int
ndim
)
nogil
:
"""
Figure out the best memory access order for a given slice.
"""
cdef
int
i
cdef
Py_ssize_t
c_stride
=
0
cdef
Py_ssize_t
f_stride
=
0
for
i
in
range
(
ndim
-
1
,
-
1
,
-
1
):
if
mslice
.
shape
[
i
]
>
1
:
c_stride
=
mslice
.
strides
[
i
]
for
i
in
range
(
ndim
):
if
mslice
.
shape
[
i
]
>
1
:
f_stride
=
mslice
.
strides
[
i
]
if
abs_py_ssize_t
(
c_stride
)
<=
abs_py_ssize_t
(
f_stride
):
return
'C'
else
:
return
'F'
cdef
void
_copy_strided_to_strided
(
char
*
src_data
,
Py_ssize_t
*
strides1
,
char
*
dst_data
,
Py_ssize_t
*
strides2
,
Py_ssize_t
*
shape
,
int
ndim
,
size_t
itemsize
)
nogil
:
cdef
Py_ssize_t
i
,
extent
,
stride1
,
stride2
extent
=
shape
[
0
]
stride1
=
strides1
[
0
]
stride2
=
strides2
[
0
]
if
ndim
==
1
:
if
stride1
>
0
and
stride2
>
0
and
<
size_t
>
stride1
==
itemsize
==
<
size_t
>
stride2
:
memcpy
(
dst_data
,
src_data
,
itemsize
*
extent
)
else
:
for
i
in
range
(
extent
):
memcpy
(
dst_data
,
src_data
,
itemsize
)
src_data
+=
stride1
dst_data
+=
stride2
else
:
for
i
in
range
(
extent
):
_copy_strided_to_strided
(
src_data
,
strides1
+
1
,
dst_data
,
strides2
+
1
,
shape
+
1
,
ndim
-
1
,
itemsize
)
src_data
+=
stride1
dst_data
+=
stride2
cdef
void
copy_strided_to_strided
({{
memviewslice_name
}}
*
src
,
{{
memviewslice_name
}}
*
dst
,
int
ndim
,
size_t
itemsize
)
nogil
:
_copy_strided_to_strided
(
src
.
data
,
src
.
strides
,
dst
.
data
,
dst
.
strides
,
src
.
shape
,
ndim
,
itemsize
)
{{
for
strided_to_contig
in
(
True
,
False
)}}
{{
if
strided_to_contig
}}
{{
py
:
func_name
=
"copy_strided_to_contig"
}}
{{
else
}}
{{
py
:
func_name
=
"copy_contig_to_strided"
}}
{{
endif
}}
@
cname
(
'__pyx_{{func_name}}'
)
cdef
char
*
{{
func_name
}}(
char
*
strided
,
char
*
contig
,
Py_ssize_t
*
shape
,
Py_ssize_t
*
strides
,
int
ndim
,
size_t
itemsize
)
nogil
:
"""
Copy contiguous data to strided memory, or strided memory to contiguous data.
The shape and strides are given only for the strided data.
"""
cdef
Py_ssize_t
i
,
extent
,
stride
cdef
void
*
src
,
*
dst
stride
=
strides
[
0
]
extent
=
shape
[
0
]
{{
if
strided_to_contig
}}
src
=
strided
dst
=
contig
{{
else
}}
src
=
contig
dst
=
strided
{{
endif
}}
if
ndim
==
1
:
# inner dimension, copy data
if
stride
>
0
and
<
size_t
>
stride
==
itemsize
:
memcpy
(
dst
,
src
,
itemsize
*
extent
)
contig
+=
itemsize
*
extent
else
:
for
i
in
range
(
extent
):
{{
if
strided_to_contig
}}
memcpy
(
contig
,
strided
,
itemsize
)
{{
else
}}
memcpy
(
strided
,
contig
,
itemsize
)
{{
endif
}}
contig
+=
itemsize
strided
+=
stride
else
:
for
i
in
range
(
extent
):
contig
=
{{
func_name
}}(
strided
,
contig
,
shape
+
1
,
strides
+
1
,
ndim
-
1
,
itemsize
)
strided
+=
stride
return
contig
{{
endfor
}}
@
cname
(
'__pyx_memoryview_slice_get_size'
)
cdef
Py_ssize_t
slice_get_size
({{
memviewslice_name
}}
*
src
,
int
ndim
)
nogil
:
"Return the size of the memory occupied by the slice in number of bytes"
cdef
int
i
cdef
Py_ssize_t
size
=
src
.
memview
.
view
.
itemsize
for
i
in
range
(
ndim
):
size
*=
src
.
shape
[
i
]
return
size
@
cname
(
'__pyx_memoryview_copy_data_to_temp'
)
cdef
void
*
copy_data_to_temp
({{
memviewslice_name
}}
*
src
,
char
order
,
int
ndim
)
nogil
except
NULL
:
"""
Copy a direct slice to temporary contiguous memory. The caller should free
the result when done.
"""
cdef
int
i
cdef
void
*
result
cdef
size_t
itemsize
=
src
.
memview
.
view
.
itemsize
cdef
size_t
size
=
slice_get_size
(
src
,
ndim
)
result
=
malloc
(
size
)
if
not
result
:
with
gil
:
raise
MemoryError
if
slice_is_contig
(
src
,
order
,
ndim
):
memcpy
(
result
,
src
.
data
,
size
)
else
:
copy_strided_to_contig
(
src
.
data
,
<
char
*>
result
,
src
.
shape
,
src
.
strides
,
ndim
,
itemsize
)
return
result
@
cname
(
'__pyx_memoryview_copy_contents'
)
cdef
int
memoryview_copy_contents
({{
memviewslice_name
}}
*
src
,
{{
memviewslice_name
}}
*
dst
,
int
ndim
)
nogil
except
-
1
:
"""
Copy memory from slice src to slice dst.
Check for overlapping memory and verify the shapes.
This function DOES NOT verify ndim and itemsize (either the compiler
or the caller should do that)
"""
cdef
void
*
tmpdata
cdef
size_t
itemsize
=
src
.
memview
.
view
.
itemsize
cdef
int
i
,
direct_copy
cdef
char
order
=
get_best_order
(
src
,
ndim
)
cdef
{{
memviewslice_name
}}
src_copy
,
dst_copy
for
i
in
range
(
ndim
):
if
src
.
shape
[
i
]
!=
dst
.
shape
[
i
]:
with
gil
:
raise
ValueError
(
"memoryview shapes are not the same in dimension %d, "
"got %d and %d"
%
(
i
,
src
.
shape
[
i
],
dst
.
shape
[
i
]))
if
slices_overlap
(
src
,
dst
,
ndim
,
itemsize
):
# slices overlap, copy to temp, copy temp to dst
if
not
slice_is_contig
(
src
,
order
,
ndim
):
order
=
get_best_order
(
dst
,
ndim
)
tmpdata
=
copy_data_to_temp
(
src
,
order
,
ndim
)
copy_contig_to_strided
(
dst
.
data
,
<
char
*>
tmpdata
,
dst
.
shape
,
dst
.
strides
,
ndim
,
itemsize
)
free
(
tmpdata
)
return
0
# See if both slices have equal contiguity
if
slice_is_contig
(
src
,
'C'
,
ndim
):
direct_copy
=
slice_is_contig
(
dst
,
'C'
,
ndim
)
elif
slice_is_contig
(
src
,
'F'
,
ndim
):
direct_copy
=
slice_is_contig
(
dst
,
'F'
,
ndim
)
else
:
direct_copy
=
False
if
direct_copy
:
# Contiguous slices with same order
memcpy
(
dst
.
data
,
src
.
data
,
slice_get_size
(
src
,
ndim
))
return
0
# Slices are not overlapping and not contiguous
if
order
==
'F'
==
get_best_order
(
dst
,
ndim
):
# see if both slices have Fortran order, transpose them to match our
# C-style indexing order
if
src
!=
&
src_copy
:
src_copy
=
src
[
0
]
src
=
&
src_copy
if
dst
!=
&
dst_copy
:
dst_copy
=
dst
[
0
]
dst
=
&
dst_copy
transpose_memslice
(
src
)
transpose_memslice
(
dst
)
copy_strided_to_strided
(
src
,
dst
,
ndim
,
itemsize
)
return
0
############### BufferFormatFromTypeInfo ###############
cdef
extern
from
*
:
ctypedef
struct
__Pyx_StructField
...
...
Cython/Utility/MemoryView_C.c
View file @
4b9a1ff7
This diff is collapsed.
Click to expand it.
tests/run/memoryviewattrs.pyx
View file @
4b9a1ff7
...
...
@@ -74,6 +74,37 @@ def test_copy_to():
print
to_data
[
i
],
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
@
cython
.
nonecheck
(
True
)
def
test_nonecheck1
():
...
...
@@ -140,7 +171,7 @@ def test_copy_mismatch():
>>> test_copy_mismatch()
Traceback (most recent call last):
...
ValueError: memoryview shapes
not the same in dimension 0
ValueError: memoryview shapes
are not the same in dimension 0, got 1 and 2
'''
cdef
int
[:,:,::
1
]
mv1
=
array
((
2
,
2
,
3
),
sizeof
(
int
),
'i'
)
cdef
int
[:,:,::
1
]
mv2
=
array
((
1
,
2
,
3
),
sizeof
(
int
),
'i'
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment