implement tuple(genexp) as tuple(list(genexp))
authorStefan Behnel <scoder@users.berlios.de>
Thu, 27 May 2010 16:12:13 +0000 (18:12 +0200)
committerStefan Behnel <scoder@users.berlios.de>
Thu, 27 May 2010 16:12:13 +0000 (18:12 +0200)
Cython/Compiler/Optimize.py
tests/run/inlined_generator_expressions.pyx

index 051a0b05dab3dc555b0ee2a91f9dd029291c8e79..00c69c34c186de2b87efca98b1294f335e379029 100644 (file)
@@ -1186,6 +1186,21 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
             gen_expr_node.pos, loop = exec_code, result_node = result_ref,
             expr_scope = gen_expr_node.expr_scope, orig_func = 'sum')
 
+    def _handle_simple_function_tuple(self, node, pos_args):
+        if len(pos_args) == 0:
+            return ExprNodes.TupleNode(node.pos, args=[], constant_result=())
+        # This is a bit special - for iterables (including genexps),
+        # Python actually overallocates and resizes a newly created
+        # tuple incrementally while reading items, which we can't
+        # easily do without explicit node support. Instead, we read
+        # the items into a list and then copy them into a tuple of the
+        # final size.  This takes up to twice as much memory, but will
+        # have to do until we have real support for genexps.
+        result = self._transform_list_set_genexpr(node, pos_args, ExprNodes.ListNode)
+        if result is not node:
+            return ExprNodes.AsTupleNode(node.pos, arg=result)
+        return node
+
     def _handle_simple_function_list(self, node, pos_args):
         if len(pos_args) == 0:
             return ExprNodes.ListNode(node.pos, args=[], constant_result=[])
index 9e516531dddbbb49bd17e81b66bfdf27550331bc..3fd1bbde9daf9b0867474e4d9bd86ca3571f9c9b 100644 (file)
@@ -1,6 +1,14 @@
 
 cimport cython
 
+def range_tuple_genexp(int N):
+    """
+    >>> range_tuple_genexp(5)
+    (0, 1, 2, 3, 4)
+    """
+    return tuple(i for i in range(N))
+
+
 @cython.test_assert_path_exists('//ForFromStatNode',
                                 "//InlinedGeneratorExpressionNode")
 @cython.test_fail_if_path_exists('//SimpleCallNode',
@@ -15,6 +23,7 @@ def range_sum(int N):
     result = sum(i for i in range(N))
     return result
 
+
 @cython.test_assert_path_exists('//ForFromStatNode',
                                 "//InlinedGeneratorExpressionNode")
 @cython.test_fail_if_path_exists('//SimpleCallNode',
@@ -30,6 +39,7 @@ def range_sum_typed(int N):
     cdef int result = sum(i for i in range(N))
     return result
 
+
 @cython.test_assert_path_exists('//ForFromStatNode',
                                 "//InlinedGeneratorExpressionNode",
                                 "//ReturnStatNode//InlinedGeneratorExpressionNode",
@@ -47,6 +57,7 @@ def return_range_sum_cast(int N):
     """
     return <int>sum(i for i in range(N))
 
+
 @cython.test_assert_path_exists('//ForFromStatNode',
                                 "//InlinedGeneratorExpressionNode")
 @cython.test_fail_if_path_exists('//SimpleCallNode',
@@ -60,6 +71,7 @@ def return_range_sum(int N):
     """
     return sum(i for i in range(N))
 
+
 @cython.test_assert_path_exists('//ForFromStatNode',
                                 "//InlinedGeneratorExpressionNode")
 @cython.test_fail_if_path_exists('//SimpleCallNode',
@@ -78,6 +90,7 @@ def return_range_sum_squares(int N):
     """
     return sum(i*i for i in range(N))
 
+
 @cython.test_assert_path_exists('//ForInStatNode',
                                 "//InlinedGeneratorExpressionNode")
 @cython.test_fail_if_path_exists('//SimpleCallNode')
@@ -95,6 +108,7 @@ def return_sum_squares(seq):
     """
     return sum(i*i for i in seq)
 
+
 @cython.test_assert_path_exists('//ForInStatNode',
                                 "//InlinedGeneratorExpressionNode")
 @cython.test_fail_if_path_exists('//SimpleCallNode')