/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hazelcast.internal.memory.impl; import com.hazelcast.internal.memory.ByteAccessStrategy; import com.hazelcast.internal.memory.GlobalMemoryAccessorRegistry; import com.hazelcast.internal.memory.MemoryAccessor; import java.io.DataInput; import java.io.IOException; import java.io.UTFDataFormatException; /** * A utility class with methods that read/write multibyte values from/to byte-addressed memory, with * explicitly specified endianness. The low-level strategy of reading and writing individual bytes is * supplied by an instance of {@link ByteAccessStrategy}. */ @SuppressWarnings({"checkstyle:magicnumber", "MagicNumber", "checkstyle:methodcount", "checkstyle:booleanexpressioncomplexity"}) public final class EndiannessUtil { /** * Accesses bytes in a Java byte array */ public static final ByteAccessStrategy<byte[]> BYTE_ARRAY_ACCESS = ByteArrayAccessStrategy.INSTANCE; /** * Accesses bytes in CPU's native address space */ public static final ByteAccessStrategy<Object> NATIVE_ACCESS = GlobalMemoryAccessorRegistry.MEM; public static final ByteAccessStrategy<MemoryAccessor> CUSTOM_ACCESS = CustomByteAccessStrategy.INSTANCE; private EndiannessUtil() { } public static <R> char readChar( ByteAccessStrategy<R> strategy, R resource, long offset, boolean useBigEndian) { return useBigEndian ? readCharB(strategy, resource, offset) : readCharL(strategy, resource, offset); } public static <R> char readCharB(ByteAccessStrategy<R> strategy, R resource, long offset) { int byte1 = strategy.getByte(resource, offset) & 0xFF; int byte0 = strategy.getByte(resource, offset + 1) & 0xFF; return (char) ((byte1 << 8) | byte0); } public static <R> char readCharL(ByteAccessStrategy<R> strategy, R resource, long offset) { int byte1 = strategy.getByte(resource, offset) & 0xFF; int byte0 = strategy.getByte(resource, offset + 1) & 0xFF; return (char) ((byte0 << 8) | byte1); } public static <R> void writeChar( ByteAccessStrategy<R> strategy, R resource, long offset, char v, boolean useBigEndian) { if (useBigEndian) { writeCharB(strategy, resource, offset, v); } else { writeCharL(strategy, resource, offset, v); } } public static <R> void writeCharB(ByteAccessStrategy<R> strategy, R resource, long offset, char v) { strategy.putByte(resource, offset, (byte) ((v >>> 8) & 0xFF)); strategy.putByte(resource, offset + 1, (byte) ((v) & 0xFF)); } public static <R> void writeCharL(ByteAccessStrategy<R> strategy, R resource, long offset, char v) { strategy.putByte(resource, offset, (byte) ((v) & 0xFF)); strategy.putByte(resource, offset + 1, (byte) ((v >>> 8) & 0xFF)); } ////////////////////////////////////////////////////////////////////////////////////////// public static <R> short readShort(ByteAccessStrategy<R> strategy, R resource, long offset, boolean useBigEndian) { return useBigEndian ? readShortB(strategy, resource, offset) : readShortL(strategy, resource, offset); } public static <R> short readShortB(ByteAccessStrategy<R> strategy, R resource, long offset) { int byte1 = strategy.getByte(resource, offset) & 0xFF; int byte0 = strategy.getByte(resource, offset + 1) & 0xFF; return (short) ((byte1 << 8) | byte0); } public static <R> short readShortL(ByteAccessStrategy<R> strategy, R resource, long offset) { int byte1 = strategy.getByte(resource, offset) & 0xFF; int byte0 = strategy.getByte(resource, offset + 1) & 0xFF; return (short) ((byte0 << 8) | byte1); } public static <R> void writeShort( ByteAccessStrategy<R> strategy, R resource, long offset, short v, boolean useBigEndian) { if (useBigEndian) { writeShortB(strategy, resource, offset, v); } else { writeShortL(strategy, resource, offset, v); } } public static <R> void writeShortB(ByteAccessStrategy<R> strategy, R resource, long offset, short v) { strategy.putByte(resource, offset, (byte) ((v >>> 8) & 0xFF)); strategy.putByte(resource, offset + 1, (byte) ((v) & 0xFF)); } public static <R> void writeShortL(ByteAccessStrategy<R> strategy, R resource, long offset, short v) { strategy.putByte(resource, offset, (byte) ((v) & 0xFF)); strategy.putByte(resource, offset + 1, (byte) ((v >>> 8) & 0xFF)); } ////////////////////////////////////////////////////////////////////////////////////////// public static <R> int readInt(ByteAccessStrategy<R> strategy, R resource, long offset, boolean useBigEndian) { return useBigEndian ? readIntB(strategy, resource, offset) : readIntL(strategy, resource, offset); } public static <R> int readIntB(ByteAccessStrategy<R> strategy, R resource, long offset) { int byte3 = (strategy.getByte(resource, offset) & 0xFF) << 24; int byte2 = (strategy.getByte(resource, offset + 1) & 0xFF) << 16; int byte1 = (strategy.getByte(resource, offset + 2) & 0xFF) << 8; int byte0 = strategy.getByte(resource, offset + 3) & 0xFF; return byte3 | byte2 | byte1 | byte0; } public static <R> int readIntL(ByteAccessStrategy<R> strategy, R resource, long offset) { int byte3 = strategy.getByte(resource, offset) & 0xFF; int byte2 = (strategy.getByte(resource, offset + 1) & 0xFF) << 8; int byte1 = (strategy.getByte(resource, offset + 2) & 0xFF) << 16; int byte0 = (strategy.getByte(resource, offset + 3) & 0xFF) << 24; return byte3 | byte2 | byte1 | byte0; } public static <R> void writeInt( ByteAccessStrategy<R> strategy, R resource, long offset, int v, boolean useBigEndian) { if (useBigEndian) { writeIntB(strategy, resource, offset, v); } else { writeIntL(strategy, resource, offset, v); } } public static <R> void writeIntB(ByteAccessStrategy<R> strategy, R resource, long offset, int v) { strategy.putByte(resource, offset, (byte) ((v >>> 24) & 0xFF)); strategy.putByte(resource, offset + 1, (byte) ((v >>> 16) & 0xFF)); strategy.putByte(resource, offset + 2, (byte) ((v >>> 8) & 0xFF)); strategy.putByte(resource, offset + 3, (byte) ((v) & 0xFF)); } public static <R> void writeIntL(ByteAccessStrategy<R> strategy, R resource, long offset, int v) { strategy.putByte(resource, offset, (byte) ((v) & 0xFF)); strategy.putByte(resource, offset + 1, (byte) ((v >>> 8) & 0xFF)); strategy.putByte(resource, offset + 2, (byte) ((v >>> 16) & 0xFF)); strategy.putByte(resource, offset + 3, (byte) ((v >>> 24) & 0xFF)); } ////////////////////////////////////////////////////////////////////////////////////////// public static <R> float readFloat(ByteAccessStrategy<R> strategy, R resource, long offset, boolean useBigEndian) { return useBigEndian ? readFloatB(strategy, resource, offset) : readFloatL(strategy, resource, offset); } public static <R> float readFloatB(ByteAccessStrategy<R> strategy, R resource, long offset) { return Float.intBitsToFloat(readIntB(strategy, resource, offset)); } public static <R> float readFloatL(ByteAccessStrategy<R> strategy, R resource, long offset) { return Float.intBitsToFloat(readIntL(strategy, resource, offset)); } public static <R> void writeFloat( ByteAccessStrategy<R> strategy, R resource, long offset, float v, boolean useBigEndian) { if (useBigEndian) { writeFloatB(strategy, resource, offset, v); } else { writeFloatL(strategy, resource, offset, v); } } public static <R> void writeFloatB(ByteAccessStrategy<R> strategy, R resource, long offset, float v) { writeIntB(strategy, resource, offset, Float.floatToRawIntBits(v)); } public static <R> void writeFloatL(ByteAccessStrategy<R> strategy, R resource, long offset, float v) { writeIntL(strategy, resource, offset, Float.floatToRawIntBits(v)); } ////////////////////////////////////////////////////////////////////////////////////////// public static <R> long readLong(ByteAccessStrategy<R> strategy, R resource, long offset, boolean useBigEndian) { return useBigEndian ? readLongB(strategy, resource, offset) : readLongL(strategy, resource, offset); } public static <R> long readLongB(ByteAccessStrategy<R> strategy, R resource, long offset) { long byte7 = (long) strategy.getByte(resource, offset) << 56; long byte6 = (long) (strategy.getByte(resource, offset + 1) & 0xFF) << 48; long byte5 = (long) (strategy.getByte(resource, offset + 2) & 0xFF) << 40; long byte4 = (long) (strategy.getByte(resource, offset + 3) & 0xFF) << 32; long byte3 = (long) (strategy.getByte(resource, offset + 4) & 0xFF) << 24; long byte2 = (long) (strategy.getByte(resource, offset + 5) & 0xFF) << 16; long byte1 = (long) (strategy.getByte(resource, offset + 6) & 0xFF) << 8; long byte0 = (long) (strategy.getByte(resource, offset + 7) & 0xFF); return byte7 | byte6 | byte5 | byte4 | byte3 | byte2 | byte1 | byte0; } public static <R> long readLongL(ByteAccessStrategy<R> strategy, R resource, long offset) { long byte7 = (long) (strategy.getByte(resource, offset) & 0xFF); long byte6 = (long) (strategy.getByte(resource, offset + 1) & 0xFF) << 8; long byte5 = (long) (strategy.getByte(resource, offset + 2) & 0xFF) << 16; long byte4 = (long) (strategy.getByte(resource, offset + 3) & 0xFF) << 24; long byte3 = (long) (strategy.getByte(resource, offset + 4) & 0xFF) << 32; long byte2 = (long) (strategy.getByte(resource, offset + 5) & 0xFF) << 40; long byte1 = (long) (strategy.getByte(resource, offset + 6) & 0xFF) << 48; long byte0 = (long) (strategy.getByte(resource, offset + 7) & 0xFF) << 56; return byte7 | byte6 | byte5 | byte4 | byte3 | byte2 | byte1 | byte0; } public static <R> void writeLong( ByteAccessStrategy<R> strategy, R resource, long offset, long v, boolean useBigEndian) { if (useBigEndian) { writeLongB(strategy, resource, offset, v); } else { writeLongL(strategy, resource, offset, v); } } public static <R> void writeLongB(ByteAccessStrategy<R> strategy, R resource, long offset, long v) { strategy.putByte(resource, offset, (byte) (v >>> 56)); strategy.putByte(resource, offset + 1, (byte) (v >>> 48)); strategy.putByte(resource, offset + 2, (byte) (v >>> 40)); strategy.putByte(resource, offset + 3, (byte) (v >>> 32)); strategy.putByte(resource, offset + 4, (byte) (v >>> 24)); strategy.putByte(resource, offset + 5, (byte) (v >>> 16)); strategy.putByte(resource, offset + 6, (byte) (v >>> 8)); strategy.putByte(resource, offset + 7, (byte) (v)); } public static <R> void writeLongL(ByteAccessStrategy<R> strategy, R resource, long offset, long v) { strategy.putByte(resource, offset, (byte) (v)); strategy.putByte(resource, offset + 1, (byte) (v >>> 8)); strategy.putByte(resource, offset + 2, (byte) (v >>> 16)); strategy.putByte(resource, offset + 3, (byte) (v >>> 24)); strategy.putByte(resource, offset + 4, (byte) (v >>> 32)); strategy.putByte(resource, offset + 5, (byte) (v >>> 40)); strategy.putByte(resource, offset + 6, (byte) (v >>> 48)); strategy.putByte(resource, offset + 7, (byte) (v >>> 56)); } ////////////////////////////////////////////////////////////////////////////////////////// public static <R> double readDouble( ByteAccessStrategy<R> strategy, R resource, long offset, boolean useBigEndian) { return useBigEndian ? readDoubleB(strategy, resource, offset) : readDoubleL(strategy, resource, offset); } public static <R> double readDoubleB(ByteAccessStrategy<R> strategy, R resource, long offset) { return Double.longBitsToDouble(readLongB(strategy, resource, offset)); } public static <R> double readDoubleL(ByteAccessStrategy<R> strategy, R resource, long offset) { return Double.longBitsToDouble(readLongL(strategy, resource, offset)); } public static <R> void writeDouble( ByteAccessStrategy<R> strategy, R resource, long offset, double v, boolean useBigEndian) { if (useBigEndian) { writeDoubleB(strategy, resource, offset, v); } else { writeDoubleL(strategy, resource, offset, v); } } public static <R> void writeDoubleB( ByteAccessStrategy<R> memoryAccessStrategy, R resource, long offset, double v) { writeLongB(memoryAccessStrategy, resource, offset, Double.doubleToRawLongBits(v)); } public static <R> void writeDoubleL( ByteAccessStrategy<R> memoryAccessStrategy, R resource, long offset, double v) { writeLongL(memoryAccessStrategy, resource, offset, Double.doubleToRawLongBits(v)); } ////////////////////////////////////////////////////////////////// public static <R> int writeUtf8Char(ByteAccessStrategy<R> strategy, R resource, long pos, int c) { if (c <= 0x007F) { strategy.putByte(resource, pos, (byte) c); return 1; } else if (c > 0x07FF) { strategy.putByte(resource, pos, (byte) (0xE0 | c >> 12 & 0x0F)); strategy.putByte(resource, pos + 1, (byte) (0x80 | c >> 6 & 0x3F)); strategy.putByte(resource, pos + 2, (byte) (0x80 | c & 0x3F)); return 3; } else { strategy.putByte(resource, pos, (byte) (0xC0 | c >> 6 & 0x1F)); strategy.putByte(resource, pos + 1, (byte) (0x80 | c & 0x3F)); return 2; } } public static char readUtf8Char(DataInput in, byte firstByte) throws IOException { int b = firstByte & 0xFF; switch (b >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: return (char) b; case 12: case 13: int first = (b & 0x1F) << 6; int second = in.readByte() & 0x3F; return (char) (first | second); case 14: int first2 = (b & 0x0F) << 12; int second2 = (in.readByte() & 0x3F) << 6; int third2 = in.readByte() & 0x3F; return (char) (first2 | second2 | third2); default: throw new UTFDataFormatException("Malformed byte sequence"); } } public static int readUtf8Char(byte[] buffer, int pos, char[] dst, int dstPos) throws IOException { int b = buffer[pos] & 0xFF; switch (b >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: dst[dstPos] = (char) b; return 1; case 12: case 13: int first = (b & 0x1F) << 6; int second = buffer[pos + 1] & 0x3F; dst[dstPos] = (char) (first | second); return 2; case 14: int first2 = (b & 0x0F) << 12; int second2 = (buffer[pos + 1] & 0x3F) << 6; int third2 = buffer[pos + 2] & 0x3F; dst[dstPos] = (char) (first2 | second2 | third2); return 3; default: throw new UTFDataFormatException("Malformed byte sequence"); } } }