Author: Armin Rigo <[email protected]>
Branch: stmgc-c8
Changeset: r78257:350b6a396e7a
Date: 2015-06-23 12:50 +0200
http://bitbucket.org/pypy/pypy/changeset/350b6a396e7a/

Log:    Support the common primitive types in unsafe_write()

diff --git a/pypy/module/_cffi_backend/ctypeprim.py 
b/pypy/module/_cffi_backend/ctypeprim.py
--- a/pypy/module/_cffi_backend/ctypeprim.py
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -184,12 +184,16 @@
         value = misc.read_raw_signed_data(cdata, self.size)
         return self.space.wrap(value)    # r_longlong => on 32-bit, 'long'
 
+    def _convert_to_long(self, w_ob):
+        value = misc.as_long(self.space, w_ob)
+        if self.value_smaller_than_long:
+            if value != misc.signext(value, self.size):
+                self._overflow(w_ob)
+        return value
+
     def convert_from_object(self, cdata, w_ob):
         if self.value_fits_long:
-            value = misc.as_long(self.space, w_ob)
-            if self.value_smaller_than_long:
-                if value != misc.signext(value, self.size):
-                    self._overflow(w_ob)
+            value = self._convert_to_long(w_ob)
             misc.write_raw_signed_data(cdata, value, self.size)
         else:
             self._convert_from_object_longlong(cdata, w_ob)
@@ -261,12 +265,16 @@
     def cast_to_int(self, cdata):
         return self.convert_to_object(cdata)
 
+    def _convert_to_ulong(self, w_ob):
+        value = misc.as_unsigned_long(self.space, w_ob, strict=True)
+        if self.value_fits_long:
+            if value > self.vrangemax:
+                self._overflow(w_ob)
+        return value
+
     def convert_from_object(self, cdata, w_ob):
         if self.value_fits_ulong:
-            value = misc.as_unsigned_long(self.space, w_ob, strict=True)
-            if self.value_fits_long:
-                if value > self.vrangemax:
-                    self._overflow(w_ob)
+            value = self._convert_to_ulong(w_ob)
             misc.write_raw_unsigned_data(cdata, value, self.size)
         else:
             self._convert_from_object_longlong(cdata, w_ob)
@@ -373,9 +381,12 @@
         value = misc.read_raw_float_data(cdata, self.size)
         return self.space.wrap(value)
 
+    def _convert_to_double(self, w_ob):
+        space = self.space
+        return space.float_w(space.float(w_ob))
+
     def convert_from_object(self, cdata, w_ob):
-        space = self.space
-        value = space.float_w(space.float(w_ob))
+        value = self._convert_to_double(w_ob)
         misc.write_raw_float_data(cdata, value, self.size)
 
     def unpack_list_of_float_items(self, w_cdata):
diff --git a/pypy/module/pypystm/__init__.py b/pypy/module/pypystm/__init__.py
--- a/pypy/module/pypystm/__init__.py
+++ b/pypy/module/pypystm/__init__.py
@@ -30,5 +30,5 @@
         'queue': 'queue.W_Queue',
         'Empty': 'space.fromcache(queue.Cache).w_Empty',
 
-        'unsafe_write_int32': 'unsafe_op.unsafe_write_int32',
+        'unsafe_write': 'unsafe_op.unsafe_write',
     }
diff --git a/pypy/module/pypystm/test/test_unsafe_op.py 
b/pypy/module/pypystm/test/test_unsafe_op.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/pypystm/test/test_unsafe_op.py
@@ -0,0 +1,62 @@
+import pypy.module._cffi_backend.misc    # side-effects
+
+
+class AppTestUnsafeOp:
+    spaceconfig = dict(usemodules=['pypystm', '_cffi_backend'])
+
+    def test_unsafe_write_char(self):
+        import pypystm, _cffi_backend
+        BChar = _cffi_backend.new_primitive_type('char')
+        BCharP = _cffi_backend.new_pointer_type(BChar)
+        x = _cffi_backend.newp(_cffi_backend.new_array_type(BCharP, 2))
+        pypystm.unsafe_write(x, 0, 'A')
+        pypystm.unsafe_write(x, 1, '\xAA')
+        assert x[0] == 'A'
+        assert x[1] == '\xAA'
+
+    def test_unsafe_write_int32(self):
+        import pypystm, _cffi_backend
+        BInt32 = _cffi_backend.new_primitive_type('int32_t')
+        BInt32P = _cffi_backend.new_pointer_type(BInt32)
+        x = _cffi_backend.newp(_cffi_backend.new_array_type(BInt32P, 2))
+        pypystm.unsafe_write(x, 0, -0x01020304)
+        pypystm.unsafe_write(x, 1, -0x05060708)
+        assert x[0] == -0x01020304
+        assert x[1] == -0x05060708
+
+    def test_unsafe_write_uint64(self):
+        import pypystm, _cffi_backend
+        BUInt64 = _cffi_backend.new_primitive_type('uint64_t')
+        BUInt64P = _cffi_backend.new_pointer_type(BUInt64)
+        x = _cffi_backend.newp(_cffi_backend.new_array_type(BUInt64P, 2))
+        pypystm.unsafe_write(x, 0, 0x0102030411223344)
+        pypystm.unsafe_write(x, 1, 0xF506070855667788)
+        assert x[0] == 0x0102030411223344
+        assert x[1] == 0xF506070855667788
+
+    def test_unsafe_write_unsupported_case(self):
+        import pypystm, _cffi_backend
+        BUniChar = _cffi_backend.new_primitive_type('wchar_t')
+        BUniCharP = _cffi_backend.new_pointer_type(BUniChar)
+        x = _cffi_backend.newp(_cffi_backend.new_array_type(BUniCharP, 2))
+        raises(TypeError, pypystm.unsafe_write, x, 0, u'X')
+
+    def test_unsafe_write_float(self):
+        import pypystm, _cffi_backend
+        BFloat = _cffi_backend.new_primitive_type('float')
+        BFloatP = _cffi_backend.new_pointer_type(BFloat)
+        x = _cffi_backend.newp(_cffi_backend.new_array_type(BFloatP, 2))
+        pypystm.unsafe_write(x, 0, 12.25)
+        pypystm.unsafe_write(x, 1, -42.0)
+        assert x[0] == 12.25
+        assert x[1] == -42.0
+
+    def test_unsafe_write_double(self):
+        import pypystm, _cffi_backend
+        BDouble = _cffi_backend.new_primitive_type('double')
+        BDoubleP = _cffi_backend.new_pointer_type(BDouble)
+        x = _cffi_backend.newp(_cffi_backend.new_array_type(BDoubleP, 2))
+        pypystm.unsafe_write(x, 0, 12.25)
+        pypystm.unsafe_write(x, 1, -42.0)
+        assert x[0] == 12.25
+        assert x[1] == -42.0
diff --git a/pypy/module/pypystm/unsafe_op.py b/pypy/module/pypystm/unsafe_op.py
--- a/pypy/module/pypystm/unsafe_op.py
+++ b/pypy/module/pypystm/unsafe_op.py
@@ -1,15 +1,75 @@
 from pypy.interpreter.gateway import unwrap_spec
-from pypy.module._cffi_backend import cdataobj
+from pypy.interpreter.error import oefmt
+from pypy.module._cffi_backend import cdataobj, ctypeptr, ctypeprim, misc
 from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rlib.objectmodel import specialize
 
 
-UNSAFE_INT = lltype.Struct('UNSAFE_INT', ('x', rffi.INT),
[email protected]()
+def get_unsafe_type_ptr(TP):
+    UNSAFE = lltype.Struct('UNSAFE', ('x', TP),
                            hints = {'stm_dont_track_raw_accesses': True})
-UNSAFE_INT_P = lltype.Ptr(UNSAFE_INT)
+    return rffi.CArrayPtr(UNSAFE)
 
 
-@unwrap_spec(w_cdata=cdataobj.W_CData, index=int, value='c_int')
-def unsafe_write_int32(space, w_cdata, index, value):
-    with w_cdata as ptr:
-        ptr = rffi.cast(UNSAFE_INT_P, rffi.ptradd(ptr, index * 4))
-        ptr.x = rffi.cast(rffi.INT, value)
+def unsafe_write_raw_signed_data(w_cdata, index, source, size):
+    with w_cdata as target:
+        for TP, _ in misc._prim_signed_types:
+            if size == rffi.sizeof(TP):
+                TPP = get_unsafe_type_ptr(TP)
+                rffi.cast(TPP, target)[index].x = rffi.cast(TP, source)
+                return
+    raise NotImplementedError("bad integer size")
+
+def unsafe_write_raw_unsigned_data(w_cdata, index, source, size):
+    with w_cdata as target:
+        for TP, _ in misc._prim_unsigned_types:
+            if size == rffi.sizeof(TP):
+                TPP = get_unsafe_type_ptr(TP)
+                rffi.cast(TPP, target)[index].x = rffi.cast(TP, source)
+                return
+    raise NotImplementedError("bad integer size")
+
+def unsafe_write_raw_float_data(w_cdata, index, source, size):
+    with w_cdata as target:
+        for TP, _ in misc._prim_float_types:
+            if size == rffi.sizeof(TP):
+                TPP = get_unsafe_type_ptr(TP)
+                rffi.cast(TPP, target)[index].x = rffi.cast(TP, source)
+                return
+    raise NotImplementedError("bad float size")
+
+
+@unwrap_spec(w_cdata=cdataobj.W_CData, index=int)
+def unsafe_write(space, w_cdata, index, w_value):
+    ctype = w_cdata.ctype
+    if not isinstance(ctype, ctypeptr.W_CTypePtrOrArray):
+        raise oefmt(space.w_TypeError,
+                    "expected a cdata of type pointer or array")
+    ctitem = ctype.ctitem
+
+    if isinstance(ctitem, ctypeprim.W_CTypePrimitiveChar):
+        charvalue = ctitem._convert_to_char(w_value)
+        unsafe_write_raw_signed_data(w_cdata, index, ord(charvalue), size=1)
+        return
+
+    if isinstance(ctitem, ctypeprim.W_CTypePrimitiveSigned):
+        if ctitem.value_fits_long:
+            value = ctitem._convert_to_long(w_value)
+            unsafe_write_raw_signed_data(w_cdata, index, value, ctitem.size)
+            return
+
+    if isinstance(ctitem, ctypeprim.W_CTypePrimitiveUnsigned):
+        if ctitem.value_fits_ulong:
+            value = ctitem._convert_to_ulong(w_value)
+            unsafe_write_raw_unsigned_data(w_cdata, index, value, ctitem.size)
+            return
+
+    if isinstance(ctitem, ctypeprim.W_CTypePrimitiveFloat):
+        if not isinstance(ctitem, ctypeprim.W_CTypePrimitiveLongDouble):
+            value = ctitem._convert_to_double(w_value)
+            unsafe_write_raw_float_data(w_cdata, index, value, ctitem.size)
+            return
+
+    raise oefmt(space.w_TypeError, "unsupported type in unsafe_write(): '%s'",
+                ctitem.name)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to