Methods in Array are shared between different VMs, but other types like Integer, or Float, aren't. Need to be careful when using equality then
2 * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
26 package java.lang.reflect;
28 import org.apidesign.bck2brwsr.core.Exported;
29 import org.apidesign.bck2brwsr.core.JavaScriptBody;
30 import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
33 * The {@code Array} class provides static methods to dynamically create and
36 * <p>{@code Array} permits widening conversions to occur during a get or set
37 * operation, but throws an {@code IllegalArgumentException} if a narrowing
38 * conversion would occur.
40 * @author Nakul Saraiya
42 @JavaScriptPrototype(prototype = "new Array", container = "Array.prototype")
47 * Constructor. Class Array is not instantiable.
52 * Creates a new array with the specified component type and
54 * Invoking this method is equivalent to creating an array
59 * Array.newInstance(componentType, x);
63 * @param componentType the {@code Class} object representing the
64 * component type of the new array
65 * @param length the length of the new array
66 * @return the new array
67 * @exception NullPointerException if the specified
68 * {@code componentType} parameter is null
69 * @exception IllegalArgumentException if componentType is {@link Void#TYPE}
70 * @exception NegativeArraySizeException if the specified {@code length}
73 public static Object newInstance(Class<?> componentType, int length)
74 throws NegativeArraySizeException {
76 throw new NegativeArraySizeException();
78 String sig = Method.findArraySignature(componentType);
79 return newArray(componentType.isPrimitive(), sig, null, length);
84 * with the specified component type and dimensions.
85 * If {@code componentType}
86 * represents a non-array class or interface, the new array
87 * has {@code dimensions.length} dimensions and
88 * {@code componentType} as its component type. If
89 * {@code componentType} represents an array class, the
90 * number of dimensions of the new array is equal to the sum
91 * of {@code dimensions.length} and the number of
92 * dimensions of {@code componentType}. In this case, the
93 * component type of the new array is the component type of
94 * {@code componentType}.
96 * <p>The number of dimensions of the new array must not
97 * exceed the number of array dimensions supported by the
98 * implementation (typically 255).
100 * @param componentType the {@code Class} object representing the component
101 * type of the new array
102 * @param dimensions an array of {@code int} representing the dimensions of
104 * @return the new array
105 * @exception NullPointerException if the specified
106 * {@code componentType} argument is null
107 * @exception IllegalArgumentException if the specified {@code dimensions}
108 * argument is a zero-dimensional array, or if the number of
109 * requested dimensions exceeds the limit on the number of array dimensions
110 * supported by the implementation (typically 255), or if componentType
111 * is {@link Void#TYPE}.
112 * @exception NegativeArraySizeException if any of the components in
113 * the specified {@code dimensions} argument is negative.
115 public static Object newInstance(Class<?> componentType, int... dimensions)
116 throws IllegalArgumentException, NegativeArraySizeException {
117 StringBuilder sig = new StringBuilder();
118 for (int i = 1; i < dimensions.length; i++) {
121 sig.append(Method.findArraySignature(componentType));
122 return multiNewArray(sig.toString(), dimensions, 0);
126 * Returns the length of the specified array object, as an {@code int}.
128 * @param array the array
129 * @return the length of the array
130 * @exception IllegalArgumentException if the object argument is not
133 public static int getLength(Object array)
134 throws IllegalArgumentException {
135 if (!array.getClass().isArray()) {
136 throw new IllegalArgumentException("Argument is not an array");
138 return length(array);
141 @JavaScriptBody(args = { "arr" }, body = "return arr.length;")
142 private static native int length(Object arr);
145 * Returns the value of the indexed component in the specified
146 * array object. The value is automatically wrapped in an object
147 * if it has a primitive type.
149 * @param array the array
150 * @param index the index
151 * @return the (possibly wrapped) value of the indexed component in
152 * the specified array
153 * @exception NullPointerException If the specified object is null
154 * @exception IllegalArgumentException If the specified object is not
156 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
157 * argument is negative, or if it is greater than or equal to the
158 * length of the specified array
160 public static Object get(Object array, int index)
161 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
162 final Class<?> t = array.getClass().getComponentType();
163 if (t.isPrimitive()) {
164 return fromPrimitive(t, array, index);
166 return ((Object[])array)[index];
171 * Returns the value of the indexed component in the specified
172 * array object, as a {@code boolean}.
174 * @param array the array
175 * @param index the index
176 * @return the value of the indexed component in the specified array
177 * @exception NullPointerException If the specified object is null
178 * @exception IllegalArgumentException If the specified object is not
179 * an array, or if the indexed element cannot be converted to the
180 * return type by an identity or widening conversion
181 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
182 * argument is negative, or if it is greater than or equal to the
183 * length of the specified array
186 public static native boolean getBoolean(Object array, int index)
187 throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
190 * Returns the value of the indexed component in the specified
191 * array object, as a {@code byte}.
193 * @param array the array
194 * @param index the index
195 * @return the value of the indexed component in the specified array
196 * @exception NullPointerException If the specified object is null
197 * @exception IllegalArgumentException If the specified object is not
198 * an array, or if the indexed element cannot be converted to the
199 * return type by an identity or widening conversion
200 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
201 * argument is negative, or if it is greater than or equal to the
202 * length of the specified array
205 public static byte getByte(Object array, int index)
206 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
207 if (!Method.samePrimitive(array.getClass().getComponentType(), Byte.TYPE)) {
208 throw new IllegalArgumentException();
210 byte[] arr = (byte[]) array;
215 * Returns the value of the indexed component in the specified
216 * array object, as a {@code char}.
218 * @param array the array
219 * @param index the index
220 * @return the value of the indexed component in the specified array
221 * @exception NullPointerException If the specified object is null
222 * @exception IllegalArgumentException If the specified object is not
223 * an array, or if the indexed element cannot be converted to the
224 * return type by an identity or widening conversion
225 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
226 * argument is negative, or if it is greater than or equal to the
227 * length of the specified array
230 public static native char getChar(Object array, int index)
231 throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
234 * Returns the value of the indexed component in the specified
235 * array object, as a {@code short}.
237 * @param array the array
238 * @param index the index
239 * @return the value of the indexed component in the specified array
240 * @exception NullPointerException If the specified object is null
241 * @exception IllegalArgumentException If the specified object is not
242 * an array, or if the indexed element cannot be converted to the
243 * return type by an identity or widening conversion
244 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
245 * argument is negative, or if it is greater than or equal to the
246 * length of the specified array
249 public static short getShort(Object array, int index)
250 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
251 final Class<?> t = array.getClass().getComponentType();
252 if (Method.samePrimitive(t, Short.TYPE)) {
253 short[] arr = (short[]) array;
256 return getByte(array, index);
260 * Returns the value of the indexed component in the specified
261 * array object, as an {@code int}.
263 * @param array the array
264 * @param index the index
265 * @return the value of the indexed component in the specified array
266 * @exception NullPointerException If the specified object is null
267 * @exception IllegalArgumentException If the specified object is not
268 * an array, or if the indexed element cannot be converted to the
269 * return type by an identity or widening conversion
270 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
271 * argument is negative, or if it is greater than or equal to the
272 * length of the specified array
275 public static int getInt(Object array, int index)
276 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
277 final Class<?> t = array.getClass().getComponentType();
278 if (Method.samePrimitive(t, Integer.TYPE)) {
279 int[] arr = (int[]) array;
282 return getShort(array, index);
286 * Returns the value of the indexed component in the specified
287 * array object, as a {@code long}.
289 * @param array the array
290 * @param index the index
291 * @return the value of the indexed component in the specified array
292 * @exception NullPointerException If the specified object is null
293 * @exception IllegalArgumentException If the specified object is not
294 * an array, or if the indexed element cannot be converted to the
295 * return type by an identity or widening conversion
296 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
297 * argument is negative, or if it is greater than or equal to the
298 * length of the specified array
301 public static long getLong(Object array, int index)
302 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
303 final Class<?> t = array.getClass().getComponentType();
304 if (Method.samePrimitive(t, Long.TYPE)) {
305 long[] arr = (long[]) array;
308 return getInt(array, index);
312 * Returns the value of the indexed component in the specified
313 * array object, as a {@code float}.
315 * @param array the array
316 * @param index the index
317 * @return the value of the indexed component in the specified array
318 * @exception NullPointerException If the specified object is null
319 * @exception IllegalArgumentException If the specified object is not
320 * an array, or if the indexed element cannot be converted to the
321 * return type by an identity or widening conversion
322 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
323 * argument is negative, or if it is greater than or equal to the
324 * length of the specified array
327 public static float getFloat(Object array, int index)
328 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
329 final Class<?> t = array.getClass().getComponentType();
330 if (Method.samePrimitive(t, Float.TYPE)) {
331 float[] arr = (float[]) array;
334 return getLong(array, index);
338 * Returns the value of the indexed component in the specified
339 * array object, as a {@code double}.
341 * @param array the array
342 * @param index the index
343 * @return the value of the indexed component in the specified array
344 * @exception NullPointerException If the specified object is null
345 * @exception IllegalArgumentException If the specified object is not
346 * an array, or if the indexed element cannot be converted to the
347 * return type by an identity or widening conversion
348 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
349 * argument is negative, or if it is greater than or equal to the
350 * length of the specified array
353 public static double getDouble(Object array, int index)
354 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
355 final Class<?> t = array.getClass().getComponentType();
356 if (Method.samePrimitive(t, Double.TYPE)) {
357 double[] arr = (double[]) array;
360 return getFloat(array, index);
364 * Sets the value of the indexed component of the specified array
365 * object to the specified new value. The new value is first
366 * automatically unwrapped if the array has a primitive component
368 * @param array the array
369 * @param index the index into the array
370 * @param value the new value of the indexed component
371 * @exception NullPointerException If the specified object argument
373 * @exception IllegalArgumentException If the specified object argument
374 * is not an array, or if the array component type is primitive and
375 * an unwrapping conversion fails
376 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
377 * argument is negative, or if it is greater than or equal to
378 * the length of the specified array
380 public static void set(Object array, int index, Object value)
381 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
382 if (array.getClass().getComponentType().isPrimitive()) {
383 throw new IllegalArgumentException();
385 Object[] arr = (Object[])array;
391 * Sets the value of the indexed component of the specified array
392 * object to the specified {@code boolean} value.
393 * @param array the array
394 * @param index the index into the array
395 * @param z the new value of the indexed component
396 * @exception NullPointerException If the specified object argument
398 * @exception IllegalArgumentException If the specified object argument
399 * is not an array, or if the specified value cannot be converted
400 * to the underlying array's component type by an identity or a
401 * primitive widening conversion
402 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
403 * argument is negative, or if it is greater than or equal to
404 * the length of the specified array
407 public static native void setBoolean(Object array, int index, boolean z)
408 throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
411 * Sets the value of the indexed component of the specified array
412 * object to the specified {@code byte} value.
413 * @param array the array
414 * @param index the index into the array
415 * @param b the new value of the indexed component
416 * @exception NullPointerException If the specified object argument
418 * @exception IllegalArgumentException If the specified object argument
419 * is not an array, or if the specified value cannot be converted
420 * to the underlying array's component type by an identity or a
421 * primitive widening conversion
422 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
423 * argument is negative, or if it is greater than or equal to
424 * the length of the specified array
427 public static void setByte(Object array, int index, byte b)
428 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
429 Class<?> t = array.getClass().getComponentType();
430 if (Method.samePrimitive(t, Byte.TYPE)) {
431 byte[] arr = (byte[]) array;
434 setShort(array, index, b);
439 * Sets the value of the indexed component of the specified array
440 * object to the specified {@code char} value.
441 * @param array the array
442 * @param index the index into the array
443 * @param c the new value of the indexed component
444 * @exception NullPointerException If the specified object argument
446 * @exception IllegalArgumentException If the specified object argument
447 * is not an array, or if the specified value cannot be converted
448 * to the underlying array's component type by an identity or a
449 * primitive widening conversion
450 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
451 * argument is negative, or if it is greater than or equal to
452 * the length of the specified array
455 public static native void setChar(Object array, int index, char c)
456 throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
459 * Sets the value of the indexed component of the specified array
460 * object to the specified {@code short} value.
461 * @param array the array
462 * @param index the index into the array
463 * @param s the new value of the indexed component
464 * @exception NullPointerException If the specified object argument
466 * @exception IllegalArgumentException If the specified object argument
467 * is not an array, or if the specified value cannot be converted
468 * to the underlying array's component type by an identity or a
469 * primitive widening conversion
470 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
471 * argument is negative, or if it is greater than or equal to
472 * the length of the specified array
475 public static void setShort(Object array, int index, short s)
476 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
477 Class<?> t = array.getClass().getComponentType();
478 if (Method.samePrimitive(t, Short.TYPE)) {
479 short[] arr = (short[]) array;
482 setInt(array, index, s);
488 * Sets the value of the indexed component of the specified array
489 * object to the specified {@code int} value.
490 * @param array the array
491 * @param index the index into the array
492 * @param i the new value of the indexed component
493 * @exception NullPointerException If the specified object argument
495 * @exception IllegalArgumentException If the specified object argument
496 * is not an array, or if the specified value cannot be converted
497 * to the underlying array's component type by an identity or a
498 * primitive widening conversion
499 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
500 * argument is negative, or if it is greater than or equal to
501 * the length of the specified array
504 public static void setInt(Object array, int index, int i)
505 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
506 Class<?> t = array.getClass().getComponentType();
507 if (Method.samePrimitive(t, Integer.TYPE)) {
508 int[] arr = (int[]) array;
511 setLong(array, index, i);
516 * Sets the value of the indexed component of the specified array
517 * object to the specified {@code long} value.
518 * @param array the array
519 * @param index the index into the array
520 * @param l the new value of the indexed component
521 * @exception NullPointerException If the specified object argument
523 * @exception IllegalArgumentException If the specified object argument
524 * is not an array, or if the specified value cannot be converted
525 * to the underlying array's component type by an identity or a
526 * primitive widening conversion
527 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
528 * argument is negative, or if it is greater than or equal to
529 * the length of the specified array
532 public static void setLong(Object array, int index, long l)
533 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
534 Class<?> t = array.getClass().getComponentType();
535 if (Method.samePrimitive(t, Long.TYPE)) {
536 long[] arr = (long[]) array;
539 setFloat(array, index, l);
544 * Sets the value of the indexed component of the specified array
545 * object to the specified {@code float} value.
546 * @param array the array
547 * @param index the index into the array
548 * @param f the new value of the indexed component
549 * @exception NullPointerException If the specified object argument
551 * @exception IllegalArgumentException If the specified object argument
552 * is not an array, or if the specified value cannot be converted
553 * to the underlying array's component type by an identity or a
554 * primitive widening conversion
555 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
556 * argument is negative, or if it is greater than or equal to
557 * the length of the specified array
560 public static void setFloat(Object array, int index, float f)
561 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
562 Class<?> t = array.getClass().getComponentType();
563 if (Method.samePrimitive(t, Float.TYPE)) {
564 float[] arr = (float[])array;
567 setDouble(array, index, f);
572 * Sets the value of the indexed component of the specified array
573 * object to the specified {@code double} value.
574 * @param array the array
575 * @param index the index into the array
576 * @param d the new value of the indexed component
577 * @exception NullPointerException If the specified object argument
579 * @exception IllegalArgumentException If the specified object argument
580 * is not an array, or if the specified value cannot be converted
581 * to the underlying array's component type by an identity or a
582 * primitive widening conversion
583 * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
584 * argument is negative, or if it is greater than or equal to
585 * the length of the specified array
588 public static void setDouble(Object array, int index, double d)
589 throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
590 Class<?> t = array.getClass().getComponentType();
591 if (Method.samePrimitive(t, Double.TYPE)) {
592 double[] arr = (double[])array;
595 throw new IllegalArgumentException("argument type mismatch");
603 @JavaScriptBody(args = { "primitive", "sig", "fn", "length" }, body =
604 "var arr = new Array(length);\n"
605 + "var value = primitive ? 0 : null;\n"
606 + "for(var i = 0; i < length; i++) arr[i] = value;\n"
607 + "arr.jvmName = sig;\n"
609 // + "java.lang.System.out.println('Assigned ' + arr.jvmName + ' fn: ' + (!!arr.fnc));\n"
613 private static native Object newArray(boolean primitive, String sig, Object fn, int length);
616 private static boolean isInstance(Object arr, String sig) {
620 return sig.equals(arr.getClass().getName());
624 private static boolean isInstance(Object arr, int dimensions, Object fn) throws ClassNotFoundException {
628 // log("isInstance for " + arr + " and " + dimensions);
629 Class<?> c = arr.getClass();
630 while (dimensions-- > 0) {
631 // log(" class: " + c);
632 c = c.getComponentType();
633 // log(" next class: " + c);
638 Class<?> t = classFromFn(fn);
639 // log(" to check: " + t);
640 return t.isAssignableFrom(c);
643 @JavaScriptBody(args = { "cntstr" }, body = "return cntstr(false).constructor.$class;")
644 private static native Class<?> classFromFn(Object cntstr);
646 // @JavaScriptBody(args = { "m" }, body = "java.lang.System.out.println(m.toString().toString());")
647 // private static native void log(Object m);
650 private static Object multiNewArray(String sig, int[] dims, Object fn)
651 throws IllegalArgumentException, NegativeArraySizeException {
652 return multiNewArray(sig, dims, 0, fn);
654 private static Object multiNewArray(String sig, int[] dims, int index, Object fn)
655 throws IllegalArgumentException, NegativeArraySizeException {
656 if (dims.length == index + 1) {
657 return newArray(sig.length() == 2, sig, fn, dims[index]);
659 Object arr = newArray(false, sig, null, dims[index]);
660 String compsig = sig.substring(1);
661 int len = getLength(arr);
662 for (int i = 0; i < len; i++) {
663 setArray(arr, i, multiNewArray(compsig, dims, index + 1, fn));
667 private static Object fromPrimitive(Class<?> t, Object array, int index) {
668 return Method.fromPrimitive(t, atArray(array, index));
671 @JavaScriptBody(args = { "array", "index" }, body = "return array[index];")
672 private static native Object atArray(Object array, int index);
674 @JavaScriptBody(args = { "array", "index", "v" }, body = "array[index] = v;")
675 private static native Object setArray(Object array, int index, Object v);