]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/ArrayBinding.java
Use type reflection tools from databoard in objmap2.
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / ArrayBinding.java
1 /*******************************************************************************
2  *  Copyright (c) 2010 Association for Decentralized Information Management in
3  *  Industry THTH ry.
4  *  All rights reserved. This program and the accompanying materials
5  *  are made available under the terms of the Eclipse Public License v1.0
6  *  which accompanies this distribution, and is available at
7  *  http://www.eclipse.org/legal/epl-v10.html
8  *
9  *  Contributors:
10  *      VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.databoard.binding;
13
14 import java.util.Collection;
15 import java.util.IdentityHashMap;
16 import java.util.Iterator;
17 import java.util.Set;
18
19 import org.simantics.databoard.Bindings;
20 import org.simantics.databoard.accessor.reference.ChildReference;
21 import org.simantics.databoard.accessor.reference.IndexReference;
22 import org.simantics.databoard.accessor.reference.LabelReference;
23 import org.simantics.databoard.adapter.AdaptException;
24 import org.simantics.databoard.adapter.Adapter;
25 import org.simantics.databoard.adapter.AdapterConstructionException;
26 import org.simantics.databoard.binding.error.BindingException;
27 import org.simantics.databoard.binding.error.RuntimeBindingException;
28 import org.simantics.databoard.binding.impl.ArrayListBinding;
29 import org.simantics.databoard.binding.impl.BindingPrintContext;
30 import org.simantics.databoard.binding.impl.ByteArrayBinding;
31 import org.simantics.databoard.binding.impl.DoubleArrayBinding;
32 import org.simantics.databoard.binding.impl.FloatArrayBinding;
33 import org.simantics.databoard.binding.impl.IntArrayBinding;
34 import org.simantics.databoard.binding.impl.LinkedListBinding;
35 import org.simantics.databoard.binding.impl.LongArrayBinding;
36 import org.simantics.databoard.binding.impl.ObjectArrayBinding;
37 import org.simantics.databoard.type.ArrayType;
38 import org.simantics.databoard.util.IdentityPair;
39 import org.simantics.databoard.util.Range;
40
41 /**
42  * This is a binding of Array type and a Java Object.
43  * 
44  * @see ArrayType
45  * @see ArrayListBinding for Binding of java.util.ArrayList<?>
46  * @see LinkedListBinding for Binding of java.util.LinkedList<?>
47  * @see ObjectArrayBinding for Binding of Object[]
48  * @see IntArrayBinding for primitive array int[] binding
49  * @see ByteArrayBinding for primitive array byte[] binding
50  * @see LongArrayBinding for primitive array long[] binding
51  * @see DoubleArrayBinding for primitive array double[] binding
52  * @see FloatArrayBinding for primitive array float[] binding 
53  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
54  */
55 public abstract class ArrayBinding extends Binding {
56
57     public Binding componentBinding;
58     
59         public ArrayBinding(ArrayType type, Binding componentBinding) {
60 //              if (!type.getComponentType().equals(componentBinding.type()))
61 //                      throw new IllegalArgumentException("Binding for "+type.componentType+" expected, got "+componentBinding.type());
62         this.componentBinding = componentBinding;
63         this.type = type;
64     }
65         
66         @Override
67         public Binding getComponentBinding(ChildReference path) {
68                 if (path==null) return this;            
69                 if (path instanceof org.simantics.databoard.accessor.reference.ComponentReference) {
70                 return componentBinding.getComponentBinding(path.childReference);
71                 }
72                 if (path instanceof IndexReference) {
73                         IndexReference ir = (IndexReference) path;                      
74                         if (ir.index == 0) { 
75                         return componentBinding.getComponentBinding(path.childReference);
76                         }
77                 }
78                 if (path instanceof LabelReference) {
79                         LabelReference lr = (LabelReference) path;
80                         if (lr.label.equals("v")) { 
81                         return componentBinding.getComponentBinding(path.childReference);
82                         }
83                 }
84                 throw new IllegalArgumentException();
85         }
86         
87         /**
88          * Returns true if array length can be modified. 
89          * 
90          * @return true if array length can be modified, false if not
91          */
92         @Override
93         public boolean isImmutable() {
94                 return super.isImmutable();
95         }
96         
97         /**
98          * Return true if the array's size can be adjusted and false if not
99          * 
100          * @return true if array is resizable
101          */
102         public abstract boolean isResizable();
103         
104         @Override
105         public ArrayType type() {
106                 return (ArrayType) type;
107         }
108
109     public Binding getComponentBinding() {
110         return componentBinding;
111     }
112     
113     /**
114      * Create a new empty array
115      * @return array object
116      */
117     public abstract Object create();
118         
119     /**
120      * Create a new array with initial values copied or referred from a collection. 
121      * 
122      * @param collection
123      * @return array object
124      * @throws BindingException
125      */
126         public Object create(Collection<Object> collection) throws BindingException {
127                 return create(collection.size(), collection.iterator());
128         }
129     
130     /**
131      * Create new array instance with initial values possibly borrowed from an interator.
132      * <p>
133      * The implementation iterate the iterator before returning.
134      * 
135      * @param length array length
136      * @param values value iterator 
137      * @return new instance
138      */
139         public abstract Object create(int length, Iterator<Object> values)
140         throws BindingException;
141         
142         /**
143          * 
144          * @param length
145          * @return array
146          * @throws BindingException
147          */
148         public Object create(int length) throws BindingException
149         {
150                 try {
151                         return create(length, new Iterator<Object>() {
152                                 @Override
153                                 public boolean hasNext() {
154                                         return true;
155                                 }
156         
157                                 @Override
158                                 public Object next() {
159                                         try {
160                                                 return componentBinding.createDefault();
161                                         } catch (BindingException e) {
162                                                 throw new RuntimeBindingException(e);
163                                         }
164                                 }
165         
166                                 @Override
167                                 public void remove() {
168                                 }});
169                 } catch (RuntimeBindingException e) {
170                         throw e.getCause();
171                 }
172         }
173                 
174         /**
175          * Create Array with initial values possibly borrowed from an java.lang.Array
176          * 
177          * @param array
178          * @return array of ArrayType
179          * @throws BindingException
180          */
181         public abstract Object create(Object[] array)
182         throws BindingException;
183         
184         public Object createUnchecked(Object...array)
185         throws RuntimeBindingException {
186                 try {
187                         return create(array);
188                 } catch (BindingException e) {
189                         throw new RuntimeBindingException(e);
190                 }
191         }
192
193         @Override
194         public void readFrom(Binding srcBinding, Object src, Object dst)
195                         throws BindingException {
196                 
197                 try {
198                 
199                         // Src Binding
200                         ArrayBinding sb = (ArrayBinding) srcBinding;
201                         // Src Component Binding
202                         Binding scb = sb.getComponentBinding();
203                                 
204                         // Dst Component Binding
205                         Binding dcb = getComponentBinding();
206                                 
207                         int newLen = sb.size(src);
208                         int oldLen = size(dst);
209                         boolean cbImmutable = dcb.isImmutable();
210                         Adapter cloner = cbImmutable ? Bindings.adapterFactory.getAdapter(scb, dcb, false, true) : null;
211                                 
212                         // Set elements
213                         for (int i=0; i<newLen; i++) {
214                                 if (cbImmutable) {
215                                         // Create new instance
216                                         Object sc = sb.get(src, i);
217                                         Object dc = cloner.adapt(sc);
218                                         if (i<oldLen) set(dst, i, dc); else add(dst, dc); 
219                                 } else 
220                                 if (i<oldLen) {
221                                         // Read over old instance
222                                         Object dc = get(dst, i);
223                                         Object sc = sb.get(src, i);
224                                         dc = dcb.readFromTry(scb, sc, dc);
225                                         // Safety-writeback - clone/reference nature of get is unknown
226                                         set(dst, i, dc);
227                                 } else {
228                                         // New instance
229                                         Object sc = sb.get(src, i);
230                                         Object dc = dcb.createDefault();
231                                         dc = dcb.readFromTry(scb, sc, dc);
232                                         add(dst, dc);
233                                 }
234                         }
235                                 
236                         // Remove excess elements
237                         if (oldLen>newLen) {
238                                 setSize(dst, newLen);
239                         }
240                         
241                         if (!Bindings.equals(srcBinding, src, this, dst))
242                                 throw new BindingException("internal error");
243
244                 } catch (AdaptException e) {
245                         throw new BindingException(e);
246                 } catch (AdapterConstructionException e) {
247                         throw new BindingException(e);
248                 }
249                 
250         }       
251
252         
253         public void add(Object array, Object element) throws BindingException 
254         {
255                 int size = size(array);
256                 add(array, size, element);
257         }
258         public abstract void add(Object array, int index, Object element) throws BindingException, IndexOutOfBoundsException;
259         public void remove(Object array, int index) throws BindingException, IndexOutOfBoundsException
260         {
261                 remove(array, index, 1);
262         }
263         public abstract void remove(Object array, int index, int count) throws BindingException, IndexOutOfBoundsException;
264         public abstract Object get(Object array, int index) throws BindingException, IndexOutOfBoundsException;         
265         public abstract void getAll(Object array, Object[] result) throws BindingException;
266         public abstract void set(Object array, int index, Object value) throws BindingException;
267         public abstract void setSize(Object array, int newSize) throws BindingException;
268         
269         public abstract int size(Object array) throws BindingException;
270         
271         @Override
272         public void accept(Visitor1 v, Object obj) {
273             v.visit(this, obj);        
274         }
275
276         @Override
277         public <T> T accept(Visitor<T> v) {
278             return v.visit(this);
279         }
280         
281     /**
282      * Assert the instance is valid and follows restrictions set in data type.
283      * Assertions:
284      *   1. The Length of the array meets ArrayType range
285      *   2. Recursive assertion of each element
286      * 
287      * @param obj the instance
288      * @throws BindingException on invalid instance
289      */
290     public void assertInstaceIsValid(Object obj, Set<Object> validInstances)
291     throws BindingException 
292     {
293         ArrayType type = type();
294         // Assert The Length of the array meets ArrayType range
295         int length = size(obj);
296         Range range = type.getLength();
297         if (range!=null && !range.contains(length)) {
298                 throw new BindingException("Array length (="+length+")out of bounds. "+range+" was expected.");
299         }
300         // Recursive assertion of each element
301         for (int i=0; i<length; i++)
302         {
303                 Object component = get(obj, i);
304                 componentBinding.assertInstaceIsValid(component, validInstances);
305         }
306     }
307     
308     @Override
309     public int deepHashValue(Object value, IdentityHashMap<Object, Object> hashedObjects) throws BindingException {
310         int result = 1;
311         int len = size(value);
312         for (int i=0; i<len; i++) {
313                 Object element = get(value, i);
314                 result = 31*result + componentBinding.deepHashValue(element, hashedObjects);
315         }
316         return result;
317     }
318     
319     @Override
320     public int deepCompare(Object o1, Object o2,
321                 Set<IdentityPair<Object, Object>> compareHistory)
322                 throws BindingException {
323                 // Compare Lengths
324                 int l1 = size(o1);
325                 int l2 = size(o2);
326                 int dif = l1 - l2;
327                 if (dif!=0) return dif;
328                 // Compare elements
329                 Binding c = getComponentBinding();
330                 for (int i=0; i<l1; i++) {
331                         Object e1 = get(o1, i);
332                         Object e2 = get(o2, i);
333                         dif = c.deepCompare(e1, e2, compareHistory);
334                         if (dif!=0) return dif;
335                 }
336                 return 0;
337     }
338
339     @Override
340         protected void toString(Object value, BindingPrintContext ctx) throws BindingException {
341                 Binding componentBinding = getComponentBinding();
342                 ctx.b.append('[');
343                 int size = size(value);
344                 boolean numberArray = componentBinding instanceof NumberBinding;
345                 boolean hasMany = size > 1;
346                 for(int i=0;i<size;++i) {
347                         if(i>0) {
348                                 ctx.b.append(", ");
349                                 if ( hasMany && !numberArray && !ctx.singleLine ) {
350                                         ctx.b.append("\n");
351                                 }
352                         }
353                         componentBinding.toString(get(value, i), ctx);
354                 }
355                 ctx.b.append(']');
356         }
357     
358     /**
359      * Get the number of component bindings
360      */
361     @Override
362     public int getComponentCount() {
363         return 1;
364     }
365     
366     @Override
367     public Binding getComponentBinding(int index) {
368         if (index!=0) throw new IllegalArgumentException();
369         return componentBinding;
370     }
371
372     @Override
373     protected boolean deepEquals(Object obj,
374                 Set<IdentityPair<Binding, Binding>> compareHistory) {
375         return super.deepEquals( obj, compareHistory ) && componentBinding.equals(((ArrayBinding)obj).componentBinding, compareHistory);
376     }
377     
378     @Override
379     public int deepHashCode(IdentityHashMap<Object, Object> hashedObjects) {
380         return super.deepHashCode(hashedObjects) + 13 * componentBinding.hashCode(hashedObjects);
381     }
382 }