PageRenderTime 48ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/objspace/std/specialisedtupleobject.py

https://bitbucket.org/pypy/pypy/
Python | 211 lines | 190 code | 16 blank | 5 comment | 32 complexity | 34b5e3ce54d33b860e619090da49988b MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from pypy.interpreter.error import oefmt
  2. from pypy.objspace.std.tupleobject import W_AbstractTupleObject
  3. from pypy.objspace.std.util import negate
  4. from rpython.rlib.objectmodel import compute_hash, specialize
  5. from rpython.rlib.rarithmetic import intmask
  6. from rpython.rlib.unroll import unrolling_iterable
  7. from rpython.tool.sourcetools import func_with_new_name
  8. from rpython.rlib.longlong2float import float2longlong
  9. class NotSpecialised(Exception):
  10. pass
  11. def make_specialised_class(typetuple):
  12. assert type(typetuple) == tuple
  13. typelen = len(typetuple)
  14. iter_n = unrolling_iterable(range(typelen))
  15. class cls(W_AbstractTupleObject):
  16. _immutable_fields_ = ['value%s' % i for i in iter_n]
  17. def __init__(self, space, *values_w):
  18. self.space = space
  19. assert len(values_w) == typelen
  20. for i in iter_n:
  21. w_obj = values_w[i]
  22. val_type = typetuple[i]
  23. if val_type == int:
  24. unwrapped = w_obj.int_w(space)
  25. elif val_type == float:
  26. unwrapped = w_obj.float_w(space)
  27. elif val_type == str:
  28. unwrapped = w_obj.str_w(space)
  29. elif val_type == object:
  30. unwrapped = w_obj
  31. else:
  32. raise AssertionError
  33. setattr(self, 'value%s' % i, unwrapped)
  34. def length(self):
  35. return typelen
  36. def tolist(self):
  37. list_w = [None] * typelen
  38. for i in iter_n:
  39. value = getattr(self, 'value%s' % i)
  40. if typetuple[i] != object:
  41. value = self.space.wrap(value)
  42. list_w[i] = value
  43. return list_w
  44. # same source code, but builds and returns a resizable list
  45. getitems_copy = func_with_new_name(tolist, 'getitems_copy')
  46. def descr_hash(self, space):
  47. mult = 1000003
  48. x = 0x345678
  49. z = typelen
  50. for i in iter_n:
  51. value = getattr(self, 'value%s' % i)
  52. if typetuple[i] == object:
  53. y = space.int_w(space.hash(value))
  54. elif typetuple[i] == int:
  55. # mimic cpythons behavior of a hash value of -2 for -1
  56. y = value
  57. if y == -1:
  58. y = -2
  59. elif typetuple[i] == float:
  60. # get the correct hash for float which is an
  61. # integer & other less frequent cases
  62. from pypy.objspace.std.floatobject import _hash_float
  63. y = _hash_float(space, value)
  64. else:
  65. y = compute_hash(value)
  66. x = (x ^ y) * mult
  67. z -= 1
  68. mult += 82520 + z + z
  69. x += 97531
  70. return space.wrap(intmask(x))
  71. def descr_eq(self, space, w_other):
  72. if not isinstance(w_other, W_AbstractTupleObject):
  73. return space.w_NotImplemented
  74. if not isinstance(w_other, cls):
  75. if typelen != w_other.length():
  76. return space.w_False
  77. for i in iter_n:
  78. myval = getattr(self, 'value%s' % i)
  79. otherval = w_other.getitem(space, i)
  80. if typetuple[i] != object:
  81. myval = space.wrap(myval)
  82. if not space.eq_w(myval, otherval):
  83. return space.w_False
  84. return space.w_True
  85. for i in iter_n:
  86. myval = getattr(self, 'value%s' % i)
  87. otherval = getattr(w_other, 'value%s' % i)
  88. if typetuple[i] == object:
  89. if not self.space.eq_w(myval, otherval):
  90. return space.w_False
  91. else:
  92. if myval != otherval:
  93. if typetuple[i] == float:
  94. # issue with NaNs, which should be equal here
  95. if (float2longlong(myval) ==
  96. float2longlong(otherval)):
  97. continue
  98. return space.w_False
  99. return space.w_True
  100. descr_ne = negate(descr_eq)
  101. def getitem(self, space, index):
  102. if index < 0:
  103. index += typelen
  104. for i in iter_n:
  105. if index == i:
  106. value = getattr(self, 'value%s' % i)
  107. if typetuple[i] != object:
  108. value = space.wrap(value)
  109. return value
  110. raise oefmt(space.w_IndexError, "tuple index out of range")
  111. cls.__name__ = ('W_SpecialisedTupleObject_' +
  112. ''.join([t.__name__[0] for t in typetuple]))
  113. _specialisations.append(cls)
  114. return cls
  115. # ---------- current specialized versions ----------
  116. _specialisations = []
  117. Cls_ii = make_specialised_class((int, int))
  118. Cls_oo = make_specialised_class((object, object))
  119. Cls_ff = make_specialised_class((float, float))
  120. def makespecialisedtuple(space, list_w):
  121. from pypy.objspace.std.intobject import W_IntObject
  122. from pypy.objspace.std.floatobject import W_FloatObject
  123. if len(list_w) == 2:
  124. w_arg1, w_arg2 = list_w
  125. if type(w_arg1) is W_IntObject:
  126. if type(w_arg2) is W_IntObject:
  127. return Cls_ii(space, w_arg1, w_arg2)
  128. elif type(w_arg1) is W_FloatObject:
  129. if type(w_arg2) is W_FloatObject:
  130. return Cls_ff(space, w_arg1, w_arg2)
  131. return Cls_oo(space, w_arg1, w_arg2)
  132. else:
  133. raise NotSpecialised
  134. # --------------------------------------------------
  135. # Special code based on list strategies to implement zip(),
  136. # here with two list arguments only. This builds a zipped
  137. # list that differs from what the app-level code would build:
  138. # if the source lists contain sometimes ints/floats and
  139. # sometimes not, here we will use uniformly 'Cls_oo' instead
  140. # of using 'Cls_ii' or 'Cls_ff' for the elements that match.
  141. # This is a trade-off, but it looks like a good idea to keep
  142. # the list uniform for the JIT---not to mention, it is much
  143. # faster to move the decision out of the loop.
  144. @specialize.arg(1)
  145. def _build_zipped_spec(space, Cls, lst1, lst2):
  146. length = min(len(lst1), len(lst2))
  147. return [Cls(space, space.wrap(lst1[i]),
  148. space.wrap(lst2[i])) for i in range(length)]
  149. def _build_zipped_spec_oo(space, w_list1, w_list2):
  150. strat1 = w_list1.strategy
  151. strat2 = w_list2.strategy
  152. length = min(strat1.length(w_list1), strat2.length(w_list2))
  153. return [Cls_oo(space, strat1.getitem(w_list1, i),
  154. strat2.getitem(w_list2, i)) for i in range(length)]
  155. def _build_zipped_unspec(space, w_list1, w_list2):
  156. strat1 = w_list1.strategy
  157. strat2 = w_list2.strategy
  158. length = min(strat1.length(w_list1), strat2.length(w_list2))
  159. return [space.newtuple([strat1.getitem(w_list1, i),
  160. strat2.getitem(w_list2, i)]) for i in range(length)]
  161. def specialized_zip_2_lists(space, w_list1, w_list2):
  162. from pypy.objspace.std.listobject import W_ListObject
  163. if type(w_list1) is not W_ListObject or type(w_list2) is not W_ListObject:
  164. raise oefmt(space.w_TypeError, "expected two exact lists")
  165. if space.config.objspace.std.withspecialisedtuple:
  166. intlist1 = w_list1.getitems_int()
  167. if intlist1 is not None:
  168. intlist2 = w_list2.getitems_int()
  169. if intlist2 is not None:
  170. lst_w = _build_zipped_spec(space, Cls_ii, intlist1, intlist2)
  171. return space.newlist(lst_w)
  172. else:
  173. floatlist1 = w_list1.getitems_float()
  174. if floatlist1 is not None:
  175. floatlist2 = w_list2.getitems_float()
  176. if floatlist2 is not None:
  177. lst_w = _build_zipped_spec(space, Cls_ff, floatlist1,
  178. floatlist2)
  179. return space.newlist(lst_w)
  180. lst_w = _build_zipped_spec_oo(space, w_list1, w_list2)
  181. return space.newlist(lst_w)
  182. else:
  183. lst_w = _build_zipped_unspec(space, w_list1, w_list2)
  184. return space.newlist(lst_w)