]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/ArrayBinding.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / ArrayBinding.java
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/ArrayBinding.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/ArrayBinding.java
new file mode 100644 (file)
index 0000000..1a0cd56
--- /dev/null
@@ -0,0 +1,382 @@
+/*******************************************************************************\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.binding;
+
+import java.util.Collection;\r
+import java.util.IdentityHashMap;\r
+import java.util.Iterator;\r
+import java.util.Set;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.accessor.reference.ChildReference;\r
+import org.simantics.databoard.accessor.reference.IndexReference;\r
+import org.simantics.databoard.accessor.reference.LabelReference;\r
+import org.simantics.databoard.adapter.AdaptException;\r
+import org.simantics.databoard.adapter.Adapter;\r
+import org.simantics.databoard.adapter.AdapterConstructionException;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.error.RuntimeBindingException;\r
+import org.simantics.databoard.binding.impl.ArrayListBinding;\r
+import org.simantics.databoard.binding.impl.BindingPrintContext;\r
+import org.simantics.databoard.binding.impl.ByteArrayBinding;\r
+import org.simantics.databoard.binding.impl.DoubleArrayBinding;\r
+import org.simantics.databoard.binding.impl.FloatArrayBinding;\r
+import org.simantics.databoard.binding.impl.IntArrayBinding;\r
+import org.simantics.databoard.binding.impl.LinkedListBinding;\r
+import org.simantics.databoard.binding.impl.LongArrayBinding;\r
+import org.simantics.databoard.binding.impl.ObjectArrayBinding;\r
+import org.simantics.databoard.type.ArrayType;\r
+import org.simantics.databoard.util.IdentityPair;\r
+import org.simantics.databoard.util.Range;\r
+
+/**
+ * This is a binding of Array type and a Java Object.
+ * 
+ * @see ArrayType\r
+ * @see ArrayListBinding for Binding of java.util.ArrayList<?>\r
+ * @see LinkedListBinding for Binding of java.util.LinkedList<?>\r
+ * @see ObjectArrayBinding for Binding of Object[]\r
+ * @see IntArrayBinding for primitive array int[] binding\r
+ * @see ByteArrayBinding for primitive array byte[] binding\r
+ * @see LongArrayBinding for primitive array long[] binding\r
+ * @see DoubleArrayBinding for primitive array double[] binding\r
+ * @see FloatArrayBinding for primitive array float[] binding \r
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
+ */
+public abstract class ArrayBinding extends Binding {
+
+    public Binding componentBinding;
+    
+       public ArrayBinding(ArrayType type, Binding componentBinding) {
+//             if (!type.getComponentType().equals(componentBinding.type()))
+//                     throw new IllegalArgumentException("Binding for "+type.componentType+" expected, got "+componentBinding.type());
+        this.componentBinding = componentBinding;
+        this.type = type;
+    }
+       \r
+       @Override\r
+       public Binding getComponentBinding(ChildReference path) {\r
+               if (path==null) return this;            \r
+               if (path instanceof org.simantics.databoard.accessor.reference.ComponentReference) {\r
+               return componentBinding.getComponentBinding(path.childReference);\r
+               }\r
+               if (path instanceof IndexReference) {\r
+                       IndexReference ir = (IndexReference) path;                      \r
+                       if (ir.index == 0) { \r
+                       return componentBinding.getComponentBinding(path.childReference);\r
+                       }\r
+               }\r
+               if (path instanceof LabelReference) {\r
+                       LabelReference lr = (LabelReference) path;\r
+                       if (lr.label.equals("v")) { \r
+                       return componentBinding.getComponentBinding(path.childReference);\r
+                       }\r
+               }\r
+               throw new IllegalArgumentException();\r
+       }\r
+       
+       /**
+        * Returns true if array length can be modified. 
+        * 
+        * @return true if array length can be modified, false if not
+        */
+       @Override
+       public boolean isImmutable() {
+               return super.isImmutable();
+       }\r
+       \r
+       /**\r
+        * Return true if the array's size can be adjusted and false if not\r
+        * \r
+        * @return true if array is resizable\r
+        */\r
+       public abstract boolean isResizable();\r
+       
+       @Override
+       public ArrayType type() {
+               return (ArrayType) type;
+       }
+
+    public Binding getComponentBinding() {
+        return componentBinding;
+    }
+    
+    /**
+     * Create a new empty array
+     * @return array object
+     */
+    public abstract Object create();
+       
+    /**
+     * Create a new array with initial values copied or referred from a collection. 
+     * 
+     * @param collection
+     * @return array object
+     * @throws BindingException
+     */
+       public Object create(Collection<Object> collection) throws BindingException {
+               return create(collection.size(), collection.iterator());
+       }
+    
+    /**
+     * Create new array instance with initial values possibly borrowed from an interator.
+     * <p>
+     * The implementation iterate the iterator before returning.
+     * 
+     * @param length array length
+     * @param values value iterator 
+     * @return new instance
+     */
+       public abstract Object create(int length, Iterator<Object> values)
+       throws BindingException;\r
+       \r
+       /**\r
+        * \r
+        * @param length\r
+        * @return array\r
+        * @throws BindingException\r
+        */\r
+       public Object create(int length) throws BindingException\r
+       {\r
+               try {\r
+                       return create(length, new Iterator<Object>() {\r
+                               @Override\r
+                               public boolean hasNext() {\r
+                                       return true;\r
+                               }\r
+       \r
+                               @Override\r
+                               public Object next() {\r
+                                       try {\r
+                                               return componentBinding.createDefault();\r
+                                       } catch (BindingException e) {\r
+                                               throw new RuntimeBindingException(e);\r
+                                       }\r
+                               }\r
+       \r
+                               @Override\r
+                               public void remove() {\r
+                               }});\r
+               } catch (RuntimeBindingException e) {\r
+                       throw e.getCause();\r
+               }\r
+       }
+               
+       /**
+        * Create Array with initial values possibly borrowed from an java.lang.Array
+        * 
+        * @param array
+        * @return array of ArrayType
+        * @throws BindingException
+        */
+       public abstract Object create(Object[] array)
+       throws BindingException;
+       
+       public Object createUnchecked(Object...array)
+       throws RuntimeBindingException {
+               try {
+                       return create(array);
+               } catch (BindingException e) {
+                       throw new RuntimeBindingException(e);
+               }
+       }\r
+\r
+       @Override\r
+       public void readFrom(Binding srcBinding, Object src, Object dst)\r
+                       throws BindingException {\r
+               \r
+               try {\r
+               \r
+                       // Src Binding\r
+                       ArrayBinding sb = (ArrayBinding) srcBinding;\r
+                       // Src Component Binding\r
+                       Binding scb = sb.getComponentBinding();\r
+                               \r
+                       // Dst Component Binding\r
+                       Binding dcb = getComponentBinding();\r
+                               \r
+                       int newLen = sb.size(src);\r
+                       int oldLen = size(dst);\r
+                       boolean cbImmutable = dcb.isImmutable();\r
+                       Adapter cloner = cbImmutable ? Bindings.adapterFactory.getAdapter(scb, dcb, false, true) : null;\r
+                               \r
+                       // Set elements\r
+                       for (int i=0; i<newLen; i++) {\r
+                               if (cbImmutable) {\r
+                                       // Create new instance\r
+                                       Object sc = sb.get(src, i);\r
+                                       Object dc = cloner.adapt(sc);\r
+                                       if (i<oldLen) set(dst, i, dc); else add(dst, dc); \r
+                               } else \r
+                               if (i<oldLen) {\r
+                                       // Read over old instance\r
+                                       Object dc = get(dst, i);\r
+                                       Object sc = sb.get(src, i);\r
+                                       dc = dcb.readFromTry(scb, sc, dc);\r
+                                       // Safety-writeback - clone/reference nature of get is unknown\r
+                                       set(dst, i, dc);\r
+                               } else {\r
+                                       // New instance\r
+                                       Object sc = sb.get(src, i);\r
+                                       Object dc = dcb.createDefault();\r
+                                       dc = dcb.readFromTry(scb, sc, dc);\r
+                                       add(dst, dc);\r
+                               }\r
+                       }\r
+                               \r
+                       // Remove excess elements\r
+                       if (oldLen>newLen) {\r
+                               setSize(dst, newLen);\r
+                       }\r
+                       \r
+                       if (!Bindings.equals(srcBinding, src, this, dst))\r
+                               throw new BindingException("internal error");\r
+\r
+               } catch (AdaptException e) {\r
+                       throw new BindingException(e);\r
+               } catch (AdapterConstructionException e) {\r
+                       throw new BindingException(e);\r
+               }\r
+               \r
+       }       \r
+\r
+       
+       public void add(Object array, Object element) throws BindingException 
+       {
+               int size = size(array);
+               add(array, size, element);
+       }
+       public abstract void add(Object array, int index, Object element) throws BindingException, IndexOutOfBoundsException;
+       public void remove(Object array, int index) throws BindingException, IndexOutOfBoundsException
+       {
+               remove(array, index, 1);
+       }
+       public abstract void remove(Object array, int index, int count) throws BindingException, IndexOutOfBoundsException;
+       public abstract Object get(Object array, int index) throws BindingException, IndexOutOfBoundsException;         
+       public abstract void getAll(Object array, Object[] result) throws BindingException;
+       public abstract void set(Object array, int index, Object value) throws BindingException;\r
+       public abstract void setSize(Object array, int newSize) throws BindingException;
+       
+       public abstract int size(Object array) throws BindingException;
+       
+       @Override
+       public void accept(Visitor1 v, Object obj) {
+           v.visit(this, obj);        
+       }
+
+       @Override
+       public <T> T accept(Visitor<T> v) {
+           return v.visit(this);
+       }
+       
+    /**
+     * Assert the instance is valid and follows restrictions set in data type.
+     * Assertions:
+     *   1. The Length of the array meets ArrayType range
+     *   2. Recursive assertion of each element
+     * 
+     * @param obj the instance
+     * @throws BindingException on invalid instance
+     */
+    public void assertInstaceIsValid(Object obj, Set<Object> validInstances)
+    throws BindingException 
+    {
+       ArrayType type = type();
+       // Assert The Length of the array meets ArrayType range
+       int length = size(obj);
+       Range range = type.getLength();
+       if (range!=null && !range.contains(length)) {
+               throw new BindingException("Array length (="+length+")out of bounds. "+range+" was expected.");
+       }
+       // Recursive assertion of each element
+       for (int i=0; i<length; i++)
+       {
+               Object component = get(obj, i);
+               componentBinding.assertInstaceIsValid(component, validInstances);
+       }
+    }
+    
+    @Override
+    public int deepHashValue(Object value, IdentityHashMap<Object, Object> hashedObjects) throws BindingException {
+       int result = 1;
+       int len = size(value);
+       for (int i=0; i<len; i++) {
+               Object element = get(value, i);
+               result = 31*result + componentBinding.deepHashValue(element, hashedObjects);
+       }
+       return result;
+    }
+    
+    @Override
+    public int deepCompare(Object o1, Object o2,
+               Set<IdentityPair<Object, Object>> compareHistory)
+               throws BindingException {
+               // Compare Lengths
+               int l1 = size(o1);
+               int l2 = size(o2);
+               int dif = l1 - l2;
+               if (dif!=0) return dif;
+               // Compare elements
+               Binding c = getComponentBinding();
+               for (int i=0; i<l1; i++) {
+                       Object e1 = get(o1, i);
+                       Object e2 = get(o2, i);
+                       dif = c.deepCompare(e1, e2, compareHistory);
+                       if (dif!=0) return dif;
+               }
+               return 0;
+    }
+\r
+    @Override\r
+       protected void toString(Object value, BindingPrintContext ctx) throws BindingException {\r
+               Binding componentBinding = getComponentBinding();\r
+               ctx.b.append('[');\r
+               int size = size(value);\r
+               boolean numberArray = componentBinding instanceof NumberBinding;\r
+               boolean hasMany = size > 1;\r
+               for(int i=0;i<size;++i) {\r
+                       if(i>0) {\r
+                               ctx.b.append(", ");\r
+                               if ( hasMany && !numberArray && !ctx.singleLine ) {\r
+                                       ctx.b.append("\n");\r
+                               }\r
+                       }\r
+                       componentBinding.toString(get(value, i), ctx);\r
+               }\r
+               ctx.b.append(']');\r
+       }\r
+    \r
+    /**\r
+     * Get the number of component bindings\r
+     */\r
+    @Override\r
+    public int getComponentCount() {\r
+       return 1;\r
+    }\r
+    \r
+    @Override\r
+    public Binding getComponentBinding(int index) {\r
+       if (index!=0) throw new IllegalArgumentException();\r
+       return componentBinding;\r
+    }\r
+\r
+    @Override\r
+    protected boolean deepEquals(Object obj,\r
+               Set<IdentityPair<Binding, Binding>> compareHistory) {\r
+       return super.deepEquals( obj, compareHistory ) && componentBinding.equals(((ArrayBinding)obj).componentBinding, compareHistory);\r
+    }\r
+    \r
+    @Override\r
+    public int deepHashCode(IdentityHashMap<Object, Object> hashedObjects) {\r
+       return super.deepHashCode(hashedObjects) + 13 * componentBinding.hashCode(hashedObjects);\r
+    }\r
+}