Skip to content

Commit

Permalink
Merge PR #13
Browse files Browse the repository at this point in the history
  • Loading branch information
fluentfuture committed Aug 21, 2019
2 parents b34025c + 106b1f6 commit 3fdff10
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 151 deletions.
66 changes: 29 additions & 37 deletions core/src/main/java/com/google/mu/util/stream/BiStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,46 +14,22 @@
*****************************************************************************/
package com.google.mu.util.stream;

import java.util.*;
import java.util.Spliterators.AbstractDoubleSpliterator;
import java.util.Spliterators.AbstractIntSpliterator;
import java.util.Spliterators.AbstractLongSpliterator;
import java.util.Spliterators.AbstractSpliterator;
import java.util.function.*;
import java.util.stream.*;
import java.util.stream.Collector.Characteristics;

import static java.util.Comparator.comparing;
import static java.util.Objects.requireNonNull;
import static java.util.Spliterator.ORDERED;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;
import static java.util.stream.StreamSupport.doubleStream;
import static java.util.stream.StreamSupport.intStream;
import static java.util.stream.StreamSupport.longStream;
import static java.util.stream.StreamSupport.stream;

import java.util.AbstractMap;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Spliterator;
import java.util.Spliterators.AbstractDoubleSpliterator;
import java.util.Spliterators.AbstractIntSpliterator;
import java.util.Spliterators.AbstractLongSpliterator;
import java.util.Spliterators.AbstractSpliterator;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.Function;
import java.util.function.IntConsumer;
import java.util.function.LongConsumer;
import java.util.function.Predicate;
import java.util.function.ToDoubleBiFunction;
import java.util.function.ToIntBiFunction;
import java.util.function.ToLongBiFunction;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
import static java.util.stream.StreamSupport.*;

/**
* A class similar to {@link Stream}, but operating over a sequence of pairs of objects.
Expand Down Expand Up @@ -222,8 +198,8 @@ public abstract class BiStream<K, V> {
public static <T, K, V, R> Collector<T, ?, BiStream<K, R>> groupingValuesFrom(
Function<? super T, ? extends Collection<Map.Entry<K, V>>> entrySource,
Collector<? super V, ?, R> valueCollector) {
return Collectors.flatMapping(
requireNonNull(entrySource.andThen(Collection::stream)),
return flatMapping(
requireNonNull(entrySource),
groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, valueCollector)));
}

Expand Down Expand Up @@ -1103,5 +1079,21 @@ public void accept(T value) {
}
}

// TODO: switch to Java 9 Collectors.flatMapping() when we can.
private static <T, E, A, R> Collector<T, A, R> flatMapping(
Function<? super T, ? extends Collection<? extends E>> mapper, Collector<E, A, R> collector) {
BiConsumer<A, E> accumulator = collector.accumulator();
return Collector.of(
collector.supplier(),
(a, input) -> {
for (E entry : mapper.apply(input)) {
accumulator.accept(a, entry);
}
},
collector.combiner(),
collector.finisher(),
collector.characteristics().toArray(new Characteristics[0]));
}

private BiStream() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,22 @@
*****************************************************************************/
package com.google.mu.util.stream;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;

import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.truth.MultimapSubject;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;
import java.util.stream.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import junit.framework.TestCase;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;

/**
* Tests to ensure {@link BiStream#from(Stream, Function, Function)} maintains the invariant that
Expand Down Expand Up @@ -367,12 +362,17 @@ private static <F, T> Function<F, T> trackCallHistory(
};
}

private static MultimapSubject assertKeyValues(BiStream<?, ?> stream) {
Multimap<?, ?> multimap = stream.collect(BiStreamFunctionEvaluationTest::toLinkedListMultimap);
private static<K,V> MultimapSubject assertKeyValues(BiStream<K, V> stream) {
Multimap<?, ?> multimap = stream.collect(new BiCollector<K, V, Multimap<K, V>>() {
@Override
public <E> Collector<E, ?, Multimap<K, V>> bisecting(Function<E, K> toKey, Function<E, V> toValue) {
return BiStreamFunctionEvaluationTest.toLinkedListMultimap(toKey,toValue);
}
});
return assertThat(multimap);
}

private static <T, K, V> Collector<T, ?, LinkedListMultimap<K, V>> toLinkedListMultimap(
public static <T, K, V> Collector<T, ?, Multimap<K, V>> toLinkedListMultimap(
Function<? super T, ? extends K> toKey, Function<? super T, ? extends V> toValue) {
return Collector.of(
LinkedListMultimap::create,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,27 @@
*****************************************************************************/
package com.google.mu.util.stream;

import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.mu.util.stream.BiCollectors.toMap;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static java.util.Arrays.asList;
import static java.util.function.Function.identity;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import com.google.common.collect.Sets;
import com.google.common.collect.*;
import com.google.common.truth.MultimapSubject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Stream;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Stream;

import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static com.google.mu.util.stream.BiCollectors.toMap;
import static java.util.Arrays.asList;
import static java.util.function.Function.identity;

@RunWith(Parameterized.class)
public class BiStreamInvariantsTest {

Expand Down Expand Up @@ -303,7 +291,12 @@ public void collect() {
@Test
public void collect_toImmutableListMultimapWithInflexibleMapperTypes() {
ImmutableListMultimap<String, Integer> multimap =
of("one", 1, "one", 10, "two", 2).collect(BiStreamInvariantsTest::toImmutableMultimap);
of("one", 1, "one", 10, "two", 2).collect(new BiCollector<String, Integer, ImmutableListMultimap<String, Integer>>() {
@Override
public <E> Collector<E, ?, ImmutableListMultimap<String, Integer>> bisecting(Function<E, String> toKey, Function<E, Integer> toValue) {
return BiStreamInvariantsTest.toImmutableMultimap(toKey,toValue);
}
});
assertThat(multimap)
.containsExactlyEntriesIn(ImmutableListMultimap.of("one", 1, "one", 10, "two", 2));
}
Expand Down Expand Up @@ -495,19 +488,24 @@ private <K, V> BiStream<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
return variant.wrap(factory.newBiStream(k1, v1, k2, v2, k3, v3));
}

static MultimapSubject assertKeyValues(BiStream<?, ?> stream) {
Multimap<?, ?> multimap = stream.collect(BiStreamInvariantsTest::toLinkedListMultimap);
static<K, V> MultimapSubject assertKeyValues(BiStream<K, V> stream) {
Multimap<?, ?> multimap = stream.collect(new BiCollector<K, V, Multimap<K,V>>() {
@Override
public <E> Collector<E, ?, Multimap<K, V>> bisecting(Function<E, K> toKey, Function<E, V> toValue) {
return BiStreamInvariantsTest.toLinkedListMultimap(toKey,toValue);
}
});
return assertThat(multimap);
}

// Intentionally declare the parameter types without wildcards, to make sure
// BiCollector can still work with such naive method references.
private static <T, K, V> Collector<T, ?, ImmutableListMultimap<K, V>> toImmutableMultimap(
public static <T, K, V> Collector<T, ?, ImmutableListMultimap<K, V>> toImmutableMultimap(
Function<T, K> keyMapper, Function<T, V> valueMapper) {
return ImmutableListMultimap.toImmutableListMultimap(keyMapper, valueMapper);
}

private static <T, K, V> Collector<T, ?, LinkedListMultimap<K, V>> toLinkedListMultimap(
private static <T, K, V> Collector<T, ?, Multimap<K, V>> toLinkedListMultimap(
Function<? super T, ? extends K> toKey, Function<? super T, ? extends V> toValue) {
return Collector.of(
LinkedListMultimap::create,
Expand Down
53 changes: 22 additions & 31 deletions core/src/test/java/com/google/mu/util/stream/BiStreamTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@
*****************************************************************************/
package com.google.mu.util.stream;

import com.google.common.collect.*;
import com.google.common.truth.IterableSubject;
import com.google.common.truth.MultimapSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.*;

import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
Expand All @@ -23,34 +37,6 @@
import static java.util.stream.Collectors.toList;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.truth.IterableSubject;
import com.google.common.truth.MultimapSubject;

@RunWith(JUnit4.class)
public class BiStreamTest {

Expand Down Expand Up @@ -594,12 +580,17 @@ public class BiStreamTest {
.inOrder();
}

static MultimapSubject assertKeyValues(BiStream<?, ?> stream) {
Multimap<?, ?> multimap = stream.collect(BiStreamTest::toLinkedListMultimap);
static<K,V> MultimapSubject assertKeyValues(BiStream<K, V> stream) {
Multimap<?, ?> multimap = stream.collect(new BiCollector<K, V, Multimap<K, V>>() {
@Override
public <E> Collector<E, ?, Multimap<K, V>> bisecting(Function<E, K> toKey, Function<E, V> toValue) {
return BiStreamTest.toLinkedListMultimap(toKey,toValue);
}
});
return assertThat(multimap);
}

private static <T, K, V> Collector<T, ?, LinkedListMultimap<K, V>> toLinkedListMultimap(
public static <T, K, V> Collector<T, ?, Multimap<K, V>> toLinkedListMultimap(
Function<? super T, ? extends K> toKey, Function<? super T, ? extends V> toValue) {
return Collector.of(
LinkedListMultimap::create,
Expand Down
36 changes: 27 additions & 9 deletions examples/src/test/java/examples/HowToCollectToCustomTypesTest.java
Original file line number Diff line number Diff line change
@@ -1,39 +1,57 @@
package examples;

import static com.google.common.truth.Truth.assertThat;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableRangeMap;
import com.google.common.collect.Range;
import com.google.mu.util.stream.BiCollector;
import com.google.mu.util.stream.BiStream;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.function.Function;
import java.util.stream.Collector;

import static com.google.common.truth.Truth.assertThat;

/** Some examples to show how {@link BiStream#collect} can be used to collect to custom types. */
@RunWith(JUnit4.class)
public class HowToCollectToCustomTypesTest {

@Test public void how_to_collect_to_immutableMap() {
BiStream<String, Integer> biStream = BiStream.of("one", 1, "two", 2);
ImmutableMap<String, Integer> map = biStream.collect(ImmutableMap::toImmutableMap);
ImmutableMap<String, Integer> map = biStream.collect(new BiCollector<String, Integer, ImmutableMap<String, Integer>>() {
@Override
public <E> Collector<E, ?, ImmutableMap<String, Integer>> bisecting(Function<E, String> toKey, Function<E, Integer> toValue) {
return ImmutableMap.toImmutableMap(toKey,toValue);
}
});
assertThat(map).containsExactly("one", 1, "two", 2);
}

@Test public void how_to_collect_to_immutableListMultimap() {
BiStream<String, Integer> biStream = BiStream.of("one", 1, "two", 2);
ImmutableListMultimap<String, Integer> map =
biStream.collect(ImmutableListMultimap::toImmutableListMultimap);
biStream.collect(new BiCollector<String, Integer, ImmutableListMultimap<String, Integer>>() {
@Override
public <E> Collector<E, ?, ImmutableListMultimap<String, Integer>> bisecting(Function<E, String> toKey, Function<E, Integer> toValue) {
return ImmutableListMultimap.toImmutableListMultimap(toKey,toValue);
}
});
assertThat(map).containsExactly("one", 1, "two", 2);
}

@Test public void how_to_collect_to_immutableRangeMap() {
BiStream<Range<Integer>, String> biStream =
BiStream.of(Range.closed(10, 19), "ten", Range.closed(20, 29), "twenty");
ImmutableRangeMap<Integer, String> map =
biStream.collect(ImmutableRangeMap::toImmutableRangeMap);
biStream.collect(new BiCollector<Range<Integer>, String, ImmutableRangeMap<Integer, String>>() {
@Override
public <E> Collector<E, ?, ImmutableRangeMap<Integer, String>> bisecting(Function<E, Range<Integer>> toKey, Function<E, String> toValue) {
return ImmutableRangeMap.toImmutableRangeMap(toKey,toValue);
}
});
assertThat(map.get(12)).isEqualTo("ten");
}
}
Loading

0 comments on commit 3fdff10

Please sign in to comment.