use crate::clmul;
#[inline]
pub fn morton_encode(x: u64, y: u64) -> u128 {
let xd = dilate(x);
let yd = dilate(y);
(yd << 1) | xd
}
#[inline]
pub fn dilate(x: u64) -> u128 {
clmul(x, x)
}
#[inline]
pub fn morton_encode_magic(x: u64, y: u64) -> u64 {
let xd = dilate_magic(x);
let yd = dilate_magic(y);
(yd << 1) | xd
}
#[inline]
pub fn dilate_magic(x: u64) -> u64 {
let x = (x | (x << 8)) & 0x00FF00FF;
let x = (x | (x << 4)) & 0x0F0F0F0F;
let x = (x | (x << 2)) & 0x0F0F0F0F;
let x = (x | (x << 2)) & 0x55555555;
x
}
#[cfg(test)]
mod tests {
use super::*;
extern crate std;
#[test]
fn test_dilate() {
let input = 0b1101;
let expected = 0b1010001;
let res = dilate(input);
assert_eq!(res, expected);
}
#[test]
fn test_morton_encode() {
let x = 543;
let y = 23765;
let res = morton_encode(x, y);
let res_magic = morton_encode_magic(x, y);
println!("X {:032b}", x);
println!("Y {:032b}", y);
println!("R {:032b}", res);
println!("M {:032b}", res_magic);
let roundtrip: [u32; 2] = morton_encoding::morton_decode(res as u64);
println!("Rt {:?}", roundtrip);
}
#[test]
fn test_morton_decode() {
use morton_encoding::{morton_decode, morton_encode};
let input = 992;
let output: [u8; 5] = morton_decode(input);
assert_eq!(output, [2u8; 5]);
let input = [543u32, 23765];
let encoded_input: u64 = morton_encode(input);
let reassembled_input: [u32; 2] = morton_decode(encoded_input);
assert_eq!(input, reassembled_input);
}
#[test]
fn test_decode() {
let b = [0x55555555u32, 0x33333333, 0x0F0F0F0F, 0x00FF00FF];
let mut x = 0b1111_1111_1111_1111;
for (i, b) in b.iter().enumerate().rev() {
let s = 1 << i;
println!("{}: s={}", i, s);
println!("x= {:032b}", x);
println!("x<<s= {:032b}", x << s);
println!("x|x<<s={:032b}", (x << s) | x);
println!("b= {:032b}", b);
let x = (x | (x << s)) & b;
println!("x'= {:032b}", x);
}
}
}