package de.take_weiland.mods.commons.nbt; import com.google.common.base.Throwables; import de.take_weiland.mods.commons.asm.MCPNames; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagByteArray; import net.minecraft.nbt.NBTTagIntArray; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import static java.lang.invoke.MethodType.methodType; /** * @author diesieben07 */ final class ArrayConversions { private ArrayConversions() { } static MethodHandle getReader(Class<?> arrClass) { Class<?> repr; MethodHandle read; if (arrClass == boolean[].class || arrClass == short[].class || arrClass == char[].class) { repr = byte[].class; read = readByteArr(); } else { repr = int[].class; read = readIntArr(); } if (repr != arrClass) { MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle conv; try { conv = lookup.findStatic(ArrayConversions.class, "d" + arrClass.getComponentType().getName(), methodType(arrClass, repr)); } catch (ReflectiveOperationException e) { throw Throwables.propagate(e); } read = MethodHandles.filterReturnValue(read, conv); } return read; } static MethodHandle getWriter(Class<?> arrClass) { Class<?> repr; MethodHandle write; if (arrClass == boolean[].class || arrClass == short[].class || arrClass == char[].class) { repr = byte[].class; write = writeByteArr(); } else { repr = int[].class; write = writeIntArr(); } if (repr != arrClass) { MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle conv; try { conv = lookup.findStatic(ArrayConversions.class, "e" + arrClass.getComponentType().getName(), methodType(repr, arrClass)); } catch (ReflectiveOperationException e) { throw Throwables.propagate(e); } write = MethodHandles.filterArguments(write, 0, conv); } return write; } private static MethodHandle WR_BYTE_ARR; private static MethodHandle RE_BYTE_ARR; private static MethodHandle WR_INT_ARR; private static MethodHandle RE_INT_ARR; private static MethodHandle writeByteArr() { if (WR_BYTE_ARR == null) { try { WR_BYTE_ARR = MethodHandles.publicLookup() .findConstructor(NBTTagByteArray.class, methodType(void.class, String.class, byte[].class)) .bindTo("") .asType(methodType(NBTBase.class, byte[].class)); } catch (ReflectiveOperationException e) { throw Throwables.propagate(e); } } return WR_BYTE_ARR; } private static MethodHandle readByteArr() { if (RE_BYTE_ARR == null) { try { RE_BYTE_ARR = MethodHandles.publicLookup() .findGetter(NBTTagByteArray.class, MCPNames.field(MCPNames.F_NBT_BYTE_ARR_DATA), byte[].class); } catch (ReflectiveOperationException e) { throw Throwables.propagate(e); } } return RE_BYTE_ARR; } private static MethodHandle writeIntArr() { if (WR_INT_ARR == null) { try { WR_INT_ARR = MethodHandles.publicLookup() .findConstructor(NBTTagIntArray.class, methodType(void.class, String.class, int[].class)) .bindTo("") .asType(methodType(NBTBase.class, int[].class)); } catch (ReflectiveOperationException e) { throw Throwables.propagate(e); } } return WR_INT_ARR; } private static MethodHandle readIntArr() { if (RE_INT_ARR == null) { try { RE_INT_ARR = MethodHandles.publicLookup() .findGetter(NBTTagIntArray.class, MCPNames.field(MCPNames.F_NBT_INT_ARR_DATA), int[].class); } catch (ReflectiveOperationException e) { throw Throwables.propagate(e); } } return RE_INT_ARR; } static byte[] eS(short[] value) { int sLen = value.length; byte[] bytes = new byte[sLen << 1]; for (int sOff = 0, bOff = 0; sOff < sLen; sOff++) { short s = value[sOff]; bytes[bOff++] = (byte) s; bytes[bOff++] = (byte) (s >>> 8); } return bytes; } static short[] dS(byte[] bytes) { int sLen = bytes.length << 1; short[] shorts = new short[sLen]; for (int sOff = 0, boff = 0; sOff < sLen; sOff++) { shorts[sOff] = (short) (bytes[boff++] | bytes[boff++] << 8); } return shorts; } static byte[] eC(char[] value) { int cLen = value.length; byte[] bytes = new byte[cLen << 1]; for (int sOff = 0, bOff = 0; sOff < cLen; sOff++) { char c = value[sOff]; bytes[bOff++] = (byte) c; bytes[bOff++] = (byte) (c >>> 8); } return bytes; } static char[] dC(byte[] bytes) { int cLen = bytes.length >>> 1; char[] chars = new char[cLen]; for (int cOff = 0, boff = 0; cOff < cLen; cOff++) { chars[cOff] = (char) (bytes[boff++] | bytes[boff++] << 8); } return chars; } static int[] eJ(long[] value) { int lLen = value.length; int[] ints = new int[lLen << 1]; for (int lOff = 0, iOff = 0; lOff < lLen; ++lOff) { long l = value[lOff]; ints[iOff++] = (int) l; ints[iOff++] = (int) (l >>> 32); } return ints; } static long[] dJ(int[] ints) { int lLen = ints.length << 1; long[] longs = new long[lLen]; for (int lOff = 0, iOff = 0; lOff < lLen; ++lOff) { longs[lOff] = (long) ints[iOff++] | (long) ints[iOff++] << 32; } return longs; } static int[] eF(float[] value) { int len = value.length; int[] ints = new int[len]; for (int i = 0; i < len; i++) { ints[i] = Float.floatToRawIntBits(value[i]); } return ints; } static float[] dF(int[] ints) { int len = ints.length; float[] floats = new float[len]; for (int i = 0; i < len; i++) { floats[i] = Float.intBitsToFloat(ints[i]); } return floats; } static int[] eD(double[] value) { int dLen = value.length; int[] ints = new int[dLen << 1]; for (int lOff = 0, iOff = 0; lOff < dLen; ++lOff) { long l = Double.doubleToLongBits(value[lOff]); ints[iOff++] = (int) l; ints[iOff++] = (int) (l >>> 32); } return ints; } static double[] dD(int[] ints) { int dLen = ints.length << 1; double[] doubles = new double[dLen]; for (int dOff = 0, iOff = 0; dOff < dLen; ++dOff) { doubles[dOff] = Double.longBitsToDouble((long) ints[iOff++] | (long) ints[iOff++] << 32); } return doubles; } static byte[] eZ(boolean[] value) { int n = value.length; byte[] bytes = new byte[n]; for (int i = 0; i < n; i++) { if (value[i]) bytes[i] = 1; } return bytes; } static boolean[] dZ(byte[] bytes) { int n = bytes.length; boolean[] booleans = new boolean[n]; for (int i = 0; i < n; i++) { if (bytes[i] != 0) booleans[i] = true; } return booleans; } }