pub type HilbertFn = fn(u16, u16) -> u32;
pub const ENCODERS: &[(&str, HilbertFn)] = &[
("magic_bits", magic_bits),
("loop_rotation", loop_rotation),
("lut", lut),
];
#[inline]
pub fn magic_bits(x: u16, y: u16) -> u32 {
let x = x as u32;
let y = y as u32;
let mut a_1 = x ^ y;
let mut b_1 = 0xFFFF ^ a_1;
let mut c_1 = 0xFFFF ^ (x | y);
let mut d_1 = x & (y ^ 0xFFFF);
let mut a_2 = a_1 | (b_1 >> 1);
let mut b_2 = (a_1 >> 1) ^ a_1;
let mut c_2 = ((c_1 >> 1) ^ (b_1 & (d_1 >> 1))) ^ c_1;
let mut d_2 = ((a_1 & (c_1 >> 1)) ^ (d_1 >> 1)) ^ d_1;
a_1 = a_2;
b_1 = b_2;
c_1 = c_2;
d_1 = d_2;
a_2 = (a_1 & (a_1 >> 2)) ^ (b_1 & (b_1 >> 2));
b_2 = (a_1 & (b_1 >> 2)) ^ (b_1 & ((a_1 ^ b_1) >> 2));
c_2 ^= (a_1 & (c_1 >> 2)) ^ (b_1 & (d_1 >> 2));
d_2 ^= (b_1 & (c_1 >> 2)) ^ ((a_1 ^ b_1) & (d_1 >> 2));
a_1 = a_2;
b_1 = b_2;
c_1 = c_2;
d_1 = d_2;
a_2 = (a_1 & (a_1 >> 4)) ^ (b_1 & (b_1 >> 4));
b_2 = (a_1 & (b_1 >> 4)) ^ (b_1 & ((a_1 ^ b_1) >> 4));
c_2 ^= (a_1 & (c_1 >> 4)) ^ (b_1 & (d_1 >> 4));
d_2 ^= (b_1 & (c_1 >> 4)) ^ ((a_1 ^ b_1) & (d_1 >> 4));
a_1 = a_2;
b_1 = b_2;
c_1 = c_2;
d_1 = d_2;
c_2 ^= (a_1 & (c_1 >> 8)) ^ (b_1 & (d_1 >> 8));
d_2 ^= (b_1 & (c_1 >> 8)) ^ ((a_1 ^ b_1) & (d_1 >> 8));
a_1 = c_2 ^ (c_2 >> 1);
b_1 = d_2 ^ (d_2 >> 1);
let mut i0 = x ^ y;
let mut i1 = b_1 | (0xFFFF ^ (i0 | a_1));
i0 = (i0 | (i0 << 8)) & 0x00FF00FF;
i0 = (i0 | (i0 << 4)) & 0x0F0F0F0F;
i0 = (i0 | (i0 << 2)) & 0x33333333;
i0 = (i0 | (i0 << 1)) & 0x55555555;
i1 = (i1 | (i1 << 8)) & 0x00FF00FF;
i1 = (i1 | (i1 << 4)) & 0x0F0F0F0F;
i1 = (i1 | (i1 << 2)) & 0x33333333;
i1 = (i1 | (i1 << 1)) & 0x55555555;
(i1 << 1) | i0
}
const BITS: u32 = 16;
pub fn magic_bits_batch(xs: &[u16], ys: &[u16], out: &mut [u32]) {
let n = out.len();
assert!(xs.len() == n && ys.len() == n);
for i in 0..n {
out[i] = magic_bits(xs[i], ys[i]);
}
}
#[inline]
pub fn morton(x: u16, y: u16) -> u32 {
#[inline]
fn part1by1(mut n: u32) -> u32 {
n &= 0x0000FFFF;
n = (n | (n << 8)) & 0x00FF00FF;
n = (n | (n << 4)) & 0x0F0F0F0F;
n = (n | (n << 2)) & 0x33333333;
n = (n | (n << 1)) & 0x55555555;
n
}
part1by1(x as u32) | (part1by1(y as u32) << 1)
}
#[inline]
pub fn loop_rotation(x: u16, y: u16) -> u32 {
let mut x = x as u32;
let mut y = y as u32;
let mut d: u32 = 0;
let mut s: u32 = 1 << (BITS - 1);
while s > 0 {
let rx = u32::from((x & s) > 0);
let ry = u32::from((y & s) > 0);
d = (d << 2) | ((3 * rx) ^ ry);
rot(s, &mut x, &mut y, rx, ry);
s >>= 1;
}
d
}
#[inline]
fn rot(n: u32, x: &mut u32, y: &mut u32, rx: u32, ry: u32) {
if ry == 0 {
if rx == 1 {
*x = (2 * n - 1).wrapping_sub(*x);
*y = (2 * n - 1).wrapping_sub(*y);
}
std::mem::swap(x, y);
}
}
struct LutTables {
emit: [[u8; 256]; 4],
next: [[u8; 256]; 4],
}
static LUT: LutTables = build_lut();
const fn build_lut() -> LutTables {
let mut f_emit = [[0u8; 4]; 4];
let mut f_next = [[0u8; 4]; 4];
let mut state = 0usize;
while state < 4 {
let swap = (state & 1) as u8;
let flip = ((state >> 1) & 1) as u8;
let mut q = 0usize;
while q < 4 {
let mut a = ((q >> 1) & 1) as u8;
let mut b = (q & 1) as u8;
if flip == 1 {
a ^= 1;
b ^= 1;
}
if swap == 1 {
let tmp = a;
a = b;
b = tmp;
}
let (rx, ry) = (a as u32, b as u32);
f_emit[state][q] = ((3 * rx) ^ ry) as u8;
let (rot_swap, rot_flip) = if ry == 1 {
(0u8, 0u8) } else if rx == 0 {
(1u8, 0u8) } else {
(1u8, 1u8) };
f_next[state][q] = (rot_swap ^ swap) | ((rot_flip ^ flip) << 1);
q += 1;
}
state += 1;
}
let mut emit = [[0u8; 256]; 4];
let mut next = [[0u8; 256]; 4];
let mut s = 0usize;
while s < 4 {
let mut idx = 0usize;
while idx < 256 {
let xnib = (idx >> 4) & 0xF;
let ynib = idx & 0xF;
let mut st = s;
let mut out = 0u32;
let mut bit = 4usize;
while bit > 0 {
bit -= 1;
let a = (xnib >> bit) & 1;
let b = (ynib >> bit) & 1;
let q = (a << 1) | b;
out = (out << 2) | f_emit[st][q] as u32;
st = f_next[st][q] as usize;
}
emit[s][idx] = out as u8;
next[s][idx] = st as u8;
idx += 1;
}
s += 1;
}
LutTables { emit, next }
}
#[inline]
pub fn lut(x: u16, y: u16) -> u32 {
let x = x as u32;
let y = y as u32;
let mut state = 0usize;
let mut d: u32 = 0;
let mut shift = BITS;
while shift > 0 {
shift -= 4;
let xnib = (x >> shift) & 0xF;
let ynib = (y >> shift) & 0xF;
let idx = ((xnib << 4) | ynib) as usize;
d = (d << 8) | LUT.emit[state][idx] as u32;
state = LUT.next[state][idx] as usize;
}
d
}