#[cfg(feature = "nightly")]
use std::alloc::{Allocator, Global};
use std::fmt::{Debug, Formatter, Result};
use std::hash::{Hash, Hasher};
#[cfg(feature = "nightly")]
use std::marker::PhantomData;
#[cfg(not(feature = "nightly"))]
use std::marker::{PhantomData, PhantomPinned};
use std::mem;
use std::ops::{Index, IndexMut};
use crate::dim::{Const, Dim, Dyn};
use crate::expr::{AxisExpr, AxisExprMut, Expr, ExprMut, Lanes, LanesMut, Map, Zip};
use crate::expression::Expression;
use crate::grid::Grid;
use crate::index::{Axis, DimIndex, Inner, Outer, Permutation, SpanIndex, ViewIndex};
use crate::iter::Iter;
use crate::layout::{Dense, Flat, Layout};
use crate::mapping::Mapping;
use crate::raw_span::RawSpan;
use crate::shape::{IntoShape, Rank, Shape};
#[cfg(not(feature = "nightly"))]
use crate::traits::{Apply, FromExpression, IntoCloned, IntoExpression};
#[cfg(feature = "nightly")]
use crate::traits::{Apply, IntoCloned, IntoExpression};
pub struct Span<T, S: Shape, L: Layout = Dense> {
phantom: PhantomData<(T, S, L)>,
#[cfg(not(feature = "nightly"))]
_pinned: PhantomPinned,
#[cfg(feature = "nightly")]
_opaque: Opaque,
}
pub type DSpan<T, const N: usize, L = Dense> = Span<T, Rank<N>, L>;
#[cfg(feature = "nightly")]
extern "C" {
type Opaque;
}
impl<T, S: Shape, L: Layout> Span<T, S, L> {
pub fn as_mut_ptr(&mut self) -> *mut T {
if mem::size_of::<S>() > 0 {
RawSpan::from_mut_span(self).as_mut_ptr()
} else {
self as *mut Self as *mut T
}
}
pub fn as_ptr(&self) -> *const T {
if mem::size_of::<S>() > 0 {
RawSpan::from_span(self).as_ptr()
} else {
self as *const Self as *const T
}
}
pub fn assign<I: IntoExpression<Item: IntoCloned<T>>>(&mut self, expr: I) {
self.expr_mut().zip(expr).for_each(|(x, y)| y.clone_to(x));
}
pub fn axis_expr<const N: usize>(&self) -> AxisExpr<T, S, L, Inner<N>>
where
Inner<N>: Axis,
{
AxisExpr::new(self)
}
pub fn axis_expr_mut<const N: usize>(&mut self) -> AxisExprMut<T, S, L, Inner<N>>
where
Inner<N>: Axis,
{
AxisExprMut::new(self)
}
pub fn cols(&self) -> Lanes<T, S, L, Inner<0>> {
Lanes::new(self)
}
pub fn cols_mut(&mut self) -> LanesMut<T, S, L, Inner<0>> {
LanesMut::new(self)
}
pub fn contains(&self, x: &T) -> bool
where
T: PartialEq,
{
contains(self, x)
}
pub fn dim(&self, index: usize) -> usize {
self.mapping().dim(index)
}
pub fn dims(&self) -> S::Dims {
self.mapping().dims()
}
pub fn expr(&self) -> Expr<T, S, L> {
unsafe { Expr::new_unchecked(self.as_ptr(), self.mapping()) }
}
pub fn expr_mut(&mut self) -> ExprMut<T, S, L> {
unsafe { ExprMut::new_unchecked(self.as_mut_ptr(), self.mapping()) }
}
pub fn fill(&mut self, value: T)
where
T: Clone,
{
self.expr_mut().for_each(|x| x.clone_from(&value));
}
pub fn fill_with<F: FnMut() -> T>(&mut self, mut f: F) {
self.expr_mut().for_each(|x| *x = f());
}
pub fn flatten(&self) -> Expr<T, Dyn, L::Uniform> {
self.expr().into_flattened()
}
pub fn flatten_mut(&mut self) -> ExprMut<T, Dyn, L::Uniform> {
self.expr_mut().into_flattened()
}
pub unsafe fn get_unchecked<I: SpanIndex<T, S, L>>(&self, index: I) -> &I::Output {
index.get_unchecked(self)
}
pub unsafe fn get_unchecked_mut<I: SpanIndex<T, S, L>>(&mut self, index: I) -> &mut I::Output {
index.get_unchecked_mut(self)
}
pub fn is_contiguous(&self) -> bool {
self.mapping().is_contiguous()
}
pub fn is_empty(&self) -> bool {
self.mapping().is_empty()
}
pub fn is_uniformly_strided(&self) -> bool {
self.mapping().is_uniformly_strided()
}
pub fn iter(&self) -> Iter<Expr<'_, T, S, L>> {
self.expr().into_iter()
}
pub fn iter_mut(&mut self) -> Iter<ExprMut<'_, T, S, L>> {
self.expr_mut().into_iter()
}
pub fn lanes<const N: usize>(&self) -> Lanes<T, S, L, Inner<N>>
where
Inner<N>: Axis,
{
Lanes::new(self)
}
pub fn lanes_mut<const N: usize>(&mut self) -> LanesMut<T, S, L, Inner<N>>
where
Inner<N>: Axis,
{
LanesMut::new(self)
}
pub fn len(&self) -> usize {
self.mapping().len()
}
pub fn mapping(&self) -> L::Mapping<S> {
if mem::size_of::<S>() > 0 {
RawSpan::from_span(self).mapping()
} else {
L::Mapping::default()
}
}
pub fn outer_expr(&self) -> AxisExpr<T, S, L, Outer> {
AxisExpr::new(self)
}
pub fn outer_expr_mut(&mut self) -> AxisExprMut<T, S, L, Outer> {
AxisExprMut::new(self)
}
pub fn rank(&self) -> usize {
S::RANK
}
pub fn remap<M: Layout>(&self) -> Expr<T, S, M> {
self.expr().into_mapping()
}
pub fn remap_mut<M: Layout>(&mut self) -> ExprMut<T, S, M> {
self.expr_mut().into_mapping()
}
pub fn reshape<I: IntoShape>(
&self,
shape: I,
) -> Expr<T, I::IntoShape, <I::IntoShape as Shape>::Layout<L::Uniform, L>> {
self.expr().into_shape(shape)
}
pub fn reshape_mut<I: IntoShape>(
&mut self,
shape: I,
) -> ExprMut<T, I::IntoShape, <I::IntoShape as Shape>::Layout<L::Uniform, L>> {
self.expr_mut().into_shape(shape)
}
pub fn rows(&self) -> Lanes<T, S, L, Inner<1>> {
Lanes::new(self)
}
pub fn rows_mut(&mut self) -> LanesMut<T, S, L, Inner<1>> {
LanesMut::new(self)
}
pub fn shape(&self) -> S {
self.mapping().shape()
}
pub fn split_at(
&self,
mid: usize,
) -> (Expr<T, <Outer as Axis>::Replace<Dyn, S>, L>, Expr<T, <Outer as Axis>::Replace<Dyn, S>, L>)
{
self.expr().into_split_at(mid)
}
pub fn split_at_mut(
&mut self,
mid: usize,
) -> (
ExprMut<T, <Outer as Axis>::Replace<Dyn, S>, L>,
ExprMut<T, <Outer as Axis>::Replace<Dyn, S>, L>,
) {
self.expr_mut().into_split_at(mid)
}
pub fn split_axis_at<const N: usize>(
&self,
mid: usize,
) -> (
Expr<T, <Inner<N> as Axis>::Replace<Dyn, S>, <Inner<N> as Axis>::Resize<S, L>>,
Expr<T, <Inner<N> as Axis>::Replace<Dyn, S>, <Inner<N> as Axis>::Resize<S, L>>,
)
where
Inner<N>: Axis,
{
self.expr().into_split_axis_at(mid)
}
pub fn split_axis_at_mut<const N: usize>(
&mut self,
mid: usize,
) -> (
ExprMut<T, <Inner<N> as Axis>::Replace<Dyn, S>, <Inner<N> as Axis>::Resize<S, L>>,
ExprMut<T, <Inner<N> as Axis>::Replace<Dyn, S>, <Inner<N> as Axis>::Resize<S, L>>,
)
where
Inner<N>: Axis,
{
self.expr_mut().into_split_axis_at(mid)
}
pub fn stride(&self, index: usize) -> isize {
self.mapping().stride(index)
}
pub fn strides(&self) -> S::Strides {
self.mapping().strides()
}
#[cfg(not(feature = "nightly"))]
pub fn to_grid(&self) -> Grid<T, S>
where
T: Clone,
{
Grid::from_expr(self.expr().cloned())
}
#[cfg(feature = "nightly")]
pub fn to_grid(&self) -> Grid<T, S>
where
T: Clone,
{
self.to_grid_in(Global)
}
#[cfg(feature = "nightly")]
pub fn to_grid_in<A: Allocator>(&self, alloc: A) -> Grid<T, S, A>
where
T: Clone,
{
self.expr().cloned().eval_in(alloc)
}
pub fn to_vec(&self) -> Vec<T>
where
T: Clone,
{
self.to_grid().into_vec()
}
#[cfg(feature = "nightly")]
pub fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A>
where
T: Clone,
{
self.to_grid_in(alloc).into_vec()
}
}
impl<T, S: Shape> Span<T, S> {
pub fn as_mut_slice(&mut self) -> &mut [T] {
self.expr_mut().into_slice()
}
pub fn as_slice(&self) -> &[T] {
self.expr().into_slice()
}
}
impl<T, X: Dim, Y: Dim, L: Layout> Span<T, (X, Y), L> {
pub fn col(&self, index: usize) -> Expr<T, X, L::Uniform> {
self.view(.., index)
}
pub fn col_mut(&mut self, index: usize) -> ExprMut<T, X, L::Uniform> {
self.view_mut(.., index)
}
pub fn diag(&self, index: isize) -> Expr<T, Dyn, Flat> {
self.expr().into_diag(index)
}
pub fn diag_mut(&mut self, index: isize) -> ExprMut<T, Dyn, Flat> {
self.expr_mut().into_diag(index)
}
pub fn row(&self, index: usize) -> Expr<T, Y, Flat> {
self.view(index, ..)
}
pub fn row_mut(&mut self, index: usize) -> ExprMut<T, Y, Flat> {
self.view_mut(index, ..)
}
}
macro_rules! impl_permute {
(($($xyz:tt),+), ($($abc:tt),*)) => {
#[allow(unused_parens)]
impl<T, $($xyz: Dim,)+ L: Layout> Span<T, ($($xyz),+), L> {
pub fn permute<$(const $abc: usize),+>(
&self
) -> Expr<
T,
<($(Const<$abc>,)+) as Permutation>::Shape<($($xyz),+)>,
<($(Const<$abc>,)+) as Permutation>::Layout<L>,
>
where
($(Const<$abc>,)+): Permutation
{
self.expr().into_permuted()
}
pub fn permute_mut<$(const $abc: usize),+>(
&mut self
) -> ExprMut<
T,
<($(Const<$abc>,)+) as Permutation>::Shape<($($xyz),+)>,
<($(Const<$abc>,)+) as Permutation>::Layout<L>,
>
where
($(Const<$abc>,)+): Permutation
{
self.expr_mut().into_permuted()
}
}
};
}
impl_permute!((X), (A));
impl_permute!((X, Y), (A, B));
impl_permute!((X, Y, Z), (A, B, C));
impl_permute!((X, Y, Z, W), (A, B, C, D));
impl_permute!((X, Y, Z, W, U), (A, B, C, D, E));
impl_permute!((X, Y, Z, W, U, V), (A, B, C, D, E, F));
macro_rules! impl_view {
(($($xyz:tt),+), ($($abc:tt),+), ($($idx:tt),+)) => {
#[allow(unused_parens)]
impl<T, $($xyz: Dim,)+ L: Layout> Span<T, ($($xyz),+), L> {
pub fn grid<$($abc: DimIndex),+>(
&self,
$($idx: $abc),+
) -> Grid<T, <($($abc,)+) as ViewIndex>::Shape<($($xyz),+)>>
where
T: Clone,
{
self.view($($idx),+).to_grid()
}
pub fn view<$($abc: DimIndex),+>(
&self,
$($idx: $abc),+
) -> Expr<
T,
<($($abc,)+) as ViewIndex>::Shape<($($xyz),+)>,
<($($abc,)+) as ViewIndex>::Layout<($($xyz),+), L>,
> {
self.expr().into_view($($idx),+)
}
pub fn view_mut<$($abc: DimIndex),+>(
&mut self,
$($idx: $abc),+,
) -> ExprMut<
T,
<($($abc,)+) as ViewIndex>::Shape<($($xyz),+)>,
<($($abc,)+) as ViewIndex>::Layout<($($xyz),+), L>,
> {
self.expr_mut().into_view($($idx),+)
}
}
};
}
impl_view!((X), (A), (a));
impl_view!((X, Y), (A, B), (a, b));
impl_view!((X, Y, Z), (A, B, C), (a, b, c));
impl_view!((X, Y, Z, W), (A, B, C, D), (a, b, c, d));
impl_view!((X, Y, Z, W, U), (A, B, C, D, E), (a, b, c, d, e));
impl_view!((X, Y, Z, W, U, V), (A, B, C, D, E, F), (a, b, c, d, e, f));
impl<'a, T, U, S: Shape, L: Layout> Apply<U> for &'a Span<T, S, L> {
type Output<F: FnMut(&'a T) -> U> = Map<Self::IntoExpr, F>;
type ZippedWith<I: IntoExpression, F: FnMut((&'a T, I::Item)) -> U> =
Map<Zip<Self::IntoExpr, I::IntoExpr>, F>;
fn apply<F: FnMut(&'a T) -> U>(self, f: F) -> Self::Output<F> {
self.expr().map(f)
}
fn zip_with<I: IntoExpression, F>(self, expr: I, f: F) -> Self::ZippedWith<I, F>
where
F: FnMut((&'a T, I::Item)) -> U,
{
self.expr().zip(expr).map(f)
}
}
impl<'a, T, U, S: Shape, L: Layout> Apply<U> for &'a mut Span<T, S, L> {
type Output<F: FnMut(&'a mut T) -> U> = Map<Self::IntoExpr, F>;
type ZippedWith<I: IntoExpression, F: FnMut((&'a mut T, I::Item)) -> U> =
Map<Zip<Self::IntoExpr, I::IntoExpr>, F>;
fn apply<F: FnMut(&'a mut T) -> U>(self, f: F) -> Self::Output<F> {
self.expr_mut().map(f)
}
fn zip_with<I: IntoExpression, F>(self, expr: I, f: F) -> Self::ZippedWith<I, F>
where
F: FnMut((&'a mut T, I::Item)) -> U,
{
self.expr_mut().zip(expr).map(f)
}
}
impl<T, S: Shape, L: Layout> AsMut<Span<T, S, L>> for Span<T, S, L> {
fn as_mut(&mut self) -> &mut Span<T, S, L> {
self
}
}
impl<T, S: Shape> AsMut<[T]> for Span<T, S> {
fn as_mut(&mut self) -> &mut [T] {
&mut self[..]
}
}
impl<T, S: Shape, L: Layout> AsRef<Span<T, S, L>> for Span<T, S, L> {
fn as_ref(&self) -> &Span<T, S, L> {
self
}
}
impl<T, S: Shape> AsRef<[T]> for Span<T, S> {
fn as_ref(&self) -> &[T] {
&self[..]
}
}
macro_rules! impl_as_mut_ref {
(($($xyz:tt),+), $array:tt) => {
#[allow(unused_parens)]
impl<T, $(const $xyz: usize),+> AsMut<Span<T, ($(Const<$xyz>),+)>> for $array {
fn as_mut(&mut self) -> &mut Span<T, ($(Const<$xyz>),+)> {
unsafe { &mut *(self as *mut $array as *mut Span<T, ($(Const<$xyz>),+)>) }
}
}
#[allow(unused_parens)]
impl<T, $(const $xyz: usize),+> AsMut<$array> for Span<T, ($(Const<$xyz>),+)> {
fn as_mut(&mut self) -> &mut $array {
unsafe { &mut *(self as *mut Span<T, ($(Const<$xyz>),+)>).cast() }
}
}
#[allow(unused_parens)]
impl<T, $(const $xyz: usize),+> AsRef<Span<T, ($(Const<$xyz>),+)>> for $array {
fn as_ref(&self) -> &Span<T, ($(Const<$xyz>),+)> {
unsafe { &*(self as *const $array as *const Span<T, ($(Const<$xyz>),+)>) }
}
}
#[allow(unused_parens)]
impl<T, $(const $xyz: usize),+> AsRef<$array> for Span<T, ($(Const<$xyz>),+)> {
fn as_ref(&self) -> &$array {
unsafe { &*(self as *const Span<T, ($(Const<$xyz>),+)>).cast() }
}
}
};
}
impl_as_mut_ref!((X), [T; X]);
impl_as_mut_ref!((X, Y), [[T; X]; Y]);
impl_as_mut_ref!((X, Y, Z), [[[T; X]; Y]; Z]);
impl_as_mut_ref!((X, Y, Z, W), [[[[T; X]; Y]; Z]; W]);
impl_as_mut_ref!((X, Y, Z, W, U), [[[[[T; X]; Y]; Z]; W]; U]);
impl_as_mut_ref!((X, Y, Z, W, U, V), [[[[[[T; X]; Y]; Z]; W]; U]; V]);
impl<T: Debug, S: Shape, L: Layout> Debug for Span<T, S, L> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
if S::RANK == 0 {
self[S::Dims::default()].fmt(f)
} else {
let mut list = f.debug_list();
if !self.is_empty() {
_ = list.entries(self.outer_expr());
}
list.finish()
}
}
}
impl<T: Hash, S: Shape, L: Layout> Hash for Span<T, S, L> {
fn hash<H: Hasher>(&self, state: &mut H) {
for i in 0..S::RANK {
#[cfg(not(feature = "nightly"))]
state.write_usize(self.dim(i));
#[cfg(feature = "nightly")]
state.write_length_prefix(self.dim(i));
}
self.expr().for_each(|x| x.hash(state));
}
}
impl<T, S: Shape, L: Layout, I: SpanIndex<T, S, L>> Index<I> for Span<T, S, L> {
type Output = I::Output;
fn index(&self, index: I) -> &I::Output {
index.index(self)
}
}
impl<T, S: Shape, L: Layout, I: SpanIndex<T, S, L>> IndexMut<I> for Span<T, S, L> {
fn index_mut(&mut self, index: I) -> &mut I::Output {
index.index_mut(self)
}
}
impl<'a, T, S: Shape, L: Layout> IntoExpression for &'a Span<T, S, L> {
type Shape = S;
type IntoExpr = Expr<'a, T, S, L>;
fn into_expr(self) -> Self::IntoExpr {
self.expr()
}
}
impl<'a, T, S: Shape, L: Layout> IntoExpression for &'a mut Span<T, S, L> {
type Shape = S;
type IntoExpr = ExprMut<'a, T, S, L>;
fn into_expr(self) -> Self::IntoExpr {
self.expr_mut()
}
}
impl<'a, T, S: Shape, L: Layout> IntoIterator for &'a Span<T, S, L> {
type Item = &'a T;
type IntoIter = Iter<Expr<'a, T, S, L>>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T, S: Shape, L: Layout> IntoIterator for &'a mut Span<T, S, L> {
type Item = &'a mut T;
type IntoIter = Iter<ExprMut<'a, T, S, L>>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
#[cfg(feature = "nightly")]
unsafe impl<T: Send, S: Shape, L: Layout> Send for Span<T, S, L> {}
#[cfg(feature = "nightly")]
unsafe impl<T: Sync, S: Shape, L: Layout> Sync for Span<T, S, L> {}
impl<T: Clone, S: Shape> ToOwned for Span<T, S> {
type Owned = Grid<T, S>;
fn to_owned(&self) -> Self::Owned {
self.to_grid()
}
fn clone_into(&self, target: &mut Self::Owned) {
target.clone_from_span(self);
}
}
fn contains<T: PartialEq, S: Shape, L: Layout>(this: &Span<T, S, L>, value: &T) -> bool {
if L::IS_UNIFORM {
if L::IS_UNIT_STRIDED {
this.remap()[..].contains(value)
} else {
this.iter().any(|x| x == value)
}
} else {
this.outer_expr().into_iter().any(|x| x.contains(value))
}
}