Hi, A few weeks ago I started an implementation of that simple usecase:
cdef long a[2], x, y # set a[0] and a[1] to some useful values x, y = a It does works, but I’m not used to the interactions between the different parts of the code, I mainly hacked away where I could. I’m especially dissatisfied with the code duplication I came with (to check the correct types and size) and the location of the checks. I added testcases for both the array assignation and the slices of that same assignation I plan to implement, which seems to integrate badly with my current implementation, making the code even more unreadable. I tried to find a commit implementing a similar feature so I could get some inspiration but couldn’t find one. If someone has a hint about that I’d be glad. :) Btw, on a Cython.Compiler.ExprNodes.SliceIndexNode object, why does stop_code() give an int while start_code() gives a string? It’d be much better to return an int in both cases, so one could interpolate without conversion from both python or the generated C. Preliminary patch joined. -- Emmanuel Gil Peyrot XMPP: <linkma...@linkmauve.fr> OpenPGP: 24B1D609
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 2511eaf..bf04ff1 100755 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -5615,6 +5615,11 @@ class SequenceNode(ExprNode): def generate_assignment_code(self, rhs, code): if self.starred_assignment: self.generate_starred_assignment_code(rhs, code) + elif (isinstance(self, TupleNode) and + isinstance(rhs, NameNode) and + isinstance(rhs.entry.type, PyrexTypes.CArrayType)): + self.generate_parallel_assignment_code2(rhs, code) + return else: self.generate_parallel_assignment_code(rhs, code) @@ -5627,6 +5632,22 @@ class SequenceNode(ExprNode): PyrexTypes.CFuncTypeArg("it", PyrexTypes.py_object_type, None), ])) + def generate_parallel_assignment_code2(self, rhs, code): + rhs_type = rhs.entry.type + base_type = rhs_type.base_type + size = rhs_type.size + lhs_args = self.args + assert len(lhs_args) == size + for arg in lhs_args: + if arg.entry.type is not base_type: + raise ValueError("Wrong type for parallel assignment of '%s' array: %s" % + (base_type, arg.entry.type)) + for i, arg in enumerate(lhs_args): + code.putln("%s = %s[%s];" % ( + arg.result(), + rhs.result(), + i)) + def generate_parallel_assignment_code(self, rhs, code): # Need to work around the fact that generate_evaluation_code # allocates the temps in a rather hacky way -- the assignment diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index fe7adb3..7987cc6 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -4509,6 +4509,20 @@ class SingleAssignmentNode(AssignmentNode): self.lhs = self.lhs.analyse_target_types(env) self.lhs.gil_assignment_check(env) + if (isinstance(self.lhs, ExprNodes.TupleNode) and + isinstance(self.rhs, ExprNodes.NameNode)): + rhs_type = self.rhs.entry.type + if isinstance(rhs_type, PyrexTypes.CArrayType): + base_type = rhs_type.base_type + size = rhs_type.size + lhs_args = self.lhs.args + assert len(lhs_args) == size + for arg in lhs_args: + if arg.entry.type is not base_type: + break + else: + return self + if self.lhs.memslice_broadcast or self.rhs.memslice_broadcast: self.lhs.memslice_broadcast = True self.rhs.memslice_broadcast = True diff --git a/tests/run/arrayassign.pyx b/tests/run/arrayassign.pyx index 29c353e..f76ad2e 100644 --- a/tests/run/arrayassign.pyx +++ b/tests/run/arrayassign.pyx @@ -128,6 +128,59 @@ def test_ptr_literal_list_slice_end(): a[:5] = [1,2,3,4,5] return (a[0], a[1], a[2], a[3], a[4]) + +# The opposite, assignation from an array to multiple scalars. + +def test_array_to_scalars(): + """ + >>> test_array_to_scalars() + (1, 2, 3, 4, 5) + """ + cdef int l[5], a, b, c, d, e + l[:] = [1,2,3,4,5] + a, b, c, d, e = l + return (a, b, c, d, e) + +def test_slice_all_to_scalars(): + """ + >>> test_slice_all_to_scalars() + (1, 2, 3, 4, 5) + """ + cdef int l[5], a, b, c, d, e + l[:] = [1,2,3,4,5] + a, b, c, d, e = l[:] + return (a, b, c, d, e) + +def test_slice_start_to_scalars(): + """ + >>> test_slice_start_to_scalars() + (1, 2, 3, 4, 5) + """ + cdef int l[7], a, b, c, d, e + l[:] = [6,7,1,2,3,4,5] + a, b, c, d, e = l[2:] + return (a, b, c, d, e) + +def test_slice_end_to_scalars(): + """ + >>> test_slice_end_to_scalars() + (1, 2, 3, 4, 5) + """ + cdef int l[7], a, b, c, d, e + l[:] = [1,2,3,4,5,6,7] + a, b, c, d, e = l[:5] + return (a, b, c, d, e) + +def test_slice_start_end_to_scalars(): + """ + >>> test_slice_start_end_to_scalars() + (1, 2, 3, 4, 5) + """ + cdef int l[9], a, b, c, d, e + l[:] = [6,7,1,2,3,4,5,8,9] + a, b, c, d, e = l[2:7] + return (a, b, c, d, e) + # tuples aren't supported (yet) # #def test_literal_tuple():
pgp3b57ubbNAL.pgp
Description: PGP signature
_______________________________________________ cython-devel mailing list cython-devel@python.org https://mail.python.org/mailman/listinfo/cython-devel