/* * This file is a part of Alchemy OS project. * Copyright (C) 2013-2014, Sergey Basalaev <sbasalaev@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package alchemy.util; import alchemy.system.AlchemyException; import alchemy.system.Function; import alchemy.system.Process; import alchemy.system.ProcessKilledException; import alchemy.types.Float32; import alchemy.types.Float64; import alchemy.types.Int32; import alchemy.types.Int64; /** * Array-related functions. * This class provides functions to work with object arrays * and primitive arrays alike. * * @author Sergey Basalaev */ public final class Arrays { private Arrays() { } /** An instance of zero-size array. */ public static final Object[] EMPTY = new Object[0]; /** Constant for array type switches. */ public static final int AR_OBJECT = 'L'; /** Constant for array type switches. */ public static final int AR_BOOLEAN = 'Z'; /** Constant for array type switches. */ public static final int AR_BYTE = 'B'; /** Constant for array type switches. */ public static final int AR_CHAR = 'C'; /** Constant for array type switches. */ public static final int AR_SHORT = 'S'; /** Constant for array type switches. */ public static final int AR_INT = 'I'; /** Constant for array type switches. */ public static final int AR_LONG = 'J'; /** Constant for array type switches. */ public static final int AR_FLOAT = 'F'; /** Constant for array type switches. */ public static final int AR_DOUBLE = 'D'; /** * Copies portion of one array into another. * This method handles the cases when one of arrays * is Object[] and another is array of primitives. */ public static void arrayCopy(Object src, int srcofs, Object dest, int dstofs, int len) { int srctype = src.getClass().getName().charAt(1); int desttype = dest.getClass().getName().charAt(1); if (srctype == desttype) { try { System.arraycopy(src, srcofs, dest, dstofs, len); return; } catch (ArrayStoreException ase) { throw new ClassCastException("Arrays of different types"); } } else if (srctype == AR_OBJECT) { Object[] array = (Object[]) src; switch (desttype) { case AR_BOOLEAN: { boolean[] za = (boolean[]) dest; for (int i=0; i<len; i++) { za[dstofs+i] = array[srcofs+i] == Int32.ONE; } return; } case AR_BYTE: { byte[] ba = (byte[]) dest; for (int i=0; i<len; i++) { ba[dstofs+i] = (byte) ((Int32)array[srcofs+i]).value; } return; } case AR_CHAR: { char[] ca = (char[]) dest; for (int i=0; i<len; i++) { ca[dstofs+i] = (char) ((Int32)array[srcofs+i]).value; } return; } case AR_SHORT: { short[] sa = (short[]) dest; for (int i=0; i<len; i++) { sa[dstofs+i] = (short) ((Int32)array[srcofs+i]).value; } return; } case AR_INT: { int[] ia = (int[]) dest; for (int i=0; i<len; i++) { ia[dstofs+i] = ((Int32)array[srcofs+i]).value; } return; } case AR_LONG: { long[] la = (long[]) dest; for (int i=0; i<len; i++) { la[dstofs+i] = ((Int64)array[srcofs+i]).value; } return; } case AR_FLOAT: { float[] fa = (float[]) dest; for (int i=0; i<len; i++) { fa[dstofs+i] = ((Float32)array[srcofs+i]).value; } return; } case AR_DOUBLE: { double[] da = (double[]) dest; for (int i=0; i<len; i++) { da[dstofs+i] = ((Float64)array[srcofs+i]).value; } return; } } } else if (desttype == AR_OBJECT) { Object[] array = (Object[]) dest; switch (srctype) { case AR_BOOLEAN: { boolean[] za = (boolean[]) src; for (int i=0; i<len; i++) { array[dstofs+i] = za[i] ? Int32.ONE : Int32.ZERO; } return; } case AR_BYTE: { byte[] ba = (byte[]) src; for (int i=0; i<len; i++) { array[dstofs+i] = Int32.toInt32(ba[i]); } return; } case AR_CHAR: { char[] ca = (char[]) src; for (int i=0; i<len; i++) { array[dstofs+i] = Int32.toInt32(ca[i]); } return; } case AR_SHORT: { short[] sa = (short[]) src; for (int i=0; i<len; i++) { array[dstofs+i] = Int32.toInt32(sa[i]); } return; } case AR_INT: { int[] ia = (int[]) src; for (int i=0; i<len; i++) { array[dstofs+i] = Int32.toInt32(ia[i]); } return; } case AR_LONG: { long[] la = (long[]) src; for (int i=0; i<len; i++) { array[dstofs+i] = new Int64(la[i]); } return; } case AR_FLOAT: { float[] fa = (float[]) src; for (int i=0; i<len; i++) { array[dstofs+i] = new Float32(fa[i]); } return; } case AR_DOUBLE: { double[] da = (double[]) src; for (int i=0; i<len; i++) { array[dstofs+i] = new Float64(da[i]); } return; } } } throw new ClassCastException("Not an array"); } /** Returns length of array object. */ public static int arrayLength(Object array) { switch (array.getClass().getName().charAt(1)) { case AR_OBJECT: return ((Object[])array).length; case AR_BOOLEAN: return ((boolean[])array).length; case AR_BYTE: return ((byte[])array).length; case AR_CHAR: return ((char[])array).length; case AR_SHORT: return ((short[])array).length; case AR_INT: return ((int[])array).length; case AR_LONG: return ((long[])array).length; case AR_FLOAT: return ((float[])array).length; case AR_DOUBLE: return ((double[])array).length; default: throw new ClassCastException("Not an array"); } } public static void arraySet(Object array, int index, Object obj) { switch (array.getClass().getName().charAt(1)) { case AR_OBJECT: ((Object[])array)[index] = obj; return; case AR_BOOLEAN: ((boolean[])array)[index] = obj != Int32.ZERO; return; case AR_BYTE: ((byte[])array)[index] = (byte)((Int32)obj).value; return; case AR_CHAR: ((char[])array)[index] = (char)((Int32)obj).value; return; case AR_SHORT: ((short[])array)[index] = (short)((Int32)obj).value; return; case AR_INT: ((int[])array)[index] = ((Int32)obj).value; return; case AR_LONG: ((long[])array)[index] = ((Int64)obj).value; return; case AR_FLOAT: ((float[])array)[index] = ((Float32)obj).value; return; case AR_DOUBLE: ((double[])array)[index] = ((Float64)obj).value; return; default: throw new ClassCastException("Not an array"); } } public static Object arrayGet(Object array, int index) { switch (array.getClass().getName().charAt(1)) { case AR_OBJECT: return ((Object[])array)[index]; case AR_BOOLEAN: return ((boolean[])array)[index] ? Int32.ONE : Int32.ZERO; case AR_BYTE: return Int32.toInt32(((byte[])array)[index]); case AR_CHAR: return Int32.toInt32(((char[])array)[index]); case AR_SHORT: return Int32.toInt32(((short[])array)[index]); case AR_INT: return Int32.toInt32(((int[])array)[index]); case AR_LONG: return new Int64(((long[])array)[index]); case AR_FLOAT: return new Float32(((float[])array)[index]); case AR_DOUBLE: return new Float64(((double[])array)[index]); default: throw new ClassCastException("Not an array"); } } /** Returns new multidimensional array. */ public static Object newMultiArray(int[] sizes, int type) { if (sizes.length == 0) throw new IllegalArgumentException(); return newMultiArray(sizes, type, 0); } private static Object newMultiArray(int[] sizes, int type, int level) { if (level == sizes.length-1) { switch (type) { case AR_OBJECT: return new Object[sizes[level]]; case AR_BOOLEAN: return new boolean[sizes[level]]; case AR_BYTE: return new byte[sizes[level]]; case AR_CHAR: return new char[sizes[level]]; case AR_SHORT: return new short[sizes[level]]; case AR_INT: return new int[sizes[level]]; case AR_LONG: return new long[sizes[level]]; case AR_FLOAT: return new float[sizes[level]]; case AR_DOUBLE: return new double[sizes[level]]; default: throw new IllegalArgumentException(); } } else { Object[] array = new Object[sizes[level]]; for (int i=0; i<sizes[level]; i++) { array[i] = newMultiArray(sizes, type, level+1); } return array; } } /** Performs quick sort of array in given range using given implementation. */ public static void qsort(Object[] array, int low, int high, Process p, Function f) throws AlchemyException, ProcessKilledException { if (low >= high) return; int i = low; int j = high; Object x = array[(low+high)/2]; while(i <= j) { while(((Int32)f.invoke(p, new Object[] {array[i],x})).value < 0) i++; while(((Int32)f.invoke(p, new Object[] {array[j],x})).value > 0) j--; if (i <= j) { Object tmp = array[i]; array[i] = array[j]; array[j] = tmp; i++; j--; } } if (low < j) qsort(array, low, j, p, f); if (i < high) qsort(array, i, high, p, f); } /** Performs quick sort of array in given range. */ public static void qsort(byte[] array, int low, int high) { if (low >= high) return; int i = low; int j = high; byte x = array[(low+high)/2]; while(i <= j) { while(array[i] < x) i++; while(array[j] > x) j--; if (i <= j) { byte tmp = array[i]; array[i] = array[j]; array[j] = tmp; i++; j--; } } if (low < j) qsort(array, low, j); if (i < high) qsort(array, i, high); } /** Performs quick sort of array in given range. */ public static void qsort(short[] array, int low, int high) { if (low >= high) return; int i = low; int j = high; short x = array[(low+high)/2]; while(i <= j) { while(array[i] < x) i++; while(array[j] > x) j--; if (i <= j) { short tmp = array[i]; array[i] = array[j]; array[j] = tmp; i++; j--; } } if (low < j) qsort(array, low, j); if (i < high) qsort(array, i, high); } /** Performs quick sort of array in given range. */ public static void qsort(char[] array, int low, int high) { if (low >= high) return; int i = low; int j = high; char x = array[(low+high)/2]; while(i <= j) { while(array[i] < x) i++; while(array[j] > x) j--; if (i <= j) { char tmp = array[i]; array[i] = array[j]; array[j] = tmp; i++; j--; } } if (low < j) qsort(array, low, j); if (i < high) qsort(array, i, high); } /** Performs quick sort of array in given range. */ public static void qsort(int[] array, int low, int high) { if (low >= high) return; int i = low; int j = high; int x = array[(low+high)/2]; while(i <= j) { while(array[i] < x) i++; while(array[j] > x) j--; if (i <= j) { int tmp = array[i]; array[i] = array[j]; array[j] = tmp; i++; j--; } } if (low < j) qsort(array, low, j); if (i < high) qsort(array, i, high); } /** Performs quick sort of array in given range. */ public static void qsort(long[] array, int low, int high) { if (low >= high) return; int i = low; int j = high; long x = array[(low+high)/2]; while(i <= j) { while(array[i] < x) i++; while(array[j] > x) j--; if (i <= j) { long tmp = array[i]; array[i] = array[j]; array[j] = tmp; i++; j--; } } if (low < j) qsort(array, low, j); if (i < high) qsort(array, i, high); } /** Performs quick sort of array in given range. */ public static void qsort(float[] array, int low, int high) { if (low >= high) return; int i = low; int j = high; float x = array[(low+high)/2]; while(i <= j) { while(array[i] < x) i++; while(array[j] > x) j--; if (i <= j) { float tmp = array[i]; array[i] = array[j]; array[j] = tmp; i++; j--; } } if (low < j) qsort(array, low, j); if (i < high) qsort(array, i, high); } /** Performs quick sort of array in given range. */ public static void qsort(double[] array, int low, int high) { if (low >= high) return; int i = low; int j = high; double x = array[(low+high)/2]; while(i <= j) { while(array[i] < x) i++; while(array[j] > x) j--; if (i <= j) { double tmp = array[i]; array[i] = array[j]; array[j] = tmp; i++; j--; } } if (low < j) qsort(array, low, j); if (i < high) qsort(array, i, high); } }