71f95a47dcce61f48cfb0d48a5933290859318de
[scilab.git] / scilab / modules / external_objects_java / src / java / org / scilab / modules / external_objects_java / ScilabJavaArray.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - 2011 - Calixte DENIZET <calixte@contrib.scilab.org>
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 package org.scilab.modules.external_objects_java;
14
15 import java.lang.reflect.Array;
16 import java.lang.reflect.Field;
17 import java.lang.reflect.Method;
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.LinkedList;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.logging.Level;
24
25 /**
26  * Tools for arrays
27  *
28  * @author Calixte DENIZET
29  */
30 @SuppressWarnings(value = {"unchecked", "serial"})
31 public final class ScilabJavaArray {
32
33     static final Map<Class, Class> mappings = new HashMap<Class, Class>(8);
34     private static final Map<String, Class> baseType = new HashMap<String, Class>(8);
35
36     static {
37         mappings.put(Double.class, double.class);
38         mappings.put(Integer.class, int.class);
39         mappings.put(Boolean.class, boolean.class);
40         mappings.put(Short.class, short.class);
41         mappings.put(Byte.class, byte.class);
42         mappings.put(Character.class, char.class);
43         mappings.put(Long.class, long.class);
44         mappings.put(Float.class, float.class);
45
46         baseType.put("double", double.class);
47         baseType.put("int", int.class);
48         baseType.put("boolean", boolean.class);
49         baseType.put("short", short.class);
50         baseType.put("long", long.class);
51         baseType.put("float", float.class);
52         baseType.put("char", char.class);
53         baseType.put("byte", byte.class);
54     }
55
56     /**
57      * Create a wrapper for a Java Array object
58      * @param className the class to use
59      * @param dims the dimensions of the resulting array
60      * @param the id of the array
61      */
62     public static int newInstance(String className, int[] dims) throws ScilabJavaException {
63         Class cl = null;
64
65         if (ScilabJavaObject.debug) {
66             StringBuffer buf = new StringBuffer();
67             buf.append("(");
68             if (dims.length > 0) {
69                 int i = 0;
70                 for (; i < dims.length - 1; i++) {
71                     buf.append(Integer.toString(dims[i]));
72                     buf.append(",");
73                 }
74                 buf.append(Integer.toString(dims[i]));
75             }
76             buf.append(")");
77             ScilabJavaObject.logger.log(Level.INFO, "Array creation: base class is \'" + className + "\' with dims=" + buf.toString());
78         }
79
80         cl = baseType.get(className);
81         if (cl == null) {
82             try {
83                 int id = ScilabClassLoader.loadJavaClass(className, false);
84                 if (id == 0) {
85                     cl = (Class) ScilabJavaObject.arraySJO[id].object;
86                 } else {
87                     cl = Class.forName(className);
88                 }
89             } catch (ClassNotFoundException e) {
90                 throw new ScilabJavaException("Cannot find the class " + className);
91             }
92         }
93
94         return new ScilabJavaObject(Array.newInstance(cl, dims)).id;
95     }
96
97     /**
98      * Get an element in an array
99      * @param array the array
100      * @param index the index of the element to get
101      * @return the element
102      */
103     public static Object get(Object array, int[] index) throws ScilabJavaException {
104         Object obj = array;
105         for (int i = 0; i < index.length; i++) {
106             if (obj != null && obj.getClass().isArray()) {
107                 if (index[i] >= 0 && index[i] < Array.getLength(obj)) {
108                     obj = Array.get(obj, index[i]);
109                 } else {
110                     throw new ScilabJavaException("Problem in retrieving " + i + "-th element: " + index[i] + ">" + (Array.getLength(obj) - 1));
111                 }
112             } else if (obj instanceof List) {
113                 List list = (List) obj;
114                 if (index[i] >= 0 && index[i] < list.size()) {
115                     obj = list.get(index[i]);
116                 } else {
117                     throw new ScilabJavaException("Problem in retrieving " + i + "-th element: " + index[i] + ">" + (list.size() - 1));
118                 }
119             } else {
120                 throw new ScilabJavaException("Problem in retrieving " + i + "-th element: it is not an array");
121             }
122         }
123
124         return obj;
125     }
126
127     /**
128      * Set an element in an array
129      * @param array the array
130      * @param index the index of the element to set
131      * @param x the element
132      */
133     public static void set(Object array, int[] index, Object x) throws ScilabJavaException {
134         Object obj = array;
135         int i = 0;
136         for (; i < index.length - 1; i++) {
137             if (obj != null && obj.getClass().isArray()) {
138                 if (index[i] >= 0 && index[i] < Array.getLength(obj)) {
139                     obj = Array.get(obj, index[i]);
140                 } else {
141                     throw new ScilabJavaException("Problem in retrieving " + i + "-th element: " + index[i] + ">" + (Array.getLength(obj) - 1));
142                 }
143             } else if (obj instanceof List) {
144                 List list = (List) obj;
145                 if (index[i] >= 0 && index[i] < list.size()) {
146                     obj = list.get(index[i]);
147                 } else {
148                     throw new ScilabJavaException("Problem in retrieving " + i + "-th element: " + index[i] + ">" + (list.size() - 1));
149                 }
150             } else {
151                 throw new ScilabJavaException("Problem in retrieving " + i + "-th element: it is not an array");
152             }
153         }
154
155         if (obj != null && obj.getClass().isArray()) {
156             if (index[i] >= 0 && index[i] < Array.getLength(obj)) {
157                 try {
158                     Array.set(obj, index[i], x);
159                 } catch (IllegalArgumentException e) {
160                     throw new ScilabJavaException("Array " + obj + " cannot contain object which is an instance of " + x.getClass());
161                 }
162             } else {
163                 throw new ScilabJavaException("Problem in setting " + index[i] + "-th element: " + index[i] + ">" + (Array.getLength(obj) - 1));
164             }
165         } else if (obj instanceof List) {
166             List list = (List) obj;
167             if (index[i] >= 0 && index[i] < list.size()) {
168                 list.set(index[i], x);
169             } else if (index[i] == list.size()) {
170                 list.add(x);
171             } else {
172                 throw new ScilabJavaException("Problem in retrieving " + i + "-th element: " + index[i] + ">" + (list.size() - 1));
173             }
174         } else {
175             throw new ScilabJavaException("Problem in retrieving " + i + "-th element: it is not an array");
176         }
177     }
178
179     /**
180      * Unbox a Double array
181      * @param a an array
182      * @return an unboxed array
183      */
184     public static double[] toPrimitive(final Double[] a) {
185         double[] arr = new double[a.length];
186         for (int i = 0; i < a.length; i++) {
187             arr[i] = a[i];
188         }
189
190         return arr;
191     }
192
193     /**
194      * Unbox a Float array
195      * @param a an array
196      * @return an unboxed array
197      */
198     public static float[] toPrimitive(final Float[] a) {
199         float[] arr = new float[a.length];
200         for (int i = 0; i < a.length; i++) {
201             arr[i] = a[i];
202         }
203
204         return arr;
205     }
206
207     /**
208      * Unbox an Integer array
209      * @param a an array
210      * @return an unboxed array
211      */
212     public static int[] toPrimitive(final Integer[] a) {
213         int[] arr = new int[a.length];
214         for (int i = 0; i < a.length; i++) {
215             arr[i] = a[i];
216         }
217
218         return arr;
219     }
220
221     /**
222      * Unbox a Character array
223      * @param a an array
224      * @return an unboxed array
225      */
226     public static char[] toPrimitive(final Character[] a) {
227         char[] arr = new char[a.length];
228         for (int i = 0; i < a.length; i++) {
229             arr[i] = a[i];
230         }
231
232         return arr;
233     }
234
235     /**
236      * Unbox a Double array
237      * @param a an array
238      * @return an unboxed array
239      */
240     public static byte[] toPrimitive(final Byte[] a) {
241         byte[] arr = new byte[a.length];
242         for (int i = 0; i < a.length; i++) {
243             arr[i] = a[i];
244         }
245
246         return arr;
247     }
248
249     /**
250      * Unbox a Short array
251      * @param a an array
252      * @return an unboxed array
253      */
254     public static short[] toPrimitive(final Short[] a) {
255         short[] arr = new short[a.length];
256         for (int i = 0; i < a.length; i++) {
257             arr[i] = a[i];
258         }
259
260         return arr;
261     }
262
263     /**
264      * Unbox a Long array
265      * @param a an array
266      * @return an unboxed array
267      */
268     public static long[] toPrimitive(final Long[] a) {
269         long[] arr = new long[a.length];
270         for (int i = 0; i < a.length; i++) {
271             arr[i] = a[i];
272         }
273
274         return arr;
275     }
276
277     /**
278      * Unbox a Boolean array
279      * @param a an array
280      * @return an unboxed array
281      */
282     public static boolean[] toPrimitive(final Boolean[] a) {
283         boolean[] arr = new boolean[a.length];
284         for (int i = 0; i < a.length; i++) {
285             arr[i] = a[i];
286         }
287
288         return arr;
289     }
290
291     /**
292      * Convert a Double (or other type of the same kind) multiarray into a primitive double multiarray.
293      * (Take care: it is not a high performance function !!! if you have a better implementation, send it to me...)
294      * @param the array to convert, allowed types are: Double, Float, Integer, Character, Byte, Boolean, Short, Long
295      * @return the primitive array.
296      */
297     public static Object toPrimitive(final Object a) {
298         Class base = a.getClass();
299         if (base.isArray()) {
300             Class[] types = getPrimClasses(base);
301             if (types == null) {
302                 return a;
303             }
304
305             if (types.length == 0) {
306                 try {
307                     Method m = ScilabJavaArray.class.getDeclaredMethod("toPrimitive", base);
308                     return m.invoke(null, a);
309                 } catch (Exception e) {
310                     return null;
311                 }
312             }
313
314             return toPrimitive(a, types.length - 1, types);
315         }
316
317         return a;
318     }
319
320     /**
321      * Recursively convert an array Double[][][] into an array double[][][]
322      * @param a the array
323      * @param pos the position in the array types
324      * @param types an array containing the intermediate array class (see getPrimClass)
325      * @return the converted array
326      */
327     private static Object toPrimitive(final Object a, int pos, Class[] types) {
328         Object[] arr = (Object[]) a;
329         Object[] o = (Object[]) Array.newInstance(types[pos], arr.length);
330
331         if (pos != 0) {
332             for (int i = 0; i < arr.length; i++) {
333                 o[i] = toPrimitive(arr[i], pos - 1, types);
334             }
335         } else {
336             try {
337                 Method m = ScilabJavaArray.class.getDeclaredMethod("toPrimitive", a.getClass().getComponentType());
338                 for (int i = 0; i < arr.length; i++) {
339                     o[i] = m.invoke(null, arr[i]);
340                 }
341             } catch (Exception e) {
342                 return null;
343             }
344         }
345
346         return o;
347     }
348
349     /**
350      * Box a double array
351      * @param a an array
352      * @return a boxed array
353      */
354     public static Double[] fromPrimitive(final double[] a) {
355         Double[] arr = new Double[a.length];
356         for (int i = 0; i < a.length; i++) {
357             arr[i] = a[i];
358         }
359
360         return arr;
361     }
362
363     /**
364      * Box a float array
365      * @param a an array
366      * @return a boxed array
367      */
368     public static Float[] fromPrimitive(final float[] a) {
369         Float[] arr = new Float[a.length];
370         for (int i = 0; i < a.length; i++) {
371             arr[i] = a[i];
372         }
373
374         return arr;
375     }
376
377     /**
378      * Box an int array
379      * @param a an array
380      * @return a boxed array
381      */
382     public static Integer[] fromPrimitive(final int[] a) {
383         Integer[] arr = new Integer[a.length];
384         for (int i = 0; i < a.length; i++) {
385             arr[i] = a[i];
386         }
387
388         return arr;
389     }
390
391     /**
392      * Box a char array
393      * @param a an array
394      * @return a boxed array
395      */
396     public static Character[] fromPrimitive(final char[] a) {
397         Character[] arr = new Character[a.length];
398         for (int i = 0; i < a.length; i++) {
399             arr[i] = a[i];
400         }
401
402         return arr;
403     }
404
405     /**
406      * Box a double array
407      * @param a an array
408      * @return a boxed array
409      */
410     public static Byte[] fromPrimitive(final byte[] a) {
411         Byte[] arr = new Byte[a.length];
412         for (int i = 0; i < a.length; i++) {
413             arr[i] = a[i];
414         }
415
416         return arr;
417     }
418
419     /**
420      * Box a short array
421      * @param a an array
422      * @return a boxed array
423      */
424     public static Short[] fromPrimitive(final short[] a) {
425         Short[] arr = new Short[a.length];
426         for (int i = 0; i < a.length; i++) {
427             arr[i] = a[i];
428         }
429
430         return arr;
431     }
432
433     /**
434      * Box a long array
435      * @param a an array
436      * @return a boxed array
437      */
438     public static Long[] fromPrimitive(final long[] a) {
439         Long[] arr = new Long[a.length];
440         for (int i = 0; i < a.length; i++) {
441             arr[i] = a[i];
442         }
443
444         return arr;
445     }
446
447     /**
448      * Box a boolean array
449      * @param a an array
450      * @return a boxed array
451      */
452     public static Boolean[] fromPrimitive(final boolean[] a) {
453         Boolean[] arr = new Boolean[a.length];
454         for (int i = 0; i < a.length; i++) {
455             arr[i] = a[i];
456         }
457
458         return arr;
459     }
460
461     /**
462      * Convert a double (or other type of the same kind) multiarray into a primitive Double multiarray.
463      * (Take care: it is not a high performance function !!! if you have a better implementation, send it to me...)
464      * @param the array to convert, allowed types are: double, float, int, char, byte, boolean, short, long
465      * @return the primitive array.
466      */
467     public static Object fromPrimitive(final Object a) {
468         Class base = a.getClass();
469         if (base.isArray()) {
470             Class[] types = getFromPrimClasses(base);
471             if (types == null) {
472                 return a;
473             }
474
475             if (types.length == 0) {
476                 try {
477                     Method m = ScilabJavaArray.class.getDeclaredMethod("fromPrimitive", base);
478                     return m.invoke(null, a);
479                 } catch (Exception e) {
480                     return null;
481                 }
482             }
483
484             return fromPrimitive(a, types.length - 1, types);
485         }
486
487         return a;
488     }
489
490     /**
491      * Recursively convert an array double[][][] into an array Double[][][]
492      * @param a the array
493      * @param pos the position in the array types
494      * @param types an array containing the intermediate array class (see getPrimClass)
495      * @return the converted array
496      */
497     private static Object fromPrimitive(final Object a, int pos, Class[] types) {
498         Object[] arr = (Object[]) a;
499         Object[] o = (Object[]) Array.newInstance(types[pos], arr.length);
500
501         if (pos != 0) {
502             for (int i = 0; i < arr.length; i++) {
503                 o[i] = fromPrimitive(arr[i], pos - 1, types);
504             }
505         } else {
506             try {
507                 Method m = ScilabJavaArray.class.getDeclaredMethod("fromPrimitive", a.getClass().getComponentType());
508                 for (int i = 0; i < arr.length; i++) {
509                     o[i] = m.invoke(null, arr[i]);
510                 }
511             } catch (Exception e) {
512                 return null;
513             }
514         }
515
516         return o;
517     }
518
519     public static Class getArrayBaseType(Class c) {
520         Class base = c;
521         while (base.isArray()) {
522             base = base.getComponentType();
523         }
524
525         return base;
526     }
527
528     /**
529      * Get an array of primitive arrays classes. For example, double[][][][] will give {Double[], Double[][], Double[][][]}.
530      * @param c the base class
531      * @return an array of classes
532      */
533     private static Class[] getFromPrimClasses(Class c) {
534         int nbDims = 0;
535         Class base = c;
536         while (base.isArray()) {
537             base = base.getComponentType();
538             nbDims++;
539         }
540
541         base = ScilabJavaObject.primTypes.get(base);
542         if (base == null) {
543             return null;
544         }
545
546         Class[] cl = new Class[nbDims - 1];
547         if (cl.length != 0) {
548             cl[0] = Array.newInstance(base, 0).getClass();
549             for (int i = 1; i < nbDims - 1; i++) {
550                 cl[i] = Array.newInstance(cl[i - 1], 0).getClass();
551             }
552         }
553
554         return cl;
555     }
556
557     /**
558      * Get an array of primitive arrays classes. For example, Double[][][][] will give {double[], double[][], double[][][]}.
559      * @param c the base class
560      * @return an array of classes
561      */
562     private static Class[] getPrimClasses(Class c) {
563         int nbDims = 0;
564         Class base = c;
565         while (base.isArray()) {
566             base = base.getComponentType();
567             nbDims++;
568         }
569
570         base = mappings.get(base);
571         if (base == null) {
572             return null;
573         }
574
575         Class[] cl = new Class[nbDims - 1];
576         if (cl.length != 0) {
577             cl[0] = Array.newInstance(base, 0).getClass();
578             for (int i = 1; i < nbDims - 1; i++) {
579                 cl[i] = Array.newInstance(cl[i - 1], 0).getClass();
580             }
581         }
582
583         return cl;
584     }
585
586
587     /**
588      * Convert a list to an array of primitive type
589      * @return an array
590      */
591     public static double[] toDoubleArray(List<Double> l) {
592         double[] arr = new double[l.size()];
593         int i = 0;
594         for (Double d : l) {
595             arr[i++] = d;
596         }
597
598         return arr;
599     }
600
601     /**
602      * Convert a list to an array of primitive type
603      * @return an array
604      */
605     public static float[] toFloatArray(List<Float> l) {
606         float[] arr = new float[l.size()];
607         int i = 0;
608         for (Float f : l) {
609             arr[i++] = f;
610         }
611
612         return arr;
613     }
614
615     /**
616      * Convert a list to an array of primitive type
617      * @return an array
618      */
619     public static byte[] toByteArray(List<Byte> l) {
620         byte[] arr = new byte[l.size()];
621         int i = 0;
622         for (Byte b : l) {
623             arr[i++] = b;
624         }
625
626         return arr;
627     }
628
629     /**
630      * Convert a list to an array of primitive type
631      * @return an array
632      */
633     public static short[] toShortArray(List<Short> l) {
634         short[] arr = new short[l.size()];
635         int i = 0;
636         for (Short s : l) {
637             arr[i++] = s;
638         }
639
640         return arr;
641     }
642
643     /**
644      * Convert a list to an array of primitive type
645      * @return an array
646      */
647     public static int[] toIntArray(List<Integer> l) {
648         int[] arr = new int[l.size()];
649         int i = 0;
650         for (Integer in : l) {
651             arr[i++] = in;
652         }
653
654         return arr;
655     }
656
657     /**
658      * Convert a list to an array of primitive type
659      * @return an array
660      */
661     public static long[] toLongArray(List<Long> l) {
662         long[] arr = new long[l.size()];
663         int i = 0;
664         for (Long lo : l) {
665             arr[i++] = lo;
666         }
667
668         return arr;
669     }
670
671     /**
672      * Convert a list to an array of primitive type
673      * @return an array
674      */
675     public static String[] toStringArray(List<String> l) {
676         return l.toArray(new String[l.size()]);
677     }
678
679     /**
680      * Convert a list to an array of primitive type
681      * @return an array
682      */
683     public static boolean[] toBooleanArray(List<Boolean> l) {
684         boolean[] arr = new boolean[l.size()];
685         int i = 0;
686         for (Boolean b : l) {
687             arr[i++] = b;
688         }
689
690         return arr;
691     }
692
693     /**
694      * Convert a list to an array of primitive type
695      * @return an array
696      */
697     public static char[] toCharArray(List<Character> l) {
698         char[] arr = new char[l.size()];
699         int i = 0;
700         for (Character c : l) {
701             arr[i++] = c;
702         }
703
704         return arr;
705     }
706
707     /**
708      * Convert a list to an array of primitive type
709      * @return an array
710      */
711     public static List toList(Object obj) {
712         if (obj.getClass().isArray()) {
713             Class base = obj.getClass().getComponentType();
714             if (ScilabJavaObject.primTypes.containsKey(base)) {
715                 obj = fromPrimitive(obj);
716             }
717             ArrayList list = new ArrayList();
718             try {
719                 Field _elementData = ArrayList.class.getDeclaredField("elementData");
720                 Field _size = ArrayList.class.getDeclaredField("size");
721                 _elementData.setAccessible(true);
722                 _size.setAccessible(true);
723                 _elementData.set(list, obj);
724                 _size.set(list, ((Object[]) obj).length);
725             } catch (Exception e) {
726                 e.printStackTrace();
727             }
728
729             return list;
730         }
731
732         List l = new LinkedList();
733         l.add(obj);
734
735         return l;
736     }
737 }