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 SmallSetPerformanceTests<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 setType = setFactory.get().getClass().getSimpleName();
      String itemType = itemFactory.createItem(0).getClass().getSimpleName();
      return setType + "<" + 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 final Set<T> littleSet;
  private final List<T> elements;

  int i = 0;

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

    elements = longs(0, 6).mapToObj(itemFactory::createItem).collect(toList());
    littleSet = setFactory.get();
    for (int i = 0; i < 6; i++) {
      littleSet.add(elements.get(i));
    }
  }

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

  @Benchmark("Iterate through a 6-element set")
  @InterferenceWarning
  public void iterate() {
    littleSet.forEach(e -> assertNotNull(e));
  }

  @Benchmark("Hit in a 6-element set")
  public void hit() {
    assertTrue(littleSet.contains(itemFactory.createItem(i)));
    if (++i == 6) i = 0;
  }

  @Benchmark("Miss in a 6-element set")
  public void miss() {
    assertFalse(littleSet.contains(itemFactory.createItem(i++ + 6)));
  }
}

@@ -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
@@ -1769,102 +1769,109 @@
 nal 
-ItemFactory
+Set
 %3CT%3E 
+l
 it
-emFactory;%0A  private final Set%3CT%3E littleSet;%0A  private final List%3CT%3E elements
+tleSet;%0A%0A  @SuppressWarnings(%22unchecked%22)%0A  private final T%5B%5D items = (T%5B%5D) new Object%5B500%5D
 ;%0A%0A 
@@ -1977,83 +1977,69 @@
 ry;%0A
+%0A
     
-itemFactory = config.itemFactory;%0A%0A    elements = longs(0, 6).mapToObj(
+for (int i = 0; i %3C 500; ++i) %7B%0A      items%5Bi%5D = config.
 item
@@ -2045,18 +2045,17 @@
 mFactory
-::
+.
 createIt
@@ -2060,28 +2060,18 @@
 Item
-).collect(toList());
+(i);%0A    %7D
 %0A   
@@ -2159,23 +2159,16 @@
 add(
-elements.get(i)
+items%5Bi%5D
 );%0A 
@@ -2284,35 +2284,68 @@
     
-elements.forEach(set::add);
+for (int i = 0; i %3C 6; ++i) %7B%0A      set.add(items%5Bi%5D);%0A    %7D
 %0A  %7D
@@ -2416,16 +2416,79 @@
 eWarning
+  // Hitting java.lang.Iterable.forEach, which cannot be cloned
 %0A  publi
@@ -2656,37 +2656,20 @@
 ins(item
-Factory.createItem(i)
+s%5Bi%5D
 ));%0A    
@@ -2800,38 +2800,73 @@
 item
-Factory.createItem(i
+s%5Bi + 6%5D));%0A    if (
 ++
+i
  + 6
-)));
+ == items.length) %7B%0A      i = 0;%0A    %7D
 %0A  %7D

Make SmallSetPerformanceTests more reliable