Commit d7e5e0c9 authored by Kurt Smith's avatar Kurt Smith Committed by Mark Florisson

Added validation checks on memoryviews.

parent e79e17f8
...@@ -106,8 +106,51 @@ def get_axes_specs(env, axes): ...@@ -106,8 +106,51 @@ 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)
return axes_specs return axes_specs
def validate_axes_specs(pos, specs):
packing_specs = ('contig', 'strided', 'follow')
access_specs = ('direct', 'ptr', 'full')
is_c_contig = is_f_contig = False
packing_idx = 1
if (specs[0][packing_idx] == 'contig' and
all(axis[packing_idx] == 'follow' for axis in specs[1:])):
# f_contiguous: 'contig', 'follow', 'follow', ..., 'follow'
is_f_contig = True
elif (len(specs) > 1 and
specs[-1][packing_idx] == 'contig' and
all(axis[packing_idx] == 'follow' for axis in specs[:-1])):
# c_contiguous: 'follow', 'follow', ..., 'follow', 'contig'
is_c_contig = True
has_contig = has_follow = has_strided = False
for access, packing in specs:
if not (access in access_specs and
packing in packing_specs):
raise CompileError(pos, "Invalid axes specification.")
if packing == 'strided':
has_strided = True
elif packing == 'contig':
if has_contig:
raise CompileError(pos, "Only one contiguous axis may be specified.")
has_contig = True
elif packing == 'follow':
if has_strided:
raise CompileError(pos, "A memoryview cannot have both follow and strided axis specifiers.")
if not (is_c_contig or is_f_contig):
raise CompileError(pos, "Invalid use of the follow specifier.")
def _get_resolved_spec(env, spec): def _get_resolved_spec(env, spec):
# spec must be a NameNode or an AttributeNode # spec must be a NameNode or an AttributeNode
......
...@@ -311,9 +311,43 @@ class CTypedefType(BaseType): ...@@ -311,9 +311,43 @@ class CTypedefType(BaseType):
class MemoryViewType(BaseType): class MemoryViewType(BaseType):
def __init__(self, base, axes): def __init__(self, base, axes):
'''
MemoryViewType(base, axes)
Base is the C base type; axes is a list of (access, packing) strings,
where access is one of 'full', 'direct' or 'ptr' and packing is one of
'contig', 'strided' or 'follow'. There is one (access, packing) tuple
for each dimension.
the access specifiers determine whether the array data contains
pointers that need to be dereferenced along that axis when
retrieving/setting:
'direct' -- No pointers stored in this dimension.
'ptr' -- Pointer stored in this dimension.
'full' -- Check along this dimension, don't assume either.
the packing specifiers specify how the array elements are layed-out
in memory.
'contig' -- The data are contiguous in memory along this dimension.
At most one dimension may be specified as 'contig'.
'strided' -- The data aren't contiguous along this dimenison.
'follow' -- Used for C/Fortran contiguous arrays, a 'follow' dimension
has its stride automatically computed from extents of the other
dimensions to ensure C or Fortran memory layout.
C-contiguous memory has 'direct' as the access spec, 'contig' as the
*last* axis' packing spec and 'follow' for all other packing specs.
Fortran-contiguous memory has 'direct' as the access spec, 'contig' as
the *first* axis' packing spec and 'follow' for all other packing
specs.
'''
self.base = base self.base = base
self.axes = axes self.axes = axes
class BufferType(BaseType): class BufferType(BaseType):
# #
# Delegates most attribute # Delegates most attribute
......
...@@ -14,4 +14,4 @@ cdef unsigned long[0:, 0:, 0:, 0::0x0001] c_contig0 ...@@ -14,4 +14,4 @@ cdef unsigned long[0:, 0:, 0:, 0::0x0001] c_contig0
cdef float[::foo & bar, ::cython.view.direct & cython.view.follow] view4 cdef float[::foo & bar, ::cython.view.direct & cython.view.follow] view4
cdef int[::view.full & foo] view3 cdef int[::view.full & foo] view3
cdef int[::view.ptr & follow] view1000 cdef int[::view.ptr & view.strided] view1000
# mode: error
cimport cython cimport cython
from cython.view cimport contig as foo, full as bar, follow from cython.view cimport contig as foo, full as bar, follow
from cython cimport view from cython cimport view
biz = cython.view.contig biz = cython.view.contig
foz = cython.view.full foz = cython.view.full
adict = {'view': cython.view} adict = {'view': cython.view}
alist = [adict] alist = [adict]
...@@ -24,6 +24,7 @@ cdef signed char[::view.ptr & view.direct] no_access_spec ...@@ -24,6 +24,7 @@ cdef signed char[::view.ptr & view.direct] no_access_spec
cdef signed char[::1-1+1] expr_spec cdef signed char[::1-1+1] expr_spec
cdef signed char[::blargh] bad_name cdef signed char[::blargh] bad_name
cdef double[::alist[0]['view'].full] expr_attribute cdef double[::alist[0]['view'].full] expr_attribute
cdef double[::view.ptr & view.follow] no_single_follow
_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.
...@@ -42,4 +43,5 @@ _ERRORS = u''' ...@@ -42,4 +43,5 @@ _ERRORS = u'''
24:22: Invalid axis specification. 24:22: Invalid axis specification.
25:25: Invalid axis specification. 25:25: Invalid axis specification.
26:22: no expressions allowed in axis spec, only names (e.g. cython.view.contig). 26:22: no expressions allowed in axis spec, only names (e.g. cython.view.contig).
27:12: Invalid use of the follow specifier.
''' '''
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