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