use crate::*;
use noether::*;
use num_traits::*;
use std::ops::*;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ModularDyn<T: Sized> {
pub inner: T,
pub modulo: T,
}
impl<T: PartialOrd> ModularDyn<T> {
pub fn new(inner: T, modulo: T) -> Self {
debug_assert!(inner < modulo);
Self {
inner: inner,
modulo: modulo,
}
}
}
impl<T: Clone + PartialOrd + Zero + WrappingAdd + WrappingSub + One> Add
for ModularDyn<T>
{
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
debug_assert!(self.modulo == rhs.modulo);
let sum = self.inner.wrapping_add(&rhs.inner);
let power_of_two = self.modulo.clone() - T::one() == T::zero().wrapping_sub(&T::one()).into();
let r = if power_of_two {
sum
} else {
let wraparound = self.modulo.clone().wrapping_add(&(self.modulo.clone() - T::one())) > T::zero().wrapping_sub(&T::one()).into();
if wraparound && sum < rhs.inner
|| !wraparound && sum > self.modulo.clone()
{
sum - self.modulo.clone()
} else {
sum
}
};
Self { inner: r, modulo: self.modulo }
}
}