mop-structs 0.0.10

Low-level structures for MOP
Documentation
use crate::{
  dim::Dim,
  prelude::DynDenseStoMut,
  utils::{are_in_upper_bound, does_not_have_duplicates},
  vec::css::CssSlice,
};

/// Constructs a new valid row in a easy and interactive manner, abstracting away the complexity
/// of the CSR format.
///
/// This struct may panic when out of scope. Please see the `Drop` documentation in
/// the [`Trait Implementations`](#implementations) section for more information.
#[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,
    }
  }

  /// Commits the row construction, modifying the internal structure.
  ///
  /// # Examples
  ///
  /// ```rust
  /// use mop_structs::{
  ///     doc_tests::csr_matrix_empty_vec_array,
  ///     matrix::csr_matrix::CsrMatrixRef
  /// };
  /// let mut a = csr_matrix_empty_vec_array();
  /// a.row_constructor().commit();
  /// assert_eq!(a.as_ref(), CsrMatrixRef::new([1, 5], &[], &[], &[0, 0]));
  /// ```
  ///
  /// # Assertions
  ///
  /// * Inserted indices must be less than the number of columns of `Self`.
  ///
  /// ```should_panic
  /// use mop_structs::doc_tests::csr_matrix_empty_vec_array;
  /// let mut a = csr_matrix_empty_vec_array();
  /// a.row_constructor().set_value(10, 1).commit();
  /// ```
  ///
  /// * Inserted indices must be unique.
  ///
  /// ```should_panic
  /// use mop_structs::doc_tests::csr_matrix_empty_vec_array;
  /// let mut a = csr_matrix_empty_vec_array();
  /// a.row_constructor().set_value(1, 1).set_value(1, 10).commit();
  /// ```
  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() };
  }

  /// A faster and unsafe version of [`commit`](#method.commit).
  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;
  }

  /// Copies all values of `row` into the current row.
  ///
  /// # Examples
  ///
  /// ```rust
  /// use mop_structs::{
  ///     doc_tests::csr_matrix_empty_vec_array,
  ///     matrix::csr_matrix::CsrMatrixRef,
  ///     vec::css::CssSlice
  /// };
  /// let mut a = csr_matrix_empty_vec_array();
  /// let b = CssSlice::new(5, &[1, 2], &[0, 1]);
  /// a.row_constructor().copy_values_from_row(&b).commit();
  /// assert_eq!(a.as_ref(), CsrMatrixRef::new(
  ///     [1, 5],
  ///     &[1, 2],
  ///     &[0, 1],
  ///     &[0, 2]
  /// ));
  /// ```
  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
  }

  /// Sets a new value in the current row and column index `column_idx`.
  ///
  /// # Examples
  ///
  /// ```rust
  /// use mop_structs::{
  ///     doc_tests::csr_matrix_empty_vec_array,
  ///     matrix::csr_matrix::CsrMatrixRef
  /// };
  /// let mut a = csr_matrix_empty_vec_array();
  /// a.row_constructor().set_value(1, 1).commit();
  /// assert_eq!(a.as_ref(), CsrMatrixRef::new([1, 5], &[1], &[1], &[0, 1]));
  /// ```
  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> {
  /// Some measures are taken to ensure the CSR format and avoid unexpected runtime behavior.
  ///
  /// # Assertions
  ///
  /// * Every single nonempty instance of `CsrRowLayerConstructor` must end with a call to
  /// the `commit` method.
  ///
  /// ```should_panic
  /// use mop_structs::doc_tests::csr_matrix_empty_vec_array;
  /// let mut a = csr_matrix_empty_vec_array();
  /// a.row_constructor().set_value(1, 1);
  /// ```
  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."
      );
    }
  }
}