lazy static for genericgf

This commit is contained in:
Henry Schimke
2022-10-02 11:42:15 -05:00
parent 8e69cfec54
commit 11adc27fe7
5 changed files with 84 additions and 71 deletions

View File

@@ -19,7 +19,7 @@ use encoding::Encoding;
use crate::{
common::{
reedsolomon::{
get_predefined_genericgf, GenericGF, PredefinedGenericGF, ReedSolomonDecoder,
get_predefined_genericgf, GenericGF, PredefinedGenericGF, ReedSolomonDecoder, GenericGFRef,
},
BitMatrix, CharacterSetECI, DecoderRXingResult, DetectorRXingResult,
},
@@ -327,7 +327,7 @@ fn correct_bits(
ddata: &AztecDetectorRXingResult,
rawbits: &[bool],
) -> Result<CorrectedBitsRXingResult, Exceptions> {
let gf: GenericGF;
let gf: GenericGFRef;
let codeword_size;
if ddata.getNbLayers() <= 2 {

View File

@@ -19,7 +19,7 @@ use encoding::Encoding;
use crate::{
common::{
reedsolomon::{
get_predefined_genericgf, GenericGF, PredefinedGenericGF, ReedSolomonEncoder,
get_predefined_genericgf, GenericGF, PredefinedGenericGF, ReedSolomonEncoder, GenericGFRef,
},
BitArray, BitMatrix,
},
@@ -484,7 +484,7 @@ fn bitsToWords(stuffedBits: &BitArray, wordSize: usize, totalWords: usize) -> Ve
return message;
}
fn getGF(wordSize: usize) -> Result<GenericGF, Exceptions> {
fn getGF(wordSize: usize) -> Result<GenericGFRef, Exceptions> {
match wordSize {
4 => Ok(get_predefined_genericgf(PredefinedGenericGF::AztecParam)),
6 => Ok(get_predefined_genericgf(PredefinedGenericGF::AztecData6)),

View File

@@ -31,33 +31,33 @@ use super::{GenericGF, GenericGFPoly};
#[test]
fn testPolynomialString() {
let FIELD = Rc::new(super::get_predefined_genericgf(super::PredefinedGenericGF::QrCodeField256));
let fz = super::GenericGFPoly::new(FIELD.clone(), &vec![0; 1]).unwrap();
let FIELD = super::get_predefined_genericgf(super::PredefinedGenericGF::QrCodeField256);
let fz = super::GenericGFPoly::new(FIELD, &vec![0; 1]).unwrap();
assert_eq!("0", fz.getZero().to_string());
let n1mono = GenericGF::buildMonomial(FIELD.clone(), 0, -1);
let n1mono = GenericGF::buildMonomial(FIELD, 0, -1);
assert_eq!("-1", n1mono.to_string());
let p = GenericGFPoly::new(FIELD.clone(), &vec![3, 0, -2, 1, 1]).unwrap();
let p = GenericGFPoly::new(FIELD, &vec![3, 0, -2, 1, 1]).unwrap();
assert_eq!("a^25x^4 - ax^2 + x + 1", p.to_string());
let p = GenericGFPoly::new(FIELD.clone(), &vec![3]).unwrap();
let p = GenericGFPoly::new(FIELD, &vec![3]).unwrap();
assert_eq!("a^25", p.to_string());
}
#[test]
fn testZero() {
let FIELD = Rc::new(super::get_predefined_genericgf(super::PredefinedGenericGF::QrCodeField256));
let fz = super::GenericGFPoly::new(FIELD.clone(), &vec![0; 1]).unwrap();
let FIELD = super::get_predefined_genericgf(super::PredefinedGenericGF::QrCodeField256);
let fz = super::GenericGFPoly::new(FIELD, &vec![0; 1]).unwrap();
assert_eq!(fz.getZero(), GenericGF::buildMonomial(FIELD.clone(), 1, 0));
assert_eq!(fz.getZero(), GenericGF::buildMonomial(FIELD, 1, 0));
assert_eq!(
fz.getZero(),
GenericGF::buildMonomial(FIELD.clone(), 1, 2).multiply_with_scalar(0)
GenericGF::buildMonomial(FIELD, 1, 2).multiply_with_scalar(0)
);
}
#[test]
fn testEvaluate() {
let FIELD = Rc::new(super::get_predefined_genericgf(super::PredefinedGenericGF::QrCodeField256));
let FIELD = super::get_predefined_genericgf(super::PredefinedGenericGF::QrCodeField256);
assert_eq!(3, GenericGF::buildMonomial(FIELD.clone(), 0, 3).evaluateAt(0));
assert_eq!(3, GenericGF::buildMonomial(FIELD, 0, 3).evaluateAt(0));
}

View File

@@ -1,6 +1,6 @@
use rand::Rng;
use super::{GenericGF, ReedSolomonDecoder, ReedSolomonEncoder};
use super::{GenericGF, ReedSolomonDecoder, ReedSolomonEncoder, GenericGFRef};
/*
* Copyrigh&t 2013 ZXing authors
*
@@ -52,9 +52,9 @@ fn test_data_matrix() {
],
);
// synthetic test cases
test_encode_decode_random(dm256.clone(), 220, 35);
test_encode_decode_random(dm256.clone(), 10, 240);
test_encode_decode_random(dm256.clone(), 128, 127);
test_encode_decode_random(dm256, 220, 35);
test_encode_decode_random(dm256, 10, 240);
test_encode_decode_random(dm256, 128, 127);
}
#[test]
@@ -83,9 +83,9 @@ fn test_qr_code() {
);
// real life test cases
// synthetic test cases
test_encode_decode_random(qrcf256.clone(), 10, 240);
test_encode_decode_random(qrcf256.clone(), 128, 127);
test_encode_decode_random(qrcf256.clone(), 220, 35);
test_encode_decode_random(qrcf256, 10, 240);
test_encode_decode_random(qrcf256, 128, 127);
test_encode_decode_random(qrcf256, 220, 35);
}
#[test]
@@ -329,15 +329,15 @@ fn test_aztec() {
let azd10 = super::get_predefined_genericgf(super::PredefinedGenericGF::AztecData10);
let azd12 = super::get_predefined_genericgf(super::PredefinedGenericGF::AztecData12);
test_encode_decode_random(azp.clone(), 2, 5); // compact mode message
test_encode_decode_random(azp.clone(), 4, 6); // full mode message
test_encode_decode_random(azd6.clone(), 10, 7);
test_encode_decode_random(azd6.clone(), 20, 12);
test_encode_decode_random(azd8.clone(), 20, 11);
test_encode_decode_random(azd8.clone(), 128, 127);
test_encode_decode_random(azd10.clone(), 128, 128);
test_encode_decode_random(azd10.clone(), 768, 255);
test_encode_decode_random(azd12.clone(), 3072, 1023);
test_encode_decode_random(azp, 2, 5); // compact mode message
test_encode_decode_random(azp, 4, 6); // full mode message
test_encode_decode_random(azd6, 10, 7);
test_encode_decode_random(azd6, 20, 12);
test_encode_decode_random(azd8, 20, 11);
test_encode_decode_random(azd8, 128, 127);
test_encode_decode_random(azd10, 128, 128);
test_encode_decode_random(azd10, 768, 255);
test_encode_decode_random(azd12, 3072, 1023);
}
fn corrupt(received: &mut Vec<i32>, howMany: i32, random: &mut rand::rngs::ThreadRng, max: i32) {
@@ -361,7 +361,7 @@ fn corrupt(received: &mut Vec<i32>, howMany: i32, random: &mut rand::rngs::Threa
}
}
fn test_encode_decode_random(field: GenericGF, dataSize: usize, ecSize: usize) {
fn test_encode_decode_random(field: GenericGFRef, dataSize: usize, ecSize: usize) {
assert!(
dataSize > 0 && dataSize <= field.getSize() - 3,
"Invalid data size for {}",
@@ -372,7 +372,7 @@ fn test_encode_decode_random(field: GenericGF, dataSize: usize, ecSize: usize) {
"Invalid ECC size for {}",
field
);
let mut encoder = ReedSolomonEncoder::new(field.clone());
let mut encoder = ReedSolomonEncoder::new(field);
let mut message = vec![0; dataSize + ecSize];
let mut dataWords: Vec<i32> = vec![0; dataSize];
let mut ecWords = vec![0; ecSize];
@@ -402,13 +402,13 @@ fn test_encode_decode_random(field: GenericGF, dataSize: usize, ecSize: usize) {
}
}
fn test_encode_decode(field: &GenericGF, dataWords: &Vec<i32>, ecWords: &Vec<i32>) {
fn test_encode_decode(field: GenericGFRef, dataWords: &Vec<i32>, ecWords: &Vec<i32>) {
test_encoder(field, dataWords, ecWords);
test_decoder(field, dataWords, ecWords);
}
fn test_encoder(field: &GenericGF, dataWords: &Vec<i32>, ecWords: &Vec<i32>) {
let mut encoder = ReedSolomonEncoder::new(field.clone());
fn test_encoder(field: GenericGFRef, dataWords: &Vec<i32>, ecWords: &Vec<i32>) {
let mut encoder = ReedSolomonEncoder::new(field);
let mut messageExpected = vec![0; dataWords.len() + ecWords.len()];
let mut message = vec![0; dataWords.len() + ecWords.len()];
messageExpected[0..dataWords.len()].clone_from_slice(&dataWords[0..dataWords.len()]);
@@ -431,8 +431,8 @@ fn test_encoder(field: &GenericGF, dataWords: &Vec<i32>, ecWords: &Vec<i32>) {
);
}
fn test_decoder(field: &GenericGF, dataWords: &Vec<i32>, ecWords: &Vec<i32>) {
let decoder = ReedSolomonDecoder::new(field.clone());
fn test_decoder(field: GenericGFRef, dataWords: &Vec<i32>, ecWords: &Vec<i32>) {
let decoder = ReedSolomonDecoder::new(field);
let mut message = vec![0; dataWords.len() + ecWords.len()];
let maxErrors = ecWords.len() / 2;
let mut random = get_pseudo_random();

View File

@@ -1,4 +1,4 @@
use std::{fmt, rc::Rc};
use std::{fmt};
use crate::Exceptions;
use std::hash::Hash;
@@ -26,6 +26,19 @@ mod ReedSolomonTestCase;
//package com.google.zxing.common.reedsolomon;
pub type GenericGFRef = &'static GenericGF;
use lazy_static::lazy_static;
lazy_static! {
static ref AZTEC_DATA_12: GenericGF = GenericGF::new(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1
static ref AZTEC_DATA_10: GenericGF = GenericGF::new(0x409, 1024, 1); // x^10 + x^3 + 1
static ref AZTEC_DATA_6: GenericGF = GenericGF::new(0x43, 64, 1); // x^6 + x + 1
static ref AZTEC_PARAM: GenericGF = GenericGF::new(0x13, 16, 1); // x^4 + x + 1
static ref QR_CODE_FIELD_256: GenericGF = GenericGF::new(0x011D, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1
static ref DATA_MATRIX_FIELD_256: GenericGF = GenericGF::new(0x012D, 256, 1); // x^8 + x^5 + x^3 + x^2 + 1
}
// pub const AZTEC_DATA_12: GenericGF = GenericGF::new(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1
// pub const AZTEC_DATA_10: GenericGF = GenericGF::new(0x409, 1024, 1); // x^10 + x^3 + 1
// pub const AZTEC_DATA_6: GenericGF = GenericGF::new(0x43, 64, 1); // x^6 + x + 1
@@ -47,17 +60,17 @@ pub enum PredefinedGenericGF {
}
/// Replacement for old const options, has the downside of generating new versions whenever one is requested.
pub fn get_predefined_genericgf(request: PredefinedGenericGF) -> GenericGF {
pub fn get_predefined_genericgf(request: PredefinedGenericGF) -> GenericGFRef {
match request {
PredefinedGenericGF::AztecData12 => GenericGF::new(0x1069, 4096, 1), // x^12 + x^6 + x^5 + x^3 + 1,
PredefinedGenericGF::AztecData10 => GenericGF::new(0x409, 1024, 1), // x^10 + x^3 + 1
PredefinedGenericGF::AztecData12 => &AZTEC_DATA_12, // x^12 + x^6 + x^5 + x^3 + 1,
PredefinedGenericGF::AztecData10 => &AZTEC_DATA_10, // x^10 + x^3 + 1
PredefinedGenericGF::AztecData6 | PredefinedGenericGF::MaxicodeField64 => {
GenericGF::new(0x43, 64, 1)
&AZTEC_DATA_6
} // x^6 + x + 1
PredefinedGenericGF::AztecParam => GenericGF::new(0x13, 16, 1), // x^4 + x + 1
PredefinedGenericGF::QrCodeField256 => GenericGF::new(0x011D, 256, 0), // x^8 + x^4 + x^3 + x^2 + 1
PredefinedGenericGF::AztecParam => &AZTEC_PARAM, // x^4 + x + 1
PredefinedGenericGF::QrCodeField256 => &QR_CODE_FIELD_256, // x^8 + x^4 + x^3 + x^2 + 1
PredefinedGenericGF::DataMatrixField256 | PredefinedGenericGF::AztecData8 => {
GenericGF::new(0x012D, 256, 1)
&DATA_MATRIX_FIELD_256
} // x^8 + x^5 + x^3 + x^2 + 1
}
}
@@ -172,13 +185,13 @@ impl GenericGF {
/**
* @return the monomial representing coefficient * x^degree
*/
pub fn buildMonomial(source: Rc<Self>, degree: usize, coefficient: i32) -> GenericGFPoly {
pub fn buildMonomial(source: GenericGFRef, degree: usize, coefficient: i32) -> GenericGFPoly {
if coefficient == 0 {
return GenericGFPoly::new(source.clone(), &vec![0]).unwrap();
return GenericGFPoly::new(source, &vec![0]).unwrap();
}
let mut coefficients = vec![0; degree + 1];
coefficients[0] = coefficient;
return GenericGFPoly::new(source.clone(), &coefficients).unwrap();
return GenericGFPoly::new(source, &coefficients).unwrap();
}
/**
@@ -282,7 +295,7 @@ impl fmt::Display for GenericGF {
*/
#[derive(Debug, Clone)]
pub struct GenericGFPoly {
field: Rc<GenericGF>,
field: GenericGFRef,
coefficients: Vec<i32>,
}
@@ -303,7 +316,7 @@ impl GenericGFPoly {
* or if leading coefficient is 0 and this is not a
* constant polynomial (that is, it is not the monomial "0")
*/
pub fn new(field: Rc<GenericGF>, coefficients: &Vec<i32>) -> Result<Self, Exceptions> {
pub fn new(field: GenericGFRef, coefficients: &Vec<i32>) -> Result<Self, Exceptions> {
if coefficients.len() == 0 {
return Err(Exceptions::IllegalArgumentException(
"coefficients.len()".to_owned(),
@@ -431,7 +444,7 @@ impl GenericGFPoly {
);
}
return Ok(GenericGFPoly::new(self.field.clone(), &sumDiff)?);
return Ok(GenericGFPoly::new(self.field, &sumDiff)?);
}
pub fn multiply(&self, other: &GenericGFPoly) -> Result<GenericGFPoly, Exceptions> {
@@ -466,7 +479,7 @@ impl GenericGFPoly {
);
}
}
return Ok(GenericGFPoly::new(self.field.clone(), &product)?);
return Ok(GenericGFPoly::new(self.field, &product)?);
}
pub fn multiply_with_scalar(&self, scalar: i32) -> GenericGFPoly {
@@ -485,15 +498,15 @@ impl GenericGFPoly {
.field
.multiply(self.coefficients[i], scalar.try_into().unwrap());
}
return GenericGFPoly::new(self.field.clone(), &product).unwrap();
return GenericGFPoly::new(self.field, &product).unwrap();
}
pub fn getZero(&self) -> Self {
GenericGFPoly::new(self.field.clone(), &vec![0]).unwrap()
GenericGFPoly::new(self.field, &vec![0]).unwrap()
}
pub fn getOne(&self) -> Self {
GenericGFPoly::new(self.field.clone(), &vec![1]).unwrap()
GenericGFPoly::new(self.field, &vec![1]).unwrap()
}
pub fn multiply_by_monomial(
@@ -513,7 +526,7 @@ impl GenericGFPoly {
//for (int i = 0; i < size; i++) {
product[i] = self.field.multiply(self.coefficients[i], coefficient);
}
return Ok(GenericGFPoly::new(self.field.clone(), &product)?);
return Ok(GenericGFPoly::new(self.field, &product)?);
}
pub fn divide(
@@ -551,7 +564,7 @@ impl GenericGFPoly {
inverse_denominator_leading_term,
);
let term = other.multiply_by_monomial(degree_difference, scale)?;
let iteration_quotient = GenericGF::buildMonomial(self.field.clone(), degree_difference, scale);
let iteration_quotient = GenericGF::buildMonomial(self.field, degree_difference, scale);
quotient = quotient.addOrSubtract(&iteration_quotient)?;
remainder = remainder.addOrSubtract(&term)?;
}
@@ -648,12 +661,12 @@ impl fmt::Display for GenericGFPoly {
* @author sanfordsquires
*/
pub struct ReedSolomonDecoder {
field: Rc<GenericGF>,
field: GenericGFRef,
}
impl ReedSolomonDecoder {
pub fn new(field: GenericGF) -> Self {
Self { field: Rc::new(field) }
pub fn new(field: GenericGFRef) -> Self {
Self { field: field }
}
/**
@@ -666,7 +679,7 @@ impl ReedSolomonDecoder {
* @throws ReedSolomonException if decoding fails for any reason
*/
pub fn decode(&self, received: &mut Vec<i32>, twoS: i32) -> Result<(), Exceptions> {
let poly = GenericGFPoly::new(self.field.clone(), received).unwrap();
let poly = GenericGFPoly::new(self.field, received).unwrap();
let mut syndromeCoefficients = vec![0; twoS.try_into().unwrap()];
let mut noError = true;
for i in 0..twoS {
@@ -686,7 +699,7 @@ impl ReedSolomonDecoder {
if noError {
return Ok(());
}
let syndrome = match GenericGFPoly::new(self.field.clone(), &syndromeCoefficients) {
let syndrome = match GenericGFPoly::new(self.field, &syndromeCoefficients) {
Ok(res) => res,
Err(fail) => {
return Err(Exceptions::ReedSolomonException(
@@ -695,7 +708,7 @@ impl ReedSolomonDecoder {
}
};
let sigmaOmega = self.runEuclideanAlgorithm(
&GenericGF::buildMonomial(self.field.clone(), twoS.try_into().unwrap(), 1),
&GenericGF::buildMonomial(self.field, twoS.try_into().unwrap(), 1),
&syndrome,
twoS.try_into().unwrap(),
)?;
@@ -772,7 +785,7 @@ impl ReedSolomonDecoder {
let scale = self
.field
.multiply(r.getCoefficient(r.getDegree()), dltInverse);
q = match q.addOrSubtract(&GenericGF::buildMonomial(self.field.clone(), degreeDiff, scale)) {
q = match q.addOrSubtract(&GenericGF::buildMonomial(self.field, degreeDiff, scale)) {
Ok(res) => res,
Err(err) => {
return Err(Exceptions::ReedSolomonException(
@@ -951,15 +964,15 @@ impl ReedSolomonDecoder {
* @author William Rucklidge
*/
pub struct ReedSolomonEncoder {
field: Rc<GenericGF>,
field: GenericGFRef,
cachedGenerators: Vec<GenericGFPoly>,
}
impl ReedSolomonEncoder {
pub fn new(field: GenericGF) -> Self {
let n = Rc::new(field);
pub fn new(field: GenericGFRef) -> Self {
let n = field;
Self {
cachedGenerators: vec![GenericGFPoly::new(n.clone(), &vec![1]).unwrap()],
cachedGenerators: vec![GenericGFPoly::new(n, &vec![1]).unwrap()],
field: n,
}
}
@@ -977,7 +990,7 @@ impl ReedSolomonEncoder {
nextGenerator = lastGenerator
.multiply(
&GenericGFPoly::new(
self.field.clone(),
self.field,
&vec![
1,
self.field.exp(d as i32 - 1 + self.field.getGeneratorBase()),
@@ -1007,7 +1020,7 @@ impl ReedSolomonEncoder {
"No data bytes provided".to_owned(),
));
}
let fld = self.field.clone();
let fld = self.field;
let generator = self.buildGenerator(ec_bytes);
let mut info_coefficients: Vec<i32> = vec![0; data_bytes];
info_coefficients[0..data_bytes].clone_from_slice(&to_encode[0..data_bytes]);