File: dictdef.py

package info (click to toggle)
pypy 7.0.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 107,216 kB
  • sloc: python: 1,201,787; ansic: 62,419; asm: 5,169; cpp: 3,017; sh: 2,534; makefile: 545; xml: 243; lisp: 45; awk: 4
file content (117 lines) | stat: -rw-r--r-- 4,248 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
from rpython.annotator.model import (
    s_ImpossibleValue, SomeInteger, s_Bool, union, AnnotatorError)
from rpython.annotator.listdef import ListItem
from rpython.rlib.objectmodel import compute_hash


class DictKey(ListItem):
    s_rdict_eqfn = s_ImpossibleValue
    s_rdict_hashfn = s_ImpossibleValue

    def __init__(self, bookkeeper, s_value, is_r_dict=False):
        ListItem.__init__(self, bookkeeper, s_value)
        self.custom_eq_hash = is_r_dict

    def patch(self):
        for dictdef in self.itemof:
            dictdef.dictkey = self

    def merge(self, other):
        if self is not other:
            assert self.custom_eq_hash == other.custom_eq_hash, (
                "mixing plain dictionaries with r_dict()")
            ListItem.merge(self, other)
            if self.custom_eq_hash:
                self.update_rdict_annotations(other.s_rdict_eqfn,
                                              other.s_rdict_hashfn,
                                              other=other)

    def generalize(self, s_other_value):
        updated = ListItem.generalize(self, s_other_value)
        if updated and self.custom_eq_hash:
            self.emulate_rdict_calls()
        return updated

    def update_rdict_annotations(self, s_eqfn, s_hashfn, other=None):
        assert self.custom_eq_hash
        s_eqfn = union(s_eqfn, self.s_rdict_eqfn)
        s_hashfn = union(s_hashfn, self.s_rdict_hashfn)
        self.s_rdict_eqfn = s_eqfn
        self.s_rdict_hashfn = s_hashfn
        self.emulate_rdict_calls(other=other)

    def emulate_rdict_calls(self, other=None):
        myeq = (self, 'eq')
        myhash = (self, 'hash')
        if other:
            replace_othereq = [(other, 'eq')]
            replace_otherhash = [(other, 'hash')]
        else:
            replace_othereq = replace_otherhash = ()

        s_key = self.s_value

        s = self.bookkeeper.emulate_pbc_call(
            myeq, self.s_rdict_eqfn, [s_key, s_key], replace=replace_othereq)
        if not s_Bool.contains(s):
            raise AnnotatorError(
                "the custom eq function of an r_dict must return a boolean"
                " (got %r)" % (s,))

        s = self.bookkeeper.emulate_pbc_call(
            myhash, self.s_rdict_hashfn, [s_key], replace=replace_otherhash)
        if not SomeInteger().contains(s):
            raise AnnotatorError(
                "the custom hash function of an r_dict must return an integer"
                " (got %r)" % (s,))


class DictValue(ListItem):
    def patch(self):
        for dictdef in self.itemof:
            dictdef.dictvalue = self


class DictDef(object):
    """A dict definition remembers how general the keys and values in that
    particular dict have to be.  Every dict creation makes a new DictDef,
    and the union of two dicts merges the DictKeys and DictValues that each
    DictDef stores."""

    def __init__(self, bookkeeper, s_key = s_ImpossibleValue,
                                 s_value = s_ImpossibleValue,
                               is_r_dict = False,
                           force_non_null = False,
                           simple_hash_eq = False):
        self.dictkey = DictKey(bookkeeper, s_key, is_r_dict)
        self.dictkey.itemof[self] = True
        self.dictvalue = DictValue(bookkeeper, s_value)
        self.dictvalue.itemof[self] = True
        self.force_non_null = force_non_null
        self.simple_hash_eq = simple_hash_eq

    def read_key(self, position_key):
        self.dictkey.read_locations.add(position_key)
        return self.dictkey.s_value

    def read_value(self, position_key):
        self.dictvalue.read_locations.add(position_key)
        return self.dictvalue.s_value

    def same_as(self, other):
        return (self.dictkey is other.dictkey and
                self.dictvalue is other.dictvalue)

    def union(self, other):
        self.dictkey.merge(other.dictkey)
        self.dictvalue.merge(other.dictvalue)
        return self

    def generalize_key(self, s_key):
        self.dictkey.generalize(s_key)

    def generalize_value(self, s_value):
        self.dictvalue.generalize(s_value)

    def __repr__(self):
        return '<{%r: %r}>' % (self.dictkey.s_value, self.dictvalue.s_value)