move iterator::length_hint to vm

This commit is contained in:
Jeong YunWon
2021-10-03 03:51:01 +09:00
parent d90a8cb8f3
commit 910d5e7d11
6 changed files with 53 additions and 57 deletions

View File

@@ -1,7 +1,6 @@
use super::PyTypeRef;
use crate::{
function::PosArgs,
iterator,
protocol::{PyIter, PyIterReturn},
slots::{IteratorIterable, SlotConstructor, SlotIterator},
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, VirtualMachine,
@@ -38,7 +37,7 @@ impl PyMap {
#[pymethod(magic)]
fn length_hint(&self, vm: &VirtualMachine) -> PyResult<usize> {
self.iterators.iter().try_fold(0, |prev, cur| {
let cur = iterator::length_hint(vm, cur.as_object().clone())?.unwrap_or(0);
let cur = vm.length_hint(cur.as_object().clone())?.unwrap_or(0);
let max = std::cmp::max(prev, cur);
Ok(max)
})

View File

@@ -14,7 +14,6 @@ use crate::{
coroutine::Coro,
exceptions::{self, ExceptionCtor},
function::FuncArgs,
iterator,
protocol::{PyIter, PyIterReturn},
scope::Scope,
slots::PyComparisonOp,

View File

@@ -1,7 +1,6 @@
use super::IntoFuncArgs;
use crate::{
builtins::iter::PySequenceIterator,
iterator,
protocol::{PyIter, PyIterReturn},
PyObjectRef, PyResult, PyValue, TryFromObject, TypeProtocol, VirtualMachine,
};
@@ -58,7 +57,7 @@ impl<T> ArgIterable<T> {
None => PySequenceIterator::new(self.iterable.clone()).into_object(vm),
};
let length_hint = iterator::length_hint(vm, iter_obj.clone())?;
let length_hint = vm.length_hint(iter_obj.clone())?;
Ok(PyIterator {
vm,

View File

@@ -3,9 +3,8 @@
*/
use crate::{
builtins::{PyBaseExceptionRef, PyInt},
protocol::{PyIter, PyIterReturn},
IdProtocol, PyObjectRef, PyResult, TypeProtocol, VirtualMachine,
PyObjectRef, PyResult, VirtualMachine,
};
pub fn try_map<F, R>(vm: &VirtualMachine, iter: &PyIter, cap: usize, mut f: F) -> PyResult<Vec<R>>
@@ -25,52 +24,6 @@ where
Ok(results)
}
pub fn length_hint(vm: &VirtualMachine, iter: PyObjectRef) -> PyResult<Option<usize>> {
if let Some(len) = vm.obj_len_opt(&iter) {
match len {
Ok(len) => return Ok(Some(len)),
Err(e) => {
if !e.isinstance(&vm.ctx.exceptions.type_error) {
return Err(e);
}
}
}
}
let hint = match vm.get_method(iter, "__length_hint__") {
Some(hint) => hint?,
None => return Ok(None),
};
let result = match vm.invoke(&hint, ()) {
Ok(res) => {
if res.is(&vm.ctx.not_implemented) {
return Ok(None);
}
res
}
Err(e) => {
return if e.isinstance(&vm.ctx.exceptions.type_error) {
Ok(None)
} else {
Err(e)
}
}
};
let hint = result
.payload_if_subclass::<PyInt>(vm)
.ok_or_else(|| {
vm.new_type_error(format!(
"'{}' object cannot be interpreted as an integer",
result.class().name()
))
})?
.try_to_primitive::<isize>(vm)?;
if hint.is_negative() {
Err(vm.new_value_error("__length_hint__() should return >= 0".to_owned()))
} else {
Ok(Some(hint as usize))
}
}
// pub fn seq_iter_method(obj: PyObjectRef) -> PySequenceIterator {
// PySequenceIterator::new_forward(obj)
// }

View File

@@ -13,7 +13,6 @@ mod _operator {
use crate::{
builtins::{PyInt, PyIntRef, PyStrRef, PyTypeRef},
function::{ArgBytesLike, FuncArgs, KwArgs, OptionalArg},
iterator,
protocol::{PyIter, PyIterReturn},
slots::{
Callable,
@@ -284,7 +283,8 @@ mod _operator {
v.payload::<PyInt>().unwrap().try_to_primitive(vm)
})
.unwrap_or(Ok(0))?;
iterator::length_hint(vm, obj).map(|v| vm.ctx.new_int(v.unwrap_or(default)))
vm.length_hint(obj)
.map(|v| vm.ctx.new_int(v.unwrap_or(default)))
}
// Inplace Operators

View File

@@ -1285,7 +1285,7 @@ impl VirtualMachine {
.collect()
} else {
let iter = value.clone().get_iter(self)?;
let cap = match iterator::length_hint(self, value.clone()) {
let cap = match self.length_hint(value.clone()) {
Err(e) if e.class().is(&self.ctx.exceptions.runtime_error) => return Err(e),
Ok(Some(value)) => value,
// Use a power of 2 as a default capacity.
@@ -1333,7 +1333,7 @@ impl VirtualMachine {
// TODO: put internal iterable type
obj => {
let iter = obj.clone().get_iter(self)?;
let cap = match iterator::length_hint(self, obj.clone()) {
let cap = match self.length_hint(obj.clone()) {
Err(e) if e.class().is(&self.ctx.exceptions.runtime_error) => {
return Ok(Err(e))
}
@@ -1926,6 +1926,52 @@ impl VirtualMachine {
})
}
pub fn length_hint(&self, iter: PyObjectRef) -> PyResult<Option<usize>> {
if let Some(len) = self.obj_len_opt(&iter) {
match len {
Ok(len) => return Ok(Some(len)),
Err(e) => {
if !e.isinstance(&self.ctx.exceptions.type_error) {
return Err(e);
}
}
}
}
let hint = match self.get_method(iter, "__length_hint__") {
Some(hint) => hint?,
None => return Ok(None),
};
let result = match self.invoke(&hint, ()) {
Ok(res) => {
if res.is(&self.ctx.not_implemented) {
return Ok(None);
}
res
}
Err(e) => {
return if e.isinstance(&self.ctx.exceptions.type_error) {
Ok(None)
} else {
Err(e)
}
}
};
let hint = result
.payload_if_subclass::<PyInt>(self)
.ok_or_else(|| {
self.new_type_error(format!(
"'{}' object cannot be interpreted as an integer",
result.class().name()
))
})?
.try_to_primitive::<isize>(self)?;
if hint.is_negative() {
Err(self.new_value_error("__length_hint__() should return >= 0".to_owned()))
} else {
Ok(Some(hint as usize))
}
}
/// Checks that the multiplication is able to be performed. On Ok returns the
/// index as a usize for sequences to be able to use immediately.
pub fn check_repeat_or_memory_error(&self, length: usize, n: isize) -> PyResult<usize> {