1 /*******************************************************************************
\r
2 * Copyright (c) 2010 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.databoard.util;
14 import java.util.Comparator;
\r
15 import java.util.HashSet;
\r
16 import java.util.Iterator;
\r
17 import java.util.Map.Entry;
\r
18 import java.util.Set;
\r
19 import java.util.TreeMap;
\r
21 import org.simantics.databoard.Bindings;
\r
22 import org.simantics.databoard.binding.ArrayBinding;
\r
23 import org.simantics.databoard.binding.Binding;
\r
24 import org.simantics.databoard.binding.BooleanBinding;
\r
25 import org.simantics.databoard.binding.ByteBinding;
\r
26 import org.simantics.databoard.binding.DoubleBinding;
\r
27 import org.simantics.databoard.binding.FloatBinding;
\r
28 import org.simantics.databoard.binding.IntegerBinding;
\r
29 import org.simantics.databoard.binding.LongBinding;
\r
30 import org.simantics.databoard.binding.MapBinding;
\r
31 import org.simantics.databoard.binding.OptionalBinding;
\r
32 import org.simantics.databoard.binding.RecordBinding;
\r
33 import org.simantics.databoard.binding.StringBinding;
\r
34 import org.simantics.databoard.binding.UnionBinding;
\r
35 import org.simantics.databoard.binding.VariantBinding;
\r
36 import org.simantics.databoard.binding.error.BindingException;
\r
37 import org.simantics.databoard.binding.error.RuntimeBindingException;
\r
38 import org.simantics.databoard.type.ArrayType;
\r
39 import org.simantics.databoard.type.BooleanType;
\r
40 import org.simantics.databoard.type.ByteType;
\r
41 import org.simantics.databoard.type.Datatype;
\r
42 import org.simantics.databoard.type.DoubleType;
\r
43 import org.simantics.databoard.type.FloatType;
\r
44 import org.simantics.databoard.type.IntegerType;
\r
45 import org.simantics.databoard.type.LongType;
\r
46 import org.simantics.databoard.type.MapType;
\r
47 import org.simantics.databoard.type.OptionalType;
\r
48 import org.simantics.databoard.type.RecordType;
\r
49 import org.simantics.databoard.type.StringType;
\r
50 import org.simantics.databoard.type.UnionType;
\r
51 import org.simantics.databoard.type.VariantType;
\r
54 * DataValue handling utilities
56 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
58 public class DataValueUtil {
61 * Compares its two data values for order. Returns a negative integer,
62 * zero, or a positive integer as the first argument is less than, equal
63 * to, or greater than the second.<p>
65 * The implementor must also ensure that the relation is transitive:
66 * <code>((compare(x, y)>0) && (compare(y, z)>0))</code> implies
67 * <code>compare(x, z)>0</code>.<p>
69 * Finally, the implementor must ensure that <code>compare(x, y)==0</code>
70 * implies that <code>sgn(compare(x, z))==sgn(compare(y, z))</code> for all
73 * DataTypes of b1 and b2 are not equal then data types are compared.
75 * The comparison function is defined at
76 * http://dev.simantics.org/index.php/Org.simantics.datatype_Manual#CompareTo_and_Equals
78 * @param b1 Binding of o1
79 * @param o1 the first object to be compared.
80 * @param b2 Binding of o2
81 * @param o2 the second object to be compared.
82 * @return a negative integer, zero, or a positive integer as the
83 * first argument is less than, equal to, or greater than the
85 * @throws BindingException if object cannot be handled by a binding
87 public static int compare(Binding b1, Object o1, Binding b2, Object o2)
88 throws BindingException
90 // Not implemented yet
93 return b1.compare(o1, o2);
94 } catch (RuntimeBindingException e) {
99 Datatype t1 = b1.type();
100 Datatype t2 = b2.type();
101 int typeComparison = Bindings.getBindingUnchecked(Datatype.class).compare(t1, t2);
102 if (typeComparison != 0) return typeComparison;
104 return deepCompare(t1, b1, o1, b2, o2, null);
107 public static boolean equals(Binding b1, Object o1, Binding b2, Object o2)
108 throws BindingException
110 // Not implemented yet
113 return b1.compare(o1, o2) == 0;
114 } catch (RuntimeBindingException e) {
119 Datatype t1 = b1.type();
120 Datatype t2 = b2.type();
121 if (!t1.equals(t2)) return false;
123 int compare = deepCompare(t1, b1, o1, b2, o2, null);
127 static int deepCompare(Datatype t, Binding b1, Object o1, Binding b2, Object o2, Set<IdentityPair<Object, Object>> compareHistory)
128 throws BindingException {
129 /*// Not implemented yet
132 return b1.compare(o1, o2);
133 } catch (RuntimeBindingException e) {
138 assert(b1.type().equals(t));
139 assert(b2.type().equals(t));
141 if (t instanceof ByteType) {
142 byte v1 = ((ByteBinding) b1).getValue_(o1);
143 byte v2 = ((ByteBinding) b2).getValue_(o2);
147 if (t instanceof IntegerType) {
148 int v1 = ((IntegerBinding) b1).getValue_(o1);
149 int v2 = ((IntegerBinding) b2).getValue_(o2);
150 return (v1<v2 ? -1 : (v1==v2 ? 0 : 1));
153 if (t instanceof LongType) {
154 long v1 = ((LongBinding) b1).getValue_(o1);
155 long v2 = ((LongBinding) b2).getValue_(o2);
156 return (v1<v2 ? -1 : (v1==v2 ? 0 : 1));
159 if (t instanceof FloatType) {
160 float v1 = ((FloatBinding) b1).getValue_(o1);
161 float v2 = ((FloatBinding) b2).getValue_(o2);
162 return Float.compare(v1, v2);
165 if (t instanceof DoubleType) {
166 Double v1 = ((DoubleBinding) b1).getValue_(o1);
167 Double v2 = ((DoubleBinding) b2).getValue_(o2);
168 return Double.compare(v1, v2);
171 if (t instanceof BooleanType) {
172 boolean v1 = ((BooleanBinding) b1).getValue_(o1);
173 boolean v2 = ((BooleanBinding) b2).getValue_(o2);
174 return (v2 == v1 ? 0 : (v1 ? 1 : -1));
177 if (t instanceof ArrayType) {
178 ArrayBinding a1 = (ArrayBinding) b1;
179 ArrayBinding a2 = (ArrayBinding) b2;
181 int l1 = a1.size(o1);
182 int l2 = a2.size(o2);
184 if (dif!=0) return dif;
186 Binding c1 = a1.getComponentBinding();
187 Binding c2 = a2.getComponentBinding();
188 Datatype ct = c1.type();
189 for (int i=0; i<l1; i++) {
190 Object e1 = a1.get(o1, i);
191 Object e2 = a2.get(o2, i);
192 dif = deepCompare(ct, c1, e1, c2, e2, compareHistory);
193 if (dif!=0) return dif;
198 if (t instanceof MapType) {
199 MapBinding m1 = (MapBinding) b1;
200 MapBinding m2 = (MapBinding) b2;
202 int l1 = m1.size(o1);
203 int l2 = m2.size(o2);
205 if (dif!=0) return dif;
207 Binding k1 = m1.getKeyBinding();
208 Binding k2 = m2.getKeyBinding();
209 Binding v1 = m1.getValueBinding();
210 Binding v2 = m2.getValueBinding();
211 TreeMap<Object, Object> e1 = new TreeMap<Object, Object>( k1 );
212 TreeMap<Object, Object> e2 = new TreeMap<Object, Object>( k2 );
216 Iterator<Entry<Object, Object>> i1 = e1.entrySet().iterator();
217 Iterator<Entry<Object, Object>> i2 = e2.entrySet().iterator();
218 while (i1.hasNext()) {
219 Entry<Object, Object> h1 = i1.next();
220 Entry<Object, Object> h2 = i2.next();
221 dif = deepCompare(k1.type(), k1, h1.getKey(), k2, h2.getKey(), compareHistory);
222 if (dif!=0) return dif;
223 dif = deepCompare(v1.type(), v1, h1.getValue(), v2, h2.getValue(), compareHistory);
224 if (dif!=0) return dif;
231 if (t instanceof OptionalType) {
232 OptionalBinding ob1 = (OptionalBinding) b1;
233 OptionalBinding ob2 = (OptionalBinding) b2;
234 Boolean h1 = ob1.hasValue(o1);
235 Boolean h2 = ob2.hasValue(o2);
236 if (!h1 && !h2) return 0;
237 int dif = h1.compareTo(h2);
238 if (dif!=0) return dif;
240 Binding c1 = ob1.getComponentBinding();
241 Binding c2 = ob2.getComponentBinding();
242 Object v1 = ob1.getValue(o1);
243 Object v2 = ob2.getValue(o2);
244 Datatype ct = c1.type();
245 return deepCompare(ct, c1, v1, c2, v2, compareHistory);
248 if (t instanceof StringType) {
249 StringBinding s1 = (StringBinding) b1;
250 StringBinding s2 = (StringBinding) b2;
251 String v1 = s1.getValue(o1);
252 String v2 = s2.getValue(o2);
253 return v1.compareTo(v2);
256 if (t instanceof UnionType) {
257 UnionBinding u1 = (UnionBinding) b1;
258 UnionBinding u2 = (UnionBinding) b2;
259 Integer t1 = u1.getTag(o1);
260 Integer t2 = u2.getTag(o2);
261 int dif = t1.compareTo(t2);
262 if (dif!=0) return dif;
263 Object v1 = u1.getValue(o1);
264 Object v2 = u2.getValue(o2);
265 Binding c1 = u1.getComponentBindings()[t1];
266 Binding c2 = u2.getComponentBindings()[t2];
267 Datatype ct = c1.type();
268 return deepCompare(ct, c1, v1, c2, v2, compareHistory);
271 if (t instanceof VariantType) {
272 VariantBinding v1 = (VariantBinding) b1;
273 VariantBinding v2 = (VariantBinding) b2;
275 Datatype t1 = v1.getContentType(o1);
276 Datatype t2 = v2.getContentType(o2);
277 Binding dataTypeBinding = Bindings.getBindingUnchecked(Datatype.class);
278 int dif = dataTypeBinding.compare(t1, t2);
279 if (dif!=0) return dif;
281 Binding bi1 = v1.getContentBinding(o1);
282 Binding bi2 = v2.getContentBinding(o2);
283 Object va1 = v1.getContent(o1, bi1);
284 Object va2 = v2.getContent(o2, bi2);
285 return compare(bi1, va1, bi2, va2);
288 if (t instanceof RecordType) {
289 RecordType rt = (RecordType) t;
290 RecordBinding r1 = (RecordBinding) b1;
291 RecordBinding r2 = (RecordBinding) b2;
293 // Compare History is used to prevent infinite loops
294 if (rt.isReferable()) {
295 if (compareHistory==null) {
296 compareHistory = new HashSet<IdentityPair<Object, Object>>();
298 IdentityPair<Object, Object> p = new IdentityPair<Object, Object>(o1, o2);
299 if (compareHistory.contains(p)) return 0;
300 compareHistory.add(p);
303 int len = rt.getComponentCount();
304 for (int i=0; i<len; i++) {
305 Binding c1 = r1.getComponentBindings()[i];
306 Binding c2 = r2.getComponentBindings()[i];
307 Object v1 = r1.getComponent(o1, i);
308 Object v2 = r2.getComponent(o2, i);
309 Datatype ct = c1.type();
310 int dif = deepCompare(ct, c1, v1, c2, v2, compareHistory);
311 if (dif!=0) return dif;
316 throw new IllegalArgumentException("Unsupported data type "+t);
319 public static Comparator<Object> createComparator(final Binding b1, final Binding b2)
321 if (b1==b2) return b1;
322 return new Comparator<Object>() {
324 public int compare(Object o1, Object o2)
327 return DataValueUtil.compare(b1, o1, b2, o2);
328 } catch (BindingException e) {
329 throw new RuntimeBindingException(e);