]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/MultiDimensionArrayUtils.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.utils.datastructures / src / org / simantics / utils / datastructures / MultiDimensionArrayUtils.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in 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.utils.datastructures;
13
14 import java.io.PrintStream;
15 import java.lang.reflect.Array;
16 import java.util.Arrays;
17 import java.util.Collections;
18 import java.util.Iterator;
19 import java.util.NoSuchElementException;
20
21 /**
22  * Multi-dimension array utils.
23  * 
24  * @See {@link Array} related
25  * @See {@link Arrays} related
26  * @See {@link Collections} related
27  * @author Toni Kalajainen (toni.kalajainen@vtt.fi)
28  */
29 public class MultiDimensionArrayUtils {
30
31         
32         /**
33          * Print multi-dimension array
34          * @param o
35          */
36         public static void printArrayDeep(Object v, PrintStream out)
37         {
38                 ArrayIterator<Boolean> i = arrayIterator(v, getArrayLengths(v));
39                 while (i.hasNext())
40                         System.out.println(Arrays.toString(i.getIndices())+" = "+i.next());
41         }       
42         
43     /**
44      * Get array length of each dimension of a multi-dimension array.
45      * 
46      * @param value multi-dimension array
47      * @return lengths of each dimension
48      */
49         public static int[] getArrayLengths(Object value)
50         {                       
51                 int dim = getDimension(value.getClass());
52                 int result[] = new int[ dim ];
53                 if (dim==0) return result;
54                 
55                 Object o = value;
56                 for (int i=0; i<dim; i++)                       
57                 {
58                         result[i] = Array.getLength(o);
59                         if (result[i]==0) break;
60                         o = Array.get(o, 0);
61                 }
62                 
63                 return result;
64         }
65         
66         /**
67          * Get the number of dimensions in a multi-dimension array.
68          * 
69          * @param value multi-dimension array
70          * @return the number of dimensions
71          */
72         public static int getDimension(Class<?> clazz)
73         {                       
74                 String signature = clazz.getName();
75                 int dim = 0;
76                 for (; dim<signature.length(); dim++)           
77                         if (signature.charAt(dim)!='[') break;          
78                 return dim;
79         }
80         
81         
82         /**
83          * Deep create multi-level array
84          * 
85          * @param componentType component type
86          * @param dims dimension lengths
87          * @return multi-level array
88          */
89         public static Object[] createMultiDimArray(Class<?> componentType, int[] dims)
90         {
91                 // Java 1.6.0
92                 return (Object[]) Array.newInstance(componentType, dims);
93                 
94                 /*
95                 // Older than 1.6.0
96                 if (dims==null || componentType==null || dims.length==0) throw new IllegalArgumentException();
97                 if (dims.length==1) 
98                         return Array.newInstance(componentType, dims[0]);
99                 
100                 int[][] dimArrays = new int[dims.length][];
101                 dimArrays[0] = dims;
102                 for (int j=1; j<dims.length; j++)
103                 {
104                         dimArrays[j] = new int[dims.length-j];
105                         System.arraycopy(dims, 1, dimArrays[j], 0, dims.length-j);
106                 }
107                 return _createMultiDimArray(componentType, dimArrays, 0);
108                 */
109         }
110 /*      
111         private static Object[] _createMultiDimArray(Class<?> componentType, int[][] dimArrays, int lvl)
112         {
113                 int[] dims = dimArrays[lvl];
114                 int len = dims[0];
115                 Object[] result = (Object[]) Array.newInstance(componentType, dims);
116                 if (lvl<dimArrays.length-1)
117                         for (int i=0; i<len; i++)
118                                 result[i] = _createMultiDimArray(componentType, dimArrays, lvl+1);
119                 return result;
120         }
121 */      
122                 
123         /**
124          * Returns the total number of elements in a multi-dimension array
125          * 
126          * @param dims lengths of each dimension
127          * @return total number of elements
128          */
129         public static int getLength(int[] dims)
130         {
131                 int len = dims[0];
132                 for (int i=1; i<dims.length; i++)
133                         len *= dims[i];
134                 return len;             
135         }
136
137         /**
138          * Get the component type of an array class
139          * 
140          * @param clazz (array) class
141          * @return component type
142          */
143         public static Class<?> getComponentType(Class<?> clazz)
144         {
145                 Class<?> result = clazz;
146                 while (result.isArray())
147                         result = result.getComponentType();
148                 return result;
149         }
150         
151         /**
152          * Demux single-dimension array (x[]) to a multi-dimension array (x[][][])
153          * 
154          * @param src single-dimension array
155          * @param dims
156          * @return multi-dimension array
157          */
158         public static Object demuxArray(Object src, int[] dims)
159         {
160                 return demuxArray(src, dims, getComponentType(src.getClass()));
161         }
162
163         /**
164          * Demux single-dimension array (x[]) to a multi-dimension array (x[][][])
165          * 
166          * @param src single-dimension array
167          * @param dims 
168          * @param componentType
169          * @return multi-dimension array
170          */
171         public static Object demuxArray(Object src, int[] dims, Class<?> componentType)
172         {
173                 Object dst = Array.newInstance(componentType, dims);
174                 _fillDemux(0, dims, src, 0, dst);
175                 return dst;
176         }
177         
178         /**
179          * Demuxes single dimension array into a multi-dimension array
180          *  
181          * @param src one dimension array (e.g. int[])
182          * @param dimensions length of each dimension
183          * @param dst multi-dimension array to be filled (use createMultiDimArray())
184          */
185         public static void demuxArray(Object src, int[] dims, Object dst)
186         {
187                 if (Array.getLength(src) != getLength(dims)) 
188                         throw new IllegalArgumentException("The length of src does not match the length of dst");       
189                 _fillDemux(0, dims, src, 0, dst);
190         }
191                 
192         private static int _fillDemux(int lvl, int[] dims, Object src, int srcIndex, Object dst)
193         {
194                 // lower level
195                 if (lvl==dims.length-1) {
196                         int len = dims[dims.length-1]; 
197                         System.arraycopy(src, srcIndex, dst, 0, len);
198                         return srcIndex + len;
199                 }
200                 // higher level
201                 for (int i=0; i<dims[lvl]; i++)
202                         srcIndex = _fillDemux(lvl+1, dims, src, srcIndex, Array.get(dst, i));
203                 
204                 return srcIndex;
205         }
206
207         /**
208          * Multiplex multi-dimension array (x[][][]) to single-dimension array (x[])
209          * 
210          * @param src multi-dimension array
211          * @return single-dimension array
212          */
213         public static Object muxArray(Object src)
214         {
215                 return muxArray(src, getArrayLengths(src), getComponentType(src.getClass()));
216         }       
217         
218         /**
219          * Multiplex multi-dimension array (x[][][]) to single-dimension array (x[])
220          * 
221          * @param src multi-dimension array
222          * @param dims
223          * @return single-dimension array
224          */
225         public static Object muxArray(Object src, int[] dims)
226         {
227                 return muxArray(src, dims, getComponentType(src.getClass()));
228         }       
229         
230         /**
231          * Multiplex multi-dimension array (x[][][]) to single-dimension array (x[])
232          * 
233          * @param src multi-dimension array
234          * @param dims
235          * @param componentType
236          * @return single-dimension array
237          */
238         public static Object muxArray(Object src, int[] dims, Class<?> componentType)
239         {
240                 int len = getLength(dims);
241                 Object dst = Array.newInstance(componentType, len);
242                 muxArray(src, dims, dst);
243                 return dst;
244         }
245         
246         /**
247          * Multiplexes multi-dimension array into a single-dimension array
248          * 
249          * @param src multi-dimension array
250          * @param dims dimensions
251          * @param dst single-dimension array
252          */
253         public static void muxArray(Object src, int[] dims, Object dst)
254         {
255                 int len = getLength(dims);
256                 if (Array.getLength(dst) != len) 
257                         throw new IllegalArgumentException("The length of src does not match the length of dst");
258                 
259                 _fillMux(0, dims, src, dst, 0);
260         }
261         
262         private static int _fillMux(int lvl, int[] dims, Object src, Object dst, int dstIndex)
263         {
264                 if (lvl == dims.length-1)
265                 {
266                         int len = dims[lvl];
267                         System.arraycopy(src, 0, dst, dstIndex, len);
268                         return dstIndex + len;
269                 }
270                 
271                 for (int i=0; i<dims[lvl]; i++)
272                         dstIndex += _fillMux(lvl+1, dims, Array.get(src, i), dst, dstIndex);
273                 
274                 return 0;
275         }
276         
277         public static <R> ArrayIterator<R> arrayIterator(Object array, int[] dimLens)
278         {
279                 return new ArrayIterator<R>(array, dimLens);
280         }
281         
282         public static class ArrayIterator<T> implements Iterator<T>
283         {
284                 Object v;
285                 int[] dims;
286                 int[] indices;
287                 Object[] arrays;
288                 int lastIndex, len;
289                 boolean hasNext = true;
290                 
291                 ArrayIterator(Object array, int[] dimLens)
292                 {
293                         this.v = array;
294                         this.dims = dimLens;
295                         this.indices = new int[dimLens.length];
296                         this.arrays = new Object[dimLens.length];
297                         lastIndex = dimLens.length-1;
298                         @SuppressWarnings("unused")
299                         int len = dimLens[0];
300                         for (int i=0; i<=lastIndex; i++)
301                                 if (dimLens[i]==0) hasNext = false;
302                         for (int i=1; i<=lastIndex; i++) 
303                                 len *= dimLens[i];
304                         arrays[0] = (Object[]) v;
305                         for (int i=1; i<dimLens.length; i++)
306                                 arrays[i] = ((Object[])arrays[i-1])[0];                         
307                 }
308                 
309                 public int[] getIndices()
310                 {
311                         return indices;                 
312                 }
313                 
314                 @Override
315                 public boolean hasNext() {
316                         return hasNext;
317                 }
318
319                 private void _next() {
320                         int index = lastIndex;                  
321                         while (++indices[index] >= dims[index])
322                         {
323                                 indices[index] = 0;
324                                 index--;
325                                 if (index<0) {
326                                         hasNext = false;
327                                         return;
328                                 }
329                                 arrays[index+1] = ((Object[]) arrays[index])[indices[index]];
330                         }
331                         if (index<lastIndex)
332                                 for (int i=index+1; i<=lastIndex; i++)
333                                         arrays[i] = ((Object[])arrays[i-1])[indices[i-1]];                      
334                 }
335                 
336                 @SuppressWarnings("unchecked")
337                 @Override
338                 public T next() {
339                         if (!hasNext)
340                                 throw new NoSuchElementException();
341                         
342                         T result = (T) Array.get(Array.get(arrays, lastIndex), indices[lastIndex]);
343                         _next();
344                         return result;
345                 }
346
347                 @Override
348                 public void remove() {
349                         throw new UnsupportedOperationException("Cannot remove array element");
350                 }               
351         }
352
353 }