package org.simantics.graph.diff; import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.procedure.TIntObjectProcedure; import gnu.trove.set.hash.THashSet; import java.util.ArrayList; import java.util.Collection; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.graph.matching.GraphMatching; import org.simantics.graph.representation.External; import org.simantics.graph.representation.Identity; import org.simantics.graph.representation.IdentityDefinition; import org.simantics.graph.representation.Internal; import org.simantics.graph.representation.Optional; import org.simantics.graph.representation.Root; import org.simantics.graph.representation.TransferableGraph1; import org.simantics.graph.representation.Value; public class Diff extends GraphMatching { TransferableGraph1 a; TransferableGraph1 b; public Diff(TransferableGraph1 a, TransferableGraph1 b) { super(a, b); this.a = a; this.b = b; } static THashSet createStatementSet(int[] statements) { THashSet result = new THashSet(); for(int i=0;i aStatements = createStatementSet(a.statements); ArrayList bStatements = new ArrayList(); int[] statements = b.statements; for(int i=0;i aIdentities = new TIntObjectHashMap(); ArrayList bIdentities = new ArrayList(); for(Identity id : a.identities) aIdentities.put(id.resource, id.definition); for(Identity id : b.identities) { int a = bToA[id.resource]; IdentityDefinition def = aIdentities.get(a); if(def != null && identityDefinitionEquals(bToA, def, id.definition)) aIdentities.remove(a); else bIdentities.add(id); } // Value diff TIntObjectHashMap aValues = new TIntObjectHashMap(); ArrayList bValues = new ArrayList(); for(Value value : a.values) aValues.put(value.resource, value.value); for(Value value : b.values) { int a = bToA[value.resource]; // a may be -1 Variant aValue = aValues.get(a); if(aValue != null && aValue.equals(value.value)) aValues.remove(a); else bValues.add(value); } // Create result TransferableGraphDelta1 result = new TransferableGraphDelta1( aToB, new TransferableGraph1( a.resourceCount, toIdentityArray(aIdentities), toStatementArray(aStatements), toValueArray(aValues) ), new TransferableGraph1( b.resourceCount, bIdentities.toArray(new Identity[bIdentities.size()]), toStatementArray(bStatements), bValues.toArray(new Value[bValues.size()]) ) ); if(GraphMatching.TIMING) { long end = System.nanoTime(); System.out.println("Diffing: " + (end-begin)*1e-6 + "ms"); } return result; } private static boolean identityDefinitionEquals(int[] bToA, IdentityDefinition a, IdentityDefinition b) { if(a instanceof Root) return b instanceof Root && ((Root)a).name.equals(((Root)b).name); if(b instanceof Root) return false; int aParent, bParent; String aName, bName; if(b instanceof External) { External def = (External)b; bParent = def.parent; bName = def.name; } else if(b instanceof Internal) { Internal def = (Internal)b; bParent = def.parent; bName = def.name; } else if(b instanceof Optional) { Optional def = (Optional)b; bParent = def.parent; bName = def.name; } else return false; bParent = bToA[bParent]; if(bParent < 0) return false; if(a instanceof External) { External def = (External)a; aParent = def.parent; aName = def.name; } else if(a instanceof Internal) { Internal def = (Internal)a; aParent = def.parent; aName = def.name; } else if(a instanceof Optional) { Optional def = (Optional)a; aParent = def.parent; aName = def.name; } else return false; return aParent == bParent && aName.equals(bName); } static int[] toStatementArray(Collection statements) { int[] result = new int[4*statements.size()]; int i=0; for(Statement statement : statements) { result[i++] = statement.subject; result[i++] = statement.predicate; result[i++] = statement.inverse; result[i++] = statement.object; } return result; } static Value[] toValueArray(TIntObjectHashMap values) { final Value[] result = new Value[values.size()]; values.forEachEntry(new TIntObjectProcedure() { int i=0; @Override public boolean execute(int a, Variant b) { result[i++] = new Value(a, b); return true; } }); return result; } static Identity[] toIdentityArray(TIntObjectHashMap identities) { final Identity[] result = new Identity[identities.size()]; identities.forEachEntry(new TIntObjectProcedure() { int i=0; @Override public boolean execute(int a, IdentityDefinition b) { result[i++] = new Identity(a, b); return true; } }); return result; } }