1import sys
2import types
3from collections.abc import MutableSequence
4
5
6cdef class FrozenList:
7
8    if sys.version_info >= (3, 9):
9        __class_getitem__ = classmethod(types.GenericAlias)
10    else:
11        @classmethod
12        def __class_getitem__(cls):
13            return cls
14
15    cdef readonly bint frozen
16    cdef list _items
17
18    def __init__(self, items=None):
19        self.frozen = False
20        if items is not None:
21            items = list(items)
22        else:
23            items = []
24        self._items = items
25
26    cdef object _check_frozen(self):
27        if self.frozen:
28            raise RuntimeError("Cannot modify frozen list.")
29
30    cdef inline object _fast_len(self):
31        return len(self._items)
32
33    def freeze(self):
34        self.frozen = True
35
36    def __getitem__(self, index):
37        return self._items[index]
38
39    def __setitem__(self, index, value):
40        self._check_frozen()
41        self._items[index] = value
42
43    def __delitem__(self, index):
44        self._check_frozen()
45        del self._items[index]
46
47    def __len__(self):
48        return self._fast_len()
49
50    def __iter__(self):
51        return self._items.__iter__()
52
53    def __reversed__(self):
54        return self._items.__reversed__()
55
56    def __richcmp__(self, other, op):
57        if op == 0:  # <
58            return list(self) < other
59        if op == 1:  # <=
60            return list(self) <= other
61        if op == 2:  # ==
62            return list(self) == other
63        if op == 3:  # !=
64            return list(self) != other
65        if op == 4:  # >
66            return list(self) > other
67        if op == 5:  # =>
68            return list(self) >= other
69
70    def insert(self, pos, item):
71        self._check_frozen()
72        self._items.insert(pos, item)
73
74    def __contains__(self, item):
75        return item in self._items
76
77    def __iadd__(self, items):
78        self._check_frozen()
79        self._items += list(items)
80        return self
81
82    def index(self, item):
83        return self._items.index(item)
84
85    def remove(self, item):
86        self._check_frozen()
87        self._items.remove(item)
88
89    def clear(self):
90        self._check_frozen()
91        self._items.clear()
92
93    def extend(self, items):
94        self._check_frozen()
95        self._items += list(items)
96
97    def reverse(self):
98        self._check_frozen()
99        self._items.reverse()
100
101    def pop(self, index=-1):
102        self._check_frozen()
103        return self._items.pop(index)
104
105    def append(self, item):
106        self._check_frozen()
107        return self._items.append(item)
108
109    def count(self, item):
110        return self._items.count(item)
111
112    def __repr__(self):
113        return '<FrozenList(frozen={}, {!r})>'.format(self.frozen,
114                                                      self._items)
115
116    def __hash__(self):
117        if self.frozen:
118            return hash(tuple(self._items))
119        else:
120            raise RuntimeError("Cannot hash unfrozen list.")
121
122
123MutableSequence.register(FrozenList)
124