PageRenderTime 31ms CodeModel.GetById 19ms 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
  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(space.w_list, self)
  1142. w_repr = space.repr(w_seq)
  1143. return space.wrap("%s(%s)" % (space.type(self).getname(space),
  1144. space.str_w(w_repr)))
  1145. def descr_len(self, space):
  1146. return space.len(self.w_dict)
  1147. def _all_contained_in(space, w_dictview, w_other):
  1148. for w_item in space.iteriterable(w_dictview):
  1149. if not space.contains_w(w_other, w_item):
  1150. return space.w_False
  1151. return space.w_True
  1152. def _is_set_like(w_other):
  1153. from pypy.objspace.std.setobject import W_BaseSetObject
  1154. return (isinstance(w_other, W_BaseSetObject) or
  1155. isinstance(w_other, W_DictViewKeysObject) or
  1156. isinstance(w_other, W_DictViewItemsObject))
  1157. class SetLikeDictView(object):
  1158. _mixin_ = True
  1159. def descr_eq(self, space, w_other):
  1160. if not _is_set_like(w_other):
  1161. return space.w_NotImplemented
  1162. if space.len_w(self) == space.len_w(w_other):
  1163. return _all_contained_in(space, self, w_other)
  1164. return space.w_False
  1165. descr_ne = negate(descr_eq)
  1166. def descr_lt(self, space, w_other):
  1167. if not _is_set_like(w_other):
  1168. return space.w_NotImplemented
  1169. if space.len_w(self) < space.len_w(w_other):
  1170. return _all_contained_in(space, self, w_other)
  1171. return space.w_False
  1172. def descr_le(self, space, w_other):
  1173. if not _is_set_like(w_other):
  1174. return space.w_NotImplemented
  1175. if space.len_w(self) <= space.len_w(w_other):
  1176. return _all_contained_in(space, self, w_other)
  1177. return space.w_False
  1178. def descr_gt(self, space, w_other):
  1179. if not _is_set_like(w_other):
  1180. return space.w_NotImplemented
  1181. if space.len_w(self) > space.len_w(w_other):
  1182. return _all_contained_in(space, w_other, self)
  1183. return space.w_False
  1184. def descr_ge(self, space, w_other):
  1185. if not _is_set_like(w_other):
  1186. return space.w_NotImplemented
  1187. if space.len_w(self) >= space.len_w(w_other):
  1188. return _all_contained_in(space, w_other, self)
  1189. return space.w_False
  1190. def _as_set_op(name, methname):
  1191. @func_renamer('descr_' + name)
  1192. def op(self, space, w_other):
  1193. w_set = space.call_function(space.w_set, self)
  1194. space.call_method(w_set, methname, w_other)
  1195. return w_set
  1196. @func_renamer('descr_r' + name)
  1197. def rop(self, space, w_other):
  1198. w_set = space.call_function(space.w_set, w_other)
  1199. space.call_method(w_set, methname, self)
  1200. return w_set
  1201. return op, rop
  1202. descr_sub, descr_rsub = _as_set_op('sub', 'difference_update')
  1203. descr_and, descr_rand = _as_set_op('and', 'intersection_update')
  1204. descr_or, descr_ror = _as_set_op('or', 'update')
  1205. descr_xor, descr_rxor = _as_set_op('xor', 'symmetric_difference_update')
  1206. class W_DictViewItemsObject(W_DictViewObject, SetLikeDictView):
  1207. def descr_iter(self, space):
  1208. return W_DictMultiIterItemsObject(space, self.w_dict.iteritems())
  1209. class W_DictViewKeysObject(W_DictViewObject, SetLikeDictView):
  1210. def descr_iter(self, space):
  1211. return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys())
  1212. class W_DictViewValuesObject(W_DictViewObject):
  1213. def descr_iter(self, space):
  1214. return W_DictMultiIterValuesObject(space, self.w_dict.itervalues())
  1215. W_DictViewItemsObject.typedef = TypeDef(
  1216. "dict_items",
  1217. __repr__ = interp2app(W_DictViewItemsObject.descr_repr),
  1218. __len__ = interp2app(W_DictViewItemsObject.descr_len),
  1219. __iter__ = interp2app(W_DictViewItemsObject.descr_iter),
  1220. __eq__ = interp2app(W_DictViewItemsObject.descr_eq),
  1221. __ne__ = interp2app(W_DictViewItemsObject.descr_ne),
  1222. __lt__ = interp2app(W_DictViewItemsObject.descr_lt),
  1223. __le__ = interp2app(W_DictViewItemsObject.descr_le),
  1224. __gt__ = interp2app(W_DictViewItemsObject.descr_gt),
  1225. __ge__ = interp2app(W_DictViewItemsObject.descr_ge),
  1226. __sub__ = interp2app(W_DictViewItemsObject.descr_sub),
  1227. __rsub__ = interp2app(W_DictViewItemsObject.descr_rsub),
  1228. __and__ = interp2app(W_DictViewItemsObject.descr_and),
  1229. __rand__ = interp2app(W_DictViewItemsObject.descr_rand),
  1230. __or__ = interp2app(W_DictViewItemsObject.descr_or),
  1231. __ror__ = interp2app(W_DictViewItemsObject.descr_ror),
  1232. __xor__ = interp2app(W_DictViewItemsObject.descr_xor),
  1233. __rxor__ = interp2app(W_DictViewItemsObject.descr_rxor),
  1234. )
  1235. W_DictViewKeysObject.typedef = TypeDef(
  1236. "dict_keys",
  1237. __repr__ = interp2app(W_DictViewKeysObject.descr_repr),
  1238. __len__ = interp2app(W_DictViewKeysObject.descr_len),
  1239. __iter__ = interp2app(W_DictViewKeysObject.descr_iter),
  1240. __eq__ = interp2app(W_DictViewKeysObject.descr_eq),
  1241. __ne__ = interp2app(W_DictViewKeysObject.descr_ne),
  1242. __lt__ = interp2app(W_DictViewKeysObject.descr_lt),
  1243. __le__ = interp2app(W_DictViewKeysObject.descr_le),
  1244. __gt__ = interp2app(W_DictViewKeysObject.descr_gt),
  1245. __ge__ = interp2app(W_DictViewKeysObject.descr_ge),
  1246. __sub__ = interp2app(W_DictViewKeysObject.descr_sub),
  1247. __rsub__ = interp2app(W_DictViewKeysObject.descr_rsub),
  1248. __and__ = interp2app(W_DictViewKeysObject.descr_and),
  1249. __rand__ = interp2app(W_DictViewKeysObject.descr_rand),
  1250. __or__ = interp2app(W_DictViewKeysObject.descr_or),
  1251. __ror__ = interp2app(W_DictViewKeysObject.descr_ror),
  1252. __xor__ = interp2app(W_DictViewKeysObject.descr_xor),
  1253. __rxor__ = interp2app(W_DictViewKeysObject.descr_rxor),
  1254. )
  1255. W_DictViewValuesObject.typedef = TypeDef(
  1256. "dict_values",
  1257. __repr__ = interp2app(W_DictViewValuesObject.descr_repr),
  1258. __len__ = interp2app(W_DictViewValuesObject.descr_len),
  1259. __iter__ = interp2app(W_DictViewValuesObject.descr_iter),
  1260. )