PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/rpython/rrange.py

https://bitbucket.org/pypy/pypy/
Python | 215 lines | 171 code | 27 blank | 17 comment | 45 complexity | 49822bc41635945b62906af21ffad6bd MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from pypy.tool.pairtype import pairtype
  2. from pypy.rpython.error import TyperError
  3. from pypy.rpython.lltypesystem.lltype import Signed, Void, Ptr
  4. from pypy.rpython.rmodel import Repr, IntegerRepr, IteratorRepr
  5. from pypy.objspace.flow.model import Constant
  6. from pypy.rpython.rlist import dum_nocheck, dum_checkidx
  7. class AbstractRangeRepr(Repr):
  8. def __init__(self, step):
  9. self.step = step
  10. if step != 0:
  11. self.lowleveltype = self.RANGE
  12. else:
  13. self.lowleveltype = self.RANGEST
  14. def _getstep(self, v_rng, hop):
  15. return hop.genop(self.getfield_opname,
  16. [v_rng, hop.inputconst(Void, 'step')], resulttype=Signed)
  17. def rtype_len(self, hop):
  18. v_rng, = hop.inputargs(self)
  19. if self.step == 1:
  20. return hop.gendirectcall(ll_rangelen1, v_rng)
  21. elif self.step != 0:
  22. v_step = hop.inputconst(Signed, self.step)
  23. else:
  24. v_step = self._getstep(v_rng, hop)
  25. return hop.gendirectcall(ll_rangelen, v_rng, v_step)
  26. class __extend__(pairtype(AbstractRangeRepr, IntegerRepr)):
  27. def rtype_getitem((r_rng, r_int), hop):
  28. if hop.has_implicit_exception(IndexError):
  29. spec = dum_checkidx
  30. else:
  31. spec = dum_nocheck
  32. v_func = hop.inputconst(Void, spec)
  33. v_lst, v_index = hop.inputargs(r_rng, Signed)
  34. if r_rng.step != 0:
  35. cstep = hop.inputconst(Signed, r_rng.step)
  36. else:
  37. cstep = r_rng._getstep(v_lst, hop)
  38. if hop.args_s[1].nonneg:
  39. llfn = ll_rangeitem_nonneg
  40. else:
  41. llfn = ll_rangeitem
  42. hop.exception_is_here()
  43. return hop.gendirectcall(llfn, v_func, v_lst, v_index, cstep)
  44. # ____________________________________________________________
  45. #
  46. # Low-level methods.
  47. def _ll_rangelen(start, stop, step):
  48. if step > 0:
  49. result = (stop - start + (step-1)) // step
  50. else:
  51. result = (start - stop - (step+1)) // (-step)
  52. if result < 0:
  53. result = 0
  54. return result
  55. def ll_rangelen(l, step):
  56. return _ll_rangelen(l.start, l.stop, step)
  57. def ll_rangelen1(l):
  58. result = l.stop - l.start
  59. if result < 0:
  60. result = 0
  61. return result
  62. def ll_rangeitem_nonneg(func, l, index, step):
  63. if func is dum_checkidx and index >= _ll_rangelen(l.start, l.stop, step):
  64. raise IndexError
  65. return l.start + index * step
  66. def ll_rangeitem(func, l, index, step):
  67. if func is dum_checkidx:
  68. length = _ll_rangelen(l.start, l.stop, step)
  69. if index < 0:
  70. index += length
  71. if index < 0 or index >= length:
  72. raise IndexError
  73. else:
  74. if index < 0:
  75. length = _ll_rangelen(l.start, l.stop, step)
  76. index += length
  77. return l.start + index * step
  78. # ____________________________________________________________
  79. #
  80. # Irregular operations.
  81. def rtype_builtin_range(hop):
  82. vstep = hop.inputconst(Signed, 1)
  83. if hop.nb_args == 1:
  84. vstart = hop.inputconst(Signed, 0)
  85. vstop, = hop.inputargs(Signed)
  86. elif hop.nb_args == 2:
  87. vstart, vstop = hop.inputargs(Signed, Signed)
  88. else:
  89. vstart, vstop, vstep = hop.inputargs(Signed, Signed, Signed)
  90. if isinstance(vstep, Constant) and vstep.value == 0:
  91. # not really needed, annotator catches it. Just in case...
  92. raise TyperError("range cannot have a const step of zero")
  93. if isinstance(hop.r_result, AbstractRangeRepr):
  94. if hop.r_result.step != 0:
  95. c_rng = hop.inputconst(Void, hop.r_result.RANGE)
  96. return hop.gendirectcall(hop.r_result.ll_newrange, c_rng, vstart, vstop)
  97. else:
  98. return hop.gendirectcall(hop.r_result.ll_newrangest, vstart, vstop, vstep)
  99. else:
  100. # cannot build a RANGE object, needs a real list
  101. r_list = hop.r_result
  102. ITEMTYPE = r_list.lowleveltype
  103. if isinstance(ITEMTYPE, Ptr):
  104. ITEMTYPE = ITEMTYPE.TO
  105. cLIST = hop.inputconst(Void, ITEMTYPE)
  106. return hop.gendirectcall(ll_range2list, cLIST, vstart, vstop, vstep)
  107. rtype_builtin_xrange = rtype_builtin_range
  108. def ll_range2list(LIST, start, stop, step):
  109. if step == 0:
  110. raise ValueError
  111. length = _ll_rangelen(start, stop, step)
  112. l = LIST.ll_newlist(length)
  113. if LIST.ITEM is not Void:
  114. idx = 0
  115. while idx < length:
  116. l.ll_setitem_fast(idx, start)
  117. start += step
  118. idx += 1
  119. return l
  120. # ____________________________________________________________
  121. #
  122. # Iteration.
  123. class AbstractRangeIteratorRepr(IteratorRepr):
  124. def __init__(self, r_rng):
  125. self.r_rng = r_rng
  126. if r_rng.step != 0:
  127. self.lowleveltype = r_rng.RANGEITER
  128. else:
  129. self.lowleveltype = r_rng.RANGESTITER
  130. def newiter(self, hop):
  131. v_rng, = hop.inputargs(self.r_rng)
  132. citerptr = hop.inputconst(Void, self.lowleveltype)
  133. return hop.gendirectcall(self.ll_rangeiter, citerptr, v_rng)
  134. def rtype_next(self, hop):
  135. v_iter, = hop.inputargs(self)
  136. args = hop.inputconst(Signed, self.r_rng.step),
  137. if self.r_rng.step > 0:
  138. llfn = ll_rangenext_up
  139. elif self.r_rng.step < 0:
  140. llfn = ll_rangenext_down
  141. else:
  142. llfn = ll_rangenext_updown
  143. args = ()
  144. hop.has_implicit_exception(StopIteration) # record that we know about it
  145. hop.exception_is_here()
  146. return hop.gendirectcall(llfn, v_iter, *args)
  147. def ll_rangenext_up(iter, step):
  148. next = iter.next
  149. if next >= iter.stop:
  150. raise StopIteration
  151. iter.next = next + step
  152. return next
  153. def ll_rangenext_down(iter, step):
  154. next = iter.next
  155. if next <= iter.stop:
  156. raise StopIteration
  157. iter.next = next + step
  158. return next
  159. def ll_rangenext_updown(iter):
  160. step = iter.step
  161. if step > 0:
  162. return ll_rangenext_up(iter, step)
  163. else:
  164. return ll_rangenext_down(iter, step)
  165. # ____________________________________________________________
  166. #
  167. # Support for enumerate().
  168. class EnumerateIteratorRepr(IteratorRepr):
  169. def __init__(self, r_baseiter):
  170. self.r_baseiter = r_baseiter
  171. self.lowleveltype = r_baseiter.lowleveltype
  172. # only supports for now enumerate() on sequence types whose iterators
  173. # have a method ll_getnextindex. It's easy to add one for most
  174. # iterator types, but I didn't do it so far.
  175. self.ll_getnextindex = r_baseiter.ll_getnextindex
  176. def rtype_next(self, hop):
  177. v_enumerate, = hop.inputargs(self)
  178. v_index = hop.gendirectcall(self.ll_getnextindex, v_enumerate)
  179. hop2 = hop.copy()
  180. hop2.args_r = [self.r_baseiter]
  181. r_item_src = self.r_baseiter.r_list.external_item_repr
  182. r_item_dst = hop.r_result.items_r[1]
  183. v_item = self.r_baseiter.rtype_next(hop2)
  184. v_item = hop.llops.convertvar(v_item, r_item_src, r_item_dst)
  185. return hop.r_result.newtuple(hop.llops, hop.r_result,
  186. [v_index, v_item])
  187. def rtype_builtin_enumerate(hop):
  188. return hop.r_result.r_baseiter.newiter(hop)