PageRenderTime 32ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/objspace/std/listobject.py

https://bitbucket.org/pypy/pypy/
Python | 2182 lines | 2104 code | 53 blank | 25 comment | 42 complexity | dea1d5e21f252fdb2cef507b73756299 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """The builtin list implementation
  2. Lists optimize their storage by holding certain primitive datatypes in
  3. unwrapped form. For more information:
  4. http://morepypy.blogspot.com/2011/10/more-compact-lists-with-list-strategies.html
  5. """
  6. import operator
  7. import sys
  8. from rpython.rlib import debug, jit, rerased
  9. from rpython.rlib.listsort import make_timsort_class
  10. from rpython.rlib.objectmodel import (
  11. import_from_mixin, instantiate, newlist_hint, resizelist_hint, specialize)
  12. from rpython.rlib import longlong2float
  13. from rpython.tool.sourcetools import func_with_new_name
  14. from pypy.interpreter.baseobjspace import W_Root
  15. from pypy.interpreter.error import OperationError, oefmt
  16. from pypy.interpreter.gateway import (
  17. WrappedDefault, applevel, interp2app, unwrap_spec)
  18. from pypy.interpreter.generator import GeneratorIterator
  19. from pypy.interpreter.signature import Signature
  20. from pypy.interpreter.typedef import TypeDef
  21. from pypy.objspace.std.bytesobject import W_BytesObject
  22. from pypy.objspace.std.floatobject import W_FloatObject
  23. from pypy.objspace.std.intobject import W_IntObject
  24. from pypy.objspace.std.iterobject import (
  25. W_FastListIterObject, W_ReverseSeqIterObject)
  26. from pypy.objspace.std.sliceobject import (
  27. W_SliceObject, normalize_simple_slice, unwrap_start_stop)
  28. from pypy.objspace.std.tupleobject import W_AbstractTupleObject
  29. from pypy.objspace.std.unicodeobject import W_UnicodeObject
  30. from pypy.objspace.std.util import get_positive_index, negate
  31. __all__ = ['W_ListObject', 'make_range_list', 'make_empty_list_with_size']
  32. UNROLL_CUTOFF = 5
  33. def make_range_list(space, start, step, length):
  34. if length <= 0:
  35. strategy = space.fromcache(EmptyListStrategy)
  36. storage = strategy.erase(None)
  37. elif start == 0 and step == 1:
  38. strategy = space.fromcache(SimpleRangeListStrategy)
  39. storage = strategy.erase((length,))
  40. else:
  41. strategy = space.fromcache(RangeListStrategy)
  42. storage = strategy.erase((start, step, length))
  43. return W_ListObject.from_storage_and_strategy(space, storage, strategy)
  44. def make_empty_list(space):
  45. strategy = space.fromcache(EmptyListStrategy)
  46. storage = strategy.erase(None)
  47. return W_ListObject.from_storage_and_strategy(space, storage, strategy)
  48. def make_empty_list_with_size(space, hint):
  49. strategy = SizeListStrategy(space, hint)
  50. storage = strategy.erase(None)
  51. return W_ListObject.from_storage_and_strategy(space, storage, strategy)
  52. @jit.look_inside_iff(lambda space, list_w, sizehint:
  53. jit.loop_unrolling_heuristic(list_w, len(list_w), UNROLL_CUTOFF))
  54. def get_strategy_from_list_objects(space, list_w, sizehint):
  55. if not list_w:
  56. if sizehint != -1:
  57. return SizeListStrategy(space, sizehint)
  58. return space.fromcache(EmptyListStrategy)
  59. w_firstobj = list_w[0]
  60. check_int_or_float = False
  61. if type(w_firstobj) is W_IntObject:
  62. # check for all-ints
  63. for i in range(1, len(list_w)):
  64. w_obj = list_w[i]
  65. if type(w_obj) is not W_IntObject:
  66. check_int_or_float = (type(w_obj) is W_FloatObject)
  67. break
  68. else:
  69. return space.fromcache(IntegerListStrategy)
  70. elif type(w_firstobj) is W_BytesObject:
  71. # check for all-strings
  72. for i in range(1, len(list_w)):
  73. if type(list_w[i]) is not W_BytesObject:
  74. break
  75. else:
  76. return space.fromcache(BytesListStrategy)
  77. elif type(w_firstobj) is W_UnicodeObject:
  78. # check for all-unicodes
  79. for i in range(1, len(list_w)):
  80. if type(list_w[i]) is not W_UnicodeObject:
  81. break
  82. else:
  83. return space.fromcache(UnicodeListStrategy)
  84. elif type(w_firstobj) is W_FloatObject:
  85. # check for all-floats
  86. for i in range(1, len(list_w)):
  87. w_obj = list_w[i]
  88. if type(w_obj) is not W_FloatObject:
  89. check_int_or_float = (type(w_obj) is W_IntObject)
  90. break
  91. else:
  92. return space.fromcache(FloatListStrategy)
  93. if check_int_or_float:
  94. for w_obj in list_w:
  95. if type(w_obj) is W_IntObject:
  96. if longlong2float.can_encode_int32(space.int_w(w_obj)):
  97. continue # ok
  98. elif type(w_obj) is W_FloatObject:
  99. if longlong2float.can_encode_float(space.float_w(w_obj)):
  100. continue # ok
  101. break
  102. else:
  103. return space.fromcache(IntOrFloatListStrategy)
  104. return space.fromcache(ObjectListStrategy)
  105. def _get_printable_location(w_type):
  106. return ('list__do_extend_from_iterable [w_type=%s]' %
  107. w_type.getname(w_type.space))
  108. _do_extend_jitdriver = jit.JitDriver(
  109. name='list__do_extend_from_iterable',
  110. greens=['w_type'],
  111. reds=['i', 'w_iterator', 'w_list'],
  112. get_printable_location=_get_printable_location)
  113. def _do_extend_from_iterable(space, w_list, w_iterable):
  114. w_iterator = space.iter(w_iterable)
  115. w_type = space.type(w_iterator)
  116. i = 0
  117. while True:
  118. _do_extend_jitdriver.jit_merge_point(w_type=w_type,
  119. i=i,
  120. w_iterator=w_iterator,
  121. w_list=w_list)
  122. try:
  123. w_list.append(space.next(w_iterator))
  124. except OperationError as e:
  125. if not e.match(space, space.w_StopIteration):
  126. raise
  127. break
  128. i += 1
  129. return i
  130. def list_unroll_condition(w_list1, space, w_list2):
  131. return (jit.loop_unrolling_heuristic(w_list1, w_list1.length(),
  132. UNROLL_CUTOFF) or
  133. jit.loop_unrolling_heuristic(w_list2, w_list2.length(),
  134. UNROLL_CUTOFF))
  135. class W_ListObject(W_Root):
  136. strategy = None
  137. def __init__(self, space, wrappeditems, sizehint=-1):
  138. assert isinstance(wrappeditems, list)
  139. self.space = space
  140. if space.config.objspace.std.withliststrategies:
  141. self.strategy = get_strategy_from_list_objects(space, wrappeditems,
  142. sizehint)
  143. else:
  144. self.strategy = space.fromcache(ObjectListStrategy)
  145. self.init_from_list_w(wrappeditems)
  146. @staticmethod
  147. def from_storage_and_strategy(space, storage, strategy):
  148. self = instantiate(W_ListObject)
  149. self.space = space
  150. self.strategy = strategy
  151. self.lstorage = storage
  152. if not space.config.objspace.std.withliststrategies:
  153. self.switch_to_object_strategy()
  154. return self
  155. @staticmethod
  156. def newlist_bytes(space, list_b):
  157. strategy = space.fromcache(BytesListStrategy)
  158. storage = strategy.erase(list_b)
  159. return W_ListObject.from_storage_and_strategy(space, storage, strategy)
  160. @staticmethod
  161. def newlist_unicode(space, list_u):
  162. strategy = space.fromcache(UnicodeListStrategy)
  163. storage = strategy.erase(list_u)
  164. return W_ListObject.from_storage_and_strategy(space, storage, strategy)
  165. @staticmethod
  166. def newlist_int(space, list_i):
  167. strategy = space.fromcache(IntegerListStrategy)
  168. storage = strategy.erase(list_i)
  169. return W_ListObject.from_storage_and_strategy(space, storage, strategy)
  170. @staticmethod
  171. def newlist_float(space, list_f):
  172. strategy = space.fromcache(FloatListStrategy)
  173. storage = strategy.erase(list_f)
  174. return W_ListObject.from_storage_and_strategy(space, storage, strategy)
  175. @staticmethod
  176. def newlist_cpyext(space, list):
  177. from pypy.module.cpyext.sequence import CPyListStrategy, CPyListStorage
  178. strategy = space.fromcache(CPyListStrategy)
  179. storage = strategy.erase(CPyListStorage(space, list))
  180. return W_ListObject.from_storage_and_strategy(space, storage, strategy)
  181. def __repr__(self):
  182. """ representation for debugging purposes """
  183. return "%s(%s, %s)" % (self.__class__.__name__, self.strategy,
  184. self.lstorage._x)
  185. def unwrap(w_list, space):
  186. # for tests only!
  187. items = [space.unwrap(w_item) for w_item in w_list.getitems()]
  188. return list(items)
  189. def switch_to_object_strategy(self):
  190. list_w = self.getitems()
  191. object_strategy = self.space.fromcache(ObjectListStrategy)
  192. self.strategy = object_strategy
  193. object_strategy.init_from_list_w(self, list_w)
  194. def ensure_object_strategy(self): # for cpyext
  195. if self.strategy is not self.space.fromcache(ObjectListStrategy):
  196. self.switch_to_object_strategy()
  197. def _temporarily_as_objects(self):
  198. if self.strategy is self.space.fromcache(ObjectListStrategy):
  199. return self
  200. list_w = self.getitems()
  201. strategy = self.space.fromcache(ObjectListStrategy)
  202. storage = strategy.erase(list_w)
  203. w_objectlist = W_ListObject.from_storage_and_strategy(
  204. self.space, storage, strategy)
  205. return w_objectlist
  206. def convert_to_cpy_strategy(self, space):
  207. from pypy.module.cpyext.sequence import CPyListStorage, CPyListStrategy
  208. cpy_strategy = self.space.fromcache(CPyListStrategy)
  209. if self.strategy is cpy_strategy:
  210. return
  211. lst = self.getitems()
  212. self.strategy = cpy_strategy
  213. self.lstorage = cpy_strategy.erase(CPyListStorage(space, lst))
  214. def get_raw_items(self):
  215. from pypy.module.cpyext.sequence import CPyListStrategy
  216. cpy_strategy = self.space.fromcache(CPyListStrategy)
  217. assert self.strategy is cpy_strategy # should we return an error?
  218. return cpy_strategy.get_raw_items(self)
  219. # ___________________________________________________
  220. def init_from_list_w(self, list_w):
  221. """Initializes listobject by iterating through the given list of
  222. wrapped items, unwrapping them if neccessary and creating a
  223. new erased object as storage"""
  224. self.strategy.init_from_list_w(self, list_w)
  225. def clear(self, space):
  226. """Initializes (or overrides) the listobject as empty."""
  227. self.space = space
  228. if space.config.objspace.std.withliststrategies:
  229. strategy = space.fromcache(EmptyListStrategy)
  230. else:
  231. strategy = space.fromcache(ObjectListStrategy)
  232. self.strategy = strategy
  233. strategy.clear(self)
  234. def clone(self):
  235. """Returns a clone by creating a new listobject
  236. with the same strategy and a copy of the storage"""
  237. return self.strategy.clone(self)
  238. def _resize_hint(self, hint):
  239. """Ensure the underlying list has room for at least hint
  240. elements without changing the len() of the list"""
  241. return self.strategy._resize_hint(self, hint)
  242. def copy_into(self, other):
  243. """Used only when extending an EmptyList. Sets the EmptyLists
  244. strategy and storage according to the other W_List"""
  245. self.strategy.copy_into(self, other)
  246. def find(self, w_item, start=0, end=sys.maxint):
  247. """Find w_item in list[start:end]. If not found, raise ValueError"""
  248. return self.strategy.find(self, w_item, start, end)
  249. def append(self, w_item):
  250. """L.append(object) -- append object to end"""
  251. self.strategy.append(self, w_item)
  252. def length(self):
  253. return self.strategy.length(self)
  254. def getitem(self, index):
  255. """Returns the wrapped object that is found in the
  256. list at the given index. The index must be unwrapped.
  257. May raise IndexError."""
  258. return self.strategy.getitem(self, index)
  259. def getslice(self, start, stop, step, length):
  260. """Returns a slice of the list defined by the arguments. Arguments must
  261. be normalized (i.e. using normalize_simple_slice or W_Slice.indices4).
  262. May raise IndexError."""
  263. return self.strategy.getslice(self, start, stop, step, length)
  264. def getitems(self):
  265. """Returns a list of all items after wrapping them. The result can
  266. share with the storage, if possible."""
  267. return self.strategy.getitems(self)
  268. def getitems_fixedsize(self):
  269. """Returns a fixed-size list of all items after wrapping them."""
  270. l = self.strategy.getitems_fixedsize(self)
  271. debug.make_sure_not_resized(l)
  272. return l
  273. def getitems_unroll(self):
  274. """Returns a fixed-size list of all items after wrapping them. The JIT
  275. will fully unroll this function."""
  276. l = self.strategy.getitems_unroll(self)
  277. debug.make_sure_not_resized(l)
  278. return l
  279. def getitems_copy(self):
  280. """Returns a copy of all items in the list. Same as getitems except for
  281. ObjectListStrategy."""
  282. return self.strategy.getitems_copy(self)
  283. def getitems_bytes(self):
  284. """Return the items in the list as unwrapped strings. If the list does
  285. not use the list strategy, return None."""
  286. return self.strategy.getitems_bytes(self)
  287. def getitems_unicode(self):
  288. """Return the items in the list as unwrapped unicodes. If the list does
  289. not use the list strategy, return None."""
  290. return self.strategy.getitems_unicode(self)
  291. def getitems_int(self):
  292. """Return the items in the list as unwrapped ints. If the list does not
  293. use the list strategy, return None."""
  294. return self.strategy.getitems_int(self)
  295. def getitems_float(self):
  296. """Return the items in the list as unwrapped floats. If the list does not
  297. use the list strategy, return None."""
  298. return self.strategy.getitems_float(self)
  299. # ___________________________________________________
  300. def mul(self, times):
  301. """Returns a copy of the list, multiplied by times.
  302. Argument must be unwrapped."""
  303. return self.strategy.mul(self, times)
  304. def inplace_mul(self, times):
  305. """Alters the list by multiplying its content by times."""
  306. self.strategy.inplace_mul(self, times)
  307. def deleteslice(self, start, step, length):
  308. """Deletes a slice from the list. Used in delitem and delslice.
  309. Arguments must be normalized (see getslice)."""
  310. self.strategy.deleteslice(self, start, step, length)
  311. def pop(self, index):
  312. """Pops an item from the list. Index must be normalized.
  313. May raise IndexError."""
  314. return self.strategy.pop(self, index)
  315. def pop_end(self):
  316. """ Pop the last element from the list."""
  317. return self.strategy.pop_end(self)
  318. def setitem(self, index, w_item):
  319. """Inserts a wrapped item at the given (unwrapped) index.
  320. May raise IndexError."""
  321. self.strategy.setitem(self, index, w_item)
  322. def setslice(self, start, step, slicelength, sequence_w):
  323. """Sets the slice of the list from start to start+step*slicelength to
  324. the sequence sequence_w.
  325. Used by setslice and setitem."""
  326. self.strategy.setslice(self, start, step, slicelength, sequence_w)
  327. def insert(self, index, w_item):
  328. """Inserts an item at the given position. Item must be wrapped,
  329. index not."""
  330. self.strategy.insert(self, index, w_item)
  331. def extend(self, w_iterable):
  332. '''L.extend(iterable) -- extend list by appending
  333. elements from the iterable'''
  334. self.strategy.extend(self, w_iterable)
  335. def reverse(self):
  336. """Reverses the list."""
  337. self.strategy.reverse(self)
  338. def sort(self, reverse):
  339. """Sorts the list ascending or descending depending on
  340. argument reverse. Argument must be unwrapped."""
  341. self.strategy.sort(self, reverse)
  342. # exposed to app-level
  343. @staticmethod
  344. def descr_new(space, w_listtype, __args__):
  345. """T.__new__(S, ...) -> a new object with type S, a subtype of T"""
  346. w_obj = space.allocate_instance(W_ListObject, w_listtype)
  347. w_obj.clear(space)
  348. return w_obj
  349. def descr_init(self, space, __args__):
  350. """x.__init__(...) initializes x; see help(type(x)) for signature"""
  351. # this is on the silly side
  352. w_iterable, = __args__.parse_obj(
  353. None, 'list', init_signature, init_defaults)
  354. self.clear(space)
  355. if w_iterable is not None:
  356. self.extend(w_iterable)
  357. def descr_repr(self, space):
  358. if self.length() == 0:
  359. return space.wrap('[]')
  360. ec = space.getexecutioncontext()
  361. w_currently_in_repr = ec._py_repr
  362. if w_currently_in_repr is None:
  363. w_currently_in_repr = ec._py_repr = space.newdict()
  364. return listrepr(space, w_currently_in_repr, self)
  365. def descr_eq(self, space, w_other):
  366. if not isinstance(w_other, W_ListObject):
  367. return space.w_NotImplemented
  368. return self._descr_eq(space, w_other)
  369. @jit.look_inside_iff(list_unroll_condition)
  370. def _descr_eq(self, space, w_other):
  371. # needs to be safe against eq_w() mutating the w_lists behind our back
  372. if self.length() != w_other.length():
  373. return space.w_False
  374. # XXX in theory, this can be implemented more efficiently as well.
  375. # let's not care for now
  376. i = 0
  377. while i < self.length() and i < w_other.length():
  378. if not space.eq_w(self.getitem(i), w_other.getitem(i)):
  379. return space.w_False
  380. i += 1
  381. return space.w_True
  382. descr_ne = negate(descr_eq)
  383. def _make_list_comparison(name):
  384. op = getattr(operator, name)
  385. def compare_unwrappeditems(self, space, w_list2):
  386. if not isinstance(w_list2, W_ListObject):
  387. return space.w_NotImplemented
  388. return _compare_unwrappeditems(self, space, w_list2)
  389. @jit.look_inside_iff(list_unroll_condition)
  390. def _compare_unwrappeditems(self, space, w_list2):
  391. # needs to be safe against eq_w() mutating the w_lists behind our
  392. # back
  393. # Search for the first index where items are different
  394. i = 0
  395. # XXX in theory, this can be implemented more efficiently as well.
  396. # let's not care for now
  397. while i < self.length() and i < w_list2.length():
  398. w_item1 = self.getitem(i)
  399. w_item2 = w_list2.getitem(i)
  400. if not space.eq_w(w_item1, w_item2):
  401. return getattr(space, name)(w_item1, w_item2)
  402. i += 1
  403. # No more items to compare -- compare sizes
  404. return space.newbool(op(self.length(), w_list2.length()))
  405. return func_with_new_name(compare_unwrappeditems, 'descr_' + name)
  406. descr_lt = _make_list_comparison('lt')
  407. descr_le = _make_list_comparison('le')
  408. descr_gt = _make_list_comparison('gt')
  409. descr_ge = _make_list_comparison('ge')
  410. def descr_len(self, space):
  411. result = self.length()
  412. return space.newint(result)
  413. def descr_iter(self, space):
  414. return W_FastListIterObject(self)
  415. def descr_contains(self, space, w_obj):
  416. try:
  417. self.find(w_obj)
  418. return space.w_True
  419. except ValueError:
  420. return space.w_False
  421. def descr_add(self, space, w_list2):
  422. if not isinstance(w_list2, W_ListObject):
  423. return space.w_NotImplemented
  424. w_clone = self.clone()
  425. w_clone.extend(w_list2)
  426. return w_clone
  427. def descr_inplace_add(self, space, w_iterable):
  428. if isinstance(w_iterable, W_ListObject):
  429. self.extend(w_iterable)
  430. return self
  431. try:
  432. self.extend(w_iterable)
  433. except OperationError as e:
  434. if e.match(space, space.w_TypeError):
  435. return space.w_NotImplemented
  436. raise
  437. return self
  438. def descr_mul(self, space, w_times):
  439. try:
  440. times = space.getindex_w(w_times, space.w_OverflowError)
  441. except OperationError as e:
  442. if e.match(space, space.w_TypeError):
  443. return space.w_NotImplemented
  444. raise
  445. return self.mul(times)
  446. def descr_inplace_mul(self, space, w_times):
  447. try:
  448. times = space.getindex_w(w_times, space.w_OverflowError)
  449. except OperationError as e:
  450. if e.match(space, space.w_TypeError):
  451. return space.w_NotImplemented
  452. raise
  453. self.inplace_mul(times)
  454. return self
  455. def descr_getitem(self, space, w_index):
  456. if isinstance(w_index, W_SliceObject):
  457. length = self.length()
  458. start, stop, step, slicelength = w_index.indices4(space, length)
  459. assert slicelength >= 0
  460. if slicelength == 0:
  461. return make_empty_list(space)
  462. return self.getslice(start, stop, step, slicelength)
  463. try:
  464. index = space.getindex_w(w_index, space.w_IndexError, "list index")
  465. return self.getitem(index)
  466. except IndexError:
  467. raise oefmt(space.w_IndexError, "list index out of range")
  468. def descr_getslice(self, space, w_start, w_stop):
  469. length = self.length()
  470. start, stop = normalize_simple_slice(space, length, w_start, w_stop)
  471. slicelength = stop - start
  472. if slicelength == 0:
  473. return make_empty_list(space)
  474. return self.getslice(start, stop, 1, stop - start)
  475. def descr_setitem(self, space, w_index, w_any):
  476. if isinstance(w_index, W_SliceObject):
  477. oldsize = self.length()
  478. start, stop, step, slicelength = w_index.indices4(space, oldsize)
  479. if isinstance(w_any, W_ListObject):
  480. self.setslice(start, step, slicelength, w_any)
  481. else:
  482. sequence_w = space.listview(w_any)
  483. w_other = W_ListObject(space, sequence_w)
  484. self.setslice(start, step, slicelength, w_other)
  485. return
  486. idx = space.getindex_w(w_index, space.w_IndexError, "list index")
  487. try:
  488. self.setitem(idx, w_any)
  489. except IndexError:
  490. raise oefmt(space.w_IndexError, "list index out of range")
  491. def descr_setslice(self, space, w_start, w_stop, w_iterable):
  492. length = self.length()
  493. start, stop = normalize_simple_slice(space, length, w_start, w_stop)
  494. if isinstance(w_iterable, W_ListObject):
  495. self.setslice(start, 1, stop - start, w_iterable)
  496. else:
  497. sequence_w = space.listview(w_iterable)
  498. w_other = W_ListObject(space, sequence_w)
  499. self.setslice(start, 1, stop - start, w_other)
  500. def descr_delitem(self, space, w_idx):
  501. if isinstance(w_idx, W_SliceObject):
  502. start, stop, step, slicelength = w_idx.indices4(
  503. space, self.length())
  504. self.deleteslice(start, step, slicelength)
  505. return
  506. idx = space.getindex_w(w_idx, space.w_IndexError, "list index")
  507. if idx < 0:
  508. idx += self.length()
  509. try:
  510. self.pop(idx)
  511. except IndexError:
  512. raise oefmt(space.w_IndexError, "list index out of range")
  513. def descr_delslice(self, space, w_start, w_stop):
  514. length = self.length()
  515. start, stop = normalize_simple_slice(space, length, w_start, w_stop)
  516. self.deleteslice(start, 1, stop - start)
  517. def descr_reversed(self, space):
  518. 'L.__reversed__() -- return a reverse iterator over the list'
  519. return W_ReverseSeqIterObject(space, self, -1)
  520. def descr_reverse(self, space):
  521. 'L.reverse() -- reverse *IN PLACE*'
  522. self.reverse()
  523. def descr_count(self, space, w_value):
  524. '''L.count(value) -> integer -- return number of
  525. occurrences of value'''
  526. # needs to be safe against eq_w() mutating the w_list behind our back
  527. count = 0
  528. i = 0
  529. while i < self.length():
  530. if space.eq_w(self.getitem(i), w_value):
  531. count += 1
  532. i += 1
  533. return space.wrap(count)
  534. @unwrap_spec(index=int)
  535. def descr_insert(self, space, index, w_value):
  536. 'L.insert(index, object) -- insert object before index'
  537. length = self.length()
  538. index = get_positive_index(index, length)
  539. self.insert(index, w_value)
  540. @unwrap_spec(index=int)
  541. def descr_pop(self, space, index=-1):
  542. '''L.pop([index]) -> item -- remove and return item at
  543. index (default last)'''
  544. length = self.length()
  545. if length == 0:
  546. raise oefmt(space.w_IndexError, "pop from empty list")
  547. # clearly differentiate between list.pop() and list.pop(index)
  548. if index == -1:
  549. return self.pop_end() # cannot raise because list is not empty
  550. if index < 0:
  551. index += length
  552. try:
  553. return self.pop(index)
  554. except IndexError:
  555. raise oefmt(space.w_IndexError, "pop index out of range")
  556. def descr_remove(self, space, w_value):
  557. 'L.remove(value) -- remove first occurrence of value'
  558. # needs to be safe against eq_w() mutating the w_list behind our back
  559. try:
  560. i = self.find(w_value, 0, sys.maxint)
  561. except ValueError:
  562. raise oefmt(space.w_ValueError,
  563. "list.remove(): %R is not in list", w_value)
  564. if i < self.length(): # otherwise list was mutated
  565. self.pop(i)
  566. @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(sys.maxint))
  567. def descr_index(self, space, w_value, w_start, w_stop):
  568. '''L.index(value, [start, [stop]]) -> integer -- return
  569. first index of value'''
  570. # needs to be safe against eq_w() mutating the w_list behind our back
  571. size = self.length()
  572. i, stop = unwrap_start_stop(space, size, w_start, w_stop)
  573. # note that 'i' and 'stop' can be bigger than the length of the list
  574. try:
  575. i = self.find(w_value, i, stop)
  576. except ValueError:
  577. raise oefmt(space.w_ValueError, "%R is not in list", w_value)
  578. return space.wrap(i)
  579. @unwrap_spec(reverse=bool)
  580. def descr_sort(self, space, w_cmp=None, w_key=None, reverse=False):
  581. """ L.sort(cmp=None, key=None, reverse=False) -- stable
  582. sort *IN PLACE*;
  583. cmp(x, y) -> -1, 0, 1"""
  584. has_cmp = not space.is_none(w_cmp)
  585. has_key = not space.is_none(w_key)
  586. # create and setup a TimSort instance
  587. if has_cmp:
  588. if has_key:
  589. sorterclass = CustomKeyCompareSort
  590. else:
  591. sorterclass = CustomCompareSort
  592. else:
  593. if has_key:
  594. sorterclass = CustomKeySort
  595. else:
  596. if self.strategy is space.fromcache(ObjectListStrategy):
  597. sorterclass = SimpleSort
  598. else:
  599. self.sort(reverse)
  600. return
  601. sorter = sorterclass(self.getitems(), self.length())
  602. sorter.space = space
  603. sorter.w_cmp = w_cmp
  604. try:
  605. # The list is temporarily made empty, so that mutations performed
  606. # by comparison functions can't affect the slice of memory we're
  607. # sorting (allowing mutations during sorting is an IndexError or
  608. # core-dump factory, since the storage may change).
  609. self.__init__(space, [])
  610. # wrap each item in a KeyContainer if needed
  611. if has_key:
  612. for i in range(sorter.listlength):
  613. w_item = sorter.list[i]
  614. w_keyitem = space.call_function(w_key, w_item)
  615. sorter.list[i] = KeyContainer(w_keyitem, w_item)
  616. # Reverse sort stability achieved by initially reversing the list,
  617. # applying a stable forward sort, then reversing the final result.
  618. if reverse:
  619. sorter.list.reverse()
  620. # perform the sort
  621. sorter.sort()
  622. # reverse again
  623. if reverse:
  624. sorter.list.reverse()
  625. finally:
  626. # unwrap each item if needed
  627. if has_key:
  628. for i in range(sorter.listlength):
  629. w_obj = sorter.list[i]
  630. if isinstance(w_obj, KeyContainer):
  631. sorter.list[i] = w_obj.w_item
  632. # check if the user mucked with the list during the sort
  633. mucked = self.length() > 0
  634. # put the items back into the list
  635. self.__init__(space, sorter.list)
  636. if mucked:
  637. raise oefmt(space.w_ValueError, "list modified during sort")
  638. find_jmp = jit.JitDriver(greens = ['tp'], reds = 'auto', name = 'list.find')
  639. class ListStrategy(object):
  640. def __init__(self, space):
  641. self.space = space
  642. def get_sizehint(self):
  643. return -1
  644. def init_from_list_w(self, w_list, list_w):
  645. raise NotImplementedError
  646. def clone(self, w_list):
  647. raise NotImplementedError
  648. def copy_into(self, w_list, w_other):
  649. raise NotImplementedError
  650. def _resize_hint(self, w_list, hint):
  651. raise NotImplementedError
  652. def find(self, w_list, w_item, start, stop):
  653. space = self.space
  654. i = start
  655. # needs to be safe against eq_w mutating stuff
  656. tp = space.type(w_item)
  657. while i < stop and i < w_list.length():
  658. find_jmp.jit_merge_point(tp=tp)
  659. if space.eq_w(w_item, w_list.getitem(i)):
  660. return i
  661. i += 1
  662. raise ValueError
  663. def length(self, w_list):
  664. raise NotImplementedError
  665. def getitem(self, w_list, index):
  666. raise NotImplementedError
  667. def getslice(self, w_list, start, stop, step, length):
  668. raise NotImplementedError
  669. def getitems(self, w_list):
  670. return self.getitems_copy(w_list)
  671. def getitems_copy(self, w_list):
  672. raise NotImplementedError
  673. def getitems_bytes(self, w_list):
  674. return None
  675. def getitems_unicode(self, w_list):
  676. return None
  677. def getitems_int(self, w_list):
  678. return None
  679. def getitems_float(self, w_list):
  680. return None
  681. def getstorage_copy(self, w_list):
  682. raise NotImplementedError
  683. def append(self, w_list, w_item):
  684. raise NotImplementedError
  685. def mul(self, w_list, times):
  686. w_newlist = w_list.clone()
  687. w_newlist.inplace_mul(times)
  688. return w_newlist
  689. def inplace_mul(self, w_list, times):
  690. raise NotImplementedError
  691. def deleteslice(self, w_list, start, step, slicelength):
  692. raise NotImplementedError
  693. def pop(self, w_list, index):
  694. raise NotImplementedError
  695. def pop_end(self, w_list):
  696. return self.pop(w_list, self.length(w_list) - 1)
  697. def setitem(self, w_list, index, w_item):
  698. raise NotImplementedError
  699. def setslice(self, w_list, start, step, slicelength, sequence_w):
  700. raise NotImplementedError
  701. def insert(self, w_list, index, w_item):
  702. raise NotImplementedError
  703. def extend(self, w_list, w_any):
  704. if type(w_any) is W_ListObject or (isinstance(w_any, W_ListObject) and
  705. self.space._uses_list_iter(w_any)):
  706. self._extend_from_list(w_list, w_any)
  707. elif isinstance(w_any, GeneratorIterator):
  708. w_any.unpack_into_w(w_list)
  709. else:
  710. self._extend_from_iterable(w_list, w_any)
  711. def _extend_from_list(self, w_list, w_other):
  712. raise NotImplementedError
  713. def _extend_from_iterable(self, w_list, w_iterable):
  714. """Extend w_list from a generic iterable"""
  715. length_hint = self.space.length_hint(w_iterable, 0)
  716. if length_hint:
  717. w_list._resize_hint(w_list.length() + length_hint)
  718. extended = _do_extend_from_iterable(self.space, w_list, w_iterable)
  719. # cut back if the length hint was too large
  720. if extended < length_hint:
  721. w_list._resize_hint(w_list.length())
  722. def reverse(self, w_list):
  723. raise NotImplementedError
  724. def sort(self, w_list, reverse):
  725. raise NotImplementedError
  726. def is_empty_strategy(self):
  727. return False
  728. class EmptyListStrategy(ListStrategy):
  729. """EmptyListStrategy is used when a W_List withouth elements is created.
  730. The storage is None. When items are added to the W_List a new RPython list
  731. is created and the strategy and storage of the W_List are changed depending
  732. to the added item.
  733. W_Lists do not switch back to EmptyListStrategy when becoming empty again.
  734. """
  735. def __init__(self, space):
  736. ListStrategy.__init__(self, space)
  737. def init_from_list_w(self, w_list, list_w):
  738. assert len(list_w) == 0
  739. w_list.lstorage = self.erase(None)
  740. def clear(self, w_list):
  741. w_list.lstorage = self.erase(None)
  742. erase, unerase = rerased.new_erasing_pair("empty")
  743. erase = staticmethod(erase)
  744. unerase = staticmethod(unerase)
  745. def clone(self, w_list):
  746. return W_ListObject.from_storage_and_strategy(
  747. self.space, w_list.lstorage, self)
  748. def copy_into(self, w_list, w_other):
  749. pass
  750. def _resize_hint(self, w_list, hint):
  751. assert hint >= 0
  752. if hint:
  753. w_list.strategy = SizeListStrategy(self.space, hint)
  754. def find(self, w_list, w_item, start, stop):
  755. raise ValueError
  756. def length(self, w_list):
  757. return 0
  758. def getitem(self, w_list, index):
  759. raise IndexError
  760. def getslice(self, w_list, start, stop, step, length):
  761. # will never be called because the empty list case is already caught in
  762. # getslice__List_ANY_ANY and getitem__List_Slice
  763. return W_ListObject(self.space, [])
  764. def getitems(self, w_list):
  765. return []
  766. def getitems_copy(self, w_list):
  767. return []
  768. getitems_fixedsize = func_with_new_name(getitems_copy,
  769. "getitems_fixedsize")
  770. getitems_unroll = getitems_fixedsize
  771. def getstorage_copy(self, w_list):
  772. return self.erase(None)
  773. def switch_to_correct_strategy(self, w_list, w_item):
  774. if type(w_item) is W_IntObject:
  775. strategy = self.space.fromcache(IntegerListStrategy)
  776. elif type(w_item) is W_BytesObject:
  777. strategy = self.space.fromcache(BytesListStrategy)
  778. elif type(w_item) is W_UnicodeObject:
  779. strategy = self.space.fromcache(UnicodeListStrategy)
  780. elif type(w_item) is W_FloatObject:
  781. strategy = self.space.fromcache(FloatListStrategy)
  782. else:
  783. strategy = self.space.fromcache(ObjectListStrategy)
  784. storage = strategy.get_empty_storage(self.get_sizehint())
  785. w_list.strategy = strategy
  786. w_list.lstorage = storage
  787. def append(self, w_list, w_item):
  788. self.switch_to_correct_strategy(w_list, w_item)
  789. w_list.append(w_item)
  790. def inplace_mul(self, w_list, times):
  791. return
  792. def deleteslice(self, w_list, start, step, slicelength):
  793. pass
  794. def pop(self, w_list, index):
  795. # will not be called because IndexError was already raised in
  796. # list_pop__List_ANY
  797. raise IndexError
  798. def setitem(self, w_list, index, w_item):
  799. raise IndexError
  800. def setslice(self, w_list, start, step, slicelength, w_other):
  801. strategy = w_other.strategy
  802. storage = strategy.getstorage_copy(w_other)
  803. w_list.strategy = strategy
  804. w_list.lstorage = storage
  805. def sort(self, w_list, reverse):
  806. return
  807. def insert(self, w_list, index, w_item):
  808. assert index == 0
  809. self.append(w_list, w_item)
  810. def _extend_from_list(self, w_list, w_other):
  811. w_other.copy_into(w_list)
  812. def _extend_from_iterable(self, w_list, w_iterable):
  813. space = self.space
  814. if (isinstance(w_iterable, W_AbstractTupleObject)
  815. and space._uses_tuple_iter(w_iterable)):
  816. w_list.__init__(space, w_iterable.getitems_copy())
  817. return
  818. intlist = space.unpackiterable_int(w_iterable)
  819. if intlist is not None:
  820. w_list.strategy = strategy = space.fromcache(IntegerListStrategy)
  821. w_list.lstorage = strategy.erase(intlist)
  822. return
  823. floatlist = space.unpackiterable_float(w_iterable)
  824. if floatlist is not None:
  825. w_list.strategy = strategy = space.fromcache(FloatListStrategy)
  826. w_list.lstorage = strategy.erase(floatlist)
  827. return
  828. byteslist = space.listview_bytes(w_iterable)
  829. if byteslist is not None:
  830. w_list.strategy = strategy = space.fromcache(BytesListStrategy)
  831. # need to copy because intlist can share with w_iterable
  832. w_list.lstorage = strategy.erase(byteslist[:])
  833. return
  834. unilist = space.listview_unicode(w_iterable)
  835. if unilist is not None:
  836. w_list.strategy = strategy = space.fromcache(UnicodeListStrategy)
  837. # need to copy because intlist can share with w_iterable
  838. w_list.lstorage = strategy.erase(unilist[:])
  839. return
  840. ListStrategy._extend_from_iterable(self, w_list, w_iterable)
  841. def reverse(self, w_list):
  842. pass
  843. def is_empty_strategy(self):
  844. return True
  845. class SizeListStrategy(EmptyListStrategy):
  846. """Like empty, but when modified it'll preallocate the size to sizehint."""
  847. def __init__(self, space, sizehint):
  848. self.sizehint = sizehint
  849. ListStrategy.__init__(self, space)
  850. def get_sizehint(self):
  851. return self.sizehint
  852. def _resize_hint(self, w_list, hint):
  853. assert hint >= 0
  854. self.sizehint = hint
  855. class BaseRangeListStrategy(ListStrategy):
  856. def switch_to_integer_strategy(self, w_list):
  857. items = self._getitems_range(w_list, False)
  858. strategy = w_list.strategy = self.space.fromcache(IntegerListStrategy)
  859. w_list.lstorage = strategy.erase(items)
  860. def wrap(self, intval):
  861. return self.space.wrap(intval)
  862. def unwrap(self, w_int):
  863. return self.space.int_w(w_int)
  864. def init_from_list_w(self, w_list, list_w):
  865. raise NotImplementedError
  866. def clone(self, w_list):
  867. storage = w_list.lstorage # lstorage is tuple, no need to clone
  868. w_clone = W_ListObject.from_storage_and_strategy(self.space, storage,
  869. self)
  870. return w_clone
  871. def _resize_hint(self, w_list, hint):
  872. # XXX: this could be supported
  873. assert hint >= 0
  874. def copy_into(self, w_list, w_other):
  875. w_other.strategy = self
  876. w_other.lstorage = w_list.lstorage
  877. def getitem(self, w_list, i):
  878. return self.wrap(self._getitem_unwrapped(w_list, i))
  879. def getitems_int(self, w_list):
  880. return self._getitems_range(w_list, False)
  881. def getitems_copy(self, w_list):
  882. return self._getitems_range(w_list, True)
  883. def getstorage_copy(self, w_list):
  884. # tuple is immutable
  885. return w_list.lstorage
  886. @jit.dont_look_inside
  887. def getitems_fixedsize(self, w_list):
  888. return self._getitems_range_unroll(w_list, True)
  889. def getitems_unroll(self, w_list):
  890. return self._getitems_range_unroll(w_list, True)
  891. def getslice(self, w_list, start, stop, step, length):
  892. self.switch_to_integer_strategy(w_list)
  893. return w_list.getslice(start, stop, step, length)
  894. def append(self, w_list, w_item):
  895. if type(w_item) is W_IntObject:
  896. self.switch_to_integer_strategy(w_list)
  897. else:
  898. w_list.switch_to_object_strategy()
  899. w_list.append(w_item)
  900. def inplace_mul(self, w_list, times):
  901. self.switch_to_integer_strategy(w_list)
  902. w_list.inplace_mul(times)
  903. def deleteslice(self, w_list, start, step, slicelength):
  904. self.switch_to_integer_strategy(w_list)
  905. w_list.deleteslice(start, step, slicelength)
  906. def setitem(self, w_list, index, w_item):
  907. self.switch_to_integer_strategy(w_list)
  908. w_list.setitem(index, w_item)
  909. def setslice(self, w_list, start, step, slicelength, sequence_w):
  910. self.switch_to_integer_strategy(w_list)
  911. w_list.setslice(start, step, slicelength, sequence_w)
  912. def insert(self, w_list, index, w_item):
  913. self.switch_to_integer_strategy(w_list)
  914. w_list.insert(index, w_item)
  915. def extend(self, w_list, w_any):
  916. self.switch_to_integer_strategy(w_list)
  917. w_list.extend(w_any)
  918. def reverse(self, w_list):
  919. self.switch_to_integer_strategy(w_list)
  920. w_list.reverse()
  921. def sort(self, w_list, reverse):
  922. step = self.step(w_list)
  923. if step > 0 and reverse or step < 0 and not reverse:
  924. self.switch_to_integer_strategy(w_list)
  925. w_list.sort(reverse)
  926. class SimpleRangeListStrategy(BaseRangeListStrategy):
  927. """SimpleRangeListStrategy is used when a list is created using the range
  928. method providing only positive length. The storage is a one element tuple
  929. with positive integer storing length."""
  930. erase, unerase = rerased.new_erasing_pair("simple_range")
  931. erase = staticmethod(erase)
  932. unerase = staticmethod(unerase)
  933. def find(self, w_list, w_obj, startindex, stopindex):
  934. if type(w_obj) is W_IntObject:
  935. obj = self.unwrap(w_obj)
  936. length = self.unerase(w_list.lstorage)[0]
  937. if 0 <= obj < length and startindex <= obj < stopindex:
  938. return obj
  939. else:
  940. raise ValueError
  941. return ListStrategy.find(self, w_list, w_obj, startindex, stopindex)
  942. def length(self, w_list):
  943. return self.unerase(w_list.lstorage)[0]
  944. def step(self, w_list):
  945. return 1
  946. def _getitem_unwrapped(self, w_list, i):
  947. length = self.unerase(w_list.lstorage)[0]
  948. if i < 0:
  949. i += length
  950. if i < 0:
  951. raise IndexError
  952. elif i >= length:
  953. raise IndexError
  954. return i
  955. @specialize.arg(2)
  956. def _getitems_range(self, w_list, wrap_items):
  957. length = self.unerase(w_list.lstorage)[0]
  958. if wrap_items:
  959. r = [None] * length
  960. else:
  961. r = [0] * length
  962. i = 0
  963. while i < length:
  964. if wrap_items:
  965. r[i] = self.wrap(i)
  966. else:
  967. r[i] = i
  968. i += 1
  969. return r
  970. _getitems_range_unroll = jit.unroll_safe(
  971. func_with_new_name(_getitems_range, "_getitems_range_unroll"))
  972. def pop_end(self, w_list):
  973. new_length = self.unerase(w_list.lstorage)[0] - 1
  974. w_result = self.wrap(new_length)
  975. if new_length > 0:
  976. w_list.lstorage = self.erase((new_length,))
  977. else:
  978. strategy = w_list.strategy = self.space.fromcache(EmptyListStrategy)
  979. w_list.lstorage = strategy.erase(None)
  980. return w_result
  981. def pop(self, w_list, index):
  982. self.switch_to_integer_strategy(w_list)
  983. return w_list.pop(index)
  984. class RangeListStrategy(BaseRangeListStrategy):
  985. """RangeListStrategy is used when a list is created using the range method.
  986. The storage is a tuple containing only three integers start, step and
  987. length and elements are calculated based on these values. On any operation
  988. destroying the range (inserting, appending non-ints) the strategy is
  989. switched to IntegerListStrategy."""
  990. erase, unerase = rerased.new_erasing_pair("range")
  991. erase = staticmethod(erase)
  992. unerase = staticmethod(unerase)
  993. def find(self, w_list, w_obj, startindex, stopindex):
  994. if type(w_obj) is W_IntObject:
  995. obj = self.unwrap(w_obj)
  996. start, step, length = self.unerase(w_list.lstorage)
  997. if ((step > 0 and start <= obj <= start + (length - 1) * step and
  998. (start - obj) % step == 0) or
  999. (step < 0 and start + (length - 1) * step <= obj <= start and
  1000. (start - obj) % step == 0)):
  1001. index = (obj - start) // step
  1002. else:
  1003. raise ValueError
  1004. if startindex <= index < stopindex:
  1005. return index
  1006. raise ValueError
  1007. return ListStrategy.find(self, w_list, w_obj, startindex, stopindex)
  1008. def length(self, w_list):
  1009. return self.unerase(w_list.lstorage)[2]
  1010. def step(self, w_list):
  1011. return self.unerase(w_list.lstorage)[1]
  1012. def _getitem_unwrapped(self, w_list, i):
  1013. v = self.unerase(w_list.lstorage)
  1014. start = v[0]
  1015. step = v[1]
  1016. length = v[2]
  1017. if i < 0:
  1018. i += length
  1019. if i < 0:
  1020. raise IndexError
  1021. elif i >= length:
  1022. raise IndexError
  1023. return start + i * step
  1024. @specialize.arg(2)
  1025. def _getitems_range(self, w_list, wrap_items):
  1026. l = self.unerase(w_list.lstorage)
  1027. start = l[0]
  1028. step = l[1]
  1029. length = l[2]
  1030. if wrap_items:
  1031. r = [None] * length
  1032. else:
  1033. r = [0] * length
  1034. i = start
  1035. n = 0
  1036. while n < length:
  1037. if wrap_items:
  1038. r[n] = self.wrap(i)
  1039. else:
  1040. r[n] = i
  1041. i += step
  1042. n += 1
  1043. return r
  1044. _getitems_range_unroll = jit.unroll_safe(
  1045. func_with_new_name(_getitems_range, "_getitems_range_unroll"))
  1046. def pop_end(self, w_list):
  1047. start, step, length = self.unerase(w_list.lstorage)
  1048. w_result = self.wrap(start + (length - 1) * step)
  1049. new = self.erase((start, step, length - 1))
  1050. w_list.lstorage = new
  1051. return w_result
  1052. def pop(self, w_list, index):
  1053. l = self.unerase(w_list.lstorage)
  1054. start = l[0]
  1055. step = l[1]
  1056. length = l[2]
  1057. if index == 0:
  1058. w_result = self.wrap(start)
  1059. new = self.erase((start + step, step, length - 1))
  1060. w_list.lstorage = new
  1061. return w_result
  1062. elif index == length - 1:
  1063. return self.pop_end(w_list)
  1064. else:
  1065. self.switch_to_integer_strategy(w_list)
  1066. return w_list.pop(index)
  1067. class AbstractUnwrappedStrategy(object):
  1068. def wrap(self, unwrapped):
  1069. raise NotImplementedError
  1070. def unwrap(self, wrapped):
  1071. raise NotImplementedError
  1072. @staticmethod
  1073. def unerase(storage):
  1074. raise NotImplementedError("abstract base class")
  1075. @staticmethod
  1076. def erase(obj):
  1077. raise NotImplementedError("abstract base class")
  1078. def is_correct_type(self, w_obj):
  1079. raise NotImplementedError("abstract base class")
  1080. def list_is_correct_type(self, w_list):
  1081. raise NotImplementedError("abstract base class")
  1082. @jit.look_inside_iff(lambda space, w_list, list_w:
  1083. jit.loop_unrolling_heuristic(list_w, len(list_w), UNROLL_CUTOFF))
  1084. def init_from_list_w(self, w_list, list_w):
  1085. l = [self.unwrap(w_item) for w_item in list_w]
  1086. w_list.lstorage = self.erase(l)
  1087. def get_empty_storage(self, sizehint):
  1088. if sizehint == -1:
  1089. return self.erase([])
  1090. return self.erase(newlist_hint(sizehint))
  1091. def clone(self, w_list):
  1092. l = self.unerase(w_list.lstorage)
  1093. storage = self.erase(l[:])
  1094. w_clone = W_ListObject.from_storage_and_strategy(
  1095. self.space, storage, self)
  1096. return w_clone
  1097. def _resize_hint(self, w_list, hint):
  1098. resizelist_hint(self.unerase(w_list.lstorage), hint)
  1099. def copy_into(self, w_list, w_other):
  1100. w_other.strategy = self
  1101. items = self.unerase(w_list.lstorage)[:]
  1102. w_other.lstorage = self.erase(items)
  1103. def find(self, w_list, w_obj, start, stop):
  1104. if self.is_correct_type(w_obj):
  1105. return self._safe_find(w_list, self.unwrap(w_obj), start, stop)
  1106. return ListStrategy.find(self, w_list, w_obj, start, stop)
  1107. def _safe_find(self, w_list, obj, start, stop):
  1108. l = self.unerase(w_list.lstorage)
  1109. for i in range(start, min(stop, len(l))):
  1110. val = l[i]
  1111. if val == obj:
  1112. return i
  1113. raise ValueError
  1114. def length(self, w_list):
  1115. return len(self.unerase(w_list.lstorage))
  1116. def getitem(self, w_list, index):
  1117. l = self.unerase(w_list.lstorage)
  1118. try:
  1119. r = l[index]
  1120. except IndexError: # make RPython raise the exception
  1121. raise
  1122. return self.wrap(r)
  1123. @jit.look_inside_iff(lambda self, w_list:
  1124. jit.loop_unrolling_heuristic(w_list, w_list.length(),
  1125. UNROLL_CUTOFF))
  1126. def getitems_copy(self, w_list):
  1127. return [self.wrap(item) for item in self.unerase(w_list.lstorage)]
  1128. @jit.unroll_safe
  1129. def getitems_unroll(self, w_list):
  1130. return [self.wrap(item) for item in self.unerase(w_list.lstorage)]
  1131. @jit.look_inside_iff(lambda self, w_list:
  1132. jit.loop_unrolling_heuristic(w_list, w_list.length(),
  1133. UNROLL_CUTOFF))
  1134. def getitems_fixedsize(self, w_list):
  1135. return self.getitems_unroll(w_list)
  1136. def getstorage_copy(self, w_list):
  1137. items = self.unerase(w_list.lstorage)[:]
  1138. return self.erase(items)
  1139. def getslice(self, w_list, start, stop, step, length):
  1140. if step == 1 and 0 <= start <= stop:
  1141. l = self.unerase(w_list.lstorage)
  1142. assert start >= 0
  1143. assert stop >= 0
  1144. sublist = l[start:stop]
  1145. storage = self.erase(sublist)
  1146. return W_ListObject.from_storage_and_strategy(
  1147. self.space, storage, self)
  1148. else:
  1149. subitems_w = [self._none_value] * length
  1150. l = self.unerase(w_list.lstorage)
  1151. self._fill_in_with_sliced_items(subitems_w, l, start, step, length)
  1152. storage = self.erase(subitems_w)
  1153. return W_ListObject.from_storage_and_strategy(
  1154. self.space, storage, self)
  1155. def _fill_in_with_sliced_items(self, subitems_w, l, start, step, length):
  1156. for i in range(length):
  1157. try:
  1158. subitems_w[i] = l[start]
  1159. start += step
  1160. except IndexError:
  1161. raise
  1162. def switch_to_next_strategy(self, w_list, w_sample_item):
  1163. w_list.switch_to_object_strategy()
  1164. def append(self, w_list, w_item):
  1165. if self.is_correct_type(w_item):
  1166. self.unerase(w_list.lstorage).append(self.unwrap(w_item))
  1167. return
  1168. self.switch_to_next_strategy(w_list, w_item)
  1169. w_list.append(w_item)
  1170. def insert(self, w_list, index, w_item):
  1171. l = self.unerase(w_list.lstorage)
  1172. if self.is_correct_type(w_item):
  1173. l.insert(index, self.unwrap(w_item))
  1174. return
  1175. self.switch_to_next_strategy(w_list, w_item)
  1176. w_list.insert(index, w_item)
  1177. def _extend_from_list(self, w_list, w_other):
  1178. l = self.unerase(w_list.lstorage)
  1179. if self.list_is_correct_type(w_other):
  1180. l += self.unerase(w_other.lstorage)
  1181. return
  1182. elif w_other.strategy.is_empty_strategy():
  1183. return
  1184. w_other = w_other._temporarily_as_objects()
  1185. w_list.switch_to_object_strategy()
  1186. w_list.extend(w_other)
  1187. def setitem(self, w_list, index, w_item):
  1188. l = self.unerase(w_list.lstorage)
  1189. if self.is_correct_type(w_item):
  1190. try:
  1191. l[index] = self.unwrap(w_item)
  1192. except IndexError:
  1193. raise
  1194. else:
  1195. self.switch_to_next_strategy(w_list, w_item)
  1196. w_list.setitem(index, w_item)
  1197. def setslice(self, w_list, start, step, slicelength, w_other):
  1198. assert slicelength >= 0
  1199. space = self.space
  1200. if self is space.fromcache(ObjectListStrategy):
  1201. w_other = w_other._temporarily_as_objects()
  1202. elif not self.list_is_correct_type(w_other) and w_other.length() != 0:
  1203. w_list.switch_to_object_strategy()
  1204. w_other_as_object = w_other._temporarily_as_objects()
  1205. assert (w_other_as_object.strategy is
  1206. space.fromcache(ObjectListStrategy))
  1207. w_list.setslice(start, step, slicelength, w_other_as_object)
  1208. return
  1209. items = self.unerase(w_list.lstorage)
  1210. oldsize = len(items)
  1211. len2 = w_other.length()
  1212. if step == 1: # Support list resizing for non-extended slices
  1213. delta = slicelength - len2
  1214. if delta < 0:
  1215. delta = -delta
  1216. newsize = oldsize + delta
  1217. # XXX support this in rlist!
  1218. items += [self._none_value] * delta
  1219. lim = start + len2
  1220. i = newsize - 1
  1221. while i >= lim:
  1222. items[i] = items[i - delta]
  1223. i -= 1
  1224. elif delta == 0:
  1225. pass
  1226. else:
  1227. # start < 0 is only possible with slicelength == 0
  1228. assert start >= 0
  1229. del items[start:start + delta]
  1230. elif len2 != slicelength: # No resize for extended slices
  1231. raise oefmt(space.w_ValueError,
  1232. "attempt to assign sequence of size %d to extended "
  1233. "slice of size %d", len2, slicelength)
  1234. if len2 == 0:
  1235. other_items = []
  1236. else:
  1237. # at this point both w_list and w_other have the same type, so
  1238. # self.unerase is valid for both of them
  1239. other_items = self.unerase(w_other.lstorage)
  1240. if other_items is items:
  1241. if step > 0:
  1242. # Always copy starting from the right to avoid
  1243. # having to make a shallow copy in the case where
  1244. # the source and destination lists are the same list.
  1245. i = len2 - 1
  1246. start += i * step
  1247. while i >= 0:
  1248. items[start] = other_items[i]
  1249. start -= step
  1250. i -= 1
  1251. return
  1252. else:
  1253. # Make a shallow copy to more easily handle the reversal case
  1254. w_list.reverse()
  1255. return
  1256. #other_items = list(other_items)
  1257. for i in range(len2):
  1258. items[start] = other_items[i]
  1259. start += step
  1260. def deleteslice(self, w_list, start, step, slicelength):
  1261. items = self.unerase(w_list.lstorage)
  1262. if slicelength == 0:
  1263. return
  1264. if step < 0:
  1265. start = start + step * (slicelength - 1)
  1266. step = -step
  1267. if step == 1:
  1268. assert start >= 0
  1269. if slicelength > 0:
  1270. del items[start:start + slicelength]
  1271. else:
  1272. n = len(items)
  1273. i = start
  1274. for discard in range(1, slicelength):
  1275. j = i + 1
  1276. i += step
  1277. while j < i:
  1278. items[j - discard] = items[j]
  1279. j += 1
  1280. j = i + 1
  1281. while j < n:
  1282. items[j - slicelength] = items[j]
  1283. j += 1
  1284. start = n - slicelength
  1285. assert start >= 0 # annotator hint
  1286. del items[start:]
  1287. def pop_end(self, w_list):
  1288. l = self.unerase(w_list.lstorage)
  1289. return self.wrap(l.pop())
  1290. def pop(self, w_list, index):
  1291. l = self.unerase(w_list.lstorage)
  1292. # not sure if RPython raises IndexError on pop
  1293. # so check again here
  1294. if index < 0:
  1295. raise IndexError
  1296. try:
  1297. item = l.pop(index)
  1298. except IndexError:
  1299. raise
  1300. w_item = self.wrap(item)
  1301. return w_item
  1302. def mul(self, w_list, times):
  1303. l = self.unerase(w_list.lstorage)
  1304. return W_ListObject.from_storage_and_strategy(
  1305. self.space, self.erase(l * times), self)
  1306. def inplace_mul(self, w_list, times):
  1307. l = self.unerase(w_list.lstorage)
  1308. l *= times
  1309. def reverse(self, w_list):
  1310. self.unerase(w_list.lstorage).reverse()
  1311. class ObjectListStrategy(ListStrategy):
  1312. import_from_mixin(AbstractUnwrappedStrategy)
  1313. _none_value = None
  1314. def unwrap(self, w_obj):
  1315. return w_obj
  1316. def wrap(self, item):
  1317. return item
  1318. erase, unerase = rerased.new_erasing_pair("object")
  1319. erase = staticmethod(erase)
  1320. unerase = staticmethod(unerase)
  1321. def is_correct_type(self, w_obj):
  1322. return True
  1323. def list_is_correct_type(self, w_list):
  1324. return w_list.strategy is self.space.fromcache(ObjectListStrategy)
  1325. def init_from_list_w(self, w_list, list_w):
  1326. w_list.lstorage = self.erase(list_w)
  1327. def clear(self, w_list):
  1328. w_list.lstorage = self.erase([])
  1329. def find(self, w_list, w_obj, start, stop):
  1330. return ListStrategy.find(self, w_list, w_obj, start, stop)
  1331. def getitems(self, w_list):
  1332. return self.unerase(w_list.lstorage)
  1333. # no sort() method here: W_ListObject.descr_sort() handles this
  1334. # case explicitly
  1335. class IntegerListStrategy(ListStrategy):
  1336. import_from_mixin(AbstractUnwrappedStrategy)
  1337. _none_value = 0
  1338. def wrap(self, intval):
  1339. return self.space.wrap(intval)
  1340. def unwrap(self, w_int):
  1341. return self.space.int_w(w_int)
  1342. erase, unerase = rerased.new_erasing_pair("integer")
  1343. erase = staticmethod(erase)
  1344. unerase = staticmethod(unerase)
  1345. def is_correct_type(self, w_obj):
  1346. return type(w_obj) is W_IntObject
  1347. def list_is_correct_type(self, w_list):
  1348. return w_list.strategy is self.space.fromcache(IntegerListStrategy)
  1349. def sort(self, w_list, reverse):
  1350. l = self.unerase(w_list.lstorage)
  1351. sorter = IntSort(l, len(l))
  1352. sorter.sort()
  1353. if reverse:
  1354. l.reverse()
  1355. def getitems_int(self, w_list):
  1356. return self.unerase(w_list.lstorage)
  1357. _base_extend_from_list = _extend_from_list
  1358. def _extend_from_list(self, w_list, w_other):
  1359. if isinstance(w_other.strategy, BaseRangeListStrategy):
  1360. l = self.unerase(w_list.lstorage)
  1361. other = w_other.getitems_int()
  1362. assert other is not None
  1363. l += other
  1364. return
  1365. if (w_other.strategy is self.space.fromcache(FloatListStrategy) or
  1366. w_other.strategy is self.space.fromcache(IntOrFloatListStrategy)):
  1367. if self.switch_to_int_or_float_strategy(w_list):
  1368. w_list.extend(w_other)
  1369. return
  1370. return self._base_extend_from_list(w_list, w_other)
  1371. _base_setslice = setslice
  1372. def setslice(self, w_list, start, step, slicelength, w_other):
  1373. if w_other.strategy is self.space.fromcache(RangeListStrategy):
  1374. storage = self.erase(w_other.getitems_int())
  1375. w_other = W_ListObject.from_storage_and_strategy(
  1376. self.space, storage, self)
  1377. if (w_other.strategy is self.space.fromcache(FloatListStrategy) or
  1378. w_other.strategy is self.space.fromcache(IntOrFloatListStrategy)):
  1379. if self.switch_to_int_or_float_strategy(w_list):
  1380. w_list.setslice(start, step, slicelength, w_other)
  1381. return
  1382. return self._base_setslice(w_list, start, step, slicelength, w_other)
  1383. @staticmethod
  1384. def int_2_float_or_int(w_list):
  1385. l = IntegerListStrategy.unerase(w_list.lstorage)
  1386. if not longlong2float.CAN_ALWAYS_ENCODE_INT32:
  1387. for intval in l:
  1388. if not longlong2float.can_encode_int32(intval):
  1389. raise ValueError
  1390. return [longlong2float.encode_int32_into_longlong_nan(intval)
  1391. for intval in l]
  1392. def switch_to_int_or_float_strategy(self, w_list):
  1393. try:
  1394. generalized_list = self.int_2_float_or_int(w_list)
  1395. except ValueError:
  1396. return False
  1397. strategy = self.space.fromcache(IntOrFloatListStrategy)
  1398. w_list.strategy = strategy
  1399. w_list.lstorage = strategy.erase(generalized_list)
  1400. return True
  1401. def switch_to_next_strategy(self, w_list, w_sample_item):
  1402. if type(w_sample_item) is W_FloatObject:
  1403. if self.switch_to_int_or_float_strategy(w_list):
  1404. # yes, we can switch to IntOrFloatListStrategy
  1405. # (ignore here the extremely unlikely case where
  1406. # w_sample_item is just the wrong nonstandard NaN float;
  1407. # it will caught later and yet another switch will occur)
  1408. return
  1409. # no, fall back to ObjectListStrategy
  1410. w_list.switch_to_object_strategy()
  1411. class FloatListStrategy(ListStrategy):
  1412. import_from_mixin(AbstractUnwrappedStrategy)
  1413. _none_value = 0.0
  1414. def wrap(self, floatval):
  1415. return self.space.wrap(floatval)
  1416. def unwrap(self, w_float):
  1417. return self.space.float_w(w_float)
  1418. erase, unerase = rerased.new_erasing_pair("float")
  1419. erase = staticmethod(erase)
  1420. unerase = staticmethod(unerase)
  1421. def is_correct_type(self, w_obj):
  1422. return type(w_obj) is W_FloatObject
  1423. def list_is_correct_type(self, w_list):
  1424. return w_list.strategy is self.space.fromcache(FloatListStrategy)
  1425. def sort(self, w_list, reverse):
  1426. l = self.unerase(w_list.lstorage)
  1427. sorter = FloatSort(l, len(l))
  1428. sorter.sort()
  1429. if reverse:
  1430. l.reverse()
  1431. def getitems_float(self, w_list):
  1432. return self.unerase(w_list.lstorage)
  1433. _base_extend_from_list = _extend_from_list
  1434. def _extend_from_list(self, w_list, w_other):
  1435. if (w_other.strategy is self.space.fromcache(IntegerListStrategy) or
  1436. w_other.strategy is self.space.fromcache(IntOrFloatListStrategy)):
  1437. # xxx a case that we don't optimize: [3.4].extend([9999999999999])
  1438. # will cause a switch to int-or-float, followed by another
  1439. # switch to object
  1440. if self.switch_to_int_or_float_strategy(w_list):
  1441. w_list.extend(w_other)
  1442. return
  1443. return self._base_extend_from_list(w_list, w_other)
  1444. _base_setslice = setslice
  1445. def setslice(self, w_list, start, step, slicelength, w_other):
  1446. if (w_other.strategy is self.space.fromcache(IntegerListStrategy) or
  1447. w_other.strategy is self.space.fromcache(IntOrFloatListStrategy)):
  1448. if self.switch_to_int_or_float_strategy(w_list):
  1449. w_list.setslice(start, step, slicelength, w_other)
  1450. return
  1451. return self._base_setslice(w_list, start, step, slicelength, w_other)
  1452. def _safe_find(self, w_list, obj, start, stop):
  1453. from rpython.rlib.rfloat import isnan
  1454. #
  1455. l = self.unerase(w_list.lstorage)
  1456. stop = min(stop, len(l))
  1457. if not isnan(obj):
  1458. for i in range(start, stop):
  1459. val = l[i]
  1460. if val == obj:
  1461. return i
  1462. else:
  1463. search = longlong2float.float2longlong(obj)
  1464. for i in range(start, stop):
  1465. val = l[i]
  1466. if longlong2float.float2longlong(val) == search:
  1467. return i
  1468. raise ValueError
  1469. @staticmethod
  1470. def float_2_float_or_int(w_list):
  1471. l = FloatListStrategy.unerase(w_list.lstorage)
  1472. generalized_list = []
  1473. for floatval in l:
  1474. if not longlong2float.can_encode_float(floatval):
  1475. raise ValueError
  1476. generalized_list.append(
  1477. longlong2float.float2longlong(floatval))
  1478. return generalized_list
  1479. def switch_to_int_or_float_strategy(self, w_list):
  1480. # xxx we should be able to use the same lstorage, but
  1481. # there is a typing issue (float vs longlong)...
  1482. try:
  1483. generalized_list = self.float_2_float_or_int(w_list)
  1484. except ValueError:
  1485. return False
  1486. strategy = self.space.fromcache(IntOrFloatListStrategy)
  1487. w_list.strategy = strategy
  1488. w_list.lstorage = strategy.erase(generalized_list)
  1489. return True
  1490. def switch_to_next_strategy(self, w_list, w_sample_item):
  1491. if type(w_sample_item) is W_IntObject:
  1492. sample_intval = self.space.int_w(w_sample_item)
  1493. if longlong2float.can_encode_int32(sample_intval):
  1494. if self.switch_to_int_or_float_strategy(w_list):
  1495. # yes, we can switch to IntOrFloatListStrategy
  1496. return
  1497. # no, fall back to ObjectListStrategy
  1498. w_list.switch_to_object_strategy()
  1499. class IntOrFloatListStrategy(ListStrategy):
  1500. import_from_mixin(AbstractUnwrappedStrategy)
  1501. _none_value = longlong2float.float2longlong(0.0)
  1502. def wrap(self, llval):
  1503. if longlong2float.is_int32_from_longlong_nan(llval):
  1504. intval = longlong2float.decode_int32_from_longlong_nan(llval)
  1505. return self.space.wrap(intval)
  1506. else:
  1507. floatval = longlong2float.longlong2float(llval)
  1508. return self.space.wrap(floatval)
  1509. def unwrap(self, w_int_or_float):
  1510. if type(w_int_or_float) is W_IntObject:
  1511. intval = self.space.int_w(w_int_or_float)
  1512. return longlong2float.encode_int32_into_longlong_nan(intval)
  1513. else:
  1514. floatval = self.space.float_w(w_int_or_float)
  1515. return longlong2float.float2longlong(floatval)
  1516. erase, unerase = rerased.new_erasing_pair("longlong")
  1517. erase = staticmethod(erase)
  1518. unerase = staticmethod(unerase)
  1519. def is_correct_type(self, w_obj):
  1520. if type(w_obj) is W_IntObject:
  1521. intval = self.space.int_w(w_obj)
  1522. return longlong2float.can_encode_int32(intval)
  1523. elif type(w_obj) is W_FloatObject:
  1524. floatval = self.space.float_w(w_obj)
  1525. return longlong2float.can_encode_float(floatval)
  1526. else:
  1527. return False
  1528. def list_is_correct_type(self, w_list):
  1529. return w_list.strategy is self.space.fromcache(IntOrFloatListStrategy)
  1530. def sort(self, w_list, reverse):
  1531. l = self.unerase(w_list.lstorage)
  1532. sorter = IntOrFloatSort(l, len(l))
  1533. # Reverse sort stability achieved by initially reversing the list,
  1534. # applying a stable forward sort, then reversing the final result.
  1535. if reverse:
  1536. l.reverse()
  1537. sorter.sort()
  1538. if reverse:
  1539. l.reverse()
  1540. _base_extend_from_list = _extend_from_list
  1541. def _extend_longlong(self, w_list, longlong_list):
  1542. l = self.unerase(w_list.lstorage)
  1543. l += longlong_list
  1544. def _extend_from_list(self, w_list, w_other):
  1545. if w_other.strategy is self.space.fromcache(IntegerListStrategy):
  1546. try:
  1547. longlong_list = IntegerListStrategy.int_2_float_or_int(w_other)
  1548. except ValueError:
  1549. pass
  1550. else:
  1551. return self._extend_longlong(w_list, longlong_list)
  1552. if w_other.strategy is self.space.fromcache(FloatListStrategy):
  1553. try:
  1554. longlong_list = FloatListStrategy.float_2_float_or_int(w_other)
  1555. except ValueError:
  1556. pass
  1557. else:
  1558. return self._extend_longlong(w_list, longlong_list)
  1559. return self._base_extend_from_list(w_list, w_other)
  1560. _base_setslice = setslice
  1561. def _temporary_longlong_list(self, longlong_list):
  1562. storage = self.erase(longlong_list)
  1563. return W_ListObject.from_storage_and_strategy(self.space, storage, self)
  1564. def setslice(self, w_list, start, step, slicelength, w_other):
  1565. if w_other.strategy is self.space.fromcache(IntegerListStrategy):
  1566. try:
  1567. longlong_list = IntegerListStrategy.int_2_float_or_int(w_other)
  1568. except ValueError:
  1569. pass
  1570. else:
  1571. w_other = self._temporary_longlong_list(longlong_list)
  1572. elif w_other.strategy is self.space.fromcache(FloatListStrategy):
  1573. try:
  1574. longlong_list = FloatListStrategy.float_2_float_or_int(w_other)
  1575. except ValueError:
  1576. pass
  1577. else:
  1578. w_other = self._temporary_longlong_list(longlong_list)
  1579. return self._base_setslice(w_list, start, step, slicelength, w_other)
  1580. def _safe_find(self, w_list, obj, start, stop):
  1581. l = self.unerase(w_list.lstorage)
  1582. # careful: we must consider that 0.0 == -0.0 == 0, but also
  1583. # NaN == NaN if they have the same bit pattern.
  1584. fobj = longlong2float.maybe_decode_longlong_as_float(obj)
  1585. for i in range(start, min(stop, len(l))):
  1586. llval = l[i]
  1587. if llval == obj: # equal as longlongs: includes NaN == NaN
  1588. return i
  1589. fval = longlong2float.maybe_decode_longlong_as_float(llval)
  1590. if fval == fobj: # cases like 0.0 == -0.0 or 42 == 42.0
  1591. return i
  1592. raise ValueError
  1593. class BytesListStrategy(ListStrategy):
  1594. import_from_mixin(AbstractUnwrappedStrategy)
  1595. _none_value = None
  1596. def wrap(self, stringval):
  1597. return self.space.wrap(stringval)
  1598. def unwrap(self, w_string):
  1599. return self.space.str_w(w_string)
  1600. erase, unerase = rerased.new_erasing_pair("bytes")
  1601. erase = staticmethod(erase)
  1602. unerase = staticmethod(unerase)
  1603. def is_correct_type(self, w_obj):
  1604. return type(w_obj) is W_BytesObject
  1605. def list_is_correct_type(self, w_list):
  1606. return w_list.strategy is self.space.fromcache(BytesListStrategy)
  1607. def sort(self, w_list, reverse):
  1608. l = self.unerase(w_list.lstorage)
  1609. sorter = StringSort(l, len(l))
  1610. sorter.sort()
  1611. if reverse:
  1612. l.reverse()
  1613. def getitems_bytes(self, w_list):
  1614. return self.unerase(w_list.lstorage)
  1615. class UnicodeListStrategy(ListStrategy):
  1616. import_from_mixin(AbstractUnwrappedStrategy)
  1617. _none_value = None
  1618. def wrap(self, stringval):
  1619. return self.space.wrap(stringval)
  1620. def unwrap(self, w_string):
  1621. return self.space.unicode_w(w_string)
  1622. erase, unerase = rerased.new_erasing_pair("unicode")
  1623. erase = staticmethod(erase)
  1624. unerase = staticmethod(unerase)
  1625. def is_correct_type(self, w_obj):
  1626. return type(w_obj) is W_UnicodeObject
  1627. def list_is_correct_type(self, w_list):
  1628. return w_list.strategy is self.space.fromcache(UnicodeListStrategy)
  1629. def sort(self, w_list, reverse):
  1630. l = self.unerase(w_list.lstorage)
  1631. sorter = UnicodeSort(l, len(l))
  1632. sorter.sort()
  1633. if reverse:
  1634. l.reverse()
  1635. def getitems_unicode(self, w_list):
  1636. return self.unerase(w_list.lstorage)
  1637. # _______________________________________________________
  1638. init_signature = Signature(['sequence'], None, None)
  1639. init_defaults = [None]
  1640. app = applevel("""
  1641. def listrepr(currently_in_repr, l):
  1642. 'The app-level part of repr().'
  1643. list_id = id(l)
  1644. if list_id in currently_in_repr:
  1645. return '[...]'
  1646. currently_in_repr[list_id] = 1
  1647. try:
  1648. return "[" + ", ".join([repr(x) for x in l]) + ']'
  1649. finally:
  1650. try:
  1651. del currently_in_repr[list_id]
  1652. except:
  1653. pass
  1654. """, filename=__file__)
  1655. listrepr = app.interphook("listrepr")
  1656. # ____________________________________________________________
  1657. # Sorting
  1658. # Reverse a slice of a list in place, from lo up to (exclusive) hi.
  1659. # (used in sort)
  1660. TimSort = make_timsort_class()
  1661. IntBaseTimSort = make_timsort_class()
  1662. FloatBaseTimSort = make_timsort_class()
  1663. IntOrFloatBaseTimSort = make_timsort_class()
  1664. StringBaseTimSort = make_timsort_class()
  1665. UnicodeBaseTimSort = make_timsort_class()
  1666. class KeyContainer(W_Root):
  1667. def __init__(self, w_key, w_item):
  1668. self.w_key = w_key
  1669. self.w_item = w_item
  1670. # NOTE: all the subclasses of TimSort should inherit from a common subclass,
  1671. # so make sure that only SimpleSort inherits directly from TimSort.
  1672. # This is necessary to hide the parent method TimSort.lt() from the
  1673. # annotator.
  1674. class SimpleSort(TimSort):
  1675. def lt(self, a, b):
  1676. space = self.space
  1677. return space.is_true(space.lt(a, b))
  1678. class IntSort(IntBaseTimSort):
  1679. def lt(self, a, b):
  1680. return a < b
  1681. class FloatSort(FloatBaseTimSort):
  1682. def lt(self, a, b):
  1683. return a < b
  1684. class IntOrFloatSort(IntOrFloatBaseTimSort):
  1685. def lt(self, a, b):
  1686. fa = longlong2float.maybe_decode_longlong_as_float(a)
  1687. fb = longlong2float.maybe_decode_longlong_as_float(b)
  1688. return fa < fb
  1689. class StringSort(StringBaseTimSort):
  1690. def lt(self, a, b):
  1691. return a < b
  1692. class UnicodeSort(UnicodeBaseTimSort):
  1693. def lt(self, a, b):
  1694. return a < b
  1695. class CustomCompareSort(SimpleSort):
  1696. def lt(self, a, b):
  1697. space = self.space
  1698. w_cmp = self.w_cmp
  1699. w_result = space.call_function(w_cmp, a, b)
  1700. try:
  1701. result = space.int_w(w_result)
  1702. except OperationError as e:
  1703. if e.match(space, space.w_TypeError):
  1704. raise oefmt(space.w_TypeError,
  1705. "comparison function must return int")
  1706. raise
  1707. return result < 0
  1708. class CustomKeySort(SimpleSort):
  1709. def lt(self, a, b):
  1710. assert isinstance(a, KeyContainer)
  1711. assert isinstance(b, KeyContainer)
  1712. space = self.space
  1713. return space.is_true(space.lt(a.w_key, b.w_key))
  1714. class CustomKeyCompareSort(CustomCompareSort):
  1715. def lt(self, a, b):
  1716. assert isinstance(a, KeyContainer)
  1717. assert isinstance(b, KeyContainer)
  1718. return CustomCompareSort.lt(self, a.w_key, b.w_key)
  1719. W_ListObject.typedef = TypeDef("list",
  1720. __doc__ = """list() -> new empty list
  1721. list(iterable) -> new list initialized from iterable's items""",
  1722. __new__ = interp2app(W_ListObject.descr_new),
  1723. __init__ = interp2app(W_ListObject.descr_init),
  1724. __repr__ = interp2app(W_ListObject.descr_repr),
  1725. __hash__ = None,
  1726. __eq__ = interp2app(W_ListObject.descr_eq),
  1727. __ne__ = interp2app(W_ListObject.descr_ne),
  1728. __lt__ = interp2app(W_ListObject.descr_lt),
  1729. __le__ = interp2app(W_ListObject.descr_le),
  1730. __gt__ = interp2app(W_ListObject.descr_gt),
  1731. __ge__ = interp2app(W_ListObject.descr_ge),
  1732. __len__ = interp2app(W_ListObject.descr_len),
  1733. __iter__ = interp2app(W_ListObject.descr_iter),
  1734. __contains__ = interp2app(W_ListObject.descr_contains),
  1735. __add__ = interp2app(W_ListObject.descr_add),
  1736. __iadd__ = interp2app(W_ListObject.descr_inplace_add),
  1737. __mul__ = interp2app(W_ListObject.descr_mul),
  1738. __rmul__ = interp2app(W_ListObject.descr_mul),
  1739. __imul__ = interp2app(W_ListObject.descr_inplace_mul),
  1740. __getitem__ = interp2app(W_ListObject.descr_getitem),
  1741. __getslice__ = interp2app(W_ListObject.descr_getslice),
  1742. __setitem__ = interp2app(W_ListObject.descr_setitem),
  1743. __setslice__ = interp2app(W_ListObject.descr_setslice),
  1744. __delitem__ = interp2app(W_ListObject.descr_delitem),
  1745. __delslice__ = interp2app(W_ListObject.descr_delslice),
  1746. sort = interp2app(W_ListObject.descr_sort),
  1747. index = interp2app(W_ListObject.descr_index),
  1748. append = interp2app(W_ListObject.append),
  1749. reverse = interp2app(W_ListObject.descr_reverse),
  1750. __reversed__ = interp2app(W_ListObject.descr_reversed),
  1751. count = interp2app(W_ListObject.descr_count),
  1752. pop = interp2app(W_ListObject.descr_pop),
  1753. extend = interp2app(W_ListObject.extend),
  1754. insert = interp2app(W_ListObject.descr_insert),
  1755. remove = interp2app(W_ListObject.descr_remove),
  1756. )
  1757. W_ListObject.typedef.flag_sequence_bug_compat = True