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