use std::fmt;
use crate::Exceptions;
use crate::common::Result;
use super::{GenericGFPoly, GenericGFRef};
pub(crate) const MAX_GF_SIZE: usize = 4096;
type InternalTableType = u16;
#[derive(Debug, PartialEq, Eq)]
pub struct GenericGF {
expTable: [InternalTableType; MAX_GF_SIZE],
logTable: [InternalTableType; MAX_GF_SIZE],
size: usize,
primitive: i32,
generatorBase: i32,
}
impl GenericGF {
pub const fn new(primitive: i32, size: usize, b: i32) -> Self {
debug_assert!(
size <= MAX_GF_SIZE,
"GenericGF field size exceeds MAX_GF_SIZE"
);
let mut expTable = [0; MAX_GF_SIZE];
let mut logTable = [0; MAX_GF_SIZE];
let mut x: i32 = 1;
let mut i = 0;
while i < size {
expTable[i] = x as InternalTableType;
x *= 2; if x >= size as i32 {
x ^= primitive;
let sz_m_1: i32 = size as i32 - 1;
x &= sz_m_1;
}
i += 1;
}
let mut i = 0;
while i < size - 1 {
let loc = expTable[i] as usize;
logTable[loc] = i as InternalTableType;
i += 1;
}
logTable[0] = 0;
Self {
expTable,
logTable,
size,
primitive,
generatorBase: b,
}
}
pub fn buildMonomial(source: GenericGFRef, degree: usize, coefficient: i32) -> GenericGFPoly {
if coefficient == 0 {
return GenericGFPoly::new(source, &[0]).unwrap();
}
let mut coefficients = vec![0; degree + 1];
coefficients[0] = coefficient;
GenericGFPoly::new(source, &coefficients).unwrap()
}
pub const fn addOrSubtract(a: i32, b: i32) -> i32 {
a ^ b
}
pub const fn exp(&self, a: i32) -> i32 {
debug_assert!((a as usize) < self.size, "GF element out of range");
self.expTable[a as usize] as i32
}
pub const fn log(&self, a: i32) -> Result<i32> {
if a == 0 {
return Err(Exceptions::ILLEGAL_ARGUMENT);
}
if (a as usize) >= self.size {
return Err(Exceptions::ILLEGAL_ARGUMENT);
}
Ok(self.logTable[a as usize] as i32)
}
pub const fn inverse(&self, a: i32) -> Result<i32> {
if a == 0 {
return Err(Exceptions::ARITHMETIC);
}
let log_t_loc: usize = a as usize;
if log_t_loc >= self.size {
return Err(Exceptions::ILLEGAL_ARGUMENT);
}
let loc: usize = ((self.size as i32) - self.logTable[log_t_loc] as i32 - 1) as usize;
Ok(self.expTable[loc] as i32)
}
pub const fn multiply(&self, a: i32, b: i32) -> i32 {
if a == 0 || b == 0 {
return 0;
}
let a_loc: usize = a as usize;
let b_loc: usize = b as usize;
debug_assert!(
a_loc < self.size && b_loc < self.size,
"GF element out of range"
);
let comb_loc: usize = self.logTable[a_loc] as usize + self.logTable[b_loc] as usize;
self.expTable[comb_loc % (self.size - 1)] as i32
}
pub const fn getSize(&self) -> usize {
self.size
}
pub const fn getGeneratorBase(&self) -> i32 {
self.generatorBase
}
}
impl fmt::Display for GenericGF {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "GF({:#06x},{}", self.primitive, self.size)
}
}