use ndarray::ShapeBuilder;
use crate::dimension::Dimension;
use crate::dtype::Element;
use crate::layout::MemoryLayout;
use super::ArrayFlags;
use super::owned::Array;
pub struct ArrayView<'a, T: Element, D: Dimension> {
pub(crate) inner: ndarray::ArrayView<'a, T, D::NdarrayDim>,
pub(crate) dim: D,
}
impl<'a, T: Element, D: Dimension> ArrayView<'a, T, D> {
pub(crate) fn from_ndarray(inner: ndarray::ArrayView<'a, T, D::NdarrayDim>) -> Self {
let dim = D::from_ndarray_dim(&inner.raw_dim());
Self { inner, dim }
}
#[inline]
pub fn shape(&self) -> &[usize] {
self.inner.shape()
}
#[inline]
pub fn ndim(&self) -> usize {
self.dim.ndim()
}
#[inline]
pub fn size(&self) -> usize {
self.inner.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[inline]
pub fn strides(&self) -> &[isize] {
self.inner.strides()
}
#[inline]
pub fn as_ptr(&self) -> *const T {
self.inner.as_ptr()
}
pub fn as_slice(&self) -> Option<&[T]> {
self.inner.as_slice()
}
pub fn layout(&self) -> MemoryLayout {
if self.inner.is_standard_layout() {
MemoryLayout::C
} else {
let shape = self.dim.as_slice();
let strides: Vec<isize> = self.inner.strides().to_vec();
crate::layout::detect_layout(shape, &strides)
}
}
#[inline]
pub fn dim(&self) -> &D {
&self.dim
}
pub fn to_owned(&self) -> Array<T, D> {
Array::from_ndarray(self.inner.to_owned())
}
pub fn flags(&self) -> ArrayFlags {
let layout = self.layout();
ArrayFlags {
c_contiguous: layout.is_c_contiguous(),
f_contiguous: layout.is_f_contiguous(),
owndata: false,
writeable: false,
}
}
}
use crate::dimension::IxDyn;
impl<'a, T: Element> ArrayView<'a, T, IxDyn> {
pub unsafe fn from_shape_ptr(ptr: *const T, shape: &[usize], strides: &[usize]) -> Self {
let nd_shape = ndarray::IxDyn(shape);
let nd_strides = ndarray::IxDyn(strides);
let nd_view =
unsafe { ndarray::ArrayView::from_shape_ptr(nd_shape.strides(nd_strides), ptr) };
Self::from_ndarray(nd_view)
}
}
impl<T: Element, D: Dimension> Clone for ArrayView<'_, T, D> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
dim: self.dim.clone(),
}
}
}
impl<T: Element, D: Dimension> Array<T, D> {
pub fn view(&self) -> ArrayView<'_, T, D> {
ArrayView::from_ndarray(self.inner.view())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dimension::Ix2;
#[test]
fn view_from_owned() {
let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
.unwrap();
let v = arr.view();
assert_eq!(v.shape(), &[2, 3]);
assert_eq!(v.size(), 6);
assert!(!v.flags().owndata);
assert!(!v.flags().writeable);
}
#[test]
fn view_shares_data() {
let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
.unwrap();
let v = arr.view();
assert_eq!(arr.as_ptr(), v.as_ptr());
}
#[test]
fn view_to_owned() {
let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
.unwrap();
let v = arr.view();
let owned = v.to_owned();
assert_eq!(owned.shape(), arr.shape());
assert_eq!(owned.as_slice().unwrap(), arr.as_slice().unwrap());
assert_ne!(owned.as_ptr(), arr.as_ptr());
}
}