@Test
 public void newSet() {
   for (int i = 1; i <= 5; i++) {
     Interval interval = Interval.oneTo(i);
     Verify.assertEqualsAndHashCode(UnifiedSet.newSet(interval), Sets.immutable.ofAll(interval));
   }
 }
 @Override
 @Test
 public void reject() {
   Verify.assertContainsAll(this.newWith(1, 2, 3, 4).reject(Predicates.lessThan(3)), 3, 4);
   Verify.assertContainsAll(
       this.newWith(1, 2, 3, 4).reject(Predicates.lessThan(3), UnifiedSet.newSet()), 3, 4);
 }
 @Test
 public void rejectWith() {
   Verify.assertEmpty(SingletonListTest.newWith(1).rejectWith(Predicates2.<Integer>lessThan(), 3));
   Verify.assertContainsAll(
       SingletonListTest.newWith(1)
           .rejectWith(Predicates2.<Integer>greaterThan(), 3, UnifiedSet.<Integer>newSet()),
       1);
 }
 @Test
 public void flatCollect() {
   Function<Integer, MutableSet<String>> function =
       object -> UnifiedSet.newSetWith(object.toString());
   Verify.assertListsEqual(
       FastList.newListWith("1"), SingletonListTest.newWith(1).flatCollect(function));
   Verify.assertSetsEqual(
       UnifiedSet.newSetWith("1"),
       SingletonListTest.newWith(1).flatCollect(function, UnifiedSet.<String>newSet()));
 }
 @Test
 public void fixedSize() {
   FixedSizeSetFactory setFactory = Sets.fixedSize;
   Assert.assertEquals(UnifiedSet.newSet(), setFactory.of());
   Verify.assertInstanceOf(FixedSizeSet.class, setFactory.of());
   Assert.assertEquals(UnifiedSet.newSetWith(1), setFactory.of(1));
   Verify.assertInstanceOf(FixedSizeSet.class, setFactory.of(1));
   Assert.assertEquals(UnifiedSet.newSetWith(1, 2), setFactory.of(1, 2));
   Verify.assertInstanceOf(FixedSizeSet.class, setFactory.of(1, 2));
   Assert.assertEquals(UnifiedSet.newSetWith(1, 2, 3), setFactory.of(1, 2, 3));
   Verify.assertInstanceOf(FixedSizeSet.class, setFactory.of(1, 2, 3));
   Assert.assertEquals(UnifiedSet.newSetWith(1, 2, 3, 4), setFactory.of(1, 2, 3, 4));
   Verify.assertInstanceOf(FixedSizeSet.class, setFactory.of(1, 2, 3, 4));
 }
 @Test
 public void powerSet() {
   MutableSet<Integer> set = UnifiedSet.newSetWith(1, 2, 3);
   MutableSet<MutableSet<Integer>> expectedPowerSet =
       UnifiedSet.<MutableSet<Integer>>newSetWith(
           UnifiedSet.<Integer>newSet(),
           UnifiedSet.newSetWith(1),
           UnifiedSet.newSetWith(2),
           UnifiedSet.newSetWith(3),
           UnifiedSet.newSetWith(1, 2),
           UnifiedSet.newSetWith(1, 3),
           UnifiedSet.newSetWith(2, 3),
           UnifiedSet.newSetWith(1, 2, 3));
   Assert.assertEquals(expectedPowerSet, Sets.powerSet(set));
 }
 @Test
 public void mutables() {
   MutableSetFactory setFactory = Sets.mutable;
   Assert.assertEquals(UnifiedSet.newSet(), setFactory.of());
   Verify.assertInstanceOf(MutableSet.class, setFactory.of());
   Assert.assertEquals(UnifiedSet.newSetWith(1), setFactory.of(1));
   Verify.assertInstanceOf(MutableSet.class, setFactory.of(1));
   Assert.assertEquals(UnifiedSet.newSetWith(1, 2), setFactory.of(1, 2));
   Verify.assertInstanceOf(MutableSet.class, setFactory.of(1, 2));
   Assert.assertEquals(UnifiedSet.newSetWith(1, 2, 3), setFactory.of(1, 2, 3));
   Verify.assertInstanceOf(MutableSet.class, setFactory.of(1, 2, 3));
   Assert.assertEquals(UnifiedSet.newSetWith(1, 2, 3, 4), setFactory.of(1, 2, 3, 4));
   Verify.assertInstanceOf(MutableSet.class, setFactory.of(1, 2, 3, 4));
   Assert.assertEquals(UnifiedSet.newSetWith(1, 2, 3, 4, 5), setFactory.of(1, 2, 3, 4, 5));
   Verify.assertInstanceOf(MutableSet.class, setFactory.of(1, 2, 3, 4, 5));
   Assert.assertEquals(
       UnifiedSet.newSetWith(1, 2, 3, 4, 5),
       setFactory.ofAll(UnifiedSet.newSetWith(1, 2, 3, 4, 5)));
   Verify.assertInstanceOf(
       MutableSet.class, setFactory.ofAll(UnifiedSet.newSetWith(1, 2, 3, 4, 5)));
 }
@State(Scope.Thread)
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
public class AnagramSetTest extends AbstractJMHTestRunner {
  private static final int SIZE = 1_000_000;
  private static final int BATCH_SIZE = 10_000;

  private static final int SIZE_THRESHOLD = 10;
  private final UnifiedSet<String> ecWords =
      UnifiedSet.newSet(
          FastList.newWithNValues(SIZE, () -> RandomStringUtils.randomAlphabetic(5).toUpperCase()));
  private final Set<String> jdkWords = new HashSet<>(this.ecWords);

  private ExecutorService executorService;

  @Setup
  public void setUp() {
    this.executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
  }

  @TearDown
  public void tearDown() throws InterruptedException {
    this.executorService.shutdownNow();
    this.executorService.awaitTermination(1L, TimeUnit.SECONDS);
  }

  @Benchmark
  public void serial_eager_scala() {
    AnagramSetScalaTest.serial_eager_scala();
  }

  @Benchmark
  public void serial_lazy_scala() {
    AnagramSetScalaTest.serial_lazy_scala();
  }

  @Benchmark
  public void parallel_lazy_scala() {
    AnagramSetScalaTest.parallel_lazy_scala();
  }

  @Benchmark
  public void serial_eager_ec() {
    MutableSetMultimap<Alphagram, String> groupBy = this.ecWords.groupBy(Alphagram::new);
    groupBy
        .multiValuesView()
        .select(iterable -> iterable.size() >= SIZE_THRESHOLD)
        .toSortedList(Comparators.<RichIterable<String>>byIntFunction(RichIterable::size))
        .asReversed()
        .collect(iterable -> iterable.size() + ": " + iterable)
        .forEach(Procedures.cast(e -> Assert.assertFalse(e.isEmpty())));
  }

  @Benchmark
  public void parallel_eager_ec() {
    MutableMultimap<Alphagram, String> groupBy =
        ParallelIterate.groupBy(this.ecWords, Alphagram::new);
    CompositeFastList<RichIterable<String>> select =
        ParallelIterate.select(
            groupBy.multiValuesView(),
            iterable -> iterable.size() >= SIZE_THRESHOLD,
            new CompositeFastList<>(),
            false);
    Collection<String> collect =
        ParallelIterate.collect(
            select
                .toSortedList(Comparators.<RichIterable<String>>byIntFunction(RichIterable::size))
                .asReversed(),
            iterable -> iterable.size() + ": " + iterable);
    ParallelIterate.forEach(collect, Procedures.cast(e -> Assert.assertFalse(e.isEmpty())));
  }

  @Benchmark
  public void parallel_lazy_ec() {
    UnsortedSetMultimap<Alphagram, String> multimap =
        this.ecWords.asParallel(this.executorService, BATCH_SIZE).groupBy(Alphagram::new);
    FastList<Pair<Integer, String>> pairs =
        (FastList<Pair<Integer, String>>)
            FastList.newList(multimap.multiValuesView())
                .asParallel(this.executorService, BATCH_SIZE)
                .select(iterable -> iterable.size() >= SIZE_THRESHOLD)
                .collect(
                    iterable -> Tuples.pair(iterable.size(), iterable.size() + ": " + iterable))
                .toSortedList((pair1, pair2) -> Integer.compare(pair2.getOne(), pair1.getOne()));
    pairs
        .asParallel(this.executorService, BATCH_SIZE)
        .collect(Pair::getTwo)
        .forEach(Procedures.cast(e -> Assert.assertFalse(e.isEmpty())));
  }

  @Benchmark
  public void parallel_eager_forkjoin_ec() {
    MutableMultimap<Alphagram, String> groupBy = FJIterate.groupBy(this.ecWords, Alphagram::new);
    CompositeFastList<RichIterable<String>> select =
        FJIterate.select(
            groupBy.multiValuesView(),
            iterable -> iterable.size() >= SIZE_THRESHOLD,
            new CompositeFastList<>(),
            false);
    Collection<String> collect =
        FJIterate.collect(
            select
                .toSortedList(Comparators.<RichIterable<String>>byIntFunction(RichIterable::size))
                .asReversed(),
            iterable -> iterable.size() + ": " + iterable);
    FJIterate.forEach(collect, Procedures.cast(e -> Assert.assertFalse(e.isEmpty())));
  }

  @Benchmark
  public void serial_lazy_jdk() {
    Map<Alphagram, Set<String>> groupBy =
        this.jdkWords
            .stream()
            .collect(Collectors.groupingBy(Alphagram::new, Collectors.<String>toSet()));
    groupBy
        .entrySet()
        .stream()
        .map(Map.Entry::getValue)
        .filter(list -> list.size() >= SIZE_THRESHOLD)
        .sorted(Comparator.<Set<String>>comparingInt(Set::size).reversed())
        .map(list -> list.size() + ": " + list)
        .forEach(e -> Assert.assertFalse(e.isEmpty()));
  }

  @Benchmark
  public void serial_lazy_streams_ec() {
    Map<Alphagram, Set<String>> groupBy =
        this.ecWords
            .stream()
            .collect(Collectors.groupingBy(Alphagram::new, Collectors.<String>toSet()));
    groupBy
        .entrySet()
        .stream()
        .map(Map.Entry::getValue)
        .filter(list -> list.size() >= SIZE_THRESHOLD)
        .sorted(Comparator.<Set<String>>comparingInt(Set::size).reversed())
        .map(list -> list.size() + ": " + list)
        .forEach(e -> Assert.assertFalse(e.isEmpty()));
  }

  @Benchmark
  public void parallel_lazy_jdk() {
    Map<Alphagram, Set<String>> groupBy =
        this.jdkWords
            .parallelStream()
            .collect(Collectors.groupingBy(Alphagram::new, Collectors.<String>toSet()));
    groupBy
        .entrySet()
        .parallelStream()
        .map(Map.Entry::getValue)
        .filter(list -> list.size() >= SIZE_THRESHOLD)
        .sorted(Comparator.<Set<String>>comparingInt(Set::size).reversed())
        .parallel()
        .map(list -> list.size() + ": " + list)
        .forEach(e -> Assert.assertFalse(e.isEmpty()));
  }

  @Benchmark
  public void parallel_lazy_streams_ec() {
    Map<Alphagram, Set<String>> groupBy =
        this.ecWords
            .parallelStream()
            .collect(Collectors.groupingBy(Alphagram::new, Collectors.<String>toSet()));
    groupBy
        .entrySet()
        .parallelStream()
        .map(Map.Entry::getValue)
        .filter(list -> list.size() >= SIZE_THRESHOLD)
        .sorted(Comparator.<Set<String>>comparingInt(Set::size).reversed())
        .parallel()
        .map(list -> list.size() + ": " + list)
        .forEach(e -> Assert.assertFalse(e.isEmpty()));
  }

  private static final class Alphagram {
    private final char[] key;

    private Alphagram(String string) {
      this.key = string.toCharArray();
      Arrays.sort(this.key);
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || this.getClass() != o.getClass()) {
        return false;
      }
      Alphagram alphagram = (Alphagram) o;
      return Arrays.equals(this.key, alphagram.key);
    }

    @Override
    public int hashCode() {
      return Arrays.hashCode(this.key);
    }

    @Override
    public String toString() {
      return new String(this.key);
    }
  }
}
 @Test
 public void cartesianProduct_empty() {
   Assert.assertEquals(
       Bags.mutable.of(),
       HashBag.newBag(Sets.cartesianProduct(UnifiedSet.newSetWith(1, 2), UnifiedSet.newSet())));
 }
 @Test
 public void powerSet_empty() {
   Assert.assertEquals(
       UnifiedSet.newSetWith(UnifiedSet.newSet()), Sets.powerSet(UnifiedSet.newSet()));
 }
 @Test
 public void collect() {
   Verify.assertContainsAll(SingletonListTest.newWith(1).collect(String::valueOf), "1");
   Verify.assertContainsAll(
       SingletonListTest.newWith(1).collect(String::valueOf, UnifiedSet.<String>newSet()), "1");
 }