From: Dag Sverre Seljebotn Date: Fri, 15 Aug 2008 18:20:49 +0000 (+0200) Subject: Buffers: Inplace operators working X-Git-Tag: 0.9.8.1~34 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=8418439db5a2a22f76bc932971d087b1903a5faf;p=cython.git Buffers: Inplace operators working This time hopefully without breaking other inplace operators. --- diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index b7e2b406..6439a7e8 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -1534,30 +1534,34 @@ class IndexNode(ExprNode): value_code, self.index_unsigned_parameter(), code.error_goto(self.pos))) - + + def generate_buffer_setitem_code(self, rhs, code, op=""): + # Used from generate_assignment_code and InPlaceAssignmentNode + ptrexpr = self.buffer_lookup_code(code) + if self.buffer_type.dtype.is_pyobject: + # Must manage refcounts. Decref what is already there + # and incref what we put in. + ptr = code.funcstate.allocate_temp(self.buffer_type.buffer_ptr_type) + if rhs.is_temp: + rhs_code = code.funcstate.allocate_temp(rhs.type) + else: + rhs_code = rhs.result_code + code.putln("%s = %s;" % (ptr, ptrexpr)) + code.putln("Py_DECREF(*%s); Py_INCREF(%s);" % ( + ptr, rhs_code + )) + code.putln("*%s %s= %s;" % (ptr, op, rhs_code)) + if rhs.is_temp: + code.funcstate.release_temp(rhs_code) + code.funcstate.release_temp(ptr) + else: + # Simple case + code.putln("*%s %s= %s;" % (ptrexpr, op, rhs.result_code)) + def generate_assignment_code(self, rhs, code): self.generate_subexpr_evaluation_code(code) if self.is_buffer_access: - ptrexpr = self.buffer_lookup_code(code) - if self.buffer_type.dtype.is_pyobject: - # Must manage refcounts. Decref what is already there - # and incref what we put in. - ptr = code.funcstate.allocate_temp(self.buffer_type.buffer_ptr_type) - if rhs.is_temp: - rhs_code = code.funcstate.allocate_temp(rhs.type) - else: - rhs_code = rhs.result_code - code.putln("%s = %s;" % (ptr, ptrexpr)) - code.putln("Py_DECREF(*%s); Py_INCREF(%s);" % ( - ptr, rhs_code - )) - code.putln("*%s = %s;" % (ptr, rhs_code)) - if rhs.is_temp: - code.funcstate.release_temp(rhs_code) - code.funcstate.release_temp(ptr) - else: - # Simple case - code.putln("*%s = %s;" % (ptrexpr, rhs.result_code)) + self.generate_buffer_setitem_code(rhs, code) elif self.type.is_pyobject: self.generate_setitem_code(rhs.py_result(), code) else: @@ -3946,6 +3950,7 @@ class CoercionNode(ExprNode): def __init__(self, arg): self.pos = arg.pos self.arg = arg + self.options = arg.options if debug_coercion: print("%s Coercing %s" % (self, self.arg)) diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 246b7e5d..c006d71d 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -71,10 +71,12 @@ class Node(object): # pos (string, int, int) Source file position # is_name boolean Is a NameNode # is_literal boolean Is a ConstNode + # options dict Compiler directives in effect for this node is_name = 0 is_literal = 0 temps = None + options = None # All descandants should set child_attrs to a list of the attributes # containing nodes considered "children" in the tree. Each such attribute @@ -2517,12 +2519,13 @@ class InPlaceAssignmentNode(AssignmentNode): def generate_execution_code(self, code): self.rhs.generate_evaluation_code(code) self.dup.generate_subexpr_evaluation_code(code) - self.dup.generate_result_code(code) + # self.dup.generate_result_code is run only if it is not buffer access if self.operator == "**": extra = ", Py_None" else: extra = "" if self.lhs.type.is_pyobject: + self.dup.generate_result_code(code) code.putln( "%s = %s(%s, %s%s); %s" % ( self.result.result_code, @@ -2545,7 +2548,12 @@ class InPlaceAssignmentNode(AssignmentNode): else: error(self.pos, "No C inplace power operator") # have to do assignment directly to avoid side-effects - code.putln("%s %s= %s;" % (self.lhs.result_code, c_op, self.rhs.result_code) ) + import ExprNodes + if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access: + self.lhs.generate_buffer_setitem_code(self.rhs, code, c_op) + else: + self.dup.generate_result_code(code) + code.putln("%s %s= %s;" % (self.lhs.result_code, c_op, self.rhs.result_code) ) self.rhs.generate_disposal_code(code) if self.dup.is_temp: self.dup.generate_subexpr_disposal_code(code) @@ -2558,12 +2566,14 @@ class InPlaceAssignmentNode(AssignmentNode): target_lhs = ExprNodes.NameNode(self.dup.pos, name = self.dup.name, is_temp = self.dup.is_temp, - entry = self.dup.entry) + entry = self.dup.entry, + options = self.dup.options) elif isinstance(self.lhs, ExprNodes.AttributeNode): target_lhs = ExprNodes.AttributeNode(self.dup.pos, obj = ExprNodes.CloneNode(self.lhs.obj), attribute = self.dup.attribute, - is_temp = self.dup.is_temp) + is_temp = self.dup.is_temp, + options = self.dup.options) elif isinstance(self.lhs, ExprNodes.IndexNode): if self.lhs.index: index = ExprNodes.CloneNode(self.lhs.index) @@ -2577,7 +2587,8 @@ class InPlaceAssignmentNode(AssignmentNode): base = ExprNodes.CloneNode(self.dup.base), index = index, indices = indices, - is_temp = self.dup.is_temp) + is_temp = self.dup.is_temp, + options = self.dup.options) self.lhs = target_lhs return self.dup diff --git a/tests/run/bufaccess.pyx b/tests/run/bufaccess.pyx index a4ad192c..5d7d32e1 100644 --- a/tests/run/bufaccess.pyx +++ b/tests/run/bufaccess.pyx @@ -596,12 +596,23 @@ TODO uc[0] = 3.14 print uc[0] + cdef char* ch = "asfd" + cdef object[object] objbuf + objbuf[3] = ch + # # Testing that accessing data using various types of buffer access # all works. # +def printbuf_int(object[int] buf, shape): + # Utility func + cdef int i + for i in range(shape[0]): + print buf[i], + print 'END' + @testcase def printbuf_int_2d(o, shape): @@ -654,6 +665,24 @@ def printbuf_float(o, shape): print "END" +# +# Test assignments +# +@testcase +def inplace_operators(object[int] buf): + """ + >>> buf = IntMockBuffer(None, [2, 2]) + >>> inplace_operators(buf) + >>> printbuf_int(buf, (2,)) + 0 3 END + """ + cdef int j = 0 + buf[1] += 1 + buf[j] *= 2 + buf[0] -= 4 + + + # # Typedefs #