blueloveTH 5 месяцев назад
Родитель
Сommit
f12a379760
3 измененных файлов с 59 добавлено и 11 удалено
  1. 31 11
      python/collections.py
  2. 0 0
      src/common/_generated.c
  3. 28 0
      tests/72_collections.py

+ 31 - 11
python/collections.py

@@ -27,20 +27,29 @@ class defaultdict(dict):
 
 
 class deque[T]:
-    _data: list[T]
     _head: int
     _tail: int
+    _maxlen: int | None
     _capacity: int
+    _data: list[T]
+
+    def __init__(self, iterable: Iterable[T] = None, maxlen: int | None = None):
+        if maxlen is not None:
+            assert maxlen > 0
 
-    def __init__(self, iterable: Iterable[T] = None):
-        self._data = [None] * 8 # type: ignore
         self._head = 0
         self._tail = 0
-        self._capacity = len(self._data)
+        self._maxlen = maxlen
+        self._capacity = 8 if maxlen is None else maxlen + 1
+        self._data = [None] * self._capacity # type: ignore
 
         if iterable is not None:
             self.extend(iterable)
 
+    @property
+    def maxlen(self) -> int | None:
+        return self._maxlen
+
     def __resize_2x(self):
         backup = list(self)
         self._capacity *= 2
@@ -51,19 +60,25 @@ class deque[T]:
         self._data.extend([None] * (self._capacity - len(backup)))
 
     def append(self, x: T):
+        if (self._tail + 1) % self._capacity == self._head:
+            if self._maxlen is None:
+                self.__resize_2x()
+            else:
+                self.popleft()
         self._data[self._tail] = x
         self._tail = (self._tail + 1) % self._capacity
-        if (self._tail + 1) % self._capacity == self._head:
-            self.__resize_2x()
 
     def appendleft(self, x: T):
+        if (self._tail + 1) % self._capacity == self._head:
+            if self._maxlen is None:
+                self.__resize_2x()
+            else:
+                self.pop()
         self._head = (self._head - 1) % self._capacity
         self._data[self._head] = x
-        if (self._tail + 1) % self._capacity == self._head:
-            self.__resize_2x()
 
     def copy(self):
-        return deque(self)
+        return deque(self, maxlen=self.maxlen)
     
     def count(self, x: T) -> int:
         n = 0
@@ -84,12 +99,15 @@ class deque[T]:
         if self._head == self._tail:
             raise IndexError("pop from an empty deque")
         self._tail = (self._tail - 1) % self._capacity
-        return self._data[self._tail]
+        x = self._data[self._tail]
+        self._data[self._tail] = None
+        return x
     
     def popleft(self) -> T:
         if self._head == self._tail:
             raise IndexError("pop from an empty deque")
         x = self._data[self._head]
+        self._data[self._head] = None
         self._head = (self._head + 1) % self._capacity
         return x
     
@@ -144,5 +162,7 @@ class deque[T]:
         return not self == other
     
     def __repr__(self) -> str:
-        return f"deque({list(self)!r})"
+        if self.maxlen is None:
+            return f"deque({list(self)!r})"
+        return f"deque({list(self)!r}, maxlen={self.maxlen})"
 

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/common/_generated.c


+ 28 - 0
tests/72_collections.py

@@ -516,3 +516,31 @@ d = deque()
 for i in range(100):
     d.append(1)
     gc.collect()
+
+# test maxlen
+q = deque(maxlen=3)
+assertEqual(q.maxlen, 3)
+q.append(1)
+q.append(2)
+q.append(3)
+assertEqual(list(q), [1, 2, 3])
+assertEqual(q._data, [1, 2, 3, None])
+q.append(4)
+assertEqual(list(q), [2, 3, 4])
+assertEqual(q._data, [None, 2, 3, 4])
+q.appendleft(1)
+assertEqual(list(q), [1, 2, 3])
+assertEqual(q._data, [1, 2, 3, None])
+q.appendleft(0)
+assertEqual(list(q), [0, 1, 2])
+assertEqual(q._data, [1, 2, None, 0])
+q.pop()
+assertEqual(list(q), [0, 1])
+assertEqual(q._data, [1, None, None, 0])
+assertEqual(len(q), 2)
+assertEqual(q._capacity, 4)
+q.popleft()
+assertEqual(list(q), [1])
+assertEqual(q._data, [1, None, None, None])
+
+

Некоторые файлы не были показаны из-за большого количества измененных файлов