use crate::{
dim::Dim,
prelude::DynDenseStoMut,
utils::{are_in_upper_bound, does_not_have_duplicates},
vec::css::CssSlice,
};
#[derive(Debug, PartialEq)]
pub struct CsrMatrixRowConstructor<'a, DS, US> {
row_nnz: usize,
data: &'a mut DS,
dim: &'a mut Dim<[usize; 2]>,
indcs: &'a mut US,
ptrs: &'a mut US,
}
impl<'a, DS, US> CsrMatrixRowConstructor<'a, DS, US>
where
DS: DynDenseStoMut,
US: DynDenseStoMut<Item = usize>,
{
pub(crate) fn new(
dim: &'a mut Dim<[usize; 2]>,
data: &'a mut DS,
indcs: &'a mut US,
ptrs: &'a mut US,
) -> Self {
CsrMatrixRowConstructor {
row_nnz: 0,
data,
dim,
indcs,
ptrs,
}
}
pub fn commit(self) {
let last_ptr = *self.ptrs.as_slice().last().unwrap();
let inserted_indcs = &self.indcs.as_slice()[last_ptr..];
assert!(
are_in_upper_bound(inserted_indcs, &self.dim.cols()),
"Inserted indices must be less than the number of columns of `Self`"
);
assert!(
does_not_have_duplicates(inserted_indcs),
"Inserted indices must be unique."
);
unsafe { self.commit_unchecked() };
}
pub unsafe fn commit_unchecked(mut self) {
let last_ptr = *self.ptrs.as_slice().last().unwrap();
self.ptrs.push(last_ptr + self.row_nnz);
*self.dim.rows_mut() += 1;
self.row_nnz = 0;
}
pub fn copy_values_from_row(mut self, row: &CssSlice<'_, DS::Item>) -> Self
where
DS::Item: Copy,
{
self.row_nnz += row.nnz();
self.data.extend(row.data());
self.indcs.extend(row.indcs());
self
}
pub fn set_value(mut self, column_idx: usize, value: DS::Item) -> Self {
self.row_nnz += 1;
self.data.push(value);
self.indcs.push(column_idx);
self
}
}
impl<'a, DS, US> Drop for CsrMatrixRowConstructor<'a, DS, US> {
fn drop(&mut self) {
if self.row_nnz > 0 {
panic!(
"Every single nonempty instance of `CsrMatrixRowConstructor` must
end with a call to the `commit` method."
);
}
}
}