ferray_core/array/
view.rs1use ndarray::ShapeBuilder;
4
5use crate::dimension::Dimension;
6use crate::dtype::Element;
7use crate::layout::MemoryLayout;
8
9use super::ArrayFlags;
10use super::owned::Array;
11
12pub struct ArrayView<'a, T: Element, D: Dimension> {
17 pub(crate) inner: ndarray::ArrayView<'a, T, D::NdarrayDim>,
18 pub(crate) dim: D,
19}
20
21impl<'a, T: Element, D: Dimension> ArrayView<'a, T, D> {
22 pub(crate) fn from_ndarray(inner: ndarray::ArrayView<'a, T, D::NdarrayDim>) -> Self {
24 let dim = D::from_ndarray_dim(&inner.raw_dim());
25 Self { inner, dim }
26 }
27
28 #[inline]
30 pub fn shape(&self) -> &[usize] {
31 self.inner.shape()
32 }
33
34 #[inline]
36 pub fn ndim(&self) -> usize {
37 self.dim.ndim()
38 }
39
40 #[inline]
42 pub fn size(&self) -> usize {
43 self.inner.len()
44 }
45
46 #[inline]
48 pub fn is_empty(&self) -> bool {
49 self.inner.is_empty()
50 }
51
52 #[inline]
54 pub fn strides(&self) -> &[isize] {
55 self.inner.strides()
56 }
57
58 #[inline]
60 pub fn as_ptr(&self) -> *const T {
61 self.inner.as_ptr()
62 }
63
64 pub fn as_slice(&self) -> Option<&[T]> {
66 self.inner.as_slice()
67 }
68
69 pub fn layout(&self) -> MemoryLayout {
71 crate::layout::classify_layout(
72 self.inner.is_standard_layout(),
73 self.dim.as_slice(),
74 self.inner.strides(),
75 )
76 }
77
78 #[inline]
80 pub const fn dim(&self) -> &D {
81 &self.dim
82 }
83
84 pub fn to_owned(&self) -> Array<T, D> {
86 Array::from_ndarray(self.inner.to_owned())
87 }
88
89 pub fn to_vec_flat(&self) -> Vec<T> {
94 self.inner.iter().cloned().collect()
95 }
96
97 pub fn flags(&self) -> ArrayFlags {
99 let layout = self.layout();
100 ArrayFlags {
101 c_contiguous: layout.is_c_contiguous(),
102 f_contiguous: layout.is_f_contiguous(),
103 owndata: false,
104 writeable: false,
105 aligned: (self.inner.as_ptr() as usize) % core::mem::align_of::<T>() == 0,
108 }
109 }
110}
111
112use crate::dimension::IxDyn;
113
114impl<T: Element> ArrayView<'_, T, IxDyn> {
115 pub unsafe fn from_shape_ptr(ptr: *const T, shape: &[usize], strides: &[usize]) -> Self {
131 let nd_shape = ndarray::IxDyn(shape);
132 let nd_strides = ndarray::IxDyn(strides);
133 let nd_view =
134 unsafe { ndarray::ArrayView::from_shape_ptr(nd_shape.strides(nd_strides), ptr) };
135 Self::from_ndarray(nd_view)
136 }
137}
138
139impl<T: Element, D: Dimension> Clone for ArrayView<'_, T, D> {
140 fn clone(&self) -> Self {
141 Self {
142 inner: self.inner.clone(),
143 dim: self.dim.clone(),
144 }
145 }
146}
147
148impl<T: Element, D: Dimension> Array<T, D> {
150 pub fn view(&self) -> ArrayView<'_, T, D> {
152 ArrayView::from_ndarray(self.inner.view())
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159 use crate::dimension::Ix2;
160
161 #[test]
162 fn view_from_owned() {
163 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
164 .unwrap();
165 let v = arr.view();
166 assert_eq!(v.shape(), &[2, 3]);
167 assert_eq!(v.size(), 6);
168 assert!(!v.flags().owndata);
169 assert!(!v.flags().writeable);
170 }
171
172 #[test]
173 fn view_shares_data() {
174 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
175 .unwrap();
176 let v = arr.view();
177 assert_eq!(arr.as_ptr(), v.as_ptr());
179 }
180
181 #[test]
182 fn view_to_owned() {
183 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
184 .unwrap();
185 let v = arr.view();
186 let owned = v.to_owned();
187 assert_eq!(owned.shape(), arr.shape());
188 assert_eq!(owned.as_slice().unwrap(), arr.as_slice().unwrap());
189 assert_ne!(owned.as_ptr(), arr.as_ptr());
191 }
192}