Commit 5fbfb6f6 authored by Mark Florisson's avatar Mark Florisson

Support None memoryview slices

parent 3aa13fa7
......@@ -2886,8 +2886,7 @@ class IndexNode(ExprNode):
def generate_result_code(self, code):
if self.is_buffer_access or self.memslice_index:
if code.globalstate.directives['nonecheck']:
self.put_nonecheck(code)
self.nonecheck(code)
buffer_entry, self.buffer_ptr_code = self.buffer_lookup_code(code)
if self.type.is_pyobject:
# is_temp is True, so must pull out value and incref it.
......@@ -2895,6 +2894,7 @@ class IndexNode(ExprNode):
code.putln("__Pyx_INCREF((PyObject*)%s);" % self.result())
elif self.memslice_slice:
self.nonecheck(code)
self.put_memoryviewslice_slice_code(code)
elif self.is_temp:
......@@ -2969,9 +2969,7 @@ class IndexNode(ExprNode):
def generate_buffer_setitem_code(self, rhs, code, op=""):
# Used from generate_assignment_code and InPlaceAssignmentNode
if code.globalstate.directives['nonecheck'] and not self.memslice_index:
self.put_nonecheck(code)
self.nonecheck(code)
buffer_entry, ptrexpr = self.buffer_lookup_code(code)
if self.buffer_type.dtype.is_pyobject:
......@@ -3133,10 +3131,23 @@ class IndexNode(ExprNode):
import MemoryView
MemoryView.assign_scalar(self, rhs, code)
def nonecheck(self, code):
if code.globalstate.directives['nonecheck']:
self.put_nonecheck(code)
def put_nonecheck(self, code):
code.globalstate.use_utility_code(raise_noneindex_error_utility_code)
code.putln("if (%s) {" % code.unlikely("%s == Py_None") % self.base.result_as(PyrexTypes.py_object_type))
code.putln("__Pyx_RaiseNoneIndexingError();")
if self.base.type.is_memoryviewslice:
code.globalstate.use_utility_code(
raise_noneindex_memview_error_utility_code)
code.putln("if (unlikely((PyObject *) %s.memview == Py_None)) {" %
self.base.result())
code.putln("__Pyx_RaiseNoneMemviewIndexingError();")
else:
code.globalstate.use_utility_code(raise_noneindex_error_utility_code)
code.putln("if (%s) {" % code.unlikely("%s == Py_None") %
self.base.result_as(PyrexTypes.py_object_type))
code.putln("__Pyx_RaiseNoneIndexingError();")
code.putln(code.error_goto(self.pos))
code.putln("}")
......@@ -4515,6 +4526,9 @@ class AttributeNode(ExprNode):
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
elif self.type.is_memoryviewslice:
if code.globalstate.directives['nonecheck']:
self.put_nonecheck(code)
if self.is_memslice_transpose:
# transpose the slice
for access, packing in self.type.axes:
......@@ -4537,6 +4551,9 @@ class AttributeNode(ExprNode):
'"Memoryview is not initialized");'
'%s'
'}' % (self.result(), code.error_goto(self.pos)))
elif (self.obj.type.is_memoryviewslice and
code.globalstate.directives['nonecheck']):
self.put_nonecheck(code)
else:
# result_code contains what is needed, but we may need to insert
# a check and raise an exception
......@@ -4614,7 +4631,7 @@ class AttributeNode(ExprNode):
if self.obj.type.is_extension_type:
test = "%s == Py_None" % self.obj.result_as(PyrexTypes.py_object_type)
elif self.obj.type.is_memoryviewslice:
test = "!%s.memview" % self.obj.result()
test = "(PyObject *) %s.memview == Py_None" % self.obj.result()
else:
assert False
code.putln("if (%s) {" % code.unlikely(test))
......@@ -9647,6 +9664,16 @@ static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void) {
}
''')
raise_noneindex_memview_error_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneMemviewIndexingError(void);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneMemviewIndexingError(void) {
PyErr_SetString(PyExc_TypeError, "Cannot index None memoryview slice");
}
''')
raise_none_iter_error_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void);
......
......@@ -921,6 +921,9 @@ cdef memoryview_fromslice({{memviewslice_name}} *memviewslice,
cdef _memoryviewslice result
cdef int i
if <PyObject *> memviewslice.memview == Py_None:
return None
# assert 0 < ndim <= memviewslice.memview.view.ndim, (
# ndim, memviewslice.memview.view.ndim)
......
......@@ -163,9 +163,15 @@ static CYTHON_INLINE char *__pyx_memviewslice_index_full(const char *bufp, Py_ss
static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *obj) {
{{memviewslice_name}} result = {{memslice_init}};
struct __pyx_memoryview_obj *memview;
struct __pyx_memoryview_obj *memview = \
(struct __pyx_memoryview_obj *) __pyx_memoryview_new(obj, {{buf_flag}}, 0);
if (obj == Py_None) {
/* We don't bother to refcount None */
result.memview = (struct __pyx_memoryview_obj *) Py_None;
return result;
}
memview = (struct __pyx_memoryview_obj *) __pyx_memoryview_new(obj, {{buf_flag}}, 0);
__Pyx_BufFmt_StackElem stack[{{struct_nesting_depth}}];
int axes_specs[] = { {{axes_specs}} };
int retcode;
......@@ -419,7 +425,7 @@ __Pyx_INC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil, int lineno)
{
int first_time;
struct {{memview_struct_name}} *memview = memslice->memview;
if (!memview)
if (!memview || (PyObject *) memview == Py_None)
return; /* allow uninitialized memoryview assignment */
if (memview->acquisition_count < 0)
......@@ -444,7 +450,7 @@ static CYTHON_INLINE void __Pyx_XDEC_MEMVIEW({{memviewslice_name}} *memslice,
int last_time;
struct {{memview_struct_name}} *memview = memslice->memview;
if (!memview)
if (!memview || (PyObject *) memview == Py_None)
return;
if (memview->acquisition_count <= 0)
......
......@@ -218,11 +218,15 @@ e.g. do::
Of course, you are not restricted to using NumPy's type (such as ``np.int32_t`` here), you can use any usable type.
The future
==========
In the future some functionality may be added for convenience, like
None Slices
===========
Although memoryview slices are not objects they can be set to None and they can be be
checked for being None as well::
1. A numpy-like `.flat` attribute (that allows efficient iteration)
2. Indexing with newaxis or None to introduce a new axis
def func(double[:] myarray = None):
print myarray is None
Unlike object attributes of extension classes, memoryview slices are not initialized
to None.
.. _NumPy: http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html#memory-layout
......@@ -52,9 +52,8 @@ def acquire_release(o1, o2):
released A
released B
>>> acquire_release(None, B)
Traceback (most recent call last):
...
TypeError: 'NoneType' does not have the buffer interface
acquired B
released B
"""
cdef int[:] buf
buf = o1
......@@ -148,7 +147,7 @@ def acquire_nonbuffer1(first, second=None):
>>> acquire_nonbuffer1(None, 2)
Traceback (most recent call last):
...
TypeError: 'NoneType' does not have the buffer interface
TypeError: 'int' does not have the buffer interface
>>> acquire_nonbuffer1(4, object())
Traceback (most recent call last):
...
......@@ -2086,3 +2085,95 @@ def test_dtype_object_scalar_assignment():
(<object> m)[:] = SingleObject(3)
assert m[0] == m[4] == m[-1] == 3
#
### Test slices that are set to None
#
@testcase
def test_coerce_to_from_None(double[:] m1, double[:] m2 = None):
"""
>>> test_coerce_to_from_None(None)
(None, None)
>>> test_coerce_to_from_None(None, None)
(None, None)
"""
return m1, m2
@testcase
def test_noneslice_attrib(double[:] m):
"""
>>> test_noneslice_attrib(None)
'NoneType' object has no attribute 'copy'
'NoneType' object has no attribute 'T'
"""
cdef double[:] m2
with cython.nonecheck(True):
try:
m2 = m.copy()
except Exception, e:
print e.args[0]
try:
m2 = m.T
except Exception, e:
print e.args[0]
@testcase
def test_noneslice_index(double[:] m):
"""
>>> test_noneslice_index(None)
Cannot index None memoryview slice
Cannot index None memoryview slice
Cannot index None memoryview slice
Cannot index None memoryview slice
"""
with cython.nonecheck(True):
try:
m[10]
except Exception, e:
print e.args[0]
try:
m[:]
except Exception, e:
print e.args[0]
try:
m[10] = 2
except Exception, e:
print e.args[0]
try:
m[:] = 2
except Exception, e:
print e.args[0]
@testcase
def test_noneslice_compare(double[:] m):
"""
>>> test_noneslice_compare(None)
(True, True)
"""
with cython.nonecheck(True):
result = m is None
return result, m is None
cdef class NoneSliceAttr(object):
cdef double[:] m
@testcase
def test_noneslice_ext_attr():
"""
>>> test_noneslice_ext_attr()
AttributeError Memoryview is not initialized
None
"""
cdef NoneSliceAttr obj = NoneSliceAttr()
with cython.nonecheck(True):
try: print obj.m
except Exception, e: print type(e).__name__, e.args[0]
obj.m = None
print obj.m
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