PageRenderTime 44ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 1ms

/rpython/rlib/objectmodel.py

https://bitbucket.org/pypy/pypy/
Python | 943 lines | 898 code | 9 blank | 36 comment | 20 complexity | 30a8eef84beb0cfa9c6601e9901be351 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """
  2. This file defines utilities for manipulating objects in an
  3. RPython-compliant way.
  4. """
  5. from __future__ import absolute_import
  6. import sys
  7. import types
  8. import math
  9. import inspect
  10. from collections import OrderedDict
  11. from rpython.tool.sourcetools import rpython_wrapper, func_with_new_name
  12. from rpython.rtyper.extregistry import ExtRegistryEntry
  13. from rpython.flowspace.specialcase import register_flow_sc
  14. from rpython.flowspace.model import Constant
  15. # specialize is a decorator factory for attaching _annspecialcase_
  16. # attributes to functions: for example
  17. #
  18. # f._annspecialcase_ = 'specialize:memo' can be expressed with:
  19. # @specialize.memo()
  20. # def f(...
  21. #
  22. # f._annspecialcase_ = 'specialize:arg(0)' can be expressed with:
  23. # @specialize.arg(0)
  24. # def f(...
  25. #
  26. class _Specialize(object):
  27. def memo(self):
  28. """ Specialize the function based on argument values. All arguments
  29. have to be either constants or PBCs (i.e. instances of classes with a
  30. _freeze_ method returning True). The function call is replaced by
  31. just its result, or in case several PBCs are used, by some fast
  32. look-up of the result.
  33. """
  34. def decorated_func(func):
  35. func._annspecialcase_ = 'specialize:memo'
  36. return func
  37. return decorated_func
  38. def arg(self, *args):
  39. """ Specialize the function based on the values of given positions
  40. of arguments. They must be compile-time constants in order to work.
  41. There will be a copy of provided function for each combination
  42. of given arguments on positions in args (that can lead to
  43. exponential behavior!).
  44. """
  45. def decorated_func(func):
  46. func._annspecialcase_ = 'specialize:arg' + self._wrap(args)
  47. return func
  48. return decorated_func
  49. def arg_or_var(self, *args):
  50. """ Same as arg, but additionally allow for a 'variable' annotation,
  51. that would simply be a situation where designated arg is not
  52. a constant
  53. """
  54. def decorated_func(func):
  55. func._annspecialcase_ = 'specialize:arg_or_var' + self._wrap(args)
  56. return func
  57. return decorated_func
  58. def argtype(self, *args):
  59. """ Specialize function based on types of arguments on given positions.
  60. There will be a copy of provided function for each combination
  61. of given arguments on positions in args (that can lead to
  62. exponential behavior!).
  63. """
  64. def decorated_func(func):
  65. func._annspecialcase_ = 'specialize:argtype' + self._wrap(args)
  66. return func
  67. return decorated_func
  68. def ll(self):
  69. """ This is version of argtypes that cares about low-level types
  70. (so it'll get additional copies for two different types of pointers
  71. for example). Same warnings about exponential behavior apply.
  72. """
  73. def decorated_func(func):
  74. func._annspecialcase_ = 'specialize:ll'
  75. return func
  76. return decorated_func
  77. def ll_and_arg(self, *args):
  78. """ This is like ll(), and additionally like arg(...).
  79. """
  80. def decorated_func(func):
  81. func._annspecialcase_ = 'specialize:ll_and_arg' + self._wrap(args)
  82. return func
  83. return decorated_func
  84. def call_location(self):
  85. """ Specializes the function for each call site.
  86. """
  87. def decorated_func(func):
  88. func._annspecialcase_ = "specialize:call_location"
  89. return func
  90. return decorated_func
  91. def _wrap(self, args):
  92. return "("+','.join([repr(arg) for arg in args]) +")"
  93. specialize = _Specialize()
  94. NOT_CONSTANT = object() # to use in enforceargs()
  95. def enforceargs(*types_, **kwds):
  96. """ Decorate a function with forcing of RPython-level types on arguments.
  97. None means no enforcing.
  98. When not translated, the type of the actual arguments are checked against
  99. the enforced types every time the function is called. You can disable the
  100. typechecking by passing ``typecheck=False`` to @enforceargs.
  101. """
  102. typecheck = kwds.pop('typecheck', True)
  103. if types_ and kwds:
  104. raise TypeError('Cannot mix positional arguments and keywords')
  105. if not typecheck:
  106. def decorator(f):
  107. f._annenforceargs_ = types_
  108. return f
  109. return decorator
  110. #
  111. def decorator(f):
  112. def get_annotation(t):
  113. from rpython.annotator.signature import annotation
  114. from rpython.annotator.model import SomeObject, SomeString, SomeUnicodeString
  115. if isinstance(t, SomeObject):
  116. return t
  117. s_result = annotation(t)
  118. if (isinstance(s_result, SomeString) or
  119. isinstance(s_result, SomeUnicodeString)):
  120. return s_result.__class__(can_be_None=True)
  121. return s_result
  122. def get_type_descr_of_argument(arg):
  123. # we don't want to check *all* the items in list/dict: we assume
  124. # they are already homogeneous, so we only check the first
  125. # item. The case of empty list/dict is handled inside typecheck()
  126. if isinstance(arg, list):
  127. item = arg[0]
  128. return [get_type_descr_of_argument(item)]
  129. elif isinstance(arg, dict):
  130. key, value = next(arg.iteritems())
  131. return {get_type_descr_of_argument(key): get_type_descr_of_argument(value)}
  132. else:
  133. return type(arg)
  134. def typecheck(*args):
  135. from rpython.annotator.model import SomeList, SomeDict, SomeChar,\
  136. SomeInteger
  137. for i, (expected_type, arg) in enumerate(zip(types, args)):
  138. if expected_type is None:
  139. continue
  140. s_expected = get_annotation(expected_type)
  141. # special case: if we expect a list or dict and the argument
  142. # is an empty list/dict, the typecheck always pass
  143. if isinstance(s_expected, SomeList) and arg == []:
  144. continue
  145. if isinstance(s_expected, SomeDict) and arg == {}:
  146. continue
  147. if isinstance(s_expected, SomeChar) and (
  148. isinstance(arg, str) and len(arg) == 1): # a char
  149. continue
  150. if (isinstance(s_expected, SomeInteger) and
  151. isinstance(arg, s_expected.knowntype)):
  152. continue
  153. #
  154. s_argtype = get_annotation(get_type_descr_of_argument(arg))
  155. if not s_expected.contains(s_argtype):
  156. msg = "%s argument %r must be of type %s" % (
  157. f.func_name, srcargs[i], expected_type)
  158. raise TypeError(msg)
  159. #
  160. template = """
  161. def {name}({arglist}):
  162. if not we_are_translated():
  163. typecheck({arglist}) # rpython.rlib.objectmodel
  164. return {original}({arglist})
  165. """
  166. result = rpython_wrapper(f, template,
  167. typecheck=typecheck,
  168. we_are_translated=we_are_translated)
  169. #
  170. srcargs, srcvarargs, srckeywords, defaults = inspect.getargspec(f)
  171. if kwds:
  172. types = tuple([kwds.get(arg) for arg in srcargs])
  173. else:
  174. types = types_
  175. assert len(srcargs) == len(types), (
  176. 'not enough types provided: expected %d, got %d' %
  177. (len(types), len(srcargs)))
  178. result._annenforceargs_ = types
  179. return result
  180. return decorator
  181. def always_inline(func):
  182. """ mark the function as to-be-inlined by the RPython optimizations (not
  183. the JIT!), no matter its size."""
  184. func._always_inline_ = True
  185. return func
  186. def dont_inline(func):
  187. """ mark the function as never-to-be-inlined by the RPython optimizations
  188. (not the JIT!), no matter its size."""
  189. func._dont_inline_ = True
  190. return func
  191. # ____________________________________________________________
  192. class Symbolic(object):
  193. def annotation(self):
  194. return None
  195. def lltype(self):
  196. return None
  197. def __cmp__(self, other):
  198. if self is other:
  199. return 0
  200. else:
  201. raise TypeError("Symbolics cannot be compared! (%r, %r)"
  202. % (self, other))
  203. def __hash__(self):
  204. raise TypeError("Symbolics are not hashable! %r" % (self,))
  205. def __nonzero__(self):
  206. raise TypeError("Symbolics are not comparable! %r" % (self,))
  207. class ComputedIntSymbolic(Symbolic):
  208. def __init__(self, compute_fn):
  209. self.compute_fn = compute_fn
  210. def __repr__(self):
  211. # repr(self.compute_fn) can arrive back here in an
  212. # infinite recursion
  213. try:
  214. name = self.compute_fn.__name__
  215. except (AttributeError, TypeError):
  216. name = hex(id(self.compute_fn))
  217. return '%s(%r)' % (self.__class__.__name__, name)
  218. def annotation(self):
  219. from rpython.annotator import model
  220. return model.SomeInteger()
  221. def lltype(self):
  222. from rpython.rtyper.lltypesystem import lltype
  223. return lltype.Signed
  224. class CDefinedIntSymbolic(Symbolic):
  225. def __init__(self, expr, default=0):
  226. self.expr = expr
  227. self.default = default
  228. def __repr__(self):
  229. return '%s(%r)' % (self.__class__.__name__, self.expr)
  230. def annotation(self):
  231. from rpython.annotator import model
  232. return model.SomeInteger()
  233. def lltype(self):
  234. from rpython.rtyper.lltypesystem import lltype
  235. return lltype.Signed
  236. malloc_zero_filled = CDefinedIntSymbolic('MALLOC_ZERO_FILLED', default=0)
  237. _translated_to_c = CDefinedIntSymbolic('1 /*_translated_to_c*/', default=0)
  238. def we_are_translated_to_c():
  239. return we_are_translated() and _translated_to_c
  240. # ____________________________________________________________
  241. def instantiate(cls, nonmovable=False):
  242. "Create an empty instance of 'cls'."
  243. if isinstance(cls, type):
  244. return cls.__new__(cls)
  245. else:
  246. return types.InstanceType(cls)
  247. def we_are_translated():
  248. return False
  249. @register_flow_sc(we_are_translated)
  250. def sc_we_are_translated(ctx):
  251. return Constant(True)
  252. def register_replacement_for(replaced_function, sandboxed_name=None):
  253. def wrap(func):
  254. from rpython.rtyper.extregistry import ExtRegistryEntry
  255. class ExtRegistry(ExtRegistryEntry):
  256. _about_ = replaced_function
  257. def compute_annotation(self):
  258. if sandboxed_name:
  259. config = self.bookkeeper.annotator.translator.config
  260. if config.translation.sandbox:
  261. func._sandbox_external_name = sandboxed_name
  262. func._dont_inline_ = True
  263. return self.bookkeeper.immutablevalue(func)
  264. return func
  265. return wrap
  266. def keepalive_until_here(*values):
  267. pass
  268. def is_annotation_constant(thing):
  269. """ Returns whether the annotator can prove that the argument is constant.
  270. For advanced usage only."""
  271. return True
  272. class Entry(ExtRegistryEntry):
  273. _about_ = is_annotation_constant
  274. def compute_result_annotation(self, s_arg):
  275. from rpython.annotator import model
  276. r = model.SomeBool()
  277. r.const = s_arg.is_constant()
  278. return r
  279. def specialize_call(self, hop):
  280. from rpython.rtyper.lltypesystem import lltype
  281. hop.exception_cannot_occur()
  282. return hop.inputconst(lltype.Bool, hop.s_result.const)
  283. def int_to_bytearray(i):
  284. # XXX this can be made more efficient in the future
  285. return bytearray(str(i))
  286. def fetch_translated_config():
  287. """Returns the config that is current when translating.
  288. Returns None if not translated.
  289. """
  290. return None
  291. class Entry(ExtRegistryEntry):
  292. _about_ = fetch_translated_config
  293. def compute_result_annotation(self):
  294. config = self.bookkeeper.annotator.translator.config
  295. return self.bookkeeper.immutablevalue(config)
  296. def specialize_call(self, hop):
  297. from rpython.rtyper.lltypesystem import lltype
  298. translator = hop.rtyper.annotator.translator
  299. hop.exception_cannot_occur()
  300. return hop.inputconst(lltype.Void, translator.config)
  301. # ____________________________________________________________
  302. class FREED_OBJECT(object):
  303. def __getattribute__(self, attr):
  304. raise RuntimeError("trying to access freed object")
  305. def __setattr__(self, attr, value):
  306. raise RuntimeError("trying to access freed object")
  307. def free_non_gc_object(obj):
  308. assert not getattr(obj.__class__, "_alloc_flavor_", 'gc').startswith('gc'), "trying to free gc object"
  309. obj.__dict__ = {}
  310. obj.__class__ = FREED_OBJECT
  311. # ____________________________________________________________
  312. def newlist_hint(sizehint=0):
  313. """ Create a new list, but pass a hint how big the size should be
  314. preallocated
  315. """
  316. return []
  317. class Entry(ExtRegistryEntry):
  318. _about_ = newlist_hint
  319. def compute_result_annotation(self, s_sizehint):
  320. from rpython.annotator.model import SomeInteger, AnnotatorError
  321. if not isinstance(s_sizehint, SomeInteger):
  322. raise AnnotatorError("newlist_hint() argument must be an int")
  323. s_l = self.bookkeeper.newlist()
  324. s_l.listdef.listitem.resize()
  325. return s_l
  326. def specialize_call(self, orig_hop, i_sizehint=None):
  327. from rpython.rtyper.rlist import rtype_newlist
  328. # fish a bit hop
  329. hop = orig_hop.copy()
  330. v = hop.args_v[0]
  331. r, s = hop.r_s_popfirstarg()
  332. if s.is_constant():
  333. v = hop.inputconst(r, s.const)
  334. hop.exception_is_here()
  335. return rtype_newlist(hop, v_sizehint=v)
  336. def resizelist_hint(l, sizehint):
  337. """Reallocate the underlying list to the specified sizehint"""
  338. return
  339. class Entry(ExtRegistryEntry):
  340. _about_ = resizelist_hint
  341. def compute_result_annotation(self, s_l, s_sizehint):
  342. from rpython.annotator import model as annmodel
  343. if annmodel.s_None.contains(s_l):
  344. return # first argument is only None so far, but we
  345. # expect a generalization later
  346. if not isinstance(s_l, annmodel.SomeList):
  347. raise annmodel.AnnotatorError("First argument must be a list")
  348. if not isinstance(s_sizehint, annmodel.SomeInteger):
  349. raise annmodel.AnnotatorError("Second argument must be an integer")
  350. s_l.listdef.listitem.resize()
  351. def specialize_call(self, hop):
  352. r_list = hop.args_r[0]
  353. v_list, v_sizehint = hop.inputargs(*hop.args_r)
  354. hop.exception_is_here()
  355. hop.gendirectcall(r_list.LIST._ll_resize_hint, v_list, v_sizehint)
  356. # ____________________________________________________________
  357. #
  358. # id-like functions. The idea is that calling hash() or id() is not
  359. # allowed in RPython. You have to call one of the following more
  360. # precise functions.
  361. def compute_hash(x):
  362. """RPython equivalent of hash(x), where 'x' is an immutable
  363. RPython-level. For strings or unicodes it computes the hash as
  364. in Python. For tuples it calls compute_hash() recursively.
  365. For instances it uses compute_identity_hash().
  366. Note that this can return 0 or -1 too.
  367. It returns the same number, both before and after translation.
  368. Dictionaries don't need to be rehashed after translation.
  369. """
  370. if isinstance(x, (str, unicode)):
  371. return _hash_string(x)
  372. if isinstance(x, int):
  373. return x
  374. if isinstance(x, float):
  375. return _hash_float(x)
  376. if isinstance(x, tuple):
  377. return _hash_tuple(x)
  378. if x is None:
  379. return 0
  380. return compute_identity_hash(x)
  381. def compute_identity_hash(x):
  382. """RPython equivalent of object.__hash__(x). This returns the
  383. so-called 'identity hash', which is the non-overridable default hash
  384. of Python. Can be called for any RPython-level object that turns
  385. into a GC object, but not NULL. The value is not guaranteed to be the
  386. same before and after translation, except for RPython instances on the
  387. lltypesystem.
  388. """
  389. assert x is not None
  390. result = object.__hash__(x)
  391. try:
  392. x.__dict__['__precomputed_identity_hash'] = result
  393. except (TypeError, AttributeError):
  394. pass
  395. return result
  396. def compute_unique_id(x):
  397. """RPython equivalent of id(x). The 'x' must be an RPython-level
  398. object that turns into a GC object. This operation can be very
  399. costly depending on the garbage collector. To remind you of this
  400. fact, we don't support id(x) directly.
  401. """
  402. # The assumption with RPython is that a regular integer is wide enough
  403. # to store a pointer. The following intmask() should not loose any
  404. # information.
  405. from rpython.rlib.rarithmetic import intmask
  406. return intmask(id(x))
  407. def current_object_addr_as_int(x):
  408. """A cheap version of id(x).
  409. The current memory location of an object can change over time for moving
  410. GCs.
  411. """
  412. from rpython.rlib.rarithmetic import intmask
  413. return intmask(id(x))
  414. # ----------
  415. def _hash_string(s):
  416. """The algorithm behind compute_hash() for a string or a unicode."""
  417. from rpython.rlib.rarithmetic import intmask
  418. length = len(s)
  419. if length == 0:
  420. return -1
  421. x = ord(s[0]) << 7
  422. i = 0
  423. while i < length:
  424. x = intmask((1000003*x) ^ ord(s[i]))
  425. i += 1
  426. x ^= length
  427. return intmask(x)
  428. def _hash_float(f):
  429. """The algorithm behind compute_hash() for a float.
  430. This implementation is identical to the CPython implementation,
  431. except the fact that the integer case is not treated specially.
  432. In RPython, floats cannot be used with ints in dicts, anyway.
  433. """
  434. from rpython.rlib.rarithmetic import intmask
  435. from rpython.rlib.rfloat import isfinite, isinf
  436. if not isfinite(f):
  437. if isinf(f):
  438. if f < 0.0:
  439. return -271828
  440. else:
  441. return 314159
  442. else: #isnan(f):
  443. return 0
  444. v, expo = math.frexp(f)
  445. v *= TAKE_NEXT
  446. hipart = int(v)
  447. v = (v - float(hipart)) * TAKE_NEXT
  448. x = hipart + int(v) + (expo << 15)
  449. return intmask(x)
  450. TAKE_NEXT = float(2**31)
  451. def _hash_tuple(t):
  452. """NOT_RPYTHON. The algorithm behind compute_hash() for a tuple.
  453. It is modelled after the old algorithm of Python 2.3, which is
  454. a bit faster than the one introduced by Python 2.4. We assume
  455. that nested tuples are very uncommon in RPython, making the bad
  456. case unlikely.
  457. """
  458. from rpython.rlib.rarithmetic import intmask
  459. x = 0x345678
  460. for item in t:
  461. y = compute_hash(item)
  462. x = intmask((1000003 * x) ^ y)
  463. return x
  464. # ----------
  465. class Entry(ExtRegistryEntry):
  466. _about_ = compute_hash
  467. def compute_result_annotation(self, s_x):
  468. from rpython.annotator import model as annmodel
  469. return annmodel.SomeInteger()
  470. def specialize_call(self, hop):
  471. r_obj, = hop.args_r
  472. v_obj, = hop.inputargs(r_obj)
  473. ll_fn = r_obj.get_ll_hash_function()
  474. hop.exception_is_here()
  475. return hop.gendirectcall(ll_fn, v_obj)
  476. class Entry(ExtRegistryEntry):
  477. _about_ = compute_identity_hash
  478. def compute_result_annotation(self, s_x):
  479. from rpython.annotator import model as annmodel
  480. return annmodel.SomeInteger()
  481. def specialize_call(self, hop):
  482. from rpython.rtyper.lltypesystem import lltype
  483. vobj, = hop.inputargs(hop.args_r[0])
  484. ok = (isinstance(vobj.concretetype, lltype.Ptr) and
  485. vobj.concretetype.TO._gckind == 'gc')
  486. if not ok:
  487. from rpython.rtyper.error import TyperError
  488. raise TyperError("compute_identity_hash() cannot be applied to"
  489. " %r" % (vobj.concretetype,))
  490. hop.exception_cannot_occur()
  491. return hop.genop('gc_identityhash', [vobj], resulttype=lltype.Signed)
  492. class Entry(ExtRegistryEntry):
  493. _about_ = compute_unique_id
  494. def compute_result_annotation(self, s_x):
  495. from rpython.annotator import model as annmodel
  496. return annmodel.SomeInteger()
  497. def specialize_call(self, hop):
  498. from rpython.rtyper.lltypesystem import lltype
  499. vobj, = hop.inputargs(hop.args_r[0])
  500. ok = (isinstance(vobj.concretetype, lltype.Ptr) and
  501. vobj.concretetype.TO._gckind == 'gc')
  502. if not ok:
  503. from rpython.rtyper.error import TyperError
  504. raise TyperError("compute_unique_id() cannot be applied to"
  505. " %r" % (vobj.concretetype,))
  506. hop.exception_cannot_occur()
  507. return hop.genop('gc_id', [vobj], resulttype=lltype.Signed)
  508. class Entry(ExtRegistryEntry):
  509. _about_ = current_object_addr_as_int
  510. def compute_result_annotation(self, s_x):
  511. from rpython.annotator import model as annmodel
  512. return annmodel.SomeInteger()
  513. def specialize_call(self, hop):
  514. vobj, = hop.inputargs(hop.args_r[0])
  515. hop.exception_cannot_occur()
  516. from rpython.rtyper.lltypesystem import lltype
  517. if isinstance(vobj.concretetype, lltype.Ptr):
  518. return hop.genop('cast_ptr_to_int', [vobj],
  519. resulttype = lltype.Signed)
  520. from rpython.rtyper.error import TyperError
  521. raise TyperError("current_object_addr_as_int() cannot be applied to"
  522. " %r" % (vobj.concretetype,))
  523. # ____________________________________________________________
  524. def hlinvoke(repr, llcallable, *args):
  525. raise TypeError("hlinvoke is meant to be rtyped and not called direclty")
  526. def is_in_callback():
  527. """Returns True if we're currently in a callback *or* if there are
  528. multiple threads around.
  529. """
  530. from rpython.rtyper.lltypesystem import rffi
  531. return rffi.stackcounter.stacks_counter > 1
  532. class UnboxedValue(object):
  533. """A mixin class to use for classes that have exactly one field which
  534. is an integer. They are represented as a tagged pointer, if the
  535. translation.taggedpointers config option is used."""
  536. _mixin_ = True
  537. def __new__(cls, value):
  538. assert '__init__' not in cls.__dict__ # won't be called anyway
  539. assert isinstance(cls.__slots__, str) or len(cls.__slots__) == 1
  540. return super(UnboxedValue, cls).__new__(cls)
  541. def __init__(self, value):
  542. # this funtion is annotated but not included in the translated program
  543. int_as_pointer = value * 2 + 1 # XXX for now
  544. if -sys.maxint-1 <= int_as_pointer <= sys.maxint:
  545. if isinstance(self.__class__.__slots__, str):
  546. setattr(self, self.__class__.__slots__, value)
  547. else:
  548. setattr(self, self.__class__.__slots__[0], value)
  549. else:
  550. raise OverflowError("UnboxedValue: argument out of range")
  551. def __repr__(self):
  552. return '<unboxed %d>' % (self.get_untagged_value(),)
  553. def get_untagged_value(self): # helper, equivalent to reading the custom field
  554. if isinstance(self.__class__.__slots__, str):
  555. return getattr(self, self.__class__.__slots__)
  556. else:
  557. return getattr(self, self.__class__.__slots__[0])
  558. # ____________________________________________________________
  559. def likely(condition):
  560. assert isinstance(condition, bool)
  561. return condition
  562. def unlikely(condition):
  563. assert isinstance(condition, bool)
  564. return condition
  565. class Entry(ExtRegistryEntry):
  566. _about_ = (likely, unlikely)
  567. def compute_result_annotation(self, s_x):
  568. from rpython.annotator import model as annmodel
  569. return annmodel.SomeBool()
  570. def specialize_call(self, hop):
  571. from rpython.rtyper.lltypesystem import lltype
  572. vlist = hop.inputargs(lltype.Bool)
  573. hop.exception_cannot_occur()
  574. return hop.genop(self.instance.__name__, vlist,
  575. resulttype=lltype.Bool)
  576. # ____________________________________________________________
  577. class r_dict(object):
  578. """An RPython dict-like object.
  579. Only provides the interface supported by RPython.
  580. The functions key_eq() and key_hash() are used by the key comparison
  581. algorithm."""
  582. def _newdict(self):
  583. return {}
  584. def __init__(self, key_eq, key_hash, force_non_null=False):
  585. self._dict = self._newdict()
  586. self.key_eq = key_eq
  587. self.key_hash = key_hash
  588. self.force_non_null = force_non_null
  589. def __getitem__(self, key):
  590. return self._dict[_r_dictkey(self, key)]
  591. def __setitem__(self, key, value):
  592. self._dict[_r_dictkey(self, key)] = value
  593. def __delitem__(self, key):
  594. del self._dict[_r_dictkey(self, key)]
  595. def __len__(self):
  596. return len(self._dict)
  597. def __iter__(self):
  598. for dk in self._dict:
  599. yield dk.key
  600. def __contains__(self, key):
  601. return _r_dictkey(self, key) in self._dict
  602. def get(self, key, default):
  603. return self._dict.get(_r_dictkey(self, key), default)
  604. def setdefault(self, key, default):
  605. return self._dict.setdefault(_r_dictkey(self, key), default)
  606. def popitem(self):
  607. dk, value = self._dict.popitem()
  608. return dk.key, value
  609. def copy(self):
  610. result = self.__class__(self.key_eq, self.key_hash)
  611. result.update(self)
  612. return result
  613. def update(self, other):
  614. for key, value in other.items():
  615. self[key] = value
  616. def keys(self):
  617. return [dk.key for dk in self._dict]
  618. def values(self):
  619. return self._dict.values()
  620. def items(self):
  621. return [(dk.key, value) for dk, value in self._dict.items()]
  622. iterkeys = __iter__
  623. def itervalues(self):
  624. return self._dict.itervalues()
  625. def iteritems(self):
  626. for dk, value in self._dict.items():
  627. yield dk.key, value
  628. def clear(self):
  629. self._dict.clear()
  630. def __repr__(self):
  631. "Representation for debugging purposes."
  632. return 'r_dict(%r)' % (self._dict,)
  633. def __hash__(self):
  634. raise TypeError("cannot hash r_dict instances")
  635. class r_ordereddict(r_dict):
  636. def _newdict(self):
  637. return OrderedDict()
  638. class _r_dictkey(object):
  639. __slots__ = ['dic', 'key', 'hash']
  640. def __init__(self, dic, key):
  641. self.dic = dic
  642. self.key = key
  643. self.hash = dic.key_hash(key)
  644. def __eq__(self, other):
  645. if not isinstance(other, _r_dictkey):
  646. return NotImplemented
  647. return self.dic.key_eq(self.key, other.key)
  648. def __ne__(self, other):
  649. if not isinstance(other, _r_dictkey):
  650. return NotImplemented
  651. return not self.dic.key_eq(self.key, other.key)
  652. def __hash__(self):
  653. return self.hash
  654. def __repr__(self):
  655. return repr(self.key)
  656. @specialize.call_location()
  657. def prepare_dict_update(dict, n_elements):
  658. """RPython hint that the given dict (or r_dict) will soon be
  659. enlarged by n_elements."""
  660. if we_are_translated():
  661. dict._prepare_dict_update(n_elements)
  662. # ^^ call an extra method that doesn't exist before translation
  663. @specialize.call_location()
  664. def reversed_dict(d):
  665. """Equivalent to reversed(ordered_dict), but works also for
  666. regular dicts."""
  667. # note that there is also __pypy__.reversed_dict(), which we could
  668. # try to use here if we're not translated and running on top of pypy,
  669. # but that seems a bit pointless
  670. if not we_are_translated():
  671. d = d.keys()
  672. return reversed(d)
  673. def _expected_hash(d, key):
  674. if isinstance(d, r_dict):
  675. return d.key_hash(key)
  676. else:
  677. return compute_hash(key)
  678. def _iterkeys_with_hash_untranslated(d):
  679. for k in d:
  680. yield (k, _expected_hash(d, k))
  681. @specialize.call_location()
  682. def iterkeys_with_hash(d):
  683. """Iterates (key, hash) pairs without recomputing the hash."""
  684. if not we_are_translated():
  685. return _iterkeys_with_hash_untranslated(d)
  686. return d.iterkeys_with_hash()
  687. def _iteritems_with_hash_untranslated(d):
  688. for k, v in d.iteritems():
  689. yield (k, v, _expected_hash(d, k))
  690. @specialize.call_location()
  691. def iteritems_with_hash(d):
  692. """Iterates (key, value, keyhash) triples without recomputing the hash."""
  693. if not we_are_translated():
  694. return _iteritems_with_hash_untranslated(d)
  695. return d.iteritems_with_hash()
  696. @specialize.call_location()
  697. def contains_with_hash(d, key, h):
  698. """Same as 'key in d'. The extra argument is the hash. Use this only
  699. if you got the hash just now from some other ..._with_hash() function."""
  700. if not we_are_translated():
  701. assert _expected_hash(d, key) == h
  702. return key in d
  703. return d.contains_with_hash(key, h)
  704. @specialize.call_location()
  705. def setitem_with_hash(d, key, h, value):
  706. """Same as 'd[key] = value'. The extra argument is the hash. Use this only
  707. if you got the hash just now from some other ..._with_hash() function."""
  708. if not we_are_translated():
  709. assert _expected_hash(d, key) == h
  710. d[key] = value
  711. return
  712. d.setitem_with_hash(key, h, value)
  713. @specialize.call_location()
  714. def getitem_with_hash(d, key, h):
  715. """Same as 'd[key]'. The extra argument is the hash. Use this only
  716. if you got the hash just now from some other ..._with_hash() function."""
  717. if not we_are_translated():
  718. assert _expected_hash(d, key) == h
  719. return d[key]
  720. return d.getitem_with_hash(key, h)
  721. @specialize.call_location()
  722. def delitem_with_hash(d, key, h):
  723. """Same as 'del d[key]'. The extra argument is the hash. Use this only
  724. if you got the hash just now from some other ..._with_hash() function."""
  725. if not we_are_translated():
  726. assert _expected_hash(d, key) == h
  727. del d[key]
  728. return
  729. d.delitem_with_hash(key, h)
  730. # ____________________________________________________________
  731. def import_from_mixin(M, special_methods=['__init__', '__del__']):
  732. """Copy all methods and class attributes from the class M into
  733. the current scope. Should be called when defining a class body.
  734. Function and staticmethod objects are duplicated, which means
  735. that annotation will not consider them as identical to another
  736. copy in another unrelated class.
  737. By default, "special" methods and class attributes, with a name
  738. like "__xxx__", are not copied unless they are "__init__" or
  739. "__del__". The list can be changed with the optional second
  740. argument.
  741. """
  742. flatten = {}
  743. caller = sys._getframe(1)
  744. caller_name = caller.f_globals.get('__name__')
  745. immutable_fields = []
  746. for base in inspect.getmro(M):
  747. if base is object:
  748. continue
  749. for key, value in base.__dict__.items():
  750. if key == '_immutable_fields_':
  751. immutable_fields.extend(value)
  752. continue
  753. if key.startswith('__') and key.endswith('__'):
  754. if key not in special_methods:
  755. continue
  756. if key in flatten:
  757. continue
  758. if isinstance(value, types.FunctionType):
  759. value = func_with_new_name(value, value.__name__)
  760. elif isinstance(value, staticmethod):
  761. func = value.__get__(42)
  762. func = func_with_new_name(func, func.__name__)
  763. if caller_name:
  764. # staticmethods lack a unique im_class so further
  765. # distinguish them from themselves
  766. func.__module__ = caller_name
  767. value = staticmethod(func)
  768. elif isinstance(value, classmethod):
  769. raise AssertionError("classmethods not supported "
  770. "in 'import_from_mixin'")
  771. flatten[key] = value
  772. #
  773. target = caller.f_locals
  774. for key, value in flatten.items():
  775. if key in target:
  776. raise Exception("import_from_mixin: would overwrite the value "
  777. "already defined locally for %r" % (key,))
  778. if key == '_mixin_':
  779. raise Exception("import_from_mixin(M): class M should not "
  780. "have '_mixin_ = True'")
  781. target[key] = value
  782. if immutable_fields:
  783. target['_immutable_fields_'] = target.get('_immutable_fields_', []) + immutable_fields