--- /dev/null
+package org.simantics.scl.runtime.tests;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.LinkedHashSet;\r
+import java.util.List;\r
+import java.util.Random;\r
+\r
+import org.junit.Assert;\r
+import org.junit.Before;\r
+import org.junit.Test;\r
+import org.simantics.scl.runtime.chr.CHRHashIndex;\r
+\r
+import gnu.trove.map.hash.TIntObjectHashMap;\r
+import gnu.trove.set.hash.THashSet;\r
+import gnu.trove.set.hash.TIntHashSet;\r
+\r
+public class TestCHRHashIndex {\r
+ \r
+ Random random;\r
+ Store store;\r
+ Store2 store2;\r
+ THashSet<Fact> aliveFacts = new THashSet<Fact>(); \r
+ \r
+ public static class Store {\r
+ CHRHashIndex bfIndex = new CHRHashIndex() {\r
+ @Override\r
+ protected boolean keyEquals(Object a, Object b) {\r
+ return ((Fact)a).a == ((Fact)b).a;\r
+ }\r
+ @Override\r
+ protected int keyHashCode(Object key) {\r
+ return ((Fact)key).a;\r
+ }\r
+ };\r
+ }\r
+ \r
+ public static class Store2 {\r
+ TIntObjectHashMap<LinkedHashSet<Fact>> bfIndex = new TIntObjectHashMap<LinkedHashSet<Fact>>(); \r
+ }\r
+ \r
+ public static class Fact {\r
+ public int a; // key\r
+ public int b;\r
+ public Fact bfPrev;\r
+ public Fact bfNext;\r
+ \r
+ public Fact(int a, int b) {\r
+ this.a = a;\r
+ this.b = b;\r
+ }\r
+ \r
+ public void add(Store store) {\r
+ bfNext = (Fact)store.bfIndex.addFreshAndReturnOld(this);\r
+ if(bfNext != null)\r
+ bfNext.bfPrev = this;\r
+ }\r
+ \r
+ public void remove(Store store) {\r
+ if(bfPrev == null) {\r
+ if(bfNext == null)\r
+ store.bfIndex.removeKnownToExistKey(this);\r
+ else {\r
+ bfNext.bfPrev = null;\r
+ store.bfIndex.replaceKnownToExistKey(this, bfNext);\r
+ }\r
+ }\r
+ else {\r
+ bfPrev.bfNext = bfNext;\r
+ if(bfNext != null)\r
+ bfNext.bfPrev = bfPrev;\r
+ }\r
+ }\r
+ \r
+ public List<Fact> get(Store store) {\r
+ Object r = store.bfIndex.getEqual(this);\r
+ if(r == null)\r
+ return Collections.emptyList();\r
+ else {\r
+ ArrayList<Fact> result = new ArrayList<Fact>(); \r
+ for(Fact cur=(Fact)r;cur!=null;cur=cur.bfNext)\r
+ result.add(cur);\r
+ Collections.reverse(result);\r
+ return result;\r
+ }\r
+ }\r
+ \r
+ public void add(Store2 store) {\r
+ LinkedHashSet<Fact> set = store.bfIndex.get(a);\r
+ if(set == null) {\r
+ set = new LinkedHashSet<>();\r
+ store.bfIndex.put(a, set);\r
+ }\r
+ set.add(this);\r
+ }\r
+ \r
+ public void remove(Store2 store) {\r
+ store.bfIndex.get(a).remove(this);\r
+ }\r
+ \r
+ public List<Fact> get(Store2 store) {\r
+ LinkedHashSet<Fact> set = store.bfIndex.get(a);\r
+ if(set == null)\r
+ return Collections.emptyList();\r
+ else\r
+ return new ArrayList<Fact>(set);\r
+ }\r
+ }\r
+ \r
+ @Before\r
+ public void init() {\r
+ random = new Random(123L);\r
+ store = new Store();\r
+ store2 = new Store2();\r
+ }\r
+ \r
+ public Fact createFact(int maxA, int maxB) {\r
+ return new Fact(random.nextInt(maxA), random.nextInt(maxB));\r
+ }\r
+ \r
+ public void add(Fact fact) {\r
+ fact.add(store);\r
+ fact.add(store2);\r
+ aliveFacts.add(fact);\r
+ }\r
+ \r
+ public void remove(Fact fact) {\r
+ fact.remove(store);\r
+ fact.remove(store2);\r
+ aliveFacts.remove(fact);\r
+ }\r
+ \r
+ public void checkConsistency() {\r
+ TIntHashSet keys = new TIntHashSet();\r
+ for(Fact fact : aliveFacts)\r
+ keys.add(fact.a);\r
+ Fact temp = new Fact(0, 0);\r
+ for(int a : keys.toArray()) {\r
+ temp.a = a;\r
+ Assert.assertEquals(temp.get(store2), temp.get(store));\r
+ }\r
+ TIntHashSet keys2 = new TIntHashSet();\r
+ for(Fact fact : store.bfIndex.toArray(new Fact[keys.size()]))\r
+ keys2.add(fact.a);\r
+ Assert.assertEquals(keys, keys2);\r
+ }\r
+ \r
+ @Test\r
+ public void testStore() {\r
+ for(int i=0;;++i) {\r
+ System.out.println("Run " + i);\r
+ for(int j=0;j<1000000;++j)\r
+ add(createFact(10000, 1000000));\r
+ checkConsistency();\r
+ ArrayList<Fact> factArray = new ArrayList<Fact>(aliveFacts);\r
+ Collections.shuffle(factArray, random);\r
+ for(Fact fact : factArray.subList(100000, factArray.size()))\r
+ remove(fact);\r
+ checkConsistency();\r
+ }\r
+ }\r
+ \r
+}\r