use core::fmt;
use core::fmt::{Formatter, Debug};
use core::ops::{Index, IndexMut, Range};
use core::ptr;
use core::mem;
use crate::toodee::*;
use crate::ops::*;
use crate::iter::*;
fn calculate_view_dimensions<T>(start: Coordinate, end: Coordinate, toodee: &impl TooDeeOps<T>, stride: usize) -> (usize, usize, Range<usize>) {
assert!(end.0 >= start.0);
assert!(end.1 >= start.1);
assert!(end.0 <= toodee.num_cols());
assert!(end.1 <= toodee.num_rows());
assert!(stride >= toodee.num_cols());
let mut num_cols = end.0 - start.0;
let mut num_rows = end.1 - start.1;
if num_cols == 0 || num_rows == 0 {
num_cols = 0;
num_rows = 0;
}
let data_start = start.1 * stride + start.0;
let data_len = {
if num_rows == 0 {
0
} else {
(num_rows - 1) * stride + num_cols
}
};
(num_cols, num_rows, data_start..data_start + data_len)
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn calc_dims_view() {
let v = vec![1u32; 32];
let view = TooDeeView::new(4, 4, &v);
let (num_cols, num_rows, range) = calculate_view_dimensions((0, 1), (2,3), &view, 4);
assert_eq!(num_cols, 2);
assert_eq!(num_rows, 2);
assert_eq!(range, 4..10);
}
}
trait TooDeeViewCommon<T>: TooDeeOps<T> {
fn data(&self) -> &[T];
fn stride(&self) -> usize;
fn get_col_params(&self, col: usize) -> (Range<usize>, usize){
assert!(col < self.num_cols());
let stride = self.stride();
let start = col;
let end = {
let num_rows = self.num_rows();
if num_rows == 0 {
start
} else {
start + (num_rows - 1) * stride + 1
}
};
(start..end, stride - 1)
}
}
impl<T> TooDeeViewCommon<T> for TooDeeView<'_, T> {
#[inline]
fn data(&self) -> &[T] { &self.data }
#[inline]
fn stride(&self) -> usize {
self.stride
}
}
impl<T> TooDeeViewCommon<T> for TooDeeViewMut<'_, T> {
#[inline]
fn data(&self) -> &[T] { &self.data }
#[inline]
fn stride(&self) -> usize {
self.stride
}
}
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct TooDeeView<'a, T> {
data: &'a [T],
num_cols: usize,
num_rows: usize,
stride: usize,
}
impl<'a, T> TooDeeView<'a, T> {
pub fn new(num_cols: usize, num_rows: usize, data: &'a [T]) -> TooDeeView<'a, T> {
if num_cols == 0 || num_rows == 0 {
assert_eq!(num_rows, num_cols);
}
let size = num_cols.checked_mul(num_rows).unwrap();
assert!(size <= data.len());
TooDeeView {
data: &data[..size],
num_cols,
num_rows,
stride: num_cols,
}
}
pub(super) fn from_toodee(start: Coordinate, end: Coordinate, toodee: &'a TooDee<T>) -> TooDeeView<'a, T> {
let stride = toodee.num_cols();
let (num_cols, num_rows, data_range) = calculate_view_dimensions(start, end, toodee, stride);
unsafe {
TooDeeView {
data: toodee.data().get_unchecked(data_range),
num_cols,
num_rows,
stride,
}
}
}
}
impl<'a, T> TooDeeOps<T> for TooDeeView<'a, T>
{
#[inline]
fn num_cols(&self) -> usize {
self.num_cols
}
#[inline]
fn num_rows(&self) -> usize {
self.num_rows
}
fn view(&self, start: Coordinate, end: Coordinate) -> TooDeeView<'_, T> {
let (num_cols, num_rows, data_range) = calculate_view_dimensions(start, end, self, self.stride);
unsafe {
TooDeeView {
data: self.data.get_unchecked(data_range),
num_cols,
num_rows,
stride: self.stride,
}
}
}
fn rows(&self) -> Rows<'_, T> {
Rows {
v: self.data,
cols: self.num_cols,
skip_cols: self.stride - self.num_cols,
}
}
fn col(&self, col: usize) -> Col<'_, T> {
let (data_range, skip) = self.get_col_params(col);
unsafe {
Col {
v: self.data.get_unchecked(data_range),
skip,
}
}
}
unsafe fn get_unchecked_row(&self, row: usize) -> &[T] {
let start = row * self.stride;
self.data.get_unchecked(start..start + self.num_cols)
}
unsafe fn get_unchecked(&self, coord: Coordinate) -> &T {
self.data.get_unchecked(coord.1 * self.stride + coord.0)
}
}
impl<'a, T> Index<usize> for TooDeeView<'a, T> {
type Output = [T];
fn index(&self, row: usize) -> &Self::Output {
assert!(row < self.num_rows);
let start = row * self.stride;
unsafe {
self.data.get_unchecked(start..start + self.num_cols)
}
}
}
impl<'a, T> Index<Coordinate> for TooDeeView<'a, T> {
type Output = T;
fn index(&self, coord: Coordinate) -> &Self::Output {
assert!(coord.1 < self.num_rows);
assert!(coord.0 < self.num_cols);
unsafe {
self.data.get_unchecked(coord.1 * self.stride + coord.0)
}
}
}
#[derive(Hash, Eq, PartialEq)]
pub struct TooDeeViewMut<'a, T> {
data: &'a mut [T],
num_cols: usize,
num_rows: usize,
stride: usize,
}
impl<'a, T> TooDeeViewMut<'a, T> {
pub fn new(num_cols: usize, num_rows: usize, data: &'a mut [T]) -> TooDeeViewMut<'a, T> {
if num_cols == 0 || num_rows == 0 {
assert_eq!(num_rows, num_cols);
}
let size = num_cols.checked_mul(num_rows).unwrap();
assert!(size <= data.len());
unsafe {
TooDeeViewMut {
data: data.get_unchecked_mut(..size),
num_cols,
num_rows,
stride: num_cols,
}
}
}
pub(super) fn from_toodee(start: Coordinate, end: Coordinate, toodee: &'a mut TooDee<T>) -> TooDeeViewMut<'a, T> {
let stride = toodee.num_cols();
let (num_cols, num_rows, data_range) = calculate_view_dimensions(start, end, toodee, stride);
unsafe {
TooDeeViewMut {
data: toodee.data_mut().get_unchecked_mut(data_range),
num_cols,
num_rows,
stride,
}
}
}
}
impl<'a, T> TooDeeOps<T> for TooDeeViewMut<'a, T> {
#[inline]
fn num_rows(&self) -> usize {
self.num_rows
}
#[inline]
fn num_cols(&self) -> usize {
self.num_cols
}
fn view(&self, start: Coordinate, end: Coordinate) -> TooDeeView<'_, T> {
let (num_cols, num_rows, data_range) = calculate_view_dimensions(start, end, self, self.stride);
TooDeeView {
data: &self.data[data_range],
num_cols,
num_rows,
stride: self.stride,
}
}
fn rows(&self) -> Rows<'_, T> {
Rows {
v: self.data,
cols: self.num_cols,
skip_cols: self.stride - self.num_cols,
}
}
fn col(&self, col: usize) -> Col<'_, T> {
let (data_range, skip) = self.get_col_params(col);
unsafe {
Col {
v: self.data.get_unchecked(data_range),
skip,
}
}
}
unsafe fn get_unchecked_row(&self, row: usize) -> &[T] {
let start = row * self.stride;
self.data.get_unchecked(start..start + self.num_cols)
}
unsafe fn get_unchecked(&self, coord: Coordinate) -> &T {
self.data.get_unchecked(coord.1 * self.stride + coord.0)
}
}
impl<'a, T> TooDeeOpsMut<T> for TooDeeViewMut<'a, T> {
fn view_mut(&mut self, start: Coordinate, end: Coordinate) -> TooDeeViewMut<'_, T> {
let (num_cols, num_rows, data_range) = calculate_view_dimensions(start, end, self, self.stride);
unsafe {
TooDeeViewMut {
data: self.data.get_unchecked_mut(data_range),
num_cols,
num_rows,
stride: self.stride,
}
}
}
fn rows_mut(&mut self) -> RowsMut<'_, T> {
RowsMut {
v: self.data,
cols: self.num_cols,
skip_cols: self.stride - self.num_cols,
}
}
fn col_mut(&mut self, col: usize) -> ColMut<'_, T> {
let (data_range, skip) = self.get_col_params(col);
unsafe {
ColMut {
v: self.data.get_unchecked_mut(data_range),
skip,
}
}
}
fn swap_rows(&mut self, mut r1: usize, mut r2: usize) {
if r1 == r2 {
return;
}
if r2 < r1 {
mem::swap(&mut r1, &mut r2);
}
assert!(r2 < self.num_rows);
let num_cols = self.num_cols;
unsafe {
let (first, rest) = self.data.get_unchecked_mut(r1 * self.stride..).split_at_mut(num_cols);
let snd_idx = (r2 - r1) * self.stride - num_cols;
let second = rest.get_unchecked_mut(snd_idx..snd_idx + num_cols);
debug_assert_eq!(first.len(), num_cols);
debug_assert_eq!(second.len(), num_cols);
ptr::swap_nonoverlapping(first.as_mut_ptr(), second.as_mut_ptr(), num_cols);
}
}
unsafe fn get_unchecked_row_mut(&mut self, row: usize) -> &mut [T] {
let start = row * self.stride;
self.data.get_unchecked_mut(start..start + self.num_cols)
}
unsafe fn get_unchecked_mut(&mut self, coord: Coordinate) -> &mut T {
self.data.get_unchecked_mut(coord.1 * self.stride + coord.0)
}
}
impl<'a, T> Index<usize> for TooDeeViewMut<'a, T> {
type Output = [T];
fn index(&self, row: usize) -> &Self::Output {
assert!(row < self.num_rows);
let start = row * self.stride;
unsafe {
self.data.get_unchecked(start..start + self.num_cols)
}
}
}
impl<'a, T> Index<Coordinate> for TooDeeViewMut<'a, T> {
type Output = T;
fn index(&self, coord: Coordinate) -> &Self::Output {
assert!(coord.1 < self.num_rows);
assert!(coord.0 < self.num_cols);
unsafe {
self.data.get_unchecked(coord.1 * self.stride + coord.0)
}
}
}
impl<'a, T> IndexMut<usize> for TooDeeViewMut<'a, T> {
fn index_mut(&mut self, row: usize) -> &mut Self::Output {
assert!(row < self.num_rows);
let start = row * self.stride;
unsafe {
self.data.get_unchecked_mut(start..start + self.num_cols)
}
}
}
impl<'a, T> IndexMut<Coordinate> for TooDeeViewMut<'a, T> {
fn index_mut(&mut self, coord: Coordinate) -> &mut Self::Output {
assert!(coord.1 < self.num_rows);
assert!(coord.0 < self.num_cols);
unsafe {
self.data.get_unchecked_mut(coord.1 * self.stride + coord.0)
}
}
}
impl<'a, T> From<TooDeeViewMut<'a, T>> for TooDeeView<'a, T> {
fn from(v: TooDeeViewMut<'a, T>) -> TooDeeView<'a, T> {
TooDeeView {
data: v.data,
num_cols: v.num_cols,
num_rows: v.num_rows,
stride: v.stride,
}
}
}
impl<'a, T> IntoIterator for &'a TooDeeView<'a, T> {
type Item = &'a T;
type IntoIter = Cells<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.cells()
}
}
impl<'a, T> IntoIterator for &'a TooDeeViewMut<'a, T> {
type Item = &'a T;
type IntoIter = Cells<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.cells()
}
}
impl<'a, T> IntoIterator for &'a mut TooDeeViewMut<'a, T> {
type Item = &'a mut T;
type IntoIter = CellsMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.cells_mut()
}
}
impl<T> Debug for TooDeeView<'_, T> where T: Debug {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.rows()).finish()
}
}
impl<T> Debug for TooDeeViewMut<'_, T> where T: Debug {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.rows()).finish()
}
}