PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/objspace/std/dictmultiobject.py

https://bitbucket.org/pypy/pypy/
Python | 1559 lines | 1459 code | 79 blank | 21 comment | 61 complexity | 3b7b24e6e657736da46a188989482747 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. """The builtin dict implementation"""
  2. from rpython.rlib import jit, rerased, objectmodel
  3. from rpython.rlib.debug import mark_dict_non_null
  4. from rpython.rlib.objectmodel import newlist_hint, r_dict, specialize
  5. from rpython.tool.sourcetools import func_renamer, func_with_new_name
  6. from pypy.interpreter.baseobjspace import W_Root
  7. from pypy.interpreter.error import OperationError, oefmt
  8. from pypy.interpreter.gateway import (
  9. WrappedDefault, applevel, interp2app, unwrap_spec)
  10. from pypy.interpreter.mixedmodule import MixedModule
  11. from pypy.interpreter.signature import Signature
  12. from pypy.interpreter.typedef import TypeDef
  13. from pypy.objspace.std.util import negate
  14. UNROLL_CUTOFF = 5
  15. def _never_equal_to_string(space, w_lookup_type):
  16. """Handles the case of a non string key lookup.
  17. Types that have a sane hash/eq function should allow us to return True
  18. directly to signal that the key is not in the dict in any case.
  19. XXX The types should provide such a flag. """
  20. # XXX there are many more types
  21. return (space.is_w(w_lookup_type, space.w_NoneType) or
  22. space.is_w(w_lookup_type, space.w_int) or
  23. space.is_w(w_lookup_type, space.w_bool) or
  24. space.is_w(w_lookup_type, space.w_float))
  25. @specialize.call_location()
  26. def w_dict_unrolling_heuristic(w_dct):
  27. """In which cases iterating over dict items can be unrolled.
  28. Note that w_dct is an instance of W_DictMultiObject, not necesarilly
  29. an actual dict
  30. """
  31. return jit.isvirtual(w_dct) or (jit.isconstant(w_dct) and
  32. w_dct.length() <= UNROLL_CUTOFF)
  33. class W_DictMultiObject(W_Root):
  34. """ Abstract base class that does not store a strategy. """
  35. __slots__ = ['space', 'dstorage']
  36. def get_strategy(self):
  37. raise NotImplementedError("abstract method")
  38. def set_strategy(self, strategy):
  39. raise NotImplementedError("abstract method")
  40. @staticmethod
  41. def allocate_and_init_instance(space, w_type=None, module=False,
  42. instance=False, strdict=False,
  43. kwargs=False):
  44. if space.config.objspace.std.withcelldict and module:
  45. from pypy.objspace.std.celldict import ModuleDictStrategy
  46. assert w_type is None
  47. # every module needs its own strategy, because the strategy stores
  48. # the version tag
  49. strategy = ModuleDictStrategy(space)
  50. storage = strategy.get_empty_storage()
  51. w_obj = space.allocate_instance(W_ModuleDictObject, space.w_dict)
  52. W_ModuleDictObject.__init__(w_obj, space, strategy, storage)
  53. return w_obj
  54. elif instance:
  55. from pypy.objspace.std.mapdict import MapDictStrategy
  56. strategy = space.fromcache(MapDictStrategy)
  57. elif strdict or module:
  58. assert w_type is None
  59. strategy = space.fromcache(BytesDictStrategy)
  60. elif kwargs:
  61. assert w_type is None
  62. from pypy.objspace.std.kwargsdict import EmptyKwargsDictStrategy
  63. strategy = space.fromcache(EmptyKwargsDictStrategy)
  64. else:
  65. strategy = space.fromcache(EmptyDictStrategy)
  66. if w_type is None:
  67. w_type = space.w_dict
  68. storage = strategy.get_empty_storage()
  69. w_obj = space.allocate_instance(W_DictObject, w_type)
  70. W_DictObject.__init__(w_obj, space, strategy, storage)
  71. return w_obj
  72. def __init__(self, space, storage):
  73. self.space = space
  74. self.dstorage = storage
  75. def __repr__(self):
  76. """representation for debugging purposes"""
  77. return "%s(%s)" % (self.__class__.__name__, self.get_strategy())
  78. def unwrap(w_dict, space):
  79. result = {}
  80. items = w_dict.items()
  81. for w_pair in items:
  82. key, val = space.unwrap(w_pair)
  83. result[key] = val
  84. return result
  85. def missing_method(w_dict, space, w_key):
  86. if not space.is_w(space.type(w_dict), space.w_dict):
  87. w_missing = space.lookup(w_dict, '__missing__')
  88. if w_missing is not None:
  89. return space.get_and_call_function(w_missing, w_dict, w_key)
  90. return None
  91. def initialize_content(self, list_pairs_w):
  92. for w_k, w_v in list_pairs_w:
  93. self.setitem(w_k, w_v)
  94. def setitem_str(self, key, w_value):
  95. self.get_strategy().setitem_str(self, key, w_value)
  96. @staticmethod
  97. def descr_new(space, w_dicttype, __args__):
  98. w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype)
  99. return w_obj
  100. @staticmethod
  101. def descr_fromkeys(space, w_type, w_keys, w_fill=None):
  102. if w_fill is None:
  103. w_fill = space.w_None
  104. if space.is_w(w_type, space.w_dict):
  105. w_dict = W_DictMultiObject.allocate_and_init_instance(space,
  106. w_type)
  107. byteslist = space.listview_bytes(w_keys)
  108. if byteslist is not None:
  109. for key in byteslist:
  110. w_dict.setitem_str(key, w_fill)
  111. else:
  112. for w_key in space.listview(w_keys):
  113. w_dict.setitem(w_key, w_fill)
  114. else:
  115. w_dict = space.call_function(w_type)
  116. for w_key in space.listview(w_keys):
  117. space.setitem(w_dict, w_key, w_fill)
  118. return w_dict
  119. def descr_init(self, space, __args__):
  120. init_or_update(space, self, __args__, 'dict')
  121. def descr_repr(self, space):
  122. ec = space.getexecutioncontext()
  123. w_currently_in_repr = ec._py_repr
  124. if w_currently_in_repr is None:
  125. w_currently_in_repr = ec._py_repr = space.newdict()
  126. return dictrepr(space, w_currently_in_repr, self)
  127. def descr_eq(self, space, w_other):
  128. if space.is_w(self, w_other):
  129. return space.w_True
  130. if not isinstance(w_other, W_DictMultiObject):
  131. return space.w_NotImplemented
  132. if self.length() != w_other.length():
  133. return space.w_False
  134. iteratorimplementation = self.iteritems()
  135. while True:
  136. w_key, w_val = iteratorimplementation.next_item()
  137. if w_key is None:
  138. break
  139. w_rightval = w_other.getitem(w_key)
  140. if w_rightval is None:
  141. return space.w_False
  142. if not space.eq_w(w_val, w_rightval):
  143. return space.w_False
  144. return space.w_True
  145. def descr_lt(self, space, w_other):
  146. if not isinstance(w_other, W_DictMultiObject):
  147. return space.w_NotImplemented
  148. return self._compare_lt(space, w_other)
  149. def descr_gt(self, space, w_other):
  150. if not isinstance(w_other, W_DictMultiObject):
  151. return space.w_NotImplemented
  152. return w_other._compare_lt(space, self)
  153. def _compare_lt(self, space, w_other):
  154. # Different sizes, no problem
  155. if self.length() < w_other.length():
  156. return space.w_True
  157. if self.length() > w_other.length():
  158. return space.w_False
  159. # Same size
  160. w_leftdiff, w_leftval = characterize(space, self, w_other)
  161. if w_leftdiff is None:
  162. return space.w_False
  163. w_rightdiff, w_rightval = characterize(space, w_other, self)
  164. if w_rightdiff is None:
  165. # w_leftdiff is not None, w_rightdiff is None
  166. return space.w_True
  167. w_res = space.lt(w_leftdiff, w_rightdiff)
  168. if (not space.is_true(w_res) and
  169. space.eq_w(w_leftdiff, w_rightdiff) and
  170. w_rightval is not None):
  171. w_res = space.lt(w_leftval, w_rightval)
  172. return w_res
  173. descr_ne = negate(descr_eq)
  174. descr_le = negate(descr_gt)
  175. descr_ge = negate(descr_lt)
  176. def descr_len(self, space):
  177. return space.wrap(self.length())
  178. def descr_iter(self, space):
  179. return W_DictMultiIterKeysObject(space, self.iterkeys())
  180. def descr_contains(self, space, w_key):
  181. return space.newbool(self.getitem(w_key) is not None)
  182. def descr_getitem(self, space, w_key):
  183. w_value = self.getitem(w_key)
  184. if w_value is not None:
  185. return w_value
  186. w_missing_item = self.missing_method(space, w_key)
  187. if w_missing_item is not None:
  188. return w_missing_item
  189. space.raise_key_error(w_key)
  190. def descr_setitem(self, space, w_newkey, w_newvalue):
  191. self.setitem(w_newkey, w_newvalue)
  192. def descr_delitem(self, space, w_key):
  193. try:
  194. self.delitem(w_key)
  195. except KeyError:
  196. space.raise_key_error(w_key)
  197. def descr_reversed(self, space):
  198. raise oefmt(space.w_TypeError,
  199. "argument to reversed() must be a sequence")
  200. def descr_copy(self, space):
  201. """D.copy() -> a shallow copy of D"""
  202. w_new = W_DictMultiObject.allocate_and_init_instance(space)
  203. update1_dict_dict(space, w_new, self)
  204. return w_new
  205. def descr_items(self, space):
  206. """D.items() -> list of D's (key, value) pairs, as 2-tuples"""
  207. return space.newlist(self.items())
  208. def descr_keys(self, space):
  209. """D.keys() -> list of D's keys"""
  210. return self.w_keys()
  211. def descr_values(self, space):
  212. """D.values() -> list of D's values"""
  213. return space.newlist(self.values())
  214. def descr_iteritems(self, space):
  215. """D.iteritems() -> an iterator over the (key, value) items of D"""
  216. return W_DictMultiIterItemsObject(space, self.iteritems())
  217. def descr_iterkeys(self, space):
  218. """D.iterkeys() -> an iterator over the keys of D"""
  219. return W_DictMultiIterKeysObject(space, self.iterkeys())
  220. def descr_itervalues(self, space):
  221. """D.itervalues() -> an iterator over the values of D"""
  222. return W_DictMultiIterValuesObject(space, self.itervalues())
  223. def nondescr_reversed_dict(self, space):
  224. """Not exposed directly to app-level, but via __pypy__.reversed_dict().
  225. """
  226. strategy = self.get_strategy()
  227. if strategy.has_iterreversed:
  228. it = strategy.iterreversed(self)
  229. return W_DictMultiIterKeysObject(space, it)
  230. else:
  231. # fall-back
  232. w_keys = self.w_keys()
  233. return space.call_method(w_keys, '__reversed__')
  234. def descr_viewitems(self, space):
  235. """D.viewitems() -> a set-like object providing a view on D's items"""
  236. return W_DictViewItemsObject(space, self)
  237. def descr_viewkeys(self, space):
  238. """D.viewkeys() -> a set-like object providing a view on D's keys"""
  239. return W_DictViewKeysObject(space, self)
  240. def descr_viewvalues(self, space):
  241. """D.viewvalues() -> an object providing a view on D's values"""
  242. return W_DictViewValuesObject(space, self)
  243. def descr_has_key(self, space, w_key):
  244. """D.has_key(k) -> True if D has a key k, else False"""
  245. return space.newbool(self.getitem(w_key) is not None)
  246. def descr_clear(self, space):
  247. """D.clear() -> None. Remove all items from D."""
  248. self.clear()
  249. @unwrap_spec(w_default=WrappedDefault(None))
  250. def descr_get(self, space, w_key, w_default):
  251. """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None."""
  252. w_value = self.getitem(w_key)
  253. return w_value if w_value is not None else w_default
  254. @unwrap_spec(defaults_w='args_w')
  255. def descr_pop(self, space, w_key, defaults_w):
  256. """D.pop(k[,d]) -> v, remove specified key and return the
  257. corresponding value\nIf key is not found, d is returned if given,
  258. otherwise KeyError is raised
  259. """
  260. len_defaults = len(defaults_w)
  261. if len_defaults > 1:
  262. raise oefmt(space.w_TypeError,
  263. "pop expected at most 2 arguments, got %d",
  264. 1 + len_defaults)
  265. w_item = self.getitem(w_key)
  266. if w_item is None:
  267. if len_defaults > 0:
  268. return defaults_w[0]
  269. else:
  270. space.raise_key_error(w_key)
  271. else:
  272. self.delitem(w_key)
  273. return w_item
  274. def descr_popitem(self, space):
  275. """D.popitem() -> (k, v), remove and return some (key, value) pair as
  276. a\n2-tuple; but raise KeyError if D is empty"""
  277. try:
  278. w_key, w_value = self.popitem()
  279. except KeyError:
  280. raise oefmt(space.w_KeyError, "popitem(): dictionary is empty")
  281. return space.newtuple([w_key, w_value])
  282. @unwrap_spec(w_default=WrappedDefault(None))
  283. def descr_setdefault(self, space, w_key, w_default):
  284. """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D"""
  285. return self.setdefault(w_key, w_default)
  286. def descr_update(self, space, __args__):
  287. """D.update(E, **F) -> None. Update D from E and F: for k in E: D[k]
  288. = E[k]\n(if E has keys else: for (k, v) in E: D[k] = v) then: for k in
  289. F: D[k] = F[k]"""
  290. init_or_update(space, self, __args__, 'dict.update')
  291. def ensure_object_strategy(self): # for cpyext
  292. object_strategy = self.space.fromcache(ObjectDictStrategy)
  293. strategy = self.get_strategy()
  294. if strategy is not object_strategy:
  295. strategy.switch_to_object_strategy(self)
  296. class W_DictObject(W_DictMultiObject):
  297. """ a regular dict object """
  298. __slots__ = ['dstrategy']
  299. def __init__(self, space, strategy, storage):
  300. W_DictMultiObject.__init__(self, space, storage)
  301. self.dstrategy = strategy
  302. def get_strategy(self):
  303. return self.dstrategy
  304. def set_strategy(self, strategy):
  305. self.dstrategy = strategy
  306. class W_ModuleDictObject(W_DictMultiObject):
  307. """ a dict object for a module, that is not expected to change. It stores
  308. the strategy as a quasi-immutable field. """
  309. __slots__ = ['mstrategy']
  310. _immutable_fields_ = ['mstrategy?']
  311. def __init__(self, space, strategy, storage):
  312. W_DictMultiObject.__init__(self, space, storage)
  313. self.mstrategy = strategy
  314. def get_strategy(self):
  315. return self.mstrategy
  316. def set_strategy(self, strategy):
  317. self.mstrategy = strategy
  318. def _add_indirections():
  319. dict_methods = "getitem getitem_str setitem setdefault \
  320. popitem delitem clear \
  321. length w_keys values items \
  322. iterkeys itervalues iteritems \
  323. listview_bytes listview_unicode listview_int \
  324. view_as_kwargs".split()
  325. def make_method(method):
  326. def f(self, *args):
  327. return getattr(self.get_strategy(), method)(self, *args)
  328. f.func_name = method
  329. return f
  330. for method in dict_methods:
  331. setattr(W_DictMultiObject, method, make_method(method))
  332. _add_indirections()
  333. app = applevel('''
  334. def dictrepr(currently_in_repr, d):
  335. if len(d) == 0:
  336. return "{}"
  337. dict_id = id(d)
  338. if dict_id in currently_in_repr:
  339. return '{...}'
  340. currently_in_repr[dict_id] = 1
  341. try:
  342. items = []
  343. # XXX for now, we cannot use iteritems() at app-level because
  344. # we want a reasonable result instead of a RuntimeError
  345. # even if the dict is mutated by the repr() in the loop.
  346. for k, v in dict.items(d):
  347. items.append(repr(k) + ": " + repr(v))
  348. return "{" + ', '.join(items) + "}"
  349. finally:
  350. try:
  351. del currently_in_repr[dict_id]
  352. except:
  353. pass
  354. ''', filename=__file__)
  355. dictrepr = app.interphook("dictrepr")
  356. W_DictMultiObject.typedef = TypeDef("dict",
  357. __doc__ = '''dict() -> new empty dictionary.
  358. dict(mapping) -> new dictionary initialized from a mapping object\'s
  359. (key, value) pairs.
  360. dict(seq) -> new dictionary initialized as if via:
  361. d = {}
  362. for k, v in seq:
  363. d[k] = v
  364. dict(**kwargs) -> new dictionary initialized with the name=value pairs
  365. in the keyword argument list. For example: dict(one=1, two=2)''',
  366. __new__ = interp2app(W_DictMultiObject.descr_new),
  367. fromkeys = interp2app(W_DictMultiObject.descr_fromkeys,
  368. as_classmethod=True),
  369. __hash__ = None,
  370. __repr__ = interp2app(W_DictMultiObject.descr_repr),
  371. __init__ = interp2app(W_DictMultiObject.descr_init),
  372. __eq__ = interp2app(W_DictMultiObject.descr_eq),
  373. __ne__ = interp2app(W_DictMultiObject.descr_ne),
  374. __lt__ = interp2app(W_DictMultiObject.descr_lt),
  375. __le__ = interp2app(W_DictMultiObject.descr_le),
  376. __gt__ = interp2app(W_DictMultiObject.descr_gt),
  377. __ge__ = interp2app(W_DictMultiObject.descr_ge),
  378. __len__ = interp2app(W_DictMultiObject.descr_len),
  379. __iter__ = interp2app(W_DictMultiObject.descr_iter),
  380. __contains__ = interp2app(W_DictMultiObject.descr_contains),
  381. __getitem__ = interp2app(W_DictMultiObject.descr_getitem),
  382. __setitem__ = interp2app(W_DictMultiObject.descr_setitem),
  383. __delitem__ = interp2app(W_DictMultiObject.descr_delitem),
  384. __reversed__ = interp2app(W_DictMultiObject.descr_reversed),
  385. copy = interp2app(W_DictMultiObject.descr_copy),
  386. items = interp2app(W_DictMultiObject.descr_items),
  387. keys = interp2app(W_DictMultiObject.descr_keys),
  388. values = interp2app(W_DictMultiObject.descr_values),
  389. iteritems = interp2app(W_DictMultiObject.descr_iteritems),
  390. iterkeys = interp2app(W_DictMultiObject.descr_iterkeys),
  391. itervalues = interp2app(W_DictMultiObject.descr_itervalues),
  392. viewkeys = interp2app(W_DictMultiObject.descr_viewkeys),
  393. viewitems = interp2app(W_DictMultiObject.descr_viewitems),
  394. viewvalues = interp2app(W_DictMultiObject.descr_viewvalues),
  395. has_key = interp2app(W_DictMultiObject.descr_has_key),
  396. clear = interp2app(W_DictMultiObject.descr_clear),
  397. get = interp2app(W_DictMultiObject.descr_get),
  398. pop = interp2app(W_DictMultiObject.descr_pop),
  399. popitem = interp2app(W_DictMultiObject.descr_popitem),
  400. setdefault = interp2app(W_DictMultiObject.descr_setdefault),
  401. update = interp2app(W_DictMultiObject.descr_update),
  402. )
  403. class DictStrategy(object):
  404. def __init__(self, space):
  405. self.space = space
  406. def get_empty_storage(self):
  407. raise NotImplementedError
  408. @jit.look_inside_iff(lambda self, w_dict:
  409. w_dict_unrolling_heuristic(w_dict))
  410. def w_keys(self, w_dict):
  411. iterator = self.iterkeys(w_dict)
  412. result = newlist_hint(self.length(w_dict))
  413. while True:
  414. w_key = iterator.next_key()
  415. if w_key is not None:
  416. result.append(w_key)
  417. else:
  418. return self.space.newlist(result)
  419. def values(self, w_dict):
  420. iterator = self.itervalues(w_dict)
  421. result = newlist_hint(self.length(w_dict))
  422. while True:
  423. w_value = iterator.next_value()
  424. if w_value is not None:
  425. result.append(w_value)
  426. else:
  427. return result
  428. def items(self, w_dict):
  429. iterator = self.iteritems(w_dict)
  430. result = newlist_hint(self.length(w_dict))
  431. while True:
  432. w_key, w_value = iterator.next_item()
  433. if w_key is not None:
  434. result.append(self.space.newtuple([w_key, w_value]))
  435. else:
  436. return result
  437. def popitem(self, w_dict):
  438. # this is a bad implementation: if we call popitem() repeatedly,
  439. # it ends up taking n**2 time, because the next() calls below
  440. # will take longer and longer. But all interesting strategies
  441. # provide a better one.
  442. iterator = self.iteritems(w_dict)
  443. w_key, w_value = iterator.next_item()
  444. if w_key is None:
  445. raise KeyError
  446. self.delitem(w_dict, w_key)
  447. return (w_key, w_value)
  448. def clear(self, w_dict):
  449. strategy = self.space.fromcache(EmptyDictStrategy)
  450. storage = strategy.get_empty_storage()
  451. w_dict.set_strategy(strategy)
  452. w_dict.dstorage = storage
  453. def listview_bytes(self, w_dict):
  454. return None
  455. def listview_unicode(self, w_dict):
  456. return None
  457. def listview_int(self, w_dict):
  458. return None
  459. def view_as_kwargs(self, w_dict):
  460. return (None, None)
  461. def getiterkeys(self, w_dict):
  462. raise NotImplementedError
  463. def getitervalues(self, w_dict):
  464. raise NotImplementedError
  465. def getiteritems_with_hash(self, w_dict):
  466. raise NotImplementedError
  467. has_iterreversed = False
  468. # no 'getiterreversed': no default implementation available
  469. def rev_update1_dict_dict(self, w_dict, w_updatedict):
  470. iteritems = self.iteritems(w_dict)
  471. while True:
  472. w_key, w_value = iteritems.next_item()
  473. if w_key is None:
  474. break
  475. w_updatedict.setitem(w_key, w_value)
  476. def prepare_update(self, w_dict, num_extra):
  477. pass
  478. class EmptyDictStrategy(DictStrategy):
  479. erase, unerase = rerased.new_erasing_pair("empty")
  480. erase = staticmethod(erase)
  481. unerase = staticmethod(unerase)
  482. def get_empty_storage(self):
  483. return self.erase(None)
  484. def switch_to_correct_strategy(self, w_dict, w_key):
  485. if type(w_key) is self.space.StringObjectCls:
  486. self.switch_to_bytes_strategy(w_dict)
  487. return
  488. elif type(w_key) is self.space.UnicodeObjectCls:
  489. self.switch_to_unicode_strategy(w_dict)
  490. return
  491. w_type = self.space.type(w_key)
  492. if self.space.is_w(w_type, self.space.w_int):
  493. self.switch_to_int_strategy(w_dict)
  494. elif w_type.compares_by_identity():
  495. self.switch_to_identity_strategy(w_dict)
  496. else:
  497. self.switch_to_object_strategy(w_dict)
  498. def switch_to_bytes_strategy(self, w_dict):
  499. strategy = self.space.fromcache(BytesDictStrategy)
  500. storage = strategy.get_empty_storage()
  501. w_dict.set_strategy(strategy)
  502. w_dict.dstorage = storage
  503. def switch_to_unicode_strategy(self, w_dict):
  504. strategy = self.space.fromcache(UnicodeDictStrategy)
  505. storage = strategy.get_empty_storage()
  506. w_dict.set_strategy(strategy)
  507. w_dict.dstorage = storage
  508. def switch_to_int_strategy(self, w_dict):
  509. strategy = self.space.fromcache(IntDictStrategy)
  510. storage = strategy.get_empty_storage()
  511. w_dict.set_strategy(strategy)
  512. w_dict.dstorage = storage
  513. def switch_to_identity_strategy(self, w_dict):
  514. from pypy.objspace.std.identitydict import IdentityDictStrategy
  515. strategy = self.space.fromcache(IdentityDictStrategy)
  516. storage = strategy.get_empty_storage()
  517. w_dict.set_strategy(strategy)
  518. w_dict.dstorage = storage
  519. def switch_to_object_strategy(self, w_dict):
  520. strategy = self.space.fromcache(ObjectDictStrategy)
  521. storage = strategy.get_empty_storage()
  522. w_dict.set_strategy(strategy)
  523. w_dict.dstorage = storage
  524. def getitem(self, w_dict, w_key):
  525. #return w_value or None
  526. # in case the key is unhashable, try to hash it
  527. self.space.hash(w_key)
  528. # return None anyway
  529. return None
  530. def getitem_str(self, w_dict, key):
  531. #return w_value or None
  532. return None
  533. def setdefault(self, w_dict, w_key, w_default):
  534. # here the dict is always empty
  535. self.switch_to_correct_strategy(w_dict, w_key)
  536. w_dict.setitem(w_key, w_default)
  537. return w_default
  538. def setitem(self, w_dict, w_key, w_value):
  539. self.switch_to_correct_strategy(w_dict, w_key)
  540. w_dict.setitem(w_key, w_value)
  541. def setitem_str(self, w_dict, key, w_value):
  542. self.switch_to_bytes_strategy(w_dict)
  543. w_dict.setitem_str(key, w_value)
  544. def delitem(self, w_dict, w_key):
  545. # in case the key is unhashable, try to hash it
  546. self.space.hash(w_key)
  547. raise KeyError
  548. def length(self, w_dict):
  549. return 0
  550. def clear(self, w_dict):
  551. return
  552. def popitem(self, w_dict):
  553. raise KeyError
  554. def view_as_kwargs(self, w_dict):
  555. return ([], [])
  556. # ---------- iterator interface ----------------
  557. def getiterkeys(self, w_dict):
  558. return iter([])
  559. def getitervalues(self, w_dict):
  560. return iter([])
  561. def getiteritems_with_hash(self, w_dict):
  562. return iter([])
  563. def getiterreversed(self, w_dict):
  564. return iter([])
  565. # Iterator Implementation base classes
  566. def _new_next(TP):
  567. if TP in ('key', 'value'):
  568. EMPTY = None
  569. else:
  570. EMPTY = None, None
  571. def next(self):
  572. if self.w_dict is None:
  573. return EMPTY
  574. space = self.space
  575. if self.len != self.w_dict.length():
  576. self.len = -1 # Make this error state sticky
  577. raise oefmt(space.w_RuntimeError,
  578. "dictionary changed size during iteration")
  579. # look for the next entry
  580. if self.pos < self.len:
  581. result = getattr(self, 'next_' + TP + '_entry')()
  582. self.pos += 1
  583. if self.strategy is self.w_dict.get_strategy():
  584. return result # common case
  585. else:
  586. # waaa, obscure case: the strategy changed, but not the
  587. # length of the dict. The (key, value) pair in 'result'
  588. # might be out-of-date. We try to explicitly look up
  589. # the key in the dict.
  590. if TP == 'key' or TP == 'value':
  591. return result
  592. w_key = result[0]
  593. w_value = self.w_dict.getitem(w_key)
  594. if w_value is None:
  595. self.len = -1 # Make this error state sticky
  596. raise oefmt(space.w_RuntimeError,
  597. "dictionary changed during iteration")
  598. return (w_key, w_value)
  599. # no more entries
  600. self.w_dict = None
  601. return EMPTY
  602. return func_with_new_name(next, 'next_' + TP)
  603. class BaseIteratorImplementation(object):
  604. def __init__(self, space, strategy, w_dict):
  605. self.space = space
  606. self.strategy = strategy
  607. self.w_dict = w_dict
  608. self.len = w_dict.length()
  609. self.pos = 0
  610. def length(self):
  611. if self.w_dict is not None and self.len != -1:
  612. return self.len - self.pos
  613. return 0
  614. def _cleanup_(self):
  615. raise Exception("seeing a prebuilt %r object" % (
  616. self.__class__,))
  617. class BaseKeyIterator(BaseIteratorImplementation):
  618. next_key = _new_next('key')
  619. class BaseValueIterator(BaseIteratorImplementation):
  620. next_value = _new_next('value')
  621. class BaseItemIterator(BaseIteratorImplementation):
  622. next_item = _new_next('item')
  623. def create_iterator_classes(dictimpl):
  624. if not hasattr(dictimpl, 'wrapkey'):
  625. wrapkey = lambda space, key: key
  626. else:
  627. wrapkey = dictimpl.wrapkey.im_func
  628. if not hasattr(dictimpl, 'wrapvalue'):
  629. wrapvalue = lambda space, value: value
  630. else:
  631. wrapvalue = dictimpl.wrapvalue.im_func
  632. if not hasattr(dictimpl, 'setitem_untyped'):
  633. setitem_untyped = None
  634. else:
  635. setitem_untyped = dictimpl.setitem_untyped.im_func
  636. setitem_untyped = func_with_new_name(setitem_untyped,
  637. 'setitem_untyped_%s' % dictimpl.__name__)
  638. class IterClassKeys(BaseKeyIterator):
  639. def __init__(self, space, strategy, w_dict):
  640. self.iterator = strategy.getiterkeys(w_dict)
  641. BaseIteratorImplementation.__init__(self, space, strategy, w_dict)
  642. def next_key_entry(self):
  643. for key in self.iterator:
  644. return wrapkey(self.space, key)
  645. else:
  646. return None
  647. class IterClassValues(BaseValueIterator):
  648. def __init__(self, space, strategy, w_dict):
  649. self.iterator = strategy.getitervalues(w_dict)
  650. BaseIteratorImplementation.__init__(self, space, strategy, w_dict)
  651. def next_value_entry(self):
  652. for value in self.iterator:
  653. return wrapvalue(self.space, value)
  654. else:
  655. return None
  656. class IterClassItems(BaseItemIterator):
  657. def __init__(self, space, strategy, w_dict):
  658. self.iterator = strategy.getiteritems_with_hash(w_dict)
  659. BaseIteratorImplementation.__init__(self, space, strategy, w_dict)
  660. def next_item_entry(self):
  661. for key, value, keyhash in self.iterator:
  662. return (wrapkey(self.space, key),
  663. wrapvalue(self.space, value))
  664. else:
  665. return None, None
  666. class IterClassReversed(BaseKeyIterator):
  667. def __init__(self, space, strategy, w_dict):
  668. self.iterator = strategy.getiterreversed(w_dict)
  669. BaseIteratorImplementation.__init__(self, space, strategy, w_dict)
  670. def next_key_entry(self):
  671. for key in self.iterator:
  672. return wrapkey(self.space, key)
  673. else:
  674. return None
  675. def iterkeys(self, w_dict):
  676. return IterClassKeys(self.space, self, w_dict)
  677. def itervalues(self, w_dict):
  678. return IterClassValues(self.space, self, w_dict)
  679. def iteritems(self, w_dict):
  680. return IterClassItems(self.space, self, w_dict)
  681. if hasattr(dictimpl, 'getiterreversed'):
  682. def iterreversed(self, w_dict):
  683. return IterClassReversed(self.space, self, w_dict)
  684. dictimpl.iterreversed = iterreversed
  685. dictimpl.has_iterreversed = True
  686. @jit.look_inside_iff(lambda self, w_dict, w_updatedict:
  687. w_dict_unrolling_heuristic(w_dict))
  688. def rev_update1_dict_dict(self, w_dict, w_updatedict):
  689. # the logic is to call prepare_dict_update() after the first setitem():
  690. # it gives the w_updatedict a chance to switch its strategy.
  691. if 1: # (preserve indentation)
  692. iteritemsh = self.getiteritems_with_hash(w_dict)
  693. if not same_strategy(self, w_updatedict):
  694. # Different strategy. Try to copy one item of w_dict
  695. for key, value, keyhash in iteritemsh:
  696. w_key = wrapkey(self.space, key)
  697. w_value = wrapvalue(self.space, value)
  698. w_updatedict.setitem(w_key, w_value)
  699. break
  700. else:
  701. return # w_dict is completely empty, nothing to do
  702. count = w_dict.length() - 1
  703. w_updatedict.get_strategy().prepare_update(w_updatedict, count)
  704. # If the strategy is still different, continue the slow way
  705. if not same_strategy(self, w_updatedict):
  706. for key, value, keyhash in iteritemsh:
  707. w_key = wrapkey(self.space, key)
  708. w_value = wrapvalue(self.space, value)
  709. w_updatedict.setitem(w_key, w_value)
  710. return # done
  711. else:
  712. # Same strategy.
  713. self.prepare_update(w_updatedict, w_dict.length())
  714. #
  715. # Use setitem_untyped() to speed up copying without
  716. # wrapping/unwrapping the key.
  717. assert setitem_untyped is not None
  718. dstorage = w_updatedict.dstorage
  719. for key, value, keyhash in iteritemsh:
  720. setitem_untyped(self, dstorage, key, value, keyhash)
  721. def same_strategy(self, w_otherdict):
  722. return (setitem_untyped is not None and
  723. w_otherdict.get_strategy() is self)
  724. dictimpl.iterkeys = iterkeys
  725. dictimpl.itervalues = itervalues
  726. dictimpl.iteritems = iteritems
  727. dictimpl.rev_update1_dict_dict = rev_update1_dict_dict
  728. create_iterator_classes(EmptyDictStrategy)
  729. # concrete subclasses of the above
  730. class AbstractTypedStrategy(object):
  731. _mixin_ = True
  732. @staticmethod
  733. def erase(storage):
  734. raise NotImplementedError("abstract base class")
  735. @staticmethod
  736. def unerase(obj):
  737. raise NotImplementedError("abstract base class")
  738. def wrap(self, unwrapped):
  739. raise NotImplementedError
  740. def unwrap(self, wrapped):
  741. raise NotImplementedError
  742. def is_correct_type(self, w_obj):
  743. raise NotImplementedError("abstract base class")
  744. def get_empty_storage(self):
  745. raise NotImplementedError("abstract base class")
  746. def _never_equal_to(self, w_lookup_type):
  747. raise NotImplementedError("abstract base class")
  748. def setitem(self, w_dict, w_key, w_value):
  749. if self.is_correct_type(w_key):
  750. self.unerase(w_dict.dstorage)[self.unwrap(w_key)] = w_value
  751. return
  752. else:
  753. self.switch_to_object_strategy(w_dict)
  754. w_dict.setitem(w_key, w_value)
  755. def setitem_str(self, w_dict, key, w_value):
  756. self.switch_to_object_strategy(w_dict)
  757. w_dict.setitem(self.space.wrap(key), w_value)
  758. def setdefault(self, w_dict, w_key, w_default):
  759. if self.is_correct_type(w_key):
  760. return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key),
  761. w_default)
  762. else:
  763. self.switch_to_object_strategy(w_dict)
  764. return w_dict.setdefault(w_key, w_default)
  765. def delitem(self, w_dict, w_key):
  766. if self.is_correct_type(w_key):
  767. del self.unerase(w_dict.dstorage)[self.unwrap(w_key)]
  768. return
  769. else:
  770. self.switch_to_object_strategy(w_dict)
  771. return w_dict.delitem(w_key)
  772. def length(self, w_dict):
  773. return len(self.unerase(w_dict.dstorage))
  774. def getitem_str(self, w_dict, key):
  775. return self.getitem(w_dict, self.space.wrap(key))
  776. def getitem(self, w_dict, w_key):
  777. space = self.space
  778. if self.is_correct_type(w_key):
  779. return self.unerase(w_dict.dstorage).get(self.unwrap(w_key), None)
  780. elif self._never_equal_to(space.type(w_key)):
  781. return None
  782. else:
  783. self.switch_to_object_strategy(w_dict)
  784. return w_dict.getitem(w_key)
  785. def w_keys(self, w_dict):
  786. l = [self.wrap(key)
  787. for key in self.unerase(w_dict.dstorage).iterkeys()]
  788. return self.space.newlist(l)
  789. def values(self, w_dict):
  790. return self.unerase(w_dict.dstorage).values()
  791. def items(self, w_dict):
  792. space = self.space
  793. dict_w = self.unerase(w_dict.dstorage)
  794. return [space.newtuple([self.wrap(key), w_value])
  795. for (key, w_value) in dict_w.iteritems()]
  796. def popitem(self, w_dict):
  797. key, value = self.unerase(w_dict.dstorage).popitem()
  798. return (self.wrap(key), value)
  799. def clear(self, w_dict):
  800. self.unerase(w_dict.dstorage).clear()
  801. def switch_to_object_strategy(self, w_dict):
  802. d = self.unerase(w_dict.dstorage)
  803. strategy = self.space.fromcache(ObjectDictStrategy)
  804. d_new = strategy.unerase(strategy.get_empty_storage())
  805. for key, value in d.iteritems():
  806. d_new[self.wrap(key)] = value
  807. w_dict.set_strategy(strategy)
  808. w_dict.dstorage = strategy.erase(d_new)
  809. # --------------- iterator interface -----------------
  810. def getiterkeys(self, w_dict):
  811. return self.unerase(w_dict.dstorage).iterkeys()
  812. def getitervalues(self, w_dict):
  813. return self.unerase(w_dict.dstorage).itervalues()
  814. def getiteritems_with_hash(self, w_dict):
  815. return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage))
  816. def getiterreversed(self, w_dict):
  817. return objectmodel.reversed_dict(self.unerase(w_dict.dstorage))
  818. def prepare_update(self, w_dict, num_extra):
  819. objectmodel.prepare_dict_update(self.unerase(w_dict.dstorage),
  820. num_extra)
  821. def setitem_untyped(self, dstorage, key, w_value, keyhash):
  822. d = self.unerase(dstorage)
  823. objectmodel.setitem_with_hash(d, key, keyhash, w_value)
  824. class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy):
  825. erase, unerase = rerased.new_erasing_pair("object")
  826. erase = staticmethod(erase)
  827. unerase = staticmethod(unerase)
  828. def wrap(self, unwrapped):
  829. return unwrapped
  830. def unwrap(self, wrapped):
  831. return wrapped
  832. def is_correct_type(self, w_obj):
  833. return True
  834. def get_empty_storage(self):
  835. new_dict = r_dict(self.space.eq_w, self.space.hash_w,
  836. force_non_null=True)
  837. return self.erase(new_dict)
  838. def _never_equal_to(self, w_lookup_type):
  839. return False
  840. def w_keys(self, w_dict):
  841. return self.space.newlist(self.unerase(w_dict.dstorage).keys())
  842. def setitem_str(self, w_dict, s, w_value):
  843. self.setitem(w_dict, self.space.wrap(s), w_value)
  844. def switch_to_object_strategy(self, w_dict):
  845. assert 0, "should be unreachable"
  846. create_iterator_classes(ObjectDictStrategy)
  847. class BytesDictStrategy(AbstractTypedStrategy, DictStrategy):
  848. erase, unerase = rerased.new_erasing_pair("bytes")
  849. erase = staticmethod(erase)
  850. unerase = staticmethod(unerase)
  851. def wrap(self, unwrapped):
  852. return self.space.wrap(unwrapped)
  853. def unwrap(self, wrapped):
  854. return self.space.str_w(wrapped)
  855. def is_correct_type(self, w_obj):
  856. space = self.space
  857. return space.is_w(space.type(w_obj), space.w_str)
  858. def get_empty_storage(self):
  859. res = {}
  860. mark_dict_non_null(res)
  861. return self.erase(res)
  862. def _never_equal_to(self, w_lookup_type):
  863. return _never_equal_to_string(self.space, w_lookup_type)
  864. def setitem_str(self, w_dict, key, w_value):
  865. assert key is not None
  866. self.unerase(w_dict.dstorage)[key] = w_value
  867. def getitem(self, w_dict, w_key):
  868. space = self.space
  869. # -- This is called extremely often. Hack for performance --
  870. if type(w_key) is space.StringObjectCls:
  871. return self.getitem_str(w_dict, w_key.unwrap(space))
  872. # -- End of performance hack --
  873. return AbstractTypedStrategy.getitem(self, w_dict, w_key)
  874. def getitem_str(self, w_dict, key):
  875. assert key is not None
  876. return self.unerase(w_dict.dstorage).get(key, None)
  877. def listview_bytes(self, w_dict):
  878. return self.unerase(w_dict.dstorage).keys()
  879. def w_keys(self, w_dict):
  880. return self.space.newlist_bytes(self.listview_bytes(w_dict))
  881. def wrapkey(space, key):
  882. return space.wrap(key)
  883. @jit.look_inside_iff(lambda self, w_dict:
  884. w_dict_unrolling_heuristic(w_dict))
  885. def view_as_kwargs(self, w_dict):
  886. d = self.unerase(w_dict.dstorage)
  887. l = len(d)
  888. keys, values = [None] * l, [None] * l
  889. i = 0
  890. for key, val in d.iteritems():
  891. keys[i] = key
  892. values[i] = val
  893. i += 1
  894. return keys, values
  895. create_iterator_classes(BytesDictStrategy)
  896. class UnicodeDictStrategy(AbstractTypedStrategy, DictStrategy):
  897. erase, unerase = rerased.new_erasing_pair("unicode")
  898. erase = staticmethod(erase)
  899. unerase = staticmethod(unerase)
  900. def wrap(self, unwrapped):
  901. return self.space.wrap(unwrapped)
  902. def unwrap(self, wrapped):
  903. return self.space.unicode_w(wrapped)
  904. def is_correct_type(self, w_obj):
  905. space = self.space
  906. return space.is_w(space.type(w_obj), space.w_unicode)
  907. def get_empty_storage(self):
  908. res = {}
  909. mark_dict_non_null(res)
  910. return self.erase(res)
  911. def _never_equal_to(self, w_lookup_type):
  912. return _never_equal_to_string(self.space, w_lookup_type)
  913. # we should implement the same shortcuts as we do for BytesDictStrategy
  914. ## def setitem_str(self, w_dict, key, w_value):
  915. ## assert key is not None
  916. ## self.unerase(w_dict.dstorage)[key] = w_value
  917. ## def getitem(self, w_dict, w_key):
  918. ## space = self.space
  919. ## # -- This is called extremely often. Hack for performance --
  920. ## if type(w_key) is space.StringObjectCls:
  921. ## return self.getitem_str(w_dict, w_key.unwrap(space))
  922. ## # -- End of performance hack --
  923. ## return AbstractTypedStrategy.getitem(self, w_dict, w_key)
  924. ## def getitem_str(self, w_dict, key):
  925. ## assert key is not None
  926. ## return self.unerase(w_dict.dstorage).get(key, None)
  927. def listview_unicode(self, w_dict):
  928. return self.unerase(w_dict.dstorage).keys()
  929. ## def w_keys(self, w_dict):
  930. ## return self.space.newlist_bytes(self.listview_bytes(w_dict))
  931. def wrapkey(space, key):
  932. return space.wrap(key)
  933. ## @jit.look_inside_iff(lambda self, w_dict:
  934. ## w_dict_unrolling_heuristic(w_dict))
  935. ## def view_as_kwargs(self, w_dict):
  936. ## d = self.unerase(w_dict.dstorage)
  937. ## l = len(d)
  938. ## keys, values = [None] * l, [None] * l
  939. ## i = 0
  940. ## for key, val in d.iteritems():
  941. ## keys[i] = key
  942. ## values[i] = val
  943. ## i += 1
  944. ## return keys, values
  945. create_iterator_classes(UnicodeDictStrategy)
  946. class IntDictStrategy(AbstractTypedStrategy, DictStrategy):
  947. erase, unerase = rerased.new_erasing_pair("int")
  948. erase = staticmethod(erase)
  949. unerase = staticmethod(unerase)
  950. def wrap(self, unwrapped):
  951. return self.space.wrap(unwrapped)
  952. def unwrap(self, wrapped):
  953. return self.space.int_w(wrapped)
  954. def get_empty_storage(self):
  955. return self.erase({})
  956. def is_correct_type(self, w_obj):
  957. space = self.space
  958. return space.is_w(space.type(w_obj), space.w_int)
  959. def _never_equal_to(self, w_lookup_type):
  960. space = self.space
  961. # XXX there are many more types
  962. return (space.is_w(w_lookup_type, space.w_NoneType) or
  963. space.is_w(w_lookup_type, space.w_str) or
  964. space.is_w(w_lookup_type, space.w_unicode)
  965. )
  966. def listview_int(self, w_dict):
  967. return self.unerase(w_dict.dstorage).keys()
  968. def wrapkey(space, key):
  969. return space.wrap(key)
  970. def w_keys(self, w_dict):
  971. return self.space.newlist_int(self.listview_int(w_dict))
  972. create_iterator_classes(IntDictStrategy)
  973. def update1(space, w_dict, w_data):
  974. if isinstance(w_data, W_DictMultiObject): # optimization case only
  975. update1_dict_dict(space, w_dict, w_data)
  976. return
  977. w_method = space.findattr(w_data, space.wrap("keys"))
  978. if w_method is None:
  979. # no 'keys' method, so we assume it is a sequence of pairs
  980. data_w = space.listview(w_data)
  981. update1_pairs(space, w_dict, data_w)
  982. else:
  983. # general case -- "for k in o.keys(): dict.__setitem__(d, k, o[k])"
  984. data_w = space.listview(space.call_function(w_method))
  985. update1_keys(space, w_dict, w_data, data_w)
  986. def update1_dict_dict(space, w_dict, w_data):
  987. w_data.get_strategy().rev_update1_dict_dict(w_data, w_dict)
  988. def update1_pairs(space, w_dict, data_w):
  989. for w_pair in data_w:
  990. pair = space.fixedview(w_pair)
  991. if len(pair) != 2:
  992. raise oefmt(space.w_ValueError, "sequence of pairs expected")
  993. w_key, w_value = pair
  994. w_dict.setitem(w_key, w_value)
  995. def update1_keys(space, w_dict, w_data, data_w):
  996. for w_key in data_w:
  997. w_value = space.getitem(w_data, w_key)
  998. w_dict.setitem(w_key, w_value)
  999. init_signature = Signature(['seq_or_map'], None, 'kwargs')
  1000. init_defaults = [None]
  1001. def init_or_update(space, w_dict, __args__, funcname):
  1002. w_src, w_kwds = __args__.parse_obj(
  1003. None, funcname,
  1004. init_signature, # signature
  1005. init_defaults) # default argument
  1006. if w_src is not None:
  1007. update1(space, w_dict, w_src)
  1008. if space.is_true(w_kwds):
  1009. update1(space, w_dict, w_kwds)
  1010. def characterize(space, w_a, w_b):
  1011. """(similar to CPython)
  1012. returns the smallest key in acontent for which b's value is
  1013. different or absent and this value"""
  1014. w_smallest_diff_a_key = None
  1015. w_its_value = None
  1016. iteratorimplementation = w_a.iteritems()
  1017. while True:
  1018. w_key, w_val = iteratorimplementation.next_item()
  1019. if w_key is None:
  1020. break
  1021. if w_smallest_diff_a_key is None or space.is_true(space.lt(
  1022. w_key, w_smallest_diff_a_key)):
  1023. w_bvalue = w_b.getitem(w_key)
  1024. if w_bvalue is None:
  1025. w_its_value = w_val
  1026. w_smallest_diff_a_key = w_key
  1027. else:
  1028. if not space.eq_w(w_val, w_bvalue):
  1029. w_its_value = w_val
  1030. w_smallest_diff_a_key = w_key
  1031. return w_smallest_diff_a_key, w_its_value
  1032. # ____________________________________________________________
  1033. # Iteration
  1034. class W_BaseDictMultiIterObject(W_Root):
  1035. _immutable_fields_ = ["iteratorimplementation"]
  1036. def __init__(self, space, iteratorimplementation):
  1037. self.space = space
  1038. self.iteratorimplementation = iteratorimplementation
  1039. def descr_iter(self, space):
  1040. return self
  1041. def descr_length_hint(self, space):
  1042. return space.wrap(self.iteratorimplementation.length())
  1043. def descr_reduce(self, space):
  1044. """
  1045. This is a slightly special case of pickling.
  1046. Since iteration over a dict is a bit hairy,
  1047. we do the following:
  1048. - create a clone of the dict iterator
  1049. - run it to the original position
  1050. - collect all remaining elements into a list
  1051. At unpickling time, we just use that list
  1052. and create an iterator on it.
  1053. This is of course not the standard way.
  1054. XXX to do: remove this __reduce__ method and do
  1055. a registration with copy_reg, instead.
  1056. """
  1057. w_mod = space.getbuiltinmodule('_pickle_support')
  1058. mod = space.interp_w(MixedModule, w_mod)
  1059. new_inst = mod.get('dictiter_surrogate_new')
  1060. w_typeobj = space.type(self)
  1061. raise oefmt(space.w_TypeError,
  1062. "can't pickle dictionary-keyiterator objects")
  1063. # XXXXXX get that working again
  1064. # we cannot call __init__ since we don't have the original dict
  1065. if isinstance(self, W_DictMultiIterKeysObject):
  1066. w_clone = space.allocate_instance(W_DictMultiIterKeysObject,
  1067. w_typeobj)
  1068. elif isinstance(self, W_DictMultiIterValuesObject):
  1069. w_clone = space.allocate_instance(W_DictMultiIterValuesObject,
  1070. w_typeobj)
  1071. elif isinstance(self, W_DictMultiIterItemsObject):
  1072. w_clone = space.allocate_instance(W_DictMultiIterItemsObject,
  1073. w_typeobj)
  1074. else:
  1075. raise oefmt(space.w_TypeError,
  1076. "unsupported dictiter type '%R' during pickling", self)
  1077. w_clone.space = space
  1078. w_clone.content = self.content
  1079. w_clone.len = self.len
  1080. w_clone.pos = 0
  1081. w_clone.setup_iterator()
  1082. # spool until we have the same pos
  1083. while w_clone.pos < self.pos:
  1084. w_clone.next_entry()
  1085. w_clone.pos += 1
  1086. stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)]
  1087. w_res = space.newlist(stuff)
  1088. w_ret = space.newtuple([new_inst, space.newtuple([w_res])])
  1089. return w_ret
  1090. def _cleanup_(self):
  1091. raise Exception("seeing a prebuilt %r object" % (
  1092. self.__class__,))
  1093. class W_DictMultiIterKeysObject(W_BaseDictMultiIterObject):
  1094. def descr_next(self, space):
  1095. iteratorimplementation = self.iteratorimplementation
  1096. w_key = iteratorimplementation.next_key()
  1097. if w_key is not None:
  1098. return w_key
  1099. raise OperationError(space.w_StopIteration, space.w_None)
  1100. class W_DictMultiIterValuesObject(W_BaseDictMultiIterObject):
  1101. def descr_next(self, space):
  1102. iteratorimplementation = self.iteratorimplementation
  1103. w_value = iteratorimplementation.next_value()
  1104. if w_value is not None:
  1105. return w_value
  1106. raise OperationError(space.w_StopIteration, space.w_None)
  1107. class W_DictMultiIterItemsObject(W_BaseDictMultiIterObject):
  1108. def descr_next(self, space):
  1109. iteratorimplementation = self.iteratorimplementation
  1110. w_key, w_value = iteratorimplementation.next_item()
  1111. if w_key is not None:
  1112. return space.newtuple([w_key, w_value])
  1113. raise OperationError(space.w_StopIteration, space.w_None)
  1114. W_DictMultiIterItemsObject.typedef = TypeDef(
  1115. "dict_iteritems",
  1116. __iter__ = interp2app(W_DictMultiIterItemsObject.descr_iter),
  1117. next = interp2app(W_DictMultiIterItemsObject.descr_next),
  1118. __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint),
  1119. __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce),
  1120. )
  1121. W_DictMultiIterKeysObject.typedef = TypeDef(
  1122. "dict_iterkeys",
  1123. __iter__ = interp2app(W_DictMultiIterKeysObject.descr_iter),
  1124. next = interp2app(W_DictMultiIterKeysObject.descr_next),
  1125. __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint),
  1126. __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce),
  1127. )
  1128. W_DictMultiIterValuesObject.typedef = TypeDef(
  1129. "dict_itervalues",
  1130. __iter__ = interp2app(W_DictMultiIterValuesObject.descr_iter),
  1131. next = interp2app(W_DictMultiIterValuesObject.descr_next),
  1132. __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint),
  1133. __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce),
  1134. )
  1135. # ____________________________________________________________
  1136. # Views
  1137. class W_DictViewObject(W_Root):
  1138. def __init__(self, space, w_dict):
  1139. self.w_dict = w_dict
  1140. def descr_repr(self, space):
  1141. w_seq = space.call_function(spac

Large files files are truncated, but you can click here to view the full file