const fn crc16_table() -> [u16; 256] {
let mut table = [0u16; 256];
let mut i = 0usize;
while i < 256 {
let mut crc = (i as u16) << 8;
let mut bit = 0;
while bit < 8 {
crc = if crc & 0x8000 != 0 {
(crc << 1) ^ 0x1021
} else {
crc << 1
};
bit += 1;
}
table[i] = crc;
i += 1;
}
table
}
static CRC16_TABLE: [u16; 256] = crc16_table();
#[inline]
pub fn crc16(data: &[u8]) -> u16 {
let mut crc: u16 = 0;
for &b in data {
let idx = (((crc >> 8) ^ b as u16) & 0xff) as usize;
crc = (crc << 8) ^ CRC16_TABLE[idx];
}
crc
}
pub const SLOT_COUNT: u16 = 16384;
#[inline]
pub fn slot_of(key: &[u8]) -> u16 {
crc16(hash_tag(key)) & (SLOT_COUNT - 1)
}
#[inline]
pub fn hash_tag(key: &[u8]) -> &[u8] {
let Some(open) = key.iter().position(|&b| b == b'{') else {
return key;
};
let rest = &key[open + 1..];
let Some(close) = rest.iter().position(|&b| b == b'}') else {
return key;
};
if close == 0 {
return key;
}
&rest[..close]
}
const fn crc32c_table() -> [u32; 256] {
let mut table = [0u32; 256];
let mut i = 0usize;
while i < 256 {
let mut crc = i as u32;
let mut bit = 0;
while bit < 8 {
crc = if crc & 1 != 0 {
(crc >> 1) ^ 0x82F6_3B78
} else {
crc >> 1
};
bit += 1;
}
table[i] = crc;
i += 1;
}
table
}
static CRC32C_TABLE: [u32; 256] = crc32c_table();
#[inline]
fn crc32c_software(mut crc: u32, data: &[u8]) -> u32 {
crc = !crc;
for &b in data {
crc = (crc >> 8) ^ CRC32C_TABLE[((crc ^ b as u32) & 0xff) as usize];
}
!crc
}
#[inline]
pub fn crc32c(crc: u32, data: &[u8]) -> u32 {
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("sse4.2") {
return unsafe { crc32c_sse42(crc, data) };
}
}
crc32c_software(crc, data)
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "sse4.2")]
unsafe fn crc32c_sse42(crc: u32, data: &[u8]) -> u32 {
use core::arch::x86_64::{_mm_crc32_u8, _mm_crc32_u64};
let mut c = !crc;
let (words, rest) = data.as_chunks::<8>();
for chunk in words {
c = _mm_crc32_u64(c as u64, u64::from_le_bytes(*chunk)) as u32;
}
for &b in rest {
c = _mm_crc32_u8(c, b);
}
!c
}
const fn crc64_table() -> [u64; 256] {
let mut table = [0u64; 256];
let mut i = 0usize;
while i < 256 {
let mut crc = i as u64;
let mut bit = 0;
while bit < 8 {
crc = if crc & 1 != 0 {
(crc >> 1) ^ 0x95AC_9329_AC4B_C9B5
} else {
crc >> 1
};
bit += 1;
}
table[i] = crc;
i += 1;
}
table
}
static CRC64_TABLE: [u64; 256] = crc64_table();
#[inline]
pub fn crc64(crc: u64, data: &[u8]) -> u64 {
let mut c = crc;
for &b in data {
c = (c >> 8) ^ CRC64_TABLE[((c ^ b as u64) & 0xff) as usize];
}
c
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn redis_slot_examples() {
assert_eq!(crc16(b"123456789"), 0x31C3);
assert_eq!(slot_of(b"foo"), 12182);
assert_eq!(slot_of(b"bar"), 5061);
}
#[test]
fn hash_tags_pick_the_inner_run() {
assert_eq!(hash_tag(b"{user1000}.following"), b"user1000");
assert_eq!(hash_tag(b"foo{}{bar}"), b"foo{}{bar}");
assert_eq!(hash_tag(b"foo{{bar}}zap"), b"{bar");
assert_eq!(hash_tag(b"foo{bar}{zap}"), b"bar");
assert_eq!(hash_tag(b"nothing"), b"nothing");
}
#[test]
fn tagged_keys_land_on_one_slot() {
assert_eq!(
slot_of(b"{user1000}.following"),
slot_of(b"{user1000}.followers")
);
}
#[test]
fn crc32c_reference() {
assert_eq!(crc32c(0, b"123456789"), 0xE306_9283);
assert_eq!(crc32c(0, b""), 0);
}
#[test]
fn crc32c_hardware_matches_software() {
let buf: Vec<u8> = (0..1000u32).map(|i| (i * 7 % 251) as u8).collect();
for n in [0usize, 1, 7, 8, 9, 15, 16, 63, 64, 65, 999, 1000] {
assert_eq!(
crc32c(0, &buf[..n]),
crc32c_software(0, &buf[..n]),
"length {n} disagrees between the two paths"
);
}
}
#[test]
fn crc32c_is_resumable() {
let buf: Vec<u8> = (0..256u32).map(|i| i as u8).collect();
let one_shot = crc32c(0, &buf);
let split = crc32c(crc32c(0, &buf[..100]), &buf[100..]);
assert_eq!(one_shot, split);
}
#[test]
fn crc64_matches_the_redis_self_test() {
assert_eq!(crc64(0, b"123456789"), 0xe9c6_d914_c4b8_d9ca);
assert_eq!(crc64(0, b""), 0);
}
#[test]
fn crc64_is_resumable() {
let buf: Vec<u8> = (0..256u32).map(|i| i as u8).collect();
assert_eq!(crc64(0, &buf), crc64(crc64(0, &buf[..100]), &buf[100..]));
}
}