From f8e85bee920b37b94aebd303bbb9ef4ba733f905 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Fri, 3 Sep 2010 21:15:40 +0200 Subject: [PATCH] implement C array iteration with explicit step size (#574), always coerce start/stop offsets in C array iteration to Py_ssize_t --- Cython/Compiler/Optimize.py | 49 +++++++++++++++++++++++++++++++++--- tests/run/carray_slicing.pyx | 38 +++++++++++++++++----------- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/Cython/Compiler/Optimize.py b/Cython/Compiler/Optimize.py index cae8c982..316fcd41 100644 --- a/Cython/Compiler/Optimize.py +++ b/Cython/Compiler/Optimize.py @@ -90,9 +90,15 @@ class IterationTransform(Visitor.VisitorTransform): node, dict_obj=iterator, keys=True, values=False) # C array (slice) iteration? + if isinstance(iterator, ExprNodes.CoerceToPyTypeNode): + iterator = iterator.arg if isinstance(iterator, ExprNodes.SliceIndexNode) and \ (iterator.base.type.is_array or iterator.base.type.is_ptr): return self._transform_carray_iteration(node, iterator) + elif isinstance(iterator, ExprNodes.IndexNode) and \ + isinstance(iterator.index, (ExprNodes.SliceNode, ExprNodes.CoerceFromPyTypeNode)) and \ + (iterator.base.type.is_array or iterator.base.type.is_ptr): + return self._transform_carray_iteration(node, iterator) elif iterator.type.is_array: return self._transform_carray_iteration(node, iterator) elif iterator.type in (Builtin.bytes_type, Builtin.unicode_type): @@ -201,6 +207,7 @@ class IterationTransform(Visitor.VisitorTransform): ))) def _transform_carray_iteration(self, node, slice_node): + neg_step = False if isinstance(slice_node, ExprNodes.SliceIndexNode): slice_base = slice_node.base start = slice_node.start @@ -208,15 +215,51 @@ class IterationTransform(Visitor.VisitorTransform): step = None if not stop: return node + elif isinstance(slice_node, ExprNodes.IndexNode): + # slice_node.index must be a SliceNode + slice_base = slice_node.base + index = slice_node.index + if isinstance(index, ExprNodes.CoerceFromPyTypeNode): + index = index.arg + start = index.start + stop = index.stop + step = index.step + if step: + if step.constant_result is None: + step = None + elif not isinstance(step.constant_result, (int,long)) \ + or step.constant_result == 0 \ + or step.constant_result > 0 and not stop \ + or step.constant_result < 0 and not start: + error(step.pos, "C array iteration requires known step size and end index") + return node + else: + # step sign is handled internally by ForFromStatNode + neg_step = step.constant_result < 0 + step = ExprNodes.IntNode(step.pos, type=PyrexTypes.c_py_ssize_t_type, + value=abs(step.constant_result), + constant_result=abs(step.constant_result)) elif slice_node.type.is_array and slice_node.type.size is not None: slice_base = slice_node start = None stop = ExprNodes.IntNode( - slice_node.pos, value=str(slice_node.type.size)) + slice_node.pos, value=str(slice_node.type.size), + type=PyrexTypes.c_py_ssize_t_type, constant_result=slice_node.type.size) step = None else: return node + if start: + if start.constant_result is None: + start = None + else: + start = start.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_scope) + if stop: + if stop.constant_result is None: + stop = None + else: + stop = stop.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_scope) + ptr_type = slice_base.type if ptr_type.is_array: ptr_type = ptr_type.element_ptr_type() @@ -281,9 +324,9 @@ class IterationTransform(Visitor.VisitorTransform): for_node = Nodes.ForFromStatNode( node.pos, - bound1=start_ptr_node, relation1='<=', + bound1=start_ptr_node, relation1=neg_step and '>=' or '<=', target=counter_temp, - relation2='<', bound2=stop_ptr_node, + relation2=neg_step and '>' or '<', bound2=stop_ptr_node, step=step, body=body, else_clause=node.else_clause, from_range=True) diff --git a/tests/run/carray_slicing.pyx b/tests/run/carray_slicing.pyx index a33bd2df..8ad31374 100644 --- a/tests/run/carray_slicing.pyx +++ b/tests/run/carray_slicing.pyx @@ -42,20 +42,30 @@ def slice_charptr_for_loop_c(): print [ chr(c) for c in cstring[1:5] ] print [ chr(c) for c in cstring[4:9] ] -## @cython.test_assert_path_exists("//ForFromStatNode", -## "//ForFromStatNode//IndexNode") -## @cython.test_fail_if_path_exists("//ForInStatNode") -## def slice_charptr_for_loop_c_step(): -## """ -## >>> slice_charptr_for_loop_c() -## ['c', 'b', 'a'] -## ['b', 'c', 'A', 'B'] -## ['p', 't', 'q', 'C', 'B'] -## """ -## cdef char c -## print [ chr(c) for c in cstring[:3:-1] ] -## print [ chr(c) for c in cstring[1:5:2] ] -## print [ chr(c) for c in cstring[4:9:-1] ] +@cython.test_assert_path_exists("//ForFromStatNode", + "//ForFromStatNode//IndexNode") +@cython.test_fail_if_path_exists("//ForInStatNode") +def slice_charptr_for_loop_c_step(): + """ + >>> slice_charptr_for_loop_c_step() + [] + [] + ['b', 'A'] + ['a', 'c', 'B'] + ['a', 'c', 'B'] + [] + ['p', 't', 'q', 'C'] + ['p', 'q'] + """ + cdef char c + print [ chr(c) for c in cstring[:3:-1] ] + print [ chr(c) for c in cstring[None:3:-1] ] + print [ chr(c) for c in cstring[1:5:2] ] + print [ chr(c) for c in cstring[:5:2] ] + print [ chr(c) for c in cstring[None:5:2] ] + print [ chr(c) for c in cstring[4:9:-1] ] + print [ chr(c) for c in cstring[8:4:-1] ] + print [ chr(c) for c in cstring[8:4:-2] ] @cython.test_assert_path_exists("//ForFromStatNode", "//ForFromStatNode//IndexNode") -- 2.26.2