-
Couldn't load subscription status.
- Fork 1.4k
Replace List with Chunk in ZTransducer.collectAllN #3886
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
Replace List with Chunk in ZTransducer.collectAllN #3886
Conversation
|
Yes, it's very tempting to get rid of lists. Unfortunately, |
|
Thought about going the |
|
Hey @svranesevic! Thank you for following up on this. A ChunkBuilder would be best here indeed. Appending elements to a chunk is fast, but not as fast as building with a ChunkBuilder. |
bda1b39 to
bd83fe5
Compare
|
Thanks @svranesevic, this revision looks great. The only thing we need to do is make sure the creation of the |
| def collectAllN[I](n: Long): ZTransducer[Any, Nothing, I, Chunk[I]] = | ||
| ZTransducer { | ||
|
|
||
| def go(in: Chunk[I], builder: ChunkBuilder[I], size: Long): (ChunkBuilder[Chunk[I]], ChunkBuilder[I], Long) = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can append in to builder all at once instead of appending elements one by one. It is faster and would save some lines of code as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, I was wrapping my mind around transducer internals while writing this 😅
With that approach we need to handle case when appending the in would produce Chunk that has more elements than N by splitting the in accordingly and carrying over leftover. I will check Chunk#splitAt but afaik it should be better than current impl.
| } | ||
|
|
||
| case Some(in) => | ||
| stateRef.modify { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ChunkBuilder could be reused after emitting a chunk, if I'm not wrong
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be reused and I almost went for it, but after giving it a thought I'd argue that it's reusability is implementation detail as ChunkBuilder is not ReusableBuilder as of right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ChunkBuilder has a public clear method, so yes
|
@svranesevic I have couple of ideas how to simplify implementation a bit. Let me explore it today or tomorrow. |
Sure thing, looking forward to it! |
|
@svranesevic how about finalizing Regarding
|
I agree with scoping down the PR to
|
|
I guess the main reason why |
|
Admittedly reusing the ChunkBuilder is probably unsafe with streams of In any case, let's scope this down to |
| */ | ||
| def collectAllN[I](n: Long): ZTransducer[Any, Nothing, I, List[I]] = | ||
| foldUntil[I, List[I]](Nil, n)((list, element) => element :: list).map(_.reverse).filter(_.nonEmpty) | ||
| def collectAllN[I](n: Int): ZTransducer[Any, Nothing, I, Chunk[I]] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementation detail that bubbled up due to the Chunk's size being Int, might be a deal breaker for this change?
Affects https://github.com/zio/zio/pull/3886/files#diff-e2c16046e05624c39e46b9e4c2870b9cR1596 and https://github.com/zio/zio/pull/3886/files#diff-e2c16046e05624c39e46b9e4c2870b9cR1603.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a fair compromise, n is fine as an Int here.
| suite("collectAllN")( | ||
| testM("happy path") { | ||
| assertM(run(ZTransducer.collectAllN[Int](3), List(Chunk(1, 2, 3, 4))))(equalTo(Chunk(List(1, 2, 3), List(4)))) | ||
| assertM(run(ZTransducer.collectAllN[Int](3), List(Chunk(1, 2, 3, 4))))( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@svranesevic Last request and then this is good to merge: the implementation is a bit more involved now, so can we add a property check? Just equivalence with List#grouped should be sufficient.
|
Hey @svranesevic, need any help getting this over the finish line? |
|
Hey @iravid, haven't had time lately to wrap this up, sorry about it, will do today! |
|
Ping @iravid |
|
Looks good @svranesevic! Thanks! |
Replace usage of
Listin favor of a more performantChunkthroughout ZTransducer.collectAllN