use crate::core::marker::EdgeType;
#[allow(clippy::len_without_is_empty)]
pub trait MatrixLinearStorage<E>: Default {
fn with_capacity(capacity: usize) -> Self;
fn resize_with_none(&mut self, new_len: usize);
fn push(&mut self, value: Option<E>);
fn len(&self) -> usize;
fn into_entries(self) -> impl Iterator<Item = Option<E>>;
}
pub fn linear_len<Ty: EdgeType>(vertex_capacity: usize) -> usize {
if Ty::is_directed() {
vertex_capacity * vertex_capacity
} else {
vertex_capacity * (vertex_capacity + 1) / 2
}
}
pub fn resize<E, Ty: EdgeType, M: MatrixLinearStorage<E>>(prev: &mut M, vertex_capacity: usize) {
let prev_len = prev.len();
let len = linear_len::<Ty>(vertex_capacity);
if len <= prev_len {
return;
}
if Ty::is_directed() {
let mut next = M::with_capacity(len);
let prev_capacity = (prev_len as f32).sqrt() as usize;
for (i, value) in core::mem::take(prev).into_entries().enumerate() {
next.push(value);
if (i + 1) % prev_capacity == 0 {
let additional = next.len() + vertex_capacity - prev_capacity;
next.resize_with_none(additional);
}
}
next.resize_with_none(len);
*prev = next;
} else {
prev.resize_with_none(len);
}
}
pub fn index<Ty: EdgeType>(row: usize, col: usize, vertex_capacity: usize) -> usize {
if Ty::is_directed() {
row * vertex_capacity + col
} else {
let (row, col) = if row >= col { (row, col) } else { (col, row) };
row * (row + 1) / 2 + col
}
}
pub fn coords<Ty: EdgeType>(index: usize, vertex_capacity: usize) -> (usize, usize) {
if Ty::is_directed() {
let col = index % vertex_capacity;
let row = index / vertex_capacity;
(row, col)
} else {
let d = (1. + 8. * index as f64).sqrt().floor() as usize;
let row = (d - 1) / 2;
let col = index - row * (row + 1) / 2;
(row, col)
}
}
mod imp {
use bitvec::{order::BitOrder, store::BitStore, vec::BitVec};
use super::MatrixLinearStorage;
impl<E> MatrixLinearStorage<E> for Vec<Option<E>> {
fn with_capacity(capacity: usize) -> Self {
Self::with_capacity(capacity)
}
fn resize_with_none(&mut self, new_len: usize) {
self.resize_with(new_len, || None);
}
fn push(&mut self, value: Option<E>) {
self.push(value);
}
fn len(&self) -> usize {
self.len()
}
fn into_entries(self) -> impl Iterator<Item = Option<E>> {
self.into_iter()
}
}
impl<T, O> MatrixLinearStorage<()> for BitVec<T, O>
where
T: BitStore,
O: BitOrder,
{
fn with_capacity(capacity: usize) -> Self {
Self::with_capacity(capacity)
}
fn resize_with_none(&mut self, new_len: usize) {
self.resize_with(new_len, |_| false);
}
fn push(&mut self, value: Option<()>) {
self.push(value.is_some())
}
fn len(&self) -> usize {
self.len()
}
fn into_entries(self) -> impl Iterator<Item = Option<()>> {
self.into_iter().map(|bit| bit.then_some(()))
}
}
}