use super::modulo::{ModuloDoubleRaw, ModuloLargeRaw, ModuloSingleRaw};
use crate::{
arch::word::{DoubleWord, Word},
buffer::Buffer,
cmp,
error::panic_divide_by_0,
fast_div::{
ConstDoubleDivisor, ConstLargeDivisor, ConstSingleDivisor, FastDivideNormalized,
FastDivideNormalized2,
},
math,
primitive::shrink_dword,
repr::{Repr, TypedRepr},
ubig::UBig,
};
use core::cmp::Ordering;
pub struct ModuloRing(ModuloRingRepr);
pub(crate) enum ModuloRingRepr {
Single(ModuloRingSingle),
Double(ModuloRingDouble),
Large(ModuloRingLarge),
}
pub(crate) struct ModuloRingSingle(pub(super) ConstSingleDivisor);
pub(crate) struct ModuloRingDouble(pub(super) ConstDoubleDivisor);
pub(crate) struct ModuloRingLarge(pub(super) ConstLargeDivisor);
impl ModuloRing {
#[inline]
pub fn new(n: UBig) -> ModuloRing {
Self(match n.into_repr() {
TypedRepr::Small(0) => panic_divide_by_0(),
TypedRepr::Small(dword) => {
if let Some(word) = shrink_dword(dword) {
ModuloRingRepr::Single(ModuloRingSingle::new(word))
} else {
ModuloRingRepr::Double(ModuloRingDouble::new(dword))
}
}
TypedRepr::Large(words) => ModuloRingRepr::Large(ModuloRingLarge::new(words)),
})
}
#[inline]
pub(crate) fn repr(&self) -> &ModuloRingRepr {
&self.0
}
}
impl ModuloRingSingle {
#[inline]
pub const fn new(n: Word) -> Self {
Self(ConstSingleDivisor::new(n))
}
#[inline]
pub const fn normalized_modulus(&self) -> Word {
self.0.fast_div.divisor
}
#[inline]
pub const fn modulus(&self) -> UBig {
UBig(Repr::from_word(self.0.divisor()))
}
#[inline]
pub const fn shift(&self) -> u32 {
self.0.shift
}
#[inline]
pub const fn fast_div(&self) -> FastDivideNormalized {
self.0.fast_div
}
#[inline]
pub const fn is_valid(&self, val: ModuloSingleRaw) -> bool {
val.0 < self.normalized_modulus() && val.0 & math::ones_word(self.shift()) == 0
}
}
impl ModuloRingDouble {
#[inline]
pub const fn new(n: DoubleWord) -> Self {
Self(ConstDoubleDivisor::new(n))
}
#[inline]
pub const fn normalized_modulus(&self) -> DoubleWord {
self.0.fast_div.divisor
}
#[inline]
pub const fn modulus(&self) -> UBig {
UBig(Repr::from_dword(self.0.divisor()))
}
#[inline]
pub const fn shift(&self) -> u32 {
self.0.shift
}
#[inline]
pub const fn fast_div(&self) -> FastDivideNormalized2 {
self.0.fast_div
}
#[inline]
pub const fn is_valid(&self, val: ModuloDoubleRaw) -> bool {
val.0 < self.normalized_modulus() && val.0 & math::ones_dword(self.shift()) == 0
}
}
impl ModuloRingLarge {
#[inline]
pub fn new(n: Buffer) -> ModuloRingLarge {
Self(ConstLargeDivisor::new(n))
}
#[inline]
pub fn normalized_modulus(&self) -> &[Word] {
&self.0.normalized_modulus
}
#[inline]
pub fn modulus(&self) -> UBig {
UBig(Repr::from_buffer(self.0.divisor()))
}
#[inline]
pub fn shift(&self) -> u32 {
self.0.shift
}
#[inline]
pub fn fast_div_top(&self) -> FastDivideNormalized2 {
self.0.fast_div_top
}
#[inline]
pub fn is_valid(&self, val: &ModuloLargeRaw) -> bool {
val.0.len() == self.normalized_modulus().len()
&& cmp::cmp_same_len(&val.0, self.normalized_modulus()) == Ordering::Less
&& val.0[0] & math::ones_word(self.shift()) == 0 }
}