Buffers: Inplace operators working
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Fri, 15 Aug 2008 18:20:49 +0000 (20:20 +0200)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Fri, 15 Aug 2008 18:20:49 +0000 (20:20 +0200)
This time hopefully without breaking other inplace operators.

Cython/Compiler/ExprNodes.py
Cython/Compiler/Nodes.py
tests/run/bufaccess.pyx

index b7e2b40645410af5a14bbc0db46dea44452e9334..6439a7e815c0a595809fcb94c4d1b1969801cf04 100644 (file)
@@ -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))
             
index 246b7e5dfe000b4998051549c2972acd57a0a7c8..c006d71df29751d44add675524bd7ed677ebd754 100644 (file)
@@ -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
     
index a4ad192cf72ad83e22c3eb42300ba73ed7d8e921..5d7d32e19f95b4d252027a6a679dcd0a7285953c 100644 (file)
@@ -596,12 +596,23 @@ TODO
     uc[0] = <int>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
 #