xref: /aosp_15_r20/external/fonttools/Lib/fontTools/misc/dictTools.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1"""Misc dict tools."""
2
3__all__ = ["hashdict"]
4
5
6# https://stackoverflow.com/questions/1151658/python-hashable-dicts
7class hashdict(dict):
8    """
9    hashable dict implementation, suitable for use as a key into
10    other dicts.
11
12        >>> h1 = hashdict({"apples": 1, "bananas":2})
13        >>> h2 = hashdict({"bananas": 3, "mangoes": 5})
14        >>> h1+h2
15        hashdict(apples=1, bananas=3, mangoes=5)
16        >>> d1 = {}
17        >>> d1[h1] = "salad"
18        >>> d1[h1]
19        'salad'
20        >>> d1[h2]
21        Traceback (most recent call last):
22        ...
23        KeyError: hashdict(bananas=3, mangoes=5)
24
25    based on answers from
26       http://stackoverflow.com/questions/1151658/python-hashable-dicts
27
28    """
29
30    def __key(self):
31        return tuple(sorted(self.items()))
32
33    def __repr__(self):
34        return "{0}({1})".format(
35            self.__class__.__name__,
36            ", ".join("{0}={1}".format(str(i[0]), repr(i[1])) for i in self.__key()),
37        )
38
39    def __hash__(self):
40        return hash(self.__key())
41
42    def __setitem__(self, key, value):
43        raise TypeError(
44            "{0} does not support item assignment".format(self.__class__.__name__)
45        )
46
47    def __delitem__(self, key):
48        raise TypeError(
49            "{0} does not support item assignment".format(self.__class__.__name__)
50        )
51
52    def clear(self):
53        raise TypeError(
54            "{0} does not support item assignment".format(self.__class__.__name__)
55        )
56
57    def pop(self, *args, **kwargs):
58        raise TypeError(
59            "{0} does not support item assignment".format(self.__class__.__name__)
60        )
61
62    def popitem(self, *args, **kwargs):
63        raise TypeError(
64            "{0} does not support item assignment".format(self.__class__.__name__)
65        )
66
67    def setdefault(self, *args, **kwargs):
68        raise TypeError(
69            "{0} does not support item assignment".format(self.__class__.__name__)
70        )
71
72    def update(self, *args, **kwargs):
73        raise TypeError(
74            "{0} does not support item assignment".format(self.__class__.__name__)
75        )
76
77    # update is not ok because it mutates the object
78    # __add__ is ok because it creates a new object
79    # while the new object is under construction, it's ok to mutate it
80    def __add__(self, right):
81        result = hashdict(self)
82        dict.update(result, right)
83        return result
84