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