PageRenderTime 54ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/rpython/rtyper/rlist.py

https://bitbucket.org/pypy/pypy/
Python | 1089 lines | 889 code | 134 blank | 66 comment | 184 complexity | f1fa9abff992bd6660736fa3cdbdc4b2 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.annotator import model as annmodel
  2. from rpython.flowspace.model import Constant
  3. from rpython.rlib import rgc, jit, types
  4. from rpython.rtyper.debug import ll_assert
  5. from rpython.rlib.objectmodel import malloc_zero_filled, enforceargs, specialize
  6. from rpython.rlib.signature import signature
  7. from rpython.rlib.rarithmetic import ovfcheck, widen, r_uint, intmask
  8. from rpython.rlib.rarithmetic import int_force_ge_zero
  9. from rpython.rtyper.annlowlevel import ADTInterface
  10. from rpython.rtyper.error import TyperError
  11. from rpython.rtyper.lltypesystem.lltype import typeOf, Ptr, Void, Signed, Bool
  12. from rpython.rtyper.lltypesystem.lltype import nullptr, Char, UniChar, Number
  13. from rpython.rtyper.rmodel import Repr, IteratorRepr
  14. from rpython.rtyper.rint import IntegerRepr
  15. from rpython.rtyper.rstr import AbstractStringRepr, AbstractCharRepr
  16. from rpython.tool.pairtype import pairtype, pair
  17. ADTIFixedList = ADTInterface(None, {
  18. 'll_newlist': (['SELF', Signed ], 'self'),
  19. 'll_length': (['self' ], Signed),
  20. 'll_getitem_fast': (['self', Signed ], 'item'),
  21. 'll_setitem_fast': (['self', Signed, 'item'], Void),
  22. })
  23. ADTIList = ADTInterface(ADTIFixedList, {
  24. # grow the length if needed, overallocating a bit
  25. '_ll_resize_ge': (['self', Signed ], Void),
  26. # shrink the length; if reallocating, don't keep any overallocation
  27. '_ll_resize_le': (['self', Signed ], Void),
  28. # resize to exactly the given size; no overallocation
  29. '_ll_resize': (['self', Signed ], Void),
  30. # give a hint about the size; does overallocation if growing
  31. '_ll_resize_hint': (['self', Signed ], Void),
  32. })
  33. def dum_checkidx(): pass
  34. def dum_nocheck(): pass
  35. class __extend__(annmodel.SomeList):
  36. def rtyper_makerepr(self, rtyper):
  37. listitem = self.listdef.listitem
  38. s_value = listitem.s_value
  39. if (listitem.range_step is not None and not listitem.mutated and
  40. not isinstance(s_value, annmodel.SomeImpossibleValue)):
  41. from rpython.rtyper.lltypesystem.rrange import RangeRepr
  42. return RangeRepr(listitem.range_step)
  43. else:
  44. # cannot do the rtyper.getrepr() call immediately, for the case
  45. # of recursive structures -- i.e. if the listdef contains itself
  46. from rpython.rtyper.lltypesystem.rlist import ListRepr, FixedSizeListRepr
  47. item_repr = lambda: rtyper.getrepr(listitem.s_value)
  48. if self.listdef.listitem.resized:
  49. return ListRepr(rtyper, item_repr, listitem)
  50. else:
  51. return FixedSizeListRepr(rtyper, item_repr, listitem)
  52. def rtyper_makekey(self):
  53. self.listdef.listitem.dont_change_any_more = True
  54. return self.__class__, self.listdef.listitem
  55. class AbstractBaseListRepr(Repr):
  56. eq_func_cache = None
  57. def recast(self, llops, v):
  58. return llops.convertvar(v, self.item_repr, self.external_item_repr)
  59. def convert_const(self, listobj):
  60. # get object from bound list method
  61. if listobj is None:
  62. return self.null_const()
  63. if not isinstance(listobj, list):
  64. raise TyperError("expected a list: %r" % (listobj,))
  65. try:
  66. key = Constant(listobj)
  67. return self.list_cache[key]
  68. except KeyError:
  69. self.setup()
  70. n = len(listobj)
  71. result = self.prepare_const(n)
  72. self.list_cache[key] = result
  73. r_item = self.item_repr
  74. if r_item.lowleveltype is not Void:
  75. for i in range(n):
  76. x = listobj[i]
  77. result.ll_setitem_fast(i, r_item.convert_const(x))
  78. return result
  79. def null_const(self):
  80. raise NotImplementedError
  81. def prepare_const(self, nitems):
  82. raise NotImplementedError
  83. def ll_str(self, l):
  84. constant = self.rstr_ll.ll_constant
  85. start = self.rstr_ll.ll_build_start
  86. push = self.rstr_ll.ll_build_push
  87. finish = self.rstr_ll.ll_build_finish
  88. length = l.ll_length()
  89. if length == 0:
  90. return constant("[]")
  91. buf = start(2 * length + 1)
  92. push(buf, constant("["), 0)
  93. item_repr = self.item_repr
  94. i = 0
  95. while i < length:
  96. if i > 0:
  97. push(buf, constant(", "), 2 * i)
  98. item = l.ll_getitem_fast(i)
  99. push(buf, item_repr.ll_str(item), 2 * i + 1)
  100. i += 1
  101. push(buf, constant("]"), 2 * length)
  102. return finish(buf)
  103. def rtype_bltn_list(self, hop):
  104. v_lst = hop.inputarg(self, 0)
  105. cRESLIST = hop.inputconst(Void, hop.r_result.LIST)
  106. hop.exception_is_here()
  107. return hop.gendirectcall(ll_copy, cRESLIST, v_lst)
  108. def rtype_len(self, hop):
  109. v_lst, = hop.inputargs(self)
  110. if hop.args_s[0].listdef.listitem.resized:
  111. ll_func = ll_len
  112. else:
  113. ll_func = ll_len_foldable
  114. return hop.gendirectcall(ll_func, v_lst)
  115. def rtype_bool(self, hop):
  116. v_lst, = hop.inputargs(self)
  117. if hop.args_s[0].listdef.listitem.resized:
  118. ll_func = ll_list_is_true
  119. else:
  120. ll_func = ll_list_is_true_foldable
  121. return hop.gendirectcall(ll_func, v_lst)
  122. def rtype_method_reverse(self, hop):
  123. v_lst, = hop.inputargs(self)
  124. hop.exception_cannot_occur()
  125. hop.gendirectcall(ll_reverse,v_lst)
  126. def rtype_method_remove(self, hop):
  127. v_lst, v_value = hop.inputargs(self, self.item_repr)
  128. hop.has_implicit_exception(ValueError) # record that we know about it
  129. hop.exception_is_here()
  130. return hop.gendirectcall(ll_listremove, v_lst, v_value,
  131. self.get_eqfunc())
  132. def rtype_method_index(self, hop):
  133. v_lst, v_value = hop.inputargs(self, self.item_repr)
  134. hop.has_implicit_exception(ValueError) # record that we know about it
  135. hop.exception_is_here()
  136. return hop.gendirectcall(ll_listindex, v_lst, v_value, self.get_eqfunc())
  137. def get_ll_eq_function(self):
  138. result = self.eq_func_cache
  139. if result is not None:
  140. return result
  141. def list_eq(l1, l2):
  142. return ll_listeq(l1, l2, item_eq_func)
  143. self.eq_func_cache = list_eq
  144. # ^^^ do this first, before item_repr.get_ll_eq_function()
  145. item_eq_func = self.item_repr.get_ll_eq_function()
  146. return list_eq
  147. def _get_v_maxlength(self, hop):
  148. from rpython.rtyper.rint import signed_repr
  149. v_iterable = hop.args_v[1]
  150. s_iterable = hop.args_s[1]
  151. r_iterable = hop.args_r[1]
  152. hop2 = hop.copy()
  153. while hop2.nb_args > 0:
  154. hop2.r_s_popfirstarg()
  155. hop2.v_s_insertfirstarg(v_iterable, s_iterable)
  156. hop2.r_result = signed_repr
  157. v_maxlength = r_iterable.rtype_len(hop2)
  158. return v_maxlength
  159. class AbstractListRepr(AbstractBaseListRepr):
  160. def rtype_method_append(self, hop):
  161. v_lst, v_value = hop.inputargs(self, self.item_repr)
  162. hop.exception_cannot_occur()
  163. hop.gendirectcall(ll_append, v_lst, v_value)
  164. def rtype_method_insert(self, hop):
  165. v_lst, v_index, v_value = hop.inputargs(self, Signed, self.item_repr)
  166. arg1 = hop.args_s[1]
  167. args = v_lst, v_index, v_value
  168. if arg1.is_constant() and arg1.const == 0:
  169. llfn = ll_prepend
  170. args = v_lst, v_value
  171. elif arg1.nonneg:
  172. llfn = ll_insert_nonneg
  173. else:
  174. raise TyperError("insert() index must be proven non-negative")
  175. hop.exception_cannot_occur()
  176. hop.gendirectcall(llfn, *args)
  177. def rtype_method_extend(self, hop):
  178. v_lst1, v_lst2 = hop.inputargs(*hop.args_r)
  179. hop.exception_cannot_occur()
  180. hop.gendirectcall(ll_extend, v_lst1, v_lst2)
  181. def rtype_method_pop(self, hop):
  182. if hop.has_implicit_exception(IndexError):
  183. spec = dum_checkidx
  184. else:
  185. spec = dum_nocheck
  186. v_func = hop.inputconst(Void, spec)
  187. if hop.nb_args == 2:
  188. args = hop.inputargs(self, Signed)
  189. assert hasattr(args[1], 'concretetype')
  190. arg1 = hop.args_s[1]
  191. if arg1.is_constant() and arg1.const == 0:
  192. llfn = ll_pop_zero
  193. args = args[:1]
  194. elif hop.args_s[1].nonneg:
  195. llfn = ll_pop_nonneg
  196. else:
  197. llfn = ll_pop
  198. else:
  199. args = hop.inputargs(self)
  200. llfn = ll_pop_default
  201. hop.exception_is_here()
  202. v_res = hop.gendirectcall(llfn, v_func, *args)
  203. return self.recast(hop.llops, v_res)
  204. class AbstractFixedSizeListRepr(AbstractBaseListRepr):
  205. pass
  206. class __extend__(pairtype(AbstractBaseListRepr, Repr)):
  207. def rtype_contains((r_lst, _), hop):
  208. v_lst, v_any = hop.inputargs(r_lst, r_lst.item_repr)
  209. hop.exception_cannot_occur()
  210. return hop.gendirectcall(ll_listcontains, v_lst, v_any, r_lst.get_eqfunc())
  211. class __extend__(pairtype(AbstractBaseListRepr, IntegerRepr)):
  212. def rtype_getitem((r_lst, r_int), hop, checkidx=False):
  213. v_lst, v_index = hop.inputargs(r_lst, Signed)
  214. if checkidx:
  215. hop.exception_is_here()
  216. spec = dum_checkidx
  217. else:
  218. spec = dum_nocheck
  219. hop.exception_cannot_occur()
  220. if hop.args_s[0].listdef.listitem.mutated:
  221. basegetitem = ll_getitem_fast
  222. else:
  223. basegetitem = ll_getitem_foldable_nonneg
  224. if hop.args_s[1].nonneg:
  225. llfn = ll_getitem_nonneg
  226. else:
  227. llfn = ll_getitem
  228. c_func_marker = hop.inputconst(Void, spec)
  229. c_basegetitem = hop.inputconst(Void, basegetitem)
  230. v_res = hop.gendirectcall(llfn, c_func_marker, c_basegetitem, v_lst, v_index)
  231. return r_lst.recast(hop.llops, v_res)
  232. def rtype_getitem_idx((r_lst, r_int), hop):
  233. return pair(r_lst, r_int).rtype_getitem(hop, checkidx=True)
  234. def rtype_setitem((r_lst, r_int), hop):
  235. if hop.has_implicit_exception(IndexError):
  236. spec = dum_checkidx
  237. else:
  238. spec = dum_nocheck
  239. v_func = hop.inputconst(Void, spec)
  240. v_lst, v_index, v_item = hop.inputargs(r_lst, Signed, r_lst.item_repr)
  241. if hop.args_s[1].nonneg:
  242. llfn = ll_setitem_nonneg
  243. else:
  244. llfn = ll_setitem
  245. hop.exception_is_here()
  246. return hop.gendirectcall(llfn, v_func, v_lst, v_index, v_item)
  247. def rtype_mul((r_lst, r_int), hop):
  248. cRESLIST = hop.inputconst(Void, hop.r_result.LIST)
  249. v_lst, v_factor = hop.inputargs(r_lst, Signed)
  250. return hop.gendirectcall(ll_mul, cRESLIST, v_lst, v_factor)
  251. class __extend__(pairtype(IntegerRepr, AbstractBaseListRepr)):
  252. def rtype_mul((r_int, r_lst), hop):
  253. cRESLIST = hop.inputconst(Void, hop.r_result.LIST)
  254. v_factor, v_lst = hop.inputargs(Signed, r_lst)
  255. return hop.gendirectcall(ll_mul, cRESLIST, v_lst, v_factor)
  256. class __extend__(pairtype(AbstractListRepr, IntegerRepr)):
  257. def rtype_delitem((r_lst, r_int), hop):
  258. if hop.has_implicit_exception(IndexError):
  259. spec = dum_checkidx
  260. else:
  261. spec = dum_nocheck
  262. v_func = hop.inputconst(Void, spec)
  263. v_lst, v_index = hop.inputargs(r_lst, Signed)
  264. if hop.args_s[1].nonneg:
  265. llfn = ll_delitem_nonneg
  266. else:
  267. llfn = ll_delitem
  268. hop.exception_is_here()
  269. return hop.gendirectcall(llfn, v_func, v_lst, v_index)
  270. def rtype_inplace_mul((r_lst, r_int), hop):
  271. v_lst, v_factor = hop.inputargs(r_lst, Signed)
  272. return hop.gendirectcall(ll_inplace_mul, v_lst, v_factor)
  273. class __extend__(pairtype(AbstractBaseListRepr, AbstractBaseListRepr)):
  274. def convert_from_to((r_lst1, r_lst2), v, llops):
  275. if r_lst1.listitem is None or r_lst2.listitem is None:
  276. return NotImplemented
  277. if r_lst1.listitem is not r_lst2.listitem:
  278. return NotImplemented
  279. return v
  280. def rtype_eq((r_lst1, r_lst2), hop):
  281. assert r_lst1.item_repr == r_lst2.item_repr
  282. v_lst1, v_lst2 = hop.inputargs(r_lst1, r_lst2)
  283. return hop.gendirectcall(ll_listeq, v_lst1, v_lst2, r_lst1.get_eqfunc())
  284. def rtype_ne((r_lst1, r_lst2), hop):
  285. assert r_lst1.item_repr == r_lst2.item_repr
  286. v_lst1, v_lst2 = hop.inputargs(r_lst1, r_lst2)
  287. flag = hop.gendirectcall(ll_listeq, v_lst1, v_lst2, r_lst1.get_eqfunc())
  288. return hop.genop('bool_not', [flag], resulttype=Bool)
  289. def rtype_newlist(hop, v_sizehint=None):
  290. from rpython.rtyper.lltypesystem.rlist import newlist
  291. nb_args = hop.nb_args
  292. r_list = hop.r_result
  293. r_listitem = r_list.item_repr
  294. items_v = [hop.inputarg(r_listitem, arg=i) for i in range(nb_args)]
  295. return newlist(hop.llops, r_list, items_v, v_sizehint=v_sizehint)
  296. def rtype_alloc_and_set(hop):
  297. r_list = hop.r_result
  298. v_count, v_item = hop.inputargs(Signed, r_list.item_repr)
  299. cLIST = hop.inputconst(Void, r_list.LIST)
  300. return hop.gendirectcall(ll_alloc_and_set, cLIST, v_count, v_item)
  301. class __extend__(pairtype(AbstractBaseListRepr, AbstractBaseListRepr)):
  302. def rtype_add((r_lst1, r_lst2), hop):
  303. v_lst1, v_lst2 = hop.inputargs(r_lst1, r_lst2)
  304. cRESLIST = hop.inputconst(Void, hop.r_result.LIST)
  305. return hop.gendirectcall(ll_concat, cRESLIST, v_lst1, v_lst2)
  306. class __extend__(pairtype(AbstractListRepr, AbstractBaseListRepr)):
  307. def rtype_inplace_add((r_lst1, r_lst2), hop):
  308. v_lst1, v_lst2 = hop.inputargs(r_lst1, r_lst2)
  309. hop.gendirectcall(ll_extend, v_lst1, v_lst2)
  310. return v_lst1
  311. class __extend__(pairtype(AbstractListRepr, AbstractStringRepr)):
  312. def rtype_inplace_add((r_lst1, r_str2), hop):
  313. if r_lst1.item_repr.lowleveltype not in (Char, UniChar):
  314. raise TyperError('"lst += string" only supported with a list '
  315. 'of chars or unichars')
  316. string_repr = r_str2.repr
  317. v_lst1, v_str2 = hop.inputargs(r_lst1, string_repr)
  318. c_strlen = hop.inputconst(Void, string_repr.ll.ll_strlen)
  319. c_stritem = hop.inputconst(Void, string_repr.ll.ll_stritem_nonneg)
  320. hop.gendirectcall(ll_extend_with_str, v_lst1, v_str2,
  321. c_strlen, c_stritem)
  322. return v_lst1
  323. def rtype_extend_with_str_slice((r_lst1, r_str2), hop):
  324. from rpython.rtyper.lltypesystem.rstr import string_repr
  325. if r_lst1.item_repr.lowleveltype not in (Char, UniChar):
  326. raise TyperError('"lst += string" only supported with a list '
  327. 'of chars or unichars')
  328. v_lst1 = hop.inputarg(r_lst1, arg=0)
  329. v_str2 = hop.inputarg(string_repr, arg=3)
  330. kind, vlist = hop.decompose_slice_args()
  331. c_strlen = hop.inputconst(Void, string_repr.ll.ll_strlen)
  332. c_stritem = hop.inputconst(Void, string_repr.ll.ll_stritem_nonneg)
  333. ll_fn = globals()['ll_extend_with_str_slice_%s' % kind]
  334. hop.gendirectcall(ll_fn, v_lst1, v_str2, c_strlen, c_stritem, *vlist)
  335. return v_lst1
  336. class __extend__(pairtype(AbstractListRepr, AbstractCharRepr)):
  337. def rtype_extend_with_char_count((r_lst1, r_chr2), hop):
  338. from rpython.rtyper.lltypesystem.rstr import char_repr
  339. if r_lst1.item_repr.lowleveltype not in (Char, UniChar):
  340. raise TyperError('"lst += string" only supported with a list '
  341. 'of chars or unichars')
  342. v_lst1, v_chr, v_count = hop.inputargs(r_lst1, char_repr, Signed)
  343. hop.gendirectcall(ll_extend_with_char_count, v_lst1, v_chr, v_count)
  344. return v_lst1
  345. class __extend__(AbstractBaseListRepr):
  346. def rtype_getslice(r_lst, hop):
  347. cRESLIST = hop.inputconst(Void, hop.r_result.LIST)
  348. v_lst = hop.inputarg(r_lst, arg=0)
  349. kind, vlist = hop.decompose_slice_args()
  350. ll_listslice = globals()['ll_listslice_%s' % kind]
  351. return hop.gendirectcall(ll_listslice, cRESLIST, v_lst, *vlist)
  352. def rtype_setslice(r_lst, hop):
  353. v_lst = hop.inputarg(r_lst, arg=0)
  354. kind, vlist = hop.decompose_slice_args()
  355. if kind != 'startstop':
  356. raise TyperError('list.setitem does not support %r slices' % (
  357. kind,))
  358. v_start, v_stop = vlist
  359. v_lst2 = hop.inputarg(hop.args_r[3], arg=3)
  360. hop.gendirectcall(ll_listsetslice, v_lst, v_start, v_stop, v_lst2)
  361. def rtype_delslice(r_lst, hop):
  362. v_lst = hop.inputarg(r_lst, arg=0)
  363. kind, vlist = hop.decompose_slice_args()
  364. ll_listdelslice = globals()['ll_listdelslice_%s' % kind]
  365. return hop.gendirectcall(ll_listdelslice, v_lst, *vlist)
  366. # ____________________________________________________________
  367. #
  368. # Iteration.
  369. class AbstractListIteratorRepr(IteratorRepr):
  370. def newiter(self, hop):
  371. v_lst, = hop.inputargs(self.r_list)
  372. citerptr = hop.inputconst(Void, self.lowleveltype)
  373. return hop.gendirectcall(self.ll_listiter, citerptr, v_lst)
  374. def rtype_next(self, hop):
  375. v_iter, = hop.inputargs(self)
  376. hop.has_implicit_exception(StopIteration) # record that we know about it
  377. hop.exception_is_here()
  378. v_res = hop.gendirectcall(self.ll_listnext, v_iter)
  379. return self.r_list.recast(hop.llops, v_res)
  380. # ____________________________________________________________
  381. #
  382. # Low-level methods. These can be run for testing, but are meant to
  383. # be direct_call'ed from rtyped flow graphs, which means that they will
  384. # get flowed and annotated, mostly with SomePtr.
  385. #
  386. # === a note about overflows ===
  387. #
  388. # The maximal length of RPython lists is bounded by the assumption that
  389. # we can never allocate arrays more than sys.maxint bytes in size.
  390. # Our arrays have a length and some GC headers, so a list of characters
  391. # could come near sys.maxint in length (but not reach it). A list of
  392. # pointers could only come near sys.maxint/sizeof(void*) elements. There
  393. # is the list of Voids that could reach exactly sys.maxint elements,
  394. # but for now let's ignore this case -- the reasoning is that even if
  395. # the length of a Void list overflows, nothing bad memory-wise can be
  396. # done with it. So in the sequel we don't bother checking for overflow
  397. # when we compute "ll_length() + 1".
  398. def _ll_zero_or_null(item):
  399. # Check if 'item' is zero/null, or not.
  400. T = typeOf(item)
  401. if T is Char or T is UniChar:
  402. check = ord(item)
  403. elif isinstance(T, Number):
  404. check = widen(item)
  405. else:
  406. check = item
  407. return not check
  408. @specialize.memo()
  409. def _null_of_type(T):
  410. return T._defl()
  411. def ll_alloc_and_set(LIST, count, item):
  412. count = int_force_ge_zero(count)
  413. if jit.we_are_jitted():
  414. return _ll_alloc_and_set_jit(LIST, count, item)
  415. else:
  416. return _ll_alloc_and_set_nojit(LIST, count, item)
  417. def _ll_alloc_and_set_nojit(LIST, count, item):
  418. l = LIST.ll_newlist(count)
  419. if malloc_zero_filled and _ll_zero_or_null(item):
  420. return l
  421. i = 0
  422. while i < count:
  423. l.ll_setitem_fast(i, item)
  424. i += 1
  425. return l
  426. def _ll_alloc_and_set_jit(LIST, count, item):
  427. if _ll_zero_or_null(item):
  428. # 'item' is zero/null. Do the list allocation with the
  429. # function _ll_alloc_and_clear(), which the JIT knows about.
  430. return _ll_alloc_and_clear(LIST, count)
  431. else:
  432. # 'item' is not zero/null. Do the list allocation with the
  433. # function _ll_alloc_and_set_nonnull(). That function has
  434. # a JIT marker to unroll it, but only if the 'count' is
  435. # a not-too-large constant.
  436. return _ll_alloc_and_set_nonnull(LIST, count, item)
  437. @jit.oopspec("newlist_clear(count)")
  438. def _ll_alloc_and_clear(LIST, count):
  439. l = LIST.ll_newlist(count)
  440. if malloc_zero_filled:
  441. return l
  442. zeroitem = _null_of_type(LIST.ITEM)
  443. i = 0
  444. while i < count:
  445. l.ll_setitem_fast(i, zeroitem)
  446. i += 1
  447. return l
  448. @jit.look_inside_iff(lambda LIST, count, item: jit.isconstant(count) and count < 137)
  449. def _ll_alloc_and_set_nonnull(LIST, count, item):
  450. l = LIST.ll_newlist(count)
  451. i = 0
  452. while i < count:
  453. l.ll_setitem_fast(i, item)
  454. i += 1
  455. return l
  456. # return a nullptr() if lst is a list of pointers it, else None.
  457. def ll_null_item(lst):
  458. LIST = typeOf(lst)
  459. if isinstance(LIST, Ptr):
  460. ITEM = LIST.TO.ITEM
  461. if isinstance(ITEM, Ptr):
  462. return nullptr(ITEM.TO)
  463. return None
  464. def listItemType(lst):
  465. LIST = typeOf(lst)
  466. return LIST.TO.ITEM
  467. @signature(types.any(), types.any(), types.int(), types.int(), types.int(), returns=types.none())
  468. def ll_arraycopy(source, dest, source_start, dest_start, length):
  469. SRCTYPE = typeOf(source)
  470. # lltype
  471. rgc.ll_arraycopy(source.ll_items(), dest.ll_items(),
  472. source_start, dest_start, length)
  473. def ll_copy(RESLIST, l):
  474. length = l.ll_length()
  475. new_lst = RESLIST.ll_newlist(length)
  476. ll_arraycopy(l, new_lst, 0, 0, length)
  477. return new_lst
  478. # no oopspec -- the function is inlined by the JIT
  479. def ll_len(l):
  480. return l.ll_length()
  481. def ll_list_is_true(l):
  482. # check if a list is True, allowing for None
  483. return bool(l) and l.ll_length() != 0
  484. # no oopspec -- the function is inlined by the JIT
  485. def ll_len_foldable(l):
  486. return l.ll_length()
  487. ll_len_foldable.oopspec = 'list.len_foldable(l)'
  488. def ll_list_is_true_foldable(l):
  489. return bool(l) and ll_len_foldable(l) != 0
  490. # no oopspec -- the function is inlined by the JIT
  491. def ll_append(l, newitem):
  492. length = l.ll_length()
  493. l._ll_resize_ge(length+1) # see "a note about overflows" above
  494. l.ll_setitem_fast(length, newitem)
  495. # this one is for the special case of insert(0, x)
  496. def ll_prepend(l, newitem):
  497. length = l.ll_length()
  498. l._ll_resize_ge(length+1) # see "a note about overflows" above
  499. dst = length
  500. while dst > 0:
  501. src = dst - 1
  502. l.ll_setitem_fast(dst, l.ll_getitem_fast(src))
  503. dst = src
  504. l.ll_setitem_fast(0, newitem)
  505. ll_prepend.oopspec = 'list.insert(l, 0, newitem)'
  506. def ll_concat(RESLIST, l1, l2):
  507. len1 = l1.ll_length()
  508. len2 = l2.ll_length()
  509. try:
  510. newlength = ovfcheck(len1 + len2)
  511. except OverflowError:
  512. raise MemoryError
  513. l = RESLIST.ll_newlist(newlength)
  514. ll_arraycopy(l1, l, 0, 0, len1)
  515. ll_arraycopy(l2, l, 0, len1, len2)
  516. return l
  517. # no oopspec -- the function is inlined by the JIT
  518. def ll_insert_nonneg(l, index, newitem):
  519. length = l.ll_length()
  520. ll_assert(0 <= index, "negative list insertion index")
  521. ll_assert(index <= length, "list insertion index out of bound")
  522. l._ll_resize_ge(length+1) # see "a note about overflows" above
  523. dst = length
  524. while dst > index:
  525. src = dst - 1
  526. l.ll_setitem_fast(dst, l.ll_getitem_fast(src))
  527. dst = src
  528. l.ll_setitem_fast(index, newitem)
  529. ll_insert_nonneg.oopspec = 'list.insert(l, index, newitem)'
  530. def ll_pop_nonneg(func, l, index):
  531. ll_assert(index >= 0, "unexpectedly negative list pop index")
  532. if func is dum_checkidx:
  533. if index >= l.ll_length():
  534. raise IndexError
  535. else:
  536. ll_assert(index < l.ll_length(), "list pop index out of bound")
  537. res = l.ll_getitem_fast(index)
  538. ll_delitem_nonneg(dum_nocheck, l, index)
  539. return res
  540. ll_pop_nonneg.oopspec = 'list.pop(l, index)'
  541. def ll_pop_default(func, l):
  542. length = l.ll_length()
  543. if func is dum_checkidx and (length == 0):
  544. raise IndexError
  545. ll_assert(length > 0, "pop from empty list")
  546. index = length - 1
  547. newlength = index
  548. res = l.ll_getitem_fast(index)
  549. null = ll_null_item(l)
  550. if null is not None:
  551. l.ll_setitem_fast(index, null)
  552. l._ll_resize_le(newlength)
  553. return res
  554. def ll_pop_zero(func, l):
  555. length = l.ll_length()
  556. if func is dum_checkidx and (length == 0):
  557. raise IndexError
  558. ll_assert(length > 0, "pop(0) from empty list")
  559. newlength = length - 1
  560. res = l.ll_getitem_fast(0)
  561. j = 0
  562. j1 = j+1
  563. while j < newlength:
  564. l.ll_setitem_fast(j, l.ll_getitem_fast(j1))
  565. j = j1
  566. j1 += 1
  567. null = ll_null_item(l)
  568. if null is not None:
  569. l.ll_setitem_fast(newlength, null)
  570. l._ll_resize_le(newlength)
  571. return res
  572. ll_pop_zero.oopspec = 'list.pop(l, 0)'
  573. def ll_pop(func, l, index):
  574. length = l.ll_length()
  575. if index < 0:
  576. index += length
  577. if func is dum_checkidx:
  578. if index < 0 or index >= length:
  579. raise IndexError
  580. else:
  581. ll_assert(index >= 0, "negative list pop index out of bound")
  582. ll_assert(index < length, "list pop index out of bound")
  583. res = l.ll_getitem_fast(index)
  584. ll_delitem_nonneg(dum_nocheck, l, index)
  585. return res
  586. @jit.look_inside_iff(lambda l: jit.isvirtual(l))
  587. def ll_reverse(l):
  588. length = l.ll_length()
  589. i = 0
  590. length_1_i = length-1-i
  591. while i < length_1_i:
  592. tmp = l.ll_getitem_fast(i)
  593. l.ll_setitem_fast(i, l.ll_getitem_fast(length_1_i))
  594. l.ll_setitem_fast(length_1_i, tmp)
  595. i += 1
  596. length_1_i -= 1
  597. def ll_getitem_nonneg(func, basegetitem, l, index):
  598. ll_assert(index >= 0, "unexpectedly negative list getitem index")
  599. if func is dum_checkidx:
  600. if index >= l.ll_length():
  601. raise IndexError
  602. return basegetitem(l, index)
  603. ll_getitem_nonneg._always_inline_ = True
  604. # no oopspec -- the function is inlined by the JIT
  605. def ll_getitem(func, basegetitem, l, index):
  606. if func is dum_checkidx:
  607. length = l.ll_length() # common case: 0 <= index < length
  608. if r_uint(index) >= r_uint(length):
  609. # Failed, so either (-length <= index < 0), or we have to raise
  610. # IndexError. First add 'length' to get the final index, then
  611. # check that we now have (0 <= index < length).
  612. index = r_uint(index) + r_uint(length)
  613. if index >= r_uint(length):
  614. raise IndexError
  615. index = intmask(index)
  616. else:
  617. # We don't want checking, but still want to support index < 0.
  618. # Only call ll_length() if needed.
  619. if index < 0:
  620. index += l.ll_length()
  621. ll_assert(index >= 0, "negative list getitem index out of bound")
  622. return basegetitem(l, index)
  623. # no oopspec -- the function is inlined by the JIT
  624. def ll_getitem_fast(l, index):
  625. return l.ll_getitem_fast(index)
  626. ll_getitem_fast._always_inline_ = True
  627. def ll_getitem_foldable_nonneg(l, index):
  628. ll_assert(index >= 0, "unexpectedly negative list getitem index")
  629. return l.ll_getitem_fast(index)
  630. ll_getitem_foldable_nonneg.oopspec = 'list.getitem_foldable(l, index)'
  631. def ll_setitem_nonneg(func, l, index, newitem):
  632. ll_assert(index >= 0, "unexpectedly negative list setitem index")
  633. if func is dum_checkidx:
  634. if index >= l.ll_length():
  635. raise IndexError
  636. l.ll_setitem_fast(index, newitem)
  637. ll_setitem_nonneg._always_inline_ = True
  638. # no oopspec -- the function is inlined by the JIT
  639. def ll_setitem(func, l, index, newitem):
  640. if func is dum_checkidx:
  641. length = l.ll_length()
  642. if r_uint(index) >= r_uint(length): # see comments in ll_getitem().
  643. index = r_uint(index) + r_uint(length)
  644. if index >= r_uint(length):
  645. raise IndexError
  646. index = intmask(index)
  647. else:
  648. if index < 0:
  649. index += l.ll_length()
  650. ll_assert(index >= 0, "negative list setitem index out of bound")
  651. l.ll_setitem_fast(index, newitem)
  652. # no oopspec -- the function is inlined by the JIT
  653. @enforceargs(None, None, int)
  654. def ll_delitem_nonneg(func, l, index):
  655. ll_assert(index >= 0, "unexpectedly negative list delitem index")
  656. length = l.ll_length()
  657. if func is dum_checkidx:
  658. if index >= length:
  659. raise IndexError
  660. else:
  661. ll_assert(index < length, "list delitem index out of bound")
  662. newlength = length - 1
  663. j = index
  664. j1 = j+1
  665. while j < newlength:
  666. l.ll_setitem_fast(j, l.ll_getitem_fast(j1))
  667. j = j1
  668. j1 += 1
  669. null = ll_null_item(l)
  670. if null is not None:
  671. l.ll_setitem_fast(newlength, null)
  672. l._ll_resize_le(newlength)
  673. ll_delitem_nonneg.oopspec = 'list.delitem(l, index)'
  674. def ll_delitem(func, l, index):
  675. if func is dum_checkidx:
  676. length = l.ll_length()
  677. if r_uint(index) >= r_uint(length): # see comments in ll_getitem().
  678. index = r_uint(index) + r_uint(length)
  679. if index >= r_uint(length):
  680. raise IndexError
  681. index = intmask(index)
  682. else:
  683. if index < 0:
  684. index += l.ll_length()
  685. ll_assert(index >= 0, "negative list delitem index out of bound")
  686. ll_delitem_nonneg(dum_nocheck, l, index)
  687. # no oopspec -- the function is inlined by the JIT
  688. def ll_extend(l1, l2):
  689. len1 = l1.ll_length()
  690. len2 = l2.ll_length()
  691. try:
  692. newlength = ovfcheck(len1 + len2)
  693. except OverflowError:
  694. raise MemoryError
  695. l1._ll_resize_ge(newlength)
  696. ll_arraycopy(l2, l1, 0, len1, len2)
  697. def ll_extend_with_str(lst, s, getstrlen, getstritem):
  698. return ll_extend_with_str_slice_startonly(lst, s, getstrlen, getstritem, 0)
  699. def ll_extend_with_str_slice_startonly(lst, s, getstrlen, getstritem, start):
  700. len1 = lst.ll_length()
  701. len2 = getstrlen(s)
  702. count2 = len2 - start
  703. ll_assert(start >= 0, "unexpectedly negative str slice start")
  704. assert count2 >= 0, "str slice start larger than str length"
  705. try:
  706. newlength = ovfcheck(len1 + count2)
  707. except OverflowError:
  708. raise MemoryError
  709. lst._ll_resize_ge(newlength)
  710. i = start
  711. j = len1
  712. while i < len2:
  713. c = getstritem(s, i)
  714. if listItemType(lst) is UniChar:
  715. c = unichr(ord(c))
  716. lst.ll_setitem_fast(j, c)
  717. i += 1
  718. j += 1
  719. # not inlined by the JIT -- contains a loop
  720. def ll_extend_with_str_slice_startstop(lst, s, getstrlen, getstritem,
  721. start, stop):
  722. len1 = lst.ll_length()
  723. len2 = getstrlen(s)
  724. ll_assert(start >= 0, "unexpectedly negative str slice start")
  725. ll_assert(start <= len2, "str slice start larger than str length")
  726. if stop > len2:
  727. stop = len2
  728. count2 = stop - start
  729. assert count2 >= 0, "str slice stop smaller than start"
  730. try:
  731. newlength = ovfcheck(len1 + count2)
  732. except OverflowError:
  733. raise MemoryError
  734. lst._ll_resize_ge(newlength)
  735. i = start
  736. j = len1
  737. while i < stop:
  738. c = getstritem(s, i)
  739. if listItemType(lst) is UniChar:
  740. c = unichr(ord(c))
  741. lst.ll_setitem_fast(j, c)
  742. i += 1
  743. j += 1
  744. # not inlined by the JIT -- contains a loop
  745. def ll_extend_with_str_slice_minusone(lst, s, getstrlen, getstritem):
  746. len1 = lst.ll_length()
  747. len2m1 = getstrlen(s) - 1
  748. assert len2m1 >= 0, "empty string is sliced with [:-1]"
  749. try:
  750. newlength = ovfcheck(len1 + len2m1)
  751. except OverflowError:
  752. raise MemoryError
  753. lst._ll_resize_ge(newlength)
  754. i = 0
  755. j = len1
  756. while i < len2m1:
  757. c = getstritem(s, i)
  758. if listItemType(lst) is UniChar:
  759. c = unichr(ord(c))
  760. lst.ll_setitem_fast(j, c)
  761. i += 1
  762. j += 1
  763. # not inlined by the JIT -- contains a loop
  764. def ll_extend_with_char_count(lst, char, count):
  765. if count <= 0:
  766. return
  767. len1 = lst.ll_length()
  768. try:
  769. newlength = ovfcheck(len1 + count)
  770. except OverflowError:
  771. raise MemoryError
  772. lst._ll_resize_ge(newlength)
  773. j = len1
  774. if listItemType(lst) is UniChar:
  775. char = unichr(ord(char))
  776. while j < newlength:
  777. lst.ll_setitem_fast(j, char)
  778. j += 1
  779. @signature(types.any(), types.any(), types.int(), returns=types.any())
  780. def ll_listslice_startonly(RESLIST, l1, start):
  781. len1 = l1.ll_length()
  782. ll_assert(start >= 0, "unexpectedly negative list slice start")
  783. ll_assert(start <= len1, "list slice start larger than list length")
  784. newlength = len1 - start
  785. l = RESLIST.ll_newlist(newlength)
  786. ll_arraycopy(l1, l, start, 0, newlength)
  787. return l
  788. def ll_listslice_startstop(RESLIST, l1, start, stop):
  789. length = l1.ll_length()
  790. ll_assert(start >= 0, "unexpectedly negative list slice start")
  791. ll_assert(start <= length, "list slice start larger than list length")
  792. ll_assert(stop >= start, "list slice stop smaller than start")
  793. if stop > length:
  794. stop = length
  795. newlength = stop - start
  796. l = RESLIST.ll_newlist(newlength)
  797. ll_arraycopy(l1, l, start, 0, newlength)
  798. return l
  799. # no oopspec -- the function is inlined by the JIT
  800. def ll_listslice_minusone(RESLIST, l1):
  801. newlength = l1.ll_length() - 1
  802. ll_assert(newlength >= 0, "empty list is sliced with [:-1]")
  803. l = RESLIST.ll_newlist(newlength)
  804. ll_arraycopy(l1, l, 0, 0, newlength)
  805. return l
  806. # no oopspec -- the function is inlined by the JIT
  807. @jit.look_inside_iff(lambda l, start: jit.isconstant(start) and jit.isvirtual(l))
  808. @jit.oopspec('list.delslice_startonly(l, start)')
  809. def ll_listdelslice_startonly(l, start):
  810. ll_assert(start >= 0, "del l[start:] with unexpectedly negative start")
  811. ll_assert(start <= l.ll_length(), "del l[start:] with start > len(l)")
  812. newlength = start
  813. null = ll_null_item(l)
  814. if null is not None:
  815. j = l.ll_length() - 1
  816. while j >= newlength:
  817. l.ll_setitem_fast(j, null)
  818. j -= 1
  819. l._ll_resize_le(newlength)
  820. def ll_listdelslice_startstop(l, start, stop):
  821. length = l.ll_length()
  822. ll_assert(start >= 0, "del l[start:x] with unexpectedly negative start")
  823. ll_assert(start <= length, "del l[start:x] with start > len(l)")
  824. ll_assert(stop >= start, "del l[x:y] with x > y")
  825. if stop > length:
  826. stop = length
  827. newlength = length - (stop-start)
  828. j = start
  829. i = stop
  830. while j < newlength:
  831. l.ll_setitem_fast(j, l.ll_getitem_fast(i))
  832. i += 1
  833. j += 1
  834. null = ll_null_item(l)
  835. if null is not None:
  836. j = length - 1
  837. while j >= newlength:
  838. l.ll_setitem_fast(j, null)
  839. j -= 1
  840. l._ll_resize_le(newlength)
  841. ll_listdelslice_startstop.oopspec = 'list.delslice_startstop(l, start, stop)'
  842. def ll_listsetslice(l1, start, stop, l2):
  843. len1 = l1.ll_length()
  844. len2 = l2.ll_length()
  845. ll_assert(start >= 0, "l[start:x] = l with unexpectedly negative start")
  846. ll_assert(start <= len1, "l[start:x] = l with start > len(l)")
  847. ll_assert(stop <= len1, "stop cannot be past the end of l1")
  848. if len2 == stop - start:
  849. ll_arraycopy(l2, l1, 0, start, len2)
  850. elif len2 < stop - start:
  851. ll_arraycopy(l2, l1, 0, start, len2)
  852. ll_arraycopy(l1, l1, stop, start + len2, len1 - stop)
  853. l1._ll_resize_le(len1 + len2 - (stop - start))
  854. else: # len2 > stop - start:
  855. try:
  856. newlength = ovfcheck(len1 + len2)
  857. except OverflowError:
  858. raise MemoryError
  859. l1._ll_resize_ge(newlength)
  860. ll_arraycopy(l1, l1, stop, start + len2, len1 - stop)
  861. ll_arraycopy(l2, l1, 0, start, len2)
  862. # ____________________________________________________________
  863. #
  864. # Comparison.
  865. def listeq_unroll_case(l1, l2, eqfn):
  866. if jit.isvirtual(l1) and l1.ll_length() < 10:
  867. return True
  868. if jit.isvirtual(l2) and l2.ll_length() < 10:
  869. return True
  870. return False
  871. @jit.look_inside_iff(listeq_unroll_case)
  872. def ll_listeq(l1, l2, eqfn):
  873. if not l1 and not l2:
  874. return True
  875. if not l1 or not l2:
  876. return False
  877. len1 = l1.ll_length()
  878. len2 = l2.ll_length()
  879. if len1 != len2:
  880. return False
  881. j = 0
  882. while j < len1:
  883. if eqfn is None:
  884. if l1.ll_getitem_fast(j) != l2.ll_getitem_fast(j):
  885. return False
  886. else:
  887. if not eqfn(l1.ll_getitem_fast(j), l2.ll_getitem_fast(j)):
  888. return False
  889. j += 1
  890. return True
  891. # not inlined by the JIT -- contains a loop
  892. def ll_listcontains(lst, obj, eqfn):
  893. lng = lst.ll_length()
  894. j = 0
  895. while j < lng:
  896. if eqfn is None:
  897. if lst.ll_getitem_fast(j) == obj:
  898. return True
  899. else:
  900. if eqfn(lst.ll_getitem_fast(j), obj):
  901. return True
  902. j += 1
  903. return False
  904. # not inlined by the JIT -- contains a loop
  905. def ll_listindex(lst, obj, eqfn):
  906. lng = lst.ll_length()
  907. j = 0
  908. while j < lng:
  909. if eqfn is None:
  910. if lst.ll_getitem_fast(j) == obj:
  911. return j
  912. else:
  913. if eqfn(lst.ll_getitem_fast(j), obj):
  914. return j
  915. j += 1
  916. raise ValueError # can't say 'list.index(x): x not in list'
  917. # not inlined by the JIT -- contains a loop
  918. def ll_listremove(lst, obj, eqfn):
  919. index = ll_listindex(lst, obj, eqfn) # raises ValueError if obj not in lst
  920. ll_delitem_nonneg(dum_nocheck, lst, index)
  921. def ll_inplace_mul(l, factor):
  922. if factor == 1:
  923. return l
  924. length = l.ll_length()
  925. if factor < 0:
  926. factor = 0
  927. try:
  928. resultlen = ovfcheck(length * factor)
  929. except OverflowError:
  930. raise MemoryError
  931. res = l
  932. res._ll_resize(resultlen)
  933. j = length
  934. while j < resultlen:
  935. ll_arraycopy(l, res, 0, j, length)
  936. j += length
  937. return res
  938. ll_inplace_mul.oopspec = 'list.inplace_mul(l, factor)'
  939. @jit.look_inside_iff(lambda _, l, factor: jit.isvirtual(l) and
  940. jit.isconstant(factor) and factor < 10)
  941. def ll_mul(RESLIST, l, factor):
  942. length = l.ll_length()
  943. if factor < 0:
  944. factor = 0
  945. try:
  946. resultlen = ovfcheck(length * factor)
  947. except OverflowError:
  948. raise MemoryError
  949. res = RESLIST.ll_newlist(resultlen)
  950. j = 0
  951. while j < resultlen:
  952. ll_arraycopy(l, res, 0, j, length)
  953. j += length
  954. return res
  955. # not inlined by the JIT -- contains a loop