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
Gwenaël Samain
cython
Commits
522cb284
Commit
522cb284
authored
Jul 31, 2011
by
Mark Florisson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow contig to follow indirect contig
parent
a0e188d4
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
195 additions
and
31 deletions
+195
-31
Cython/Compiler/MemoryView.py
Cython/Compiler/MemoryView.py
+23
-17
Cython/Utility/MemoryView_C.c
Cython/Utility/MemoryView_C.c
+20
-11
tests/errors/memview_declarations.pyx
tests/errors/memview_declarations.pyx
+24
-0
tests/run/memslice.pyx
tests/run/memslice.pyx
+122
-1
tests/run/mockbuffers.pxi
tests/run/mockbuffers.pxi
+6
-2
No files found.
Cython/Compiler/MemoryView.py
View file @
522cb284
...
@@ -197,24 +197,22 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
...
@@ -197,24 +197,22 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
flag
=
get_memoryview_flag
(
access
,
packing
)
flag
=
get_memoryview_flag
(
access
,
packing
)
if
flag
==
"generic"
:
if
flag
in
(
"generic"
,
"generic_contiguous"
):
# Note: we cannot do cast tricks to avoid stride multiplication
# for generic_contiguous, as we may have to do (dtype *)
# or (dtype **) arithmetic, we won't know which unless
# we check suboffsets
code
.
globalstate
.
use_utility_code
(
memviewslice_index_helpers
)
code
.
globalstate
.
use_utility_code
(
memviewslice_index_helpers
)
bufp
=
(
'__pyx_memviewslice_index_full(%s, %s, %s, %s)'
%
bufp
=
(
'__pyx_memviewslice_index_full(%s, %s, %s, %s)'
%
(
bufp
,
index
,
stride
,
suboffset
))
(
bufp
,
index
,
stride
,
suboffset
))
elif
flag
==
"generic_contiguous"
:
# We can skip stride multiplication with the cast
code
.
globalstate
.
use_utility_code
(
memviewslice_index_helpers
)
bufp
=
'((char *) ((%s *) %s) + %s)'
%
(
type_decl
,
bufp
,
index
)
bufp
=
(
'__pyx_memviewslice_index_full_contig(%s, %s)'
%
(
bufp
,
suboffset
))
elif
flag
==
"indirect"
:
elif
flag
==
"indirect"
:
bufp
=
(
"(*((char **) %s + %s * %s) + %s)"
%
bufp
=
"(%s + %s * %s)"
%
(
bufp
,
index
,
stride
)
(
bufp
,
index
,
stride
,
suboffset
))
bufp
=
(
"(*((char **) %s) + %s)"
%
(
bufp
,
suboffset
))
elif
flag
==
"indirect_contiguous"
:
elif
flag
==
"indirect_contiguous"
:
bufp
=
"(*((char **) %s) + %s)"
%
(
bufp
,
suboffset
)
# Note: we do char ** arithmetic
bufp
=
"(*((char **) %s + %s) + %s)"
%
(
bufp
,
index
,
suboffset
)
elif
flag
==
"strided"
:
elif
flag
==
"strided"
:
bufp
=
"(%s + %s * %s)"
%
(
bufp
,
index
,
stride
)
bufp
=
"(%s + %s * %s)"
%
(
bufp
,
index
,
stride
)
...
@@ -621,7 +619,7 @@ def get_axes_specs(env, axes):
...
@@ -621,7 +619,7 @@ def get_axes_specs(env, axes):
else
:
else
:
raise
CompileError
(
axis
.
step
.
pos
,
INVALID_ERR
)
raise
CompileError
(
axis
.
step
.
pos
,
INVALID_ERR
)
validate_axes_specs
(
axes
[
0
].
start
.
pos
,
axes_specs
)
validate_axes_specs
(
[
axis
.
start
.
pos
for
axis
in
axes
]
,
axes_specs
)
return
axes_specs
return
axes_specs
...
@@ -677,16 +675,16 @@ def get_access_packing(view_scope_constant):
...
@@ -677,16 +675,16 @@ def get_access_packing(view_scope_constant):
if
view_scope_constant
.
name
==
'generic'
:
if
view_scope_constant
.
name
==
'generic'
:
return
'full'
,
return
'full'
,
def
validate_axes_specs
(
pos
,
specs
):
def
validate_axes_specs
(
pos
itions
,
specs
):
packing_specs
=
(
'contig'
,
'strided'
,
'follow'
)
packing_specs
=
(
'contig'
,
'strided'
,
'follow'
)
access_specs
=
(
'direct'
,
'ptr'
,
'full'
)
access_specs
=
(
'direct'
,
'ptr'
,
'full'
)
is_c_contig
,
is_f_contig
=
is_cf_contig
(
specs
)
is_c_contig
,
is_f_contig
=
is_cf_contig
(
specs
)
has_contig
=
has_follow
=
has_strided
=
False
has_contig
=
has_follow
=
has_strided
=
has_generic_contig
=
False
for
access
,
packing
in
specs
:
for
pos
,
(
access
,
packing
)
in
zip
(
positions
,
specs
)
:
if
not
(
access
in
access_specs
and
if
not
(
access
in
access_specs
and
packing
in
packing_specs
):
packing
in
packing_specs
):
...
@@ -696,8 +694,16 @@ def validate_axes_specs(pos, specs):
...
@@ -696,8 +694,16 @@ def validate_axes_specs(pos, specs):
has_strided
=
True
has_strided
=
True
elif
packing
==
'contig'
:
elif
packing
==
'contig'
:
if
has_contig
:
if
has_contig
:
raise
CompileError
(
pos
,
"Only one contiguous axis may be specified."
)
if
access
==
'ptr'
:
has_contig
=
True
raise
CompileError
(
pos
,
"Indirect contiguous dimensions must precede direct contiguous"
)
elif
has_generic_contig
or
access
==
'full'
:
raise
CompileError
(
pos
,
"Generic contiguous cannot be combined with direct contiguous"
)
else
:
raise
CompileError
(
pos
,
"Only one direct contiguous axis may be specified."
)
# Note: We do NOT allow access == 'full' to act as
# "additionally potentially contiguous"
has_contig
=
access
!=
'ptr'
has_generic_contig
=
has_generic_contig
or
access
==
'full'
elif
packing
==
'follow'
:
elif
packing
==
'follow'
:
if
has_strided
:
if
has_strided
:
raise
CompileError
(
pos
,
"A memoryview cannot have both follow and strided axis specifiers."
)
raise
CompileError
(
pos
,
"A memoryview cannot have both follow and strided axis specifiers."
)
...
...
Cython/Utility/MemoryView_C.c
View file @
522cb284
...
@@ -42,6 +42,11 @@ static int __Pyx_init_memviewslice(
...
@@ -42,6 +42,11 @@ static int __Pyx_init_memviewslice(
int
ndim
,
int
ndim
,
__Pyx_memviewslice
*
memviewslice
);
__Pyx_memviewslice
*
memviewslice
);
#if CYTHON_REFNANNY
/* disable inlining when running tests */
#define CYTHON_INLINE
#endif
#define __PYX_INC_MEMVIEW(slice, have_gil) __Pyx_INC_MEMVIEW(slice, have_gil, __LINE__)
#define __PYX_INC_MEMVIEW(slice, have_gil) __Pyx_INC_MEMVIEW(slice, have_gil, __LINE__)
#define __PYX_XDEC_MEMVIEW(slice, have_gil) __Pyx_XDEC_MEMVIEW(slice, have_gil, __LINE__)
#define __PYX_XDEC_MEMVIEW(slice, have_gil) __Pyx_XDEC_MEMVIEW(slice, have_gil, __LINE__)
static
CYTHON_INLINE
void
__Pyx_INC_MEMVIEW
({{
memviewslice_name
}}
*
,
int
,
int
);
static
CYTHON_INLINE
void
__Pyx_INC_MEMVIEW
({{
memviewslice_name
}}
*
,
int
,
int
);
...
@@ -141,7 +146,13 @@ static int __Pyx_ValidateAndInit_memviewslice(
...
@@ -141,7 +146,13 @@ static int __Pyx_ValidateAndInit_memviewslice(
spec
=
axes_specs
[
i
];
spec
=
axes_specs
[
i
];
if
(
spec
&
__Pyx_MEMVIEW_CONTIG
)
{
if
(
spec
&
__Pyx_MEMVIEW_CONTIG
)
{
if
(
buf
->
strides
[
i
]
!=
buf
->
itemsize
)
{
if
(
spec
&
(
__Pyx_MEMVIEW_PTR
|
__Pyx_MEMVIEW_FULL
))
{
if
(
buf
->
strides
[
i
]
!=
sizeof
(
void
*
))
{
PyErr_Format
(
PyExc_ValueError
,
"Buffer is not indirectly contiguous in dimension %d."
,
i
);
goto
fail
;
}
}
else
if
(
buf
->
strides
[
i
]
!=
buf
->
itemsize
)
{
PyErr_SetString
(
PyExc_ValueError
,
PyErr_SetString
(
PyExc_ValueError
,
"Buffer and memoryview are not contiguous in the same dimension."
);
"Buffer and memoryview are not contiguous in the same dimension."
);
goto
fail
;
goto
fail
;
...
@@ -156,26 +167,24 @@ static int __Pyx_ValidateAndInit_memviewslice(
...
@@ -156,26 +167,24 @@ static int __Pyx_ValidateAndInit_memviewslice(
}
}
}
}
/* Todo: without PyBUF_INDIRECT we may not have suboffset information, i.e., the
ptr may not be set to NULL but may be uninitialized? */
if
(
spec
&
__Pyx_MEMVIEW_DIRECT
)
{
if
(
spec
&
__Pyx_MEMVIEW_DIRECT
)
{
if
(
buf
->
suboffsets
&&
buf
->
suboffsets
[
i
]
>=
0
)
{
if
(
buf
->
suboffsets
&&
buf
->
suboffsets
[
i
]
>=
0
)
{
PyErr_
SetString
(
PyExc_ValueError
,
PyErr_
Format
(
PyExc_ValueError
,
"Buffer not compatible with direct access
."
);
"Buffer not compatible with direct access
in dimension %d."
,
i
);
goto
fail
;
goto
fail
;
}
}
}
}
if
(
spec
&
__Pyx_MEMVIEW_PTR
)
{
if
(
spec
&
(
__Pyx_MEMVIEW_PTR
|
__Pyx_MEMVIEW_FULL
)
&&
!
buf
->
suboffsets
)
{
if
(
!
buf
->
suboffsets
)
{
memviewslice
->
suboffsets
[
i
]
=
-
1
;
PyErr_SetString
(
PyExc_ValueError
,
"Buffer not able to be indirectly accessed."
);
goto
fail
;
}
}
}
if
(
spec
&
__Pyx_MEMVIEW_PTR
)
{
if
(
spec
&
__Pyx_MEMVIEW_PTR
)
{
if
(
buf
->
suboffsets
[
i
]
<
0
)
{
if
(
buf
->
suboffsets
&&
buf
->
suboffsets
[
i
]
<
0
)
{
PyErr_Format
(
PyExc_ValueError
,
PyErr_Format
(
PyExc_ValueError
,
"Buffer
not indirectly accessed in %d dimension, although memoryview is
."
,
i
);
"Buffer
is not indirectly accessisble in dimension %d
."
,
i
);
goto
fail
;
goto
fail
;
}
}
}
}
...
...
tests/errors/memview_declarations.pyx
View file @
522cb284
...
@@ -27,6 +27,22 @@ cdef object[:, ::1] unconformable2 = unconformable1
...
@@ -27,6 +27,22 @@ cdef object[:, ::1] unconformable2 = unconformable1
cdef
int
[::
1
,
:]
dtype_unconformable
=
object
()
cdef
int
[::
1
,
:]
dtype_unconformable
=
object
()
unconformable1
=
dtype_unconformable
unconformable1
=
dtype_unconformable
# These are INVALID
cdef
int
[::
view
.
contiguous
,
::
1
]
a1
cdef
int
[::
view
.
generic_contiguous
,
::
1
]
a2
cdef
int
[::
view
.
contiguous
,
::
view
.
generic_contiguous
]
a3
cdef
int
[::
view
.
generic_contiguous
,
::
view
.
generic_contiguous
]
a4
cdef
int
[::
view
.
contiguous
,
::
view
.
contiguous
]
a5
cdef
int
[:,
::
view
.
contiguous
,
::
view
.
indirect_contiguous
]
a6
cdef
int
[::
view
.
generic_contiguous
,
::
view
.
contiguous
]
a7
cdef
int
[::
view
.
contiguous
,
::
view
.
generic_contiguous
]
a8
# These are VALID
cdef
int
[::
view
.
indirect_contiguous
,
::
view
.
contiguous
]
a9
_ERRORS
=
u'''
_ERRORS
=
u'''
11:25: Cannot specify an array that is both C and Fortran contiguous.
11:25: Cannot specify an array that is both C and Fortran contiguous.
12:31: Cannot specify an array that is both C and Fortran contiguous.
12:31: Cannot specify an array that is both C and Fortran contiguous.
...
@@ -42,4 +58,12 @@ _ERRORS = u'''
...
@@ -42,4 +58,12 @@ _ERRORS = u'''
22:22: no expressions allowed in axis spec, only names and literals.
22:22: no expressions allowed in axis spec, only names and literals.
25:51: Memoryview 'object[::contiguous, :]' not conformable to memoryview 'object[:, ::contiguous]'.
25:51: Memoryview 'object[::contiguous, :]' not conformable to memoryview 'object[:, ::contiguous]'.
28:36: Different base types for memoryviews (int, Python object)
28:36: Different base types for memoryviews (int, Python object)
31:15: Invalid axis specification for a C/Fortran contiguous array.
32:15: Invalid axis specification for a C/Fortran contiguous array.
34:9: Generic contiguous cannot be combined with direct contiguous
35:9: Generic contiguous cannot be combined with direct contiguous
37:9: Only one direct contiguous axis may be specified.
38:9: Indirect contiguous dimensions must precede direct contiguous
40:9: Generic contiguous cannot be combined with direct contiguous
41:9: Generic contiguous cannot be combined with direct contiguous
'''
'''
tests/run/memslice.pyx
View file @
522cb284
...
@@ -431,7 +431,7 @@ def wraparound_directive(int[:] buf, int pos_idx, int neg_idx):
...
@@ -431,7 +431,7 @@ def wraparound_directive(int[:] buf, int pos_idx, int neg_idx):
#
#
# Test
which flags are passed.
# Test
all kinds of indexing and flags
#
#
@
testcase
@
testcase
...
@@ -512,6 +512,127 @@ def f_contig_2d(int[::1, :] buf):
...
@@ -512,6 +512,127 @@ def f_contig_2d(int[::1, :] buf):
"""
"""
return
buf
[
3
,
1
]
return
buf
[
3
,
1
]
@
testcase
def
generic
(
int
[::
view
.
generic
,
::
view
.
generic
]
buf1
,
int
[::
view
.
generic
,
::
view
.
generic
]
buf2
):
"""
>>> A = IntMockBuffer("A", [[0,1,2], [3,4,5], [6,7,8]])
>>> B = IntMockBuffer("B", [[0,1,2], [3,4,5], [6,7,8]], shape=(3, 3), strides=(1, 3))
>>> generic(A, B)
acquired A
acquired B
4
4
10
11
released A
released B
>>> [str(x) for x in A.recieved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
>>> [str(x) for x in B.recieved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
"""
print
buf1
[
1
,
1
]
print
buf2
[
1
,
1
]
buf1
[
2
,
-
1
]
=
10
buf2
[
2
,
-
1
]
=
11
print
buf1
[
2
,
2
]
print
buf2
[
2
,
2
]
@
testcase
def
generic_contig
(
int
[::
view
.
generic_contiguous
,
:]
buf1
,
int
[::
view
.
generic_contiguous
,
:]
buf2
):
"""
>>> A = IntMockBuffer("A", [[0,1,2], [3,4,5], [6,7,8]])
>>> B = IntMockBuffer("B", [[0,1,2], [3,4,5], [6,7,8]], shape=(3, 3), strides=(1, 3))
>>> generic_contig(A, B)
acquired A
acquired B
4
4
10
11
released A
released B
>>> [str(x) for x in A.recieved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
>>> [str(x) for x in B.recieved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
"""
print
buf1
[
1
,
1
]
print
buf2
[
1
,
1
]
buf1
[
2
,
-
1
]
=
10
buf2
[
2
,
-
1
]
=
11
print
buf1
[
2
,
2
]
print
buf2
[
2
,
2
]
@
testcase
def
indirect_strided_and_contig
(
int
[::
view
.
indirect
,
::
view
.
strided
]
buf1
,
int
[::
view
.
indirect
,
::
view
.
contiguous
]
buf2
):
"""
>>> A = IntMockBuffer("A", [[0,1,2], [3,4,5], [6,7,8]])
>>> B = IntMockBuffer("B", [[0,1,2], [3,4,5], [6,7,8]], shape=(3, 3), strides=(1, 3))
>>> indirect_strided_and_contig(A, B)
acquired A
acquired B
4
4
10
11
released A
released B
>>> [str(x) for x in A.recieved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
>>> [str(x) for x in B.recieved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
"""
print
buf1
[
1
,
1
]
print
buf2
[
1
,
1
]
buf1
[
2
,
-
1
]
=
10
buf2
[
2
,
-
1
]
=
11
print
buf1
[
2
,
2
]
print
buf2
[
2
,
2
]
@
testcase
def
indirect_contig
(
int
[::
view
.
indirect_contiguous
,
::
view
.
contiguous
]
buf1
,
int
[::
view
.
indirect_contiguous
,
::
view
.
generic
]
buf2
):
"""
>>> A = IntMockBuffer("A", [[0,1,2], [3,4,5], [6,7,8]])
>>> B = IntMockBuffer("B", [[0,1,2], [3,4,5], [6,7,8]], shape=(3, 3), strides=(1, 3))
>>> indirect_contig(A, B)
acquired A
acquired B
4
4
10
11
released A
released B
>>> [str(x) for x in A.recieved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
>>> [str(x) for x in B.recieved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
"""
print
buf1
[
1
,
1
]
print
buf2
[
1
,
1
]
buf1
[
2
,
-
1
]
=
10
buf2
[
2
,
-
1
]
=
11
print
buf1
[
2
,
2
]
print
buf2
[
2
,
2
]
#
#
# Test compiler options for bounds checking. We create an array with a
# Test compiler options for bounds checking. We create an array with a
# safe "boundary" (memory
# safe "boundary" (memory
...
...
tests/run/mockbuffers.pxi
View file @
522cb284
...
@@ -99,18 +99,22 @@ cdef class MockBuffer:
...
@@ -99,18 +99,22 @@ cdef class MockBuffer:
it
+=
self
.
itemsize
it
+=
self
.
itemsize
return
buf
return
buf
cdef
void
*
create_indirect_buffer
(
self
,
data
,
shape
):
cdef
void
*
create_indirect_buffer
(
self
,
data
,
shape
)
except
NULL
:
cdef
size_t
n
=
0
cdef
size_t
n
=
0
cdef
void
**
buf
cdef
void
**
buf
assert
shape
[
0
]
==
len
(
data
)
assert
shape
[
0
]
==
len
(
data
)
,
(
shape
[
0
],
len
(
data
))
if
len
(
shape
)
==
1
:
if
len
(
shape
)
==
1
:
return
self
.
create_buffer
(
data
)
return
self
.
create_buffer
(
data
)
else
:
else
:
shape
=
shape
[
1
:]
shape
=
shape
[
1
:]
n
=
<
size_t
>
len
(
data
)
*
sizeof
(
void
*
)
n
=
<
size_t
>
len
(
data
)
*
sizeof
(
void
*
)
buf
=
<
void
**>
stdlib
.
malloc
(
n
)
buf
=
<
void
**>
stdlib
.
malloc
(
n
)
if
buf
==
NULL
:
return
NULL
for
idx
,
subdata
in
enumerate
(
data
):
for
idx
,
subdata
in
enumerate
(
data
):
buf
[
idx
]
=
self
.
create_indirect_buffer
(
subdata
,
shape
)
buf
[
idx
]
=
self
.
create_indirect_buffer
(
subdata
,
shape
)
return
buf
return
buf
cdef
Py_ssize_t
*
list_to_sizebuf
(
self
,
l
):
cdef
Py_ssize_t
*
list_to_sizebuf
(
self
,
l
):
...
...
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