Skip to content

Make iter::Fuse truly zero cost #70374

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 81 additions & 113 deletions src/libcore/iter/adapters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2261,17 +2261,60 @@ where
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Fuse<I> {
iter: I,
done: bool,
done: <I as fuse_flag::FlagType>::Flag,
}
impl<I> Fuse<I> {
pub(super) fn new(iter: I) -> Fuse<I> {
Fuse { iter, done: false }
Fuse { iter, done: <_>::default() }
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Fuse<I> where I: Iterator {}

mod fuse_flag {
pub trait Flag: Clone + crate::fmt::Debug + Default {
fn is_set(&self) -> bool;
fn set(&mut self);
}

impl Flag for bool {
fn is_set(&self) -> bool {
*self
}

fn set(&mut self) {
*self = true
}
}

#[derive(Clone, Debug, Default)]
pub struct False;

impl Flag for False {
fn is_set(&self) -> bool {
false
}

fn set(&mut self) {
/* intenionally does nothing */
}
}

pub trait FlagType {
type Flag: Flag;
}

impl<I> FlagType for I {
default type Flag = bool;
}

impl<I: super::FusedIterator> FlagType for I {
type Flag = False;
}
}
use fuse_flag::Flag;

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Fuse<I>
where
Expand All @@ -2280,64 +2323,68 @@ where
type Item = <I as Iterator>::Item;

#[inline]
default fn next(&mut self) -> Option<<I as Iterator>::Item> {
if self.done {
fn next(&mut self) -> Option<<I as Iterator>::Item> {
if self.done.is_set() {
None
} else {
let next = self.iter.next();
self.done = next.is_none();
if next.is_none() {
self.done.set();
}
next
}
}

#[inline]
default fn nth(&mut self, n: usize) -> Option<I::Item> {
if self.done {
fn nth(&mut self, n: usize) -> Option<I::Item> {
if self.done.is_set() {
None
} else {
let nth = self.iter.nth(n);
self.done = nth.is_none();
if nth.is_none() {
self.done.set();
}
nth
}
}

#[inline]
default fn last(self) -> Option<I::Item> {
if self.done { None } else { self.iter.last() }
fn last(self) -> Option<I::Item> {
if self.done.is_set() { None } else { self.iter.last() }
}

#[inline]
default fn count(self) -> usize {
if self.done { 0 } else { self.iter.count() }
fn count(self) -> usize {
if self.done.is_set() { 0 } else { self.iter.count() }
}

#[inline]
default fn size_hint(&self) -> (usize, Option<usize>) {
if self.done { (0, Some(0)) } else { self.iter.size_hint() }
fn size_hint(&self) -> (usize, Option<usize>) {
if self.done.is_set() { (0, Some(0)) } else { self.iter.size_hint() }
}

#[inline]
default fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
if self.done {
if self.done.is_set() {
Try::from_ok(init)
} else {
let acc = self.iter.try_fold(init, fold)?;
self.done = true;
self.done.set();
Try::from_ok(acc)
}
}

#[inline]
default fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
if self.done { init } else { self.iter.fold(init, fold) }
if self.done.is_set() { init } else { self.iter.fold(init, fold) }
}
}

Expand All @@ -2347,49 +2394,53 @@ where
I: DoubleEndedIterator,
{
#[inline]
default fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
if self.done {
fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
if self.done.is_set() {
None
} else {
let next = self.iter.next_back();
self.done = next.is_none();
if next.is_none() {
self.done.set();
}
next
}
}

#[inline]
default fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
if self.done {
fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
if self.done.is_set() {
None
} else {
let nth = self.iter.nth_back(n);
self.done = nth.is_none();
if nth.is_none() {
self.done.set();
}
nth
}
}

#[inline]
default fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
if self.done {
if self.done.is_set() {
Try::from_ok(init)
} else {
let acc = self.iter.try_rfold(init, fold)?;
self.done = true;
self.done.set();
Try::from_ok(acc)
}
}

#[inline]
default fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
if self.done { init } else { self.iter.rfold(init, fold) }
if self.done.is_set() { init } else { self.iter.rfold(init, fold) }
}
}

Expand All @@ -2406,89 +2457,6 @@ where
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> Iterator for Fuse<I>
where
I: FusedIterator,
{
#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
self.iter.next()
}

#[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> {
self.iter.nth(n)
}

#[inline]
fn last(self) -> Option<I::Item> {
self.iter.last()
}

#[inline]
fn count(self) -> usize {
self.iter.count()
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.iter.try_fold(init, fold)
}

#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.fold(init, fold)
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> DoubleEndedIterator for Fuse<I>
where
I: DoubleEndedIterator + FusedIterator,
{
#[inline]
fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
self.iter.next_back()
}

#[inline]
fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
self.iter.nth_back(n)
}

#[inline]
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.iter.try_rfold(init, fold)
}

#[inline]
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.rfold(init, fold)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Fuse<I>
where
Expand Down