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