Author: Armin Rigo <ar...@tunes.org>
Branch: int-float-list-strategy
Changeset: r78393:8e7ea72a85bf
Date: 2015-07-01 23:53 +0200
http://bitbucket.org/pypy/pypy/changeset/8e7ea72a85bf/

Log:    Support the (likely) most common mixed cases:

         [int-or-float].extend([int])

         [int-or-float].extend([float])

diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -1671,20 +1671,26 @@
         return self._base_setslice(w_list, start, step, slicelength, w_other)
 
 
+    def int_2_float_or_int(self, w_list):
+        l = self.unerase(w_list.lstorage)
+        if not longlong2float.CAN_ALWAYS_ENCODE_INT32:
+            for intval in l:
+                if not longlong2float.can_encode_int32(intval):
+                    raise ValueError
+        return [longlong2float.encode_int32_into_longlong_nan(intval)
+                for intval in l]
+
     def switch_to_next_strategy(self, w_list, w_sample_item):
         if type(w_sample_item) is W_FloatObject:
-            l = self.unerase(w_list.lstorage)
-            for intval in l:
-                if not longlong2float.can_encode_int32(intval):
-                    break
+            try:
+                generalized_list = self.int_2_float_or_int(w_list)
+            except ValueError:
+                pass
             else:
                 # yes, we can switch to IntOrFloatListStrategy
                 # (ignore here the extremely unlikely case where
                 # w_sample_item is just the wrong nonstandard NaN float;
                 # it will caught later and yet another switch will occur)
-                generalized_list = [
-                    longlong2float.encode_int32_into_longlong_nan(intval)
-                    for intval in l]
                 strategy = self.space.fromcache(IntOrFloatListStrategy)
                 w_list.strategy = strategy
                 w_list.lstorage = strategy.erase(generalized_list)
@@ -1742,19 +1748,26 @@
                     return i
         raise ValueError
 
+    def float_2_float_or_int(self, w_list):
+        l = self.unerase(w_list.lstorage)
+        generalized_list = []
+        for floatval in l:
+            if not longlong2float.can_encode_float(floatval):
+                raise ValueError
+            generalized_list.append(
+                longlong2float.float2longlong(floatval))
+        return generalized_list
+
     def switch_to_next_strategy(self, w_list, w_sample_item):
         if type(w_sample_item) is W_IntObject:
             sample_intval = self.space.int_w(w_sample_item)
             if longlong2float.can_encode_int32(sample_intval):
                 # xxx we should be able to use the same lstorage, but
                 # there is a typing issue (float vs longlong)...
-                l = self.unerase(w_list.lstorage)
-                generalized_list = []
-                for floatval in l:
-                    if not longlong2float.can_encode_float(floatval):
-                        break
-                    generalized_list.append(
-                        longlong2float.float2longlong(floatval))
+                try:
+                    generalized_list = self.float_2_float_or_int(w_list)
+                except ValueError:
+                    pass
                 else:
                     # yes, we can switch to IntOrFloatListStrategy
                     strategy = self.space.fromcache(IntOrFloatListStrategy)
@@ -1814,6 +1827,29 @@
         if reverse:
             l.reverse()
 
+    _base_extend_from_list = _extend_from_list
+
+    def _extend_longlong(self, w_list, longlong_list):
+        l = self.unerase(w_list.lstorage)
+        l += longlong_list
+
+    def _extend_from_list(self, w_list, w_other):
+        if w_other.strategy is self.space.fromcache(IntegerListStrategy):
+            try:
+                longlong_list = w_other.strategy.int_2_float_or_int(w_other)
+            except ValueError:
+                pass
+            else:
+                return self._extend_longlong(w_list, longlong_list)
+        if w_other.strategy is self.space.fromcache(FloatListStrategy):
+            try:
+                longlong_list = w_other.strategy.float_2_float_or_int(w_other)
+            except ValueError:
+                pass
+            else:
+                return self._extend_longlong(w_list, longlong_list)
+        return self._base_extend_from_list(w_list, w_other)
+
 
 class BytesListStrategy(ListStrategy):
     import_from_mixin(AbstractUnwrappedStrategy)
diff --git a/pypy/objspace/std/test/test_liststrategies.py 
b/pypy/objspace/std/test/test_liststrategies.py
--- a/pypy/objspace/std/test/test_liststrategies.py
+++ b/pypy/objspace/std/test/test_liststrategies.py
@@ -866,7 +866,28 @@
         assert isinstance(w_l1.strategy, IntOrFloatListStrategy)
         assert space.unwrap(w_l1) == [0, 1.2, 3, 4.5]
 
-    def test_int_or_float_extend_mixed(self):
+    def test_int_or_float_extend_mixed_1(self):
+        space = self.space
+        w_l1 = W_ListObject(space, [space.wrap(0), space.wrap(1.2)])
+        w_l2 = W_ListObject(space, [space.wrap(3)])
+        assert isinstance(w_l1.strategy, IntOrFloatListStrategy)
+        assert isinstance(w_l2.strategy, IntegerListStrategy)
+        w_l1.extend(w_l2)
+        assert isinstance(w_l1.strategy, IntOrFloatListStrategy)
+        assert [(type(x), x) for x in space.unwrap(w_l1)] == [
+            (int, 0), (float, 1.2), (int, 3)]
+
+    def test_int_or_float_extend_mixed_2(self):
+        space = self.space
+        w_l1 = W_ListObject(space, [space.wrap(0), space.wrap(1.2)])
+        w_l2 = W_ListObject(space, [space.wrap(3.4)])
+        assert isinstance(w_l1.strategy, IntOrFloatListStrategy)
+        assert isinstance(w_l2.strategy, FloatListStrategy)
+        w_l1.extend(w_l2)
+        assert isinstance(w_l1.strategy, IntOrFloatListStrategy)
+        assert space.unwrap(w_l1) == [0, 1.2, 3.4]
+
+    def test_int_or_float_extend_mixed_3(self):
         py.test.skip("XXX not implemented")
         # lst = [0]; lst += [1.2]
         # lst = [0]; lst += [1.2, 3]
diff --git a/rpython/rlib/longlong2float.py b/rpython/rlib/longlong2float.py
--- a/rpython/rlib/longlong2float.py
+++ b/rpython/rlib/longlong2float.py
@@ -119,8 +119,10 @@
 def is_int32_from_longlong_nan(value):
     return (value >> 32) == nan_high_word_int32
 
+CAN_ALWAYS_ENCODE_INT32 = (sys.maxint == 2147483647)
+
 def can_encode_int32(value):
-    if sys.maxint == 2147483647:
+    if CAN_ALWAYS_ENCODE_INT32:
         return True
     return value == rffi.cast(lltype.Signed, rffi.cast(rffi.INT, value))
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to