use core::cmp;
use core::fmt;
use core::mem;
use core::ops::RangeBounds;
use core::ops::{Index, IndexMut};
use core::slice;
use crate::local_prelude::*;
use crate::util::{div_rem, round_up_to_next};
pub struct BitSubMatrix<'a, B: BitBlock> {
pub(crate) slice: &'a [B],
pub(crate) row_bits: usize,
}
pub struct BitSubMatrixMut<'a, B: BitBlock> {
pub(crate) slice: &'a mut [B],
pub(crate) row_bits: usize,
}
impl<'a, B: BitBlock> BitSubMatrix<'a, B> {
#[inline]
pub unsafe fn from_raw_parts(ptr: *const B, rows: usize, row_bits: usize) -> Self {
BitSubMatrix {
slice: slice::from_raw_parts(
ptr,
round_up_to_next(row_bits, B::bits()) / B::bits() * rows,
),
row_bits,
}
}
pub fn iter(&self) -> impl Iterator<Item = &BitSlice<B>> {
fn f<B: BitBlock>(arg: &[B]) -> &BitSlice<B> {
unsafe { mem::transmute(arg) }
}
let row_size = round_up_to_next(self.row_bits, B::bits()) / B::bits();
self.slice.chunks(row_size).map(f::<B>)
}
fn row_size(&self) -> usize {
round_up_to_next(self.row_bits, B::bits()) / B::bits()
}
}
impl<'a, B: BitBlock> BitSubMatrixMut<'a, B> {
pub(crate) fn new(slice: &mut [B], row_bits: usize) -> BitSubMatrixMut<'_, B> {
BitSubMatrixMut { slice, row_bits }
}
#[inline]
pub unsafe fn from_raw_parts(ptr: *mut B, rows: usize, row_bits: usize) -> Self {
BitSubMatrixMut {
slice: slice::from_raw_parts_mut(
ptr,
round_up_to_next(row_bits, B::bits()) / B::bits() * rows,
),
row_bits,
}
}
#[inline]
fn num_rows(&self) -> usize {
self.slice.len().checked_div(self.row_size()).unwrap_or(0)
}
#[inline]
pub fn num_cols(&self) -> usize {
self.row_bits
}
#[inline]
pub fn set(&mut self, row: usize, col: usize, enabled: bool) {
let row_size_in_bits = round_up_to_next(self.row_bits, B::bits());
let bit = row * row_size_in_bits + col;
let (block, i) = div_rem(bit, B::bits());
assert!(
block < self.slice.len() && col < self.row_bits,
"invalid index given to `BitSubMatrixMut::set`"
);
unsafe {
let elt = self.slice.get_unchecked_mut(block);
if enabled {
*elt |= B::one() << i;
} else {
*elt = *elt & !(B::one() << i);
}
}
}
#[inline]
pub unsafe fn set_unchecked(&mut self, row: usize, col: usize, enabled: bool) {
let row_size_in_bits = round_up_to_next(self.row_bits, B::bits());
let bit = row * row_size_in_bits + col;
let (block, i) = div_rem(bit, B::bits());
unsafe {
let elt = self.slice.get_unchecked_mut(block);
if enabled {
*elt |= B::one() << i;
} else {
*elt = *elt & !(B::one() << i);
}
}
}
pub fn sub_matrix<R: RangeBounds<usize>>(&self, range: R) -> BitSubMatrix<'_, B> {
BitSubMatrix {
slice: &self.slice[(
range.start_bound().map(|&s| s * self.row_size()),
range.end_bound().map(|&e| e * self.row_size()),
)],
row_bits: self.row_bits,
}
}
#[inline]
pub fn split_at(&self, row: usize) -> (BitSubMatrix<'_, B>, BitSubMatrix<'_, B>) {
(
self.sub_matrix(0..row),
self.sub_matrix(row..self.num_rows()),
)
}
#[inline]
pub fn split_at_mut(&mut self, row: usize) -> (BitSubMatrixMut<'_, B>, BitSubMatrixMut<'_, B>) {
let (first, second) = self.slice.split_at_mut(row * self.row_size());
(
BitSubMatrixMut::new(first, self.row_bits),
BitSubMatrixMut::new(second, self.row_bits),
)
}
pub fn transitive_closure(&mut self) {
assert!(self.is_square());
for pos in 0..self.row_bits {
let (mut rows0, mut rows1a) = self.split_at_mut(pos);
let (mut row, mut rows1b) = rows1a.split_at_mut(1);
for mut dst_row in rows0.iter_mut().chain(rows1b.iter_mut()) {
if dst_row[pos] {
dst_row |= &mut row[0];
}
}
}
}
fn is_square(&self) -> bool {
self.num_rows() == self.row_bits
}
pub fn reflexive_closure(&mut self) {
for i in 0..cmp::min(self.row_bits, self.num_rows()) {
self.set(i, i, true);
}
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut BitSlice<B>> {
fn f<B: BitBlock>(arg: &mut [B]) -> &mut BitSlice<B> {
unsafe { mem::transmute(arg) }
}
self.slice.chunks_mut(self.row_size()).map(f::<B>)
}
fn row_size(&self) -> usize {
round_up_to_next(self.row_bits, B::bits()) / B::bits()
}
}
impl<'a, B: BitBlock> Index<usize> for BitSubMatrixMut<'a, B> {
type Output = BitSlice<B>;
#[inline]
fn index(&self, row: usize) -> &Self::Output {
unsafe { mem::transmute(&self.slice[row * self.row_size()..(row + 1) * self.row_size()]) }
}
}
impl<'a, B: BitBlock> IndexMut<usize> for BitSubMatrixMut<'a, B> {
#[inline]
fn index_mut(&mut self, row: usize) -> &mut Self::Output {
let row_size = self.row_size();
unsafe { mem::transmute(&mut self.slice[row * row_size..(row + 1) * row_size]) }
}
}
impl<'a, B: BitBlock> Index<usize> for BitSubMatrix<'a, B> {
type Output = BitSlice<B>;
#[inline]
fn index(&self, row: usize) -> &Self::Output {
let row_size = self.row_size();
unsafe { mem::transmute(&self.slice[row * row_size..(row + 1) * row_size]) }
}
}
impl<'a, B: BitBlock> fmt::Debug for BitSubMatrix<'a, B> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
for row in self.iter() {
for bit in row.iter_bits(self.row_bits) {
write!(fmt, "{}", if bit { 1 } else { 0 })?;
}
writeln!(fmt)?;
}
Ok(())
}
}