Skip to content

Instantly share code, notes, and snippets.

@tk2217
Last active March 5, 2022 22:11
Show Gist options
  • Save tk2217/d004396b3d8e865f1290c64e7d3f85c2 to your computer and use it in GitHub Desktop.
Save tk2217/d004396b3d8e865f1290c64e7d3f85c2 to your computer and use it in GitHub Desktop.
A semi-optimized java class to work with varints.
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