Last active
March 5, 2022 22:11
-
-
Save tk2217/d004396b3d8e865f1290c64e7d3f85c2 to your computer and use it in GitHub Desktop.
A semi-optimized java class to work with varints.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.tk2217.util; | |
import io.netty.buffer.ByteBuf; | |
public class VarInts { | |
/* Bazel varint reading routines | |
* https://github.com/bazelbuild/bazel/blob/master/src/main/java/com/google/devtools/build/lib/util/VarInt.java | |
* Licensed under the Apache License 2.0. | |
* Slightly modified to use a `ByteBuf`. | |
*/ | |
/** | |
* Reads a varint from the current position of the given ByteBuf and returns the decoded value | |
* as 32 bit integer. | |
* | |
* <p>The position of the buffer is advanced to the first byte after the decoded varint. | |
* | |
* @param src the ByteBuf to readByte the var int from | |
* @return The integer value of the decoded varint | |
*/ | |
public static int readVarInt(ByteBuf src) { | |
int tmp; | |
if ((tmp = src.readByte()) >= 0) { | |
return tmp; | |
} | |
int result = tmp & 0x7f; | |
if ((tmp = src.readByte()) >= 0) { | |
result |= tmp << 7; | |
} else { | |
result |= (tmp & 0x7f) << 7; | |
if ((tmp = src.readByte()) >= 0) { | |
result |= tmp << 14; | |
} else { | |
result |= (tmp & 0x7f) << 14; | |
if ((tmp = src.readByte()) >= 0) { | |
result |= tmp << 21; | |
} else { | |
result |= (tmp & 0x7f) << 21; | |
result |= (tmp = src.readByte()) << 28; | |
while (tmp < 0) { | |
// We readByte into this loop only in the case of overflow. | |
// By doing this, we can call readByteVarInt() instead of | |
// readByteVarLong() when we only need an int. | |
tmp = src.readByte(); | |
} | |
} | |
} | |
} | |
return result; | |
} | |
/** | |
* Reads an up to 64 bit long varint from the current position of the | |
* given ByteBuf and returns the decoded value as long. | |
* | |
* <p>The position of the buffer is advanced to the first byte after the | |
* decoded varint. | |
* | |
* @param src the ByteBuf to get the var int from | |
* @return The integer value of the decoded long varint | |
*/ | |
public static long getVarLong(ByteBuf src) { | |
long tmp; | |
if ((tmp = src.readByte()) >= 0) { | |
return tmp; | |
} | |
long result = tmp & 0x7f; | |
if ((tmp = src.readByte()) >= 0) { | |
result |= tmp << 7; | |
} else { | |
result |= (tmp & 0x7f) << 7; | |
if ((tmp = src.readByte()) >= 0) { | |
result |= tmp << 14; | |
} else { | |
result |= (tmp & 0x7f) << 14; | |
if ((tmp = src.readByte()) >= 0) { | |
result |= tmp << 21; | |
} else { | |
result |= (tmp & 0x7f) << 21; | |
if ((tmp = src.readByte()) >= 0) { | |
result |= tmp << 28; | |
} else { | |
result |= (tmp & 0x7f) << 28; | |
if ((tmp = src.readByte()) >= 0) { | |
result |= tmp << 35; | |
} else { | |
result |= (tmp & 0x7f) << 35; | |
if ((tmp = src.readByte()) >= 0) { | |
result |= tmp << 42; | |
} else { | |
result |= (tmp & 0x7f) << 42; | |
if ((tmp = src.readByte()) >= 0) { | |
result |= tmp << 49; | |
} else { | |
result |= (tmp & 0x7f) << 49; | |
if ((tmp = src.readByte()) >= 0) { | |
result |= tmp << 56; | |
} else { | |
result |= (tmp & 0x7f) << 56; | |
result |= ((long) src.readByte()) << 63; | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
return result; | |
} | |
/* astei's fast varint writing routines | |
* https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/ | |
* Licensed under the MIT License. | |
*/ | |
/** | |
* Encodes a varint to a ByteBuf. | |
* @param buf the ByteBuf to write to | |
* @param value the value to encode | |
*/ | |
public static void writeVarInt(ByteBuf buf, int value) { | |
if ((value & (0xFFFFFFFF << 7)) == 0) { | |
buf.writeByte(value); | |
} else if ((value & (0xFFFFFFFF << 14)) == 0) { | |
int w = (value & 0x7F | 0x80) << 8 | (value >>> 7); | |
buf.writeShort(w); | |
} else if ((value & (0xFFFFFFFF << 21)) == 0) { | |
int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14); | |
buf.writeMedium(w); | |
} else if ((value & (0xFFFFFFFF << 28)) == 0) { | |
int w = (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16) | |
| ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21); | |
buf.writeInt(w); | |
} else { | |
int w = (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16 | ((value >>> 14) & 0x7F | 0x80) << 8 | |
| ((value >>> 21) & 0x7F | 0x80); | |
buf.writeInt(w); | |
buf.writeByte(value >>> 28); | |
} | |
} | |
/* Bazel varlong writing routine ~ I can't be bothered to transfer over the previous routine and this isn't used nearly as much. | |
* https://github.com/bazelbuild/bazel/blob/master/src/main/java/com/google/devtools/build/lib/util/VarInt.java | |
* Licensed under the Apache License 2.0. | |
* Slightly modified to use a `ByteBuf` and reorder arguments. | |
*/ | |
/** | |
* Encodes a long integer in a variable-length encoding, 7 bits per byte, to a | |
* ByteBuf. | |
* @param buf the ByteBuf to add the encoded value | |
* @param value the value to encode | |
*/ | |
public static void writeVarLong(ByteBuf buf, long value) { | |
while (true) { | |
int bits = ((int) value) & 0x7f; | |
value >>>= 7; | |
if (value == 0) { | |
buf.writeByte((byte) bits); | |
return; | |
} | |
buf.writeByte((byte) (bits | 0x80)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment