Add reversed iterator type.

This commit is contained in:
jfh
2021-08-17 05:25:30 +03:00
parent 2da818c0de
commit ca6ab792f0
4 changed files with 62 additions and 32 deletions

View File

@@ -1,14 +1,15 @@
use crate::common::lock::PyRwLock;
use crossbeam_utils::atomic::AtomicCell;
use num_bigint::BigInt;
use num_traits::Zero;
use super::int::PyIntRef;
use super::pytype::PyTypeRef;
use crate::function::OptionalArg;
use crate::iterator;
use crate::slots::PyIter;
use crate::vm::VirtualMachine;
use crate::{iterator, ItemProtocol, TypeProtocol};
use crate::{IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
#[pyclass(module = false, name = "enumerate")]
@@ -60,6 +61,52 @@ impl PyIter for PyEnumerate {
}
}
#[pyclass(module = false, name = "reversed")]
#[derive(Debug)]
pub struct PyReverseSequenceIterator {
pub position: AtomicCell<isize>,
pub obj: PyObjectRef,
}
impl PyValue for PyReverseSequenceIterator {
fn class(vm: &VirtualMachine) -> &PyTypeRef {
&vm.ctx.types.reverse_iter_type
}
}
#[pyimpl(with(PyIter))]
impl PyReverseSequenceIterator {
pub fn new(obj: PyObjectRef, len: isize) -> Self {
Self {
position: AtomicCell::new(len - 1),
obj,
}
}
#[pymethod(magic)]
fn length_hint(&self) -> PyResult<isize> {
Ok(self.position.load() + 1)
}
}
impl PyIter for PyReverseSequenceIterator {
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
let pos = zelf.position.fetch_sub(1);
if pos >= 0 {
match zelf.obj.get_item(pos, vm) {
Err(ref e) if e.isinstance(&vm.ctx.exceptions.index_error) => {
Err(vm.new_stop_iteration())
}
// also catches stop_iteration => stop_iteration
ret => ret,
}
} else {
Err(vm.new_stop_iteration())
}
}
}
pub fn init(context: &PyContext) {
PyEnumerate::extend_class(context, &context.types.enumerate_type);
PyReverseSequenceIterator::extend_class(context, &context.types.reverse_iter_type);
}

View File

@@ -21,12 +21,11 @@ pub enum IterStatus {
Exhausted,
}
#[pyclass(module = false, name = "iter")]
#[pyclass(module = false, name = "iterator")]
#[derive(Debug)]
pub struct PySequenceIterator {
pub position: AtomicCell<isize>,
pub obj: PyObjectRef,
pub reversed: bool,
}
impl PyValue for PySequenceIterator {
@@ -41,45 +40,26 @@ impl PySequenceIterator {
Self {
position: AtomicCell::new(0),
obj,
reversed: false,
}
}
pub fn new_reversed(obj: PyObjectRef, len: isize) -> Self {
Self {
position: AtomicCell::new(len - 1),
obj,
reversed: true,
}
}
#[pymethod(magic)]
fn length_hint(&self, vm: &VirtualMachine) -> PyResult<isize> {
let pos = self.position.load();
let hint = if self.reversed {
pos + 1
} else {
let len = vm.obj_len(&self.obj)?;
len as isize - pos
};
Ok(hint)
let len = vm.obj_len(&self.obj)?;
Ok(len as isize - pos)
}
}
impl PyIter for PySequenceIterator {
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
let step: isize = if zelf.reversed { -1 } else { 1 };
let pos = zelf.position.fetch_add(step);
if pos >= 0 {
match zelf.obj.get_item(pos, vm) {
Err(ref e) if e.isinstance(&vm.ctx.exceptions.index_error) => {
Err(vm.new_stop_iteration())
}
// also catches stop_iteration => stop_iteration
ret => ret,
let pos = zelf.position.fetch_add(1);
match zelf.obj.get_item(pos, vm) {
Err(ref e) if e.isinstance(&vm.ctx.exceptions.index_error) => {
Err(vm.new_stop_iteration())
}
} else {
Err(vm.new_stop_iteration())
// also catches stop_iteration => stop_iteration
ret => ret,
}
}
}

View File

@@ -12,9 +12,10 @@ mod decl {
use crate::builtins::bytes::PyBytesRef;
use crate::builtins::code::PyCodeRef;
use crate::builtins::dict::PyDictRef;
use crate::builtins::enumerate::PyReverseSequenceIterator;
use crate::builtins::function::{PyCellRef, PyFunctionRef};
use crate::builtins::int::PyIntRef;
use crate::builtins::iter::{PyCallableIterator, PySequenceIterator};
use crate::builtins::iter::PyCallableIterator;
use crate::builtins::list::{PyList, SortOptions};
use crate::builtins::pybool::IntoPyBool;
use crate::builtins::pystr::{PyStr, PyStrRef};
@@ -720,7 +721,7 @@ mod decl {
"argument to reversed() must be a sequence".to_owned()
})?;
let len = vm.obj_len(&obj)? as isize;
let obj_iterator = PySequenceIterator::new_reversed(obj, len);
let obj_iterator = PyReverseSequenceIterator::new(obj, len);
Ok(obj_iterator.into_object(vm))
}
}

View File

@@ -68,6 +68,7 @@ pub struct TypeZoo {
pub generator_type: PyTypeRef,
pub int_type: PyTypeRef,
pub iter_type: PyTypeRef,
pub reverse_iter_type: PyTypeRef,
pub complex_type: PyTypeRef,
pub list_type: PyTypeRef,
pub list_iterator_type: PyTypeRef,
@@ -182,6 +183,7 @@ impl TypeZoo {
generator_type: generator::PyGenerator::init_bare_type().clone(),
getset_type: getset::PyGetSet::init_bare_type().clone(),
iter_type: iter::PySequenceIterator::init_bare_type().clone(),
reverse_iter_type: enumerate::PyReverseSequenceIterator::init_bare_type().clone(),
list_iterator_type: list::PyListIterator::init_bare_type().clone(),
list_reverseiterator_type: list::PyListReverseIterator::init_bare_type().clone(),
mappingproxy_type: mappingproxy::PyMappingProxy::init_bare_type().clone(),