_frozenlist.pyx 2.9 KB

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