Skip to content

Commit

Permalink
Add support for appending the longer stream of an interleave operation (
Browse files Browse the repository at this point in the history
#47)

+ Add `appendLonger()` to cover when source and argument provide different number of elements
+ Add `appendArgumentIfLonger()` to cover when argument is longer than source
+ Add `appendSourceIfLonger()` to cover when source is longer than argument
  • Loading branch information
tginsberg authored Oct 20, 2024
1 parent 513edcc commit 6565b85
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
+ Implement `dropLast(n)`
+ Add support for `zipWith(iterable)` and `zipWith(iterator)`
+ Add support for `interleave(iterable)` and `interleave(iterator)`
+ Add support for `appendLonger()`, `appendArgumentIfLonger()` and `appendSourceIfLonger()` on `interleave()`

### 0.5.0
+ Implement `reverse()`
Expand Down
49 changes: 48 additions & 1 deletion src/main/java/com/ginsberg/gatherers4j/InterleavingGatherer.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.Iterator;
import java.util.Spliterator;
import java.util.function.BiConsumer;
import java.util.stream.Gatherer;
import java.util.stream.Stream;

Expand All @@ -26,6 +27,8 @@
public class InterleavingGatherer<INPUT> implements Gatherer<INPUT, Void, INPUT> {

private final Spliterator<INPUT> otherSpliterator;
private boolean appendArgumentIfLonger;
private boolean appendSourceIfLonger;

InterleavingGatherer(final Iterable<INPUT> other) {
mustNotBeNull(other, "Other iterable must not be null");
Expand All @@ -43,11 +46,55 @@ public class InterleavingGatherer<INPUT> implements Gatherer<INPUT, Void, INPUT>
otherSpliterator = other.spliterator();
}

/**
* If the source stream and the argument stream/iterator/iterable provide a different
* number of elements, append all the remaining elements from either one to the output stream.
*/
public InterleavingGatherer<INPUT> appendLonger() {
this.appendArgumentIfLonger = true;
this.appendSourceIfLonger = true;
return this;
}

/**
* If the argument stream/iterator/iterable provides more elements than the source stream,
* append all remaining elements from the argument stream/iterator/iterable to the output stream.
*/
public InterleavingGatherer<INPUT> appendArgumentIfLonger() {
this.appendArgumentIfLonger = true;
return this;
}

/**
* If the source stream provides more elements than the argument stream/iterator/iterable,
* append all the remaining elements to the output stream.
*/
public InterleavingGatherer<INPUT> appendSourceIfLonger() {
this.appendSourceIfLonger = true;
return this;
}

@Override
public Integrator<Void, INPUT, INPUT> integrator() {
return (_, element, downstream) -> {
downstream.push(element);
return otherSpliterator.tryAdvance(downstream::push) && !downstream.isRejecting();
if (appendSourceIfLonger) {
otherSpliterator.tryAdvance(downstream::push);
return !downstream.isRejecting();
} else {
// End immediately if we are not appending source if it is longer and other is finished
return otherSpliterator.tryAdvance(downstream::push) && !downstream.isRejecting();
}
};
}

@Override
public BiConsumer<Void, Downstream<? super INPUT>> finisher() {
return (_, downstream) -> {
boolean downstreamRejecting = downstream.isRejecting();
while (appendArgumentIfLonger && !downstreamRejecting) {
downstreamRejecting = !otherSpliterator.tryAdvance(downstream::push);
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,51 @@ void argumentStreamMustNotBeNull() {
).isInstanceOf(IllegalArgumentException.class);
}

@Test
void interleaveOtherLongerSpecifyingEither() {
final Stream<String> left = Stream.of("A", "B", "C");
final Stream<String> right = Stream.of("D", "E", "F", "G", "H");

// Act
final List<String> output = left
.gather(Gatherers4j.interleave(right).appendLonger())
.toList();

// Assert
assertThat(output)
.containsExactly("A", "D", "B", "E", "C", "F", "G", "H");
}

@Test
void interleaveArgumentLongerSpecifyingArgument() {
final Stream<String> left = Stream.of("A", "B", "C");
final Stream<String> right = Stream.of("D", "E", "F", "G", "H");

// Act
final List<String> output = left
.gather(Gatherers4j.interleave(right).appendArgumentIfLonger())
.toList();

// Assert
assertThat(output)
.containsExactly("A", "D", "B", "E", "C", "F", "G", "H");
}

@Test
void interleaveSourceLongerSpecifyingSourceEither() {
final Stream<String> left = Stream.of("A", "B", "C", "D", "E");
final Stream<String> right = Stream.of("F", "G", "H");

// Act
final List<String> output = left
.gather(Gatherers4j.interleave(right).appendSourceIfLonger())
.toList();

// Assert
assertThat(output)
.containsExactly("A", "F", "B", "G", "C", "H", "D", "E");
}

@Test
void interleavingGathererIterable() {
// Arrange
Expand Down

0 comments on commit 6565b85

Please sign in to comment.