use crate::word::Word;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub struct Dilated<W: Word, const D: u32>(W);
impl<W: Word, const D: u32> Dilated<W, D> {
#[inline]
#[must_use]
pub fn mask() -> W {
let mut m = W::ZERO;
let mut i = 0;
while i < W::BITS {
m = m.or(W::ONE.shl(i));
i += D;
}
m
}
#[inline]
#[must_use]
pub const fn width() -> u32 {
W::BITS.div_ceil(D)
}
#[inline]
#[must_use]
pub fn from_int(x: W) -> Self {
Self(x.pdep(Self::mask()))
}
#[inline]
#[must_use]
pub fn into_int(self) -> W {
self.0.pext(Self::mask())
}
#[inline]
#[must_use]
pub fn from_bits(bits: W) -> Self {
debug_assert!(
bits.and(Self::mask().not()).is_zero(),
"bits outside dilation mask"
);
Self(bits)
}
#[inline]
#[must_use]
pub const fn bits(self) -> W {
self.0
}
#[inline]
#[must_use]
pub fn incr(self) -> Self {
let m = Self::mask();
Self(self.0.or(m.not()).wrapping_add(W::ONE).and(m))
}
#[inline]
#[must_use]
pub fn decr(self) -> Self {
Self(self.0.wrapping_sub(W::ONE).and(Self::mask()))
}
#[inline]
#[must_use]
pub fn wrapping_add(self, other: Self) -> Self {
let m = Self::mask();
Self(self.0.or(m.not()).wrapping_add(other.0).and(m))
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
pub struct Morton2<W: Word>(W);
impl<W: Word> Morton2<W> {
#[inline]
#[must_use]
pub fn encode(x: W, y: W) -> Self {
let xd = Dilated::<W, 2>::from_int(x).bits();
let yd = Dilated::<W, 2>::from_int(y).bits();
Self(xd.or(yd.shl(1)))
}
#[inline]
#[must_use]
pub fn decode(self) -> (W, W) {
(self.x().into_int(), self.y().into_int())
}
#[inline]
#[must_use]
pub const fn from_code(code: W) -> Self {
Self(code)
}
#[inline]
#[must_use]
pub const fn code(self) -> W {
self.0
}
#[inline]
#[must_use]
pub fn x(self) -> Dilated<W, 2> {
Dilated::from_bits(self.0.and(Dilated::<W, 2>::mask()))
}
#[inline]
#[must_use]
pub fn y(self) -> Dilated<W, 2> {
Dilated::from_bits(self.0.shr(1).and(Dilated::<W, 2>::mask()))
}
#[inline]
#[must_use]
pub fn with_x(self, x: Dilated<W, 2>) -> Self {
Self(self.0.and(Dilated::<W, 2>::mask().not()).or(x.bits()))
}
#[inline]
#[must_use]
pub fn with_y(self, y: Dilated<W, 2>) -> Self {
Self(self.0.and(Dilated::<W, 2>::mask()).or(y.bits().shl(1)))
}
#[inline]
#[must_use]
pub fn step_x(self) -> Self {
self.with_x(self.x().incr())
}
#[inline]
#[must_use]
pub fn step_y(self) -> Self {
self.with_y(self.y().incr())
}
}