Java tutorial
/* * Copyright 2014 dorkbox, llc * * 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. * * Copyright (c) 2008, Nathan Sweet * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided with the distribution. * - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package dorkbox.util.bytes; import io.netty.buffer.ByteBuf; @SuppressWarnings({ "Duplicates", "NumericCastThatLosesPrecision", "UnusedAssignment", "IntegerMultiplicationImplicitCastToLong", "unused" }) public class OptimizeUtilsByteBuf { // int /** * FROM KRYO * <p> * Returns the number of bytes that would be written with {@link #writeInt(ByteBuf, int, boolean)}. * * @param optimizePositive * If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (5 * bytes). This ultimately means that it will use fewer bytes for positive numbers. */ public static int intLength(int value, boolean optimizePositive) { if (!optimizePositive) { value = value << 1 ^ value >> 31; } if (value >>> 7 == 0) { return 1; } if (value >>> 14 == 0) { return 2; } if (value >>> 21 == 0) { return 3; } if (value >>> 28 == 0) { return 4; } return 5; } /** * FROM KRYO * <p> * look at buffer, and see if we can read the length of the int off of it. (from the reader index) * * @return 0 if we could not read anything, >0 for the number of bytes for the int on the buffer */ public static int canReadInt(ByteBuf buffer) { int startIndex = buffer.readerIndex(); try { int remaining = buffer.readableBytes(); for (int offset = 0, count = 1; offset < 32 && remaining > 0; offset += 7, remaining--, count++) { int b = buffer.readByte(); if ((b & 0x80) == 0) { return count; } } return 0; } finally { buffer.readerIndex(startIndex); } } /** * FROM KRYO * <p> * Reads an int from the buffer that was optimized. * * @param optimizePositive * If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (5 * bytes). This ultimately means that it will use fewer bytes for positive numbers. * * @return the number of bytes written. */ public static int readInt(ByteBuf buffer, boolean optimizePositive) { int b = buffer.readByte(); int result = b & 0x7F; if ((b & 0x80) != 0) { b = buffer.readByte(); result |= (b & 0x7F) << 7; if ((b & 0x80) != 0) { b = buffer.readByte(); result |= (b & 0x7F) << 14; if ((b & 0x80) != 0) { b = buffer.readByte(); result |= (b & 0x7F) << 21; if ((b & 0x80) != 0) { b = buffer.readByte(); result |= (b & 0x7F) << 28; } } } } return optimizePositive ? result : result >>> 1 ^ -(result & 1); } /** * FROM KRYO * <p> * Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number. * * @param optimizePositive * If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (5 * bytes). This ultimately means that it will use fewer bytes for positive numbers. * * @return the number of bytes written. */ public static int writeInt(ByteBuf buffer, int value, boolean optimizePositive) { if (!optimizePositive) { value = value << 1 ^ value >> 31; } if (value >>> 7 == 0) { buffer.writeByte((byte) value); return 1; } if (value >>> 14 == 0) { buffer.writeByte((byte) (value & 0x7F | 0x80)); buffer.writeByte((byte) (value >>> 7)); return 2; } if (value >>> 21 == 0) { buffer.writeByte((byte) (value & 0x7F | 0x80)); buffer.writeByte((byte) (value >>> 7 | 0x80)); buffer.writeByte((byte) (value >>> 14)); return 3; } if (value >>> 28 == 0) { buffer.writeByte((byte) (value & 0x7F | 0x80)); buffer.writeByte((byte) (value >>> 7 | 0x80)); buffer.writeByte((byte) (value >>> 14 | 0x80)); buffer.writeByte((byte) (value >>> 21)); return 4; } buffer.writeByte((byte) (value & 0x7F | 0x80)); buffer.writeByte((byte) (value >>> 7 | 0x80)); buffer.writeByte((byte) (value >>> 14 | 0x80)); buffer.writeByte((byte) (value >>> 21 | 0x80)); buffer.writeByte((byte) (value >>> 28)); return 5; } // long /** * Returns the 1-9 bytes that would be written with {@link #writeLong(ByteBuf, long, boolean)}. * * @param optimizePositive * If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (9 * bytes). This ultimately means that it will use fewer bytes for positive numbers. */ public static int longLength(long value, boolean optimizePositive) { if (!optimizePositive) { value = value << 1 ^ value >> 63; } if (value >>> 7 == 0) { return 1; } if (value >>> 14 == 0) { return 2; } if (value >>> 21 == 0) { return 3; } if (value >>> 28 == 0) { return 4; } if (value >>> 35 == 0) { return 5; } if (value >>> 42 == 0) { return 6; } if (value >>> 49 == 0) { return 7; } if (value >>> 56 == 0) { return 8; } return 9; } /** * FROM KRYO * <p> * Reads a 1-9 byte long. * * @param optimizePositive * If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (9 * bytes). This ultimately means that it will use fewer bytes for positive numbers. */ public static long readLong(ByteBuf buffer, boolean optimizePositive) { int b = buffer.readByte(); long result = b & 0x7F; if ((b & 0x80) != 0) { b = buffer.readByte(); result |= (b & 0x7F) << 7; if ((b & 0x80) != 0) { b = buffer.readByte(); result |= (b & 0x7F) << 14; if ((b & 0x80) != 0) { b = buffer.readByte(); result |= (b & 0x7F) << 21; if ((b & 0x80) != 0) { b = buffer.readByte(); result |= (long) (b & 0x7F) << 28; if ((b & 0x80) != 0) { b = buffer.readByte(); result |= (long) (b & 0x7F) << 35; if ((b & 0x80) != 0) { b = buffer.readByte(); result |= (long) (b & 0x7F) << 42; if ((b & 0x80) != 0) { b = buffer.readByte(); result |= (long) (b & 0x7F) << 49; if ((b & 0x80) != 0) { b = buffer.readByte(); result |= (long) b << 56; } } } } } } } } if (!optimizePositive) { result = result >>> 1 ^ -(result & 1); } return result; } /** * FROM KRYO * <p> * Writes a 1-9 byte long. * * @param optimizePositive * If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (9 * bytes). This ultimately means that it will use fewer bytes for positive numbers. * * @return the number of bytes written. */ public static int writeLong(ByteBuf buffer, long value, boolean optimizePositive) { if (!optimizePositive) { value = value << 1 ^ value >> 63; } if (value >>> 7 == 0) { buffer.writeByte((byte) value); return 1; } if (value >>> 14 == 0) { buffer.writeByte((byte) (value & 0x7F | 0x80)); buffer.writeByte((byte) (value >>> 7)); return 2; } if (value >>> 21 == 0) { buffer.writeByte((byte) (value & 0x7F | 0x80)); buffer.writeByte((byte) (value >>> 7 | 0x80)); buffer.writeByte((byte) (value >>> 14)); return 3; } if (value >>> 28 == 0) { buffer.writeByte((byte) (value & 0x7F | 0x80)); buffer.writeByte((byte) (value >>> 7 | 0x80)); buffer.writeByte((byte) (value >>> 14 | 0x80)); buffer.writeByte((byte) (value >>> 21)); return 4; } if (value >>> 35 == 0) { buffer.writeByte((byte) (value & 0x7F | 0x80)); buffer.writeByte((byte) (value >>> 7 | 0x80)); buffer.writeByte((byte) (value >>> 14 | 0x80)); buffer.writeByte((byte) (value >>> 21 | 0x80)); buffer.writeByte((byte) (value >>> 28)); return 5; } if (value >>> 42 == 0) { buffer.writeByte((byte) (value & 0x7F | 0x80)); buffer.writeByte((byte) (value >>> 7 | 0x80)); buffer.writeByte((byte) (value >>> 14 | 0x80)); buffer.writeByte((byte) (value >>> 21 | 0x80)); buffer.writeByte((byte) (value >>> 28 | 0x80)); buffer.writeByte((byte) (value >>> 35)); return 6; } if (value >>> 49 == 0) { buffer.writeByte((byte) (value & 0x7F | 0x80)); buffer.writeByte((byte) (value >>> 7 | 0x80)); buffer.writeByte((byte) (value >>> 14 | 0x80)); buffer.writeByte((byte) (value >>> 21 | 0x80)); buffer.writeByte((byte) (value >>> 28 | 0x80)); buffer.writeByte((byte) (value >>> 35 | 0x80)); buffer.writeByte((byte) (value >>> 42)); return 7; } if (value >>> 56 == 0) { buffer.writeByte((byte) (value & 0x7F | 0x80)); buffer.writeByte((byte) (value >>> 7 | 0x80)); buffer.writeByte((byte) (value >>> 14 | 0x80)); buffer.writeByte((byte) (value >>> 21 | 0x80)); buffer.writeByte((byte) (value >>> 28 | 0x80)); buffer.writeByte((byte) (value >>> 35 | 0x80)); buffer.writeByte((byte) (value >>> 42 | 0x80)); buffer.writeByte((byte) (value >>> 49)); return 8; } buffer.writeByte((byte) (value & 0x7F | 0x80)); buffer.writeByte((byte) (value >>> 7 | 0x80)); buffer.writeByte((byte) (value >>> 14 | 0x80)); buffer.writeByte((byte) (value >>> 21 | 0x80)); buffer.writeByte((byte) (value >>> 28 | 0x80)); buffer.writeByte((byte) (value >>> 35 | 0x80)); buffer.writeByte((byte) (value >>> 42 | 0x80)); buffer.writeByte((byte) (value >>> 49 | 0x80)); buffer.writeByte((byte) (value >>> 56)); return 9; } /** * FROM KRYO * <p> * look at buffer, and see if we can read the length of the long off of it (from the reader index). * * @return 0 if we could not read anything, >0 for the number of bytes for the long on the buffer */ public static int canReadLong(ByteBuf buffer) { int position = buffer.readerIndex(); try { int remaining = buffer.readableBytes(); for (int offset = 0, count = 1; offset < 64 && remaining > 0; offset += 7, remaining--, count++) { int b = buffer.readByte(); if ((b & 0x80) == 0) { return count; } } return 0; } finally { buffer.readerIndex(position); } } }