From 0004fa3b80dc05ac59abeec7775903d0cb0a0b94 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Tue, 31 Mar 2020 10:26:12 +0900 Subject: [PATCH] pymodule _collections --- vm/src/obj/objtuple.rs | 2 +- vm/src/stdlib/collections.rs | 719 ++++++++++++++++++----------------- 2 files changed, 362 insertions(+), 359 deletions(-) diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index 622da4276..85427a189 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -11,7 +11,7 @@ use crate::pyobject::{ PyArithmaticValue::{self, *}, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, ThreadSafe, }; -use crate::sequence::{self, SimpleSeq}; +use crate::sequence; use crate::vm::{ReprGuard, VirtualMachine}; /// tuple() -> empty tuple diff --git a/vm/src/stdlib/collections.rs b/vm/src/stdlib/collections.rs index 5a5c6b9ea..4ec3633b5 100644 --- a/vm/src/stdlib/collections.rs +++ b/vm/src/stdlib/collections.rs @@ -1,395 +1,398 @@ -use crate::function::OptionalArg; -use crate::obj::{objiter, objtype::PyClassRef}; -use crate::pyobject::{ - IdProtocol, PyArithmaticValue::*, PyClassImpl, PyComparisonValue, PyIterable, PyObjectRef, - PyRef, PyResult, PyValue, -}; -use crate::sequence::{self, SimpleSeq}; -use crate::vm::ReprGuard; -use crate::VirtualMachine; -use itertools::Itertools; -use std::cell::{Cell, RefCell}; -use std::collections::VecDeque; +pub(crate) use _collections::make_module; -#[pyclass(name = "deque")] -#[derive(Debug, Clone)] -struct PyDeque { - deque: RefCell>, - maxlen: Cell>, -} -type PyDequeRef = PyRef; +#[pymodule] +mod _collections { + use crate::function::OptionalArg; + use crate::obj::{objiter, objtype::PyClassRef}; + use crate::pyobject::{ + IdProtocol, PyArithmaticValue::*, PyClassImpl, PyComparisonValue, PyIterable, PyObjectRef, + PyRef, PyResult, PyValue, + }; + use crate::sequence; + use crate::vm::ReprGuard; + use crate::VirtualMachine; + use itertools::Itertools; + use std::cell::{Cell, RefCell}; + use std::collections::VecDeque; -impl PyValue for PyDeque { - fn class(vm: &VirtualMachine) -> PyClassRef { - vm.class("_collections", "deque") + #[pyclass(name = "deque")] + #[derive(Debug, Clone)] + struct PyDeque { + deque: RefCell>, + maxlen: Cell>, } -} + type PyDequeRef = PyRef; -#[derive(FromArgs)] -struct PyDequeOptions { - #[pyarg(positional_or_keyword, default = "None")] - maxlen: Option, -} - -impl PyDeque { - fn borrow_deque<'a>(&'a self) -> impl std::ops::Deref> + 'a { - self.deque.borrow() - } -} - -#[pyimpl(flags(BASETYPE))] -impl PyDeque { - #[pyslot] - fn tp_new( - cls: PyClassRef, - iter: OptionalArg, - PyDequeOptions { maxlen }: PyDequeOptions, - vm: &VirtualMachine, - ) -> PyResult> { - let py_deque = PyDeque { - deque: RefCell::default(), - maxlen: maxlen.into(), - }; - if let OptionalArg::Present(iter) = iter { - py_deque.extend(iter, vm)?; + impl PyValue for PyDeque { + fn class(vm: &VirtualMachine) -> PyClassRef { + vm.class("_collections", "deque") } - py_deque.into_ref_with_type(vm, cls) } - #[pymethod] - fn append(&self, obj: PyObjectRef) { - let mut deque = self.deque.borrow_mut(); - if self.maxlen.get() == Some(deque.len()) { - deque.pop_front(); + #[derive(FromArgs)] + struct PyDequeOptions { + #[pyarg(positional_or_keyword, default = "None")] + maxlen: Option, + } + + impl PyDeque { + fn borrow_deque<'a>(&'a self) -> impl std::ops::Deref> + 'a { + self.deque.borrow() } - deque.push_back(obj); } - #[pymethod] - fn appendleft(&self, obj: PyObjectRef) { - let mut deque = self.deque.borrow_mut(); - if self.maxlen.get() == Some(deque.len()) { - deque.pop_back(); - } - deque.push_front(obj); - } - - #[pymethod] - fn clear(&self) { - self.deque.borrow_mut().clear() - } - - #[pymethod] - fn copy(&self) -> Self { - self.clone() - } - - #[pymethod] - fn count(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let mut count = 0; - for elem in self.deque.borrow().iter() { - if vm.identical_or_equal(elem, &obj)? { - count += 1; + #[pyimpl(flags(BASETYPE))] + impl PyDeque { + #[pyslot] + fn tp_new( + cls: PyClassRef, + iter: OptionalArg, + PyDequeOptions { maxlen }: PyDequeOptions, + vm: &VirtualMachine, + ) -> PyResult> { + let py_deque = PyDeque { + deque: RefCell::default(), + maxlen: maxlen.into(), + }; + if let OptionalArg::Present(iter) = iter { + py_deque.extend(iter, vm)?; } + py_deque.into_ref_with_type(vm, cls) } - Ok(count) - } - #[pymethod] - fn extend(&self, iter: PyIterable, vm: &VirtualMachine) -> PyResult<()> { - // TODO: use length_hint here and for extendleft - for elem in iter.iter(vm)? { - self.append(elem?); - } - Ok(()) - } - - #[pymethod] - fn extendleft(&self, iter: PyIterable, vm: &VirtualMachine) -> PyResult<()> { - for elem in iter.iter(vm)? { - self.appendleft(elem?); - } - Ok(()) - } - - #[pymethod] - fn index( - &self, - obj: PyObjectRef, - start: OptionalArg, - stop: OptionalArg, - vm: &VirtualMachine, - ) -> PyResult { - let deque = self.deque.borrow(); - let start = start.unwrap_or(0); - let stop = stop.unwrap_or_else(|| deque.len()); - for (i, elem) in deque.iter().skip(start).take(stop - start).enumerate() { - if vm.identical_or_equal(elem, &obj)? { - return Ok(i); + #[pymethod] + fn append(&self, obj: PyObjectRef) { + let mut deque = self.deque.borrow_mut(); + if self.maxlen.get() == Some(deque.len()) { + deque.pop_front(); } - } - Err(vm.new_value_error( - vm.to_repr(&obj) - .map(|repr| format!("{} is not in deque", repr)) - .unwrap_or_else(|_| String::new()), - )) - } - - #[pymethod] - fn insert(&self, idx: i32, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - let mut deque = self.deque.borrow_mut(); - - if self.maxlen.get() == Some(deque.len()) { - return Err(vm.new_index_error("deque already at its maximum size".to_owned())); + deque.push_back(obj); } - let idx = if idx < 0 { - if -idx as usize > deque.len() { - 0 + #[pymethod] + fn appendleft(&self, obj: PyObjectRef) { + let mut deque = self.deque.borrow_mut(); + if self.maxlen.get() == Some(deque.len()) { + deque.pop_back(); + } + deque.push_front(obj); + } + + #[pymethod] + fn clear(&self) { + self.deque.borrow_mut().clear() + } + + #[pymethod] + fn copy(&self) -> Self { + self.clone() + } + + #[pymethod] + fn count(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { + let mut count = 0; + for elem in self.deque.borrow().iter() { + if vm.identical_or_equal(elem, &obj)? { + count += 1; + } + } + Ok(count) + } + + #[pymethod] + fn extend(&self, iter: PyIterable, vm: &VirtualMachine) -> PyResult<()> { + // TODO: use length_hint here and for extendleft + for elem in iter.iter(vm)? { + self.append(elem?); + } + Ok(()) + } + + #[pymethod] + fn extendleft(&self, iter: PyIterable, vm: &VirtualMachine) -> PyResult<()> { + for elem in iter.iter(vm)? { + self.appendleft(elem?); + } + Ok(()) + } + + #[pymethod] + fn index( + &self, + obj: PyObjectRef, + start: OptionalArg, + stop: OptionalArg, + vm: &VirtualMachine, + ) -> PyResult { + let deque = self.deque.borrow(); + let start = start.unwrap_or(0); + let stop = stop.unwrap_or_else(|| deque.len()); + for (i, elem) in deque.iter().skip(start).take(stop - start).enumerate() { + if vm.identical_or_equal(elem, &obj)? { + return Ok(i); + } + } + Err(vm.new_value_error( + vm.to_repr(&obj) + .map(|repr| format!("{} is not in deque", repr)) + .unwrap_or_else(|_| String::new()), + )) + } + + #[pymethod] + fn insert(&self, idx: i32, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { + let mut deque = self.deque.borrow_mut(); + + if self.maxlen.get() == Some(deque.len()) { + return Err(vm.new_index_error("deque already at its maximum size".to_owned())); + } + + let idx = if idx < 0 { + if -idx as usize > deque.len() { + 0 + } else { + deque.len() - ((-idx) as usize) + } + } else if idx as usize >= deque.len() { + deque.len() - 1 } else { - deque.len() - ((-idx) as usize) + idx as usize + }; + + deque.insert(idx, obj); + + Ok(()) + } + + #[pymethod] + fn pop(&self, vm: &VirtualMachine) -> PyResult { + self.deque + .borrow_mut() + .pop_back() + .ok_or_else(|| vm.new_index_error("pop from an empty deque".to_owned())) + } + + #[pymethod] + fn popleft(&self, vm: &VirtualMachine) -> PyResult { + self.deque + .borrow_mut() + .pop_front() + .ok_or_else(|| vm.new_index_error("pop from an empty deque".to_owned())) + } + + #[pymethod] + fn remove(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { + let mut deque = self.deque.borrow_mut(); + let mut idx = None; + for (i, elem) in deque.iter().enumerate() { + if vm.identical_or_equal(elem, &obj)? { + idx = Some(i); + break; + } } - } else if idx as usize >= deque.len() { - deque.len() - 1 - } else { - idx as usize - }; + idx.map(|idx| deque.remove(idx).unwrap()) + .ok_or_else(|| vm.new_value_error("deque.remove(x): x not in deque".to_owned())) + } - deque.insert(idx, obj); + #[pymethod] + fn reverse(&self) { + self.deque + .replace_with(|deque| deque.iter().cloned().rev().collect()); + } - Ok(()) - } - - #[pymethod] - fn pop(&self, vm: &VirtualMachine) -> PyResult { - self.deque - .borrow_mut() - .pop_back() - .ok_or_else(|| vm.new_index_error("pop from an empty deque".to_owned())) - } - - #[pymethod] - fn popleft(&self, vm: &VirtualMachine) -> PyResult { - self.deque - .borrow_mut() - .pop_front() - .ok_or_else(|| vm.new_index_error("pop from an empty deque".to_owned())) - } - - #[pymethod] - fn remove(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let mut deque = self.deque.borrow_mut(); - let mut idx = None; - for (i, elem) in deque.iter().enumerate() { - if vm.identical_or_equal(elem, &obj)? { - idx = Some(i); - break; + #[pymethod] + fn rotate(&self, mid: OptionalArg) { + let mut deque = self.deque.borrow_mut(); + let mid = mid.unwrap_or(1); + if mid < 0 { + deque.rotate_left(-mid as usize); + } else { + deque.rotate_right(mid as usize); } } - idx.map(|idx| deque.remove(idx).unwrap()) - .ok_or_else(|| vm.new_value_error("deque.remove(x): x not in deque".to_owned())) - } - #[pymethod] - fn reverse(&self) { - self.deque - .replace_with(|deque| deque.iter().cloned().rev().collect()); - } + #[pyproperty] + fn maxlen(&self) -> Option { + self.maxlen.get() + } - #[pymethod] - fn rotate(&self, mid: OptionalArg) { - let mut deque = self.deque.borrow_mut(); - let mid = mid.unwrap_or(1); - if mid < 0 { - deque.rotate_left(-mid as usize); - } else { - deque.rotate_right(mid as usize); + #[pyproperty(setter)] + fn set_maxlen(&self, maxlen: Option) { + self.maxlen.set(maxlen); + } + + #[pymethod(name = "__repr__")] + fn repr(zelf: PyRef, vm: &VirtualMachine) -> PyResult { + let repr = if let Some(_guard) = ReprGuard::enter(zelf.as_object()) { + let elements = zelf + .deque + .borrow() + .iter() + .map(|obj| vm.to_repr(obj)) + .collect::, _>>()?; + let maxlen = zelf + .maxlen + .get() + .map(|maxlen| format!(", maxlen={}", maxlen)) + .unwrap_or_default(); + format!("deque([{}]{})", elements.into_iter().format(", "), maxlen) + } else { + "[...]".to_owned() + }; + Ok(repr) + } + + #[inline] + fn cmp( + &self, + other: PyObjectRef, + op: F, + vm: &VirtualMachine, + ) -> PyResult + where + F: Fn(&VecDeque, &VecDeque) -> PyResult, + { + let r = if let Some(other) = other.payload_if_subclass::(vm) { + Implemented(op(&*self.borrow_deque(), &*other.borrow_deque())?) + } else { + NotImplemented + }; + Ok(r) + } + + #[pymethod(name = "__eq__")] + fn eq( + zelf: PyRef, + other: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult { + if zelf.as_object().is(&other) { + Ok(Implemented(true)) + } else { + zelf.cmp(other, |a, b| sequence::eq(vm, a, b), vm) + } + } + + #[pymethod(name = "__ne__")] + fn ne( + zelf: PyRef, + other: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult { + Ok(PyDeque::eq(zelf, other, vm)?.map(|v| !v)) + } + + #[pymethod(name = "__lt__")] + fn lt( + zelf: PyRef, + other: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult { + if zelf.as_object().is(&other) { + Ok(Implemented(false)) + } else { + zelf.cmp(other, |a, b| sequence::lt(vm, a, b), vm) + } + } + + #[pymethod(name = "__gt__")] + fn gt( + zelf: PyRef, + other: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult { + if zelf.as_object().is(&other) { + Ok(Implemented(false)) + } else { + zelf.cmp(other, |a, b| sequence::gt(vm, a, b), vm) + } + } + + #[pymethod(name = "__le__")] + fn le( + zelf: PyRef, + other: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult { + if zelf.as_object().is(&other) { + Ok(Implemented(true)) + } else { + zelf.cmp(other, |a, b| sequence::le(vm, a, b), vm) + } + } + + #[pymethod(name = "__ge__")] + fn ge( + zelf: PyRef, + other: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult { + if zelf.as_object().is(&other) { + Ok(Implemented(true)) + } else { + zelf.cmp(other, |a, b| sequence::ge(vm, a, b), vm) + } + } + + #[pymethod(name = "__mul__")] + fn mul(&self, n: isize) -> Self { + let deque: &VecDeque<_> = &self.deque.borrow(); + let mul = sequence::seq_mul(deque, n); + let skipped = if let Some(maxlen) = self.maxlen.get() { + mul.len() - maxlen + } else { + 0 + }; + let deque = mul.skip(skipped).cloned().collect(); + PyDeque { + deque: RefCell::new(deque), + maxlen: self.maxlen.clone(), + } + } + + #[pymethod(name = "__len__")] + fn len(&self) -> usize { + self.deque.borrow().len() + } + + #[pymethod(name = "__iter__")] + fn iter(zelf: PyRef) -> PyDequeIterator { + PyDequeIterator { + position: Cell::new(0), + deque: zelf, + } } } - #[pyproperty] - fn maxlen(&self) -> Option { - self.maxlen.get() + #[pyclass(name = "_deque_iterator")] + #[derive(Debug)] + struct PyDequeIterator { + position: Cell, + deque: PyDequeRef, } - #[pyproperty(setter)] - fn set_maxlen(&self, maxlen: Option) { - self.maxlen.set(maxlen); - } - - #[pymethod(name = "__repr__")] - fn repr(zelf: PyRef, vm: &VirtualMachine) -> PyResult { - let repr = if let Some(_guard) = ReprGuard::enter(zelf.as_object()) { - let elements = zelf - .deque - .borrow() - .iter() - .map(|obj| vm.to_repr(obj)) - .collect::, _>>()?; - let maxlen = zelf - .maxlen - .get() - .map(|maxlen| format!(", maxlen={}", maxlen)) - .unwrap_or_default(); - format!("deque([{}]{})", elements.into_iter().format(", "), maxlen) - } else { - "[...]".to_owned() - }; - Ok(repr) - } - - #[inline] - fn cmp(&self, other: PyObjectRef, op: F, vm: &VirtualMachine) -> PyResult - where - F: Fn(&VecDeque, &VecDeque) -> PyResult, - { - let r = if let Some(other) = other.payload_if_subclass::(vm) { - Implemented(op(&*self.borrow_deque(), &*other.borrow_deque())?) - } else { - NotImplemented - }; - Ok(r) - } - - #[pymethod(name = "__eq__")] - fn eq( - zelf: PyRef, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult { - if zelf.as_object().is(&other) { - Ok(Implemented(true)) - } else { - zelf.cmp(other, |a, b| sequence::eq(vm, a, b), vm) + impl PyValue for PyDequeIterator { + fn class(vm: &VirtualMachine) -> PyClassRef { + vm.class("_collections", "_deque_iterator") } } - #[pymethod(name = "__ne__")] - fn ne( - zelf: PyRef, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult { - Ok(PyDeque::eq(zelf, other, vm)?.map(|v| !v)) - } - - #[pymethod(name = "__lt__")] - fn lt( - zelf: PyRef, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult { - if zelf.as_object().is(&other) { - Ok(Implemented(false)) - } else { - zelf.cmp(other, |a, b| sequence::lt(vm, a, b), vm) + #[pyimpl] + impl PyDequeIterator { + #[pymethod(name = "__next__")] + fn next(&self, vm: &VirtualMachine) -> PyResult { + if self.position.get() < self.deque.deque.borrow().len() { + let ret = self.deque.deque.borrow()[self.position.get()].clone(); + self.position.set(self.position.get() + 1); + Ok(ret) + } else { + Err(objiter::new_stop_iteration(vm)) + } } - } - #[pymethod(name = "__gt__")] - fn gt( - zelf: PyRef, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult { - if zelf.as_object().is(&other) { - Ok(Implemented(false)) - } else { - zelf.cmp(other, |a, b| sequence::gt(vm, a, b), vm) - } - } - - #[pymethod(name = "__le__")] - fn le( - zelf: PyRef, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult { - if zelf.as_object().is(&other) { - Ok(Implemented(true)) - } else { - zelf.cmp(other, |a, b| sequence::le(vm, a, b), vm) - } - } - - #[pymethod(name = "__ge__")] - fn ge( - zelf: PyRef, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult { - if zelf.as_object().is(&other) { - Ok(Implemented(true)) - } else { - zelf.cmp(other, |a, b| sequence::ge(vm, a, b), vm) - } - } - - #[pymethod(name = "__mul__")] - fn mul(&self, n: isize) -> Self { - let deque: &VecDeque<_> = &self.deque.borrow(); - let mul = sequence::seq_mul(deque, n); - let skipped = if let Some(maxlen) = self.maxlen.get() { - mul.len() - maxlen - } else { - 0 - }; - let deque = mul.skip(skipped).cloned().collect(); - PyDeque { - deque: RefCell::new(deque), - maxlen: self.maxlen.clone(), - } - } - - #[pymethod(name = "__len__")] - fn len(&self) -> usize { - self.deque.borrow().len() - } - - #[pymethod(name = "__iter__")] - fn iter(zelf: PyRef) -> PyDequeIterator { - PyDequeIterator { - position: Cell::new(0), - deque: zelf, + #[pymethod(name = "__iter__")] + fn iter(zelf: PyRef) -> PyRef { + zelf } } } - -#[pyclass(name = "_deque_iterator")] -#[derive(Debug)] -struct PyDequeIterator { - position: Cell, - deque: PyDequeRef, -} - -impl PyValue for PyDequeIterator { - fn class(vm: &VirtualMachine) -> PyClassRef { - vm.class("_collections", "_deque_iterator") - } -} - -#[pyimpl] -impl PyDequeIterator { - #[pymethod(name = "__next__")] - fn next(&self, vm: &VirtualMachine) -> PyResult { - if self.position.get() < self.deque.deque.borrow().len() { - let ret = self.deque.deque.borrow()[self.position.get()].clone(); - self.position.set(self.position.get() + 1); - Ok(ret) - } else { - Err(objiter::new_stop_iteration(vm)) - } - } - - #[pymethod(name = "__iter__")] - fn iter(zelf: PyRef) -> PyRef { - zelf - } -} - -pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { - py_module!(vm, "_collections", { - "deque" => PyDeque::make_class(&vm.ctx), - "_deque_iterator" => PyDequeIterator::make_class(&vm.ctx), - }) -}