]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.databoard/src/org/simantics/databoard/util/DataValueUtil.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / util / DataValueUtil.java
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/util/DataValueUtil.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/util/DataValueUtil.java
new file mode 100644 (file)
index 0000000..4483619
--- /dev/null
@@ -0,0 +1,336 @@
+/*******************************************************************************\r
+ *  Copyright (c) 2010 Association for Decentralized Information Management in\r
+ *  Industry THTH ry.\r
+ *  All rights reserved. This program and the accompanying materials\r
+ *  are made available under the terms of the Eclipse Public License v1.0\r
+ *  which accompanies this distribution, and is available at\r
+ *  http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ *  Contributors:\r
+ *      VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.util;
+
+import java.util.Comparator;\r
+import java.util.HashSet;\r
+import java.util.Iterator;\r
+import java.util.Map.Entry;\r
+import java.util.Set;\r
+import java.util.TreeMap;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.binding.ArrayBinding;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.BooleanBinding;\r
+import org.simantics.databoard.binding.ByteBinding;\r
+import org.simantics.databoard.binding.DoubleBinding;\r
+import org.simantics.databoard.binding.FloatBinding;\r
+import org.simantics.databoard.binding.IntegerBinding;\r
+import org.simantics.databoard.binding.LongBinding;\r
+import org.simantics.databoard.binding.MapBinding;\r
+import org.simantics.databoard.binding.OptionalBinding;\r
+import org.simantics.databoard.binding.RecordBinding;\r
+import org.simantics.databoard.binding.StringBinding;\r
+import org.simantics.databoard.binding.UnionBinding;\r
+import org.simantics.databoard.binding.VariantBinding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.error.RuntimeBindingException;\r
+import org.simantics.databoard.type.ArrayType;\r
+import org.simantics.databoard.type.BooleanType;\r
+import org.simantics.databoard.type.ByteType;\r
+import org.simantics.databoard.type.Datatype;\r
+import org.simantics.databoard.type.DoubleType;\r
+import org.simantics.databoard.type.FloatType;\r
+import org.simantics.databoard.type.IntegerType;\r
+import org.simantics.databoard.type.LongType;\r
+import org.simantics.databoard.type.MapType;\r
+import org.simantics.databoard.type.OptionalType;\r
+import org.simantics.databoard.type.RecordType;\r
+import org.simantics.databoard.type.StringType;\r
+import org.simantics.databoard.type.UnionType;\r
+import org.simantics.databoard.type.VariantType;\r
+
+/**
+ * DataValue handling utilities
+ *
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
+ */
+public class DataValueUtil {
+
+    /**
+     * Compares its two data values for order.  Returns a negative integer,
+     * zero, or a positive integer as the first argument is less than, equal
+     * to, or greater than the second.<p>
+     * 
+     * The implementor must also ensure that the relation is transitive:
+     * <code>((compare(x, y)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</code> implies
+     * <code>compare(x, z)&gt;0</code>.<p>
+     *
+     * Finally, the implementor must ensure that <code>compare(x, y)==0</code>
+     * implies that <code>sgn(compare(x, z))==sgn(compare(y, z))</code> for all
+     * <code>z</code>.<p>
+     * 
+     * DataTypes of b1 and b2 are not equal then data types are compared.
+     *
+     * The comparison function is defined at 
+     * http://dev.simantics.org/index.php/Org.simantics.datatype_Manual#CompareTo_and_Equals
+     *
+     * @param b1 Binding of o1 
+     * @param o1 the first object to be compared.
+     * @param b2 Binding of o2
+     * @param o2 the second object to be compared.
+     * @return a negative integer, zero, or a positive integer as the
+     *                first argument is less than, equal to, or greater than the
+     *        second.
+     * @throws BindingException if object cannot be handled by a binding
+     */
+    public static int compare(Binding b1, Object o1, Binding b2, Object o2) 
+    throws BindingException 
+    {
+       // Not implemented yet
+       if (b1 == b2) {
+               try {
+                       return b1.compare(o1, o2);
+               } catch (RuntimeBindingException e) {
+                       throw e.getCause();
+               }
+       }       
+               
+       Datatype t1 = b1.type();
+       Datatype t2 = b2.type();
+       int typeComparison = Bindings.getBindingUnchecked(Datatype.class).compare(t1, t2);
+       if (typeComparison != 0) return typeComparison;
+       
+               return deepCompare(t1, b1, o1, b2, o2, null);
+    }
+    
+    public static boolean equals(Binding b1, Object o1, Binding b2, Object o2)
+    throws BindingException 
+    {
+       // Not implemented yet
+       if (b1 == b2) {
+               try {
+                       return b1.compare(o1, o2) == 0;
+               } catch (RuntimeBindingException e) {
+                       throw e.getCause();
+               }
+       }       
+               
+       Datatype t1 = b1.type();
+       Datatype t2 = b2.type();
+       if (!t1.equals(t2)) return false;
+               
+               int compare = deepCompare(t1, b1, o1, b2, o2, null);
+               return compare == 0;            
+    }
+    
+    static int deepCompare(Datatype t, Binding b1, Object o1, Binding b2, Object o2, Set<IdentityPair<Object, Object>> compareHistory) 
+    throws BindingException {
+       /*// Not implemented yet
+       if (b1 == b2) {
+               try {
+                       return b1.compare(o1, o2);
+               } catch (RuntimeBindingException e) {
+                       throw e.getCause();
+               }
+       }
+       */
+       assert(b1.type().equals(t));
+       assert(b2.type().equals(t));
+       
+       if (t instanceof ByteType) {
+               byte v1 = ((ByteBinding) b1).getValue_(o1);
+               byte v2 = ((ByteBinding) b2).getValue_(o2);
+               return v1 - v2;         
+       }
+
+       if (t instanceof IntegerType) {
+               int v1 = ((IntegerBinding) b1).getValue_(o1);
+               int v2 = ((IntegerBinding) b2).getValue_(o2);
+               return (v1<v2 ? -1 : (v1==v2 ? 0 : 1));                 
+       }
+
+       if (t instanceof LongType) {
+               long v1 = ((LongBinding) b1).getValue_(o1);
+               long v2 = ((LongBinding) b2).getValue_(o2);
+               return (v1<v2 ? -1 : (v1==v2 ? 0 : 1));
+       }
+
+       if (t instanceof FloatType) {
+               float v1 = ((FloatBinding) b1).getValue_(o1);
+               float v2 = ((FloatBinding) b2).getValue_(o2);
+               return Float.compare(v1, v2);           
+       }
+
+       if (t instanceof DoubleType) {
+               Double v1 = ((DoubleBinding) b1).getValue_(o1);
+               Double v2 = ((DoubleBinding) b2).getValue_(o2);
+               return Double.compare(v1, v2);                          
+       }
+       
+       if (t instanceof BooleanType) {
+               boolean v1 = ((BooleanBinding) b1).getValue_(o1);
+               boolean v2 = ((BooleanBinding) b2).getValue_(o2);
+               return (v2 == v1 ? 0 : (v1 ? 1 : -1));          
+       }
+       
+       if (t instanceof ArrayType) {
+               ArrayBinding a1 = (ArrayBinding) b1;
+               ArrayBinding a2 = (ArrayBinding) b2;
+               // Compare Lengths
+               int l1 = a1.size(o1);
+               int l2 = a2.size(o2);
+               int dif = l1 - l2;
+               if (dif!=0) return dif;
+               // Compare elements
+               Binding c1 = a1.getComponentBinding();
+               Binding c2 = a2.getComponentBinding();                  
+               Datatype ct = c1.type();
+               for (int i=0; i<l1; i++) {
+                       Object e1 = a1.get(o1, i);
+                       Object e2 = a2.get(o2, i);
+                       dif = deepCompare(ct, c1, e1, c2, e2, compareHistory);
+                       if (dif!=0) return dif;
+               }
+               return 0;
+       }
+       
+       if (t instanceof MapType) {
+               MapBinding m1 = (MapBinding) b1;
+               MapBinding m2 = (MapBinding) b2;
+               // Compare sizes
+               int l1 = m1.size(o1);
+               int l2 = m2.size(o2);
+               int dif = l1 - l2;
+               if (dif!=0) return dif;
+               // Compare elements
+               Binding k1 = m1.getKeyBinding();
+               Binding k2 = m2.getKeyBinding();
+               Binding v1 = m1.getValueBinding();
+               Binding v2 = m2.getValueBinding();              
+               TreeMap<Object, Object> e1 = new TreeMap<Object, Object>( k1 );
+               TreeMap<Object, Object> e2 = new TreeMap<Object, Object>( k2 );
+               m1.getAll(o1, e1);
+               m2.getAll(o2, e2);
+               
+               Iterator<Entry<Object, Object>> i1 = e1.entrySet().iterator(); 
+               Iterator<Entry<Object, Object>> i2 = e2.entrySet().iterator(); 
+               while (i1.hasNext()) {
+                       Entry<Object, Object> h1 = i1.next();
+                       Entry<Object, Object> h2 = i2.next();
+                       dif = deepCompare(k1.type(), k1, h1.getKey(), k2, h2.getKey(), compareHistory);
+                       if (dif!=0) return dif;
+                       dif = deepCompare(v1.type(), v1, h1.getValue(), v2, h2.getValue(), compareHistory);
+                       if (dif!=0) return dif;
+                       i1.remove();
+                       i2.remove();
+               }
+               return 0;
+       }
+       
+       if (t instanceof OptionalType) {
+               OptionalBinding ob1 = (OptionalBinding) b1;
+               OptionalBinding ob2 = (OptionalBinding) b2;
+               Boolean h1 = ob1.hasValue(o1);
+               Boolean h2 = ob2.hasValue(o2);
+               if (!h1 && !h2) return 0;
+               int dif = h1.compareTo(h2);
+               if (dif!=0) return dif;
+               
+               Binding c1 = ob1.getComponentBinding();
+               Binding c2 = ob2.getComponentBinding();
+               Object v1 = ob1.getValue(o1);
+               Object v2 = ob2.getValue(o2);
+               Datatype ct = c1.type();
+               return deepCompare(ct, c1, v1, c2, v2, compareHistory);
+       }
+       
+       if (t instanceof StringType) {
+               StringBinding s1 = (StringBinding) b1;
+               StringBinding s2 = (StringBinding) b2;
+               String v1 = s1.getValue(o1);
+               String v2 = s2.getValue(o2);
+               return v1.compareTo(v2);
+       }
+       
+       if (t instanceof UnionType) {
+               UnionBinding u1 = (UnionBinding) b1;
+               UnionBinding u2 = (UnionBinding) b2;
+               Integer t1 = u1.getTag(o1);
+               Integer t2 = u2.getTag(o2);
+               int dif = t1.compareTo(t2);
+               if (dif!=0) return dif;
+               Object v1 = u1.getValue(o1);
+               Object v2 = u2.getValue(o2);
+               Binding c1 = u1.getComponentBindings()[t1];
+               Binding c2 = u2.getComponentBindings()[t2];
+               Datatype ct = c1.type();
+               return deepCompare(ct, c1, v1, c2, v2, compareHistory);
+       }
+       
+       if (t instanceof VariantType) {
+               VariantBinding v1 = (VariantBinding) b1;
+               VariantBinding v2 = (VariantBinding) b2;
+               // Compare Type
+               Datatype t1 = v1.getContentType(o1);
+               Datatype t2 = v2.getContentType(o2);
+               Binding dataTypeBinding = Bindings.getBindingUnchecked(Datatype.class);
+               int dif = dataTypeBinding.compare(t1, t2);
+               if (dif!=0) return dif;
+               // Compare Value
+               Binding bi1 = v1.getContentBinding(o1);
+               Binding bi2 = v2.getContentBinding(o2);
+               Object va1 = v1.getContent(o1, bi1);
+               Object va2 = v2.getContent(o2, bi2);
+               return compare(bi1, va1, bi2, va2);
+       }
+       
+       if (t instanceof RecordType) {                                  
+               RecordType rt    = (RecordType) t; 
+               RecordBinding r1 = (RecordBinding) b1;
+               RecordBinding r2 = (RecordBinding) b2;
+               
+               // Compare History is used to prevent infinite loops
+               if (rt.isReferable()) {
+               if (compareHistory==null) {
+                       compareHistory = new HashSet<IdentityPair<Object, Object>>(); 
+               }       
+               IdentityPair<Object, Object> p = new IdentityPair<Object, Object>(o1, o2);
+               if (compareHistory.contains(p)) return 0;               
+                       compareHistory.add(p);
+               }
+               
+               int len = rt.getComponentCount();
+               for (int i=0; i<len; i++) {
+                       Binding c1 = r1.getComponentBindings()[i];
+                       Binding c2 = r2.getComponentBindings()[i];
+                       Object v1 = r1.getComponent(o1, i);
+                       Object v2 = r2.getComponent(o2, i);
+                       Datatype ct = c1.type();
+                       int dif = deepCompare(ct, c1, v1, c2, v2, compareHistory);
+                       if (dif!=0) return dif;
+               }
+               return 0;
+       }
+       
+       throw new IllegalArgumentException("Unsupported data type "+t);         
+    }
+    
+    public static Comparator<Object> createComparator(final Binding b1, final Binding b2)
+    {
+       if (b1==b2) return b1;
+       return new Comparator<Object>() {
+                       @Override
+                       public int compare(Object o1, Object o2)                        
+                       {                               
+                               try {
+                                       return DataValueUtil.compare(b1, o1, b2, o2);
+                               } catch (BindingException e) {
+                                       throw new RuntimeBindingException(e);
+                               }
+                       }
+               };
+    }
+       
+}
+