optimize utils converted to kotlin
This commit is contained in:
parent
cef8cb7f5c
commit
d278130ea2
|
@ -1,477 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 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.bytes;
|
||||
|
||||
@SuppressWarnings({"Duplicates", "NumericCastThatLosesPrecision", "UnusedAssignment", "unused"})
|
||||
public
|
||||
class OptimizeUtilsByteArray {
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that would be written with {@link #writeInt(byte[], int, boolean)}.
|
||||
*
|
||||
* @param optimizePositive
|
||||
* true if you want to optimize the number of bytes needed to write the length value
|
||||
*/
|
||||
public static
|
||||
int intLength(int value, boolean optimizePositive) {
|
||||
return dorkbox.bytes.OptimizeUtilsByteBuf.intLength(value, optimizePositive);
|
||||
}
|
||||
|
||||
// int
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@SuppressWarnings("SimplifiableIfStatement")
|
||||
public static
|
||||
boolean canReadInt(byte[] buffer) {
|
||||
int position = 0;
|
||||
return canReadInt(buffer, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
* <p>
|
||||
* look at buffer, and see if we can read the length of the int off of it. (from the reader index)
|
||||
*
|
||||
* @param position where in the buffer to start reading
|
||||
* @return 0 if we could not read anything, >0 for the number of bytes for the int on the buffer
|
||||
*/
|
||||
@SuppressWarnings("SimplifiableIfStatement")
|
||||
public static
|
||||
boolean canReadInt(final byte[] buffer, int position) {
|
||||
int length = buffer.length;
|
||||
|
||||
if (length >= 5) {
|
||||
return true;
|
||||
}
|
||||
if ((buffer[position++] & 0x80) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (position == length) {
|
||||
return false;
|
||||
}
|
||||
if ((buffer[position++] & 0x80) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (position == length) {
|
||||
return false;
|
||||
}
|
||||
if ((buffer[position++] & 0x80) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (position == length) {
|
||||
return false;
|
||||
}
|
||||
if ((buffer[position++] & 0x80) == 0) {
|
||||
return true;
|
||||
}
|
||||
return position != length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an int from the buffer that was optimized at position 0
|
||||
*
|
||||
* @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 readInt(byte[] buffer, boolean optimizePositive) {
|
||||
int position = 0;
|
||||
return readInt(buffer, optimizePositive, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
* <p>
|
||||
* Reads an int from the buffer that was optimized.
|
||||
*
|
||||
* @param position where in the buffer to start reading
|
||||
* @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 readInt(final byte[] buffer, final boolean optimizePositive, int position) {
|
||||
int b = buffer[position++];
|
||||
int result = b & 0x7F;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer[position++];
|
||||
result |= (b & 0x7F) << 7;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer[position++];
|
||||
result |= (b & 0x7F) << 14;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer[position++];
|
||||
result |= (b & 0x7F) << 21;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer[position++];
|
||||
result |= (b & 0x7F) << 28;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return optimizePositive ? result : result >>> 1 ^ -(result & 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(byte[] buffer, int value, boolean optimizePositive) {
|
||||
int position = 0;
|
||||
return writeInt(buffer, value, optimizePositive, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
* <p>
|
||||
* Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number.
|
||||
*
|
||||
* @param position where in the buffer to start writing
|
||||
* @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(final byte[] buffer, int value, final boolean optimizePositive, int position) {
|
||||
if (!optimizePositive) {
|
||||
value = value << 1 ^ value >> 31;
|
||||
}
|
||||
if (value >>> 7 == 0) {
|
||||
buffer[position++] = (byte) value;
|
||||
return 1;
|
||||
}
|
||||
if (value >>> 14 == 0) {
|
||||
buffer[position++] = (byte) (value & 0x7F | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 7);
|
||||
return 2;
|
||||
}
|
||||
if (value >>> 21 == 0) {
|
||||
buffer[position++] = (byte) (value & 0x7F | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 7 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 14);
|
||||
return 3;
|
||||
}
|
||||
if (value >>> 28 == 0) {
|
||||
buffer[position++] = (byte) (value & 0x7F | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 7 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 14 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 21);
|
||||
return 4;
|
||||
}
|
||||
buffer[position++] = (byte) (value & 0x7F | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 7 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 14 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 21 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 28);
|
||||
return 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1-9 bytes that would be written with {@link #writeLong(byte[], 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) {
|
||||
return dorkbox.bytes.OptimizeUtilsByteBuf.longLength(value, optimizePositive);
|
||||
}
|
||||
|
||||
|
||||
// long
|
||||
|
||||
/**
|
||||
* 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(byte[] buffer, boolean optimizePositive) {
|
||||
int position = 0;
|
||||
return readLong(buffer, optimizePositive, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
* <p>
|
||||
* Reads a 1-9 byte long.
|
||||
*
|
||||
* @param position where in the buffer to start reading
|
||||
* @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(final byte[] buffer, final boolean optimizePositive, int position) {
|
||||
int b = buffer[position++];
|
||||
long result = b & 0x7F;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer[position++];
|
||||
result |= (b & 0x7F) << 7;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer[position++];
|
||||
result |= (b & 0x7F) << 14;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer[position++];
|
||||
result |= (b & 0x7F) << 21;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer[position++];
|
||||
result |= (long) (b & 0x7F) << 28;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer[position++];
|
||||
result |= (long) (b & 0x7F) << 35;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer[position++];
|
||||
result |= (long) (b & 0x7F) << 42;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer[position++];
|
||||
result |= (long) (b & 0x7F) << 49;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer[position++];
|
||||
result |= (long) b << 56;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!optimizePositive) {
|
||||
result = result >>> 1 ^ -(result & 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*
|
||||
* @return the number of bytes written.
|
||||
*/
|
||||
public static
|
||||
int writeLong(byte[] buffer, long value, boolean optimizePositive) {
|
||||
int position = 0;
|
||||
return writeLong(buffer, value, optimizePositive, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
* <p>
|
||||
* Writes a 1-9 byte long.
|
||||
*
|
||||
* @param position where in the buffer to start writing
|
||||
* @param optimizePositive
|
||||
* If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (9
|
||||
* bytes).
|
||||
*
|
||||
* @return the number of bytes written.
|
||||
*/
|
||||
public static
|
||||
int writeLong(final byte[] buffer, long value, final boolean optimizePositive, int position) {
|
||||
if (!optimizePositive) {
|
||||
value = value << 1 ^ value >> 63;
|
||||
}
|
||||
if (value >>> 7 == 0) {
|
||||
buffer[position++] = (byte) value;
|
||||
return 1;
|
||||
}
|
||||
if (value >>> 14 == 0) {
|
||||
buffer[position++] = (byte) (value & 0x7F | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 7);
|
||||
return 2;
|
||||
}
|
||||
if (value >>> 21 == 0) {
|
||||
buffer[position++] = (byte) (value & 0x7F | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 7 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 14);
|
||||
return 3;
|
||||
}
|
||||
if (value >>> 28 == 0) {
|
||||
buffer[position++] = (byte) (value & 0x7F | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 7 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 14 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 21);
|
||||
return 4;
|
||||
}
|
||||
if (value >>> 35 == 0) {
|
||||
buffer[position++] = (byte) (value & 0x7F | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 7 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 14 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 21 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 28);
|
||||
return 5;
|
||||
}
|
||||
if (value >>> 42 == 0) {
|
||||
buffer[position++] = (byte) (value & 0x7F | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 7 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 14 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 21 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 28 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 35);
|
||||
return 6;
|
||||
}
|
||||
if (value >>> 49 == 0) {
|
||||
buffer[position++] = (byte) (value & 0x7F | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 7 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 14 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 21 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 28 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 35 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 42);
|
||||
return 7;
|
||||
}
|
||||
if (value >>> 56 == 0) {
|
||||
buffer[position++] = (byte) (value & 0x7F | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 7 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 14 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 21 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 28 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 35 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 42 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 49);
|
||||
return 8;
|
||||
}
|
||||
buffer[position++] = (byte) (value & 0x7F | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 7 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 14 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 21 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 28 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 35 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 42 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 49 | 0x80);
|
||||
buffer[position++] = (byte) (value >>> 56);
|
||||
return 9;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
boolean canReadLong(byte[] buffer) {
|
||||
int position = 0;
|
||||
return canReadLong(buffer, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
* <p>
|
||||
* look at buffer, and see if we can read the length of the long off of it (from the reader index).
|
||||
*
|
||||
* @param position where in the buffer to start reading
|
||||
* @return 0 if we could not read anything, >0 for the number of bytes for the long on the buffer
|
||||
*/
|
||||
private static
|
||||
boolean canReadLong(final byte[] buffer, int position) {
|
||||
int limit = buffer.length;
|
||||
|
||||
if (limit >= 9) {
|
||||
return true;
|
||||
}
|
||||
if ((buffer[position++] & 0x80) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (position == limit) {
|
||||
return false;
|
||||
}
|
||||
if ((buffer[position++] & 0x80) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (position == limit) {
|
||||
return false;
|
||||
}
|
||||
if ((buffer[position++] & 0x80) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (position == limit) {
|
||||
return false;
|
||||
}
|
||||
if ((buffer[position++] & 0x80) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (position == limit) {
|
||||
return false;
|
||||
}
|
||||
if ((buffer[position++] & 0x80) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (position == limit) {
|
||||
return false;
|
||||
}
|
||||
if ((buffer[position++] & 0x80) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (position == limit) {
|
||||
return false;
|
||||
}
|
||||
if ((buffer[position++] & 0x80) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (position == limit) {
|
||||
return false;
|
||||
}
|
||||
//noinspection SimplifiableIfStatement
|
||||
if ((buffer[position++] & 0x80) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return position != limit;
|
||||
}
|
||||
|
||||
private
|
||||
OptimizeUtilsByteArray() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
@file:Suppress("UNUSED_CHANGED_VALUE", "NAME_SHADOWING")
|
||||
|
||||
package dorkbox.bytes
|
||||
|
||||
@Suppress("unused")
|
||||
object OptimizeUtilsByteArray {
|
||||
/**
|
||||
* Returns the number of bytes that would be written with [.writeInt].
|
||||
*
|
||||
* @param optimizePositive
|
||||
* true if you want to optimize the number of bytes needed to write the length value
|
||||
*/
|
||||
fun intLength(value: Int, optimizePositive: Boolean): Int {
|
||||
return OptimizeUtilsByteBuf.intLength(value, optimizePositive)
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* look at buffer, and see if we can read the length of the int off of it. (from the reader index)
|
||||
*
|
||||
* @param position where in the buffer to start reading
|
||||
* @return 0 if we could not read anything, >0 for the number of bytes for the int on the buffer
|
||||
*/
|
||||
fun canReadInt(buffer: ByteArray, position: Int = 0): Boolean {
|
||||
var position = position
|
||||
val length = buffer.size
|
||||
if (length >= 5) {
|
||||
return true
|
||||
}
|
||||
if (position + 1 > length) {
|
||||
return false
|
||||
}
|
||||
if (buffer[position++].toInt() and 0x80 == 0) {
|
||||
return true
|
||||
}
|
||||
if (position == length) {
|
||||
return false
|
||||
}
|
||||
if (buffer[position++].toInt() and 0x80 == 0) {
|
||||
return true
|
||||
}
|
||||
if (position == length) {
|
||||
return false
|
||||
}
|
||||
if (buffer[position++].toInt() and 0x80 == 0) {
|
||||
return true
|
||||
}
|
||||
if (position == length) {
|
||||
return false
|
||||
}
|
||||
return if (buffer[position++].toInt() and 0x80 == 0) {
|
||||
true
|
||||
} else position != length
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* Reads an int from the buffer that was optimized.
|
||||
*
|
||||
* @param position where in the buffer to start reading
|
||||
*/
|
||||
fun readInt(buffer: ByteArray, position: Int): Int {
|
||||
return readInt(buffer, false, position)
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* Reads an int from the buffer that was optimized.
|
||||
*
|
||||
* @param position where in the buffer to start reading
|
||||
* @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.
|
||||
*/
|
||||
fun readInt(buffer: ByteArray, optimizePositive: Boolean = false, position: Int = 0): Int {
|
||||
var position = position
|
||||
var b = buffer[position++].toInt()
|
||||
var result = b and 0x7F
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer[position++].toInt()
|
||||
result = result or (b and 0x7F shl 7)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer[position++].toInt()
|
||||
result = result or (b and 0x7F shl 14)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer[position++].toInt()
|
||||
result = result or (b and 0x7F shl 21)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer[position++].toInt()
|
||||
result = result or (b and 0x7F shl 28)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return if (optimizePositive) result else result ushr 1 xor -(result and 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number.
|
||||
*
|
||||
* @param position where in the buffer to start writing
|
||||
* @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.
|
||||
*/
|
||||
fun writeInt(buffer: ByteArray, value: Int, optimizePositive: Boolean = false, position: Int = 0): Int {
|
||||
var value = value
|
||||
var position = position
|
||||
if (!optimizePositive) {
|
||||
value = value shl 1 xor (value shr 31)
|
||||
}
|
||||
if (value ushr 7 == 0) {
|
||||
buffer[position++] = value.toByte()
|
||||
return 1
|
||||
}
|
||||
if (value ushr 14 == 0) {
|
||||
buffer[position++] = (value and 0x7F or 0x80).toByte()
|
||||
buffer[position++] = (value ushr 7).toByte()
|
||||
return 2
|
||||
}
|
||||
if (value ushr 21 == 0) {
|
||||
buffer[position++] = (value and 0x7F or 0x80).toByte()
|
||||
buffer[position++] = (value ushr 7 or 0x80).toByte()
|
||||
buffer[position++] = (value ushr 14).toByte()
|
||||
return 3
|
||||
}
|
||||
if (value ushr 28 == 0) {
|
||||
buffer[position++] = (value and 0x7F or 0x80).toByte()
|
||||
buffer[position++] = (value ushr 7 or 0x80).toByte()
|
||||
buffer[position++] = (value ushr 14 or 0x80).toByte()
|
||||
buffer[position++] = (value ushr 21).toByte()
|
||||
return 4
|
||||
}
|
||||
buffer[position++] = (value and 0x7F or 0x80).toByte()
|
||||
buffer[position++] = (value ushr 7 or 0x80).toByte()
|
||||
buffer[position++] = (value ushr 14 or 0x80).toByte()
|
||||
buffer[position++] = (value ushr 21 or 0x80).toByte()
|
||||
buffer[position++] = (value ushr 28).toByte()
|
||||
return 5
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1-9 bytes that would be written with [.writeLong].
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
fun longLength(value: Long, optimizePositive: Boolean): Int {
|
||||
return OptimizeUtilsByteBuf.longLength(value, optimizePositive)
|
||||
}
|
||||
// long
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* Reads a 1-9 byte long.
|
||||
*
|
||||
* @param position where in the buffer to start reading
|
||||
* @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.
|
||||
*/
|
||||
fun readLong(buffer: ByteArray, optimizePositive: Boolean = false, position: Int = 0): Long {
|
||||
var position = position
|
||||
var b = buffer[position++].toInt()
|
||||
var result = (b and 0x7F).toLong()
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer[position++].toInt()
|
||||
result = result or (b and 0x7F shl 7).toLong()
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer[position++].toInt()
|
||||
result = result or (b and 0x7F shl 14).toLong()
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer[position++].toInt()
|
||||
result = result or (b and 0x7F shl 21).toLong()
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer[position++].toInt()
|
||||
result = result or ((b and 0x7F).toLong() shl 28)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer[position++].toInt()
|
||||
result = result or ((b and 0x7F).toLong() shl 35)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer[position++].toInt()
|
||||
result = result or ((b and 0x7F).toLong() shl 42)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer[position++].toInt()
|
||||
result = result or ((b and 0x7F).toLong() shl 49)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer[position++].toInt()
|
||||
result = result or (b.toLong() shl 56)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!optimizePositive) {
|
||||
result = result ushr 1 xor -(result and 1L)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* Writes a 1-9 byte long.
|
||||
*
|
||||
* @param position where in the buffer to start writing
|
||||
* @param optimizePositive
|
||||
* If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be inefficient (9
|
||||
* bytes).
|
||||
*
|
||||
* @return the number of bytes written.
|
||||
*/
|
||||
fun writeLong(buffer: ByteArray, value: Long, optimizePositive: Boolean = false, position: Int = 0): Int {
|
||||
var value = value
|
||||
var position = position
|
||||
if (!optimizePositive) {
|
||||
value = value shl 1 xor (value shr 63)
|
||||
}
|
||||
if (value ushr 7 == 0L) {
|
||||
buffer[position++] = value.toByte()
|
||||
return 1
|
||||
}
|
||||
if (value ushr 14 == 0L) {
|
||||
buffer[position++] = (value and 0x7FL or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 7).toByte()
|
||||
return 2
|
||||
}
|
||||
if (value ushr 21 == 0L) {
|
||||
buffer[position++] = (value and 0x7FL or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 7 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 14).toByte()
|
||||
return 3
|
||||
}
|
||||
if (value ushr 28 == 0L) {
|
||||
buffer[position++] = (value and 0x7FL or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 7 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 14 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 21).toByte()
|
||||
return 4
|
||||
}
|
||||
if (value ushr 35 == 0L) {
|
||||
buffer[position++] = (value and 0x7FL or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 7 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 14 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 21 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 28).toByte()
|
||||
return 5
|
||||
}
|
||||
if (value ushr 42 == 0L) {
|
||||
buffer[position++] = (value and 0x7FL or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 7 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 14 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 21 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 28 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 35).toByte()
|
||||
return 6
|
||||
}
|
||||
if (value ushr 49 == 0L) {
|
||||
buffer[position++] = (value and 0x7FL or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 7 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 14 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 21 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 28 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 35 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 42).toByte()
|
||||
return 7
|
||||
}
|
||||
if (value ushr 56 == 0L) {
|
||||
buffer[position++] = (value and 0x7FL or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 7 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 14 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 21 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 28 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 35 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 42 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 49).toByte()
|
||||
return 8
|
||||
}
|
||||
buffer[position++] = (value and 0x7FL or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 7 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 14 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 21 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 28 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 35 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 42 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 49 or 0x80L).toByte()
|
||||
buffer[position++] = (value ushr 56).toByte()
|
||||
return 9
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
fun canReadLong(buffer: ByteArray): Boolean {
|
||||
val position = 0
|
||||
return canReadLong(buffer, position)
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* look at buffer, and see if we can read the length of the long off of it (from the reader index).
|
||||
*
|
||||
* @param position where in the buffer to start reading
|
||||
* @return 0 if we could not read anything, >0 for the number of bytes for the long on the buffer
|
||||
*/
|
||||
private fun canReadLong(buffer: ByteArray, position: Int): Boolean {
|
||||
var position = position
|
||||
val limit = buffer.size
|
||||
if (limit >= 9) {
|
||||
return true
|
||||
}
|
||||
if (buffer[position++].toInt() and 0x80 == 0) {
|
||||
return true
|
||||
}
|
||||
if (position == limit) {
|
||||
return false
|
||||
}
|
||||
if (buffer[position++].toInt() and 0x80 == 0) {
|
||||
return true
|
||||
}
|
||||
if (position == limit) {
|
||||
return false
|
||||
}
|
||||
if (buffer[position++].toInt() and 0x80 == 0) {
|
||||
return true
|
||||
}
|
||||
if (position == limit) {
|
||||
return false
|
||||
}
|
||||
if (buffer[position++].toInt() and 0x80 == 0) {
|
||||
return true
|
||||
}
|
||||
if (position == limit) {
|
||||
return false
|
||||
}
|
||||
if (buffer[position++].toInt() and 0x80 == 0) {
|
||||
return true
|
||||
}
|
||||
if (position == limit) {
|
||||
return false
|
||||
}
|
||||
if (buffer[position++].toInt() and 0x80 == 0) {
|
||||
return true
|
||||
}
|
||||
if (position == limit) {
|
||||
return false
|
||||
}
|
||||
if (buffer[position++].toInt() and 0x80 == 0) {
|
||||
return true
|
||||
}
|
||||
if (position == limit) {
|
||||
return false
|
||||
}
|
||||
return if (buffer[position++].toInt() and 0x80 == 0) {
|
||||
true
|
||||
} else position != limit
|
||||
}
|
||||
}
|
|
@ -1,381 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 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.bytes;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
@SuppressWarnings({"Duplicates", "NumericCastThatLosesPrecision", "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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
@file:Suppress("NAME_SHADOWING")
|
||||
|
||||
package dorkbox.bytes
|
||||
|
||||
import io.netty.buffer.ByteBuf
|
||||
|
||||
@Suppress("unused")
|
||||
object OptimizeUtilsByteBuf {
|
||||
// int
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* Returns the number of bytes that would be written with [.writeInt].
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
fun intLength(value: Int, optimizePositive: Boolean): Int {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
var value = value
|
||||
if (!optimizePositive) {
|
||||
value = value shl 1 xor (value shr 31)
|
||||
}
|
||||
if (value ushr 7 == 0) {
|
||||
return 1
|
||||
}
|
||||
if (value ushr 14 == 0) {
|
||||
return 2
|
||||
}
|
||||
if (value ushr 21 == 0) {
|
||||
return 3
|
||||
}
|
||||
return if (value ushr 28 == 0) {
|
||||
4
|
||||
} else 5
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
fun canReadInt(buffer: ByteBuf): Int {
|
||||
val startIndex = buffer.readerIndex()
|
||||
return try {
|
||||
var remaining = buffer.readableBytes()
|
||||
var offset = 0
|
||||
var count = 1
|
||||
while (offset < 32 && remaining > 0) {
|
||||
val b = buffer.readByte().toInt()
|
||||
if (b and 0x80 == 0) {
|
||||
return count
|
||||
}
|
||||
offset += 7
|
||||
remaining--
|
||||
count++
|
||||
}
|
||||
0
|
||||
} finally {
|
||||
buffer.readerIndex(startIndex)
|
||||
}
|
||||
}
|
||||
|
||||
fun canReadVarInt(buffer: ByteBuf): Boolean {
|
||||
val startIndex = buffer.readerIndex()
|
||||
try {
|
||||
var remaining = buffer.readableBytes()
|
||||
|
||||
if (remaining >= 5) return true
|
||||
|
||||
var p = startIndex
|
||||
if (buffer.getByte(p++).toInt() and 0x80 == 0) return true
|
||||
if (p == remaining) return false
|
||||
|
||||
if (buffer.getByte(p++).toInt() and 0x80 == 0) return true
|
||||
if (p == remaining) return false
|
||||
if (buffer.getByte(p++).toInt() and 0x80 == 0) return true
|
||||
if (p == remaining) return false
|
||||
if (buffer.getByte(p++).toInt() and 0x80 == 0) return true
|
||||
return if (p == remaining) false else true
|
||||
} finally {
|
||||
buffer.readerIndex(startIndex)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
fun readInt(buffer: ByteBuf, optimizePositive: Boolean = false): Int {
|
||||
var b = buffer.readByte().toInt()
|
||||
var result = b and 0x7F
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer.readByte().toInt()
|
||||
result = result or (b and 0x7F shl 7)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer.readByte().toInt()
|
||||
result = result or (b and 0x7F shl 14)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer.readByte().toInt()
|
||||
result = result or (b and 0x7F shl 21)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer.readByte().toInt()
|
||||
result = result or (b and 0x7F shl 28)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return if (optimizePositive) result else result ushr 1 xor -(result and 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
fun writeInt(buffer: ByteBuf, value: Int, optimizePositive: Boolean): Int {
|
||||
var value = value
|
||||
if (!optimizePositive) {
|
||||
value = value shl 1 xor (value shr 31)
|
||||
}
|
||||
if (value ushr 7 == 0) {
|
||||
buffer.writeByte(value.toByte().toInt())
|
||||
return 1
|
||||
}
|
||||
if (value ushr 14 == 0) {
|
||||
buffer.writeByte((value and 0x7F or 0x80).toByte().toInt())
|
||||
buffer.writeByte((value ushr 7).toByte().toInt())
|
||||
return 2
|
||||
}
|
||||
if (value ushr 21 == 0) {
|
||||
buffer.writeByte((value and 0x7F or 0x80).toByte().toInt())
|
||||
buffer.writeByte((value ushr 7 or 0x80).toByte().toInt())
|
||||
buffer.writeByte((value ushr 14).toByte().toInt())
|
||||
return 3
|
||||
}
|
||||
if (value ushr 28 == 0) {
|
||||
buffer.writeByte((value and 0x7F or 0x80).toByte().toInt())
|
||||
buffer.writeByte((value ushr 7 or 0x80).toByte().toInt())
|
||||
buffer.writeByte((value ushr 14 or 0x80).toByte().toInt())
|
||||
buffer.writeByte((value ushr 21).toByte().toInt())
|
||||
return 4
|
||||
}
|
||||
buffer.writeByte((value and 0x7F or 0x80).toByte().toInt())
|
||||
buffer.writeByte((value ushr 7 or 0x80).toByte().toInt())
|
||||
buffer.writeByte((value ushr 14 or 0x80).toByte().toInt())
|
||||
buffer.writeByte((value ushr 21 or 0x80).toByte().toInt())
|
||||
buffer.writeByte((value ushr 28).toByte().toInt())
|
||||
return 5
|
||||
}
|
||||
// long
|
||||
/**
|
||||
* Returns the 1-9 bytes that would be written with [.writeLong].
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun longLength(value: Long, optimizePositive: Boolean): Int {
|
||||
var value = value
|
||||
if (!optimizePositive) {
|
||||
value = value shl 1 xor (value shr 63)
|
||||
}
|
||||
if (value ushr 7 == 0L) {
|
||||
return 1
|
||||
}
|
||||
if (value ushr 14 == 0L) {
|
||||
return 2
|
||||
}
|
||||
if (value ushr 21 == 0L) {
|
||||
return 3
|
||||
}
|
||||
if (value ushr 28 == 0L) {
|
||||
return 4
|
||||
}
|
||||
if (value ushr 35 == 0L) {
|
||||
return 5
|
||||
}
|
||||
if (value ushr 42 == 0L) {
|
||||
return 6
|
||||
}
|
||||
if (value ushr 49 == 0L) {
|
||||
return 7
|
||||
}
|
||||
return if (value ushr 56 == 0L) {
|
||||
8
|
||||
} else 9
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
fun readLong(buffer: ByteBuf, optimizePositive: Boolean): Long {
|
||||
var b = buffer.readByte().toInt()
|
||||
var result = (b and 0x7F).toLong()
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer.readByte().toInt()
|
||||
result = result or (b and 0x7F shl 7).toLong()
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer.readByte().toInt()
|
||||
result = result or (b and 0x7F shl 14).toLong()
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer.readByte().toInt()
|
||||
result = result or (b and 0x7F shl 21).toLong()
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer.readByte().toInt()
|
||||
result = result or ((b and 0x7F).toLong() shl 28)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer.readByte().toInt()
|
||||
result = result or ((b and 0x7F).toLong() shl 35)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer.readByte().toInt()
|
||||
result = result or ((b and 0x7F).toLong() shl 42)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer.readByte().toInt()
|
||||
result = result or ((b and 0x7F).toLong() shl 49)
|
||||
if (b and 0x80 != 0) {
|
||||
b = buffer.readByte().toInt()
|
||||
result = result or (b.toLong() shl 56)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!optimizePositive) {
|
||||
result = result ushr 1 xor -(result and 1L)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
fun writeLong(buffer: ByteBuf, value: Long, optimizePositive: Boolean): Int {
|
||||
var value = value
|
||||
if (!optimizePositive) {
|
||||
value = value shl 1 xor (value shr 63)
|
||||
}
|
||||
if (value ushr 7 == 0L) {
|
||||
buffer.writeByte(value.toByte().toInt())
|
||||
return 1
|
||||
}
|
||||
if (value ushr 14 == 0L) {
|
||||
buffer.writeByte((value and 0x7FL or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 7).toByte().toInt())
|
||||
return 2
|
||||
}
|
||||
if (value ushr 21 == 0L) {
|
||||
buffer.writeByte((value and 0x7FL or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 7 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 14).toByte().toInt())
|
||||
return 3
|
||||
}
|
||||
if (value ushr 28 == 0L) {
|
||||
buffer.writeByte((value and 0x7FL or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 7 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 14 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 21).toByte().toInt())
|
||||
return 4
|
||||
}
|
||||
if (value ushr 35 == 0L) {
|
||||
buffer.writeByte((value and 0x7FL or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 7 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 14 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 21 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 28).toByte().toInt())
|
||||
return 5
|
||||
}
|
||||
if (value ushr 42 == 0L) {
|
||||
buffer.writeByte((value and 0x7FL or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 7 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 14 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 21 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 28 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 35).toByte().toInt())
|
||||
return 6
|
||||
}
|
||||
if (value ushr 49 == 0L) {
|
||||
buffer.writeByte((value and 0x7FL or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 7 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 14 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 21 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 28 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 35 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 42).toByte().toInt())
|
||||
return 7
|
||||
}
|
||||
if (value ushr 56 == 0L) {
|
||||
buffer.writeByte((value and 0x7FL or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 7 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 14 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 21 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 28 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 35 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 42 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 49).toByte().toInt())
|
||||
return 8
|
||||
}
|
||||
buffer.writeByte((value and 0x7FL or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 7 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 14 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 21 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 28 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 35 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 42 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 49 or 0x80L).toByte().toInt())
|
||||
buffer.writeByte((value ushr 56).toByte().toInt())
|
||||
return 9
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM KRYO
|
||||
*
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
fun canReadLong(buffer: ByteBuf): Int {
|
||||
val position = buffer.readerIndex()
|
||||
return try {
|
||||
var remaining = buffer.readableBytes()
|
||||
var offset = 0
|
||||
var count = 1
|
||||
while (offset < 64 && remaining > 0) {
|
||||
val b = buffer.readByte().toInt()
|
||||
if (b and 0x80 == 0) {
|
||||
return count
|
||||
}
|
||||
offset += 7
|
||||
remaining--
|
||||
count++
|
||||
}
|
||||
0
|
||||
} finally {
|
||||
buffer.readerIndex(position)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue