PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/objspace/std/tupleobject.py

https://bitbucket.org/pypy/pypy/
Python | 355 lines | 299 code | 44 blank | 12 comment | 34 complexity | fe4c73a3ed5a37c318e71ad86de85b0e MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """The builtin tuple implementation"""
  2. import sys
  3. from pypy.interpreter.baseobjspace import W_Root
  4. from pypy.interpreter.error import OperationError, oefmt
  5. from pypy.interpreter.gateway import (
  6. WrappedDefault, interp2app, interpindirect2app, unwrap_spec)
  7. from pypy.interpreter.typedef import TypeDef
  8. from pypy.objspace.std.sliceobject import (W_SliceObject, unwrap_start_stop,
  9. normalize_simple_slice)
  10. from pypy.objspace.std.util import negate, IDTAG_SPECIAL, IDTAG_SHIFT
  11. from rpython.rlib import jit
  12. from rpython.rlib.debug import make_sure_not_resized
  13. from rpython.rlib.rarithmetic import intmask
  14. UNROLL_CUTOFF = 10
  15. def _unroll_condition(self):
  16. return jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF)
  17. def _unroll_condition_cmp(self, space, other):
  18. return (jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) or
  19. jit.loop_unrolling_heuristic(other, other.length(), UNROLL_CUTOFF))
  20. contains_jmp = jit.JitDriver(greens = ['tp'], reds = 'auto',
  21. name = 'tuple.contains')
  22. hash_driver = jit.JitDriver(
  23. name='tuple.hash',
  24. greens=['w_type'],
  25. reds='auto')
  26. class W_AbstractTupleObject(W_Root):
  27. __slots__ = ()
  28. def is_w(self, space, w_other):
  29. if not isinstance(w_other, W_AbstractTupleObject):
  30. return False
  31. if self is w_other:
  32. return True
  33. if self.user_overridden_class or w_other.user_overridden_class:
  34. return False
  35. # empty tuples are unique-ified
  36. return 0 == w_other.length() == self.length()
  37. def immutable_unique_id(self, space):
  38. if self.user_overridden_class or self.length() > 0:
  39. return None
  40. # empty tuple: base value 258
  41. uid = (258 << IDTAG_SHIFT) | IDTAG_SPECIAL
  42. return space.wrap(uid)
  43. def __repr__(self):
  44. """representation for debugging purposes"""
  45. reprlist = [repr(w_item) for w_item in self.tolist()]
  46. return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist))
  47. def unwrap(self, space):
  48. items = [space.unwrap(w_item) for w_item in self.tolist()]
  49. return tuple(items)
  50. def tolist(self):
  51. """Returns the items, as a fixed-size list."""
  52. raise NotImplementedError
  53. def getitems_copy(self):
  54. """Returns a copy of the items, as a resizable list."""
  55. raise NotImplementedError
  56. def length(self):
  57. raise NotImplementedError
  58. def getitem(self, space, item):
  59. raise NotImplementedError
  60. def descr_len(self, space):
  61. result = self.length()
  62. return space.newint(result)
  63. def descr_iter(self, space):
  64. from pypy.objspace.std import iterobject
  65. return iterobject.W_FastTupleIterObject(self, self.tolist())
  66. @staticmethod
  67. def descr_new(space, w_tupletype, w_sequence=None):
  68. if w_sequence is None:
  69. tuple_w = []
  70. elif (space.is_w(w_tupletype, space.w_tuple) and
  71. space.is_w(space.type(w_sequence), space.w_tuple)):
  72. return w_sequence
  73. else:
  74. tuple_w = space.fixedview(w_sequence)
  75. w_obj = space.allocate_instance(W_TupleObject, w_tupletype)
  76. W_TupleObject.__init__(w_obj, tuple_w)
  77. return w_obj
  78. def descr_repr(self, space):
  79. items = self.tolist()
  80. if len(items) == 1:
  81. return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)")
  82. tmp = ", ".join([space.str_w(space.repr(item)) for item in items])
  83. return space.wrap("(" + tmp + ")")
  84. def descr_hash(self, space):
  85. raise NotImplementedError
  86. def descr_eq(self, space, w_other):
  87. raise NotImplementedError
  88. def descr_ne(self, space, w_other):
  89. raise NotImplementedError
  90. def _make_tuple_comparison(name):
  91. import operator
  92. op = getattr(operator, name)
  93. def compare_tuples(self, space, w_other):
  94. if not isinstance(w_other, W_AbstractTupleObject):
  95. return space.w_NotImplemented
  96. return _compare_tuples(self, space, w_other)
  97. @jit.look_inside_iff(_unroll_condition_cmp)
  98. def _compare_tuples(self, space, w_other):
  99. items1 = self.tolist()
  100. items2 = w_other.tolist()
  101. ncmp = min(len(items1), len(items2))
  102. # Search for the first index where items are different
  103. for p in range(ncmp):
  104. if not space.eq_w(items1[p], items2[p]):
  105. return getattr(space, name)(items1[p], items2[p])
  106. # No more items to compare -- compare sizes
  107. return space.newbool(op(len(items1), len(items2)))
  108. compare_tuples.__name__ = 'descr_' + name
  109. return compare_tuples
  110. descr_lt = _make_tuple_comparison('lt')
  111. descr_le = _make_tuple_comparison('le')
  112. descr_gt = _make_tuple_comparison('gt')
  113. descr_ge = _make_tuple_comparison('ge')
  114. def descr_contains(self, space, w_obj):
  115. if _unroll_condition(self):
  116. return self._descr_contains_unroll_safe(space, w_obj)
  117. else:
  118. return self._descr_contains_jmp(space, w_obj)
  119. @jit.unroll_safe
  120. def _descr_contains_unroll_safe(self, space, w_obj):
  121. for w_item in self.tolist():
  122. if space.eq_w(w_obj, w_item):
  123. return space.w_True
  124. return space.w_False
  125. def _descr_contains_jmp(self, space, w_obj):
  126. tp = space.type(w_obj)
  127. for w_item in self.tolist():
  128. contains_jmp.jit_merge_point(tp=tp)
  129. if space.eq_w(w_obj, w_item):
  130. return space.w_True
  131. return space.w_False
  132. def descr_add(self, space, w_other):
  133. if not isinstance(w_other, W_AbstractTupleObject):
  134. return space.w_NotImplemented
  135. items1 = self.tolist()
  136. items2 = w_other.tolist()
  137. return space.newtuple(items1 + items2)
  138. def descr_mul(self, space, w_times):
  139. try:
  140. times = space.getindex_w(w_times, space.w_OverflowError)
  141. except OperationError as e:
  142. if e.match(space, space.w_TypeError):
  143. return space.w_NotImplemented
  144. raise
  145. if times == 1 and space.type(self) == space.w_tuple:
  146. return self
  147. items = self.tolist()
  148. return space.newtuple(items * times)
  149. def descr_getitem(self, space, w_index):
  150. if isinstance(w_index, W_SliceObject):
  151. return self._getslice(space, w_index)
  152. index = space.getindex_w(w_index, space.w_IndexError, "tuple index")
  153. return self.getitem(space, index)
  154. def _getslice(self, space, w_index):
  155. items = self.tolist()
  156. length = len(items)
  157. start, stop, step, slicelength = w_index.indices4(space, length)
  158. assert slicelength >= 0
  159. subitems = [None] * slicelength
  160. for i in range(slicelength):
  161. subitems[i] = items[start]
  162. start += step
  163. return space.newtuple(subitems)
  164. def descr_getslice(self, space, w_start, w_stop):
  165. length = self.length()
  166. start, stop = normalize_simple_slice(space, length, w_start, w_stop)
  167. return space.newtuple(self.tolist()[start:stop])
  168. def descr_getnewargs(self, space):
  169. return space.newtuple([space.newtuple(self.tolist())])
  170. @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self))
  171. def descr_count(self, space, w_obj):
  172. """count(obj) -> number of times obj appears in the tuple"""
  173. count = 0
  174. for w_item in self.tolist():
  175. if space.eq_w(w_item, w_obj):
  176. count += 1
  177. return space.wrap(count)
  178. @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(sys.maxint))
  179. @jit.look_inside_iff(lambda self, _1, _2, _3, _4: _unroll_condition(self))
  180. def descr_index(self, space, w_obj, w_start, w_stop):
  181. """index(obj, [start, [stop]]) -> first index that obj appears in the
  182. tuple
  183. """
  184. length = self.length()
  185. start, stop = unwrap_start_stop(space, length, w_start, w_stop)
  186. for i in range(start, min(stop, length)):
  187. w_item = self.tolist()[i]
  188. if space.eq_w(w_item, w_obj):
  189. return space.wrap(i)
  190. raise oefmt(space.w_ValueError, "tuple.index(x): x not in tuple")
  191. W_AbstractTupleObject.typedef = TypeDef(
  192. "tuple",
  193. __doc__ = """tuple() -> an empty tuple
  194. tuple(sequence) -> tuple initialized from sequence's items
  195. If the argument is a tuple, the return value is the same object.""",
  196. __new__ = interp2app(W_AbstractTupleObject.descr_new),
  197. __repr__ = interp2app(W_AbstractTupleObject.descr_repr),
  198. __hash__ = interpindirect2app(W_AbstractTupleObject.descr_hash),
  199. __eq__ = interpindirect2app(W_AbstractTupleObject.descr_eq),
  200. __ne__ = interpindirect2app(W_AbstractTupleObject.descr_ne),
  201. __lt__ = interp2app(W_AbstractTupleObject.descr_lt),
  202. __le__ = interp2app(W_AbstractTupleObject.descr_le),
  203. __gt__ = interp2app(W_AbstractTupleObject.descr_gt),
  204. __ge__ = interp2app(W_AbstractTupleObject.descr_ge),
  205. __len__ = interp2app(W_AbstractTupleObject.descr_len),
  206. __iter__ = interp2app(W_AbstractTupleObject.descr_iter),
  207. __contains__ = interp2app(W_AbstractTupleObject.descr_contains),
  208. __add__ = interp2app(W_AbstractTupleObject.descr_add),
  209. __mul__ = interp2app(W_AbstractTupleObject.descr_mul),
  210. __rmul__ = interp2app(W_AbstractTupleObject.descr_mul),
  211. __getitem__ = interp2app(W_AbstractTupleObject.descr_getitem),
  212. __getslice__ = interp2app(W_AbstractTupleObject.descr_getslice),
  213. __getnewargs__ = interp2app(W_AbstractTupleObject.descr_getnewargs),
  214. count = interp2app(W_AbstractTupleObject.descr_count),
  215. index = interp2app(W_AbstractTupleObject.descr_index)
  216. )
  217. W_AbstractTupleObject.typedef.flag_sequence_bug_compat = True
  218. class W_TupleObject(W_AbstractTupleObject):
  219. _immutable_fields_ = ['wrappeditems[*]']
  220. def __init__(self, wrappeditems):
  221. make_sure_not_resized(wrappeditems)
  222. self.wrappeditems = wrappeditems
  223. def tolist(self):
  224. return self.wrappeditems
  225. def getitems_copy(self):
  226. return self.wrappeditems[:] # returns a resizable list
  227. def length(self):
  228. return len(self.wrappeditems)
  229. def descr_hash(self, space):
  230. if _unroll_condition(self):
  231. return self._descr_hash_unroll(space)
  232. else:
  233. return self._descr_hash_jitdriver(space)
  234. @jit.unroll_safe
  235. def _descr_hash_unroll(self, space):
  236. mult = 1000003
  237. x = 0x345678
  238. z = len(self.wrappeditems)
  239. for w_item in self.wrappeditems:
  240. y = space.hash_w(w_item)
  241. x = (x ^ y) * mult
  242. z -= 1
  243. mult += 82520 + z + z
  244. x += 97531
  245. return space.wrap(intmask(x))
  246. def _descr_hash_jitdriver(self, space):
  247. mult = 1000003
  248. x = 0x345678
  249. z = len(self.wrappeditems)
  250. w_type = space.type(self.wrappeditems[0])
  251. for w_item in self.wrappeditems:
  252. hash_driver.jit_merge_point(w_type=w_type)
  253. y = space.hash_w(w_item)
  254. x = (x ^ y) * mult
  255. z -= 1
  256. mult += 82520 + z + z
  257. x += 97531
  258. return space.wrap(intmask(x))
  259. def descr_eq(self, space, w_other):
  260. if not isinstance(w_other, W_AbstractTupleObject):
  261. return space.w_NotImplemented
  262. return self._descr_eq(space, w_other)
  263. @jit.look_inside_iff(_unroll_condition_cmp)
  264. def _descr_eq(self, space, w_other):
  265. items1 = self.wrappeditems
  266. items2 = w_other.tolist()
  267. lgt1 = len(items1)
  268. lgt2 = len(items2)
  269. if lgt1 != lgt2:
  270. return space.w_False
  271. for i in range(lgt1):
  272. item1 = items1[i]
  273. item2 = items2[i]
  274. if not space.eq_w(item1, item2):
  275. return space.w_False
  276. return space.w_True
  277. descr_ne = negate(descr_eq)
  278. def getitem(self, space, index):
  279. try:
  280. return self.wrappeditems[index]
  281. except IndexError:
  282. raise oefmt(space.w_IndexError, "tuple index out of range")
  283. def wraptuple(space, list_w):
  284. if space.config.objspace.std.withspecialisedtuple:
  285. from specialisedtupleobject import makespecialisedtuple, NotSpecialised
  286. try:
  287. return makespecialisedtuple(space, list_w)
  288. except NotSpecialised:
  289. pass
  290. return W_TupleObject(list_w)