From 226ebfa0c65ac8db5e63e008d32481865eb61345 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Tue, 7 Jan 2020 22:24:05 +0900 Subject: [PATCH] vm::sequence for SimpleSeq utilities --- vm/src/obj/objlist.rs | 23 ++--- vm/src/obj/objsequence.rs | 164 +---------------------------------- vm/src/obj/objtuple.rs | 17 ++-- vm/src/sequence.rs | 146 ++++++++++++++++++++++++++++++- vm/src/stdlib/collections.rs | 17 ++-- 5 files changed, 179 insertions(+), 188 deletions(-) diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index b874103b3..5ce46c1b4 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -10,9 +10,7 @@ use super::objbool; use super::objbyteinner; use super::objint::PyIntRef; use super::objiter; -use super::objsequence::{ - get_item, seq_equal, seq_ge, seq_gt, seq_le, seq_lt, seq_mul, SequenceIndex, SimpleSeq, -}; +use super::objsequence::{get_item, SequenceIndex}; use super::objslice::PySliceRef; use super::objtype::PyClassRef; use crate::function::OptionalArg; @@ -20,6 +18,7 @@ use crate::pyobject::{ IdProtocol, PyArithmaticValue::*, PyClassImpl, PyComparisonValue, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, }; +use crate::sequence::{self, SimpleSeq}; use crate::vm::{ReprGuard, VirtualMachine}; /// Built-in mutable sequence. @@ -469,7 +468,9 @@ impl PyList { #[pymethod(name = "__mul__")] fn mul(&self, counter: isize, vm: &VirtualMachine) -> PyObjectRef { - let new_elements = seq_mul(&self.borrow_sequence(), counter).cloned().collect(); + let new_elements = sequence::seq_mul(&self.borrow_sequence(), counter) + .cloned() + .collect(); vm.ctx.new_list(new_elements) } @@ -480,7 +481,9 @@ impl PyList { #[pymethod(name = "__imul__")] fn imul(zelf: PyRef, counter: isize, _vm: &VirtualMachine) -> PyRef { - let new_elements = seq_mul(&zelf.borrow_sequence(), counter).cloned().collect(); + let new_elements = sequence::seq_mul(&zelf.borrow_sequence(), counter) + .cloned() + .collect(); zelf.elements.replace(new_elements); zelf } @@ -562,7 +565,7 @@ impl PyList { let value = if zelf.as_object().is(&other) { Implemented(true) } else if let Some(other) = other.payload_if_subclass::(vm) { - Implemented(seq_equal( + Implemented(sequence::eq( vm, &zelf.borrow_sequence(), &other.borrow_sequence(), @@ -585,7 +588,7 @@ impl PyList { #[pymethod(name = "__lt__")] fn lt(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { if let Some(other) = other.payload_if_subclass::(vm) { - let res = seq_lt(vm, &self.borrow_sequence(), &other.borrow_sequence())?; + let res = sequence::lt(vm, &self.borrow_sequence(), &other.borrow_sequence())?; Ok(vm.new_bool(res)) } else { Ok(vm.ctx.not_implemented()) @@ -595,7 +598,7 @@ impl PyList { #[pymethod(name = "__gt__")] fn gt(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { if let Some(other) = other.payload_if_subclass::(vm) { - let res = seq_gt(vm, &self.borrow_sequence(), &other.borrow_sequence())?; + let res = sequence::gt(vm, &self.borrow_sequence(), &other.borrow_sequence())?; Ok(vm.new_bool(res)) } else { Ok(vm.ctx.not_implemented()) @@ -605,7 +608,7 @@ impl PyList { #[pymethod(name = "__ge__")] fn ge(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { if let Some(other) = other.payload_if_subclass::(vm) { - let res = seq_ge(vm, &self.borrow_sequence(), &other.borrow_sequence())?; + let res = sequence::ge(vm, &self.borrow_sequence(), &other.borrow_sequence())?; Ok(vm.new_bool(res)) } else { Ok(vm.ctx.not_implemented()) @@ -615,7 +618,7 @@ impl PyList { #[pymethod(name = "__le__")] fn le(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { if let Some(other) = other.payload_if_subclass::(vm) { - let res = seq_le(vm, &self.borrow_sequence(), &other.borrow_sequence())?; + let res = sequence::le(vm, &self.borrow_sequence(), &other.borrow_sequence())?; Ok(vm.new_bool(res)) } else { Ok(vm.ctx.not_implemented()) diff --git a/vm/src/obj/objsequence.rs b/vm/src/obj/objsequence.rs index 7b0a70ebb..4b1590f20 100644 --- a/vm/src/obj/objsequence.rs +++ b/vm/src/obj/objsequence.rs @@ -1,5 +1,5 @@ use std::marker::Sized; -use std::ops::{Deref, Range}; +use std::ops::Range; use num_bigint::{BigInt, ToBigInt}; use num_traits::{One, Signed, ToPrimitive, Zero}; @@ -10,7 +10,7 @@ use super::objnone::PyNone; use super::objslice::{PySlice, PySliceRef}; use super::objtuple::PyTuple; use crate::function::OptionalArg; -use crate::pyobject::{IdProtocol, PyObject, PyObjectRef, PyResult, TryFromObject, TypeProtocol}; +use crate::pyobject::{PyObject, PyObjectRef, PyResult, TryFromObject, TypeProtocol}; use crate::vm::VirtualMachine; pub trait PySliceableSequence { @@ -246,166 +246,6 @@ pub fn get_item( } } -type DynPyIter<'a> = Box + 'a>; - -#[allow(clippy::len_without_is_empty)] -pub trait SimpleSeq { - fn len(&self) -> usize; - fn iter(&self) -> DynPyIter; -} - -// impl SimpleSeq for &[PyObjectRef] { -// fn len(&self) -> usize { -// (&**self).len() -// } -// fn iter(&self) -> DynPyIter { -// Box::new((&**self).iter()) -// } -// } - -impl SimpleSeq for Vec { - fn len(&self) -> usize { - self.len() - } - fn iter(&self) -> DynPyIter { - Box::new(self.as_slice().iter()) - } -} - -impl SimpleSeq for std::collections::VecDeque { - fn len(&self) -> usize { - self.len() - } - fn iter(&self) -> DynPyIter { - Box::new(self.iter()) - } -} - -impl SimpleSeq for std::cell::Ref<'_, T> where T: SimpleSeq { - fn len(&self) -> usize { - self.deref().len() - } - fn iter(&self) -> DynPyIter { - self.deref().iter() - } -} - -// impl<'a, I> - -pub fn seq_equal( - vm: &VirtualMachine, - zelf: &impl SimpleSeq, - other: &impl SimpleSeq, -) -> PyResult { - if zelf.len() == other.len() { - for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { - if a.is(b) { - continue; - } - if !vm.bool_eq(a.clone(), b.clone())? { - return Ok(false); - } - } - Ok(true) - } else { - Ok(false) - } -} - -pub fn seq_lt( - vm: &VirtualMachine, - zelf: &impl SimpleSeq, - other: &impl SimpleSeq, -) -> PyResult { - for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { - if let Some(v) = vm.bool_seq_lt(a.clone(), b.clone())? { - return Ok(v); - } - } - Ok(zelf.len() < other.len()) -} - -pub fn seq_gt( - vm: &VirtualMachine, - zelf: &impl SimpleSeq, - other: &impl SimpleSeq, -) -> PyResult { - for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { - if let Some(v) = vm.bool_seq_gt(a.clone(), b.clone())? { - return Ok(v); - } - } - Ok(zelf.len() > other.len()) -} - -pub fn seq_ge( - vm: &VirtualMachine, - zelf: &impl SimpleSeq, - other: &impl SimpleSeq, -) -> PyResult { - for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { - if let Some(v) = vm.bool_seq_gt(a.clone(), b.clone())? { - return Ok(v); - } - } - - Ok(zelf.len() >= other.len()) -} - -pub fn seq_le( - vm: &VirtualMachine, - zelf: &impl SimpleSeq, - other: &impl SimpleSeq, -) -> PyResult { - for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { - if let Some(v) = vm.bool_seq_lt(a.clone(), b.clone())? { - return Ok(v); - } - } - - Ok(zelf.len() <= other.len()) -} - -pub struct SeqMul<'a> { - seq: &'a dyn SimpleSeq, - repetitions: usize, - iter: Option>, -} -impl<'a> Iterator for SeqMul<'a> { - type Item = &'a PyObjectRef; - fn next(&mut self) -> Option { - if self.seq.len() == 0 { - return None; - } - match self.iter.as_mut().and_then(Iterator::next) { - Some(item) => Some(item), - None => { - if self.repetitions == 0 { - None - } else { - self.repetitions -= 1; - self.iter = Some(self.seq.iter()); - self.next() - } - } - } - } - fn size_hint(&self) -> (usize, Option) { - let size = self.iter.as_ref().map_or(0, ExactSizeIterator::len) - + (self.repetitions * self.seq.len()); - (size, Some(size)) - } -} -impl ExactSizeIterator for SeqMul<'_> {} - -pub fn seq_mul<'a>(seq: &'a impl SimpleSeq, repetitions: isize) -> SeqMul<'a> { - SeqMul { - seq, - repetitions: repetitions.max(0) as usize, - iter: None, - } -} - //Check if given arg could be used with PySliceableSequence.get_slice_range() pub fn is_valid_slice_arg( arg: OptionalArg, diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index dcf58239b..77e383a73 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -2,7 +2,7 @@ use std::cell::Cell; use std::fmt; use super::objiter; -use super::objsequence::{get_item, seq_equal, seq_ge, seq_gt, seq_le, seq_lt, seq_mul, SimpleSeq}; +use super::objsequence::get_item; use super::objtype::PyClassRef; use crate::function::OptionalArg; use crate::pyhash; @@ -10,6 +10,7 @@ use crate::pyobject::{ IntoPyObject, PyArithmaticValue::*, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, }; +use crate::sequence::{self, SimpleSeq}; use crate::vm::{ReprGuard, VirtualMachine}; /// tuple() -> empty tuple @@ -95,22 +96,22 @@ impl PyTuple { #[pymethod(name = "__lt__")] fn lt(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.cmp(other, |a, b| seq_lt(vm, a, b), vm) + self.cmp(other, |a, b| sequence::lt(vm, a, b), vm) } #[pymethod(name = "__gt__")] fn gt(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.cmp(other, |a, b| seq_gt(vm, a, b), vm) + self.cmp(other, |a, b| sequence::gt(vm, a, b), vm) } #[pymethod(name = "__ge__")] fn ge(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.cmp(other, |a, b| seq_ge(vm, a, b), vm) + self.cmp(other, |a, b| sequence::ge(vm, a, b), vm) } #[pymethod(name = "__le__")] fn le(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.cmp(other, |a, b| seq_le(vm, a, b), vm) + self.cmp(other, |a, b| sequence::le(vm, a, b), vm) } #[pymethod(name = "__add__")] @@ -146,7 +147,7 @@ impl PyTuple { #[pymethod(name = "__eq__")] fn eq(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.cmp(other, |a, b| seq_equal(vm, a, b), vm) + self.cmp(other, |a, b| sequence::eq(vm, a, b), vm) } #[pymethod(name = "__ne__")] @@ -194,7 +195,9 @@ impl PyTuple { #[pymethod(name = "__mul__")] fn mul(&self, counter: isize, vm: &VirtualMachine) -> PyObjectRef { - let new_elements = seq_mul(&self.elements, counter).cloned().collect(); + let new_elements = sequence::seq_mul(&self.elements, counter) + .cloned() + .collect(); vm.ctx.new_tuple(new_elements) } diff --git a/vm/src/sequence.rs b/vm/src/sequence.rs index c0d618ee9..31c631571 100644 --- a/vm/src/sequence.rs +++ b/vm/src/sequence.rs @@ -1,2 +1,146 @@ -use crate::pyobject::{PyObjectRef, PyResult, PyValue}; +use crate::pyobject::{IdProtocol, PyObjectRef, PyResult}; use crate::vm::VirtualMachine; +use std::ops::Deref; + +type DynPyIter<'a> = Box + 'a>; + +#[allow(clippy::len_without_is_empty)] +pub trait SimpleSeq { + fn len(&self) -> usize; + fn iter(&self) -> DynPyIter; +} + +// impl SimpleSeq for &[PyObjectRef] { +// fn len(&self) -> usize { +// (&**self).len() +// } +// fn iter(&self) -> DynPyIter { +// Box::new((&**self).iter()) +// } +// } + +impl SimpleSeq for Vec { + fn len(&self) -> usize { + self.len() + } + fn iter(&self) -> DynPyIter { + Box::new(self.as_slice().iter()) + } +} + +impl SimpleSeq for std::collections::VecDeque { + fn len(&self) -> usize { + self.len() + } + fn iter(&self) -> DynPyIter { + Box::new(self.iter()) + } +} + +impl SimpleSeq for std::cell::Ref<'_, T> +where + T: SimpleSeq, +{ + fn len(&self) -> usize { + self.deref().len() + } + fn iter(&self) -> DynPyIter { + self.deref().iter() + } +} + +// impl<'a, I> + +pub fn eq(vm: &VirtualMachine, zelf: &impl SimpleSeq, other: &impl SimpleSeq) -> PyResult { + if zelf.len() == other.len() { + for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { + if a.is(b) { + continue; + } + if !vm.bool_eq(a.clone(), b.clone())? { + return Ok(false); + } + } + Ok(true) + } else { + Ok(false) + } +} + +pub fn lt(vm: &VirtualMachine, zelf: &impl SimpleSeq, other: &impl SimpleSeq) -> PyResult { + for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { + if let Some(v) = vm.bool_seq_lt(a.clone(), b.clone())? { + return Ok(v); + } + } + Ok(zelf.len() < other.len()) +} + +pub fn gt(vm: &VirtualMachine, zelf: &impl SimpleSeq, other: &impl SimpleSeq) -> PyResult { + for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { + if let Some(v) = vm.bool_seq_gt(a.clone(), b.clone())? { + return Ok(v); + } + } + Ok(zelf.len() > other.len()) +} + +pub fn ge(vm: &VirtualMachine, zelf: &impl SimpleSeq, other: &impl SimpleSeq) -> PyResult { + for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { + if let Some(v) = vm.bool_seq_gt(a.clone(), b.clone())? { + return Ok(v); + } + } + + Ok(zelf.len() >= other.len()) +} + +pub fn le(vm: &VirtualMachine, zelf: &impl SimpleSeq, other: &impl SimpleSeq) -> PyResult { + for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { + if let Some(v) = vm.bool_seq_lt(a.clone(), b.clone())? { + return Ok(v); + } + } + + Ok(zelf.len() <= other.len()) +} + +pub struct SeqMul<'a> { + seq: &'a dyn SimpleSeq, + repetitions: usize, + iter: Option>, +} +impl<'a> Iterator for SeqMul<'a> { + type Item = &'a PyObjectRef; + fn next(&mut self) -> Option { + if self.seq.len() == 0 { + return None; + } + match self.iter.as_mut().and_then(Iterator::next) { + Some(item) => Some(item), + None => { + if self.repetitions == 0 { + None + } else { + self.repetitions -= 1; + self.iter = Some(self.seq.iter()); + self.next() + } + } + } + } + fn size_hint(&self) -> (usize, Option) { + let size = self.iter.as_ref().map_or(0, ExactSizeIterator::len) + + (self.repetitions * self.seq.len()); + (size, Some(size)) + } +} +impl ExactSizeIterator for SeqMul<'_> {} + +pub fn seq_mul<'a>(seq: &'a impl SimpleSeq, repetitions: isize) -> SeqMul<'a> { + SeqMul { + seq, + repetitions: repetitions.max(0) as usize, + iter: None, + } +} diff --git a/vm/src/stdlib/collections.rs b/vm/src/stdlib/collections.rs index fbe329ac0..b307b4c33 100644 --- a/vm/src/stdlib/collections.rs +++ b/vm/src/stdlib/collections.rs @@ -1,6 +1,7 @@ use crate::function::OptionalArg; -use crate::obj::{objiter, objsequence, objtype::PyClassRef}; +use crate::obj::{objiter, objtype::PyClassRef}; use crate::pyobject::{IdProtocol, PyClassImpl, PyIterable, PyObjectRef, PyRef, PyResult, PyValue}; +use crate::sequence::{self, SimpleSeq}; use crate::vm::ReprGuard; use crate::VirtualMachine; use itertools::Itertools; @@ -28,7 +29,7 @@ struct PyDequeOptions { } impl PyDeque { - pub fn borrow_sequence<'a>(&'a self) -> impl objsequence::SimpleSeq + 'a { + pub fn borrow_sequence<'a>(&'a self) -> impl SimpleSeq + 'a { self.deque.borrow() } } @@ -247,7 +248,7 @@ impl PyDeque { let lhs = &zelf.borrow_sequence(); let rhs = &other.borrow_sequence(); - let eq = objsequence::seq_equal(vm, lhs, rhs)?; + let eq = sequence::eq(vm, lhs, rhs)?; Ok(vm.new_bool(eq)) } @@ -265,7 +266,7 @@ impl PyDeque { let lhs = &zelf.borrow_sequence(); let rhs = &other.borrow_sequence(); - let eq = objsequence::seq_lt(vm, lhs, rhs)?; + let eq = sequence::lt(vm, lhs, rhs)?; Ok(vm.new_bool(eq)) } @@ -283,7 +284,7 @@ impl PyDeque { let lhs = &zelf.borrow_sequence(); let rhs = &other.borrow_sequence(); - let eq = objsequence::seq_gt(vm, lhs, rhs)?; + let eq = sequence::gt(vm, lhs, rhs)?; Ok(vm.new_bool(eq)) } @@ -301,7 +302,7 @@ impl PyDeque { let lhs = &zelf.borrow_sequence(); let rhs = &other.borrow_sequence(); - let eq = objsequence::seq_le(vm, lhs, rhs)?; + let eq = sequence::le(vm, lhs, rhs)?; Ok(vm.new_bool(eq)) } @@ -319,14 +320,14 @@ impl PyDeque { let lhs = &zelf.borrow_sequence(); let rhs = &other.borrow_sequence(); - let eq = objsequence::seq_ge(vm, lhs, rhs)?; + let eq = sequence::ge(vm, lhs, rhs)?; Ok(vm.new_bool(eq)) } #[pymethod(name = "__mul__")] fn mul(&self, n: isize, _vm: &VirtualMachine) -> Self { let deque: &VecDeque<_> = &self.deque.borrow(); - let mul = objsequence::seq_mul(deque, n); + let mul = sequence::seq_mul(deque, n); let skipped = if let Some(maxlen) = self.maxlen.get() { mul.len() - maxlen } else {