Created
June 26, 2024 19:10
-
-
Save Horusiath/534360134b35e79748b29742aa1e2382 to your computer and use it in GitHub Desktop.
varint encoding and length-prefix int encoding
This file contains 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
#[inline] | |
fn zigzag_encode(from: i64) -> u64 { | |
((from << 1) ^ (from >> 63)) as u64 | |
} | |
// see: http://stackoverflow.com/a/2211086/56332 | |
// casting required because operations like unary negation | |
// cannot be performed on unsigned integers | |
#[inline] | |
fn zigzag_decode(from: u64) -> i64 { | |
((from >> 1) ^ (-((from & 1) as i64)) as u64) as i64 | |
} | |
const CONTINUATION_FLAG: u8 = 0b1000_0000; | |
const MASK: u8 = 0 ^ CONTINUATION_FLAG; | |
fn varint_encode(mut n: u64, buf: &mut [u8]) -> usize { | |
let mut i = 0; | |
while n >= CONTINUATION_FLAG as u64 { | |
// n won't fit in 7 bits, take the lowest 7 bits of n | |
// and set the continuation bit | |
buf[i] = MASK | (n as u8); | |
n >>= 7; | |
i += 1; | |
} | |
// put remaining bits in the last byte | |
buf[i] = n as u8; | |
i + 1 | |
} | |
fn varint_decode(bytes: &[u8]) -> Option<(u64, usize)> { | |
let mut result: u64 = 0; | |
// varint from u64 will never take more than 10 bytes | |
for i in 0..bytes.len().min(10) { | |
let byte = bytes[i]; | |
// clear the continuation bit and shift byte by 7 bits * its position | |
result |= ((byte & MASK) as u64) << (i * 7); | |
if byte & CONTINUATION_FLAG == 0 { | |
// continuation bit not set, finished decoding | |
return Some((result, i)); | |
} | |
} | |
None // never to stop byte | |
} | |
fn prefix_encode(mut n: u64, buf: &mut [u8]) -> usize { | |
let mut i = 0; | |
let mut j = 1; | |
while i < 8 { | |
let byte = (n >> 8 * (7 - i)) as u8; | |
if byte != 0 { | |
buf[j] = byte; | |
j += 1; | |
} | |
} | |
buf[0] = (j - 1) as u8; | |
j | |
} | |
fn prefix_decode(bytes: &[u8]) -> Option<(u64, usize)> { | |
let len = bytes[0] as usize; | |
if len > bytes.len() || len > 9 { | |
return None; | |
} | |
let mut result = [0; 8]; | |
result.copy_from_slice(&bytes[1..=len]); | |
Some((u64::from_be_bytes(result), len)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment