Skip to content
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

Add Repeat #337

Closed

Conversation

Projects
None yet
3 participants
@ChristopherDavenport
Copy link
Contributor

ChristopherDavenport commented May 13, 2017

Creates a Parallel Iterator that endlessly repeats a single element

I am sure this needs more testing, however I don't know the best way. I believe I have a working implementation.

Refs #331

}

pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
Repeat{element: elt}

This comment has been minimized.

@nikomatsakis

nikomatsakis May 16, 2017

Member

Nit: I'd format this as Repeat { element: elt }

This comment has been minimized.

@cuviper

cuviper May 16, 2017

Member

I'd suggest just running rustfmt repeat.rs to probably address all of the nits at once.


impl<T: Clone> Clone for Repeat<T>{
fn clone(&self) -> Repeat<T> {
Repeat{ element: self.element.clone()}

This comment has been minimized.

@nikomatsakis

nikomatsakis May 16, 2017

Member

Nit: same here

fn drive<C>(self, consumer: C) -> C::Result
where C: Consumer<Self::Item>
{
bridge(self, consumer)

This comment has been minimized.

@nikomatsakis

nikomatsakis May 16, 2017

Member

Nit: indentation


fn with_producer<CB>(self, callback: CB) -> CB :: Output
where CB: ProducerCallback<Self::Item>
{

This comment has been minimized.

@nikomatsakis

nikomatsakis May 16, 2017

Member

Nit: the { should align with fn

bridge(self, consumer)
}

fn with_producer<CB>(self, callback: CB) -> CB :: Output

This comment has been minimized.

@nikomatsakis

nikomatsakis May 16, 2017

Member

Nit: CB::Output

type Item = T;

fn split(self) -> (Self, Option<Self>) {
(Repeat{element: self.element.clone()}, Some(Repeat{element: self.element.clone()}))

This comment has been minimized.

@nikomatsakis

nikomatsakis May 16, 2017

Member

Nit: only one of these needs to be a clone

fn split_at(self, index: usize) -> (Self, Self) {
(
RepeatProducer{repeat: self.repeat.clone()},
RepeatProducer{repeat: self.repeat.clone()}

This comment has been minimized.

@nikomatsakis

nikomatsakis May 16, 2017

Member

Nit: only one of these needs to be a clone; the other can just be repeat: self.repeat and take ownership

type Item = T;
type IntoIter = RepeatIter<T>;

fn into_iter(self) -> Self::IntoIter{

This comment has been minimized.

@nikomatsakis

nikomatsakis May 16, 2017

Member

Nit: Self::IntoIter {

fn next_back(&mut self) -> Option<A> { Some(self.repeat.element.clone()) }
}

impl<T: Clone> ExactSizeIterator for RepeatIter<T> {

This comment has been minimized.

@nikomatsakis

nikomatsakis May 16, 2017

Member

Argh. The need to have ExactSizeIterator implemented is frustrating; I'm not sure if this impl is technically obeying the intentions of this trait (although I guess it works fine in practice). I'm trying to remember why we need ExactSizeIterator; something to do with the reverse operation iirc.

This comment has been minimized.

@cuviper

cuviper May 16, 2017

Member

Because std::iter::Zip is only double-ended if its inputs are double-ended and exact-size.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 22, 2017

Member

Yeah, I remembered it had something to do with Zip

let mut fours: Vec<_> = repeat(4)
.take(4)
.zip(v)
.collect();

This comment has been minimized.

@cuviper

cuviper May 16, 2017

Member

Since your producer's split_at doesn't actually use the index, I don't think this take(4) actually works -- but the result is still limited by the zip length instead. Try another test with just repeat(4).take(4).collect(), and it panics "too many values pushed to consumer".

This comment has been minimized.

@ChristopherDavenport

ChristopherDavenport Jun 1, 2017

Author Contributor

Is there something I should do in order to get take to work effectively with this implementation. It seems to play nicely with others, but no so nicely by itself.

This comment has been minimized.

@cuviper

cuviper Jun 1, 2017

Member

The producer will need to track its effective length. It should initialize to usize::MAX since that's what len() reported. Then each time it splits, use the given index to determine the resulting length of each side. And finally the iterator will also need to limit its length.

This comment has been minimized.

@ChristopherDavenport

ChristopherDavenport Jun 1, 2017

Author Contributor

So basically despite this being infinite in this formulation, when managing the IndexedParralellIterator actually limit the size to usize::MAX and reduce as we consume. So we can split where necessary.

This comment has been minimized.

@cuviper

cuviper Jun 1, 2017

Member

Yes, exactly. We can't use this as an IndexedParallelIterator unless we actually map it to indexes, which puts an upper bound on the length.

Well... actually if you want to be clever, you could track the length as Option<usize> and leave the rightmost part of the splits open-ended. So a bounded segment with Some(len) splits into two bounded segments, and an unbounded None splits into Some on the left and None on the right. This will still work with take because it splits and discards the (infinite) remainder.

fn drive_unindexed<C>(self, consumer: C) -> C::Result
where C: UnindexedConsumer<Self::Item>
{
bridge(self, consumer)

This comment has been minimized.

@cuviper

cuviper May 16, 2017

Member

This should use bridge_unindexed instead, otherwise you're never using the UnindexedProducer implementation at all.

/// Producer

struct RepeatProducer<P> {
repeat: Repeat<P>,

This comment has been minimized.

@cuviper

cuviper May 16, 2017

Member

I wonder, why does this store the whole Repeat type, and not just the element? It's a minor difference, but then we don't need to worry about Clone for Repeat itself.

/// Repeat Iter Create As Repeat Does Not Have ExactSizeIterator

struct RepeatIter<T> {
repeat: Repeat<T>,

This comment has been minimized.

@cuviper

cuviper May 16, 2017

Member

Same here, seems like this could just store the element T.

@ChristopherDavenport

This comment has been minimized.

Copy link
Contributor Author

ChristopherDavenport commented May 22, 2017

I have not forgotten about this, sorry about the long delay. Hopefully can get around to it by tomorrow evening or at latest this weekend.

element: T,
}

pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {

This comment has been minimized.

@nikomatsakis

nikomatsakis Jun 10, 2017

Member

Can we add some docs to this?

use super::internal::*;
use std::usize;

pub struct Repeat<T> {

This comment has been minimized.

@nikomatsakis

nikomatsakis Jun 10, 2017

Member

I think this should type should require T: Clone + Send

This comment has been minimized.

@nikomatsakis

nikomatsakis Jun 10, 2017

Member

Also, it should probably have some documentation, since it is user-facing.


/// Producer

struct RepeatProducer<P> {

This comment has been minimized.

@nikomatsakis

nikomatsakis Jun 10, 2017

Member

Nit: Can we make this <T> instead of <P>, so it matches the others? This confused me for a while, since I thought P must imply it is a producer or something. I'd also rather see T: Clone + Send.


impl<T: Clone> ExactSizeIterator for RepeatIter<T> {
fn len(&self) -> usize {
usize::MAX

This comment has been minimized.

@nikomatsakis

nikomatsakis Jun 10, 2017

Member

I'm still mildly nervous about this but I don't have a better suggestion. =) I feel like maybe we should revisit the way we handle rev() to see if we can lift this requirement; but I guess it's ok for now.

@nikomatsakis
Copy link
Member

nikomatsakis left a comment

This is looking great to me! I made a few minor suggestions, mostly about rustdocs and conventions -- do you think you'll have time to apply those?

@nikomatsakis

This comment has been minimized.

Copy link
Member

nikomatsakis commented Jun 28, 2017

@ChristopherDavenport do you still have time to make further changes here? (If not, that's fine, just want to know -- I can try to make the final tweaks myself.)

@ChristopherDavenport

This comment has been minimized.

Copy link
Contributor Author

ChristopherDavenport commented Jun 28, 2017

I may need you to finish the final tweaks.

I will not bore you with in depth details(sisters graduation, switching positions, 2 emergency applications needed asap for work). My experience with rust being so weak I haven't been able to yank myself out of my work, primary OSS long enough to finish this.

I apologize and if you don't finish it up I will fix it myself eventually, but the "eventually" is a problem I can't nail down at the moment.

@nikomatsakis

This comment has been minimized.

Copy link
Member

nikomatsakis commented Jun 28, 2017

@ChristopherDavenport no worries at all! I very much appreciate the work you did so far.

@nikomatsakis nikomatsakis force-pushed the ChristopherDavenport:repeat branch from 1dd7065 to 40755c3 Jun 28, 2017

ChristopherDavenport and others added some commits May 13, 2017

Add Repeat
Creates a Parallel Iterator that endlessly repeats a single element
Remove Repeat boxing, and make test use explicit
Needs something for using the take method which is missing, although elt should be available for any element

@nikomatsakis nikomatsakis force-pushed the ChristopherDavenport:repeat branch from 40755c3 to 24fe462 Jun 28, 2017

@cuviper
Copy link
Member

cuviper left a comment

We can't just ignore lengths in the indexed iterator. See my comment on split_at.

One thing we discussed on gitter, which might be more palatable than lying about lengths, is to stop trying to make Repeat an indexed iterator. Let it be unindexed only, and add a second variant like repeatn<T>(elt: T, n: usize) -> RepeatN<T> that is indexed, conceptually equivalent to repeat(elt).take(n).

Niko thought we could even add an inherent method Repeat::take(usize) -> RepeatN to let repeat(elt).take(n) still work, but we probably don't want to duplicate too many indexed methods that way.

}

fn split_at(self, index: usize) -> (Self, Self) {
(RepeatProducer { repeat: self.repeat.clone() }, RepeatProducer { repeat: self.repeat })

This comment has been minimized.

@cuviper

cuviper Jun 28, 2017

Member

I think this is still wrong. If I repeat(x).take(4), then we'll get a split_at(4), and this needs to remember to only produce 4 items on the left side. The right side is debatable, whether we leave that as infinite/usize::MAX, or now reduce it to MAX - 4 remaining.

(noted here before: #337 (comment))

This comment has been minimized.

@nikomatsakis

nikomatsakis Jul 7, 2017

Member

Ah yes, good point. On this note, I'm softening on repeatn. Seems like a useful building block.

This comment has been minimized.

@nikomatsakis

nikomatsakis Jul 7, 2017

Member

Maybe we should just not offer repeat at all; you can use repeatn(usize::MAX) for all practical purposes.

@nikomatsakis

This comment has been minimized.

Copy link
Member

nikomatsakis commented Sep 22, 2017

Closing in favor of #397

@nikomatsakis

This comment has been minimized.

Copy link
Member

nikomatsakis commented Sep 22, 2017

Thanks very much @ChristopherDavenport for laying the foundation here!

bors bot added a commit that referenced this pull request Oct 7, 2017

Merge #397
397: Add Repeat and RepeatN r=nikomatsakis a=cuviper

This adds:
- unindexed, infinite `iter::repeat(elt) -> Repeat`
- indexed, finite `iter::repeatn(elt, n) -> RepeatN`
- `Repeat` methods `take(n)` and `zip(iter)` convert to `RepeatN`

This extends #337, opened separately for review since it's a fairly major change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.