package org.alicep.collect;

import static java.util.stream.Collectors.toList;
import static org.alicep.collect.ItemFactory.longs;
import static org.alicep.collect.ItemFactory.strings;
import static org.alicep.collect.LongStreams.longs;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;

import org.alicep.collect.benchmark.BenchmarkRunner;
import org.alicep.collect.benchmark.BenchmarkRunner.Benchmark;
import org.alicep.collect.benchmark.BenchmarkRunner.Configuration;
import org.alicep.collect.benchmark.BenchmarkRunner.InterferenceWarning;
import org.junit.runner.RunWith;

import com.google.common.collect.ImmutableList;

@RunWith(BenchmarkRunner.class)
public class BigSetPerformanceTests<T> {

  static class Config<T> {
    private final Supplier<Set<T>> setFactory;
    private final ItemFactory<T> itemFactory;

    public Config(
        Supplier<Set<T>> setFactory,
        ItemFactory<T> itemFactory) {
      this.setFactory = setFactory;
      this.itemFactory = itemFactory;
    }

    @Override
    public String toString() {
      String mapType = setFactory.get().getClass().getSimpleName();
      String itemType = itemFactory.createItem(0).getClass().getSimpleName();
      return mapType + "<" + itemType + ">";
    }
  }

  @Configuration
  public static final ImmutableList<Config<?>> CONFIGURATIONS = ImmutableList.of(
      new Config<>(HashSet::new, longs),
      new Config<>(LinkedHashSet::new, longs),
      new Config<>(ArraySet::new, longs),
      new Config<>(HashSet::new, strings),
      new Config<>(LinkedHashSet::new, strings),
      new Config<>(ArraySet::new, strings));

  private final Supplier<Set<T>> setFactory;
  private final ItemFactory<T> itemFactory;
  private Set<T> bigSet;
  private final List<T> elements;

  int i = 0;

  public BigSetPerformanceTests(Config<T> config) {
    setFactory = config.setFactory;
    itemFactory = config.itemFactory;

    elements = longs(0, 1_000_000).mapToObj(itemFactory::createItem).collect(toList());
    bigSet = setFactory.get();
    elements.forEach(bigSet::add);
  }

  @Benchmark("Create a 1M-element map")
  public void create() {
    bigSet = null;
    Set<T> set = setFactory.get();
    elements.forEach(set::add);
  }

  @Benchmark("Iterate through a 1M-element map")
  @InterferenceWarning
  public void iterate() {
    bigSet.forEach(e -> assertNotNull(e));
  }

  @Benchmark("Hit in a 1M-element map")
  public void hit() {
    assertTrue(bigSet.contains(itemFactory.createItem(i)));
    if (++i == 1_000_000) i = 0;
  }

  @Benchmark("Miss in a 1M-element map")
  public void miss() {
    assertFalse(bigSet.contains(itemFactory.createItem(i++ + 1_000_000)));
  }
}

@@ -26,58 +26,8 @@
 t;%0A%0A
-import static java.util.stream.Collectors.toList;%0A
 impo
@@ -66,32 +66,32 @@
 mFactory.longs;%0A
+
 import static or
@@ -132,60 +132,8 @@
 gs;%0A
-import static org.alicep.collect.LongStreams.longs;%0A
 impo
@@ -280,32 +280,32 @@
 a.util.HashSet;%0A
+
 import java.util
@@ -324,31 +324,8 @@
 et;%0A
-import java.util.List;%0A
 impo
@@ -1815,16 +1815,50 @@
  bigSet;
+%0A%0A  @SuppressWarnings(%22unchecked%22)
 %0A  priva
@@ -1870,15 +1870,11 @@
 nal 
-List%3CT%3E
+T%5B%5D
  ele
@@ -1878,16 +1878,46 @@
 elements
+ = (T%5B%5D) new Object%5B1_000_000%5D
 ;%0A%0A  int
@@ -2060,48 +2060,72 @@
     
-elements = longs(0, 1_000_000).mapToObj(
+for (int i = 0; i %3C elements.length; ++i) %7B%0A      elements%5Bi%5D = 
 item
@@ -2131,18 +2131,17 @@
 mFactory
-::
+.
 createIt
@@ -2146,28 +2146,18 @@
 Item
-).collect(toList());
+(i);%0A    %7D
 %0A   
@@ -2192,38 +2192,63 @@
     
-elements.forEach(
+for (T item : elements) %7B%0A      
 bigSet
-::add);
+.add(item);%0A    %7D
 %0A  %7D
@@ -2376,35 +2376,60 @@
     
-elements.forEach(set::add);
+for (T item : elements) %7B%0A      set.add(item);%0A    %7D
 %0A  %7D
@@ -2673,33 +2673,19 @@
 ins(
-itemFactory.createItem(i)
+elements%5Bi%5D
 ));%0A
@@ -2699,25 +2699,31 @@
 (++i == 
-1_000_000
+elements.length
 ) i = 0;
@@ -2853,25 +2853,31 @@
 m(i++ + 
-1_000_000
+elements.length
 )));%0A  %7D

Use an array rather than a list in BigSetPerformanceTests