public static <E> ImmutableList<E> list() {
  return ImmutableList.of();
} public static <K, V> ImmutableMap<K, V> map() {
  return ImmutableMap.of();
} public static Pattern first(String str) {
  if (str.length() == 1) {
    return first(str.charAt(0));
  }
  return new Pattern() {
    @Override Match match(String input, int fromIndex) {
      int index = input.indexOf(str, fromIndex);
      return index >= 0 ? new Match(input, index, str.length()) : null;
    }

    @Override public String toString() {
      return "first('" + str + "')";
    }
  };
} public static <K, V, G, R> BiCollector<K, V, BiStream<G, R>> groupingBy(
    BiFunction<? super K, ? super V, ? extends G> classifier,
    BiCollector<? super K, ? super V, R> groupCollector) {
  requireNonNull(classifier);
  requireNonNull(groupCollector);
  return new BiCollector<K, V, BiStream<G, R>>() {
    @Override
    public <E> Collector<E, ?, BiStream<G, R>> splitting(
        Function<E, K> toKey, Function<E, V> toValue) {
      return BiStream.groupingBy(
          e -> classifier.apply(toKey.apply(e), toValue.apply(e)),
          groupCollector.splitting(toKey::apply, toValue::apply));
    }
  };
} public static <T> BiStream<T, T> biStream(Collection<T> elements) {
  return from(elements, identity(), identity());
} public static <T, B> Collector<T, ?, ImmutableMultiset<B>> countingBy(
    Function<? super T, ? extends B> bucketer) {
  return Collectors.mapping(requireNonNull(bucketer), ImmutableMultiset.toImmutableMultiset());
} public static <K, T, V>
    BiCollector<K, T, ImmutableListMultimap<K, V>> flatteningToImmutableListMultimap(
        Function<? super T, ? extends Stream<? extends V>> flattener) {
  return mappingValues(flattener, ImmutableListMultimap::flatteningToImmutableListMultimap);
} public static <K, T, V>
    BiCollector<K, T, ImmutableSetMultimap<K, V>> flatteningToImmutableSetMultimap(
        Function<? super T, ? extends Stream<? extends V>> flattener) {
  return mappingValues(flattener, ImmutableSetMultimap::flatteningToImmutableSetMultimap);
} public static <K, V> Collector<V, ?, ImmutableMap<K, V>> indexingBy(
    Function<? super V, ? extends K> indexingFunction) {
  return ImmutableMap.toImmutableMap(indexingFunction, identity());
} public static <T> Collector<T, ?, Both<ImmutableList<T>, ImmutableList<T>>> partitioningBy(
    Predicate<? super T> predicate) {
  return MoreCollectors.partitioningBy(predicate, toImmutableList());
} public static <K, V> BiCollector<K, V, ImmutableBiMap<K, V>> toImmutableBiMap() {
  return ImmutableBiMap::toImmutableBiMap;
} public static <K, V> BiCollector<K, V, ImmutableListMultimap<K, V>> toImmutableListMultimap() {
  return ImmutableListMultimap::toImmutableListMultimap;
} public static <K, V> BiCollector<K, V, ImmutableMap<K, V>> toImmutableMap() {
  return ImmutableMap::toImmutableMap;
} public static <K, V> BiCollector<K, V, ImmutableMultiset<K>> toImmutableMultiset(
    ToIntFunction<? super V> countFunction) {
  requireNonNull(countFunction);
  return new BiCollector<K, V, ImmutableMultiset<K>>() {
    @Override
    public <E> Collector<E, ?, ImmutableMultiset<K>> splitting(
        Function<E, K> toKey, Function<E, V> toValue) {
      return ImmutableMultiset.toImmutableMultiset(
          toKey, input -> countFunction.applyAsInt(toValue.apply(input)));
    }
  };
} public static <K, V> BiCollector<K, V, ImmutableSetMultimap<K, V>> toImmutableSetMultimap() {
  return ImmutableSetMultimap::toImmutableSetMultimap;
} public static <K, V> BiCollector<K, V, ImmutableSortedMap<K, V>> toImmutableSortedMap(
    Comparator<? super K> comparator, BinaryOperator<V> valueMerger) {
  requireNonNull(comparator);
  requireNonNull(valueMerger);
  return new BiCollector<K, V, ImmutableSortedMap<K, V>>() {
    @Override
    public <E> Collector<E, ?, ImmutableSortedMap<K, V>> splitting(
        Function<E, K> toKey, Function<E, V> toValue) {
      return ImmutableSortedMap.toImmutableSortedMap(comparator, toKey, toValue, valueMerger);
    }
  };
} public static <R, C, V>
    BiCollector<R, BiStream<? extends C, ? extends V>, ImmutableTable<R, C, V>>
        toImmutableTable() {
  return BiCollectors.flatMapping(
      (R r, BiStream<? extends C, ? extends V> columns) ->
          columns.mapToObj((c, v) -> Tables.immutableCell(r, c, v)),
      Collector.of(
          ImmutableTable.Builder<R, C, V>::new,
          ImmutableTable.Builder::put,
          (builder, that) -> builder.putAll(that.build()),
          ImmutableTable.Builder::build));
} public static <K, V, M extends Multimap<K, V>> BiCollector<K, V, M> toMultimap(
    Supplier<M> multimapSupplier) {
  requireNonNull(multimapSupplier);
  return new BiCollector<K, V, M>() {
    @Override
    public <E> Collector<E, ?, M> splitting(Function<E, K> toKey, Function<E, V> toValue) {
      return Multimaps.toMultimap(toKey, toValue, multimapSupplier);
    }
  };
} @FunctionalInterface
public interface Both<A, B> {
  /**
   * Returns an instance with both {@code a} and {@code b}.
   *
   * @since 5.8
   */
  public static <A, B> Both<A, B> of(A a, B b) {
    return new BiOptional.Present<>(a, b);
  }

  /**
   * Applies the {@code mapper} function with this pair of two things as arguments.
   *
   * @throws NullPointerException if {@code mapper} is null
   */
  <T> T andThen(BiFunction<? super A, ? super B, T> mapper);

  /**
   * If the pair {@link #matches matches()} {@code condition}, returns a {@link BiOptional} containing
   * the pair, or else returns empty.
   *
   * @throws NullPointerException if {@code condition} is null, or if {@code condition} matches but
   *     either value in this pair is null
   */
  default BiOptional<A, B> filter(BiPredicate<? super A, ? super B> condition) {
    requireNonNull(condition);
    return andThen((a, b) -> condition.test(a, b) ? BiOptional.of(a, b) : BiOptional.empty());
  }

  /**
   * Returns true if the pair matches {@code condition}.
   *
   * @throws NullPointerException if {@code condition} is null
   */
  default boolean matches(BiPredicate<? super A, ? super B> condition) {
    return andThen(condition::test);
  }

  /**
   * Invokes {@code consumer} with this pair and returns this object as is.
   *
   * @throws NullPointerException if {@code consumer} is null
   */
  default Both<A, B> peek(BiConsumer<? super A, ? super B> consumer) {
    requireNonNull(consumer);
    return andThen((a, b) -> {
      consumer.accept(a, b);
      return this;
    });
  }
}
import static com.google.common.truth.Truth.assertThat;
import static com.google.mu.collect.Immutables.list;
import static com.google.mu.collect.Immutables.map;
import static com.google.mu.util.Substring.first;
import static com.google.mu.util.stream.BiCollectors.groupingBy;
import static com.google.mu.util.stream.BiStream.biStream;
import static com.google.mu.util.stream.GuavaCollectors.countingBy;
import static com.google.mu.util.stream.GuavaCollectors.flatteningToImmutableListMultimap;
import static com.google.mu.util.stream.GuavaCollectors.flatteningToImmutableSetMultimap;
import static com.google.mu.util.stream.GuavaCollectors.indexingBy;
import static com.google.mu.util.stream.GuavaCollectors.partitioningBy;
import static com.google.mu.util.stream.GuavaCollectors.toImmutableBiMap;
import static com.google.mu.util.stream.GuavaCollectors.toImmutableListMultimap;
import static com.google.mu.util.stream.GuavaCollectors.toImmutableMap;
import static com.google.mu.util.stream.GuavaCollectors.toImmutableMultiset;
import static com.google.mu.util.stream.GuavaCollectors.toImmutableSetMultimap;
import static com.google.mu.util.stream.GuavaCollectors.toImmutableSortedMap;
import static com.google.mu.util.stream.GuavaCollectors.toImmutableTable;
import static com.google.mu.util.stream.GuavaCollectors.toMultimap;
import static java.util.Comparator.naturalOrder;
import static java.util.stream.Collectors.summingInt;
import static java.util.stream.Collectors.toList;
import java.util.List;
import java.util.stream.Stream;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.TreeMultimap;
import com.google.common.testing.NullPointerTester;
import com.google.mu.util.Both;
/*****************************************************************************
 * ------------------------------------------------------------------------- *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
package com.google.mu.util.stream;





@RunWith(JUnit4.class)
public class GuavaCollectorsTest {
  @Test public void testToImmutableMap_valuesCollected() {
    ImmutableList<Town> towns =
        list(new Town("WA", 100), new Town("WA", 50), new Town("IL", 200));
    assertThat(
            biStream(Town::getState, towns)
                .collect(toImmutableMap(summingInt(Town::getPopulation))))
        .containsExactly("WA", 150, "IL", 200)
        .inOrder();
  }

  @Test public void testToImmutableMap_keyEncounterOrderRetainedThroughValueCollector() {
    ImmutableList<Town> towns =
        list(
            new Town("WA", 1),
            new Town("FL", 2),
            new Town("WA", 3),
            new Town("IL", 4),
            new Town("AZ", 5),
            new Town("OH", 6),
            new Town("IN", 7),
            new Town("CA", 8),
            new Town("CA", 9));
    assertThat(
            biStream(Town::getState, towns)
                .collect(toImmutableMap(summingInt(Town::getPopulation))))
        .containsExactly("WA", 4, "FL", 2, "IL", 4, "AZ", 5, "OH", 6, "IN", 7, "CA", 17)
        .inOrder();
  }

  @Test public void testToImmutableMap_empty() {
    ImmutableList<Town> towns = list();
    assertThat(
            biStream(Town::getState, towns)
                .collect(toImmutableMap(summingInt(Town::getPopulation))))
        .isEmpty();
  }

  @Test public void testToImmutableSortedMap() {
    assertThat(BiStream.of(2, "two", 1, "one").collect(GuavaCollectors.toImmutableSortedMap(naturalOrder())))
        .containsExactly(1, "one", 2, "two")
        .inOrder();
  }

  @Test public void testToImmutableSortedMap_withDuplicateKeys() {
    assertThat(
            BiStream.of(2, "two", 1, "one", 1, "uno")
                .collect(toImmutableSortedMap(naturalOrder(), (a, b) -> b)))
        .containsExactly(1, "uno", 2, "two")
        .inOrder();
  }

  @Test public void testToImmutableMap_covariance() {
    ImmutableMap<Object, String> map = BiStream.of(1, "one").collect(toImmutableMap());
    assertThat(map).containsExactly(1, "one");
  }

  @Test public void testToMultimap_treeMultimap() {
    TreeMultimap<Integer, String> map =
        BiStream.of(2, "b", 1, "a").collect(toMultimap(TreeMultimap::create));
    assertThat(map.keySet()).containsExactly(1, 2).inOrder();
  }

  @Test public void testToImmutableListMultimap_covariance() {
    ImmutableListMultimap<Object, String> map =
        BiStream.of(1, "one", 1, "uno").collect(toImmutableListMultimap());
    assertThat(map).containsExactly(1, "one", 1, "uno");
  }

  @Test public void testToImmutableSetMultimap_covariance() {
    ImmutableSetMultimap<Object, String> map =
        BiStream.of(1, "one", 1, "uno").collect(toImmutableSetMultimap());
    assertThat(map).containsExactly(1, "one", 1, "uno");
  }

  @Test public void testToListMultimap() {
    assertThat(BiStream.of("one", 1, "two", 2).collect(toImmutableListMultimap()))
        .containsExactly("one", 1, "two", 2);
  }

  @Test public void testToSetMultimap() {
    assertThat(BiStream.of("one", 1, "two", 2).collect(toImmutableSetMultimap()))
        .containsExactly("one", 1, "two", 2);
  }

  @Test public void testFlatteningToImmutableListMultimap() {
    ImmutableListMultimap<Object, String> map =
        BiStream.of(1, list("one", "uno"))
            .collect(flatteningToImmutableListMultimap(List::stream));
    assertThat(map).containsExactly(1, "one", 1, "uno");
  }

  @Test public void testFlatteningToImmutableSetMultimap() {
    ImmutableSetMultimap<Object, String> map =
        BiStream.of(1, list("one", "one", "uno"))
            .collect(flatteningToImmutableSetMultimap(List::stream));
    assertThat(map).containsExactly(1, "one", 1, "uno");
  }

  @Test public void testToImmutableMultiset() {
    assertThat(BiStream.of(".", 3, "?", 1).collect(toImmutableMultiset(Integer::intValue)))
        .containsExactly(".", ".", ".", "?")
        .inOrder();
  }

  @Test public void testTwoDimensionalGroupingBy_collectToImmutableTable() {
    ImmutableTable<Character, Character, List<Integer>> table =
        BiStream.of("ab", 1, "bc", 2)
            .collect(groupingBy((s, i) -> s.charAt(0), groupingBy(s -> s.charAt(1), toList())))
            .collect(toImmutableTable());