Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r67550:beb446933cde
Date: 2013-10-24 09:54 +0200
http://bitbucket.org/pypy/pypy/changeset/beb446933cde/

Log:    Fast packing for arrays of other integer types than 'long'.

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
@@ -2,6 +2,7 @@
 Primitives.
 """
 
+import sys
 from pypy.interpreter.error import operationerrfmt
 
 from rpython.rlib.rarithmetic import r_uint, r_ulonglong, intmask
@@ -212,14 +213,25 @@
         return None
 
     def pack_list_of_items(self, cdata, w_ob):
-        if self.size == rffi.sizeof(rffi.LONG): # XXX
-            int_list = self.space.listview_int(w_ob)
-            if int_list is not None:
+        int_list = self.space.listview_int(w_ob)
+        if int_list is not None:
+            if self.size == rffi.sizeof(rffi.LONG): # fastest path
                 from rpython.rlib.rarray import copy_list_to_raw_array
                 cdata = rffi.cast(rffi.LONGP, cdata)
                 copy_list_to_raw_array(int_list, cdata)
-                return True
-        return False
+            else:
+                if self.value_fits_long:
+                    vmin = self.vmin
+                    vrangemax = self.vrangemax
+                else:
+                    vmin = r_uint(0)
+                    vrangemax = r_uint(-1)
+                overflowed = misc.pack_list_to_raw_array_bounds(
+                    int_list, cdata, self.size, vmin, vrangemax)
+                if overflowed != 0:
+                    self._overflow(self.space.wrap(overflowed))
+            return True
+        return W_CTypePrimitive.pack_list_of_items(self, cdata, w_ob)
 
 
 class W_CTypePrimitiveUnsigned(W_CTypePrimitive):
@@ -272,6 +284,20 @@
     def write_raw_integer_data(self, w_cdata, value):
         w_cdata.write_raw_unsigned_data(value)
 
+    def pack_list_of_items(self, cdata, w_ob):
+        int_list = self.space.listview_int(w_ob)
+        if int_list is not None:
+            if self.value_fits_long:
+                vrangemax = self.vrangemax
+            else:
+                vrangemax = r_uint(sys.maxint)
+            overflowed = misc.pack_list_to_raw_array_bounds(
+                int_list, cdata, self.size, r_uint(0), vrangemax)
+            if overflowed != 0:
+                self._overflow(self.space.wrap(overflowed))
+            return True
+        return W_CTypePrimitive.pack_list_of_items(self, cdata, w_ob)
+
 
 class W_CTypePrimitiveBool(W_CTypePrimitiveUnsigned):
     _attrs_ = []
@@ -350,7 +376,7 @@
                 cdata = rffi.cast(rffi.DOUBLEP, cdata)
                 copy_list_to_raw_array(float_list, cdata)
                 return True
-        return False
+        return W_CTypePrimitive.pack_list_of_items(self, cdata, w_ob)
 
 
 class W_CTypePrimitiveLongDouble(W_CTypePrimitiveFloat):
diff --git a/pypy/module/_cffi_backend/misc.py 
b/pypy/module/_cffi_backend/misc.py
--- a/pypy/module/_cffi_backend/misc.py
+++ b/pypy/module/_cffi_backend/misc.py
@@ -315,3 +315,17 @@
             _raw_memclear_tp(TP, TPP, dest)
             return
     raise NotImplementedError("bad clear size")
+
+# ____________________________________________________________
+
+def pack_list_to_raw_array_bounds(int_list, target, size, vmin, vrangemax):
+    for TP, TPP in _prim_signed_types:
+        if size == rffi.sizeof(TP):
+            ptr = rffi.cast(TPP, target)
+            for i in range(len(int_list)):
+                x = int_list[i]
+                if r_uint(x) - vmin > vrangemax:
+                    return x      # overflow
+                ptr[i] = rffi.cast(TP, x)
+            return 0
+    raise NotImplementedError("bad integer size")
diff --git a/pypy/module/_cffi_backend/test/test_fastpath.py 
b/pypy/module/_cffi_backend/test/test_fastpath.py
--- a/pypy/module/_cffi_backend/test/test_fastpath.py
+++ b/pypy/module/_cffi_backend/test/test_fastpath.py
@@ -1,5 +1,6 @@
 # side-effect: FORMAT_LONGDOUBLE must be built before the first test
 from pypy.module._cffi_backend import misc
+from pypy.module._cffi_backend.ctypeobj import W_CType
 
 
 class AppTest_fast_path_from_list(object):
@@ -8,11 +9,11 @@
     def setup_method(self, meth):
         def forbidden(*args):
             assert False, 'The slow path is forbidden'
-        self._original = self.space.listview
-        self.space.listview = forbidden
+        self._original = W_CType.pack_list_of_items.im_func
+        W_CType.pack_list_of_items = forbidden
 
     def teardown_method(self, meth):
-        self.space.listview = self._original
+        W_CType.pack_list_of_items = self._original
 
     def test_fast_init_from_list(self):
         import _cffi_backend
@@ -34,6 +35,58 @@
         assert buf[1] == 2.2
         assert buf[2] == 3.3
 
+    def test_fast_init_short_from_list(self):
+        import _cffi_backend
+        SHORT = _cffi_backend.new_primitive_type('short')
+        P_SHORT = _cffi_backend.new_pointer_type(SHORT)
+        SHORT_ARRAY = _cffi_backend.new_array_type(P_SHORT, None)
+        buf = _cffi_backend.newp(SHORT_ARRAY, [1, -2, 3])
+        assert buf[0] == 1
+        assert buf[1] == -2
+        assert buf[2] == 3
+        raises(OverflowError, _cffi_backend.newp, SHORT_ARRAY, [40000])
+        raises(OverflowError, _cffi_backend.newp, SHORT_ARRAY, [-40000])
+
+    def test_fast_init_longlong_from_list(self):
+        if type(2 ** 50) is long:
+            large_int = 2 ** 30
+        else:
+            large_int = 2 ** 50
+        import _cffi_backend
+        LONGLONG = _cffi_backend.new_primitive_type('long long')
+        P_LONGLONG = _cffi_backend.new_pointer_type(LONGLONG)
+        LONGLONG_ARRAY = _cffi_backend.new_array_type(P_LONGLONG, None)
+        buf = _cffi_backend.newp(LONGLONG_ARRAY, [1, -2, 3, large_int])
+        assert buf[0] == 1
+        assert buf[1] == -2
+        assert buf[2] == 3
+        assert buf[3] == large_int
+
+    def test_fast_init_ushort_from_list(self):
+        import _cffi_backend
+        USHORT = _cffi_backend.new_primitive_type('unsigned short')
+        P_USHORT = _cffi_backend.new_pointer_type(USHORT)
+        USHORT_ARRAY = _cffi_backend.new_array_type(P_USHORT, None)
+        buf = _cffi_backend.newp(USHORT_ARRAY, [1, 2, 40000])
+        assert buf[0] == 1
+        assert buf[1] == 2
+        assert buf[2] == 40000
+        raises(OverflowError, _cffi_backend.newp, USHORT_ARRAY, [70000])
+        raises(OverflowError, _cffi_backend.newp, USHORT_ARRAY, [-1])
+
+    def test_fast_init_ulong_from_list(self):
+        import sys
+        import _cffi_backend
+        ULONG = _cffi_backend.new_primitive_type('unsigned long')
+        P_ULONG = _cffi_backend.new_pointer_type(ULONG)
+        ULONG_ARRAY = _cffi_backend.new_array_type(P_ULONG, None)
+        buf = _cffi_backend.newp(ULONG_ARRAY, [1, 2, sys.maxint])
+        assert buf[0] == 1
+        assert buf[1] == 2
+        assert buf[2] == sys.maxint
+        raises(OverflowError, _cffi_backend.newp, ULONG_ARRAY, [-1])
+        raises(OverflowError, _cffi_backend.newp, ULONG_ARRAY, [-sys.maxint])
+
 
 class AppTest_fast_path_bug(object):
     spaceconfig = dict(usemodules=('_cffi_backend', 'cStringIO'))
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to