mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Drop what a deque with maxlen of zero is handed (#8567)
append and appendleft trimmed before pushing, and the test they used,
maxlen == len, holds for an empty deque whose bound is zero. The pop then
had nothing to remove and the item stayed:
>>> d = deque(maxlen=0)
>>> d.append(1)
>>> list(d)
[1]
Both now push first and trim after, which is the order CPython uses, so a
bound of zero drops what just arrived. extend, extendleft, insert, rotate,
the operators and the constructor were already right.
Assisted-by: Claude Code:claude-opus-5
This commit is contained in:
1 parent
d86ec309b1
commit
003307131f
2 files changed
+53
-4
No files matched your search
@@ -77,6 +77,10 @@ mod _collections {
|
||||
fn borrow_deque_mut(&self) -> PyRwLockWriteGuard<'_, VecDeque<PyObjectRef>> {
|
||||
self.deque.write()
|
||||
}
|
||||
|
||||
fn is_over_maxlen(&self, deque: &VecDeque<PyObjectRef>) -> bool {
|
||||
self.maxlen.is_some_and(|maxlen| deque.len() > maxlen)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
@@ -96,20 +100,22 @@ mod _collections {
|
||||
fn append(&self, obj: PyObjectRef) {
|
||||
self.state.fetch_add(1);
|
||||
let mut deque = self.borrow_deque_mut();
|
||||
if self.maxlen == Some(deque.len()) {
|
||||
deque.push_back(obj);
|
||||
// Trim after pushing, so that a `maxlen` of zero drops what just
|
||||
// arrived instead of popping from an empty deque and keeping it.
|
||||
if self.is_over_maxlen(&deque) {
|
||||
deque.pop_front();
|
||||
}
|
||||
deque.push_back(obj);
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn appendleft(&self, obj: PyObjectRef) {
|
||||
self.state.fetch_add(1);
|
||||
let mut deque = self.borrow_deque_mut();
|
||||
if self.maxlen == Some(deque.len()) {
|
||||
deque.push_front(obj);
|
||||
if self.is_over_maxlen(&deque) {
|
||||
deque.pop_back();
|
||||
}
|
||||
deque.push_front(obj);
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
|
||||
@@ -108,3 +108,46 @@ if sys.implementation.name == "rustpython":
|
||||
# until the allocator gives up, so it is left out of this check.
|
||||
with assert_raises(MemoryError):
|
||||
deque([0]) * sys.maxsize
|
||||
|
||||
|
||||
# maxlen=0 keeps nothing, whichever end the item arrives at.
|
||||
d = deque(maxlen=0)
|
||||
d.append(1)
|
||||
d.appendleft(2)
|
||||
assert list(d) == []
|
||||
assert len(d) == 0
|
||||
assert d.maxlen == 0
|
||||
|
||||
d = deque(maxlen=0)
|
||||
d.extend("abc")
|
||||
d.extendleft("abc")
|
||||
d += "abc"
|
||||
assert list(d) == []
|
||||
|
||||
assert list(deque("abc", maxlen=0)) == []
|
||||
assert list(deque("ab", maxlen=0) * 3) == []
|
||||
assert list(deque("ab", maxlen=0) + deque("cd")) == []
|
||||
|
||||
d = deque("abc", maxlen=0)
|
||||
d.rotate(1)
|
||||
assert list(d) == []
|
||||
|
||||
assert_raises(IndexError, deque(maxlen=0).insert, 0, 1)
|
||||
|
||||
|
||||
# A bounded deque still drops from the far end, and only once it is full.
|
||||
d = deque(maxlen=1)
|
||||
d.append(1)
|
||||
assert list(d) == [1]
|
||||
d.append(2)
|
||||
assert list(d) == [2]
|
||||
d.appendleft(3)
|
||||
assert list(d) == [3]
|
||||
|
||||
d = deque("ab", maxlen=3)
|
||||
d.append("c")
|
||||
assert list(d) == ["a", "b", "c"]
|
||||
d.append("d")
|
||||
assert list(d) == ["b", "c", "d"]
|
||||
d.appendleft("z")
|
||||
assert list(d) == ["z", "b", "c"]
|
||||
Reference in new issue
Block a user