Commit 64f6b025 authored by Mark Florisson's avatar Mark Florisson

Convert memoryviewslice SliceNodes to IndexNodes

parent 0b1b3f00
...@@ -2392,7 +2392,7 @@ class IndexNode(ExprNode): ...@@ -2392,7 +2392,7 @@ class IndexNode(ExprNode):
def analyse_target_types(self, env): def analyse_target_types(self, env):
self.analyse_base_and_index_types(env, setting = 1) self.analyse_base_and_index_types(env, setting = 1)
def analyse_base_and_index_types(self, env, getting = 0, setting = 0): def analyse_base_and_index_types(self, env, getting = 0, setting = 0, analyse_base = True):
# Note: This might be cleaned up by having IndexNode # Note: This might be cleaned up by having IndexNode
# parsed in a saner way and only construct the tuple if # parsed in a saner way and only construct the tuple if
# needed. # needed.
...@@ -2409,7 +2409,9 @@ class IndexNode(ExprNode): ...@@ -2409,7 +2409,9 @@ class IndexNode(ExprNode):
# integer indexing # integer indexing
self.memslice_index = False self.memslice_index = False
self.base.analyse_types(env) if analyse_base:
self.base.analyse_types(env)
if self.base.type.is_error: if self.base.type.is_error:
# Do not visit child tree if base is undeclared to avoid confusing # Do not visit child tree if base is undeclared to avoid confusing
# error messages # error messages
...@@ -2417,12 +2419,15 @@ class IndexNode(ExprNode): ...@@ -2417,12 +2419,15 @@ class IndexNode(ExprNode):
return return
is_slice = isinstance(self.index, SliceNode) is_slice = isinstance(self.index, SliceNode)
# Potentially overflowing index value. # Potentially overflowing index value.
if not is_slice and isinstance(self.index, IntNode) and Utils.long_literal(self.index.value): if not is_slice and isinstance(self.index, IntNode) and Utils.long_literal(self.index.value):
self.index = self.index.coerce_to_pyobject(env) self.index = self.index.coerce_to_pyobject(env)
is_memslice = self.base.type.is_memoryviewslice
# Handle the case where base is a literal char* (and we expect a string, not an int) # Handle the case where base is a literal char* (and we expect a string, not an int)
if isinstance(self.base, BytesNode) or is_slice: if not is_memslice and (isinstance(self.base, BytesNode) or is_slice):
if self.base.type.is_string or not (self.base.type.is_ptr or self.base.type.is_array): if self.base.type.is_string or not (self.base.type.is_ptr or self.base.type.is_array):
self.base = self.base.coerce_to_pyobject(env) self.base = self.base.coerce_to_pyobject(env)
...@@ -2430,8 +2435,6 @@ class IndexNode(ExprNode): ...@@ -2430,8 +2435,6 @@ class IndexNode(ExprNode):
buffer_access = False buffer_access = False
memoryviewslice_access = False memoryviewslice_access = False
is_memslice = self.base.type.is_memoryviewslice
if self.indices: if self.indices:
indices = self.indices indices = self.indices
elif isinstance(self.index, TupleNode): elif isinstance(self.index, TupleNode):
...@@ -2909,8 +2912,6 @@ class IndexNode(ExprNode): ...@@ -2909,8 +2912,6 @@ class IndexNode(ExprNode):
have_gil = not self.in_nogil_context have_gil = not self.in_nogil_context
buffer_entry.generate_buffer_slice_code(code, buffer_entry.generate_buffer_slice_code(code,
self.original_indices, self.original_indices,
self.base.type,
self.type,
self.result(), self.result(),
have_gil=have_gil) have_gil=have_gil)
...@@ -2965,13 +2966,33 @@ class SliceIndexNode(ExprNode): ...@@ -2965,13 +2966,33 @@ class SliceIndexNode(ExprNode):
pass pass
def analyse_target_types(self, env): def analyse_target_types(self, env):
self.analyse_types(env) self.analyse_types(env, getting=False)
# when assigning, we must accept any Python type # when assigning, we must accept any Python type
if self.type.is_pyobject: if self.type.is_pyobject:
self.type = py_object_type self.type = py_object_type
def analyse_types(self, env): def analyse_types(self, env, getting=True):
self.base.analyse_types(env) self.base.analyse_types(env)
if self.base.type.is_memoryviewslice:
# Gross hack here! But we do not know the type until this point,
# and we cannot create and return a new node. So we change the
# type...
none_node = NoneNode(self.pos)
index = SliceNode(self.pos,
start=self.start or none_node,
stop=self.stop or none_node,
step=none_node)
del self.start
del self.stop
self.index = index
self.__class__ = IndexNode
self.analyse_base_and_index_types(env,
getting=getting,
setting=not getting,
analyse_base=False)
return
if self.start: if self.start:
self.start.analyse_types(env) self.start.analyse_types(env)
if self.stop: if self.stop:
......
...@@ -230,7 +230,16 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry): ...@@ -230,7 +230,16 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
return bufp return bufp
def generate_buffer_slice_code(self, code, indices, type, dst_type, dst, have_gil): def generate_buffer_slice_code(self, code, indices, dst, have_gil):
"""
Slice a memoryviewslice.
indices - list of index nodes. If not a SliceNode, then it must be
coercible to Py_ssize_t
Simply call __pyx_memoryview_slice_memviewslice with the right
arguments.
"""
slicefunc = "__pyx_memoryview_slice_memviewslice" slicefunc = "__pyx_memoryview_slice_memviewslice"
new_ndim = 0 new_ndim = 0
cname = self.cname cname = self.cname
......
...@@ -1400,3 +1400,21 @@ def test_nogil(): ...@@ -1400,3 +1400,21 @@ def test_nogil():
cdef_nogil(_a) cdef_nogil(_a)
cdef int[:, :] a = _a cdef int[:, :] a = _a
print a[2, 7] print a[2, 7]
@testcase
def test_convert_slicenode_to_indexnode():
"""
When indexing with a[i:j] a SliceNode gets created instead of an IndexNode, which
forces coercion to object and back. This would not only be inefficient, but it would
also not compile in nogil mode. So instead we mutate it into an IndexNode.
>>> test_convert_slicenode_to_indexnode()
acquired A
2
released A
"""
cdef int[:] a = IntMockBuffer("A", range(10), shape=(10,))
with nogil:
a = a[2:4]
print a[0]
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