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