Skip to content

Instantly share code, notes, and snippets.

@ultraviolet-jordan
Created March 30, 2023 03:58
Show Gist options
  • Save ultraviolet-jordan/e4b743a023532336cb9475c649ce7a17 to your computer and use it in GitHub Desktop.
Save ultraviolet-jordan/e4b743a023532336cb9475c649ce7a17 to your computer and use it in GitHub Desktop.
import java.nio.ByteBuffer
import kotlin.math.abs
fun main() {
val expectedInt = 420
val buffer = ByteBuffer.allocate(3)
buffer.putAsVl64(expectedInt)
buffer.flip()
val readInt = buffer.getAsVl64()
println("Matches? ${expectedInt == readInt}")
}
private tailrec fun ByteBuffer.putAsVl64(
value: Int,
abs: Int = abs(value),
position: Int = position(), // The current position of this buffer used to track the prefix byte.
size: Int = 1 // Current number of bytes written.
): ByteBuffer {
if (size == 1) {
// Set prefix byte at this current position. This is only called the first iteration.
put((64 + (abs and 3)).toByte())
}
val nextByte = (abs shr 2) shr (6 * (size - 1))
if (nextByte != 0) {
// Append a new byte to the buffer with the next 6 bits of the absolute value.
put((64 + (nextByte and 0x3F)).toByte())
return putAsVl64(value, abs, position, size + 1)
}
// Modify the prefix byte to include the size and sign of the integer.
val prefix = get(position).toInt()
put(position, (prefix or (size shl 3) or if (value >= 0) 0 else 4).toByte())
return this
}
private tailrec fun ByteBuffer.getAsVl64(
prefix: Int = get().toInt(), // The prefix byte at the first position.
value: Int = prefix and 3, // Least significant bits of the first byte
position: Int = 1 // Position of the next byte to decode
): Int {
// The total number of bytes to read.
val size = prefix shr 3 and 7
return if (position < size) {
// Shift amount for the next byte's bits
val shift = 2 + (6 * (position - 1))
val nextByte = get().toInt() and 0x3F
val nextValue = (nextByte shl shift) or value
getAsVl64(prefix, nextValue, position + 1)
} else {
if (prefix and 4 == 4) -(value xor ((1 shl (size * 6)) - 1)) else value
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment