use crate::field::{Elem, FieldElem};
use crate::kernel::{FieldKernels, RawDispatch};
use super::check_width;
use super::single::mul_into;
#[cfg(feature = "alloc")]
use super::CoeffVecRef;
#[cfg(feature = "alloc")]
use super::single::mul_into_with;
#[inline]
pub fn add_gather_offsets<F: FieldKernels>(dst: &mut [u8], region: &[u8], offsets: &[u32]) {
check_width::<F>("add_gather_offsets", dst.len());
let live = dst.len();
for (index, &start) in offsets.iter().enumerate() {
let start = start as usize;
let end = start
.checked_add(live)
.expect("add_gather_offsets: offset + length overflows");
assert!(
end <= region.len(),
"add_gather_offsets: offset {index} ({start}) + {live} exceeds region of {} bytes",
region.len(),
);
}
F::add_gather_offsets(RawDispatch, region, dst, offsets);
}
pub fn mul_add_gather<F: FieldKernels>(dst: &mut [u8], coeffs: &[Elem<F>], srcs: &[&[u8]]) {
check_width::<F>("mul_add_gather", dst.len());
assert_eq!(
coeffs.len(),
srcs.len(),
"mul_add_gather: {} coefficients for {} sources",
coeffs.len(),
srcs.len()
);
for &src in srcs {
assert_eq!(
dst.len(),
src.len(),
"mul_add_gather: source is {} bytes, expected {}",
src.len(),
dst.len()
);
}
if dst.is_empty() || srcs.is_empty() || coeffs.iter().all(|c| c.is_zero()) {
return;
}
F::mul_add_gather(RawDispatch, dst, coeffs, srcs);
}
#[cfg(feature = "alloc")]
pub fn mul_add_gather_with<F: FieldKernels>(
dst: &mut [u8],
coeffs: CoeffVecRef<'_, F>,
srcs: &[&[u8]],
) {
check_width::<F>("mul_add_gather_with", dst.len());
assert_eq!(
coeffs.len(),
srcs.len(),
"mul_add_gather_with: {} coefficients for {} sources",
coeffs.len(),
srcs.len(),
);
for (index, &src) in srcs.iter().enumerate() {
assert_eq!(
dst.len(),
src.len(),
"mul_add_gather_with: source {index} is {} bytes, expected {}",
src.len(),
dst.len(),
);
}
if dst.is_empty() || srcs.is_empty() || coeffs.values().all(FieldElem::is_zero) {
return;
}
F::mul_add_gather_plan(RawDispatch, dst, coeffs.values, coeffs.prepared, srcs);
}
pub fn mul_into_gather<F: FieldKernels>(dst: &mut [u8], coeffs: &[Elem<F>], srcs: &[&[u8]]) {
check_width::<F>("mul_into_gather", dst.len());
assert_eq!(
coeffs.len(),
srcs.len(),
"mul_into_gather: {} coefficients for {} sources",
coeffs.len(),
srcs.len()
);
for (index, &src) in srcs.iter().enumerate() {
assert_eq!(
dst.len(),
src.len(),
"mul_into_gather: source {index} is {} bytes, expected {}",
src.len(),
dst.len()
);
}
if dst.is_empty() || srcs.is_empty() || coeffs.iter().all(|coeff| coeff.is_zero()) {
dst.fill(0);
return;
}
if let [coeff] = coeffs {
mul_into::<F>(dst, *coeff, srcs[0]);
return;
}
F::mul_into_gather(RawDispatch, dst, coeffs, srcs);
}
#[cfg(feature = "alloc")]
pub fn mul_into_gather_with<F: FieldKernels>(
dst: &mut [u8],
coeffs: CoeffVecRef<'_, F>,
srcs: &[&[u8]],
) {
check_width::<F>("mul_into_gather_with", dst.len());
assert_eq!(
coeffs.len(),
srcs.len(),
"mul_into_gather_with: {} coefficients for {} sources",
coeffs.len(),
srcs.len(),
);
for (index, &src) in srcs.iter().enumerate() {
assert_eq!(
dst.len(),
src.len(),
"mul_into_gather_with: source {index} is {} bytes, expected {}",
src.len(),
dst.len(),
);
}
if dst.is_empty() || srcs.is_empty() || coeffs.values().all(FieldElem::is_zero) {
dst.fill(0);
return;
}
if coeffs.len() == 1 {
let coeff = coeffs
.get(0)
.expect("single-entry view has one coefficient");
mul_into_with::<F>(dst, &coeff, srcs[0]);
return;
}
F::mul_into_gather_plan(RawDispatch, dst, coeffs.values, coeffs.prepared, srcs);
}