From 99722fa3e82564a183d8bad5e6b0683750a60e7a Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Thu, 3 Oct 2024 20:52:20 -0400 Subject: [PATCH 01/33] Adds an array reference type. The reference type, `RefBase`, is parameterized by its element type, a dimensionality type, and its "referent" type. This last type is only a `PhantomData` marker, and acts to differentiate references that are "safe" from those that are "raw", i.e., references that come from an array whose storage is `Data` vs an array whose stoarge is `RawData`. The `DerefMut` implementation contains a check of uniqueness, guaranteeing that an `&mut RefBase` is safe to mutate. This comes with one breaking change and one important internal library note. The breaking change is that `ArrayBase` no longer implements `Copy` for views. This is because a `RefBase` does not know where it is pointing, and therefore cannot implement `Copy`; this, in turn, prohibits `ArrayBase` from implementing `Copy`. Users will now have to explicitly invoke `Clone` in the same way that they do for non-view arrays. The important library note has to do with the `.try_ensure_unique` check that occurs in the `DerefMut` implementation. The library's methods are allowed to *temporarily* break the invariant that an array's `ptr` is contained within `data`. The issue comes when trying to then alter `ptr`, `shape`, or `dim` while that invariant is broken. Code was using `self.ptr = ...` (where `self` is `ArrayBase`), which triggers `DerefMut`, which calls `try_ensure_unique`, which panics on the pointer inbounds check. As a result, code that is altering `RefBase` fields while the array's invariants are broken must be sure to write `self.aref.ptr = ...` instead. --- src/arrayref.rs | 48 +++++++++++++++++++++++++++++++ src/arraytraits.rs | 2 +- src/data_traits.rs | 34 ++++++++++++++-------- src/free_functions.rs | 32 ++++++++++++++------- src/impl_clone.rs | 17 ++++++----- src/impl_cow.rs | 4 +-- src/impl_dyn.rs | 8 +++--- src/impl_internal_constructors.rs | 19 ++++++++---- src/impl_methods.rs | 42 +++++++++++++-------------- src/impl_owned_array.rs | 14 ++++----- src/impl_raw_views.rs | 22 +++++++------- src/impl_special_element_types.rs | 9 ++++-- src/impl_views/constructors.rs | 2 +- src/impl_views/conversions.rs | 16 +++++------ src/iterators/chunks.rs | 4 +-- src/iterators/into_iter.rs | 6 ++-- src/iterators/mod.rs | 6 ++-- src/lib.rs | 18 +++++++++++- src/zip/mod.rs | 2 +- tests/append.rs | 10 +++---- tests/array.rs | 10 +++---- tests/reshape.rs | 8 +++--- tests/views.rs | 2 +- 23 files changed, 216 insertions(+), 119 deletions(-) create mode 100644 src/arrayref.rs diff --git a/src/arrayref.rs b/src/arrayref.rs new file mode 100644 index 000000000..f28d21c03 --- /dev/null +++ b/src/arrayref.rs @@ -0,0 +1,48 @@ +//! Code for the array reference type + +use core::ops::{Deref, DerefMut}; + +use crate::{ArrayBase, Dimension, RawData, RawDataMut, RefBase}; + +/// Unit struct to mark a reference as raw +#[derive(Copy, Clone)] +pub struct Raw; +/// Unit struct to mark a reference as safe +#[derive(Copy, Clone)] +pub struct Safe; + +pub trait RawReferent { + private_decl! {} +} +pub trait Referent { + private_decl! {} +} + +impl RawReferent for Raw { + private_impl! {} +} +impl RawReferent for Safe { + private_impl! {} +} +impl Referent for Safe { + private_impl! {} +} + +impl Deref for ArrayBase +where S: RawData +{ + type Target = RefBase; + + fn deref(&self) -> &Self::Target { + &self.aref + } +} + +impl DerefMut for ArrayBase +where S: RawDataMut, D: Dimension, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + self.try_ensure_unique(); + &mut self.aref + } +} diff --git a/src/arraytraits.rs b/src/arraytraits.rs index e68b5d56a..1055943e0 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -463,7 +463,7 @@ where D: Dimension { let data = OwnedArcRepr(Arc::new(arr.data)); // safe because: equivalent unmoved data, ptr and dims remain valid - unsafe { ArrayBase::from_data_ptr(data, arr.ptr).with_strides_dim(arr.strides, arr.dim) } + unsafe { ArrayBase::from_data_ptr(data, arr.aref.ptr).with_strides_dim(arr.aref.strides, arr.aref.dim) } } } diff --git a/src/data_traits.rs b/src/data_traits.rs index f43bfb4ef..29feef9c2 100644 --- a/src/data_traits.rs +++ b/src/data_traits.rs @@ -23,7 +23,7 @@ use std::mem::MaybeUninit; use std::mem::{self, size_of}; use std::ptr::NonNull; -use crate::{ArcArray, Array, ArrayBase, CowRepr, Dimension, OwnedArcRepr, OwnedRepr, RawViewRepr, ViewRepr}; +use crate::{ArcArray, Array, ArrayBase, CowRepr, Dimension, OwnedArcRepr, OwnedRepr, Raw, RawReferent, RawViewRepr, Safe, ViewRepr}; /// Array representation trait. /// @@ -40,6 +40,9 @@ pub unsafe trait RawData: Sized /// The array element type. type Elem; + /// The safety of the reference type + type Referent: RawReferent; + #[doc(hidden)] fn _is_pointer_inbounds(&self, ptr: *const Self::Elem) -> bool; @@ -171,6 +174,7 @@ pub unsafe trait DataMut: Data + RawDataMut unsafe impl RawData for RawViewRepr<*const A> { type Elem = A; + type Referent = Raw; #[inline(always)] fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool @@ -192,6 +196,7 @@ unsafe impl RawDataClone for RawViewRepr<*const A> unsafe impl RawData for RawViewRepr<*mut A> { type Elem = A; + type Referent = Raw; #[inline(always)] fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool @@ -230,6 +235,7 @@ unsafe impl RawDataClone for RawViewRepr<*mut A> unsafe impl RawData for OwnedArcRepr { type Elem = A; + type Referent = Safe; fn _is_pointer_inbounds(&self, self_ptr: *const Self::Elem) -> bool { @@ -260,13 +266,13 @@ where A: Clone let rcvec = &mut self_.data.0; let a_size = mem::size_of::() as isize; let our_off = if a_size != 0 { - (self_.ptr.as_ptr() as isize - rcvec.as_ptr() as isize) / a_size + (self_.aref.ptr.as_ptr() as isize - rcvec.as_ptr() as isize) / a_size } else { 0 }; let rvec = Arc::make_mut(rcvec); unsafe { - self_.ptr = rvec.as_nonnull_mut().offset(our_off); + self_.aref.ptr = rvec.as_nonnull_mut().offset(our_off); } } @@ -286,7 +292,7 @@ unsafe impl Data for OwnedArcRepr Self::ensure_unique(&mut self_); let data = Arc::try_unwrap(self_.data.0).ok().unwrap(); // safe because data is equivalent - unsafe { ArrayBase::from_data_ptr(data, self_.ptr).with_strides_dim(self_.strides, self_.dim) } + unsafe { ArrayBase::from_data_ptr(data, self_.aref.ptr).with_strides_dim(self_.aref.strides, self_.aref.dim) } } fn try_into_owned_nocopy(self_: ArrayBase) -> Result, ArrayBase> @@ -295,13 +301,13 @@ unsafe impl Data for OwnedArcRepr match Arc::try_unwrap(self_.data.0) { Ok(owned_data) => unsafe { // Safe because the data is equivalent. - Ok(ArrayBase::from_data_ptr(owned_data, self_.ptr).with_strides_dim(self_.strides, self_.dim)) + Ok(ArrayBase::from_data_ptr(owned_data, self_.aref.ptr).with_strides_dim(self_.aref.strides, self_.aref.dim)) }, Err(arc_data) => unsafe { // Safe because the data is equivalent; we're just // reconstructing `self_`. - Err(ArrayBase::from_data_ptr(OwnedArcRepr(arc_data), self_.ptr) - .with_strides_dim(self_.strides, self_.dim)) + Err(ArrayBase::from_data_ptr(OwnedArcRepr(arc_data), self_.aref.ptr) + .with_strides_dim(self_.aref.strides, self_.aref.dim)) }, } } @@ -331,6 +337,7 @@ unsafe impl RawDataClone for OwnedArcRepr unsafe impl RawData for OwnedRepr { type Elem = A; + type Referent = Safe; fn _is_pointer_inbounds(&self, self_ptr: *const Self::Elem) -> bool { @@ -410,6 +417,7 @@ where A: Clone unsafe impl<'a, A> RawData for ViewRepr<&'a A> { type Elem = A; + type Referent = Safe; #[inline(always)] fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool @@ -448,6 +456,7 @@ unsafe impl<'a, A> RawDataClone for ViewRepr<&'a A> unsafe impl<'a, A> RawData for ViewRepr<&'a mut A> { type Elem = A; + type Referent = Safe; #[inline(always)] fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool @@ -574,6 +583,7 @@ unsafe impl DataOwned for OwnedArcRepr unsafe impl<'a, A> RawData for CowRepr<'a, A> { type Elem = A; + type Referent = Safe; #[inline] fn _is_pointer_inbounds(&self, ptr: *const Self::Elem) -> bool @@ -600,9 +610,9 @@ where A: Clone CowRepr::View(_) => { let owned = array.to_owned(); array.data = CowRepr::Owned(owned.data); - array.ptr = owned.ptr; - array.dim = owned.dim; - array.strides = owned.strides; + array.aref.ptr = owned.aref.ptr; + array.aref.dim = owned.aref.dim; + array.aref.strides = owned.aref.strides; } CowRepr::Owned(_) => {} } @@ -663,7 +673,7 @@ unsafe impl<'a, A> Data for CowRepr<'a, A> CowRepr::View(_) => self_.to_owned(), CowRepr::Owned(data) => unsafe { // safe because the data is equivalent so ptr, dims remain valid - ArrayBase::from_data_ptr(data, self_.ptr).with_strides_dim(self_.strides, self_.dim) + ArrayBase::from_data_ptr(data, self_.aref.ptr).with_strides_dim(self_.aref.strides, self_.aref.dim) }, } } @@ -675,7 +685,7 @@ unsafe impl<'a, A> Data for CowRepr<'a, A> CowRepr::View(_) => Err(self_), CowRepr::Owned(data) => unsafe { // safe because the data is equivalent so ptr, dims remain valid - Ok(ArrayBase::from_data_ptr(data, self_.ptr).with_strides_dim(self_.strides, self_.dim)) + Ok(ArrayBase::from_data_ptr(data, self_.aref.ptr).with_strides_dim(self_.aref.strides, self_.aref.dim)) }, } } diff --git a/src/free_functions.rs b/src/free_functions.rs index 5659d7024..60135f24a 100644 --- a/src/free_functions.rs +++ b/src/free_functions.rs @@ -9,6 +9,7 @@ use alloc::vec; #[cfg(not(feature = "std"))] use alloc::vec::Vec; +use core::marker::PhantomData; #[allow(unused_imports)] use std::compile_error; use std::mem::{forget, size_of}; @@ -106,10 +107,13 @@ pub const fn aview0(x: &A) -> ArrayView0<'_, A> { ArrayBase { data: ViewRepr::new(), - // Safe because references are always non-null. - ptr: unsafe { NonNull::new_unchecked(x as *const A as *mut A) }, - dim: Ix0(), - strides: Ix0(), + aref: RefBase { + // Safe because references are always non-null. + ptr: unsafe { NonNull::new_unchecked(x as *const A as *mut A) }, + dim: Ix0(), + strides: Ix0(), + phantom: PhantomData::< as RawData>::Referent>, + } } } @@ -144,10 +148,13 @@ pub const fn aview1(xs: &[A]) -> ArrayView1<'_, A> } ArrayBase { data: ViewRepr::new(), - // Safe because references are always non-null. - ptr: unsafe { NonNull::new_unchecked(xs.as_ptr() as *mut A) }, - dim: Ix1(xs.len()), - strides: Ix1(1), + aref: RefBase { + // Safe because references are always non-null. + ptr: unsafe { NonNull::new_unchecked(xs.as_ptr() as *mut A) }, + dim: Ix1(xs.len()), + strides: Ix1(1), + phantom: PhantomData::< as RawData>::Referent>, + } } } @@ -200,9 +207,12 @@ pub const fn aview2(xs: &[[A; N]]) -> ArrayView2<'_, A> }; ArrayBase { data: ViewRepr::new(), - ptr, - dim, - strides, + aref: RefBase { + ptr, + dim, + strides, + phantom: PhantomData::< as RawData>::Referent> + } } } diff --git a/src/impl_clone.rs b/src/impl_clone.rs index d65f6c338..c52e67c4e 100644 --- a/src/impl_clone.rs +++ b/src/impl_clone.rs @@ -18,9 +18,12 @@ impl Clone for ArrayBase let (data, ptr) = self.data.clone_with_ptr(self.ptr); ArrayBase { data, - ptr, - dim: self.dim.clone(), - strides: self.strides.clone(), + aref: RefBase { + ptr, + dim: self.dim.clone(), + strides: self.strides.clone(), + phantom: self.phantom + } } } } @@ -31,11 +34,11 @@ impl Clone for ArrayBase fn clone_from(&mut self, other: &Self) { unsafe { - self.ptr = self.data.clone_from_with_ptr(&other.data, other.ptr); - self.dim.clone_from(&other.dim); - self.strides.clone_from(&other.strides); + self.aref.ptr = self.data.clone_from_with_ptr(&other.data, other.ptr); + self.aref.dim.clone_from(&other.dim); + self.aref.strides.clone_from(&other.strides); } } } -impl Copy for ArrayBase {} +// impl Copy for ArrayBase {} diff --git a/src/impl_cow.rs b/src/impl_cow.rs index f064ce7bd..f17586e2a 100644 --- a/src/impl_cow.rs +++ b/src/impl_cow.rs @@ -33,7 +33,7 @@ where D: Dimension fn from(view: ArrayView<'a, A, D>) -> CowArray<'a, A, D> { // safe because equivalent data - unsafe { ArrayBase::from_data_ptr(CowRepr::View(view.data), view.ptr).with_strides_dim(view.strides, view.dim) } + unsafe { ArrayBase::from_data_ptr(CowRepr::View(view.data), view.ptr).with_strides_dim(view.aref.strides, view.aref.dim) } } } @@ -44,7 +44,7 @@ where D: Dimension { // safe because equivalent data unsafe { - ArrayBase::from_data_ptr(CowRepr::Owned(array.data), array.ptr).with_strides_dim(array.strides, array.dim) + ArrayBase::from_data_ptr(CowRepr::Owned(array.data), array.aref.ptr).with_strides_dim(array.aref.strides, array.aref.dim) } } } diff --git a/src/impl_dyn.rs b/src/impl_dyn.rs index b86c5dd69..493c016c6 100644 --- a/src/impl_dyn.rs +++ b/src/impl_dyn.rs @@ -32,8 +32,8 @@ where S: Data pub fn insert_axis_inplace(&mut self, axis: Axis) { assert!(axis.index() <= self.ndim()); - self.dim = self.dim.insert_axis(axis); - self.strides = self.strides.insert_axis(axis); + self.aref.dim = self.dim.insert_axis(axis); + self.aref.strides = self.strides.insert_axis(axis); } /// Collapses the array to `index` along the axis and removes the axis, @@ -55,8 +55,8 @@ where S: Data pub fn index_axis_inplace(&mut self, axis: Axis, index: usize) { self.collapse_axis(axis, index); - self.dim = self.dim.remove_axis(axis); - self.strides = self.strides.remove_axis(axis); + self.aref.dim = self.dim.remove_axis(axis); + self.aref.strides = self.strides.remove_axis(axis); } /// Remove axes of length 1 and return the modified array. diff --git a/src/impl_internal_constructors.rs b/src/impl_internal_constructors.rs index adb4cbd35..79a3c9671 100644 --- a/src/impl_internal_constructors.rs +++ b/src/impl_internal_constructors.rs @@ -6,6 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::marker::PhantomData; use std::ptr::NonNull; use crate::imp_prelude::*; @@ -27,9 +28,12 @@ where S: RawData { let array = ArrayBase { data, - ptr, - dim: Ix1(0), - strides: Ix1(1), + aref: RefBase { + ptr, + dim: Ix1(0), + strides: Ix1(1), + phantom: PhantomData::, + } }; debug_assert!(array.pointer_is_inbounds()); array @@ -58,9 +62,12 @@ where debug_assert_eq!(strides.ndim(), dim.ndim()); ArrayBase { data: self.data, - ptr: self.ptr, - dim, - strides, + aref: RefBase { + ptr: self.aref.ptr, + dim, + strides, + phantom: self.aref.phantom, + } } } } diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 4a00ea000..b4332dc05 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -150,7 +150,7 @@ where /// ``` pub fn shape(&self) -> &[usize] { - self.dim.slice() + self.aref.dim.slice() } /// Return the strides of the array as a slice. @@ -667,9 +667,9 @@ where pub fn slice_axis_inplace(&mut self, axis: Axis, indices: Slice) { let offset = - do_slice(&mut self.dim.slice_mut()[axis.index()], &mut self.strides.slice_mut()[axis.index()], indices); + do_slice(&mut self.aref.dim.slice_mut()[axis.index()], &mut self.aref.strides.slice_mut()[axis.index()], indices); unsafe { - self.ptr = self.ptr.offset(offset); + self.aref.ptr = self.aref.ptr.offset(offset); } debug_assert!(self.pointer_is_inbounds()); } @@ -1024,8 +1024,8 @@ where #[track_caller] pub fn collapse_axis(&mut self, axis: Axis, index: usize) { - let offset = dimension::do_collapse_axis(&mut self.dim, &self.strides, axis.index(), index); - self.ptr = unsafe { self.ptr.offset(offset) }; + let offset = dimension::do_collapse_axis(&mut self.aref.dim, &self.aref.strides, axis.index(), index); + self.aref.ptr = unsafe { self.aref.ptr.offset(offset) }; debug_assert!(self.pointer_is_inbounds()); } @@ -1549,7 +1549,7 @@ where /// This is equivalent to `.ensure_unique()` if `S: DataMut`. /// /// This method is mostly only useful with unsafe code. - fn try_ensure_unique(&mut self) + pub(crate) fn try_ensure_unique(&mut self) where S: RawDataMut { debug_assert!(self.pointer_is_inbounds()); @@ -1638,7 +1638,7 @@ where #[inline(always)] pub fn as_ptr(&self) -> *const A { - self.ptr.as_ptr() as *const A + self.aref.ptr.as_ptr() as *const A } /// Return a mutable pointer to the first element in the array. @@ -2169,7 +2169,7 @@ where { // safe because new dims equivalent unsafe { - ArrayBase::from_data_ptr(self.data, self.ptr).with_strides_dim(self.strides.into_dyn(), self.dim.into_dyn()) + ArrayBase::from_data_ptr(self.data, self.aref.ptr).with_strides_dim(self.aref.strides.into_dyn(), self.aref.dim.into_dyn()) } } @@ -2195,9 +2195,9 @@ where unsafe { if D::NDIM == D2::NDIM { // safe because D == D2 - let dim = unlimited_transmute::(self.dim); - let strides = unlimited_transmute::(self.strides); - return Ok(ArrayBase::from_data_ptr(self.data, self.ptr).with_strides_dim(strides, dim)); + let dim = unlimited_transmute::(self.aref.dim); + let strides = unlimited_transmute::(self.aref.strides); + return Ok(ArrayBase::from_data_ptr(self.data, self.aref.ptr).with_strides_dim(strides, dim)); } else if D::NDIM.is_none() || D2::NDIM.is_none() { // one is dynamic dim // safe because dim, strides are equivalent under a different type @@ -2362,8 +2362,8 @@ where #[track_caller] pub fn swap_axes(&mut self, ax: usize, bx: usize) { - self.dim.slice_mut().swap(ax, bx); - self.strides.slice_mut().swap(ax, bx); + self.aref.dim.slice_mut().swap(ax, bx); + self.aref.strides.slice_mut().swap(ax, bx); } /// Permute the axes. @@ -2422,8 +2422,8 @@ where /// while retaining the same data. pub fn reversed_axes(mut self) -> ArrayBase { - self.dim.slice_mut().reverse(); - self.strides.slice_mut().reverse(); + self.aref.dim.slice_mut().reverse(); + self.aref.strides.slice_mut().reverse(); self } @@ -2441,7 +2441,7 @@ where /// Return an iterator over the length and stride of each axis. pub fn axes(&self) -> Axes<'_, D> { - axes_of(&self.dim, &self.strides) + axes_of(&self.aref.dim, &self.aref.strides) } /* @@ -2468,9 +2468,9 @@ where let s = self.strides.axis(axis) as Ixs; let m = self.dim.axis(axis); if m != 0 { - self.ptr = self.ptr.offset(stride_offset(m - 1, s as Ix)); + self.aref.ptr = self.aref.ptr.offset(stride_offset(m - 1, s as Ix)); } - self.strides.set_axis(axis, (-s) as Ix); + self.aref.strides.set_axis(axis, (-s) as Ix); } } @@ -2512,7 +2512,7 @@ where #[track_caller] pub fn merge_axes(&mut self, take: Axis, into: Axis) -> bool { - merge_axes(&mut self.dim, &mut self.strides, take, into) + merge_axes(&mut self.aref.dim, &mut self.aref.strides, take, into) } /// Insert new array axis at `axis` and return the result. @@ -2699,7 +2699,7 @@ where slc.iter().fold(init, f) } else { let mut v = self.view(); - move_min_stride_axis_to_last(&mut v.dim, &mut v.strides); + move_min_stride_axis_to_last(&mut v.aref.dim, &mut v.aref.strides); v.into_elements_base().fold(init, f) } } @@ -2858,7 +2858,7 @@ where Ok(slc) => slc.iter_mut().for_each(f), Err(arr) => { let mut v = arr.view_mut(); - move_min_stride_axis_to_last(&mut v.dim, &mut v.strides); + move_min_stride_axis_to_last(&mut v.aref.dim, &mut v.aref.strides); v.into_elements_base().for_each(f); } } diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs index bb970f876..aac6df367 100644 --- a/src/impl_owned_array.rs +++ b/src/impl_owned_array.rs @@ -532,7 +532,7 @@ where D: Dimension /// let mut a = Array::zeros((0, 4)); /// let ones = ArrayView::from(&[1.; 4]); /// let zeros = ArrayView::from(&[0.; 4]); - /// a.push(Axis(0), ones).unwrap(); + /// a.push(Axis(0), ones.clone()).unwrap(); /// a.push(Axis(0), zeros).unwrap(); /// a.push(Axis(0), ones).unwrap(); /// @@ -588,7 +588,7 @@ where D: Dimension /// let mut a = Array::zeros((0, 4)); /// let ones = ArrayView::from(&[1.; 8]).into_shape_with_order((2, 4)).unwrap(); /// let zeros = ArrayView::from(&[0.; 8]).into_shape_with_order((2, 4)).unwrap(); - /// a.append(Axis(0), ones).unwrap(); + /// a.append(Axis(0), ones.clone()).unwrap(); /// a.append(Axis(0), zeros).unwrap(); /// a.append(Axis(0), ones).unwrap(); /// @@ -746,7 +746,7 @@ where D: Dimension sort_axes_in_default_order_tandem(&mut tail_view, &mut array); debug_assert!(tail_view.is_standard_layout(), "not std layout dim: {:?}, strides: {:?}", - tail_view.shape(), tail_view.strides()); + tail_view.shape(), ArrayBase::strides(&tail_view)); } // Keep track of currently filled length of `self.data` and update it @@ -849,7 +849,7 @@ where D: Dimension 0 }; debug_assert!(data_to_array_offset >= 0); - self.ptr = self + self.aref.ptr = self .data .reserve(len_to_append) .offset(data_to_array_offset); @@ -909,7 +909,7 @@ pub(crate) unsafe fn drop_unreachable_raw( // iter is a raw pointer iterator traversing the array in memory order now with the // sorted axes. - let mut iter = Baseiter::new(self_.ptr, self_.dim, self_.strides); + let mut iter = Baseiter::new(self_.ptr, self_.aref.dim, self_.aref.strides); let mut dropped_elements = 0; let mut last_ptr = data_ptr; @@ -948,7 +948,7 @@ where if a.ndim() <= 1 { return; } - sort_axes1_impl(&mut a.dim, &mut a.strides); + sort_axes1_impl(&mut a.aref.dim, &mut a.aref.strides); } fn sort_axes1_impl(adim: &mut D, astrides: &mut D) @@ -988,7 +988,7 @@ where if a.ndim() <= 1 { return; } - sort_axes2_impl(&mut a.dim, &mut a.strides, &mut b.dim, &mut b.strides); + sort_axes2_impl(&mut a.aref.dim, &mut a.aref.strides, &mut b.aref.dim, &mut b.aref.strides); } fn sort_axes2_impl(adim: &mut D, astrides: &mut D, bdim: &mut D, bstrides: &mut D) diff --git a/src/impl_raw_views.rs b/src/impl_raw_views.rs index 5132b1158..d57bb0721 100644 --- a/src/impl_raw_views.rs +++ b/src/impl_raw_views.rs @@ -101,7 +101,7 @@ where D: Dimension is_aligned(self.ptr.as_ptr()), "The pointer must be aligned." ); - ArrayView::new(self.ptr, self.dim, self.strides) + ArrayView::new(self.ptr, self.aref.dim, self.aref.strides) } /// Split the array view along `axis` and return one array pointer strictly @@ -126,10 +126,10 @@ where D: Dimension dim_left.set_axis(axis, index); let left = unsafe { Self::new_(left_ptr, dim_left, self.strides.clone()) }; - let mut dim_right = self.dim; + let mut dim_right = self.aref.dim; let right_len = dim_right.axis(axis) - index; dim_right.set_axis(axis, right_len); - let right = unsafe { Self::new_(right_ptr, dim_right, self.strides) }; + let right = unsafe { Self::new_(right_ptr, dim_right, self.aref.strides) }; (left, right) } @@ -153,7 +153,7 @@ where D: Dimension "size mismatch in raw view cast" ); let ptr = self.ptr.cast::(); - unsafe { RawArrayView::new(ptr, self.dim, self.strides) } + unsafe { RawArrayView::new(ptr, self.aref.dim, self.aref.strides) } } } @@ -308,7 +308,7 @@ where D: Dimension #[inline] pub(crate) fn into_raw_view(self) -> RawArrayView { - unsafe { RawArrayView::new(self.ptr, self.dim, self.strides) } + unsafe { RawArrayView::new(self.ptr, self.aref.dim, self.aref.strides) } } /// Converts to a read-only view of the array. @@ -326,7 +326,7 @@ where D: Dimension is_aligned(self.ptr.as_ptr()), "The pointer must be aligned." ); - ArrayView::new(self.ptr, self.dim, self.strides) + ArrayView::new(self.ptr, self.aref.dim, self.aref.strides) } /// Converts to a mutable view of the array. @@ -344,7 +344,7 @@ where D: Dimension is_aligned(self.ptr.as_ptr()), "The pointer must be aligned." ); - ArrayViewMut::new(self.ptr, self.dim, self.strides) + ArrayViewMut::new(self.ptr, self.aref.dim, self.aref.strides) } /// Split the array view along `axis` and return one array pointer strictly @@ -356,7 +356,7 @@ where D: Dimension pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self) { let (left, right) = self.into_raw_view().split_at(axis, index); - unsafe { (Self::new(left.ptr, left.dim, left.strides), Self::new(right.ptr, right.dim, right.strides)) } + unsafe { (Self::new(left.ptr, left.aref.dim, left.aref.strides), Self::new(right.ptr, right.aref.dim, right.aref.strides)) } } /// Cast the raw pointer of the raw array view to a different type @@ -378,7 +378,7 @@ where D: Dimension "size mismatch in raw view cast" ); let ptr = self.ptr.cast::(); - unsafe { RawArrayViewMut::new(ptr, self.dim, self.strides) } + unsafe { RawArrayViewMut::new(ptr, self.aref.dim, self.aref.strides) } } } @@ -392,8 +392,8 @@ where D: Dimension let Complex { re, im } = self.into_raw_view().split_complex(); unsafe { Complex { - re: RawArrayViewMut::new(re.ptr, re.dim, re.strides), - im: RawArrayViewMut::new(im.ptr, im.dim, im.strides), + re: RawArrayViewMut::new(re.ptr, re.aref.dim, re.aref.strides), + im: RawArrayViewMut::new(im.ptr, im.aref.dim, im.aref.strides), } } } diff --git a/src/impl_special_element_types.rs b/src/impl_special_element_types.rs index e430b20bc..4470ffea3 100644 --- a/src/impl_special_element_types.rs +++ b/src/impl_special_element_types.rs @@ -35,9 +35,12 @@ where { let ArrayBase { data, - ptr, - dim, - strides, + aref: RefBase { + ptr, + dim, + strides, + phantom: _, + } } = self; // "transmute" from storage of MaybeUninit to storage of A diff --git a/src/impl_views/constructors.rs b/src/impl_views/constructors.rs index 15f2b9b6b..ad70e571d 100644 --- a/src/impl_views/constructors.rs +++ b/src/impl_views/constructors.rs @@ -225,7 +225,7 @@ where D: Dimension pub fn reborrow<'b>(self) -> ArrayViewMut<'b, A, D> where 'a: 'b { - unsafe { ArrayViewMut::new(self.ptr, self.dim, self.strides) } + unsafe { ArrayViewMut::new(self.ptr, self.aref.dim, self.aref.strides) } } } diff --git a/src/impl_views/conversions.rs b/src/impl_views/conversions.rs index 1dd7d97f2..f2b63d8eb 100644 --- a/src/impl_views/conversions.rs +++ b/src/impl_views/conversions.rs @@ -29,7 +29,7 @@ where D: Dimension pub fn reborrow<'b>(self) -> ArrayView<'b, A, D> where 'a: 'b { - unsafe { ArrayView::new(self.ptr, self.dim, self.strides) } + unsafe { ArrayView::new(self.ptr, self.aref.dim, self.aref.strides) } } /// Return the array’s data as a slice, if it is contiguous and in standard order. @@ -66,7 +66,7 @@ where D: Dimension #[inline] pub(crate) fn into_raw_view(self) -> RawArrayView { - unsafe { RawArrayView::new(self.ptr, self.dim, self.strides) } + unsafe { RawArrayView::new(self.ptr, self.aref.dim, self.aref.strides) } } } @@ -199,7 +199,7 @@ where D: Dimension #[inline] pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } + unsafe { Baseiter::new(self.ptr, self.aref.dim, self.aref.strides) } } } @@ -209,7 +209,7 @@ where D: Dimension #[inline] pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } + unsafe { Baseiter::new(self.ptr, self.aref.dim, self.aref.strides) } } } @@ -220,7 +220,7 @@ where D: Dimension #[inline] pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } + unsafe { Baseiter::new(self.ptr, self.aref.dim, self.aref.strides) } } #[inline] @@ -250,19 +250,19 @@ where D: Dimension // Convert into a read-only view pub(crate) fn into_view(self) -> ArrayView<'a, A, D> { - unsafe { ArrayView::new(self.ptr, self.dim, self.strides) } + unsafe { ArrayView::new(self.ptr, self.aref.dim, self.aref.strides) } } /// Converts to a mutable raw array view. pub(crate) fn into_raw_view_mut(self) -> RawArrayViewMut { - unsafe { RawArrayViewMut::new(self.ptr, self.dim, self.strides) } + unsafe { RawArrayViewMut::new(self.ptr, self.aref.dim, self.aref.strides) } } #[inline] pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } + unsafe { Baseiter::new(self.ptr, self.aref.dim, self.aref.strides) } } #[inline] diff --git a/src/iterators/chunks.rs b/src/iterators/chunks.rs index 9e2f08e1e..5c624fdd0 100644 --- a/src/iterators/chunks.rs +++ b/src/iterators/chunks.rs @@ -59,10 +59,10 @@ impl<'a, A, D: Dimension> ExactChunks<'a, A, D> a.shape() ); for i in 0..a.ndim() { - a.dim[i] /= chunk[i]; + a.aref.dim[i] /= chunk[i]; } let inner_strides = a.strides.clone(); - a.strides *= &chunk; + a.aref.strides *= &chunk; ExactChunks { base: a, diff --git a/src/iterators/into_iter.rs b/src/iterators/into_iter.rs index 9374608cb..3136e27fc 100644 --- a/src/iterators/into_iter.rs +++ b/src/iterators/into_iter.rs @@ -39,9 +39,9 @@ where D: Dimension let array_head_ptr = array.ptr; let mut array_data = array.data; let data_len = array_data.release_all_elements(); - debug_assert!(data_len >= array.dim.size()); - let has_unreachable_elements = array.dim.size() != data_len; - let inner = Baseiter::new(array_head_ptr, array.dim, array.strides); + debug_assert!(data_len >= array.aref.dim.size()); + let has_unreachable_elements = array.aref.dim.size() != data_len; + let inner = Baseiter::new(array_head_ptr, array.aref.dim, array.aref.strides); IntoIter { array_data, diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index e7321d15b..360b51316 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -1372,7 +1372,7 @@ fn chunk_iter_parts(v: ArrayView<'_, A, D>, axis: Axis, size: u let mut inner_dim = v.dim.clone(); inner_dim[axis] = size; - let mut partial_chunk_dim = v.dim; + let mut partial_chunk_dim = v.aref.dim; partial_chunk_dim[axis] = chunk_remainder; let partial_chunk_index = n_whole_chunks; @@ -1381,8 +1381,8 @@ fn chunk_iter_parts(v: ArrayView<'_, A, D>, axis: Axis, size: u end: iter_len, stride, inner_dim, - inner_strides: v.strides, - ptr: v.ptr.as_ptr(), + inner_strides: v.aref.strides, + ptr: v.aref.ptr.as_ptr(), }; (iter, partial_chunk_index, partial_chunk_dim) diff --git a/src/lib.rs b/src/lib.rs index f52f25e5e..1203f76bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -126,6 +126,7 @@ pub mod doc; #[cfg(target_has_atomic = "ptr")] use alloc::sync::Arc; +use arrayref::{Raw, RawReferent, Safe}; #[cfg(not(target_has_atomic = "ptr"))] use portable_atomic_util::Arc; @@ -160,6 +161,7 @@ pub use crate::shape_builder::{Shape, ShapeArg, ShapeBuilder, StrideShape}; mod macro_utils; #[macro_use] mod private; +mod arrayref; mod aliases; #[macro_use] mod itertools; @@ -216,6 +218,7 @@ pub use crate::layout::Layout; mod imp_prelude { pub use crate::dimension::DimensionExt; + pub use crate::RefBase; pub use crate::prelude::*; pub use crate::ArcArray; pub use crate::{ @@ -1283,15 +1286,28 @@ where S: RawData /// Data buffer / ownership information. (If owned, contains the data /// buffer; if borrowed, contains the lifetime and mutability.) data: S, + /// Array reference type + aref: RefBase, +} + +/// An array reference type +pub struct RefBase +where R: RawReferent +{ /// A non-null pointer into the buffer held by `data`; may point anywhere /// in its range. If `S: Data`, this pointer must be aligned. - ptr: std::ptr::NonNull, + ptr: std::ptr::NonNull, /// The lengths of the axes. dim: D, /// The element count stride per axis. To be parsed as `isize`. strides: D, + /// The referent safety marker + phantom: PhantomData, } +pub type RawRef = RefBase; +pub type ArrRef = RefBase; + /// An array where the data has shared ownership and is copy on write. /// /// The `ArcArray` is parameterized by `A` for the element type and `D` for diff --git a/src/zip/mod.rs b/src/zip/mod.rs index b58752f66..94c6ed92b 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -97,7 +97,7 @@ where { #[allow(clippy::needless_borrow)] let res: ArrayView<'_, A, E::Dim> = (&self).broadcast_unwrap(shape.into_dimension()); - unsafe { ArrayView::new(res.ptr, res.dim, res.strides) } + unsafe { ArrayView::new(res.ptr, res.aref.dim, res.aref.strides) } } private_impl! {} } diff --git a/tests/append.rs b/tests/append.rs index cf5397de1..fc28d6ff2 100644 --- a/tests/append.rs +++ b/tests/append.rs @@ -298,9 +298,9 @@ fn test_append_2d() let zeros = ArrayView::from(&[0.; 8]) .into_shape_with_order((2, 4)) .unwrap(); - a.append(Axis(0), ones).unwrap(); - a.append(Axis(0), zeros).unwrap(); - a.append(Axis(0), ones).unwrap(); + a.append(Axis(0), ones.clone()).unwrap(); + a.append(Axis(0), zeros.clone()).unwrap(); + a.append(Axis(0), ones.clone()).unwrap(); println!("{:?}", a); assert_eq!(a.shape(), &[8, 4]); for (i, row) in a.rows().into_iter().enumerate() { @@ -312,7 +312,7 @@ fn test_append_2d() a = a.reversed_axes(); let ones = ones.reversed_axes(); let zeros = zeros.reversed_axes(); - a.append(Axis(1), ones).unwrap(); + a.append(Axis(1), ones.clone()).unwrap(); a.append(Axis(1), zeros).unwrap(); a.append(Axis(1), ones).unwrap(); println!("{:?}", a); @@ -447,7 +447,7 @@ fn zero_dimensional_ok() let one = aview0(&1); let two = aview0(&2); a.push(Axis(0), two).unwrap(); - a.push(Axis(0), one).unwrap(); + a.push(Axis(0), one.clone()).unwrap(); a.push(Axis(0), one).unwrap(); assert_eq!(a, array![2, 1, 1]); } diff --git a/tests/array.rs b/tests/array.rs index 696904dab..10dfb8c20 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -1446,7 +1446,7 @@ fn views() assert_eq!(a, b); assert_eq!(a.shape(), b.shape()); assert_eq!(a.clone() + a.clone(), &b + &b); - assert_eq!(a.clone() + b, &b + &b); + assert_eq!(a.clone() + b.clone(), &b + &b); a.clone()[(0, 0)] = 99; assert_eq!(b[(0, 0)], 1); @@ -1773,7 +1773,7 @@ fn arithmetic_broadcast() arr3(&[[[11, 15], [20, 24]], [[10, 14], [19, 23]]]) ); assert_eq!( - &a + b.into_owned() + c, + &a + b.clone().into_owned() + c.clone(), arr3(&[[[15, 19], [32, 36]], [[14, 18], [31, 35]]]) ); @@ -2154,7 +2154,7 @@ fn test_contiguous_neg_strides() assert_eq!(b, arr3(&[[[11, 7, 3], [9, 5, 1]], [[10, 6, 2], [8, 4, 0]]])); assert!(b.as_slice_memory_order().is_some()); - let mut c = b.reversed_axes(); + let mut c = b.clone().reversed_axes(); assert_eq!( c, arr3(&[[[11, 10], [9, 8]], [[7, 6], [5, 4]], [[3, 2], [1, 0]]]) @@ -2165,11 +2165,11 @@ fn test_contiguous_neg_strides() assert_eq!(c, arr3(&[[[11, 10, 9, 8]], [[7, 6, 5, 4]], [[3, 2, 1, 0]]])); assert!(c.as_slice_memory_order().is_some()); - let d = b.remove_axis(Axis(1)); + let d = b.clone().remove_axis(Axis(1)); assert_eq!(d, arr2(&[[11, 7, 3], [10, 6, 2]])); assert!(d.as_slice_memory_order().is_none()); - let e = b.remove_axis(Axis(2)); + let e = b.clone().remove_axis(Axis(2)); assert_eq!(e, arr2(&[[11, 9], [10, 8]])); assert!(e.as_slice_memory_order().is_some()); diff --git a/tests/reshape.rs b/tests/reshape.rs index a13a5c05f..ac59b8773 100644 --- a/tests/reshape.rs +++ b/tests/reshape.rs @@ -9,7 +9,7 @@ fn reshape() { let data = [1, 2, 3, 4, 5, 6, 7, 8]; let v = aview1(&data); - let u = v.into_shape_with_order((3, 3)); + let u = v.clone().into_shape_with_order((3, 3)); assert!(u.is_err()); let u = v.into_shape_with_order((2, 2, 2)); assert!(u.is_ok()); @@ -51,7 +51,7 @@ fn reshape_f() println!("{:?}", v); // noop ok - let v2 = v.into_shape_with_order(((3, 4), Order::F)); + let v2 = v.clone().into_shape_with_order(((3, 4), Order::F)); assert!(v2.is_ok()); assert_eq!(v, v2.unwrap()); @@ -247,7 +247,7 @@ fn into_shape_with_order() // 1D -> C -> C let data = [1, 2, 3, 4, 5, 6, 7, 8]; let v = aview1(&data); - let u = v.into_shape_with_order(((3, 3), Order::RowMajor)); + let u = v.clone().into_shape_with_order(((3, 3), Order::RowMajor)); assert!(u.is_err()); let u = v.into_shape_with_order(((2, 2, 2), Order::C)); @@ -264,7 +264,7 @@ fn into_shape_with_order() // 1D -> F -> F let data = [1, 2, 3, 4, 5, 6, 7, 8]; let v = aview1(&data); - let u = v.into_shape_with_order(((3, 3), Order::ColumnMajor)); + let u = v.clone().into_shape_with_order(((3, 3), Order::ColumnMajor)); assert!(u.is_err()); let u = v.into_shape_with_order(((2, 2, 2), Order::ColumnMajor)); diff --git a/tests/views.rs b/tests/views.rs index 02970b1b7..587a1da33 100644 --- a/tests/views.rs +++ b/tests/views.rs @@ -9,7 +9,7 @@ fn cell_view() { let cv1 = a.cell_view(); - let cv2 = cv1; + let cv2 = cv1.clone(); Zip::from(cv1).and(cv2).for_each(|a, b| a.set(b.get() + 1.)); } From 44079ccb82c3f5e7234f8164c7c1767ac3e966c0 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Thu, 3 Oct 2024 21:17:10 -0400 Subject: [PATCH 02/33] Adds some documentation --- src/arrayref.rs | 19 +++++++++++++++++-- src/lib.rs | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/arrayref.rs b/src/arrayref.rs index f28d21c03..a2b4036f6 100644 --- a/src/arrayref.rs +++ b/src/arrayref.rs @@ -5,15 +5,27 @@ use core::ops::{Deref, DerefMut}; use crate::{ArrayBase, Dimension, RawData, RawDataMut, RefBase}; /// Unit struct to mark a reference as raw +/// +/// Only visible because it is necessary for [`crate::RawRef`] #[derive(Copy, Clone)] pub struct Raw; + /// Unit struct to mark a reference as safe +/// +/// Only visible because it is necessary for [`crate::ArrRef`] #[derive(Copy, Clone)] pub struct Safe; +/// A trait for array references that adhere to the basic constraints of `ndarray`. +/// +/// Cannot be implemented outside of `ndarray`. pub trait RawReferent { private_decl! {} } + +/// A trait for array references that point to data that is safe to read. +/// +/// Cannot be implemented outside of `ndarray`. pub trait Referent { private_decl! {} } @@ -29,7 +41,8 @@ impl Referent for Safe { } impl Deref for ArrayBase -where S: RawData +where + S: RawData, { type Target = RefBase; @@ -39,7 +52,9 @@ where S: RawData } impl DerefMut for ArrayBase -where S: RawDataMut, D: Dimension, +where + S: RawDataMut, + D: Dimension, { fn deref_mut(&mut self) -> &mut Self::Target { self.try_ensure_unique(); diff --git a/src/lib.rs b/src/lib.rs index 1203f76bb..64744e72e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1275,6 +1275,9 @@ pub type Ixs = isize; // implementation since `ArrayBase` doesn't implement `Drop` and `&mut // ArrayBase` is `!UnwindSafe`, but the implementation must not call // methods/functions on the array while it violates the constraints. +// Critically, this includes calling `DerefMut`; as a result, methods/functions +// that temporarily violate these must not rely on the `DerefMut` implementation +// for access to the underlying `ptr`, `strides`, or `dim`. // // Users of the `ndarray` crate cannot rely on these constraints because they // may change in the future. @@ -1290,7 +1293,44 @@ where S: RawData aref: RefBase, } -/// An array reference type +/// A reference to an *n*-dimensional array. +/// +/// `RefBase`'s relationship to [`ArrayBase`] is akin to the relationship +/// between `[T]` and `Vec`: it can only be obtained by reference, and +/// represents a subset of an existing array (possibly the entire array). +/// +/// There are two variants of this type, [`RawRef`] and [`ArrRef`]; raw +/// references are obtained from raw views, and `ArrRef`s are obtained +/// from all other array types. See those types for more information. +/// +/// ## Writing Functions +/// Generally speaking, functions that operate on arrays should accept +/// this type over an `ArrayBase`. The following conventions must be +/// followed: +/// - Functions that need to safely read an array's data should accept +/// `&ArrRef` +/// ```rust +/// fn read(arr: &ArrRef) +/// ``` +/// - Functions that need to safely write to an array's data should +/// accept `&mut ArrRef` +/// ```rust +/// fn write(arr: &mut ArrRef) +/// ``` +/// - Functions that only need to read an array's shape and strides +/// (or that want to unsafely read data) should accept `&RefBase` +/// with a bound of [`RawReferent`]: +/// ```rust +/// fn read_layout(arr: &RefBase) {} +/// unsafe fn read_unchecked(arr: &RefBase) {} +/// ``` +/// - Functions that want to write to an array's shape and strides +/// (or that want to unsafely write to its data) should accept +/// `&mut RefBase` with the same bound: +/// ```rust +/// fn write_layout(arr: &mut RefBase) {} +/// unsafe fn write_unchecked(arr: &mut RefBase) {} +/// ``` pub struct RefBase where R: RawReferent { @@ -1305,7 +1345,10 @@ where R: RawReferent phantom: PhantomData, } +/// An reference to an array whose data may be unaligned or unsafe to read. pub type RawRef = RefBase; + +/// A reference to an array whose data can be read safely. pub type ArrRef = RefBase; /// An array where the data has shared ownership and is copy on write. From 3d32c0802ec877240ef41b08446d284350a5dad4 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sat, 5 Oct 2024 16:27:48 -0400 Subject: [PATCH 03/33] Fixes some CI/CD issues --- src/arrayref.rs | 24 +++++++++------ src/data_traits.rs | 18 ++++++++++-- src/free_functions.rs | 8 ++--- src/impl_clone.rs | 4 +-- src/impl_cow.rs | 8 +++-- src/impl_internal_constructors.rs | 4 +-- src/impl_methods.rs | 10 +++++-- src/impl_raw_views.rs | 7 ++++- src/impl_special_element_types.rs | 13 ++++---- src/lib.rs | 49 ++++++++++++++++++------------- tests/reshape.rs | 4 ++- 11 files changed, 97 insertions(+), 52 deletions(-) diff --git a/src/arrayref.rs b/src/arrayref.rs index a2b4036f6..cc2ac839b 100644 --- a/src/arrayref.rs +++ b/src/arrayref.rs @@ -19,34 +19,39 @@ pub struct Safe; /// A trait for array references that adhere to the basic constraints of `ndarray`. /// /// Cannot be implemented outside of `ndarray`. -pub trait RawReferent { +pub trait RawReferent +{ private_decl! {} } /// A trait for array references that point to data that is safe to read. /// /// Cannot be implemented outside of `ndarray`. -pub trait Referent { +pub trait Referent +{ private_decl! {} } -impl RawReferent for Raw { +impl RawReferent for Raw +{ private_impl! {} } -impl RawReferent for Safe { +impl RawReferent for Safe +{ private_impl! {} } -impl Referent for Safe { +impl Referent for Safe +{ private_impl! {} } impl Deref for ArrayBase -where - S: RawData, +where S: RawData { type Target = RefBase; - fn deref(&self) -> &Self::Target { + fn deref(&self) -> &Self::Target + { &self.aref } } @@ -56,7 +61,8 @@ where S: RawDataMut, D: Dimension, { - fn deref_mut(&mut self) -> &mut Self::Target { + fn deref_mut(&mut self) -> &mut Self::Target + { self.try_ensure_unique(); &mut self.aref } diff --git a/src/data_traits.rs b/src/data_traits.rs index 29feef9c2..c879d631c 100644 --- a/src/data_traits.rs +++ b/src/data_traits.rs @@ -23,7 +23,20 @@ use std::mem::MaybeUninit; use std::mem::{self, size_of}; use std::ptr::NonNull; -use crate::{ArcArray, Array, ArrayBase, CowRepr, Dimension, OwnedArcRepr, OwnedRepr, Raw, RawReferent, RawViewRepr, Safe, ViewRepr}; +use crate::{ + ArcArray, + Array, + ArrayBase, + CowRepr, + Dimension, + OwnedArcRepr, + OwnedRepr, + Raw, + RawReferent, + RawViewRepr, + Safe, + ViewRepr, +}; /// Array representation trait. /// @@ -301,7 +314,8 @@ unsafe impl Data for OwnedArcRepr match Arc::try_unwrap(self_.data.0) { Ok(owned_data) => unsafe { // Safe because the data is equivalent. - Ok(ArrayBase::from_data_ptr(owned_data, self_.aref.ptr).with_strides_dim(self_.aref.strides, self_.aref.dim)) + Ok(ArrayBase::from_data_ptr(owned_data, self_.aref.ptr) + .with_strides_dim(self_.aref.strides, self_.aref.dim)) }, Err(arc_data) => unsafe { // Safe because the data is equivalent; we're just diff --git a/src/free_functions.rs b/src/free_functions.rs index 60135f24a..c585312f3 100644 --- a/src/free_functions.rs +++ b/src/free_functions.rs @@ -113,7 +113,7 @@ pub const fn aview0(x: &A) -> ArrayView0<'_, A> dim: Ix0(), strides: Ix0(), phantom: PhantomData::< as RawData>::Referent>, - } + }, } } @@ -154,7 +154,7 @@ pub const fn aview1(xs: &[A]) -> ArrayView1<'_, A> dim: Ix1(xs.len()), strides: Ix1(1), phantom: PhantomData::< as RawData>::Referent>, - } + }, } } @@ -211,8 +211,8 @@ pub const fn aview2(xs: &[[A; N]]) -> ArrayView2<'_, A> ptr, dim, strides, - phantom: PhantomData::< as RawData>::Referent> - } + phantom: PhantomData::< as RawData>::Referent>, + }, } } diff --git a/src/impl_clone.rs b/src/impl_clone.rs index c52e67c4e..1bfb213cb 100644 --- a/src/impl_clone.rs +++ b/src/impl_clone.rs @@ -22,8 +22,8 @@ impl Clone for ArrayBase ptr, dim: self.dim.clone(), strides: self.strides.clone(), - phantom: self.phantom - } + phantom: self.phantom, + }, } } } diff --git a/src/impl_cow.rs b/src/impl_cow.rs index f17586e2a..93a7c157e 100644 --- a/src/impl_cow.rs +++ b/src/impl_cow.rs @@ -33,7 +33,10 @@ where D: Dimension fn from(view: ArrayView<'a, A, D>) -> CowArray<'a, A, D> { // safe because equivalent data - unsafe { ArrayBase::from_data_ptr(CowRepr::View(view.data), view.ptr).with_strides_dim(view.aref.strides, view.aref.dim) } + unsafe { + ArrayBase::from_data_ptr(CowRepr::View(view.data), view.ptr) + .with_strides_dim(view.aref.strides, view.aref.dim) + } } } @@ -44,7 +47,8 @@ where D: Dimension { // safe because equivalent data unsafe { - ArrayBase::from_data_ptr(CowRepr::Owned(array.data), array.aref.ptr).with_strides_dim(array.aref.strides, array.aref.dim) + ArrayBase::from_data_ptr(CowRepr::Owned(array.data), array.aref.ptr) + .with_strides_dim(array.aref.strides, array.aref.dim) } } } diff --git a/src/impl_internal_constructors.rs b/src/impl_internal_constructors.rs index 79a3c9671..08df31aeb 100644 --- a/src/impl_internal_constructors.rs +++ b/src/impl_internal_constructors.rs @@ -33,7 +33,7 @@ where S: RawData dim: Ix1(0), strides: Ix1(1), phantom: PhantomData::, - } + }, }; debug_assert!(array.pointer_is_inbounds()); array @@ -67,7 +67,7 @@ where dim, strides, phantom: self.aref.phantom, - } + }, } } } diff --git a/src/impl_methods.rs b/src/impl_methods.rs index b4332dc05..fb7cc5621 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -666,8 +666,11 @@ where #[track_caller] pub fn slice_axis_inplace(&mut self, axis: Axis, indices: Slice) { - let offset = - do_slice(&mut self.aref.dim.slice_mut()[axis.index()], &mut self.aref.strides.slice_mut()[axis.index()], indices); + let offset = do_slice( + &mut self.aref.dim.slice_mut()[axis.index()], + &mut self.aref.strides.slice_mut()[axis.index()], + indices, + ); unsafe { self.aref.ptr = self.aref.ptr.offset(offset); } @@ -2169,7 +2172,8 @@ where { // safe because new dims equivalent unsafe { - ArrayBase::from_data_ptr(self.data, self.aref.ptr).with_strides_dim(self.aref.strides.into_dyn(), self.aref.dim.into_dyn()) + ArrayBase::from_data_ptr(self.data, self.aref.ptr) + .with_strides_dim(self.aref.strides.into_dyn(), self.aref.dim.into_dyn()) } } diff --git a/src/impl_raw_views.rs b/src/impl_raw_views.rs index d57bb0721..feccd3c99 100644 --- a/src/impl_raw_views.rs +++ b/src/impl_raw_views.rs @@ -356,7 +356,12 @@ where D: Dimension pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self) { let (left, right) = self.into_raw_view().split_at(axis, index); - unsafe { (Self::new(left.ptr, left.aref.dim, left.aref.strides), Self::new(right.ptr, right.aref.dim, right.aref.strides)) } + unsafe { + ( + Self::new(left.ptr, left.aref.dim, left.aref.strides), + Self::new(right.ptr, right.aref.dim, right.aref.strides), + ) + } } /// Cast the raw pointer of the raw array view to a different type diff --git a/src/impl_special_element_types.rs b/src/impl_special_element_types.rs index 4470ffea3..6433f129d 100644 --- a/src/impl_special_element_types.rs +++ b/src/impl_special_element_types.rs @@ -35,12 +35,13 @@ where { let ArrayBase { data, - aref: RefBase { - ptr, - dim, - strides, - phantom: _, - } + aref: + RefBase { + ptr, + dim, + strides, + phantom: _, + }, } = self; // "transmute" from storage of MaybeUninit to storage of A diff --git a/src/lib.rs b/src/lib.rs index 64744e72e..6802ffce8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -126,7 +126,8 @@ pub mod doc; #[cfg(target_has_atomic = "ptr")] use alloc::sync::Arc; -use arrayref::{Raw, RawReferent, Safe}; +use arrayref::{Raw, Safe}; +pub use arrayref::RawReferent; #[cfg(not(target_has_atomic = "ptr"))] use portable_atomic_util::Arc; @@ -218,9 +219,9 @@ pub use crate::layout::Layout; mod imp_prelude { pub use crate::dimension::DimensionExt; - pub use crate::RefBase; pub use crate::prelude::*; pub use crate::ArcArray; + pub use crate::RefBase; pub use crate::{ CowRepr, Data, @@ -1294,41 +1295,53 @@ where S: RawData } /// A reference to an *n*-dimensional array. -/// +/// /// `RefBase`'s relationship to [`ArrayBase`] is akin to the relationship /// between `[T]` and `Vec`: it can only be obtained by reference, and /// represents a subset of an existing array (possibly the entire array). -/// +/// /// There are two variants of this type, [`RawRef`] and [`ArrRef`]; raw /// references are obtained from raw views, and `ArrRef`s are obtained /// from all other array types. See those types for more information. -/// +/// /// ## Writing Functions /// Generally speaking, functions that operate on arrays should accept /// this type over an `ArrayBase`. The following conventions must be /// followed: -/// - Functions that need to safely read an array's data should accept -/// `&ArrRef` +/// - Functions that need to safely read an array's data should accept `&ArrRef` /// ```rust -/// fn read(arr: &ArrRef) +/// use ndarray::ArrRef; +/// +/// #[allow(dead_code)] +/// fn read(arr: &ArrRef) {} /// ``` -/// - Functions that need to safely write to an array's data should -/// accept `&mut ArrRef` +/// - Functions that need to safely write to an array's data should accept `&mut ArrRef` /// ```rust -/// fn write(arr: &mut ArrRef) +/// use ndarray::ArrRef; +/// +/// #[allow(dead_code)] +/// fn write(arr: &mut ArrRef) {} /// ``` /// - Functions that only need to read an array's shape and strides -/// (or that want to unsafely read data) should accept `&RefBase` -/// with a bound of [`RawReferent`]: +/// (or that want to unsafely read data) should accept `&RefBase` +/// with a bound of [`RawReferent`]: /// ```rust +/// use ndarray::{RefBase, RawReferent}; +/// +/// #[allow(dead_code)] /// fn read_layout(arr: &RefBase) {} +/// #[allow(dead_code)] /// unsafe fn read_unchecked(arr: &RefBase) {} /// ``` /// - Functions that want to write to an array's shape and strides -/// (or that want to unsafely write to its data) should accept -/// `&mut RefBase` with the same bound: +/// (or that want to unsafely write to its data) should accept +/// `&mut RefBase` with the same bound: /// ```rust +/// use ndarray::{RefBase, RawReferent}; +/// +/// #[allow(dead_code)] /// fn write_layout(arr: &mut RefBase) {} +/// #[allow(dead_code)] /// unsafe fn write_unchecked(arr: &mut RefBase) {} /// ``` pub struct RefBase @@ -1607,11 +1620,7 @@ where D: Dimension, E: Dimension, { - panic!( - "ndarray: could not broadcast array from shape: {:?} to: {:?}", - from.slice(), - to.slice() - ) + panic!("ndarray: could not broadcast array from shape: {:?} to: {:?}", from.slice(), to.slice()) } match self.broadcast(dim.clone()) { diff --git a/tests/reshape.rs b/tests/reshape.rs index ac59b8773..f39e15580 100644 --- a/tests/reshape.rs +++ b/tests/reshape.rs @@ -264,7 +264,9 @@ fn into_shape_with_order() // 1D -> F -> F let data = [1, 2, 3, 4, 5, 6, 7, 8]; let v = aview1(&data); - let u = v.clone().into_shape_with_order(((3, 3), Order::ColumnMajor)); + let u = v + .clone() + .into_shape_with_order(((3, 3), Order::ColumnMajor)); assert!(u.is_err()); let u = v.into_shape_with_order(((2, 2, 2), Order::ColumnMajor)); From 8bf86df006399d873d74c7bbcb51f6795f5163ec Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sat, 5 Oct 2024 17:13:47 -0400 Subject: [PATCH 04/33] More CI/CD fixes --- benches/bench1.rs | 16 ++++++++-------- src/lib.rs | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/benches/bench1.rs b/benches/bench1.rs index 33185844a..4c216e5c8 100644 --- a/benches/bench1.rs +++ b/benches/bench1.rs @@ -776,7 +776,7 @@ fn bench_row_iter(bench: &mut test::Bencher) let a = Array::::zeros((1024, 1024)); let it = a.row(17); bench.iter(|| { - for elt in it { + for elt in it.clone() { black_box(elt); } }) @@ -788,7 +788,7 @@ fn bench_col_iter(bench: &mut test::Bencher) let a = Array::::zeros((1024, 1024)); let it = a.column(17); bench.iter(|| { - for elt in it { + for elt in it.clone() { black_box(elt); } }) @@ -861,7 +861,7 @@ fn create_iter_4d(bench: &mut test::Bencher) a.swap_axes(2, 1); let v = black_box(a.view()); - bench.iter(|| v.into_iter()); + bench.iter(|| v.clone().into_iter()); } #[bench] @@ -1023,7 +1023,7 @@ fn into_dimensionality_ix1_ok(bench: &mut test::Bencher) { let a = Array::::zeros(Ix1(10)); let a = a.view(); - bench.iter(|| a.into_dimensionality::()); + bench.iter(|| a.clone().into_dimensionality::()); } #[bench] @@ -1031,7 +1031,7 @@ fn into_dimensionality_ix3_ok(bench: &mut test::Bencher) { let a = Array::::zeros(Ix3(10, 10, 10)); let a = a.view(); - bench.iter(|| a.into_dimensionality::()); + bench.iter(|| a.clone().into_dimensionality::()); } #[bench] @@ -1039,7 +1039,7 @@ fn into_dimensionality_ix3_err(bench: &mut test::Bencher) { let a = Array::::zeros(Ix3(10, 10, 10)); let a = a.view(); - bench.iter(|| a.into_dimensionality::()); + bench.iter(|| a.clone().into_dimensionality::()); } #[bench] @@ -1063,7 +1063,7 @@ fn into_dyn_ix3(bench: &mut test::Bencher) { let a = Array::::zeros(Ix3(10, 10, 10)); let a = a.view(); - bench.iter(|| a.into_dyn()); + bench.iter(|| a.clone().into_dyn()); } #[bench] @@ -1071,7 +1071,7 @@ fn into_dyn_ix5(bench: &mut test::Bencher) { let a = Array::::zeros(Ix5(2, 2, 2, 2, 2)); let a = a.view(); - bench.iter(|| a.into_dyn()); + bench.iter(|| a.clone().into_dyn()); } #[bench] diff --git a/src/lib.rs b/src/lib.rs index 6802ffce8..db7495965 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1311,14 +1311,14 @@ where S: RawData /// - Functions that need to safely read an array's data should accept `&ArrRef` /// ```rust /// use ndarray::ArrRef; -/// +/// /// #[allow(dead_code)] /// fn read(arr: &ArrRef) {} /// ``` /// - Functions that need to safely write to an array's data should accept `&mut ArrRef` /// ```rust /// use ndarray::ArrRef; -/// +/// /// #[allow(dead_code)] /// fn write(arr: &mut ArrRef) {} /// ``` @@ -1327,7 +1327,7 @@ where S: RawData /// with a bound of [`RawReferent`]: /// ```rust /// use ndarray::{RefBase, RawReferent}; -/// +/// /// #[allow(dead_code)] /// fn read_layout(arr: &RefBase) {} /// #[allow(dead_code)] @@ -1338,7 +1338,7 @@ where S: RawData /// `&mut RefBase` with the same bound: /// ```rust /// use ndarray::{RefBase, RawReferent}; -/// +/// /// #[allow(dead_code)] /// fn write_layout(arr: &mut RefBase) {} /// #[allow(dead_code)] From dda4b662b19ddaa3cfbfe6cd9a04e788e1bcf609 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sat, 5 Oct 2024 17:18:35 -0400 Subject: [PATCH 05/33] Last CI/CD fix? --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index db7495965..a90036bd3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -126,8 +126,8 @@ pub mod doc; #[cfg(target_has_atomic = "ptr")] use alloc::sync::Arc; -use arrayref::{Raw, Safe}; pub use arrayref::RawReferent; +use arrayref::{Raw, Safe}; #[cfg(not(target_has_atomic = "ptr"))] use portable_atomic_util::Arc; From 3c75150a8ff971293555614c0a9e677411109712 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 6 Oct 2024 17:06:01 -0400 Subject: [PATCH 06/33] Switches to the "same-repr" approach to allow array views to still be Copy --- src/arrayref.rs | 22 ++++++++++++++++++++-- src/impl_clone.rs | 2 +- src/lib.rs | 11 +++++++++-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/arrayref.rs b/src/arrayref.rs index cc2ac839b..a55f536ac 100644 --- a/src/arrayref.rs +++ b/src/arrayref.rs @@ -52,7 +52,16 @@ where S: RawData fn deref(&self) -> &Self::Target { - &self.aref + // SAFETY: The pointer will hold all the guarantees of `as_ref`: + // - The pointer is aligned because neither type use repr(align) + // - It is "dereferencable" because it just points to self + // - For the same reason, it is initialized + unsafe { + (self as *const Self) + .cast::>() + .as_ref() + } + .expect("Pointer to self will always be non-null") } } @@ -64,6 +73,15 @@ where fn deref_mut(&mut self) -> &mut Self::Target { self.try_ensure_unique(); - &mut self.aref + // SAFETY: The pointer will hold all the guarantees of `as_ref`: + // - The pointer is aligned because neither type use repr(align) + // - It is "dereferencable" because it just points to self + // - For the same reason, it is initialized + unsafe { + (self as *mut Self) + .cast::>() + .as_mut() + } + .expect("Pointer to self will always be non-null") } } diff --git a/src/impl_clone.rs b/src/impl_clone.rs index 1bfb213cb..fabcaf362 100644 --- a/src/impl_clone.rs +++ b/src/impl_clone.rs @@ -41,4 +41,4 @@ impl Clone for ArrayBase } } -// impl Copy for ArrayBase {} +impl Copy for ArrayBase {} diff --git a/src/lib.rs b/src/lib.rs index a90036bd3..de4adf9ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1284,14 +1284,20 @@ pub type Ixs = isize; // may change in the future. // // [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset-1 +#[repr(C)] pub struct ArrayBase where S: RawData { + /// A non-null pointer into the buffer held by `data`; may point anywhere + /// in its range. If `S: Data`, this pointer must be aligned. + ptr: std::ptr::NonNull, + /// The lengths of the axes. + dim: D, + /// The element count stride per axis. To be parsed as `isize`. + strides: D, /// Data buffer / ownership information. (If owned, contains the data /// buffer; if borrowed, contains the lifetime and mutability.) data: S, - /// Array reference type - aref: RefBase, } /// A reference to an *n*-dimensional array. @@ -1344,6 +1350,7 @@ where S: RawData /// #[allow(dead_code)] /// unsafe fn write_unchecked(arr: &mut RefBase) {} /// ``` +#[repr(C)] pub struct RefBase where R: RawReferent { From 28fea667ee01a6af92535410283f320238fee5fe Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 6 Oct 2024 17:22:44 -0400 Subject: [PATCH 07/33] Changes back to Copy-capable ArrayBase and unchanged ArrayBase internals --- benches/bench1.rs | 16 +++++------ src/arraytraits.rs | 2 +- src/data_traits.rs | 23 ++++++++-------- src/free_functions.rs | 32 ++++++++------------- src/impl_clone.rs | 15 ++++------ src/impl_cow.rs | 8 ++---- src/impl_dyn.rs | 8 +++--- src/impl_internal_constructors.rs | 19 ++++--------- src/impl_methods.rs | 46 ++++++++++++++----------------- src/impl_owned_array.rs | 12 ++++---- src/impl_raw_views.rs | 27 ++++++++---------- src/impl_special_element_types.rs | 10 ++----- src/impl_views/constructors.rs | 2 +- src/impl_views/conversions.rs | 16 +++++------ src/iterators/chunks.rs | 4 +-- src/iterators/into_iter.rs | 6 ++-- src/iterators/mod.rs | 6 ++-- src/lib.rs | 2 +- src/zip/mod.rs | 2 +- tests/append.rs | 10 +++---- tests/array.rs | 10 +++---- tests/reshape.rs | 10 +++---- tests/views.rs | 2 +- 23 files changed, 124 insertions(+), 164 deletions(-) diff --git a/benches/bench1.rs b/benches/bench1.rs index 4c216e5c8..33185844a 100644 --- a/benches/bench1.rs +++ b/benches/bench1.rs @@ -776,7 +776,7 @@ fn bench_row_iter(bench: &mut test::Bencher) let a = Array::::zeros((1024, 1024)); let it = a.row(17); bench.iter(|| { - for elt in it.clone() { + for elt in it { black_box(elt); } }) @@ -788,7 +788,7 @@ fn bench_col_iter(bench: &mut test::Bencher) let a = Array::::zeros((1024, 1024)); let it = a.column(17); bench.iter(|| { - for elt in it.clone() { + for elt in it { black_box(elt); } }) @@ -861,7 +861,7 @@ fn create_iter_4d(bench: &mut test::Bencher) a.swap_axes(2, 1); let v = black_box(a.view()); - bench.iter(|| v.clone().into_iter()); + bench.iter(|| v.into_iter()); } #[bench] @@ -1023,7 +1023,7 @@ fn into_dimensionality_ix1_ok(bench: &mut test::Bencher) { let a = Array::::zeros(Ix1(10)); let a = a.view(); - bench.iter(|| a.clone().into_dimensionality::()); + bench.iter(|| a.into_dimensionality::()); } #[bench] @@ -1031,7 +1031,7 @@ fn into_dimensionality_ix3_ok(bench: &mut test::Bencher) { let a = Array::::zeros(Ix3(10, 10, 10)); let a = a.view(); - bench.iter(|| a.clone().into_dimensionality::()); + bench.iter(|| a.into_dimensionality::()); } #[bench] @@ -1039,7 +1039,7 @@ fn into_dimensionality_ix3_err(bench: &mut test::Bencher) { let a = Array::::zeros(Ix3(10, 10, 10)); let a = a.view(); - bench.iter(|| a.clone().into_dimensionality::()); + bench.iter(|| a.into_dimensionality::()); } #[bench] @@ -1063,7 +1063,7 @@ fn into_dyn_ix3(bench: &mut test::Bencher) { let a = Array::::zeros(Ix3(10, 10, 10)); let a = a.view(); - bench.iter(|| a.clone().into_dyn()); + bench.iter(|| a.into_dyn()); } #[bench] @@ -1071,7 +1071,7 @@ fn into_dyn_ix5(bench: &mut test::Bencher) { let a = Array::::zeros(Ix5(2, 2, 2, 2, 2)); let a = a.view(); - bench.iter(|| a.clone().into_dyn()); + bench.iter(|| a.into_dyn()); } #[bench] diff --git a/src/arraytraits.rs b/src/arraytraits.rs index 1055943e0..e68b5d56a 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -463,7 +463,7 @@ where D: Dimension { let data = OwnedArcRepr(Arc::new(arr.data)); // safe because: equivalent unmoved data, ptr and dims remain valid - unsafe { ArrayBase::from_data_ptr(data, arr.aref.ptr).with_strides_dim(arr.aref.strides, arr.aref.dim) } + unsafe { ArrayBase::from_data_ptr(data, arr.ptr).with_strides_dim(arr.strides, arr.dim) } } } diff --git a/src/data_traits.rs b/src/data_traits.rs index c879d631c..d846f010c 100644 --- a/src/data_traits.rs +++ b/src/data_traits.rs @@ -279,13 +279,13 @@ where A: Clone let rcvec = &mut self_.data.0; let a_size = mem::size_of::() as isize; let our_off = if a_size != 0 { - (self_.aref.ptr.as_ptr() as isize - rcvec.as_ptr() as isize) / a_size + (self_.ptr.as_ptr() as isize - rcvec.as_ptr() as isize) / a_size } else { 0 }; let rvec = Arc::make_mut(rcvec); unsafe { - self_.aref.ptr = rvec.as_nonnull_mut().offset(our_off); + self_.ptr = rvec.as_nonnull_mut().offset(our_off); } } @@ -305,7 +305,7 @@ unsafe impl Data for OwnedArcRepr Self::ensure_unique(&mut self_); let data = Arc::try_unwrap(self_.data.0).ok().unwrap(); // safe because data is equivalent - unsafe { ArrayBase::from_data_ptr(data, self_.aref.ptr).with_strides_dim(self_.aref.strides, self_.aref.dim) } + unsafe { ArrayBase::from_data_ptr(data, self_.ptr).with_strides_dim(self_.strides, self_.dim) } } fn try_into_owned_nocopy(self_: ArrayBase) -> Result, ArrayBase> @@ -314,14 +314,13 @@ unsafe impl Data for OwnedArcRepr match Arc::try_unwrap(self_.data.0) { Ok(owned_data) => unsafe { // Safe because the data is equivalent. - Ok(ArrayBase::from_data_ptr(owned_data, self_.aref.ptr) - .with_strides_dim(self_.aref.strides, self_.aref.dim)) + Ok(ArrayBase::from_data_ptr(owned_data, self_.ptr).with_strides_dim(self_.strides, self_.dim)) }, Err(arc_data) => unsafe { // Safe because the data is equivalent; we're just // reconstructing `self_`. - Err(ArrayBase::from_data_ptr(OwnedArcRepr(arc_data), self_.aref.ptr) - .with_strides_dim(self_.aref.strides, self_.aref.dim)) + Err(ArrayBase::from_data_ptr(OwnedArcRepr(arc_data), self_.ptr) + .with_strides_dim(self_.strides, self_.dim)) }, } } @@ -624,9 +623,9 @@ where A: Clone CowRepr::View(_) => { let owned = array.to_owned(); array.data = CowRepr::Owned(owned.data); - array.aref.ptr = owned.aref.ptr; - array.aref.dim = owned.aref.dim; - array.aref.strides = owned.aref.strides; + array.ptr = owned.ptr; + array.dim = owned.dim; + array.strides = owned.strides; } CowRepr::Owned(_) => {} } @@ -687,7 +686,7 @@ unsafe impl<'a, A> Data for CowRepr<'a, A> CowRepr::View(_) => self_.to_owned(), CowRepr::Owned(data) => unsafe { // safe because the data is equivalent so ptr, dims remain valid - ArrayBase::from_data_ptr(data, self_.aref.ptr).with_strides_dim(self_.aref.strides, self_.aref.dim) + ArrayBase::from_data_ptr(data, self_.ptr).with_strides_dim(self_.strides, self_.dim) }, } } @@ -699,7 +698,7 @@ unsafe impl<'a, A> Data for CowRepr<'a, A> CowRepr::View(_) => Err(self_), CowRepr::Owned(data) => unsafe { // safe because the data is equivalent so ptr, dims remain valid - Ok(ArrayBase::from_data_ptr(data, self_.aref.ptr).with_strides_dim(self_.aref.strides, self_.aref.dim)) + Ok(ArrayBase::from_data_ptr(data, self_.ptr).with_strides_dim(self_.strides, self_.dim)) }, } } diff --git a/src/free_functions.rs b/src/free_functions.rs index c585312f3..5659d7024 100644 --- a/src/free_functions.rs +++ b/src/free_functions.rs @@ -9,7 +9,6 @@ use alloc::vec; #[cfg(not(feature = "std"))] use alloc::vec::Vec; -use core::marker::PhantomData; #[allow(unused_imports)] use std::compile_error; use std::mem::{forget, size_of}; @@ -107,13 +106,10 @@ pub const fn aview0(x: &A) -> ArrayView0<'_, A> { ArrayBase { data: ViewRepr::new(), - aref: RefBase { - // Safe because references are always non-null. - ptr: unsafe { NonNull::new_unchecked(x as *const A as *mut A) }, - dim: Ix0(), - strides: Ix0(), - phantom: PhantomData::< as RawData>::Referent>, - }, + // Safe because references are always non-null. + ptr: unsafe { NonNull::new_unchecked(x as *const A as *mut A) }, + dim: Ix0(), + strides: Ix0(), } } @@ -148,13 +144,10 @@ pub const fn aview1(xs: &[A]) -> ArrayView1<'_, A> } ArrayBase { data: ViewRepr::new(), - aref: RefBase { - // Safe because references are always non-null. - ptr: unsafe { NonNull::new_unchecked(xs.as_ptr() as *mut A) }, - dim: Ix1(xs.len()), - strides: Ix1(1), - phantom: PhantomData::< as RawData>::Referent>, - }, + // Safe because references are always non-null. + ptr: unsafe { NonNull::new_unchecked(xs.as_ptr() as *mut A) }, + dim: Ix1(xs.len()), + strides: Ix1(1), } } @@ -207,12 +200,9 @@ pub const fn aview2(xs: &[[A; N]]) -> ArrayView2<'_, A> }; ArrayBase { data: ViewRepr::new(), - aref: RefBase { - ptr, - dim, - strides, - phantom: PhantomData::< as RawData>::Referent>, - }, + ptr, + dim, + strides, } } diff --git a/src/impl_clone.rs b/src/impl_clone.rs index fabcaf362..d65f6c338 100644 --- a/src/impl_clone.rs +++ b/src/impl_clone.rs @@ -18,12 +18,9 @@ impl Clone for ArrayBase let (data, ptr) = self.data.clone_with_ptr(self.ptr); ArrayBase { data, - aref: RefBase { - ptr, - dim: self.dim.clone(), - strides: self.strides.clone(), - phantom: self.phantom, - }, + ptr, + dim: self.dim.clone(), + strides: self.strides.clone(), } } } @@ -34,9 +31,9 @@ impl Clone for ArrayBase fn clone_from(&mut self, other: &Self) { unsafe { - self.aref.ptr = self.data.clone_from_with_ptr(&other.data, other.ptr); - self.aref.dim.clone_from(&other.dim); - self.aref.strides.clone_from(&other.strides); + self.ptr = self.data.clone_from_with_ptr(&other.data, other.ptr); + self.dim.clone_from(&other.dim); + self.strides.clone_from(&other.strides); } } } diff --git a/src/impl_cow.rs b/src/impl_cow.rs index 93a7c157e..f064ce7bd 100644 --- a/src/impl_cow.rs +++ b/src/impl_cow.rs @@ -33,10 +33,7 @@ where D: Dimension fn from(view: ArrayView<'a, A, D>) -> CowArray<'a, A, D> { // safe because equivalent data - unsafe { - ArrayBase::from_data_ptr(CowRepr::View(view.data), view.ptr) - .with_strides_dim(view.aref.strides, view.aref.dim) - } + unsafe { ArrayBase::from_data_ptr(CowRepr::View(view.data), view.ptr).with_strides_dim(view.strides, view.dim) } } } @@ -47,8 +44,7 @@ where D: Dimension { // safe because equivalent data unsafe { - ArrayBase::from_data_ptr(CowRepr::Owned(array.data), array.aref.ptr) - .with_strides_dim(array.aref.strides, array.aref.dim) + ArrayBase::from_data_ptr(CowRepr::Owned(array.data), array.ptr).with_strides_dim(array.strides, array.dim) } } } diff --git a/src/impl_dyn.rs b/src/impl_dyn.rs index 493c016c6..b86c5dd69 100644 --- a/src/impl_dyn.rs +++ b/src/impl_dyn.rs @@ -32,8 +32,8 @@ where S: Data pub fn insert_axis_inplace(&mut self, axis: Axis) { assert!(axis.index() <= self.ndim()); - self.aref.dim = self.dim.insert_axis(axis); - self.aref.strides = self.strides.insert_axis(axis); + self.dim = self.dim.insert_axis(axis); + self.strides = self.strides.insert_axis(axis); } /// Collapses the array to `index` along the axis and removes the axis, @@ -55,8 +55,8 @@ where S: Data pub fn index_axis_inplace(&mut self, axis: Axis, index: usize) { self.collapse_axis(axis, index); - self.aref.dim = self.dim.remove_axis(axis); - self.aref.strides = self.strides.remove_axis(axis); + self.dim = self.dim.remove_axis(axis); + self.strides = self.strides.remove_axis(axis); } /// Remove axes of length 1 and return the modified array. diff --git a/src/impl_internal_constructors.rs b/src/impl_internal_constructors.rs index 08df31aeb..adb4cbd35 100644 --- a/src/impl_internal_constructors.rs +++ b/src/impl_internal_constructors.rs @@ -6,7 +6,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::marker::PhantomData; use std::ptr::NonNull; use crate::imp_prelude::*; @@ -28,12 +27,9 @@ where S: RawData { let array = ArrayBase { data, - aref: RefBase { - ptr, - dim: Ix1(0), - strides: Ix1(1), - phantom: PhantomData::, - }, + ptr, + dim: Ix1(0), + strides: Ix1(1), }; debug_assert!(array.pointer_is_inbounds()); array @@ -62,12 +58,9 @@ where debug_assert_eq!(strides.ndim(), dim.ndim()); ArrayBase { data: self.data, - aref: RefBase { - ptr: self.aref.ptr, - dim, - strides, - phantom: self.aref.phantom, - }, + ptr: self.ptr, + dim, + strides, } } } diff --git a/src/impl_methods.rs b/src/impl_methods.rs index fb7cc5621..77eee5533 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -150,7 +150,7 @@ where /// ``` pub fn shape(&self) -> &[usize] { - self.aref.dim.slice() + self.dim.slice() } /// Return the strides of the array as a slice. @@ -666,13 +666,10 @@ where #[track_caller] pub fn slice_axis_inplace(&mut self, axis: Axis, indices: Slice) { - let offset = do_slice( - &mut self.aref.dim.slice_mut()[axis.index()], - &mut self.aref.strides.slice_mut()[axis.index()], - indices, - ); + let offset = + do_slice(&mut self.dim.slice_mut()[axis.index()], &mut self.strides.slice_mut()[axis.index()], indices); unsafe { - self.aref.ptr = self.aref.ptr.offset(offset); + self.ptr = self.ptr.offset(offset); } debug_assert!(self.pointer_is_inbounds()); } @@ -1027,8 +1024,8 @@ where #[track_caller] pub fn collapse_axis(&mut self, axis: Axis, index: usize) { - let offset = dimension::do_collapse_axis(&mut self.aref.dim, &self.aref.strides, axis.index(), index); - self.aref.ptr = unsafe { self.aref.ptr.offset(offset) }; + let offset = dimension::do_collapse_axis(&mut self.dim, &self.strides, axis.index(), index); + self.ptr = unsafe { self.ptr.offset(offset) }; debug_assert!(self.pointer_is_inbounds()); } @@ -1641,7 +1638,7 @@ where #[inline(always)] pub fn as_ptr(&self) -> *const A { - self.aref.ptr.as_ptr() as *const A + self.ptr.as_ptr() as *const A } /// Return a mutable pointer to the first element in the array. @@ -2172,8 +2169,7 @@ where { // safe because new dims equivalent unsafe { - ArrayBase::from_data_ptr(self.data, self.aref.ptr) - .with_strides_dim(self.aref.strides.into_dyn(), self.aref.dim.into_dyn()) + ArrayBase::from_data_ptr(self.data, self.ptr).with_strides_dim(self.strides.into_dyn(), self.dim.into_dyn()) } } @@ -2199,9 +2195,9 @@ where unsafe { if D::NDIM == D2::NDIM { // safe because D == D2 - let dim = unlimited_transmute::(self.aref.dim); - let strides = unlimited_transmute::(self.aref.strides); - return Ok(ArrayBase::from_data_ptr(self.data, self.aref.ptr).with_strides_dim(strides, dim)); + let dim = unlimited_transmute::(self.dim); + let strides = unlimited_transmute::(self.strides); + return Ok(ArrayBase::from_data_ptr(self.data, self.ptr).with_strides_dim(strides, dim)); } else if D::NDIM.is_none() || D2::NDIM.is_none() { // one is dynamic dim // safe because dim, strides are equivalent under a different type @@ -2366,8 +2362,8 @@ where #[track_caller] pub fn swap_axes(&mut self, ax: usize, bx: usize) { - self.aref.dim.slice_mut().swap(ax, bx); - self.aref.strides.slice_mut().swap(ax, bx); + self.dim.slice_mut().swap(ax, bx); + self.strides.slice_mut().swap(ax, bx); } /// Permute the axes. @@ -2426,8 +2422,8 @@ where /// while retaining the same data. pub fn reversed_axes(mut self) -> ArrayBase { - self.aref.dim.slice_mut().reverse(); - self.aref.strides.slice_mut().reverse(); + self.dim.slice_mut().reverse(); + self.strides.slice_mut().reverse(); self } @@ -2445,7 +2441,7 @@ where /// Return an iterator over the length and stride of each axis. pub fn axes(&self) -> Axes<'_, D> { - axes_of(&self.aref.dim, &self.aref.strides) + axes_of(&self.dim, &self.strides) } /* @@ -2472,9 +2468,9 @@ where let s = self.strides.axis(axis) as Ixs; let m = self.dim.axis(axis); if m != 0 { - self.aref.ptr = self.aref.ptr.offset(stride_offset(m - 1, s as Ix)); + self.ptr = self.ptr.offset(stride_offset(m - 1, s as Ix)); } - self.aref.strides.set_axis(axis, (-s) as Ix); + self.strides.set_axis(axis, (-s) as Ix); } } @@ -2516,7 +2512,7 @@ where #[track_caller] pub fn merge_axes(&mut self, take: Axis, into: Axis) -> bool { - merge_axes(&mut self.aref.dim, &mut self.aref.strides, take, into) + merge_axes(&mut self.dim, &mut self.strides, take, into) } /// Insert new array axis at `axis` and return the result. @@ -2703,7 +2699,7 @@ where slc.iter().fold(init, f) } else { let mut v = self.view(); - move_min_stride_axis_to_last(&mut v.aref.dim, &mut v.aref.strides); + move_min_stride_axis_to_last(&mut v.dim, &mut v.strides); v.into_elements_base().fold(init, f) } } @@ -2862,7 +2858,7 @@ where Ok(slc) => slc.iter_mut().for_each(f), Err(arr) => { let mut v = arr.view_mut(); - move_min_stride_axis_to_last(&mut v.aref.dim, &mut v.aref.strides); + move_min_stride_axis_to_last(&mut v.dim, &mut v.strides); v.into_elements_base().for_each(f); } } diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs index aac6df367..5b6727d17 100644 --- a/src/impl_owned_array.rs +++ b/src/impl_owned_array.rs @@ -532,7 +532,7 @@ where D: Dimension /// let mut a = Array::zeros((0, 4)); /// let ones = ArrayView::from(&[1.; 4]); /// let zeros = ArrayView::from(&[0.; 4]); - /// a.push(Axis(0), ones.clone()).unwrap(); + /// a.push(Axis(0), ones).unwrap(); /// a.push(Axis(0), zeros).unwrap(); /// a.push(Axis(0), ones).unwrap(); /// @@ -588,7 +588,7 @@ where D: Dimension /// let mut a = Array::zeros((0, 4)); /// let ones = ArrayView::from(&[1.; 8]).into_shape_with_order((2, 4)).unwrap(); /// let zeros = ArrayView::from(&[0.; 8]).into_shape_with_order((2, 4)).unwrap(); - /// a.append(Axis(0), ones.clone()).unwrap(); + /// a.append(Axis(0), ones).unwrap(); /// a.append(Axis(0), zeros).unwrap(); /// a.append(Axis(0), ones).unwrap(); /// @@ -849,7 +849,7 @@ where D: Dimension 0 }; debug_assert!(data_to_array_offset >= 0); - self.aref.ptr = self + self.ptr = self .data .reserve(len_to_append) .offset(data_to_array_offset); @@ -909,7 +909,7 @@ pub(crate) unsafe fn drop_unreachable_raw( // iter is a raw pointer iterator traversing the array in memory order now with the // sorted axes. - let mut iter = Baseiter::new(self_.ptr, self_.aref.dim, self_.aref.strides); + let mut iter = Baseiter::new(self_.ptr, self_.dim, self_.strides); let mut dropped_elements = 0; let mut last_ptr = data_ptr; @@ -948,7 +948,7 @@ where if a.ndim() <= 1 { return; } - sort_axes1_impl(&mut a.aref.dim, &mut a.aref.strides); + sort_axes1_impl(&mut a.dim, &mut a.strides); } fn sort_axes1_impl(adim: &mut D, astrides: &mut D) @@ -988,7 +988,7 @@ where if a.ndim() <= 1 { return; } - sort_axes2_impl(&mut a.aref.dim, &mut a.aref.strides, &mut b.aref.dim, &mut b.aref.strides); + sort_axes2_impl(&mut a.dim, &mut a.strides, &mut b.dim, &mut b.strides); } fn sort_axes2_impl(adim: &mut D, astrides: &mut D, bdim: &mut D, bstrides: &mut D) diff --git a/src/impl_raw_views.rs b/src/impl_raw_views.rs index feccd3c99..5132b1158 100644 --- a/src/impl_raw_views.rs +++ b/src/impl_raw_views.rs @@ -101,7 +101,7 @@ where D: Dimension is_aligned(self.ptr.as_ptr()), "The pointer must be aligned." ); - ArrayView::new(self.ptr, self.aref.dim, self.aref.strides) + ArrayView::new(self.ptr, self.dim, self.strides) } /// Split the array view along `axis` and return one array pointer strictly @@ -126,10 +126,10 @@ where D: Dimension dim_left.set_axis(axis, index); let left = unsafe { Self::new_(left_ptr, dim_left, self.strides.clone()) }; - let mut dim_right = self.aref.dim; + let mut dim_right = self.dim; let right_len = dim_right.axis(axis) - index; dim_right.set_axis(axis, right_len); - let right = unsafe { Self::new_(right_ptr, dim_right, self.aref.strides) }; + let right = unsafe { Self::new_(right_ptr, dim_right, self.strides) }; (left, right) } @@ -153,7 +153,7 @@ where D: Dimension "size mismatch in raw view cast" ); let ptr = self.ptr.cast::(); - unsafe { RawArrayView::new(ptr, self.aref.dim, self.aref.strides) } + unsafe { RawArrayView::new(ptr, self.dim, self.strides) } } } @@ -308,7 +308,7 @@ where D: Dimension #[inline] pub(crate) fn into_raw_view(self) -> RawArrayView { - unsafe { RawArrayView::new(self.ptr, self.aref.dim, self.aref.strides) } + unsafe { RawArrayView::new(self.ptr, self.dim, self.strides) } } /// Converts to a read-only view of the array. @@ -326,7 +326,7 @@ where D: Dimension is_aligned(self.ptr.as_ptr()), "The pointer must be aligned." ); - ArrayView::new(self.ptr, self.aref.dim, self.aref.strides) + ArrayView::new(self.ptr, self.dim, self.strides) } /// Converts to a mutable view of the array. @@ -344,7 +344,7 @@ where D: Dimension is_aligned(self.ptr.as_ptr()), "The pointer must be aligned." ); - ArrayViewMut::new(self.ptr, self.aref.dim, self.aref.strides) + ArrayViewMut::new(self.ptr, self.dim, self.strides) } /// Split the array view along `axis` and return one array pointer strictly @@ -356,12 +356,7 @@ where D: Dimension pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self) { let (left, right) = self.into_raw_view().split_at(axis, index); - unsafe { - ( - Self::new(left.ptr, left.aref.dim, left.aref.strides), - Self::new(right.ptr, right.aref.dim, right.aref.strides), - ) - } + unsafe { (Self::new(left.ptr, left.dim, left.strides), Self::new(right.ptr, right.dim, right.strides)) } } /// Cast the raw pointer of the raw array view to a different type @@ -383,7 +378,7 @@ where D: Dimension "size mismatch in raw view cast" ); let ptr = self.ptr.cast::(); - unsafe { RawArrayViewMut::new(ptr, self.aref.dim, self.aref.strides) } + unsafe { RawArrayViewMut::new(ptr, self.dim, self.strides) } } } @@ -397,8 +392,8 @@ where D: Dimension let Complex { re, im } = self.into_raw_view().split_complex(); unsafe { Complex { - re: RawArrayViewMut::new(re.ptr, re.aref.dim, re.aref.strides), - im: RawArrayViewMut::new(im.ptr, im.aref.dim, im.aref.strides), + re: RawArrayViewMut::new(re.ptr, re.dim, re.strides), + im: RawArrayViewMut::new(im.ptr, im.dim, im.strides), } } } diff --git a/src/impl_special_element_types.rs b/src/impl_special_element_types.rs index 6433f129d..e430b20bc 100644 --- a/src/impl_special_element_types.rs +++ b/src/impl_special_element_types.rs @@ -35,13 +35,9 @@ where { let ArrayBase { data, - aref: - RefBase { - ptr, - dim, - strides, - phantom: _, - }, + ptr, + dim, + strides, } = self; // "transmute" from storage of MaybeUninit to storage of A diff --git a/src/impl_views/constructors.rs b/src/impl_views/constructors.rs index ad70e571d..15f2b9b6b 100644 --- a/src/impl_views/constructors.rs +++ b/src/impl_views/constructors.rs @@ -225,7 +225,7 @@ where D: Dimension pub fn reborrow<'b>(self) -> ArrayViewMut<'b, A, D> where 'a: 'b { - unsafe { ArrayViewMut::new(self.ptr, self.aref.dim, self.aref.strides) } + unsafe { ArrayViewMut::new(self.ptr, self.dim, self.strides) } } } diff --git a/src/impl_views/conversions.rs b/src/impl_views/conversions.rs index f2b63d8eb..1dd7d97f2 100644 --- a/src/impl_views/conversions.rs +++ b/src/impl_views/conversions.rs @@ -29,7 +29,7 @@ where D: Dimension pub fn reborrow<'b>(self) -> ArrayView<'b, A, D> where 'a: 'b { - unsafe { ArrayView::new(self.ptr, self.aref.dim, self.aref.strides) } + unsafe { ArrayView::new(self.ptr, self.dim, self.strides) } } /// Return the array’s data as a slice, if it is contiguous and in standard order. @@ -66,7 +66,7 @@ where D: Dimension #[inline] pub(crate) fn into_raw_view(self) -> RawArrayView { - unsafe { RawArrayView::new(self.ptr, self.aref.dim, self.aref.strides) } + unsafe { RawArrayView::new(self.ptr, self.dim, self.strides) } } } @@ -199,7 +199,7 @@ where D: Dimension #[inline] pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.aref.dim, self.aref.strides) } + unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } } } @@ -209,7 +209,7 @@ where D: Dimension #[inline] pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.aref.dim, self.aref.strides) } + unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } } } @@ -220,7 +220,7 @@ where D: Dimension #[inline] pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.aref.dim, self.aref.strides) } + unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } } #[inline] @@ -250,19 +250,19 @@ where D: Dimension // Convert into a read-only view pub(crate) fn into_view(self) -> ArrayView<'a, A, D> { - unsafe { ArrayView::new(self.ptr, self.aref.dim, self.aref.strides) } + unsafe { ArrayView::new(self.ptr, self.dim, self.strides) } } /// Converts to a mutable raw array view. pub(crate) fn into_raw_view_mut(self) -> RawArrayViewMut { - unsafe { RawArrayViewMut::new(self.ptr, self.aref.dim, self.aref.strides) } + unsafe { RawArrayViewMut::new(self.ptr, self.dim, self.strides) } } #[inline] pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.aref.dim, self.aref.strides) } + unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } } #[inline] diff --git a/src/iterators/chunks.rs b/src/iterators/chunks.rs index 5c624fdd0..9e2f08e1e 100644 --- a/src/iterators/chunks.rs +++ b/src/iterators/chunks.rs @@ -59,10 +59,10 @@ impl<'a, A, D: Dimension> ExactChunks<'a, A, D> a.shape() ); for i in 0..a.ndim() { - a.aref.dim[i] /= chunk[i]; + a.dim[i] /= chunk[i]; } let inner_strides = a.strides.clone(); - a.aref.strides *= &chunk; + a.strides *= &chunk; ExactChunks { base: a, diff --git a/src/iterators/into_iter.rs b/src/iterators/into_iter.rs index 3136e27fc..9374608cb 100644 --- a/src/iterators/into_iter.rs +++ b/src/iterators/into_iter.rs @@ -39,9 +39,9 @@ where D: Dimension let array_head_ptr = array.ptr; let mut array_data = array.data; let data_len = array_data.release_all_elements(); - debug_assert!(data_len >= array.aref.dim.size()); - let has_unreachable_elements = array.aref.dim.size() != data_len; - let inner = Baseiter::new(array_head_ptr, array.aref.dim, array.aref.strides); + debug_assert!(data_len >= array.dim.size()); + let has_unreachable_elements = array.dim.size() != data_len; + let inner = Baseiter::new(array_head_ptr, array.dim, array.strides); IntoIter { array_data, diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index 360b51316..e7321d15b 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -1372,7 +1372,7 @@ fn chunk_iter_parts(v: ArrayView<'_, A, D>, axis: Axis, size: u let mut inner_dim = v.dim.clone(); inner_dim[axis] = size; - let mut partial_chunk_dim = v.aref.dim; + let mut partial_chunk_dim = v.dim; partial_chunk_dim[axis] = chunk_remainder; let partial_chunk_index = n_whole_chunks; @@ -1381,8 +1381,8 @@ fn chunk_iter_parts(v: ArrayView<'_, A, D>, axis: Axis, size: u end: iter_len, stride, inner_dim, - inner_strides: v.aref.strides, - ptr: v.aref.ptr.as_ptr(), + inner_strides: v.strides, + ptr: v.ptr.as_ptr(), }; (iter, partial_chunk_index, partial_chunk_dim) diff --git a/src/lib.rs b/src/lib.rs index de4adf9ae..6710c93d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1355,7 +1355,7 @@ pub struct RefBase where R: RawReferent { /// A non-null pointer into the buffer held by `data`; may point anywhere - /// in its range. If `S: Data`, this pointer must be aligned. + /// in its range. If `S: Referent`, this pointer must be aligned. ptr: std::ptr::NonNull, /// The lengths of the axes. dim: D, diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 94c6ed92b..b58752f66 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -97,7 +97,7 @@ where { #[allow(clippy::needless_borrow)] let res: ArrayView<'_, A, E::Dim> = (&self).broadcast_unwrap(shape.into_dimension()); - unsafe { ArrayView::new(res.ptr, res.aref.dim, res.aref.strides) } + unsafe { ArrayView::new(res.ptr, res.dim, res.strides) } } private_impl! {} } diff --git a/tests/append.rs b/tests/append.rs index fc28d6ff2..cf5397de1 100644 --- a/tests/append.rs +++ b/tests/append.rs @@ -298,9 +298,9 @@ fn test_append_2d() let zeros = ArrayView::from(&[0.; 8]) .into_shape_with_order((2, 4)) .unwrap(); - a.append(Axis(0), ones.clone()).unwrap(); - a.append(Axis(0), zeros.clone()).unwrap(); - a.append(Axis(0), ones.clone()).unwrap(); + a.append(Axis(0), ones).unwrap(); + a.append(Axis(0), zeros).unwrap(); + a.append(Axis(0), ones).unwrap(); println!("{:?}", a); assert_eq!(a.shape(), &[8, 4]); for (i, row) in a.rows().into_iter().enumerate() { @@ -312,7 +312,7 @@ fn test_append_2d() a = a.reversed_axes(); let ones = ones.reversed_axes(); let zeros = zeros.reversed_axes(); - a.append(Axis(1), ones.clone()).unwrap(); + a.append(Axis(1), ones).unwrap(); a.append(Axis(1), zeros).unwrap(); a.append(Axis(1), ones).unwrap(); println!("{:?}", a); @@ -447,7 +447,7 @@ fn zero_dimensional_ok() let one = aview0(&1); let two = aview0(&2); a.push(Axis(0), two).unwrap(); - a.push(Axis(0), one.clone()).unwrap(); + a.push(Axis(0), one).unwrap(); a.push(Axis(0), one).unwrap(); assert_eq!(a, array![2, 1, 1]); } diff --git a/tests/array.rs b/tests/array.rs index 10dfb8c20..696904dab 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -1446,7 +1446,7 @@ fn views() assert_eq!(a, b); assert_eq!(a.shape(), b.shape()); assert_eq!(a.clone() + a.clone(), &b + &b); - assert_eq!(a.clone() + b.clone(), &b + &b); + assert_eq!(a.clone() + b, &b + &b); a.clone()[(0, 0)] = 99; assert_eq!(b[(0, 0)], 1); @@ -1773,7 +1773,7 @@ fn arithmetic_broadcast() arr3(&[[[11, 15], [20, 24]], [[10, 14], [19, 23]]]) ); assert_eq!( - &a + b.clone().into_owned() + c.clone(), + &a + b.into_owned() + c, arr3(&[[[15, 19], [32, 36]], [[14, 18], [31, 35]]]) ); @@ -2154,7 +2154,7 @@ fn test_contiguous_neg_strides() assert_eq!(b, arr3(&[[[11, 7, 3], [9, 5, 1]], [[10, 6, 2], [8, 4, 0]]])); assert!(b.as_slice_memory_order().is_some()); - let mut c = b.clone().reversed_axes(); + let mut c = b.reversed_axes(); assert_eq!( c, arr3(&[[[11, 10], [9, 8]], [[7, 6], [5, 4]], [[3, 2], [1, 0]]]) @@ -2165,11 +2165,11 @@ fn test_contiguous_neg_strides() assert_eq!(c, arr3(&[[[11, 10, 9, 8]], [[7, 6, 5, 4]], [[3, 2, 1, 0]]])); assert!(c.as_slice_memory_order().is_some()); - let d = b.clone().remove_axis(Axis(1)); + let d = b.remove_axis(Axis(1)); assert_eq!(d, arr2(&[[11, 7, 3], [10, 6, 2]])); assert!(d.as_slice_memory_order().is_none()); - let e = b.clone().remove_axis(Axis(2)); + let e = b.remove_axis(Axis(2)); assert_eq!(e, arr2(&[[11, 9], [10, 8]])); assert!(e.as_slice_memory_order().is_some()); diff --git a/tests/reshape.rs b/tests/reshape.rs index f39e15580..a13a5c05f 100644 --- a/tests/reshape.rs +++ b/tests/reshape.rs @@ -9,7 +9,7 @@ fn reshape() { let data = [1, 2, 3, 4, 5, 6, 7, 8]; let v = aview1(&data); - let u = v.clone().into_shape_with_order((3, 3)); + let u = v.into_shape_with_order((3, 3)); assert!(u.is_err()); let u = v.into_shape_with_order((2, 2, 2)); assert!(u.is_ok()); @@ -51,7 +51,7 @@ fn reshape_f() println!("{:?}", v); // noop ok - let v2 = v.clone().into_shape_with_order(((3, 4), Order::F)); + let v2 = v.into_shape_with_order(((3, 4), Order::F)); assert!(v2.is_ok()); assert_eq!(v, v2.unwrap()); @@ -247,7 +247,7 @@ fn into_shape_with_order() // 1D -> C -> C let data = [1, 2, 3, 4, 5, 6, 7, 8]; let v = aview1(&data); - let u = v.clone().into_shape_with_order(((3, 3), Order::RowMajor)); + let u = v.into_shape_with_order(((3, 3), Order::RowMajor)); assert!(u.is_err()); let u = v.into_shape_with_order(((2, 2, 2), Order::C)); @@ -264,9 +264,7 @@ fn into_shape_with_order() // 1D -> F -> F let data = [1, 2, 3, 4, 5, 6, 7, 8]; let v = aview1(&data); - let u = v - .clone() - .into_shape_with_order(((3, 3), Order::ColumnMajor)); + let u = v.into_shape_with_order(((3, 3), Order::ColumnMajor)); assert!(u.is_err()); let u = v.into_shape_with_order(((2, 2, 2), Order::ColumnMajor)); diff --git a/tests/views.rs b/tests/views.rs index 587a1da33..02970b1b7 100644 --- a/tests/views.rs +++ b/tests/views.rs @@ -9,7 +9,7 @@ fn cell_view() { let cv1 = a.cell_view(); - let cv2 = cv1.clone(); + let cv2 = cv1; Zip::from(cv1).and(cv2).for_each(|a, b| a.set(b.get() + 1.)); } From 3a180c1f4e68c298ac8a88519b9b67cc80d33c5e Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 6 Oct 2024 17:24:10 -0400 Subject: [PATCH 08/33] Removes unused import --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6710c93d9..7561e66a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -221,7 +221,6 @@ mod imp_prelude pub use crate::dimension::DimensionExt; pub use crate::prelude::*; pub use crate::ArcArray; - pub use crate::RefBase; pub use crate::{ CowRepr, Data, From 6b646787ac07fccb8d88d24e7538f736fdb96aa6 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Fri, 11 Oct 2024 16:46:06 +0100 Subject: [PATCH 09/33] Introduces LayoutRef and starts to move functionality from ArrayBase to RefBase and LayoutRef --- src/alias_slicing.rs | 150 ++++++++++ src/arrayref.rs | 14 +- src/arraytraits.rs | 23 +- src/data_traits.rs | 56 ++-- src/impl_1d.rs | 5 +- src/impl_clone.rs | 15 +- src/impl_constructors.rs | 7 +- src/impl_cow.rs | 11 +- src/impl_dyn.rs | 8 +- src/impl_internal_constructors.rs | 18 +- src/impl_methods.rs | 444 +++++++++++++++++++++--------- src/impl_ops.rs | 20 ++ src/impl_owned_array.rs | 8 +- src/impl_raw_views.rs | 27 +- src/impl_special_element_types.rs | 5 +- src/layoutref.rs | 128 +++++++++ src/lib.rs | 73 +++-- src/zip/ndproducer.rs | 17 +- 18 files changed, 795 insertions(+), 234 deletions(-) create mode 100644 src/alias_slicing.rs create mode 100644 src/layoutref.rs diff --git a/src/alias_slicing.rs b/src/alias_slicing.rs new file mode 100644 index 000000000..fabcb2945 --- /dev/null +++ b/src/alias_slicing.rs @@ -0,0 +1,150 @@ +use crate::{iter::Axes, ArrayBase, Axis, AxisDescription, Dimension, RawData, Slice, SliceArg}; + +impl ArrayBase +{ + /// Slice the array in place without changing the number of dimensions. + /// + /// In particular, if an axis is sliced with an index, the axis is + /// collapsed, as in [`.collapse_axis()`], rather than removed, as in + /// [`.slice_move()`] or [`.index_axis_move()`]. + /// + /// [`.collapse_axis()`]: Self::collapse_axis + /// [`.slice_move()`]: Self::slice_move + /// [`.index_axis_move()`]: Self::index_axis_move + /// + /// See [*Slicing*](#slicing) for full documentation. + /// See also [`s!`], [`SliceArg`], and [`SliceInfo`](crate::SliceInfo). + /// + /// **Panics** in the following cases: + /// + /// - if an index is out of bounds + /// - if a step size is zero + /// - if [`SliceInfoElem::NewAxis`] is in `info`, e.g. if [`NewAxis`] was + /// used in the [`s!`] macro + /// - if `D` is `IxDyn` and `info` does not match the number of array axes + #[track_caller] + pub fn slice_collapse(&mut self, info: I) + where I: SliceArg + { + self.as_mut().slice_collapse(info); + } + + /// Slice the array in place along the specified axis. + /// + /// **Panics** if an index is out of bounds or step size is zero.
+ /// **Panics** if `axis` is out of bounds. + #[track_caller] + pub fn slice_axis_inplace(&mut self, axis: Axis, indices: Slice) + { + self.as_mut().slice_axis_inplace(axis, indices); + } + + /// Slice the array in place, with a closure specifying the slice for each + /// axis. + /// + /// This is especially useful for code which is generic over the + /// dimensionality of the array. + /// + /// **Panics** if an index is out of bounds or step size is zero. + #[track_caller] + pub fn slice_each_axis_inplace(&mut self, f: F) + where F: FnMut(AxisDescription) -> Slice + { + self.as_mut().slice_each_axis_inplace(f); + } + + /// Selects `index` along the axis, collapsing the axis into length one. + /// + /// **Panics** if `axis` or `index` is out of bounds. + #[track_caller] + pub fn collapse_axis(&mut self, axis: Axis, index: usize) + { + self.as_mut().collapse_axis(axis, index); + } + + /// Return `true` if the array data is laid out in contiguous “C order” in + /// memory (where the last index is the most rapidly varying). + /// + /// Return `false` otherwise, i.e. the array is possibly not + /// contiguous in memory, it has custom strides, etc. + pub fn is_standard_layout(&self) -> bool + { + self.as_ref().is_standard_layout() + } + + /// Return true if the array is known to be contiguous. + pub(crate) fn is_contiguous(&self) -> bool + { + self.as_ref().is_contiguous() + } + + /// Return an iterator over the length and stride of each axis. + pub fn axes(&self) -> Axes<'_, D> + { + self.as_ref().axes() + } + + /* + /// Return the axis with the least stride (by absolute value) + pub fn min_stride_axis(&self) -> Axis { + self.dim.min_stride_axis(&self.strides) + } + */ + + /// Return the axis with the greatest stride (by absolute value), + /// preferring axes with len > 1. + pub fn max_stride_axis(&self) -> Axis + { + self.as_ref().max_stride_axis() + } + + /// Reverse the stride of `axis`. + /// + /// ***Panics*** if the axis is out of bounds. + #[track_caller] + pub fn invert_axis(&mut self, axis: Axis) + { + self.as_mut().invert_axis(axis); + } + + /// If possible, merge in the axis `take` to `into`. + /// + /// Returns `true` iff the axes are now merged. + /// + /// This method merges the axes if movement along the two original axes + /// (moving fastest along the `into` axis) can be equivalently represented + /// as movement along one (merged) axis. Merging the axes preserves this + /// order in the merged axis. If `take` and `into` are the same axis, then + /// the axis is "merged" if its length is ≤ 1. + /// + /// If the return value is `true`, then the following hold: + /// + /// * The new length of the `into` axis is the product of the original + /// lengths of the two axes. + /// + /// * The new length of the `take` axis is 0 if the product of the original + /// lengths of the two axes is 0, and 1 otherwise. + /// + /// If the return value is `false`, then merging is not possible, and the + /// original shape and strides have been preserved. + /// + /// Note that the ordering constraint means that if it's possible to merge + /// `take` into `into`, it's usually not possible to merge `into` into + /// `take`, and vice versa. + /// + /// ``` + /// use ndarray::Array3; + /// use ndarray::Axis; + /// + /// let mut a = Array3::::zeros((2, 3, 4)); + /// assert!(a.merge_axes(Axis(1), Axis(2))); + /// assert_eq!(a.shape(), &[2, 1, 12]); + /// ``` + /// + /// ***Panics*** if an axis is out of bounds. + #[track_caller] + pub fn merge_axes(&mut self, take: Axis, into: Axis) -> bool + { + self.as_mut().merge_axes(take, into) + } +} diff --git a/src/arrayref.rs b/src/arrayref.rs index a55f536ac..648f38d47 100644 --- a/src/arrayref.rs +++ b/src/arrayref.rs @@ -2,7 +2,7 @@ use core::ops::{Deref, DerefMut}; -use crate::{ArrayBase, Dimension, RawData, RawDataMut, RefBase}; +use crate::{ArrayBase, Dimension, LayoutRef, RawData, RawDataMut, RefBase}; /// Unit struct to mark a reference as raw /// @@ -27,7 +27,7 @@ pub trait RawReferent /// A trait for array references that point to data that is safe to read. /// /// Cannot be implemented outside of `ndarray`. -pub trait Referent +pub trait Referent: RawReferent { private_decl! {} } @@ -48,7 +48,7 @@ impl Referent for Safe impl Deref for ArrayBase where S: RawData { - type Target = RefBase; + type Target = RefBase; fn deref(&self) -> &Self::Target { @@ -57,8 +57,8 @@ where S: RawData // - It is "dereferencable" because it just points to self // - For the same reason, it is initialized unsafe { - (self as *const Self) - .cast::>() + (&self.layout as *const LayoutRef) + .cast::>() .as_ref() } .expect("Pointer to self will always be non-null") @@ -78,8 +78,8 @@ where // - It is "dereferencable" because it just points to self // - For the same reason, it is initialized unsafe { - (self as *mut Self) - .cast::>() + (&mut self.layout as *mut LayoutRef) + .cast::>() .as_mut() } .expect("Pointer to self will always be non-null") diff --git a/src/arraytraits.rs b/src/arraytraits.rs index e68b5d56a..5e256e2f5 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -16,9 +16,11 @@ use std::mem::size_of; use std::ops::{Index, IndexMut}; use std::{iter::FromIterator, slice}; +use crate::arrayref::Referent; use crate::imp_prelude::*; use crate::Arc; +use crate::LayoutRef; use crate::{ dimension, iter::{Iter, IterMut}, @@ -37,13 +39,14 @@ pub(crate) fn array_out_of_bounds() -> ! } #[inline(always)] -pub fn debug_bounds_check(_a: &ArrayBase, _index: &I) +pub fn debug_bounds_check(_a: &T, _index: &I) where D: Dimension, I: NdIndex, - S: Data, + T: AsRef>, { - debug_bounds_check!(_a, *_index); + let layout = _a.as_ref(); + debug_bounds_check!(layout, *_index); } /// Access the element at **index**. @@ -101,6 +104,8 @@ where S: Data, S2: Data, D: Dimension, + S::RefType: Referent, + S2::RefType: Referent, { fn eq(&self, rhs: &ArrayBase) -> bool { @@ -134,6 +139,8 @@ where S: Data, S2: Data, D: Dimension, + S::RefType: Referent, + S2::RefType: Referent, { fn eq(&self, rhs: &&ArrayBase) -> bool { @@ -150,6 +157,8 @@ where S: Data, S2: Data, D: Dimension, + S::RefType: Referent, + S2::RefType: Referent, { fn eq(&self, rhs: &ArrayBase) -> bool { @@ -162,6 +171,7 @@ where D: Dimension, S: Data, S::Elem: Eq, + S::RefType: Referent, { } @@ -220,6 +230,7 @@ impl<'a, S, D> IntoIterator for &'a ArrayBase where D: Dimension, S: Data, + S::RefType: Referent, { type Item = &'a S::Elem; type IntoIter = Iter<'a, S::Elem, D>; @@ -234,6 +245,7 @@ impl<'a, S, D> IntoIterator for &'a mut ArrayBase where D: Dimension, S: DataMut, + S::RefType: Referent, { type Item = &'a mut S::Elem; type IntoIter = IterMut<'a, S::Elem, D>; @@ -273,6 +285,7 @@ where D: Dimension, S: Data, S::Elem: hash::Hash, + S::RefType: Referent, { // Note: elements are hashed in the logical order fn hash(&self, state: &mut H) @@ -370,6 +383,7 @@ impl<'a, A, S, D> From<&'a ArrayBase> for ArrayView<'a, A, D> where S: Data, D: Dimension, + S::RefType: Referent, { /// Create a read-only array view of the array. fn from(array: &'a ArrayBase) -> Self @@ -448,6 +462,7 @@ impl<'a, A, S, D> From<&'a mut ArrayBase> for ArrayViewMut<'a, A, D> where S: DataMut, D: Dimension, + S::RefType: Referent, { /// Create a read-write array view of the array. fn from(array: &'a mut ArrayBase) -> Self @@ -463,7 +478,7 @@ where D: Dimension { let data = OwnedArcRepr(Arc::new(arr.data)); // safe because: equivalent unmoved data, ptr and dims remain valid - unsafe { ArrayBase::from_data_ptr(data, arr.ptr).with_strides_dim(arr.strides, arr.dim) } + unsafe { ArrayBase::from_data_ptr(data, arr.layout.ptr).with_strides_dim(arr.layout.strides, arr.layout.dim) } } } diff --git a/src/data_traits.rs b/src/data_traits.rs index d846f010c..efd335d14 100644 --- a/src/data_traits.rs +++ b/src/data_traits.rs @@ -23,6 +23,7 @@ use std::mem::MaybeUninit; use std::mem::{self, size_of}; use std::ptr::NonNull; +use crate::arrayref::Referent; use crate::{ ArcArray, Array, @@ -34,6 +35,7 @@ use crate::{ Raw, RawReferent, RawViewRepr, + RefBase, Safe, ViewRepr, }; @@ -54,7 +56,7 @@ pub unsafe trait RawData: Sized type Elem; /// The safety of the reference type - type Referent: RawReferent; + type RefType: RawReferent; #[doc(hidden)] fn _is_pointer_inbounds(&self, ptr: *const Self::Elem) -> bool; @@ -142,9 +144,10 @@ pub unsafe trait Data: RawData where Self::Elem: Clone, D: Dimension, + Self::RefType: Referent, { // clone to shared - self_.to_owned().into_shared() + (*self_).to_owned().into_shared() } } @@ -187,7 +190,7 @@ pub unsafe trait DataMut: Data + RawDataMut unsafe impl
RawData for RawViewRepr<*const A> { type Elem = A; - type Referent = Raw; + type RefType = Raw; #[inline(always)] fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool @@ -209,7 +212,7 @@ unsafe impl RawDataClone for RawViewRepr<*const A> unsafe impl RawData for RawViewRepr<*mut A> { type Elem = A; - type Referent = Raw; + type RefType = Raw; #[inline(always)] fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool @@ -248,7 +251,7 @@ unsafe impl RawDataClone for RawViewRepr<*mut A> unsafe impl RawData for OwnedArcRepr { type Elem = A; - type Referent = Safe; + type RefType = Safe; fn _is_pointer_inbounds(&self, self_ptr: *const Self::Elem) -> bool { @@ -270,7 +273,7 @@ where A: Clone if Arc::get_mut(&mut self_.data.0).is_some() { return; } - if self_.dim.size() <= self_.data.0.len() / 2 { + if self_.layout.dim.size() <= self_.data.0.len() / 2 { // Clone only the visible elements if the current view is less than // half of backing data. *self_ = self_.to_owned().into_shared(); @@ -279,13 +282,13 @@ where A: Clone let rcvec = &mut self_.data.0; let a_size = mem::size_of::() as isize; let our_off = if a_size != 0 { - (self_.ptr.as_ptr() as isize - rcvec.as_ptr() as isize) / a_size + (self_.layout.ptr.as_ptr() as isize - rcvec.as_ptr() as isize) / a_size } else { 0 }; let rvec = Arc::make_mut(rcvec); unsafe { - self_.ptr = rvec.as_nonnull_mut().offset(our_off); + self_.layout.ptr = rvec.as_nonnull_mut().offset(our_off); } } @@ -305,7 +308,9 @@ unsafe impl Data for OwnedArcRepr Self::ensure_unique(&mut self_); let data = Arc::try_unwrap(self_.data.0).ok().unwrap(); // safe because data is equivalent - unsafe { ArrayBase::from_data_ptr(data, self_.ptr).with_strides_dim(self_.strides, self_.dim) } + unsafe { + ArrayBase::from_data_ptr(data, self_.layout.ptr).with_strides_dim(self_.layout.strides, self_.layout.dim) + } } fn try_into_owned_nocopy(self_: ArrayBase) -> Result, ArrayBase> @@ -314,13 +319,14 @@ unsafe impl Data for OwnedArcRepr match Arc::try_unwrap(self_.data.0) { Ok(owned_data) => unsafe { // Safe because the data is equivalent. - Ok(ArrayBase::from_data_ptr(owned_data, self_.ptr).with_strides_dim(self_.strides, self_.dim)) + Ok(ArrayBase::from_data_ptr(owned_data, self_.layout.ptr) + .with_strides_dim(self_.layout.strides, self_.layout.dim)) }, Err(arc_data) => unsafe { // Safe because the data is equivalent; we're just // reconstructing `self_`. - Err(ArrayBase::from_data_ptr(OwnedArcRepr(arc_data), self_.ptr) - .with_strides_dim(self_.strides, self_.dim)) + Err(ArrayBase::from_data_ptr(OwnedArcRepr(arc_data), self_.layout.ptr) + .with_strides_dim(self_.layout.strides, self_.layout.dim)) }, } } @@ -350,7 +356,7 @@ unsafe impl RawDataClone for OwnedArcRepr unsafe impl RawData for OwnedRepr { type Elem = A; - type Referent = Safe; + type RefType = Safe; fn _is_pointer_inbounds(&self, self_ptr: *const Self::Elem) -> bool { @@ -430,7 +436,7 @@ where A: Clone unsafe impl<'a, A> RawData for ViewRepr<&'a A> { type Elem = A; - type Referent = Safe; + type RefType = Safe; #[inline(always)] fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool @@ -448,7 +454,7 @@ unsafe impl<'a, A> Data for ViewRepr<&'a A> Self::Elem: Clone, D: Dimension, { - self_.to_owned() + (*self_).to_owned() } fn try_into_owned_nocopy(self_: ArrayBase) -> Result, ArrayBase> @@ -469,7 +475,7 @@ unsafe impl<'a, A> RawDataClone for ViewRepr<&'a A> unsafe impl<'a, A> RawData for ViewRepr<&'a mut A> { type Elem = A; - type Referent = Safe; + type RefType = Safe; #[inline(always)] fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool @@ -596,7 +602,7 @@ unsafe impl DataOwned for OwnedArcRepr unsafe impl<'a, A> RawData for CowRepr<'a, A> { type Elem = A; - type Referent = Safe; + type RefType = Safe; #[inline] fn _is_pointer_inbounds(&self, ptr: *const Self::Elem) -> bool @@ -621,11 +627,11 @@ where A: Clone { match array.data { CowRepr::View(_) => { - let owned = array.to_owned(); + let owned = RefBase::to_owned(array); array.data = CowRepr::Owned(owned.data); - array.ptr = owned.ptr; - array.dim = owned.dim; - array.strides = owned.strides; + array.layout.ptr = owned.layout.ptr; + array.layout.dim = owned.layout.dim; + array.layout.strides = owned.layout.strides; } CowRepr::Owned(_) => {} } @@ -683,10 +689,11 @@ unsafe impl<'a, A> Data for CowRepr<'a, A> D: Dimension, { match self_.data { - CowRepr::View(_) => self_.to_owned(), + CowRepr::View(_) => (*self_).to_owned(), CowRepr::Owned(data) => unsafe { // safe because the data is equivalent so ptr, dims remain valid - ArrayBase::from_data_ptr(data, self_.ptr).with_strides_dim(self_.strides, self_.dim) + ArrayBase::from_data_ptr(data, self_.layout.ptr) + .with_strides_dim(self_.layout.strides, self_.layout.dim) }, } } @@ -698,7 +705,8 @@ unsafe impl<'a, A> Data for CowRepr<'a, A> CowRepr::View(_) => Err(self_), CowRepr::Owned(data) => unsafe { // safe because the data is equivalent so ptr, dims remain valid - Ok(ArrayBase::from_data_ptr(data, self_.ptr).with_strides_dim(self_.strides, self_.dim)) + Ok(ArrayBase::from_data_ptr(data, self_.layout.ptr) + .with_strides_dim(self_.layout.strides, self_.layout.dim)) }, } } diff --git a/src/impl_1d.rs b/src/impl_1d.rs index e49fdd731..5257a4e4b 100644 --- a/src/impl_1d.rs +++ b/src/impl_1d.rs @@ -11,12 +11,15 @@ use alloc::vec::Vec; use std::mem::MaybeUninit; +use crate::arrayref::Referent; use crate::imp_prelude::*; use crate::low_level_util::AbortIfPanic; /// # Methods For 1-D Arrays impl ArrayBase -where S: RawData +where + S: RawData, + S::RefType: Referent, { /// Return an vector with the elements of the one-dimensional array. pub fn to_vec(&self) -> Vec diff --git a/src/impl_clone.rs b/src/impl_clone.rs index d65f6c338..4c16039a7 100644 --- a/src/impl_clone.rs +++ b/src/impl_clone.rs @@ -7,6 +7,7 @@ // except according to those terms. use crate::imp_prelude::*; +use crate::LayoutRef; use crate::RawDataClone; impl Clone for ArrayBase @@ -18,9 +19,11 @@ impl Clone for ArrayBase let (data, ptr) = self.data.clone_with_ptr(self.ptr); ArrayBase { data, - ptr, - dim: self.dim.clone(), - strides: self.strides.clone(), + layout: LayoutRef { + ptr, + dim: self.dim.clone(), + strides: self.strides.clone(), + }, } } } @@ -31,9 +34,9 @@ impl Clone for ArrayBase fn clone_from(&mut self, other: &Self) { unsafe { - self.ptr = self.data.clone_from_with_ptr(&other.data, other.ptr); - self.dim.clone_from(&other.dim); - self.strides.clone_from(&other.strides); + self.layout.ptr = self.data.clone_from_with_ptr(&other.data, other.ptr); + self.layout.dim.clone_from(&other.dim); + self.layout.strides.clone_from(&other.strides); } } } diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index 260937a90..64ec33d56 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -20,6 +20,7 @@ use num_traits::{One, Zero}; use std::mem; use std::mem::MaybeUninit; +use crate::arrayref::Referent; use crate::dimension::offset_from_low_addr_ptr_to_logical_ptr; use crate::dimension::{self, CanIndexCheckMode}; use crate::error::{self, ShapeError}; @@ -188,7 +189,9 @@ where S: DataOwned /// ## Constructor methods for two-dimensional arrays. impl ArrayBase -where S: DataOwned +where + S: DataOwned, + S::RefType: Referent, { /// Create an identity matrix of size `n` (square 2D array). /// @@ -221,6 +224,7 @@ where S: DataOwned A: Clone + Zero, S: DataMut, S2: Data, + S2::RefType: Referent, { let n = diag.len(); let mut arr = Self::zeros((n, n)); @@ -617,6 +621,7 @@ where where Sh: ShapeBuilder, F: FnOnce(ArrayViewMut, D>), + <::MaybeUninit as RawData>::RefType: Referent, { let mut array = Self::uninit(shape); // Safe because: the array is unshared here diff --git a/src/impl_cow.rs b/src/impl_cow.rs index f064ce7bd..f5cd5447d 100644 --- a/src/impl_cow.rs +++ b/src/impl_cow.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::imp_prelude::*; +use crate::{arrayref::Referent, imp_prelude::*}; /// Methods specific to `CowArray`. /// @@ -33,7 +33,10 @@ where D: Dimension fn from(view: ArrayView<'a, A, D>) -> CowArray<'a, A, D> { // safe because equivalent data - unsafe { ArrayBase::from_data_ptr(CowRepr::View(view.data), view.ptr).with_strides_dim(view.strides, view.dim) } + unsafe { + ArrayBase::from_data_ptr(CowRepr::View(view.data), view.ptr) + .with_strides_dim(view.layout.strides, view.layout.dim) + } } } @@ -44,7 +47,8 @@ where D: Dimension { // safe because equivalent data unsafe { - ArrayBase::from_data_ptr(CowRepr::Owned(array.data), array.ptr).with_strides_dim(array.strides, array.dim) + ArrayBase::from_data_ptr(CowRepr::Owned(array.data), array.layout.ptr) + .with_strides_dim(array.layout.strides, array.layout.dim) } } } @@ -73,6 +77,7 @@ impl<'a, A, S, D> From<&'a ArrayBase> for CowArray<'a, A, D> where S: Data, D: Dimension, + S::RefType: Referent, { /// Create a read-only clone-on-write view of the array. fn from(array: &'a ArrayBase) -> Self diff --git a/src/impl_dyn.rs b/src/impl_dyn.rs index b86c5dd69..840d31c69 100644 --- a/src/impl_dyn.rs +++ b/src/impl_dyn.rs @@ -32,8 +32,8 @@ where S: Data pub fn insert_axis_inplace(&mut self, axis: Axis) { assert!(axis.index() <= self.ndim()); - self.dim = self.dim.insert_axis(axis); - self.strides = self.strides.insert_axis(axis); + self.layout.dim = self.layout.dim.insert_axis(axis); + self.layout.strides = self.layout.strides.insert_axis(axis); } /// Collapses the array to `index` along the axis and removes the axis, @@ -55,8 +55,8 @@ where S: Data pub fn index_axis_inplace(&mut self, axis: Axis, index: usize) { self.collapse_axis(axis, index); - self.dim = self.dim.remove_axis(axis); - self.strides = self.strides.remove_axis(axis); + self.layout.dim = self.layout.dim.remove_axis(axis); + self.layout.strides = self.layout.strides.remove_axis(axis); } /// Remove axes of length 1 and return the modified array. diff --git a/src/impl_internal_constructors.rs b/src/impl_internal_constructors.rs index adb4cbd35..7f95339d5 100644 --- a/src/impl_internal_constructors.rs +++ b/src/impl_internal_constructors.rs @@ -8,7 +8,7 @@ use std::ptr::NonNull; -use crate::imp_prelude::*; +use crate::{imp_prelude::*, LayoutRef}; // internal "builder-like" methods impl ArrayBase @@ -27,9 +27,11 @@ where S: RawData { let array = ArrayBase { data, - ptr, - dim: Ix1(0), - strides: Ix1(1), + layout: LayoutRef { + ptr, + dim: Ix1(0), + strides: Ix1(1), + }, }; debug_assert!(array.pointer_is_inbounds()); array @@ -58,9 +60,11 @@ where debug_assert_eq!(strides.ndim(), dim.ndim()); ArrayBase { data: self.data, - ptr: self.ptr, - dim, - strides, + layout: LayoutRef { + ptr: self.layout.ptr, + dim, + strides, + }, } } } diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 77eee5533..32cf58c5d 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -14,6 +14,7 @@ use alloc::vec::Vec; use rawpointer::PointerExt; use std::mem::{size_of, ManuallyDrop}; +use crate::arrayref::Referent; use crate::imp_prelude::*; use crate::argument_traits::AssignElem; @@ -39,6 +40,9 @@ use crate::order::Order; use crate::shape_builder::ShapeArg; use crate::zip::{IntoNdProducer, Zip}; use crate::AxisDescription; +use crate::LayoutRef; +use crate::RawReferent; +use crate::RefBase; use crate::{arraytraits, DimMax}; use crate::iter::{ @@ -62,10 +66,7 @@ use crate::stacking::concatenate; use crate::{NdIndex, Slice, SliceInfoElem}; /// # Methods For All Array Types -impl ArrayBase -where - S: RawData, - D: Dimension, +impl LayoutRef { /// Return the total number of elements in the array. pub fn len(&self) -> usize @@ -173,20 +174,22 @@ where // strides are reinterpreted as isize self.strides[axis.index()] as isize } +} +impl RefBase +{ /// Return a read-only view of the array pub fn view(&self) -> ArrayView<'_, A, D> - where S: Data + where R: Referent { - debug_assert!(self.pointer_is_inbounds()); + // debug_assert!(self.pointer_is_inbounds()); unsafe { ArrayView::new(self.ptr, self.dim.clone(), self.strides.clone()) } } /// Return a read-write view of the array pub fn view_mut(&mut self) -> ArrayViewMut<'_, A, D> - where S: DataMut + where R: Referent { - self.ensure_unique(); unsafe { ArrayViewMut::new(self.ptr, self.dim.clone(), self.strides.clone()) } } @@ -198,7 +201,7 @@ where /// The view acts "as if" the elements are temporarily in cells, and elements /// can be changed through shared references using the regular cell methods. pub fn cell_view(&mut self) -> ArrayView<'_, MathCell, D> - where S: DataMut + where R: Referent { self.view_mut().into_cell_view() } @@ -236,7 +239,7 @@ where pub fn to_owned(&self) -> Array where A: Clone, - S: Data, + R: Referent, { if let Some(slc) = self.as_slice_memory_order() { unsafe { Array::from_shape_vec_unchecked(self.dim.clone().strides(self.strides.clone()), slc.to_vec()) } @@ -244,13 +247,20 @@ where self.map(A::clone) } } +} +impl ArrayBase +where + S: RawData, + D: Dimension, +{ /// Return a shared ownership (copy on write) array, cloning the array /// elements if necessary. pub fn to_shared(&self) -> ArcArray where A: Clone, S: Data, + S::RefType: Referent, { S::to_shared(self) } @@ -305,7 +315,10 @@ where { S::into_shared(self) } +} +impl RefBase +{ /// Returns a reference to the first element of the array, or `None` if it /// is empty. /// @@ -322,7 +335,7 @@ where /// assert_eq!(b.first(), None); /// ``` pub fn first(&self) -> Option<&A> - where S: Data + where R: Referent { if self.is_empty() { None @@ -347,7 +360,7 @@ where /// assert_eq!(b.first_mut(), None); /// ``` pub fn first_mut(&mut self) -> Option<&mut A> - where S: DataMut + where R: Referent { if self.is_empty() { None @@ -372,7 +385,7 @@ where /// assert_eq!(b.last(), None); /// ``` pub fn last(&self) -> Option<&A> - where S: Data + where R: Referent { if self.is_empty() { None @@ -401,12 +414,11 @@ where /// assert_eq!(b.last_mut(), None); /// ``` pub fn last_mut(&mut self) -> Option<&mut A> - where S: DataMut + where R: Referent { if self.is_empty() { None } else { - self.ensure_unique(); let mut index = self.raw_dim(); for ax in 0..index.ndim() { index[ax] -= 1; @@ -422,9 +434,9 @@ where /// /// Iterator element type is `&A`. pub fn iter(&self) -> Iter<'_, A, D> - where S: Data + where R: Referent { - debug_assert!(self.pointer_is_inbounds()); + // debug_assert!(self.pointer_is_inbounds()); self.view().into_iter_() } @@ -435,7 +447,7 @@ where /// /// Iterator element type is `&mut A`. pub fn iter_mut(&mut self) -> IterMut<'_, A, D> - where S: DataMut + where R: Referent { self.view_mut().into_iter_() } @@ -449,7 +461,7 @@ where /// /// See also [`Zip::indexed`] pub fn indexed_iter(&self) -> IndexedIter<'_, A, D> - where S: Data + where R: Referent { IndexedIter::new(self.view().into_elements_base()) } @@ -461,7 +473,7 @@ where /// /// Iterator element type is `(D::Pattern, &mut A)`. pub fn indexed_iter_mut(&mut self) -> IndexedIterMut<'_, A, D> - where S: DataMut + where R: Referent { IndexedIterMut::new(self.view_mut().into_elements_base()) } @@ -477,7 +489,7 @@ where pub fn slice(&self, info: I) -> ArrayView<'_, A, I::OutDim> where I: SliceArg, - S: Data, + R: Referent, { self.view().slice_move(info) } @@ -493,7 +505,7 @@ where pub fn slice_mut(&mut self, info: I) -> ArrayViewMut<'_, A, I::OutDim> where I: SliceArg, - S: DataMut, + R: Referent, { self.view_mut().slice_move(info) } @@ -525,11 +537,17 @@ where pub fn multi_slice_mut<'a, M>(&'a mut self, info: M) -> M::Output where M: MultiSliceArg<'a, A, D>, - S: DataMut, + R: Referent, { info.multi_slice_move(self.view_mut()) } +} +impl ArrayBase +where + S: RawData, + D: Dimension, +{ /// Slice the array, possibly changing the number of dimensions. /// /// See [*Slicing*](#slicing) for full documentation. @@ -585,7 +603,10 @@ where // safe because new dimension, strides allow access to a subset of old data unsafe { self.with_strides_dim(new_strides, new_dim) } } +} +impl LayoutRef +{ /// Slice the array in place without changing the number of dimensions. /// /// In particular, if an axis is sliced with an index, the axis is @@ -630,7 +651,10 @@ where }); debug_assert_eq!(axis, self.ndim()); } +} +impl RefBase +{ /// Return a view of the array, sliced along the specified axis. /// /// **Panics** if an index is out of bounds or step size is zero.
@@ -638,7 +662,7 @@ where #[track_caller] #[must_use = "slice_axis returns an array view with the sliced result"] pub fn slice_axis(&self, axis: Axis, indices: Slice) -> ArrayView<'_, A, D> - where S: Data + where R: Referent { let mut view = self.view(); view.slice_axis_inplace(axis, indices); @@ -652,13 +676,16 @@ where #[track_caller] #[must_use = "slice_axis_mut returns an array view with the sliced result"] pub fn slice_axis_mut(&mut self, axis: Axis, indices: Slice) -> ArrayViewMut<'_, A, D> - where S: DataMut + where R: Referent { let mut view_mut = self.view_mut(); view_mut.slice_axis_inplace(axis, indices); view_mut } +} +impl LayoutRef +{ /// Slice the array in place along the specified axis. /// /// **Panics** if an index is out of bounds or step size is zero.
@@ -671,9 +698,15 @@ where unsafe { self.ptr = self.ptr.offset(offset); } - debug_assert!(self.pointer_is_inbounds()); + // debug_assert!(self.pointer_is_inbounds()); } +} +impl ArrayBase +where + S: RawData, + D: Dimension, +{ /// Slice the array in place along the specified axis, then return the sliced array. /// /// **Panics** if an index is out of bounds or step size is zero.
@@ -684,7 +717,10 @@ where self.slice_axis_inplace(axis, indices); self } +} +impl RefBase +{ /// Return a view of a slice of the array, with a closure specifying the /// slice for each axis. /// @@ -696,7 +732,7 @@ where pub fn slice_each_axis(&self, f: F) -> ArrayView<'_, A, D> where F: FnMut(AxisDescription) -> Slice, - S: Data, + R: Referent, { let mut view = self.view(); view.slice_each_axis_inplace(f); @@ -714,13 +750,16 @@ where pub fn slice_each_axis_mut(&mut self, f: F) -> ArrayViewMut<'_, A, D> where F: FnMut(AxisDescription) -> Slice, - S: DataMut, + R: Referent, { let mut view = self.view_mut(); view.slice_each_axis_inplace(f); view } +} +impl LayoutRef +{ /// Slice the array in place, with a closure specifying the slice for each /// axis. /// @@ -743,7 +782,10 @@ where ) } } +} +impl RefBase +{ /// Return a reference to the element at `index`, or return `None` /// if the index is out of bounds. /// @@ -764,7 +806,7 @@ where /// ``` pub fn get(&self, index: I) -> Option<&A> where - S: Data, + R: Referent, I: NdIndex, { unsafe { self.get_ptr(index).map(|ptr| &*ptr) } @@ -796,7 +838,7 @@ where /// if the index is out of bounds. pub fn get_mut(&mut self, index: I) -> Option<&mut A> where - S: DataMut, + R: Referent, I: NdIndex, { unsafe { self.get_mut_ptr(index).map(|ptr| &mut *ptr) } @@ -820,9 +862,7 @@ where /// assert_eq!(a.get((0, 1)), Some(&5.)); /// ``` pub fn get_mut_ptr(&mut self, index: I) -> Option<*mut A> - where - S: RawDataMut, - I: NdIndex, + where I: NdIndex { // const and mut are separate to enforce &mutness as well as the // extra code in as_mut_ptr @@ -844,7 +884,7 @@ where #[inline] pub unsafe fn uget(&self, index: I) -> &A where - S: Data, + R: Referent, I: NdIndex, { arraytraits::debug_bounds_check(self, &index); @@ -869,10 +909,10 @@ where #[inline] pub unsafe fn uget_mut(&mut self, index: I) -> &mut A where - S: DataMut, + R: Referent, I: NdIndex, { - debug_assert!(self.data.is_unique()); + // debug_assert!(self.data.is_unique()); arraytraits::debug_bounds_check(self, &index); let off = index.index_unchecked(&self.strides); &mut *self.ptr.as_ptr().offset(off) @@ -886,7 +926,7 @@ where #[track_caller] pub fn swap(&mut self, index1: I, index2: I) where - S: DataMut, + R: Referent, I: NdIndex, { let ptr = self.as_mut_ptr(); @@ -919,10 +959,10 @@ where /// for `Array` and `ArrayViewMut`, but not for `ArcArray` or `CowArray`.) pub unsafe fn uswap(&mut self, index1: I, index2: I) where - S: DataMut, + R: Referent, I: NdIndex, { - debug_assert!(self.data.is_unique()); + // debug_assert!(self.data.is_unique()); arraytraits::debug_bounds_check(self, &index1); arraytraits::debug_bounds_check(self, &index2); let off1 = index1.index_unchecked(&self.strides); @@ -933,7 +973,7 @@ where // `get` for zero-dimensional arrays // panics if dimension is not zero. otherwise an element is always present. fn get_0d(&self) -> &A - where S: Data + where R: Referent { assert!(self.ndim() == 0); unsafe { &*self.as_ptr() } @@ -963,7 +1003,7 @@ where #[track_caller] pub fn index_axis(&self, axis: Axis, index: usize) -> ArrayView<'_, A, D::Smaller> where - S: Data, + R: Referent, D: RemoveAxis, { self.view().index_axis_move(axis, index) @@ -996,12 +1036,18 @@ where #[track_caller] pub fn index_axis_mut(&mut self, axis: Axis, index: usize) -> ArrayViewMut<'_, A, D::Smaller> where - S: DataMut, + R: Referent, D: RemoveAxis, { self.view_mut().index_axis_move(axis, index) } +} +impl ArrayBase +where + S: RawData, + D: Dimension, +{ /// Collapses the array to `index` along the axis and removes the axis. /// /// See [`.index_axis()`](Self::index_axis) and [*Subviews*](#subviews) for full documentation. @@ -1017,7 +1063,10 @@ where // safe because new dimension, strides allow access to a subset of old data unsafe { self.with_strides_dim(strides, dim) } } +} +impl LayoutRef +{ /// Selects `index` along the axis, collapsing the axis into length one. /// /// **Panics** if `axis` or `index` is out of bounds. @@ -1026,9 +1075,12 @@ where { let offset = dimension::do_collapse_axis(&mut self.dim, &self.strides, axis.index(), index); self.ptr = unsafe { self.ptr.offset(offset) }; - debug_assert!(self.pointer_is_inbounds()); + // debug_assert!(self.pointer_is_inbounds()); } +} +impl RefBase +{ /// Along `axis`, select arbitrary subviews corresponding to `indices` /// and copy them into a new array. /// @@ -1054,7 +1106,7 @@ where pub fn select(&self, axis: Axis, indices: &[Ix]) -> Array where A: Clone, - S: Data, + R: Referent, D: RemoveAxis, { if self.ndim() == 1 { @@ -1116,7 +1168,7 @@ where /// } /// ``` pub fn rows(&self) -> Lanes<'_, A, D::Smaller> - where S: Data + where R: Referent { let mut n = self.ndim(); if n == 0 { @@ -1130,7 +1182,7 @@ where /// /// Iterator element is `ArrayView1
` (1D read-write array view). pub fn rows_mut(&mut self) -> LanesMut<'_, A, D::Smaller> - where S: DataMut + where R: Referent { let mut n = self.ndim(); if n == 0 { @@ -1166,7 +1218,7 @@ where /// } /// ``` pub fn columns(&self) -> Lanes<'_, A, D::Smaller> - where S: Data + where R: Referent { Lanes::new(self.view(), Axis(0)) } @@ -1176,7 +1228,7 @@ where /// /// Iterator element is `ArrayView1` (1D read-write array view). pub fn columns_mut(&mut self) -> LanesMut<'_, A, D::Smaller> - where S: DataMut + where R: Referent { LanesMut::new(self.view_mut(), Axis(0)) } @@ -1210,7 +1262,7 @@ where /// assert_eq!(inner2.into_iter().next().unwrap(), aview1(&[0, 1, 2])); /// ``` pub fn lanes(&self, axis: Axis) -> Lanes<'_, A, D::Smaller> - where S: Data + where R: Referent { Lanes::new(self.view(), axis) } @@ -1220,7 +1272,7 @@ where /// /// Iterator element is `ArrayViewMut1` (1D read-write array view). pub fn lanes_mut(&mut self, axis: Axis) -> LanesMut<'_, A, D::Smaller> - where S: DataMut + where R: Referent { LanesMut::new(self.view_mut(), axis) } @@ -1234,7 +1286,7 @@ where #[allow(deprecated)] pub fn outer_iter(&self) -> AxisIter<'_, A, D::Smaller> where - S: Data, + R: Referent, D: RemoveAxis, { self.view().into_outer_iter() @@ -1249,7 +1301,7 @@ where #[allow(deprecated)] pub fn outer_iter_mut(&mut self) -> AxisIterMut<'_, A, D::Smaller> where - S: DataMut, + R: Referent, D: RemoveAxis, { self.view_mut().into_outer_iter() @@ -1273,7 +1325,7 @@ where #[track_caller] pub fn axis_iter(&self, axis: Axis) -> AxisIter<'_, A, D::Smaller> where - S: Data, + R: Referent, D: RemoveAxis, { AxisIter::new(self.view(), axis) @@ -1289,7 +1341,7 @@ where #[track_caller] pub fn axis_iter_mut(&mut self, axis: Axis) -> AxisIterMut<'_, A, D::Smaller> where - S: DataMut, + R: Referent, D: RemoveAxis, { AxisIterMut::new(self.view_mut(), axis) @@ -1323,7 +1375,7 @@ where /// ``` #[track_caller] pub fn axis_chunks_iter(&self, axis: Axis, size: usize) -> AxisChunksIter<'_, A, D> - where S: Data + where R: Referent { AxisChunksIter::new(self.view(), axis, size) } @@ -1336,7 +1388,7 @@ where /// **Panics** if `axis` is out of bounds or if `size` is zero. #[track_caller] pub fn axis_chunks_iter_mut(&mut self, axis: Axis, size: usize) -> AxisChunksIterMut<'_, A, D> - where S: DataMut + where R: Referent { AxisChunksIterMut::new(self.view_mut(), axis, size) } @@ -1356,7 +1408,7 @@ where pub fn exact_chunks(&self, chunk_size: E) -> ExactChunks<'_, A, D> where E: IntoDimension, - S: Data, + R: Referent, { ExactChunks::new(self.view(), chunk_size) } @@ -1397,7 +1449,7 @@ where pub fn exact_chunks_mut(&mut self, chunk_size: E) -> ExactChunksMut<'_, A, D> where E: IntoDimension, - S: DataMut, + R: Referent, { ExactChunksMut::new(self.view_mut(), chunk_size) } @@ -1412,7 +1464,7 @@ where pub fn windows(&self, window_size: E) -> Windows<'_, A, D> where E: IntoDimension, - S: Data, + R: Referent, { Windows::new(self.view(), window_size) } @@ -1465,7 +1517,7 @@ where pub fn windows_with_stride(&self, window_size: E, stride: E) -> Windows<'_, A, D> where E: IntoDimension, - S: Data, + R: Referent, { Windows::new_with_stride(self.view(), window_size, stride) } @@ -1492,7 +1544,7 @@ where /// } /// ``` pub fn axis_windows(&self, axis: Axis, window_size: usize) -> AxisWindows<'_, A, D> - where S: Data + where R: Referent { let axis_index = axis.index(); @@ -1509,32 +1561,41 @@ where AxisWindows::new(self.view(), axis, window_size) } +} - // Return (length, stride) for diagonal - fn diag_params(&self) -> (Ix, Ixs) - { - /* empty shape has len 1 */ - let len = self.dim.slice().iter().cloned().min().unwrap_or(1); - let stride = self.strides().iter().sum(); - (len, stride) - } - +impl RefBase +{ /// Return a view of the diagonal elements of the array. /// /// The diagonal is simply the sequence indexed by *(0, 0, .., 0)*, /// *(1, 1, ..., 1)* etc as long as all axes have elements. pub fn diag(&self) -> ArrayView1<'_, A> - where S: Data + where R: Referent { self.view().into_diag() } /// Return a read-write view over the diagonal elements of the array. pub fn diag_mut(&mut self) -> ArrayViewMut1<'_, A> - where S: DataMut + where R: Referent { self.view_mut().into_diag() } +} + +impl ArrayBase +where + S: RawData, + D: Dimension, +{ + // Return (length, stride) for diagonal + fn diag_params(&self) -> (Ix, Ixs) + { + /* empty shape has len 1 */ + let len = self.dim.slice().iter().cloned().min().unwrap_or(1); + let stride = self.as_ref().strides().iter().sum(); + (len, stride) + } /// Return the diagonal as a one-dimensional array. pub fn into_diag(self) -> ArrayBase @@ -1567,7 +1628,10 @@ where S::ensure_unique(self); debug_assert!(self.pointer_is_inbounds()); } +} +impl LayoutRef +{ /// Return `true` if the array data is laid out in contiguous “C order” in /// memory (where the last index is the most rapidly varying). /// @@ -1583,7 +1647,10 @@ where { D::is_contiguous(&self.dim, &self.strides) } +} +impl RefBase +{ /// Return a standard-layout array containing the data, cloning if /// necessary. /// @@ -1608,7 +1675,7 @@ where /// ``` pub fn as_standard_layout(&self) -> CowArray<'_, A, D> where - S: Data, + R: Referent, A: Clone, { if self.is_standard_layout() { @@ -1641,6 +1708,19 @@ where self.ptr.as_ptr() as *const A } + /// Return a mutable pointer to the first element in the array reference. + #[inline(always)] + pub fn as_mut_ptr(&mut self) -> *mut A + { + self.ptr.as_ptr() + } +} + +impl ArrayBase +where + S: RawData, + D: Dimension, +{ /// Return a mutable pointer to the first element in the array. /// /// This method attempts to unshare the data. If `S: DataMut`, then the @@ -1658,7 +1738,10 @@ where self.try_ensure_unique(); // for ArcArray self.ptr.as_ptr() } +} +impl RefBase +{ /// Return a raw view of the array. #[inline] pub fn raw_view(&self) -> RawArrayView @@ -1666,6 +1749,19 @@ where unsafe { RawArrayView::new(self.ptr, self.dim.clone(), self.strides.clone()) } } + /// Return a raw mutable view of the array. + #[inline] + pub fn raw_view_mut(&mut self) -> RawArrayViewMut + { + unsafe { RawArrayViewMut::new(self.ptr, self.dim.clone(), self.strides.clone()) } + } +} + +impl ArrayBase +where + S: RawData, + D: Dimension, +{ /// Return a raw mutable view of the array. /// /// This method attempts to unshare the data. If `S: DataMut`, then the @@ -1688,13 +1784,55 @@ where RawArrayViewMut::new(self.ptr, self.dim.clone(), self.strides.clone()) } + /// Return the array’s data as a slice, if it is contiguous and in standard order. + /// Return `None` otherwise. + pub fn as_slice_mut(&mut self) -> Option<&mut [A]> + where S: DataMut + { + if self.is_standard_layout() { + self.ensure_unique(); + unsafe { Some(slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len())) } + } else { + None + } + } + + /// Return the array’s data as a slice if it is contiguous, + /// return `None` otherwise. + /// + /// In the contiguous case, in order to return a unique reference, this + /// method unshares the data if necessary, but it preserves the existing + /// strides. + pub fn as_slice_memory_order_mut(&mut self) -> Option<&mut [A]> + where S: DataMut + { + self.try_as_slice_memory_order_mut().ok() + } + + /// Return the array’s data as a slice if it is contiguous, otherwise + /// return `self` in the `Err` variant. + pub(crate) fn try_as_slice_memory_order_mut(&mut self) -> Result<&mut [A], &mut Self> + where S: DataMut + { + if self.is_contiguous() { + self.ensure_unique(); + let offset = offset_from_low_addr_ptr_to_logical_ptr(&self.dim, &self.strides); + unsafe { Ok(slice::from_raw_parts_mut(self.ptr.sub(offset).as_ptr(), self.len())) } + } else { + Err(self) + } + } +} + +impl RefBase +{ /// Return the array’s data as a slice, if it is contiguous and in standard order. /// Return `None` otherwise. /// /// If this function returns `Some(_)`, then the element order in the slice /// corresponds to the logical order of the array’s elements. pub fn as_slice(&self) -> Option<&[A]> - where S: Data + where R: Referent { if self.is_standard_layout() { unsafe { Some(slice::from_raw_parts(self.ptr.as_ptr(), self.len())) } @@ -1706,10 +1844,9 @@ where /// Return the array’s data as a slice, if it is contiguous and in standard order. /// Return `None` otherwise. pub fn as_slice_mut(&mut self) -> Option<&mut [A]> - where S: DataMut + where R: Referent { if self.is_standard_layout() { - self.ensure_unique(); unsafe { Some(slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len())) } } else { None @@ -1722,7 +1859,7 @@ where /// If this function returns `Some(_)`, then the elements in the slice /// have whatever order the elements have in memory. pub fn as_slice_memory_order(&self) -> Option<&[A]> - where S: Data + where R: Referent { if self.is_contiguous() { let offset = offset_from_low_addr_ptr_to_logical_ptr(&self.dim, &self.strides); @@ -1739,7 +1876,7 @@ where /// method unshares the data if necessary, but it preserves the existing /// strides. pub fn as_slice_memory_order_mut(&mut self) -> Option<&mut [A]> - where S: DataMut + where R: Referent { self.try_as_slice_memory_order_mut().ok() } @@ -1747,10 +1884,9 @@ where /// Return the array’s data as a slice if it is contiguous, otherwise /// return `self` in the `Err` variant. pub(crate) fn try_as_slice_memory_order_mut(&mut self) -> Result<&mut [A], &mut Self> - where S: DataMut + where R: Referent { if self.is_contiguous() { - self.ensure_unique(); let offset = offset_from_low_addr_ptr_to_logical_ptr(&self.dim, &self.strides); unsafe { Ok(slice::from_raw_parts_mut(self.ptr.sub(offset).as_ptr(), self.len())) } } else { @@ -1817,7 +1953,7 @@ where where E: ShapeArg, A: Clone, - S: Data, + R: Referent, { let (shape, order) = new_shape.into_shape_and_order(); self.to_shape_order(shape, order.unwrap_or(Order::RowMajor)) @@ -1827,7 +1963,7 @@ where where E: Dimension, A: Clone, - S: Data, + R: Referent, { let len = self.dim.size(); if size_of_shape_checked(&shape) != Ok(len) { @@ -1861,7 +1997,13 @@ where Ok(CowArray::from(Array::from_shape_trusted_iter_unchecked(shape, view.into_iter(), A::clone))) } } +} +impl ArrayBase +where + S: RawData, + D: Dimension, +{ /// Transform the array into `shape`; any shape with the same number of /// elements is accepted, but the source array must be contiguous. /// @@ -1997,6 +2139,7 @@ where S: DataOwned, A: Clone, E: ShapeArg, + S::RefType: Referent, { let (shape, order) = shape.into_shape_and_order(); let order = order.unwrap_or(Order::RowMajor); @@ -2008,6 +2151,7 @@ where S: DataOwned, A: Clone, E: Dimension, + S::RefType: Referent, { let len = self.dim.size(); if size_of_shape_checked(&shape) != Ok(len) { @@ -2073,6 +2217,7 @@ where S: DataShared + DataOwned, A: Clone, E: IntoDimension, + S::RefType: Referent, { let shape = shape.into_dimension(); if size_of_shape_checked(&shape) != Ok(self.dim.size()) { @@ -2092,7 +2237,10 @@ where unsafe { ArrayBase::from_shape_vec_unchecked(shape, v) } } } +} +impl RefBase +{ /// Flatten the array to a one-dimensional array. /// /// The array is returned as a `CowArray`; a view if possible, otherwise an owned array. @@ -2107,7 +2255,7 @@ where pub fn flatten(&self) -> CowArray<'_, A, Ix1> where A: Clone, - S: Data, + R: Referent, { self.flatten_with_order(Order::RowMajor) } @@ -2130,11 +2278,17 @@ where pub fn flatten_with_order(&self, order: Order) -> CowArray<'_, A, Ix1> where A: Clone, - S: Data, + R: Referent, { self.to_shape((self.len(), order)).unwrap() } +} +impl ArrayBase +where + S: RawData, + D: Dimension, +{ /// Flatten the array to a one-dimensional array, consuming the array. /// /// If possible, no copy is made, and the new array use the same memory as the original array. @@ -2151,6 +2305,7 @@ where where A: Clone, S: DataOwned, + S::RefType: Referent, { let len = self.len(); self.into_shape_clone(Ix1(len)).unwrap() @@ -2169,7 +2324,8 @@ where { // safe because new dims equivalent unsafe { - ArrayBase::from_data_ptr(self.data, self.ptr).with_strides_dim(self.strides.into_dyn(), self.dim.into_dyn()) + ArrayBase::from_data_ptr(self.data, self.layout.ptr) + .with_strides_dim(self.layout.strides.into_dyn(), self.layout.dim.into_dyn()) } } @@ -2195,9 +2351,9 @@ where unsafe { if D::NDIM == D2::NDIM { // safe because D == D2 - let dim = unlimited_transmute::(self.dim); - let strides = unlimited_transmute::(self.strides); - return Ok(ArrayBase::from_data_ptr(self.data, self.ptr).with_strides_dim(strides, dim)); + let dim = unlimited_transmute::(self.layout.dim); + let strides = unlimited_transmute::(self.layout.strides); + return Ok(ArrayBase::from_data_ptr(self.data, self.layout.ptr).with_strides_dim(strides, dim)); } else if D::NDIM.is_none() || D2::NDIM.is_none() { // one is dynamic dim // safe because dim, strides are equivalent under a different type @@ -2210,7 +2366,10 @@ where } Err(ShapeError::from_kind(ErrorKind::IncompatibleShape)) } +} +impl RefBase +{ /// Act like a larger size and/or shape array by *broadcasting* /// into a larger shape, if possible. /// @@ -2243,7 +2402,7 @@ where pub fn broadcast(&self, dim: E) -> Option> where E: IntoDimension, - S: Data, + R: Referent, { /// Return new stride when trying to grow `from` into shape `to` /// @@ -2311,12 +2470,12 @@ where /// /// Return `ShapeError` if their shapes can not be broadcast together. #[allow(clippy::type_complexity)] - pub(crate) fn broadcast_with<'a, 'b, B, S2, E>( - &'a self, other: &'b ArrayBase, + pub(crate) fn broadcast_with<'a, 'b, B, R2, E>( + &'a self, other: &'b RefBase, ) -> Result<(ArrayView<'a, A, DimMaxOf>, ArrayView<'b, B, DimMaxOf>), ShapeError> where - S: Data, - S2: Data, + R: Referent, + R2: Referent, D: Dimension + DimMax, E: Dimension, { @@ -2342,7 +2501,10 @@ where }; Ok((view1, view2)) } +} +impl LayoutRef +{ /// Swap axes `ax` and `bx`. /// /// This does not move any data, it just adjusts the array’s dimensions @@ -2365,7 +2527,13 @@ where self.dim.slice_mut().swap(ax, bx); self.strides.slice_mut().swap(ax, bx); } +} +impl ArrayBase +where + S: RawData, + D: Dimension, +{ /// Permute the axes. /// /// This does not move any data, it just adjusts the array’s dimensions @@ -2422,22 +2590,28 @@ where /// while retaining the same data. pub fn reversed_axes(mut self) -> ArrayBase { - self.dim.slice_mut().reverse(); - self.strides.slice_mut().reverse(); + self.layout.dim.slice_mut().reverse(); + self.layout.strides.slice_mut().reverse(); self } +} +impl RefBase +{ /// Return a transposed view of the array. /// /// This is a shorthand for `self.view().reversed_axes()`. /// /// See also the more general methods `.reversed_axes()` and `.swap_axes()`. pub fn t(&self) -> ArrayView<'_, A, D> - where S: Data + where R: Referent { self.view().reversed_axes() } +} +impl LayoutRef +{ /// Return an iterator over the length and stride of each axis. pub fn axes(&self) -> Axes<'_, D> { @@ -2514,7 +2688,13 @@ where { merge_axes(&mut self.dim, &mut self.strides, take, into) } +} +impl ArrayBase +where + S: RawData, + D: Dimension, +{ /// Insert new array axis at `axis` and return the result. /// /// ``` @@ -2565,18 +2745,21 @@ where { self.data._is_pointer_inbounds(self.as_ptr()) } +} +impl RefBase +{ /// Perform an elementwise assigment to `self` from `rhs`. /// /// If their shapes disagree, `rhs` is broadcast to the shape of `self`. /// /// **Panics** if broadcasting isn’t possible. #[track_caller] - pub fn assign(&mut self, rhs: &ArrayBase) + pub fn assign(&mut self, rhs: &RefBase) where - S: DataMut, + R: Referent, A: Clone, - S2: Data, + R2: Referent, { self.zip_mut_with(rhs, |x, y| x.clone_from(y)); } @@ -2590,7 +2773,7 @@ where #[track_caller] pub fn assign_to

(&self, to: P) where - S: Data, + R: Referent, P: IntoNdProducer, P::Item: AssignElem, A: Clone, @@ -2601,16 +2784,16 @@ where /// Perform an elementwise assigment to `self` from element `x`. pub fn fill(&mut self, x: A) where - S: DataMut, + R: Referent, A: Clone, { self.map_inplace(move |elt| elt.clone_from(&x)); } - pub(crate) fn zip_mut_with_same_shape(&mut self, rhs: &ArrayBase, mut f: F) + pub(crate) fn zip_mut_with_same_shape(&mut self, rhs: &RefBase, mut f: F) where - S: DataMut, - S2: Data, + R: Referent, + R2: Referent, E: Dimension, F: FnMut(&mut A, &B), { @@ -2633,10 +2816,10 @@ where // zip two arrays where they have different layout or strides #[inline(always)] - fn zip_mut_with_by_rows(&mut self, rhs: &ArrayBase, mut f: F) + fn zip_mut_with_by_rows(&mut self, rhs: &RefBase, mut f: F) where - S: DataMut, - S2: Data, + R: Referent, + R2: Referent, E: Dimension, F: FnMut(&mut A, &B), { @@ -2653,7 +2836,7 @@ where fn zip_mut_with_elem(&mut self, rhs_elem: &B, mut f: F) where - S: DataMut, + R: Referent, F: FnMut(&mut A, &B), { self.map_inplace(move |elt| f(elt, rhs_elem)); @@ -2667,10 +2850,10 @@ where /// **Panics** if broadcasting isn’t possible. #[track_caller] #[inline] - pub fn zip_mut_with(&mut self, rhs: &ArrayBase, f: F) + pub fn zip_mut_with(&mut self, rhs: &RefBase, f: F) where - S: DataMut, - S2: Data, + R: Referent, + R2: Referent, E: Dimension, F: FnMut(&mut A, &B), { @@ -2693,13 +2876,13 @@ where where F: FnMut(B, &'a A) -> B, A: 'a, - S: Data, + R: Referent, { if let Some(slc) = self.as_slice_memory_order() { slc.iter().fold(init, f) } else { let mut v = self.view(); - move_min_stride_axis_to_last(&mut v.dim, &mut v.strides); + move_min_stride_axis_to_last(&mut v.layout.dim, &mut v.layout.strides); v.into_elements_base().fold(init, f) } } @@ -2726,7 +2909,7 @@ where where F: FnMut(&'a A) -> B, A: 'a, - S: Data, + R: Referent, { unsafe { if let Some(slc) = self.as_slice_memory_order() { @@ -2751,7 +2934,7 @@ where where F: FnMut(&'a mut A) -> B, A: 'a, - S: DataMut, + R: Referent, { let dim = self.dim.clone(); if self.is_contiguous() { @@ -2784,11 +2967,17 @@ where where F: FnMut(A) -> B, A: Clone, - S: Data, + R: Referent, { self.map(move |x| f(x.clone())) } +} +impl ArrayBase +where + S: RawData, + D: Dimension, +{ /// Call `f` by **v**alue on each element, update the array with the new values /// and return it. /// @@ -2798,6 +2987,7 @@ where S: DataMut, F: FnMut(A) -> A, A: Clone, + S::RefType: Referent, { self.mapv_inplace(f); self @@ -2823,6 +3013,7 @@ where F: FnMut(A) -> B, A: Clone + 'static, B: 'static, + S::RefType: Referent, { if core::any::TypeId::of::() == core::any::TypeId::of::() { // A and B are the same type. @@ -2844,13 +3035,16 @@ where self.mapv(f) } } +} +impl RefBase +{ /// Modify the array in place by calling `f` by mutable reference on each element. /// /// Elements are visited in arbitrary order. pub fn map_inplace<'a, F>(&'a mut self, f: F) where - S: DataMut, + R: Referent, A: 'a, F: FnMut(&'a mut A), { @@ -2858,7 +3052,7 @@ where Ok(slc) => slc.iter_mut().for_each(f), Err(arr) => { let mut v = arr.view_mut(); - move_min_stride_axis_to_last(&mut v.dim, &mut v.strides); + move_min_stride_axis_to_last(&mut v.layout.dim, &mut v.layout.strides); v.into_elements_base().for_each(f); } } @@ -2887,7 +3081,7 @@ where /// ``` pub fn mapv_inplace(&mut self, mut f: F) where - S: DataMut, + R: Referent, F: FnMut(A) -> A, A: Clone, { @@ -2901,7 +3095,7 @@ where where F: FnMut(&'a A), A: 'a, - S: Data, + R: Referent, { self.fold((), move |(), elt| f(elt)) } @@ -2920,7 +3114,7 @@ where D: RemoveAxis, F: FnMut(&B, &A) -> B, B: Clone, - S: Data, + R: Referent, { let mut res = Array::from_elem(self.raw_dim().remove_axis(axis), init); for subview in self.axis_iter(axis) { @@ -2943,7 +3137,7 @@ where D: RemoveAxis, F: FnMut(ArrayView1<'a, A>) -> B, A: 'a, - S: Data, + R: Referent, { if self.len_of(axis) == 0 { let new_dim = self.dim.remove_axis(axis); @@ -2969,7 +3163,7 @@ where D: RemoveAxis, F: FnMut(ArrayViewMut1<'a, A>) -> B, A: 'a, - S: DataMut, + R: Referent, { if self.len_of(axis) == 0 { let new_dim = self.dim.remove_axis(axis); @@ -2991,7 +3185,7 @@ where /// ***Panics*** if `axis` is out of bounds
/// ***Panics*** if not `index < self.len_of(axis)`. pub fn remove_index(&mut self, axis: Axis, index: usize) - where S: DataOwned + DataMut + where R: Referent // TODO: Check whether this needed to be DataOwned { assert!(index < self.len_of(axis), "index {} must be less than length of Axis({})", index, axis.index()); @@ -3033,7 +3227,7 @@ where pub fn accumulate_axis_inplace(&mut self, axis: Axis, mut f: F) where F: FnMut(&A, &mut A), - S: DataMut, + R: Referent, { if self.len_of(axis) <= 1 { return; diff --git a/src/impl_ops.rs b/src/impl_ops.rs index 46ea18a7c..7d2eb412b 100644 --- a/src/impl_ops.rs +++ b/src/impl_ops.rs @@ -7,6 +7,7 @@ // except according to those terms. use crate::dimension::DimMax; +use crate::Referent; use crate::Zip; use num_complex::Complex; @@ -70,6 +71,8 @@ where S2: Data, D: Dimension + DimMax, E: Dimension, + S::RefType: Referent, + S2::RefType: Referent, { type Output = ArrayBase>::Output>; #[track_caller] @@ -98,6 +101,8 @@ where S2: Data, D: Dimension + DimMax, E: Dimension, + S::RefType: Referent, + S2::RefType: Referent, { type Output = ArrayBase>::Output>; #[track_caller] @@ -139,6 +144,8 @@ where S2: DataOwned + DataMut, D: Dimension, E: Dimension + DimMax, + S::RefType: Referent, + S2::RefType: Referent, { type Output = ArrayBase>::Output>; #[track_caller] @@ -179,6 +186,8 @@ where S2: Data, D: Dimension + DimMax, E: Dimension, + S::RefType: Referent, + S2::RefType: Referent, { type Output = Array>::Output>; #[track_caller] @@ -205,6 +214,7 @@ impl $trt for ArrayBase S: DataOwned + DataMut, D: Dimension, B: ScalarOperand, + S::RefType: Referent, { type Output = ArrayBase; fn $mth(mut self, x: B) -> ArrayBase { @@ -224,6 +234,7 @@ impl<'a, A, S, D, B> $trt for &'a ArrayBase S: Data, D: Dimension, B: ScalarOperand, + S::RefType: Referent, { type Output = Array; fn $mth(self, x: B) -> Self::Output { @@ -254,6 +265,7 @@ macro_rules! impl_scalar_lhs_op { impl $trt> for $scalar where S: DataOwned + DataMut, D: Dimension, + S::RefType: Referent, { type Output = ArrayBase; fn $mth(self, rhs: ArrayBase) -> ArrayBase { @@ -275,6 +287,7 @@ impl $trt> for $scalar impl<'a, S, D> $trt<&'a ArrayBase> for $scalar where S: Data, D: Dimension, + S::RefType: Referent, { type Output = Array<$scalar, D>; fn $mth(self, rhs: &ArrayBase) -> Self::Output { @@ -379,6 +392,7 @@ mod arithmetic_ops A: Clone + Neg, S: DataOwned + DataMut, D: Dimension, + S::RefType: Referent, { type Output = Self; /// Perform an elementwise negation of `self` and return the result. @@ -396,6 +410,7 @@ mod arithmetic_ops &'a A: 'a + Neg, S: Data, D: Dimension, + S::RefType: Referent, { type Output = Array; /// Perform an elementwise negation of reference `self` and return the @@ -411,6 +426,7 @@ mod arithmetic_ops A: Clone + Not, S: DataOwned + DataMut, D: Dimension, + S::RefType: Referent, { type Output = Self; /// Perform an elementwise unary not of `self` and return the result. @@ -428,6 +444,7 @@ mod arithmetic_ops &'a A: 'a + Not, S: Data, D: Dimension, + S::RefType: Referent, { type Output = Array; /// Perform an elementwise unary not of reference `self` and return the @@ -459,6 +476,8 @@ mod assign_ops S2: Data, D: Dimension, E: Dimension, + S::RefType: Referent, + S2::RefType: Referent, { #[track_caller] fn $method(&mut self, rhs: &ArrayBase) { @@ -474,6 +493,7 @@ mod assign_ops A: ScalarOperand + $trt
, S: DataMut, D: Dimension, + S::RefType: Referent, { fn $method(&mut self, rhs: A) { self.map_inplace(move |elt| { diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs index 5b6727d17..5bf068a7e 100644 --- a/src/impl_owned_array.rs +++ b/src/impl_owned_array.rs @@ -746,7 +746,7 @@ where D: Dimension sort_axes_in_default_order_tandem(&mut tail_view, &mut array); debug_assert!(tail_view.is_standard_layout(), "not std layout dim: {:?}, strides: {:?}", - tail_view.shape(), ArrayBase::strides(&tail_view)); + tail_view.shape(), (&**tail_view).strides()); } // Keep track of currently filled length of `self.data` and update it @@ -909,7 +909,7 @@ pub(crate) unsafe fn drop_unreachable_raw( // iter is a raw pointer iterator traversing the array in memory order now with the // sorted axes. - let mut iter = Baseiter::new(self_.ptr, self_.dim, self_.strides); + let mut iter = Baseiter::new(self_.layout.ptr, self_.layout.dim, self_.layout.strides); let mut dropped_elements = 0; let mut last_ptr = data_ptr; @@ -948,7 +948,7 @@ where if a.ndim() <= 1 { return; } - sort_axes1_impl(&mut a.dim, &mut a.strides); + sort_axes1_impl(&mut a.layout.dim, &mut a.layout.strides); } fn sort_axes1_impl(adim: &mut D, astrides: &mut D) @@ -988,7 +988,7 @@ where if a.ndim() <= 1 { return; } - sort_axes2_impl(&mut a.dim, &mut a.strides, &mut b.dim, &mut b.strides); + sort_axes2_impl(&mut a.layout.dim, &mut a.layout.strides, &mut b.layout.dim, &mut b.layout.strides); } fn sort_axes2_impl(adim: &mut D, astrides: &mut D, bdim: &mut D, bstrides: &mut D) diff --git a/src/impl_raw_views.rs b/src/impl_raw_views.rs index 5132b1158..9ea69e2d2 100644 --- a/src/impl_raw_views.rs +++ b/src/impl_raw_views.rs @@ -101,7 +101,7 @@ where D: Dimension is_aligned(self.ptr.as_ptr()), "The pointer must be aligned." ); - ArrayView::new(self.ptr, self.dim, self.strides) + ArrayView::new(self.layout.ptr, self.layout.dim, self.layout.strides) } /// Split the array view along `axis` and return one array pointer strictly @@ -126,10 +126,10 @@ where D: Dimension dim_left.set_axis(axis, index); let left = unsafe { Self::new_(left_ptr, dim_left, self.strides.clone()) }; - let mut dim_right = self.dim; + let mut dim_right = self.layout.dim; let right_len = dim_right.axis(axis) - index; dim_right.set_axis(axis, right_len); - let right = unsafe { Self::new_(right_ptr, dim_right, self.strides) }; + let right = unsafe { Self::new_(right_ptr, dim_right, self.layout.strides) }; (left, right) } @@ -153,7 +153,7 @@ where D: Dimension "size mismatch in raw view cast" ); let ptr = self.ptr.cast::(); - unsafe { RawArrayView::new(ptr, self.dim, self.strides) } + unsafe { RawArrayView::new(ptr, self.layout.dim, self.layout.strides) } } } @@ -308,7 +308,7 @@ where D: Dimension #[inline] pub(crate) fn into_raw_view(self) -> RawArrayView { - unsafe { RawArrayView::new(self.ptr, self.dim, self.strides) } + unsafe { RawArrayView::new(self.ptr, self.layout.dim, self.layout.strides) } } /// Converts to a read-only view of the array. @@ -326,7 +326,7 @@ where D: Dimension is_aligned(self.ptr.as_ptr()), "The pointer must be aligned." ); - ArrayView::new(self.ptr, self.dim, self.strides) + ArrayView::new(self.ptr, self.layout.dim, self.layout.strides) } /// Converts to a mutable view of the array. @@ -344,7 +344,7 @@ where D: Dimension is_aligned(self.ptr.as_ptr()), "The pointer must be aligned." ); - ArrayViewMut::new(self.ptr, self.dim, self.strides) + ArrayViewMut::new(self.layout.ptr, self.layout.dim, self.layout.strides) } /// Split the array view along `axis` and return one array pointer strictly @@ -356,7 +356,12 @@ where D: Dimension pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self) { let (left, right) = self.into_raw_view().split_at(axis, index); - unsafe { (Self::new(left.ptr, left.dim, left.strides), Self::new(right.ptr, right.dim, right.strides)) } + unsafe { + ( + Self::new(left.layout.ptr, left.layout.dim, left.layout.strides), + Self::new(right.layout.ptr, right.layout.dim, right.layout.strides), + ) + } } /// Cast the raw pointer of the raw array view to a different type @@ -378,7 +383,7 @@ where D: Dimension "size mismatch in raw view cast" ); let ptr = self.ptr.cast::(); - unsafe { RawArrayViewMut::new(ptr, self.dim, self.strides) } + unsafe { RawArrayViewMut::new(ptr, self.layout.dim, self.layout.strides) } } } @@ -392,8 +397,8 @@ where D: Dimension let Complex { re, im } = self.into_raw_view().split_complex(); unsafe { Complex { - re: RawArrayViewMut::new(re.ptr, re.dim, re.strides), - im: RawArrayViewMut::new(im.ptr, im.dim, im.strides), + re: RawArrayViewMut::new(re.ptr, re.layout.dim, re.layout.strides), + im: RawArrayViewMut::new(im.ptr, im.layout.dim, im.layout.strides), } } } diff --git a/src/impl_special_element_types.rs b/src/impl_special_element_types.rs index e430b20bc..42b524bc2 100644 --- a/src/impl_special_element_types.rs +++ b/src/impl_special_element_types.rs @@ -9,6 +9,7 @@ use std::mem::MaybeUninit; use crate::imp_prelude::*; +use crate::LayoutRef; use crate::RawDataSubst; /// Methods specific to arrays with `MaybeUninit` elements. @@ -35,9 +36,7 @@ where { let ArrayBase { data, - ptr, - dim, - strides, + layout: LayoutRef { ptr, dim, strides }, } = self; // "transmute" from storage of MaybeUninit to storage of A diff --git a/src/layoutref.rs b/src/layoutref.rs new file mode 100644 index 000000000..0804452f3 --- /dev/null +++ b/src/layoutref.rs @@ -0,0 +1,128 @@ +//! Reference type for layouts + +use core::ops::{Deref, DerefMut}; + +use crate::{ArrayBase, LayoutRef, RawData, RefBase}; + +impl AsRef> for LayoutRef +{ + fn as_ref(&self) -> &LayoutRef + { + self + } +} + +impl AsMut> for LayoutRef +{ + fn as_mut(&mut self) -> &mut LayoutRef + { + self + } +} + +impl AsRef> for ArrayBase +where S: RawData +{ + fn as_ref(&self) -> &LayoutRef + { + // SAFETY: The pointer will hold all the guarantees of `as_ref`: + // - The pointer is aligned because neither type use repr(align) + // - It is "dereferencable" because it just points to self + // - For the same reason, it is initialized + unsafe { + (self as *const Self) + .cast::>() + .as_ref() + } + .expect("Pointer to self will always be non-null") + } +} + +impl AsMut> for ArrayBase +where S: RawData +{ + fn as_mut(&mut self) -> &mut LayoutRef + { + // SAFETY: The pointer will hold all the guarantees of `as_ref`: + // - The pointer is aligned because neither type use repr(align) + // - It is "dereferencable" because it just points to self + // - For the same reason, it is initialized + unsafe { (self as *mut Self).cast::>().as_mut() } + .expect("Pointer to self will always be non-null") + } +} + +impl Deref for RefBase +{ + type Target = LayoutRef; + + fn deref(&self) -> &Self::Target + { + unsafe { + (&self.layout as *const LayoutRef) + .cast::>() + .as_ref() + } + .expect("Pointers to parts will never be null") + } +} + +impl DerefMut for RefBase +{ + fn deref_mut(&mut self) -> &mut Self::Target + { + unsafe { + (&mut self.layout as *mut LayoutRef) + .cast::>() + .as_mut() + } + .expect("Pointers to parts will never be null") + } +} + +// Blanket impl for AsRef, so that functions that take +// AsRef can take RefBase +impl AsRef for RefBase +where + T: ?Sized, + as Deref>::Target: AsRef, +{ + fn as_ref(&self) -> &T + { + self.deref().as_ref() + } +} + +// Blanket impl for AsMut, so that functions that take +// AsMut can take RefBase +impl AsMut for RefBase +where + T: ?Sized, + as Deref>::Target: AsMut, +{ + fn as_mut(&mut self) -> &mut T + { + self.deref_mut().as_mut() + } +} + +/// # Safety +/// +/// Usually the pointer would be bad to just clone, as we'd have aliasing +/// and completely separated references to the same data. However, it is +/// impossible to read the data behind the pointer from a LayoutRef (this +/// is a safety invariant that *must* be maintained), and therefore we can +/// Clone and Copy as desired. +impl Clone for LayoutRef +{ + fn clone(&self) -> Self + { + Self { + dim: self.dim.clone(), + strides: self.strides.clone(), + ptr: self.ptr.clone(), + } + } +} + +impl Copy for LayoutRef {} diff --git a/src/lib.rs b/src/lib.rs index 7561e66a4..6a9c9f93b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -127,7 +127,7 @@ pub mod doc; use alloc::sync::Arc; pub use arrayref::RawReferent; -use arrayref::{Raw, Safe}; +use arrayref::{Raw, Referent, Safe}; #[cfg(not(target_has_atomic = "ptr"))] use portable_atomic_util::Arc; @@ -163,6 +163,7 @@ mod macro_utils; #[macro_use] mod private; mod arrayref; +mod layoutref; mod aliases; #[macro_use] mod itertools; @@ -1283,20 +1284,39 @@ pub type Ixs = isize; // may change in the future. // // [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset-1 -#[repr(C)] pub struct ArrayBase where S: RawData { - /// A non-null pointer into the buffer held by `data`; may point anywhere - /// in its range. If `S: Data`, this pointer must be aligned. - ptr: std::ptr::NonNull, + /// Data buffer / ownership information. (If owned, contains the data + /// buffer; if borrowed, contains the lifetime and mutability.) + data: S, + /// The dimension, strides, and pointer to inside of `data` + layout: LayoutRef, +} + +/// A reference to the layout of an *n*-dimensional array. +// +// # Safety for Implementors +// +// Despite carrying around a `ptr`, maintainers of `LayoutRef` +// must *guarantee* that the pointer is *never* dereferenced. +// No read access can be used when handling a `LayoutRef`, and +// the `ptr` can *never* be exposed to the user. +// +// The reason the pointer is included here is because some methods +// which alter the layout / shape / strides of an array must also +// alter the offset of the pointer. This is allowed, as it does not +// cause a pointer deref. +#[derive(Debug)] +struct LayoutRef +{ /// The lengths of the axes. dim: D, /// The element count stride per axis. To be parsed as `isize`. strides: D, - /// Data buffer / ownership information. (If owned, contains the data - /// buffer; if borrowed, contains the lifetime and mutability.) - data: S, + /// A non-null pointer into the buffer held by `data`; may point anywhere + /// in its range. If `S: Data`, this pointer must be aligned. + ptr: std::ptr::NonNull, } /// A reference to an *n*-dimensional array. @@ -1349,17 +1369,11 @@ where S: RawData /// #[allow(dead_code)] /// unsafe fn write_unchecked(arr: &mut RefBase) {} /// ``` -#[repr(C)] +#[repr(transparent)] pub struct RefBase -where R: RawReferent { - /// A non-null pointer into the buffer held by `data`; may point anywhere - /// in its range. If `S: Referent`, this pointer must be aligned. - ptr: std::ptr::NonNull, - /// The lengths of the axes. - dim: D, - /// The element count stride per axis. To be parsed as `isize`. - strides: D, + /// The parts of the array + layout: LayoutRef, /// The referent safety marker phantom: PhantomData, } @@ -1606,14 +1620,12 @@ mod impl_internal_constructors; mod impl_constructors; mod impl_methods; +mod alias_slicing; mod impl_owned_array; mod impl_special_element_types; /// Private Methods -impl ArrayBase -where - S: Data, - D: Dimension, +impl RefBase { #[inline] fn broadcast_unwrap(&self, dim: E) -> ArrayView<'_, A, E> @@ -1631,7 +1643,7 @@ where match self.broadcast(dim.clone()) { Some(it) => it, - None => broadcast_panic(&self.dim, &dim), + None => broadcast_panic(&self.layout.dim, &dim), } } @@ -1643,17 +1655,26 @@ where { let dim = dim.into_dimension(); debug_assert_eq!(self.shape(), dim.slice()); - let ptr = self.ptr; + let ptr = self.layout.ptr; let mut strides = dim.clone(); - strides.slice_mut().copy_from_slice(self.strides.slice()); + strides + .slice_mut() + .copy_from_slice(self.layout.strides.slice()); unsafe { ArrayView::new(ptr, dim, strides) } } +} +impl ArrayBase +where + S: Data, + D: Dimension, + ::RefType: Referent, +{ /// Remove array axis `axis` and return the result. fn try_remove_axis(self, axis: Axis) -> ArrayBase { - let d = self.dim.try_remove_axis(axis); - let s = self.strides.try_remove_axis(axis); + let d = self.layout.dim.try_remove_axis(axis); + let s = self.layout.strides.try_remove_axis(axis); // safe because new dimension, strides allow access to a subset of old data unsafe { self.with_strides_dim(s, d) } } diff --git a/src/zip/ndproducer.rs b/src/zip/ndproducer.rs index 1d1b3391b..acbe367c9 100644 --- a/src/zip/ndproducer.rs +++ b/src/zip/ndproducer.rs @@ -1,6 +1,7 @@ use crate::imp_prelude::*; use crate::Layout; use crate::NdIndex; +use crate::RefBase; #[cfg(not(feature = "std"))] use alloc::vec::Vec; @@ -239,7 +240,7 @@ impl<'a, A, D: Dimension> NdProducer for ArrayView<'a, A, D> fn raw_dim(&self) -> Self::Dim { - self.raw_dim() + RefBase::raw_dim(&self) } fn equal_dim(&self, dim: &Self::Dim) -> bool @@ -269,7 +270,7 @@ impl<'a, A, D: Dimension> NdProducer for ArrayView<'a, A, D> fn stride_of(&self, axis: Axis) -> isize { - self.stride_of(axis) + RefBase::stride_of(&self, axis) } #[inline(always)] @@ -295,7 +296,7 @@ impl<'a, A, D: Dimension> NdProducer for ArrayViewMut<'a, A, D> fn raw_dim(&self) -> Self::Dim { - self.raw_dim() + RefBase::raw_dim(&self) } fn equal_dim(&self, dim: &Self::Dim) -> bool @@ -325,7 +326,7 @@ impl<'a, A, D: Dimension> NdProducer for ArrayViewMut<'a, A, D> fn stride_of(&self, axis: Axis) -> isize { - self.stride_of(axis) + RefBase::stride_of(&self, axis) } #[inline(always)] @@ -351,7 +352,7 @@ impl NdProducer for RawArrayView fn raw_dim(&self) -> Self::Dim { - self.raw_dim() + RefBase::raw_dim(&self) } fn equal_dim(&self, dim: &Self::Dim) -> bool @@ -381,7 +382,7 @@ impl NdProducer for RawArrayView fn stride_of(&self, axis: Axis) -> isize { - self.stride_of(axis) + RefBase::stride_of(&self, axis) } #[inline(always)] @@ -407,7 +408,7 @@ impl NdProducer for RawArrayViewMut fn raw_dim(&self) -> Self::Dim { - self.raw_dim() + RefBase::raw_dim(&self) } fn equal_dim(&self, dim: &Self::Dim) -> bool @@ -437,7 +438,7 @@ impl NdProducer for RawArrayViewMut fn stride_of(&self, axis: Axis) -> isize { - self.stride_of(axis) + RefBase::stride_of(&self, axis) } #[inline(always)] From 4c440a88440121193ed2f93020e9c06e5776b370 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sat, 12 Oct 2024 22:16:12 -0400 Subject: [PATCH 10/33] Working version of the conversion to reference types --- crates/blas-tests/tests/oper.rs | 9 ++++- crates/numeric-tests/tests/accuracy.rs | 4 +- examples/rollaxis.rs | 2 + ndarray-rand/src/lib.rs | 6 ++- src/alias_slicing.rs | 28 +++++++++++++ src/array_approx.rs | 12 +++++- src/array_serde.rs | 2 + src/arrayformat.rs | 30 ++++++++++---- src/arraytraits.rs | 4 +- src/data_traits.rs | 6 +-- src/free_functions.rs | 26 ++++++------ src/impl_2d.rs | 18 ++++++--- src/impl_methods.rs | 39 ++++++++++++++++++ src/impl_ops.rs | 3 ++ src/impl_owned_array.rs | 5 ++- src/impl_views/constructors.rs | 2 +- src/impl_views/conversions.rs | 16 ++++---- src/iterators/chunks.rs | 4 +- src/iterators/into_iter.rs | 6 +-- src/iterators/mod.rs | 6 +-- src/layout/mod.rs | 2 +- src/layoutref.rs | 12 ++++-- src/lib.rs | 15 +++---- src/linalg/impl_linalg.rs | 33 +++++++++++++++- src/numeric/impl_float_maths.rs | 4 +- src/numeric/impl_numeric.rs | 2 + src/tri.rs | 16 +++++--- src/zip/mod.rs | 16 ++++---- src/zip/ndproducer.rs | 55 ++++++++++++++++++++------ tests/array.rs | 3 +- tests/iterators.rs | 3 +- tests/oper.rs | 7 ++++ 32 files changed, 303 insertions(+), 93 deletions(-) diff --git a/crates/blas-tests/tests/oper.rs b/crates/blas-tests/tests/oper.rs index a9dca7e83..af8d454e8 100644 --- a/crates/blas-tests/tests/oper.rs +++ b/crates/blas-tests/tests/oper.rs @@ -10,6 +10,7 @@ use ndarray::prelude::*; use ndarray::linalg::general_mat_mul; use ndarray::linalg::general_mat_vec_mul; use ndarray::Order; +use ndarray::Referent; use ndarray::{Data, Ix, LinalgScalar}; use ndarray_gen::array_builder::ArrayBuilder; use ndarray_gen::array_builder::ElementGenerator; @@ -82,6 +83,8 @@ where A: LinalgScalar, S: Data, S2: Data, + S::RefType: Referent, + S2::RefType: Referent, { let ((m, k), (k2, n)) = (lhs.dim(), rhs.dim()); assert!(m.checked_mul(n).is_some()); @@ -112,6 +115,8 @@ where A: LinalgScalar, S: Data, S2: Data, + S::RefType: Referent, + S2::RefType: Referent, { let ((m, _), k) = (lhs.dim(), rhs.dim()); reference_mat_mul( @@ -130,6 +135,8 @@ where A: LinalgScalar, S: Data, S2: Data, + S::RefType: Referent, + S2::RefType: Referent, { let (m, (_, n)) = (lhs.dim(), rhs.dim()); reference_mat_mul( @@ -280,7 +287,7 @@ fn gen_mat_mul() cv = c.view_mut(); } - let answer_part = alpha * reference_mat_mul(&av, &bv) + beta * &cv; + let answer_part: Array = alpha * reference_mat_mul(&av, &bv) + beta * &cv; answer.slice_mut(s![..;s1, ..;s2]).assign(&answer_part); general_mat_mul(alpha, &av, &bv, beta, &mut cv); diff --git a/crates/numeric-tests/tests/accuracy.rs b/crates/numeric-tests/tests/accuracy.rs index c594f020d..e3d1d62ab 100644 --- a/crates/numeric-tests/tests/accuracy.rs +++ b/crates/numeric-tests/tests/accuracy.rs @@ -13,7 +13,7 @@ use rand::rngs::SmallRng; use rand::{Rng, SeedableRng}; use ndarray::linalg::general_mat_mul; -use ndarray::prelude::*; +use ndarray::{prelude::*, Referent}; use ndarray::{Data, LinalgScalar}; use num_complex::Complex; @@ -44,6 +44,8 @@ where A: LinalgScalar, S: Data, S2: Data, + S::RefType: Referent, + S2::RefType: Referent, { let ((m, k), (_, n)) = (lhs.dim(), rhs.dim()); let mut res_elems = Array::zeros(m * n); diff --git a/examples/rollaxis.rs b/examples/rollaxis.rs index 82c381297..18dcd1864 100644 --- a/examples/rollaxis.rs +++ b/examples/rollaxis.rs @@ -1,10 +1,12 @@ use ndarray::prelude::*; use ndarray::Data; +use ndarray::Referent; pub fn roll_axis(mut a: ArrayBase, to: Axis, from: Axis) -> ArrayBase where S: Data, D: Dimension, + S::RefType: Referent, { let i = to.index(); let mut j = from.index(); diff --git a/ndarray-rand/src/lib.rs b/ndarray-rand/src/lib.rs index 6671ab334..7e3a83fbd 100644 --- a/ndarray-rand/src/lib.rs +++ b/ndarray-rand/src/lib.rs @@ -34,7 +34,7 @@ use crate::rand::rngs::SmallRng; use crate::rand::seq::index; use crate::rand::{thread_rng, Rng, SeedableRng}; -use ndarray::{Array, Axis, RemoveAxis, ShapeBuilder}; +use ndarray::{Array, Axis, Referent, RemoveAxis, ShapeBuilder}; use ndarray::{ArrayBase, Data, DataOwned, Dimension, RawData}; #[cfg(feature = "quickcheck")] use quickcheck::{Arbitrary, Gen}; @@ -168,6 +168,7 @@ where where A: Copy, S: Data, + S::RefType: Referent, D: RemoveAxis; /// Sample `n_samples` lanes slicing along `axis` using the specified RNG `rng`. @@ -225,6 +226,7 @@ where R: Rng + ?Sized, A: Copy, S: Data, + S::RefType: Referent, D: RemoveAxis; } @@ -256,6 +258,7 @@ where where A: Copy, S: Data, + S::RefType: Referent, D: RemoveAxis, { self.sample_axis_using(axis, n_samples, strategy, &mut get_rng()) @@ -266,6 +269,7 @@ where R: Rng + ?Sized, A: Copy, S: Data, + S::RefType: Referent, D: RemoveAxis, { let indices: Vec<_> = match strategy { diff --git a/src/alias_slicing.rs b/src/alias_slicing.rs index fabcb2945..4b3c2677d 100644 --- a/src/alias_slicing.rs +++ b/src/alias_slicing.rs @@ -107,6 +107,28 @@ impl ArrayBase self.as_mut().invert_axis(axis); } + /// Swap axes `ax` and `bx`. + /// + /// This does not move any data, it just adjusts the array’s dimensions + /// and strides. + /// + /// **Panics** if the axes are out of bounds. + /// + /// ``` + /// use ndarray::arr2; + /// + /// let mut a = arr2(&[[1., 2., 3.]]); + /// a.swap_axes(0, 1); + /// assert!( + /// a == arr2(&[[1.], [2.], [3.]]) + /// ); + /// ``` + #[track_caller] + pub fn swap_axes(&mut self, ax: usize, bx: usize) + { + self.as_mut().swap_axes(ax, bx); + } + /// If possible, merge in the axis `take` to `into`. /// /// Returns `true` iff the axes are now merged. @@ -147,4 +169,10 @@ impl ArrayBase { self.as_mut().merge_axes(take, into) } + + /// Return the strides of the array as a slice. + pub fn strides(&self) -> &[isize] + { + (**self).strides() + } } diff --git a/src/array_approx.rs b/src/array_approx.rs index 493864c7e..67edf05dc 100644 --- a/src/array_approx.rs +++ b/src/array_approx.rs @@ -1,12 +1,13 @@ #[cfg(feature = "approx")] mod approx_methods { - use crate::imp_prelude::*; + use crate::{arrayref::Referent, imp_prelude::*}; impl ArrayBase where S: Data, D: Dimension, + S::RefType: Referent, { /// A test for equality that uses the elementwise absolute difference to compute the /// approximate equality of two arrays. @@ -17,6 +18,7 @@ mod approx_methods A: ::approx::AbsDiffEq, A::Epsilon: Clone, S2: Data, + S2::RefType: Referent, { >::abs_diff_eq(self, other, epsilon) } @@ -30,6 +32,7 @@ mod approx_methods A: ::approx::RelativeEq, A::Epsilon: Clone, S2: Data, + S2::RefType: Referent, { >::relative_eq(self, other, epsilon, max_relative) } @@ -41,6 +44,7 @@ macro_rules! impl_approx_traits { mod $approx { use crate::imp_prelude::*; use crate::Zip; + use crate::Referent; use $approx::{AbsDiffEq, RelativeEq, UlpsEq}; #[doc = $doc] @@ -51,6 +55,8 @@ macro_rules! impl_approx_traits { S: Data, S2: Data, D: Dimension, + S::RefType: Referent, + S2::RefType: Referent, { type Epsilon = A::Epsilon; @@ -77,6 +83,8 @@ macro_rules! impl_approx_traits { S: Data, S2: Data, D: Dimension, + S::RefType: Referent, + S2::RefType: Referent, { fn default_max_relative() -> A::Epsilon { A::default_max_relative() @@ -106,6 +114,8 @@ macro_rules! impl_approx_traits { S: Data, S2: Data, D: Dimension, + S::RefType: Referent, + S2::RefType: Referent, { fn default_max_ulps() -> u32 { A::default_max_ulps() diff --git a/src/array_serde.rs b/src/array_serde.rs index 31b613d4c..6233abece 100644 --- a/src/array_serde.rs +++ b/src/array_serde.rs @@ -15,6 +15,7 @@ use alloc::vec::Vec; use std::fmt; use std::marker::PhantomData; +use crate::arrayref::Referent; use crate::imp_prelude::*; use super::arraytraits::ARRAY_FORMAT_VERSION; @@ -83,6 +84,7 @@ where A: Serialize, D: Dimension + Serialize, S: Data, + S::RefType: Referent, { fn serialize(&self, serializer: Se) -> Result where Se: Serializer diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 1a3b714c3..4d37e7f2f 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -6,7 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use super::{ArrayBase, ArrayView, Axis, Data, Dimension, NdProducer}; -use crate::aliases::{Ix1, IxDyn}; +use crate::{ + aliases::{Ix1, IxDyn}, + arrayref::Referent, +}; use alloc::format; use std::fmt; @@ -119,6 +122,7 @@ where F: FnMut(&A, &mut fmt::Formatter<'_>) -> fmt::Result + Clone, D: Dimension, S: Data, + S::RefType: Referent, { // Cast into a dynamically dimensioned view // This is required to be able to use `index_axis` for the recursive case @@ -173,7 +177,9 @@ where /// /// The array is shown in multiline style. impl fmt::Display for ArrayBase -where S: Data +where + S: Data, + S::RefType: Referent, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -187,7 +193,9 @@ where S: Data /// /// The array is shown in multiline style. impl fmt::Debug for ArrayBase -where S: Data +where + S: Data, + S::RefType: Referent, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -215,7 +223,9 @@ where S: Data /// /// The array is shown in multiline style. impl fmt::LowerExp for ArrayBase -where S: Data +where + S: Data, + S::RefType: Referent, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -229,7 +239,9 @@ where S: Data /// /// The array is shown in multiline style. impl fmt::UpperExp for ArrayBase -where S: Data +where + S: Data, + S::RefType: Referent, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -242,7 +254,9 @@ where S: Data /// /// The array is shown in multiline style. impl fmt::LowerHex for ArrayBase -where S: Data +where + S: Data, + S::RefType: Referent, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -256,7 +270,9 @@ where S: Data /// /// The array is shown in multiline style. impl fmt::Binary for ArrayBase -where S: Data +where + S: Data, + S::RefType: Referent, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/arraytraits.rs b/src/arraytraits.rs index 5e256e2f5..f1c556c0e 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -45,8 +45,8 @@ where I: NdIndex, T: AsRef>, { - let layout = _a.as_ref(); - debug_bounds_check!(layout, *_index); + let _layout = _a.as_ref(); + debug_bounds_check!(_layout, *_index); } /// Access the element at **index**. diff --git a/src/data_traits.rs b/src/data_traits.rs index efd335d14..e9cc5792f 100644 --- a/src/data_traits.rs +++ b/src/data_traits.rs @@ -147,7 +147,7 @@ pub unsafe trait Data: RawData Self::RefType: Referent, { // clone to shared - (*self_).to_owned().into_shared() + self_.to_owned().into_shared() } } @@ -454,7 +454,7 @@ unsafe impl<'a, A> Data for ViewRepr<&'a A> Self::Elem: Clone, D: Dimension, { - (*self_).to_owned() + self_.to_owned() } fn try_into_owned_nocopy(self_: ArrayBase) -> Result, ArrayBase> @@ -689,7 +689,7 @@ unsafe impl<'a, A> Data for CowRepr<'a, A> D: Dimension, { match self_.data { - CowRepr::View(_) => (*self_).to_owned(), + CowRepr::View(_) => self_.to_owned(), CowRepr::Owned(data) => unsafe { // safe because the data is equivalent so ptr, dims remain valid ArrayBase::from_data_ptr(data, self_.layout.ptr) diff --git a/src/free_functions.rs b/src/free_functions.rs index 5659d7024..c1889cec8 100644 --- a/src/free_functions.rs +++ b/src/free_functions.rs @@ -14,8 +14,8 @@ use std::compile_error; use std::mem::{forget, size_of}; use std::ptr::NonNull; -use crate::imp_prelude::*; use crate::{dimension, ArcArray1, ArcArray2}; +use crate::{imp_prelude::*, LayoutRef}; /// Create an **[`Array`]** with one, two, three, four, five, or six dimensions. /// @@ -106,10 +106,12 @@ pub const fn aview0(x: &A) -> ArrayView0<'_, A> { ArrayBase { data: ViewRepr::new(), - // Safe because references are always non-null. - ptr: unsafe { NonNull::new_unchecked(x as *const A as *mut A) }, - dim: Ix0(), - strides: Ix0(), + layout: LayoutRef { + // Safe because references are always non-null. + ptr: unsafe { NonNull::new_unchecked(x as *const A as *mut A) }, + dim: Ix0(), + strides: Ix0(), + }, } } @@ -144,10 +146,12 @@ pub const fn aview1(xs: &[A]) -> ArrayView1<'_, A> } ArrayBase { data: ViewRepr::new(), - // Safe because references are always non-null. - ptr: unsafe { NonNull::new_unchecked(xs.as_ptr() as *mut A) }, - dim: Ix1(xs.len()), - strides: Ix1(1), + layout: LayoutRef { + // Safe because references are always non-null. + ptr: unsafe { NonNull::new_unchecked(xs.as_ptr() as *mut A) }, + dim: Ix1(xs.len()), + strides: Ix1(1), + }, } } @@ -200,9 +204,7 @@ pub const fn aview2(xs: &[[A; N]]) -> ArrayView2<'_, A> }; ArrayBase { data: ViewRepr::new(), - ptr, - dim, - strides, + layout: LayoutRef { ptr, dim, strides }, } } diff --git a/src/impl_2d.rs b/src/impl_2d.rs index c2e9725ac..7259c1c29 100644 --- a/src/impl_2d.rs +++ b/src/impl_2d.rs @@ -7,7 +7,7 @@ // except according to those terms. //! Methods for two-dimensional arrays. -use crate::imp_prelude::*; +use crate::{arrayref::Referent, imp_prelude::*}; /// # Methods For 2-D Arrays impl ArrayBase @@ -24,7 +24,9 @@ where S: RawData /// ``` #[track_caller] pub fn row(&self, index: Ix) -> ArrayView1<'_, A> - where S: Data + where + S: Data, + S::RefType: Referent, { self.index_axis(Axis(0), index) } @@ -41,7 +43,9 @@ where S: RawData /// ``` #[track_caller] pub fn row_mut(&mut self, index: Ix) -> ArrayViewMut1<'_, A> - where S: DataMut + where + S: DataMut, + S::RefType: Referent, { self.index_axis_mut(Axis(0), index) } @@ -79,7 +83,9 @@ where S: RawData /// ``` #[track_caller] pub fn column(&self, index: Ix) -> ArrayView1<'_, A> - where S: Data + where + S: Data, + S::RefType: Referent, { self.index_axis(Axis(1), index) } @@ -96,7 +102,9 @@ where S: RawData /// ``` #[track_caller] pub fn column_mut(&mut self, index: Ix) -> ArrayViewMut1<'_, A> - where S: DataMut + where + S: DataMut, + S::RefType: Referent, { self.index_axis_mut(Axis(1), index) } diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 32cf58c5d..e9de470a3 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -254,6 +254,45 @@ where S: RawData, D: Dimension, { + /// Return an uniquely owned copy of the array. + /// + /// If the input array is contiguous, then the output array will have the same + /// memory layout. Otherwise, the layout of the output array is unspecified. + /// If you need a particular layout, you can allocate a new array with the + /// desired memory layout and [`.assign()`](Self::assign) the data. + /// Alternatively, you can collectan iterator, like this for a result in + /// standard layout: + /// + /// ``` + /// # use ndarray::prelude::*; + /// # let arr = Array::from_shape_vec((2, 2).f(), vec![1, 2, 3, 4]).unwrap(); + /// # let owned = { + /// Array::from_shape_vec(arr.raw_dim(), arr.iter().cloned().collect()).unwrap() + /// # }; + /// # assert!(owned.is_standard_layout()); + /// # assert_eq!(arr, owned); + /// ``` + /// + /// or this for a result in column-major (Fortran) layout: + /// + /// ``` + /// # use ndarray::prelude::*; + /// # let arr = Array::from_shape_vec((2, 2), vec![1, 2, 3, 4]).unwrap(); + /// # let owned = { + /// Array::from_shape_vec(arr.raw_dim().f(), arr.t().iter().cloned().collect()).unwrap() + /// # }; + /// # assert!(owned.t().is_standard_layout()); + /// # assert_eq!(arr, owned); + /// ``` + pub fn to_owned(&self) -> Array + where + A: Clone, + S: Data, + S::RefType: Referent, + { + (**self).to_owned() + } + /// Return a shared ownership (copy on write) array, cloning the array /// elements if necessary. pub fn to_shared(&self) -> ArcArray diff --git a/src/impl_ops.rs b/src/impl_ops.rs index 7d2eb412b..ef2ffc80f 100644 --- a/src/impl_ops.rs +++ b/src/impl_ops.rs @@ -73,6 +73,7 @@ where E: Dimension, S::RefType: Referent, S2::RefType: Referent, + <::MaybeUninit as RawData>::RefType: Referent, { type Output = ArrayBase>::Output>; #[track_caller] @@ -103,6 +104,7 @@ where E: Dimension, S::RefType: Referent, S2::RefType: Referent, + <::MaybeUninit as RawData>::RefType: Referent, { type Output = ArrayBase>::Output>; #[track_caller] @@ -146,6 +148,7 @@ where E: Dimension + DimMax, S::RefType: Referent, S2::RefType: Referent, + <::MaybeUninit as RawData>::RefType: Referent, { type Output = ArrayBase>::Output>; #[track_caller] diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs index 5bf068a7e..bef6d0498 100644 --- a/src/impl_owned_array.rs +++ b/src/impl_owned_array.rs @@ -13,6 +13,7 @@ use crate::dimension; use crate::error::{ErrorKind, ShapeError}; use crate::iterators::Baseiter; use crate::low_level_util::AbortIfPanic; +use crate::LayoutRef; use crate::OwnedRepr; use crate::Zip; @@ -746,7 +747,7 @@ where D: Dimension sort_axes_in_default_order_tandem(&mut tail_view, &mut array); debug_assert!(tail_view.is_standard_layout(), "not std layout dim: {:?}, strides: {:?}", - tail_view.shape(), (&**tail_view).strides()); + tail_view.shape(), LayoutRef::strides(&tail_view)); } // Keep track of currently filled length of `self.data` and update it @@ -849,7 +850,7 @@ where D: Dimension 0 }; debug_assert!(data_to_array_offset >= 0); - self.ptr = self + self.layout.ptr = self .data .reserve(len_to_append) .offset(data_to_array_offset); diff --git a/src/impl_views/constructors.rs b/src/impl_views/constructors.rs index 15f2b9b6b..e20644548 100644 --- a/src/impl_views/constructors.rs +++ b/src/impl_views/constructors.rs @@ -225,7 +225,7 @@ where D: Dimension pub fn reborrow<'b>(self) -> ArrayViewMut<'b, A, D> where 'a: 'b { - unsafe { ArrayViewMut::new(self.ptr, self.dim, self.strides) } + unsafe { ArrayViewMut::new(self.layout.ptr, self.layout.dim, self.layout.strides) } } } diff --git a/src/impl_views/conversions.rs b/src/impl_views/conversions.rs index 1dd7d97f2..ce852da5e 100644 --- a/src/impl_views/conversions.rs +++ b/src/impl_views/conversions.rs @@ -29,7 +29,7 @@ where D: Dimension pub fn reborrow<'b>(self) -> ArrayView<'b, A, D> where 'a: 'b { - unsafe { ArrayView::new(self.ptr, self.dim, self.strides) } + unsafe { ArrayView::new(self.layout.ptr, self.layout.dim, self.layout.strides) } } /// Return the array’s data as a slice, if it is contiguous and in standard order. @@ -66,7 +66,7 @@ where D: Dimension #[inline] pub(crate) fn into_raw_view(self) -> RawArrayView { - unsafe { RawArrayView::new(self.ptr, self.dim, self.strides) } + unsafe { RawArrayView::new(self.layout.ptr, self.layout.dim, self.layout.strides) } } } @@ -199,7 +199,7 @@ where D: Dimension #[inline] pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } + unsafe { Baseiter::new(self.layout.ptr, self.layout.dim, self.layout.strides) } } } @@ -209,7 +209,7 @@ where D: Dimension #[inline] pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } + unsafe { Baseiter::new(self.layout.ptr, self.layout.dim, self.layout.strides) } } } @@ -220,7 +220,7 @@ where D: Dimension #[inline] pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } + unsafe { Baseiter::new(self.layout.ptr, self.layout.dim, self.layout.strides) } } #[inline] @@ -250,19 +250,19 @@ where D: Dimension // Convert into a read-only view pub(crate) fn into_view(self) -> ArrayView<'a, A, D> { - unsafe { ArrayView::new(self.ptr, self.dim, self.strides) } + unsafe { ArrayView::new(self.layout.ptr, self.layout.dim, self.layout.strides) } } /// Converts to a mutable raw array view. pub(crate) fn into_raw_view_mut(self) -> RawArrayViewMut { - unsafe { RawArrayViewMut::new(self.ptr, self.dim, self.strides) } + unsafe { RawArrayViewMut::new(self.layout.ptr, self.layout.dim, self.layout.strides) } } #[inline] pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } + unsafe { Baseiter::new(self.layout.ptr, self.layout.dim, self.layout.strides) } } #[inline] diff --git a/src/iterators/chunks.rs b/src/iterators/chunks.rs index 9e2f08e1e..9da13e024 100644 --- a/src/iterators/chunks.rs +++ b/src/iterators/chunks.rs @@ -59,10 +59,10 @@ impl<'a, A, D: Dimension> ExactChunks<'a, A, D> a.shape() ); for i in 0..a.ndim() { - a.dim[i] /= chunk[i]; + a.layout.dim[i] /= chunk[i]; } let inner_strides = a.strides.clone(); - a.strides *= &chunk; + a.layout.strides *= &chunk; ExactChunks { base: a, diff --git a/src/iterators/into_iter.rs b/src/iterators/into_iter.rs index 9374608cb..b51315a0f 100644 --- a/src/iterators/into_iter.rs +++ b/src/iterators/into_iter.rs @@ -39,9 +39,9 @@ where D: Dimension let array_head_ptr = array.ptr; let mut array_data = array.data; let data_len = array_data.release_all_elements(); - debug_assert!(data_len >= array.dim.size()); - let has_unreachable_elements = array.dim.size() != data_len; - let inner = Baseiter::new(array_head_ptr, array.dim, array.strides); + debug_assert!(data_len >= array.layout.dim.size()); + let has_unreachable_elements = array.layout.dim.size() != data_len; + let inner = Baseiter::new(array_head_ptr, array.layout.dim, array.layout.strides); IntoIter { array_data, diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index e7321d15b..cf3153b14 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -1372,7 +1372,7 @@ fn chunk_iter_parts(v: ArrayView<'_, A, D>, axis: Axis, size: u let mut inner_dim = v.dim.clone(); inner_dim[axis] = size; - let mut partial_chunk_dim = v.dim; + let mut partial_chunk_dim = v.layout.dim; partial_chunk_dim[axis] = chunk_remainder; let partial_chunk_index = n_whole_chunks; @@ -1381,8 +1381,8 @@ fn chunk_iter_parts(v: ArrayView<'_, A, D>, axis: Axis, size: u end: iter_len, stride, inner_dim, - inner_strides: v.strides, - ptr: v.ptr.as_ptr(), + inner_strides: v.layout.strides, + ptr: v.layout.ptr.as_ptr(), }; (iter, partial_chunk_index, partial_chunk_dim) diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 026688d63..36853848e 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1,6 +1,6 @@ mod layoutfmt; -// Layout it a bitset used for internal layout description of +// Layout is a bitset used for internal layout description of // arrays, producers and sets of producers. // The type is public but users don't interact with it. #[doc(hidden)] diff --git a/src/layoutref.rs b/src/layoutref.rs index 0804452f3..749c5bb8a 100644 --- a/src/layoutref.rs +++ b/src/layoutref.rs @@ -30,7 +30,7 @@ where S: RawData // - It is "dereferencable" because it just points to self // - For the same reason, it is initialized unsafe { - (self as *const Self) + (&self.layout as *const LayoutRef) .cast::>() .as_ref() } @@ -47,8 +47,12 @@ where S: RawData // - The pointer is aligned because neither type use repr(align) // - It is "dereferencable" because it just points to self // - For the same reason, it is initialized - unsafe { (self as *mut Self).cast::>().as_mut() } - .expect("Pointer to self will always be non-null") + unsafe { + (&mut self.layout as *mut LayoutRef) + .cast::>() + .as_mut() + } + .expect("Pointer to self will always be non-null") } } @@ -120,7 +124,7 @@ impl Clone for LayoutRef Self { dim: self.dim.clone(), strides: self.strides.clone(), - ptr: self.ptr.clone(), + ptr: self.ptr, } } } diff --git a/src/lib.rs b/src/lib.rs index 6a9c9f93b..2c5e4a352 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -126,8 +126,8 @@ pub mod doc; #[cfg(target_has_atomic = "ptr")] use alloc::sync::Arc; -pub use arrayref::RawReferent; -use arrayref::{Raw, Referent, Safe}; +use arrayref::{Raw, Safe}; +pub use arrayref::{RawReferent, Referent}; #[cfg(not(target_has_atomic = "ptr"))] use portable_atomic_util::Arc; @@ -536,7 +536,7 @@ pub type Ixs = isize; /// [`.multi_slice_move()`]: ArrayViewMut#method.multi_slice_move /// /// ``` -/// use ndarray::{arr2, arr3, s, ArrayBase, DataMut, Dimension, NewAxis, Slice}; +/// use ndarray::{arr2, arr3, s, ArrayBase, DataMut, Dimension, NewAxis, Slice, Referent}; /// /// // 2 submatrices of 2 rows with 3 elements per row, means a shape of `[2, 2, 3]`. /// @@ -604,6 +604,7 @@ pub type Ixs = isize; /// S: DataMut, /// S::Elem: Clone, /// D: Dimension, +/// S::RefType: Referent, /// { /// arr.slice_each_axis_mut(|ax| Slice::from(0..ax.len / 2)).fill(x); /// } @@ -1308,15 +1309,15 @@ where S: RawData // alter the offset of the pointer. This is allowed, as it does not // cause a pointer deref. #[derive(Debug)] -struct LayoutRef +pub struct LayoutRef { + /// A non-null pointer into the buffer held by `data`; may point anywhere + /// in its range. If `S: Data`, this pointer must be aligned. + ptr: std::ptr::NonNull, /// The lengths of the axes. dim: D, /// The element count stride per axis. To be parsed as `isize`. strides: D, - /// A non-null pointer into the buffer held by `data`; may point anywhere - /// in its range. If `S: Data`, this pointer must be aligned. - ptr: std::ptr::NonNull, } /// A reference to an *n*-dimensional array. diff --git a/src/linalg/impl_linalg.rs b/src/linalg/impl_linalg.rs index 7472d8292..9cbc19224 100644 --- a/src/linalg/impl_linalg.rs +++ b/src/linalg/impl_linalg.rs @@ -6,6 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use crate::arrayref::Referent; use crate::imp_prelude::*; #[cfg(feature = "blas")] @@ -41,7 +42,9 @@ const GEMM_BLAS_CUTOFF: usize = 7; type blas_index = c_int; // blas index type impl ArrayBase -where S: Data +where + S: Data, + S::RefType: Referent, { /// Perform dot product or matrix multiplication of arrays `self` and `rhs`. /// @@ -71,6 +74,7 @@ where S: Data where S2: Data, A: LinalgScalar, + S2::RefType: Referent, { debug_assert_eq!(self.len(), rhs.len()); assert!(self.len() == rhs.len()); @@ -93,6 +97,7 @@ where S: Data where S2: Data, A: LinalgScalar, + S2::RefType: Referent, { self.dot_generic(rhs) } @@ -102,6 +107,7 @@ where S: Data where S2: Data, A: LinalgScalar, + S2::RefType: Referent, { // Use only if the vector is large enough to be worth it if self.len() >= DOT_BLAS_CUTOFF { @@ -173,6 +179,8 @@ where S: Data, S2: Data, A: LinalgScalar, + S::RefType: Referent, + S2::RefType: Referent, { type Output = A; @@ -196,6 +204,8 @@ where S: Data, S2: Data, A: LinalgScalar, + S::RefType: Referent, + S2::RefType: Referent, { type Output = Array; @@ -216,7 +226,9 @@ where } impl ArrayBase -where S: Data +where + S: Data, + S::RefType: Referent, { /// Perform matrix multiplication of rectangular arrays `self` and `rhs`. /// @@ -260,6 +272,8 @@ where S: Data, S2: Data, A: LinalgScalar, + S::RefType: Referent, + S2::RefType: Referent, { type Output = Array2; fn dot(&self, b: &ArrayBase) -> Array2 @@ -323,6 +337,8 @@ where S: Data, S2: Data, A: LinalgScalar, + S::RefType: Referent, + S2::RefType: Referent, { type Output = Array; #[track_caller] @@ -346,6 +362,7 @@ impl ArrayBase where S: Data, D: Dimension, + S::RefType: Referent, { /// Perform the operation `self += alpha * rhs` efficiently, where /// `alpha` is a scalar and `rhs` is another array. This operation is @@ -361,6 +378,8 @@ where S2: Data, A: LinalgScalar, E: Dimension, + S::RefType: Referent, + S2::RefType: Referent, { self.zip_mut_with(rhs, move |y, &x| *y = *y + (alpha * x)); } @@ -599,6 +618,9 @@ pub fn general_mat_mul( S2: Data, S3: DataMut, A: LinalgScalar, + S1::RefType: Referent, + S2::RefType: Referent, + S3::RefType: Referent, { let ((m, k), (k2, n)) = (a.dim(), b.dim()); let (m2, n2) = c.dim(); @@ -628,6 +650,9 @@ pub fn general_mat_vec_mul( S2: Data, S3: DataMut, A: LinalgScalar, + S1::RefType: Referent, + S2::RefType: Referent, + S3::RefType: Referent, { unsafe { general_mat_vec_mul_impl(alpha, a, x, beta, y.raw_view_mut()) } } @@ -647,6 +672,8 @@ unsafe fn general_mat_vec_mul_impl( S1: Data, S2: Data, A: LinalgScalar, + S1::RefType: Referent, + S2::RefType: Referent, { let ((m, k), k2) = (a.dim(), x.dim()); let m2 = y.dim(); @@ -726,6 +753,8 @@ where S1: Data, S2: Data, A: LinalgScalar, + S1::RefType: Referent, + S2::RefType: Referent, { let dimar = a.shape()[0]; let dimac = a.shape()[1]; diff --git a/src/numeric/impl_float_maths.rs b/src/numeric/impl_float_maths.rs index 54fed49c2..6a276dfab 100644 --- a/src/numeric/impl_float_maths.rs +++ b/src/numeric/impl_float_maths.rs @@ -3,7 +3,7 @@ #[cfg(feature = "std")] use num_traits::Float; -use crate::imp_prelude::*; +use crate::{arrayref::Referent, imp_prelude::*}; #[cfg(feature = "std")] macro_rules! boolean_ops { @@ -59,6 +59,7 @@ where A: 'static + Float, S: Data, D: Dimension, + S::RefType: Referent, { boolean_ops! { /// If the number is `NaN` (not a number), then `true` is returned for each element. @@ -148,6 +149,7 @@ where A: 'static + PartialOrd + Clone, S: Data, D: Dimension, + S::RefType: Referent, { /// Limit the values for each element, similar to NumPy's `clip` function. /// diff --git a/src/numeric/impl_numeric.rs b/src/numeric/impl_numeric.rs index 6c67b9135..a8e45541d 100644 --- a/src/numeric/impl_numeric.rs +++ b/src/numeric/impl_numeric.rs @@ -12,6 +12,7 @@ use num_traits::One; use num_traits::{FromPrimitive, Zero}; use std::ops::{Add, Div, Mul, Sub}; +use crate::arrayref::Referent; use crate::imp_prelude::*; use crate::numeric_util; use crate::Slice; @@ -21,6 +22,7 @@ impl ArrayBase where S: Data, D: Dimension, + S::RefType: Referent, { /// Return the sum of all elements in the array. /// diff --git a/src/tri.rs b/src/tri.rs index b7d297fcc..87d4e4495 100644 --- a/src/tri.rs +++ b/src/tri.rs @@ -11,6 +11,7 @@ use core::cmp::min; use num_traits::Zero; use crate::{ + arrayref::Referent, dimension::{is_layout_c, is_layout_f}, Array, ArrayBase, @@ -25,6 +26,7 @@ where S: Data, D: Dimension, A: Clone + Zero, + S::RefType: Referent, { /// Upper triangular of an array. /// @@ -83,7 +85,9 @@ where false => row_num.saturating_sub(k.unsigned_abs()), // Avoid underflow, go to 0 }; lower = min(lower, ncols); - dst.slice_mut(s![lower..]).assign(&src.slice(s![lower..])); + (*dst) + .slice_mut(s![lower..]) + .assign(&(*src).slice(s![lower..])); }); res @@ -127,10 +131,10 @@ where if is_layout_f(&self.dim, &self.strides) && !is_layout_c(&self.dim, &self.strides) && k > isize::MIN { let mut x = self.view(); x.swap_axes(n - 2, n - 1); - let mut tril = x.triu(-k); - tril.swap_axes(n - 2, n - 1); + let mut triu = x.triu(-k); + triu.swap_axes(n - 2, n - 1); - return tril; + return triu; } let mut res = Array::zeros(self.raw_dim()); @@ -147,7 +151,9 @@ where false => row_num.saturating_sub((k + 1).unsigned_abs()), // Avoid underflow }; upper = min(upper, ncols); - dst.slice_mut(s![..upper]).assign(&src.slice(s![..upper])); + (*dst) + .slice_mut(s![..upper]) + .assign(&(*src).slice(s![..upper])); }); res diff --git a/src/zip/mod.rs b/src/zip/mod.rs index b58752f66..a6b6ad45a 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -18,6 +18,8 @@ use crate::partial::Partial; use crate::AssignElem; use crate::IntoDimension; use crate::Layout; +use crate::LayoutRef; +use crate::Referent; use crate::dimension; use crate::indexes::{indices, Indices}; @@ -76,10 +78,8 @@ fn array_layout(dim: &D, strides: &D) -> Layout } } -impl ArrayBase -where - S: RawData, - D: Dimension, +impl LayoutRef +where D: Dimension { pub(crate) fn layout_impl(&self) -> Layout { @@ -96,8 +96,8 @@ where fn broadcast_unwrap(self, shape: E) -> Self::Output { #[allow(clippy::needless_borrow)] - let res: ArrayView<'_, A, E::Dim> = (&self).broadcast_unwrap(shape.into_dimension()); - unsafe { ArrayView::new(res.ptr, res.dim, res.strides) } + let res: ArrayView<'_, A, E::Dim> = (*self).broadcast_unwrap(shape.into_dimension()); + unsafe { ArrayView::new(res.layout.ptr, res.layout.dim, res.layout.strides) } } private_impl! {} } @@ -762,7 +762,9 @@ macro_rules! map_impl { pub(crate) fn map_collect_owned(self, f: impl FnMut($($p::Item,)* ) -> R) -> ArrayBase - where S: DataOwned + where + S: DataOwned, + <::MaybeUninit as RawData>::RefType: Referent, { // safe because: all elements are written before the array is completed diff --git a/src/zip/ndproducer.rs b/src/zip/ndproducer.rs index acbe367c9..7adf5b18c 100644 --- a/src/zip/ndproducer.rs +++ b/src/zip/ndproducer.rs @@ -1,3 +1,4 @@ +use crate::arrayref::Referent; use crate::imp_prelude::*; use crate::Layout; use crate::NdIndex; @@ -131,6 +132,7 @@ impl<'a, A: 'a, S, D> IntoNdProducer for &'a ArrayBase where D: Dimension, S: Data, + S::RefType: Referent, { type Item = &'a A; type Dim = D; @@ -147,6 +149,35 @@ impl<'a, A: 'a, S, D> IntoNdProducer for &'a mut ArrayBase where D: Dimension, S: DataMut, + S::RefType: Referent, +{ + type Item = &'a mut A; + type Dim = D; + type Output = ArrayViewMut<'a, A, D>; + fn into_producer(self) -> Self::Output + { + self.view_mut() + } +} + +/// An array reference is an n-dimensional producer of element references +/// (like ArrayView). +impl<'a, A: 'a, D, R: Referent> IntoNdProducer for &'a RefBase +where D: Dimension +{ + type Item = &'a A; + type Dim = D; + type Output = ArrayView<'a, A, D>; + fn into_producer(self) -> Self::Output + { + self.view() + } +} + +/// A mutable array reference is an n-dimensional producer of mutable element +/// references (like ArrayViewMut). +impl<'a, A: 'a, D, R: Referent> IntoNdProducer for &'a mut RefBase +where D: Dimension { type Item = &'a mut A; type Dim = D; @@ -240,7 +271,7 @@ impl<'a, A, D: Dimension> NdProducer for ArrayView<'a, A, D> fn raw_dim(&self) -> Self::Dim { - RefBase::raw_dim(&self) + (***self).raw_dim() } fn equal_dim(&self, dim: &Self::Dim) -> bool @@ -250,7 +281,7 @@ impl<'a, A, D: Dimension> NdProducer for ArrayView<'a, A, D> fn as_ptr(&self) -> *mut A { - self.as_ptr() as _ + (**self).as_ptr() as _ } fn layout(&self) -> Layout @@ -270,7 +301,7 @@ impl<'a, A, D: Dimension> NdProducer for ArrayView<'a, A, D> fn stride_of(&self, axis: Axis) -> isize { - RefBase::stride_of(&self, axis) + (**self).stride_of(axis) } #[inline(always)] @@ -296,7 +327,7 @@ impl<'a, A, D: Dimension> NdProducer for ArrayViewMut<'a, A, D> fn raw_dim(&self) -> Self::Dim { - RefBase::raw_dim(&self) + (***self).raw_dim() } fn equal_dim(&self, dim: &Self::Dim) -> bool @@ -306,7 +337,7 @@ impl<'a, A, D: Dimension> NdProducer for ArrayViewMut<'a, A, D> fn as_ptr(&self) -> *mut A { - self.as_ptr() as _ + (**self).as_ptr() as _ } fn layout(&self) -> Layout @@ -326,7 +357,7 @@ impl<'a, A, D: Dimension> NdProducer for ArrayViewMut<'a, A, D> fn stride_of(&self, axis: Axis) -> isize { - RefBase::stride_of(&self, axis) + (**self).stride_of(axis) } #[inline(always)] @@ -352,7 +383,7 @@ impl NdProducer for RawArrayView fn raw_dim(&self) -> Self::Dim { - RefBase::raw_dim(&self) + (***self).raw_dim() } fn equal_dim(&self, dim: &Self::Dim) -> bool @@ -362,7 +393,7 @@ impl NdProducer for RawArrayView fn as_ptr(&self) -> *const A { - self.as_ptr() + (**self).as_ptr() as _ } fn layout(&self) -> Layout @@ -382,7 +413,7 @@ impl NdProducer for RawArrayView fn stride_of(&self, axis: Axis) -> isize { - RefBase::stride_of(&self, axis) + (**self).stride_of(axis) } #[inline(always)] @@ -408,7 +439,7 @@ impl NdProducer for RawArrayViewMut fn raw_dim(&self) -> Self::Dim { - RefBase::raw_dim(&self) + (***self).raw_dim() } fn equal_dim(&self, dim: &Self::Dim) -> bool @@ -418,7 +449,7 @@ impl NdProducer for RawArrayViewMut fn as_ptr(&self) -> *mut A { - self.as_ptr() as _ + (**self).as_ptr() as _ } fn layout(&self) -> Layout @@ -438,7 +469,7 @@ impl NdProducer for RawArrayViewMut fn stride_of(&self, axis: Axis) -> isize { - RefBase::stride_of(&self, axis) + (***self).stride_of(axis) } #[inline(always)] diff --git a/tests/array.rs b/tests/array.rs index 696904dab..13244483c 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -2482,7 +2482,7 @@ fn array_macros() mod as_standard_layout_tests { use super::*; - use ndarray::Data; + use ndarray::{Data, Referent}; use std::fmt::Debug; fn test_as_standard_layout_for(orig: ArrayBase) @@ -2490,6 +2490,7 @@ mod as_standard_layout_tests S: Data, S::Elem: Clone + Debug + PartialEq, D: Dimension, + S::RefType: Referent, { let orig_is_standard = orig.is_standard_layout(); let out = orig.as_standard_layout(); diff --git a/tests/iterators.rs b/tests/iterators.rs index 908b64d15..3466dbb66 100644 --- a/tests/iterators.rs +++ b/tests/iterators.rs @@ -103,13 +103,14 @@ fn indexed() #[cfg(feature = "std")] fn as_slice() { - use ndarray::Data; + use ndarray::{Data, Referent}; fn assert_slice_correct(v: &ArrayBase) where S: Data, D: Dimension, A: PartialEq + std::fmt::Debug, + S::RefType: Referent, { let slc = v.as_slice(); assert!(slc.is_some()); diff --git a/tests/oper.rs b/tests/oper.rs index 5e3e669d0..3e5d9eef3 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -7,6 +7,7 @@ use ndarray::linalg::kron; use ndarray::prelude::*; #[cfg(feature = "approx")] use ndarray::Order; +use ndarray::Referent; use ndarray::{rcarr1, rcarr2}; use ndarray::{Data, LinalgScalar}; use ndarray::{Ix, Ixs}; @@ -297,6 +298,8 @@ where A: LinalgScalar, S: Data, S2: Data, + S::RefType: Referent, + S2::RefType: Referent, { let ((m, k), (k2, n)) = (lhs.dim(), rhs.dim()); assert!(m.checked_mul(n).is_some()); @@ -692,6 +695,8 @@ fn gen_mat_vec_mul() A: LinalgScalar, S: Data, S2: Data, + S::RefType: Referent, + S2::RefType: Referent, { let ((m, _), k) = (lhs.dim(), rhs.dim()); reference_mat_mul( @@ -757,6 +762,8 @@ fn vec_mat_mul() A: LinalgScalar, S: Data, S2: Data, + S::RefType: Referent, + S2::RefType: Referent, { let (m, (_, n)) = (lhs.dim(), rhs.dim()); reference_mat_mul( From c183903855824daaa56edd80a5a1079a9cde8e0d Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 13 Oct 2024 19:19:35 -0400 Subject: [PATCH 11/33] Uses a new design with two reference types --- crates/blas-tests/tests/oper.rs | 7 - crates/numeric-tests/tests/accuracy.rs | 4 +- examples/rollaxis.rs | 2 - ndarray-rand/src/lib.rs | 6 +- src/alias_slicing.rs | 6 +- src/array_approx.rs | 12 +- src/array_serde.rs | 2 - src/arrayformat.rs | 30 +-- src/arrayref.rs | 87 ------- src/arraytraits.rs | 19 +- src/data_traits.rs | 30 +-- src/impl_1d.rs | 5 +- src/impl_2d.rs | 24 +- src/impl_clone.rs | 12 +- src/impl_constructors.rs | 7 +- src/impl_cow.rs | 3 +- src/impl_methods.rs | 318 ++++++++---------------- src/impl_ops.rs | 23 -- src/impl_owned_array.rs | 28 +-- src/impl_raw_views.rs | 42 ++-- src/{layoutref.rs => impl_ref_types.rs} | 145 +++++++---- src/iterators/chunks.rs | 24 +- src/lib.rs | 83 +------ src/linalg/impl_linalg.rs | 43 +--- src/numeric/impl_float_maths.rs | 4 +- src/numeric/impl_numeric.rs | 2 - src/tri.rs | 2 - src/zip/mod.rs | 2 - src/zip/ndproducer.rs | 39 +-- tests/array.rs | 3 +- tests/iterators.rs | 3 +- tests/oper.rs | 7 - tests/raw_views.rs | 4 +- tests/test_ref_structure.rs | 31 +++ 34 files changed, 355 insertions(+), 704 deletions(-) delete mode 100644 src/arrayref.rs rename src/{layoutref.rs => impl_ref_types.rs} (51%) create mode 100644 tests/test_ref_structure.rs diff --git a/crates/blas-tests/tests/oper.rs b/crates/blas-tests/tests/oper.rs index af8d454e8..f604ae091 100644 --- a/crates/blas-tests/tests/oper.rs +++ b/crates/blas-tests/tests/oper.rs @@ -10,7 +10,6 @@ use ndarray::prelude::*; use ndarray::linalg::general_mat_mul; use ndarray::linalg::general_mat_vec_mul; use ndarray::Order; -use ndarray::Referent; use ndarray::{Data, Ix, LinalgScalar}; use ndarray_gen::array_builder::ArrayBuilder; use ndarray_gen::array_builder::ElementGenerator; @@ -83,8 +82,6 @@ where A: LinalgScalar, S: Data, S2: Data, - S::RefType: Referent, - S2::RefType: Referent, { let ((m, k), (k2, n)) = (lhs.dim(), rhs.dim()); assert!(m.checked_mul(n).is_some()); @@ -115,8 +112,6 @@ where A: LinalgScalar, S: Data, S2: Data, - S::RefType: Referent, - S2::RefType: Referent, { let ((m, _), k) = (lhs.dim(), rhs.dim()); reference_mat_mul( @@ -135,8 +130,6 @@ where A: LinalgScalar, S: Data, S2: Data, - S::RefType: Referent, - S2::RefType: Referent, { let (m, (_, n)) = (lhs.dim(), rhs.dim()); reference_mat_mul( diff --git a/crates/numeric-tests/tests/accuracy.rs b/crates/numeric-tests/tests/accuracy.rs index e3d1d62ab..c594f020d 100644 --- a/crates/numeric-tests/tests/accuracy.rs +++ b/crates/numeric-tests/tests/accuracy.rs @@ -13,7 +13,7 @@ use rand::rngs::SmallRng; use rand::{Rng, SeedableRng}; use ndarray::linalg::general_mat_mul; -use ndarray::{prelude::*, Referent}; +use ndarray::prelude::*; use ndarray::{Data, LinalgScalar}; use num_complex::Complex; @@ -44,8 +44,6 @@ where A: LinalgScalar, S: Data, S2: Data, - S::RefType: Referent, - S2::RefType: Referent, { let ((m, k), (_, n)) = (lhs.dim(), rhs.dim()); let mut res_elems = Array::zeros(m * n); diff --git a/examples/rollaxis.rs b/examples/rollaxis.rs index 18dcd1864..82c381297 100644 --- a/examples/rollaxis.rs +++ b/examples/rollaxis.rs @@ -1,12 +1,10 @@ use ndarray::prelude::*; use ndarray::Data; -use ndarray::Referent; pub fn roll_axis(mut a: ArrayBase, to: Axis, from: Axis) -> ArrayBase where S: Data, D: Dimension, - S::RefType: Referent, { let i = to.index(); let mut j = from.index(); diff --git a/ndarray-rand/src/lib.rs b/ndarray-rand/src/lib.rs index 7e3a83fbd..6671ab334 100644 --- a/ndarray-rand/src/lib.rs +++ b/ndarray-rand/src/lib.rs @@ -34,7 +34,7 @@ use crate::rand::rngs::SmallRng; use crate::rand::seq::index; use crate::rand::{thread_rng, Rng, SeedableRng}; -use ndarray::{Array, Axis, Referent, RemoveAxis, ShapeBuilder}; +use ndarray::{Array, Axis, RemoveAxis, ShapeBuilder}; use ndarray::{ArrayBase, Data, DataOwned, Dimension, RawData}; #[cfg(feature = "quickcheck")] use quickcheck::{Arbitrary, Gen}; @@ -168,7 +168,6 @@ where where A: Copy, S: Data, - S::RefType: Referent, D: RemoveAxis; /// Sample `n_samples` lanes slicing along `axis` using the specified RNG `rng`. @@ -226,7 +225,6 @@ where R: Rng + ?Sized, A: Copy, S: Data, - S::RefType: Referent, D: RemoveAxis; } @@ -258,7 +256,6 @@ where where A: Copy, S: Data, - S::RefType: Referent, D: RemoveAxis, { self.sample_axis_using(axis, n_samples, strategy, &mut get_rng()) @@ -269,7 +266,6 @@ where R: Rng + ?Sized, A: Copy, S: Data, - S::RefType: Referent, D: RemoveAxis, { let indices: Vec<_> = match strategy { diff --git a/src/alias_slicing.rs b/src/alias_slicing.rs index 4b3c2677d..4d685601d 100644 --- a/src/alias_slicing.rs +++ b/src/alias_slicing.rs @@ -1,4 +1,4 @@ -use crate::{iter::Axes, ArrayBase, Axis, AxisDescription, Dimension, RawData, Slice, SliceArg}; +use crate::{iter::Axes, ArrayBase, Axis, AxisDescription, Dimension, LayoutRef, RawData, Slice, SliceArg}; impl ArrayBase { @@ -95,7 +95,7 @@ impl ArrayBase /// preferring axes with len > 1. pub fn max_stride_axis(&self) -> Axis { - self.as_ref().max_stride_axis() + LayoutRef::max_stride_axis(&self.as_ref()) } /// Reverse the stride of `axis`. @@ -173,6 +173,6 @@ impl ArrayBase /// Return the strides of the array as a slice. pub fn strides(&self) -> &[isize] { - (**self).strides() + self.as_ref().strides() } } diff --git a/src/array_approx.rs b/src/array_approx.rs index 67edf05dc..493864c7e 100644 --- a/src/array_approx.rs +++ b/src/array_approx.rs @@ -1,13 +1,12 @@ #[cfg(feature = "approx")] mod approx_methods { - use crate::{arrayref::Referent, imp_prelude::*}; + use crate::imp_prelude::*; impl ArrayBase where S: Data, D: Dimension, - S::RefType: Referent, { /// A test for equality that uses the elementwise absolute difference to compute the /// approximate equality of two arrays. @@ -18,7 +17,6 @@ mod approx_methods A: ::approx::AbsDiffEq, A::Epsilon: Clone, S2: Data, - S2::RefType: Referent, { >::abs_diff_eq(self, other, epsilon) } @@ -32,7 +30,6 @@ mod approx_methods A: ::approx::RelativeEq, A::Epsilon: Clone, S2: Data, - S2::RefType: Referent, { >::relative_eq(self, other, epsilon, max_relative) } @@ -44,7 +41,6 @@ macro_rules! impl_approx_traits { mod $approx { use crate::imp_prelude::*; use crate::Zip; - use crate::Referent; use $approx::{AbsDiffEq, RelativeEq, UlpsEq}; #[doc = $doc] @@ -55,8 +51,6 @@ macro_rules! impl_approx_traits { S: Data, S2: Data, D: Dimension, - S::RefType: Referent, - S2::RefType: Referent, { type Epsilon = A::Epsilon; @@ -83,8 +77,6 @@ macro_rules! impl_approx_traits { S: Data, S2: Data, D: Dimension, - S::RefType: Referent, - S2::RefType: Referent, { fn default_max_relative() -> A::Epsilon { A::default_max_relative() @@ -114,8 +106,6 @@ macro_rules! impl_approx_traits { S: Data, S2: Data, D: Dimension, - S::RefType: Referent, - S2::RefType: Referent, { fn default_max_ulps() -> u32 { A::default_max_ulps() diff --git a/src/array_serde.rs b/src/array_serde.rs index 6233abece..31b613d4c 100644 --- a/src/array_serde.rs +++ b/src/array_serde.rs @@ -15,7 +15,6 @@ use alloc::vec::Vec; use std::fmt; use std::marker::PhantomData; -use crate::arrayref::Referent; use crate::imp_prelude::*; use super::arraytraits::ARRAY_FORMAT_VERSION; @@ -84,7 +83,6 @@ where A: Serialize, D: Dimension + Serialize, S: Data, - S::RefType: Referent, { fn serialize(&self, serializer: Se) -> Result where Se: Serializer diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 4d37e7f2f..1a3b714c3 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -6,10 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use super::{ArrayBase, ArrayView, Axis, Data, Dimension, NdProducer}; -use crate::{ - aliases::{Ix1, IxDyn}, - arrayref::Referent, -}; +use crate::aliases::{Ix1, IxDyn}; use alloc::format; use std::fmt; @@ -122,7 +119,6 @@ where F: FnMut(&A, &mut fmt::Formatter<'_>) -> fmt::Result + Clone, D: Dimension, S: Data, - S::RefType: Referent, { // Cast into a dynamically dimensioned view // This is required to be able to use `index_axis` for the recursive case @@ -177,9 +173,7 @@ where /// /// The array is shown in multiline style. impl fmt::Display for ArrayBase -where - S: Data, - S::RefType: Referent, +where S: Data { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -193,9 +187,7 @@ where /// /// The array is shown in multiline style. impl fmt::Debug for ArrayBase -where - S: Data, - S::RefType: Referent, +where S: Data { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -223,9 +215,7 @@ where /// /// The array is shown in multiline style. impl fmt::LowerExp for ArrayBase -where - S: Data, - S::RefType: Referent, +where S: Data { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -239,9 +229,7 @@ where /// /// The array is shown in multiline style. impl fmt::UpperExp for ArrayBase -where - S: Data, - S::RefType: Referent, +where S: Data { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -254,9 +242,7 @@ where /// /// The array is shown in multiline style. impl fmt::LowerHex for ArrayBase -where - S: Data, - S::RefType: Referent, +where S: Data { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -270,9 +256,7 @@ where /// /// The array is shown in multiline style. impl fmt::Binary for ArrayBase -where - S: Data, - S::RefType: Referent, +where S: Data { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/arrayref.rs b/src/arrayref.rs deleted file mode 100644 index 648f38d47..000000000 --- a/src/arrayref.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Code for the array reference type - -use core::ops::{Deref, DerefMut}; - -use crate::{ArrayBase, Dimension, LayoutRef, RawData, RawDataMut, RefBase}; - -/// Unit struct to mark a reference as raw -/// -/// Only visible because it is necessary for [`crate::RawRef`] -#[derive(Copy, Clone)] -pub struct Raw; - -/// Unit struct to mark a reference as safe -/// -/// Only visible because it is necessary for [`crate::ArrRef`] -#[derive(Copy, Clone)] -pub struct Safe; - -/// A trait for array references that adhere to the basic constraints of `ndarray`. -/// -/// Cannot be implemented outside of `ndarray`. -pub trait RawReferent -{ - private_decl! {} -} - -/// A trait for array references that point to data that is safe to read. -/// -/// Cannot be implemented outside of `ndarray`. -pub trait Referent: RawReferent -{ - private_decl! {} -} - -impl RawReferent for Raw -{ - private_impl! {} -} -impl RawReferent for Safe -{ - private_impl! {} -} -impl Referent for Safe -{ - private_impl! {} -} - -impl Deref for ArrayBase -where S: RawData -{ - type Target = RefBase; - - fn deref(&self) -> &Self::Target - { - // SAFETY: The pointer will hold all the guarantees of `as_ref`: - // - The pointer is aligned because neither type use repr(align) - // - It is "dereferencable" because it just points to self - // - For the same reason, it is initialized - unsafe { - (&self.layout as *const LayoutRef) - .cast::>() - .as_ref() - } - .expect("Pointer to self will always be non-null") - } -} - -impl DerefMut for ArrayBase -where - S: RawDataMut, - D: Dimension, -{ - fn deref_mut(&mut self) -> &mut Self::Target - { - self.try_ensure_unique(); - // SAFETY: The pointer will hold all the guarantees of `as_ref`: - // - The pointer is aligned because neither type use repr(align) - // - It is "dereferencable" because it just points to self - // - For the same reason, it is initialized - unsafe { - (&mut self.layout as *mut LayoutRef) - .cast::>() - .as_mut() - } - .expect("Pointer to self will always be non-null") - } -} diff --git a/src/arraytraits.rs b/src/arraytraits.rs index f1c556c0e..67ab05700 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -16,7 +16,6 @@ use std::mem::size_of; use std::ops::{Index, IndexMut}; use std::{iter::FromIterator, slice}; -use crate::arrayref::Referent; use crate::imp_prelude::*; use crate::Arc; @@ -39,14 +38,12 @@ pub(crate) fn array_out_of_bounds() -> ! } #[inline(always)] -pub fn debug_bounds_check(_a: &T, _index: &I) +pub fn debug_bounds_check(_a: &LayoutRef, _index: &I) where D: Dimension, I: NdIndex, - T: AsRef>, { - let _layout = _a.as_ref(); - debug_bounds_check!(_layout, *_index); + debug_bounds_check!(_a, *_index); } /// Access the element at **index**. @@ -104,8 +101,6 @@ where S: Data, S2: Data, D: Dimension, - S::RefType: Referent, - S2::RefType: Referent, { fn eq(&self, rhs: &ArrayBase) -> bool { @@ -139,8 +134,6 @@ where S: Data, S2: Data, D: Dimension, - S::RefType: Referent, - S2::RefType: Referent, { fn eq(&self, rhs: &&ArrayBase) -> bool { @@ -157,8 +150,6 @@ where S: Data, S2: Data, D: Dimension, - S::RefType: Referent, - S2::RefType: Referent, { fn eq(&self, rhs: &ArrayBase) -> bool { @@ -171,7 +162,6 @@ where D: Dimension, S: Data, S::Elem: Eq, - S::RefType: Referent, { } @@ -230,7 +220,6 @@ impl<'a, S, D> IntoIterator for &'a ArrayBase where D: Dimension, S: Data, - S::RefType: Referent, { type Item = &'a S::Elem; type IntoIter = Iter<'a, S::Elem, D>; @@ -245,7 +234,6 @@ impl<'a, S, D> IntoIterator for &'a mut ArrayBase where D: Dimension, S: DataMut, - S::RefType: Referent, { type Item = &'a mut S::Elem; type IntoIter = IterMut<'a, S::Elem, D>; @@ -285,7 +273,6 @@ where D: Dimension, S: Data, S::Elem: hash::Hash, - S::RefType: Referent, { // Note: elements are hashed in the logical order fn hash(&self, state: &mut H) @@ -383,7 +370,6 @@ impl<'a, A, S, D> From<&'a ArrayBase> for ArrayView<'a, A, D> where S: Data, D: Dimension, - S::RefType: Referent, { /// Create a read-only array view of the array. fn from(array: &'a ArrayBase) -> Self @@ -462,7 +448,6 @@ impl<'a, A, S, D> From<&'a mut ArrayBase> for ArrayViewMut<'a, A, D> where S: DataMut, D: Dimension, - S::RefType: Referent, { /// Create a read-write array view of the array. fn from(array: &'a mut ArrayBase) -> Self diff --git a/src/data_traits.rs b/src/data_traits.rs index e9cc5792f..2d7a7de31 100644 --- a/src/data_traits.rs +++ b/src/data_traits.rs @@ -23,22 +23,7 @@ use std::mem::MaybeUninit; use std::mem::{self, size_of}; use std::ptr::NonNull; -use crate::arrayref::Referent; -use crate::{ - ArcArray, - Array, - ArrayBase, - CowRepr, - Dimension, - OwnedArcRepr, - OwnedRepr, - Raw, - RawReferent, - RawViewRepr, - RefBase, - Safe, - ViewRepr, -}; +use crate::{ArcArray, Array, ArrayBase, ArrayRef, CowRepr, Dimension, OwnedArcRepr, OwnedRepr, RawViewRepr, ViewRepr}; /// Array representation trait. /// @@ -55,9 +40,6 @@ pub unsafe trait RawData: Sized /// The array element type. type Elem; - /// The safety of the reference type - type RefType: RawReferent; - #[doc(hidden)] fn _is_pointer_inbounds(&self, ptr: *const Self::Elem) -> bool; @@ -144,7 +126,6 @@ pub unsafe trait Data: RawData where Self::Elem: Clone, D: Dimension, - Self::RefType: Referent, { // clone to shared self_.to_owned().into_shared() @@ -190,7 +171,6 @@ pub unsafe trait DataMut: Data + RawDataMut unsafe impl RawData for RawViewRepr<*const A> { type Elem = A; - type RefType = Raw; #[inline(always)] fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool @@ -212,7 +192,6 @@ unsafe impl RawDataClone for RawViewRepr<*const A> unsafe impl RawData for RawViewRepr<*mut A> { type Elem = A; - type RefType = Raw; #[inline(always)] fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool @@ -251,7 +230,6 @@ unsafe impl RawDataClone for RawViewRepr<*mut A> unsafe impl RawData for OwnedArcRepr { type Elem = A; - type RefType = Safe; fn _is_pointer_inbounds(&self, self_ptr: *const Self::Elem) -> bool { @@ -356,7 +334,6 @@ unsafe impl RawDataClone for OwnedArcRepr unsafe impl RawData for OwnedRepr { type Elem = A; - type RefType = Safe; fn _is_pointer_inbounds(&self, self_ptr: *const Self::Elem) -> bool { @@ -436,7 +413,6 @@ where A: Clone unsafe impl<'a, A> RawData for ViewRepr<&'a A> { type Elem = A; - type RefType = Safe; #[inline(always)] fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool @@ -475,7 +451,6 @@ unsafe impl<'a, A> RawDataClone for ViewRepr<&'a A> unsafe impl<'a, A> RawData for ViewRepr<&'a mut A> { type Elem = A; - type RefType = Safe; #[inline(always)] fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool @@ -602,7 +577,6 @@ unsafe impl DataOwned for OwnedArcRepr unsafe impl<'a, A> RawData for CowRepr<'a, A> { type Elem = A; - type RefType = Safe; #[inline] fn _is_pointer_inbounds(&self, ptr: *const Self::Elem) -> bool @@ -627,7 +601,7 @@ where A: Clone { match array.data { CowRepr::View(_) => { - let owned = RefBase::to_owned(array); + let owned = ArrayRef::to_owned(array); array.data = CowRepr::Owned(owned.data); array.layout.ptr = owned.layout.ptr; array.layout.dim = owned.layout.dim; diff --git a/src/impl_1d.rs b/src/impl_1d.rs index 5257a4e4b..e49fdd731 100644 --- a/src/impl_1d.rs +++ b/src/impl_1d.rs @@ -11,15 +11,12 @@ use alloc::vec::Vec; use std::mem::MaybeUninit; -use crate::arrayref::Referent; use crate::imp_prelude::*; use crate::low_level_util::AbortIfPanic; /// # Methods For 1-D Arrays impl ArrayBase -where - S: RawData, - S::RefType: Referent, +where S: RawData { /// Return an vector with the elements of the one-dimensional array. pub fn to_vec(&self) -> Vec diff --git a/src/impl_2d.rs b/src/impl_2d.rs index 7259c1c29..2e5f9c31e 100644 --- a/src/impl_2d.rs +++ b/src/impl_2d.rs @@ -7,7 +7,7 @@ // except according to those terms. //! Methods for two-dimensional arrays. -use crate::{arrayref::Referent, imp_prelude::*}; +use crate::imp_prelude::*; /// # Methods For 2-D Arrays impl ArrayBase @@ -24,9 +24,7 @@ where S: RawData /// ``` #[track_caller] pub fn row(&self, index: Ix) -> ArrayView1<'_, A> - where - S: Data, - S::RefType: Referent, + where S: Data { self.index_axis(Axis(0), index) } @@ -43,9 +41,7 @@ where S: RawData /// ``` #[track_caller] pub fn row_mut(&mut self, index: Ix) -> ArrayViewMut1<'_, A> - where - S: DataMut, - S::RefType: Referent, + where S: DataMut { self.index_axis_mut(Axis(0), index) } @@ -69,7 +65,7 @@ where S: RawData /// ``` pub fn nrows(&self) -> usize { - self.len_of(Axis(0)) + self.as_ref().len_of(Axis(0)) } /// Return an array view of column `index`. @@ -83,9 +79,7 @@ where S: RawData /// ``` #[track_caller] pub fn column(&self, index: Ix) -> ArrayView1<'_, A> - where - S: Data, - S::RefType: Referent, + where S: Data { self.index_axis(Axis(1), index) } @@ -102,9 +96,7 @@ where S: RawData /// ``` #[track_caller] pub fn column_mut(&mut self, index: Ix) -> ArrayViewMut1<'_, A> - where - S: DataMut, - S::RefType: Referent, + where S: DataMut { self.index_axis_mut(Axis(1), index) } @@ -128,7 +120,7 @@ where S: RawData /// ``` pub fn ncols(&self) -> usize { - self.len_of(Axis(1)) + self.as_ref().len_of(Axis(1)) } /// Return true if the array is square, false otherwise. @@ -148,7 +140,7 @@ where S: RawData /// ``` pub fn is_square(&self) -> bool { - let (m, n) = self.dim(); + let (m, n) = self.as_ref().dim(); m == n } } diff --git a/src/impl_clone.rs b/src/impl_clone.rs index 4c16039a7..402437941 100644 --- a/src/impl_clone.rs +++ b/src/impl_clone.rs @@ -16,13 +16,13 @@ impl Clone for ArrayBase { // safe because `clone_with_ptr` promises to provide equivalent data and ptr unsafe { - let (data, ptr) = self.data.clone_with_ptr(self.ptr); + let (data, ptr) = self.data.clone_with_ptr(self.layout.ptr); ArrayBase { data, layout: LayoutRef { ptr, - dim: self.dim.clone(), - strides: self.strides.clone(), + dim: self.layout.dim.clone(), + strides: self.layout.strides.clone(), }, } } @@ -34,9 +34,9 @@ impl Clone for ArrayBase fn clone_from(&mut self, other: &Self) { unsafe { - self.layout.ptr = self.data.clone_from_with_ptr(&other.data, other.ptr); - self.layout.dim.clone_from(&other.dim); - self.layout.strides.clone_from(&other.strides); + self.layout.ptr = self.data.clone_from_with_ptr(&other.data, other.layout.ptr); + self.layout.dim.clone_from(&other.layout.dim); + self.layout.strides.clone_from(&other.layout.strides); } } } diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs index 64ec33d56..260937a90 100644 --- a/src/impl_constructors.rs +++ b/src/impl_constructors.rs @@ -20,7 +20,6 @@ use num_traits::{One, Zero}; use std::mem; use std::mem::MaybeUninit; -use crate::arrayref::Referent; use crate::dimension::offset_from_low_addr_ptr_to_logical_ptr; use crate::dimension::{self, CanIndexCheckMode}; use crate::error::{self, ShapeError}; @@ -189,9 +188,7 @@ where S: DataOwned /// ## Constructor methods for two-dimensional arrays. impl ArrayBase -where - S: DataOwned, - S::RefType: Referent, +where S: DataOwned { /// Create an identity matrix of size `n` (square 2D array). /// @@ -224,7 +221,6 @@ where A: Clone + Zero, S: DataMut, S2: Data, - S2::RefType: Referent, { let n = diag.len(); let mut arr = Self::zeros((n, n)); @@ -621,7 +617,6 @@ where where Sh: ShapeBuilder, F: FnOnce(ArrayViewMut, D>), - <::MaybeUninit as RawData>::RefType: Referent, { let mut array = Self::uninit(shape); // Safe because: the array is unshared here diff --git a/src/impl_cow.rs b/src/impl_cow.rs index f5cd5447d..c409ae0cc 100644 --- a/src/impl_cow.rs +++ b/src/impl_cow.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::{arrayref::Referent, imp_prelude::*}; +use crate::imp_prelude::*; /// Methods specific to `CowArray`. /// @@ -77,7 +77,6 @@ impl<'a, A, S, D> From<&'a ArrayBase> for CowArray<'a, A, D> where S: Data, D: Dimension, - S::RefType: Referent, { /// Create a read-only clone-on-write view of the array. fn from(array: &'a ArrayBase) -> Self diff --git a/src/impl_methods.rs b/src/impl_methods.rs index e9de470a3..7cdf7d3bc 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -14,7 +14,6 @@ use alloc::vec::Vec; use rawpointer::PointerExt; use std::mem::{size_of, ManuallyDrop}; -use crate::arrayref::Referent; use crate::imp_prelude::*; use crate::argument_traits::AssignElem; @@ -39,10 +38,10 @@ use crate::math_cell::MathCell; use crate::order::Order; use crate::shape_builder::ShapeArg; use crate::zip::{IntoNdProducer, Zip}; +use crate::ArrayRef; use crate::AxisDescription; use crate::LayoutRef; -use crate::RawReferent; -use crate::RefBase; +use crate::RawRef; use crate::{arraytraits, DimMax}; use crate::iter::{ @@ -176,11 +175,10 @@ impl LayoutRef } } -impl RefBase +impl ArrayRef { /// Return a read-only view of the array pub fn view(&self) -> ArrayView<'_, A, D> - where R: Referent { // debug_assert!(self.pointer_is_inbounds()); unsafe { ArrayView::new(self.ptr, self.dim.clone(), self.strides.clone()) } @@ -188,7 +186,6 @@ impl RefBase /// Return a read-write view of the array pub fn view_mut(&mut self) -> ArrayViewMut<'_, A, D> - where R: Referent { unsafe { ArrayViewMut::new(self.ptr, self.dim.clone(), self.strides.clone()) } } @@ -201,7 +198,6 @@ impl RefBase /// The view acts "as if" the elements are temporarily in cells, and elements /// can be changed through shared references using the regular cell methods. pub fn cell_view(&mut self) -> ArrayView<'_, MathCell, D> - where R: Referent { self.view_mut().into_cell_view() } @@ -237,9 +233,7 @@ impl RefBase /// # assert_eq!(arr, owned); /// ``` pub fn to_owned(&self) -> Array - where - A: Clone, - R: Referent, + where A: Clone { if let Some(slc) = self.as_slice_memory_order() { unsafe { Array::from_shape_vec_unchecked(self.dim.clone().strides(self.strides.clone()), slc.to_vec()) } @@ -288,7 +282,6 @@ where where A: Clone, S: Data, - S::RefType: Referent, { (**self).to_owned() } @@ -299,7 +292,6 @@ where where A: Clone, S: Data, - S::RefType: Referent, { S::to_shared(self) } @@ -356,7 +348,7 @@ where } } -impl RefBase +impl ArrayRef { /// Returns a reference to the first element of the array, or `None` if it /// is empty. @@ -374,7 +366,6 @@ impl RefBase /// assert_eq!(b.first(), None); /// ``` pub fn first(&self) -> Option<&A> - where R: Referent { if self.is_empty() { None @@ -399,7 +390,6 @@ impl RefBase /// assert_eq!(b.first_mut(), None); /// ``` pub fn first_mut(&mut self) -> Option<&mut A> - where R: Referent { if self.is_empty() { None @@ -424,7 +414,6 @@ impl RefBase /// assert_eq!(b.last(), None); /// ``` pub fn last(&self) -> Option<&A> - where R: Referent { if self.is_empty() { None @@ -453,7 +442,6 @@ impl RefBase /// assert_eq!(b.last_mut(), None); /// ``` pub fn last_mut(&mut self) -> Option<&mut A> - where R: Referent { if self.is_empty() { None @@ -473,7 +461,6 @@ impl RefBase /// /// Iterator element type is `&A`. pub fn iter(&self) -> Iter<'_, A, D> - where R: Referent { // debug_assert!(self.pointer_is_inbounds()); self.view().into_iter_() @@ -486,7 +473,6 @@ impl RefBase /// /// Iterator element type is `&mut A`. pub fn iter_mut(&mut self) -> IterMut<'_, A, D> - where R: Referent { self.view_mut().into_iter_() } @@ -500,7 +486,6 @@ impl RefBase /// /// See also [`Zip::indexed`] pub fn indexed_iter(&self) -> IndexedIter<'_, A, D> - where R: Referent { IndexedIter::new(self.view().into_elements_base()) } @@ -512,7 +497,6 @@ impl RefBase /// /// Iterator element type is `(D::Pattern, &mut A)`. pub fn indexed_iter_mut(&mut self) -> IndexedIterMut<'_, A, D> - where R: Referent { IndexedIterMut::new(self.view_mut().into_elements_base()) } @@ -526,9 +510,7 @@ impl RefBase /// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) #[track_caller] pub fn slice(&self, info: I) -> ArrayView<'_, A, I::OutDim> - where - I: SliceArg, - R: Referent, + where I: SliceArg { self.view().slice_move(info) } @@ -542,9 +524,7 @@ impl RefBase /// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) #[track_caller] pub fn slice_mut(&mut self, info: I) -> ArrayViewMut<'_, A, I::OutDim> - where - I: SliceArg, - R: Referent, + where I: SliceArg { self.view_mut().slice_move(info) } @@ -574,9 +554,7 @@ impl RefBase /// ``` #[track_caller] pub fn multi_slice_mut<'a, M>(&'a mut self, info: M) -> M::Output - where - M: MultiSliceArg<'a, A, D>, - R: Referent, + where M: MultiSliceArg<'a, A, D> { info.multi_slice_move(self.view_mut()) } @@ -600,7 +578,7 @@ where { assert_eq!( info.in_ndim(), - self.ndim(), + self.as_ref().ndim(), "The input dimension of `info` must match the array to be sliced.", ); let out_ndim = info.out_ndim(); @@ -614,14 +592,14 @@ where // Slice the axis in-place to update the `dim`, `strides`, and `ptr`. self.slice_axis_inplace(Axis(old_axis), Slice { start, end, step }); // Copy the sliced dim and stride to corresponding axis. - new_dim[new_axis] = self.dim[old_axis]; - new_strides[new_axis] = self.strides[old_axis]; + new_dim[new_axis] = self.layout.dim[old_axis]; + new_strides[new_axis] = self.layout.strides[old_axis]; old_axis += 1; new_axis += 1; } SliceInfoElem::Index(index) => { // Collapse the axis in-place to update the `ptr`. - let i_usize = abs_index(self.len_of(Axis(old_axis)), index); + let i_usize = abs_index(self.as_ref().len_of(Axis(old_axis)), index); self.collapse_axis(Axis(old_axis), i_usize); // Skip copying the axis since it should be removed. Note that // removing this axis is safe because `.collapse_axis()` panics @@ -636,7 +614,7 @@ where new_axis += 1; } }); - debug_assert_eq!(old_axis, self.ndim()); + debug_assert_eq!(old_axis, self.as_ref().ndim()); debug_assert_eq!(new_axis, out_ndim); // safe because new dimension, strides allow access to a subset of old data @@ -692,7 +670,7 @@ impl LayoutRef } } -impl RefBase +impl ArrayRef { /// Return a view of the array, sliced along the specified axis. /// @@ -701,7 +679,6 @@ impl RefBase #[track_caller] #[must_use = "slice_axis returns an array view with the sliced result"] pub fn slice_axis(&self, axis: Axis, indices: Slice) -> ArrayView<'_, A, D> - where R: Referent { let mut view = self.view(); view.slice_axis_inplace(axis, indices); @@ -715,7 +692,6 @@ impl RefBase #[track_caller] #[must_use = "slice_axis_mut returns an array view with the sliced result"] pub fn slice_axis_mut(&mut self, axis: Axis, indices: Slice) -> ArrayViewMut<'_, A, D> - where R: Referent { let mut view_mut = self.view_mut(); view_mut.slice_axis_inplace(axis, indices); @@ -758,7 +734,7 @@ where } } -impl RefBase +impl ArrayRef { /// Return a view of a slice of the array, with a closure specifying the /// slice for each axis. @@ -769,9 +745,7 @@ impl RefBase /// **Panics** if an index is out of bounds or step size is zero. #[track_caller] pub fn slice_each_axis(&self, f: F) -> ArrayView<'_, A, D> - where - F: FnMut(AxisDescription) -> Slice, - R: Referent, + where F: FnMut(AxisDescription) -> Slice { let mut view = self.view(); view.slice_each_axis_inplace(f); @@ -787,9 +761,7 @@ impl RefBase /// **Panics** if an index is out of bounds or step size is zero. #[track_caller] pub fn slice_each_axis_mut(&mut self, f: F) -> ArrayViewMut<'_, A, D> - where - F: FnMut(AxisDescription) -> Slice, - R: Referent, + where F: FnMut(AxisDescription) -> Slice { let mut view = self.view_mut(); view.slice_each_axis_inplace(f); @@ -823,7 +795,7 @@ impl LayoutRef } } -impl RefBase +impl ArrayRef { /// Return a reference to the element at `index`, or return `None` /// if the index is out of bounds. @@ -844,13 +816,14 @@ impl RefBase /// ); /// ``` pub fn get(&self, index: I) -> Option<&A> - where - R: Referent, - I: NdIndex, + where I: NdIndex { unsafe { self.get_ptr(index).map(|ptr| &*ptr) } } +} +impl RawRef +{ /// Return a raw pointer to the element at `index`, or return `None` /// if the index is out of bounds. /// @@ -872,17 +845,21 @@ impl RefBase .index_checked(&self.dim, &self.strides) .map(move |offset| unsafe { ptr.as_ptr().offset(offset) as *const _ }) } +} +impl ArrayRef +{ /// Return a mutable reference to the element at `index`, or return `None` /// if the index is out of bounds. pub fn get_mut(&mut self, index: I) -> Option<&mut A> - where - R: Referent, - I: NdIndex, + where I: NdIndex { unsafe { self.get_mut_ptr(index).map(|ptr| &mut *ptr) } } +} +impl RawRef +{ /// Return a raw pointer to the element at `index`, or return `None` /// if the index is out of bounds. /// @@ -910,7 +887,10 @@ impl RefBase .index_checked(&self.dim, &self.strides) .map(move |offset| unsafe { ptr.offset(offset) }) } +} +impl ArrayRef +{ /// Perform *unchecked* array indexing. /// /// Return a reference to the element at `index`. @@ -922,9 +902,7 @@ impl RefBase /// The caller must ensure that the index is in-bounds. #[inline] pub unsafe fn uget(&self, index: I) -> &A - where - R: Referent, - I: NdIndex, + where I: NdIndex { arraytraits::debug_bounds_check(self, &index); let off = index.index_unchecked(&self.strides); @@ -947,9 +925,7 @@ impl RefBase /// for `Array` and `ArrayViewMut`, but not for `ArcArray` or `CowArray`.) #[inline] pub unsafe fn uget_mut(&mut self, index: I) -> &mut A - where - R: Referent, - I: NdIndex, + where I: NdIndex { // debug_assert!(self.data.is_unique()); arraytraits::debug_bounds_check(self, &index); @@ -964,9 +940,7 @@ impl RefBase /// ***Panics*** if an index is out of bounds. #[track_caller] pub fn swap(&mut self, index1: I, index2: I) - where - R: Referent, - I: NdIndex, + where I: NdIndex { let ptr = self.as_mut_ptr(); let offset1 = index1.index_checked(&self.dim, &self.strides); @@ -997,9 +971,7 @@ impl RefBase /// 2. the data is uniquely held by the array. (This property is guaranteed /// for `Array` and `ArrayViewMut`, but not for `ArcArray` or `CowArray`.) pub unsafe fn uswap(&mut self, index1: I, index2: I) - where - R: Referent, - I: NdIndex, + where I: NdIndex { // debug_assert!(self.data.is_unique()); arraytraits::debug_bounds_check(self, &index1); @@ -1012,7 +984,6 @@ impl RefBase // `get` for zero-dimensional arrays // panics if dimension is not zero. otherwise an element is always present. fn get_0d(&self) -> &A - where R: Referent { assert!(self.ndim() == 0); unsafe { &*self.as_ptr() } @@ -1041,9 +1012,7 @@ impl RefBase /// ``` #[track_caller] pub fn index_axis(&self, axis: Axis, index: usize) -> ArrayView<'_, A, D::Smaller> - where - R: Referent, - D: RemoveAxis, + where D: RemoveAxis { self.view().index_axis_move(axis, index) } @@ -1074,9 +1043,7 @@ impl RefBase /// ``` #[track_caller] pub fn index_axis_mut(&mut self, axis: Axis, index: usize) -> ArrayViewMut<'_, A, D::Smaller> - where - R: Referent, - D: RemoveAxis, + where D: RemoveAxis { self.view_mut().index_axis_move(axis, index) } @@ -1097,8 +1064,8 @@ where where D: RemoveAxis { self.collapse_axis(axis, index); - let dim = self.dim.remove_axis(axis); - let strides = self.strides.remove_axis(axis); + let dim = self.layout.dim.remove_axis(axis); + let strides = self.layout.strides.remove_axis(axis); // safe because new dimension, strides allow access to a subset of old data unsafe { self.with_strides_dim(strides, dim) } } @@ -1118,7 +1085,7 @@ impl LayoutRef } } -impl RefBase +impl ArrayRef { /// Along `axis`, select arbitrary subviews corresponding to `indices` /// and copy them into a new array. @@ -1145,7 +1112,6 @@ impl RefBase pub fn select(&self, axis: Axis, indices: &[Ix]) -> Array where A: Clone, - R: Referent, D: RemoveAxis, { if self.ndim() == 1 { @@ -1207,7 +1173,6 @@ impl RefBase /// } /// ``` pub fn rows(&self) -> Lanes<'_, A, D::Smaller> - where R: Referent { let mut n = self.ndim(); if n == 0 { @@ -1221,7 +1186,6 @@ impl RefBase /// /// Iterator element is `ArrayView1` (1D read-write array view). pub fn rows_mut(&mut self) -> LanesMut<'_, A, D::Smaller> - where R: Referent { let mut n = self.ndim(); if n == 0 { @@ -1257,7 +1221,6 @@ impl RefBase /// } /// ``` pub fn columns(&self) -> Lanes<'_, A, D::Smaller> - where R: Referent { Lanes::new(self.view(), Axis(0)) } @@ -1267,7 +1230,6 @@ impl RefBase /// /// Iterator element is `ArrayView1` (1D read-write array view). pub fn columns_mut(&mut self) -> LanesMut<'_, A, D::Smaller> - where R: Referent { LanesMut::new(self.view_mut(), Axis(0)) } @@ -1301,7 +1263,6 @@ impl RefBase /// assert_eq!(inner2.into_iter().next().unwrap(), aview1(&[0, 1, 2])); /// ``` pub fn lanes(&self, axis: Axis) -> Lanes<'_, A, D::Smaller> - where R: Referent { Lanes::new(self.view(), axis) } @@ -1311,7 +1272,6 @@ impl RefBase /// /// Iterator element is `ArrayViewMut1` (1D read-write array view). pub fn lanes_mut(&mut self, axis: Axis) -> LanesMut<'_, A, D::Smaller> - where R: Referent { LanesMut::new(self.view_mut(), axis) } @@ -1324,9 +1284,7 @@ impl RefBase /// Iterator element is `ArrayView` (read-only array view). #[allow(deprecated)] pub fn outer_iter(&self) -> AxisIter<'_, A, D::Smaller> - where - R: Referent, - D: RemoveAxis, + where D: RemoveAxis { self.view().into_outer_iter() } @@ -1339,9 +1297,7 @@ impl RefBase /// Iterator element is `ArrayViewMut` (read-write array view). #[allow(deprecated)] pub fn outer_iter_mut(&mut self) -> AxisIterMut<'_, A, D::Smaller> - where - R: Referent, - D: RemoveAxis, + where D: RemoveAxis { self.view_mut().into_outer_iter() } @@ -1363,9 +1319,7 @@ impl RefBase /// #[track_caller] pub fn axis_iter(&self, axis: Axis) -> AxisIter<'_, A, D::Smaller> - where - R: Referent, - D: RemoveAxis, + where D: RemoveAxis { AxisIter::new(self.view(), axis) } @@ -1379,9 +1333,7 @@ impl RefBase /// **Panics** if `axis` is out of bounds. #[track_caller] pub fn axis_iter_mut(&mut self, axis: Axis) -> AxisIterMut<'_, A, D::Smaller> - where - R: Referent, - D: RemoveAxis, + where D: RemoveAxis { AxisIterMut::new(self.view_mut(), axis) } @@ -1414,7 +1366,6 @@ impl RefBase /// ``` #[track_caller] pub fn axis_chunks_iter(&self, axis: Axis, size: usize) -> AxisChunksIter<'_, A, D> - where R: Referent { AxisChunksIter::new(self.view(), axis, size) } @@ -1427,7 +1378,6 @@ impl RefBase /// **Panics** if `axis` is out of bounds or if `size` is zero. #[track_caller] pub fn axis_chunks_iter_mut(&mut self, axis: Axis, size: usize) -> AxisChunksIterMut<'_, A, D> - where R: Referent { AxisChunksIterMut::new(self.view_mut(), axis, size) } @@ -1445,9 +1395,7 @@ impl RefBase /// number of array axes.) #[track_caller] pub fn exact_chunks(&self, chunk_size: E) -> ExactChunks<'_, A, D> - where - E: IntoDimension, - R: Referent, + where E: IntoDimension { ExactChunks::new(self.view(), chunk_size) } @@ -1486,9 +1434,7 @@ impl RefBase /// ``` #[track_caller] pub fn exact_chunks_mut(&mut self, chunk_size: E) -> ExactChunksMut<'_, A, D> - where - E: IntoDimension, - R: Referent, + where E: IntoDimension { ExactChunksMut::new(self.view_mut(), chunk_size) } @@ -1501,9 +1447,7 @@ impl RefBase /// This is essentially equivalent to [`.windows_with_stride()`] with unit stride. #[track_caller] pub fn windows(&self, window_size: E) -> Windows<'_, A, D> - where - E: IntoDimension, - R: Referent, + where E: IntoDimension { Windows::new(self.view(), window_size) } @@ -1554,9 +1498,7 @@ impl RefBase /// ``` #[track_caller] pub fn windows_with_stride(&self, window_size: E, stride: E) -> Windows<'_, A, D> - where - E: IntoDimension, - R: Referent, + where E: IntoDimension { Windows::new_with_stride(self.view(), window_size, stride) } @@ -1583,7 +1525,6 @@ impl RefBase /// } /// ``` pub fn axis_windows(&self, axis: Axis, window_size: usize) -> AxisWindows<'_, A, D> - where R: Referent { let axis_index = axis.index(); @@ -1600,23 +1541,18 @@ impl RefBase AxisWindows::new(self.view(), axis, window_size) } -} -impl RefBase -{ /// Return a view of the diagonal elements of the array. /// /// The diagonal is simply the sequence indexed by *(0, 0, .., 0)*, /// *(1, 1, ..., 1)* etc as long as all axes have elements. pub fn diag(&self) -> ArrayView1<'_, A> - where R: Referent { self.view().into_diag() } /// Return a read-write view over the diagonal elements of the array. pub fn diag_mut(&mut self) -> ArrayViewMut1<'_, A> - where R: Referent { self.view_mut().into_diag() } @@ -1631,8 +1567,8 @@ where fn diag_params(&self) -> (Ix, Ixs) { /* empty shape has len 1 */ - let len = self.dim.slice().iter().cloned().min().unwrap_or(1); - let stride = self.as_ref().strides().iter().sum(); + let len = self.layout.dim.slice().iter().cloned().min().unwrap_or(1); + let stride = LayoutRef::strides(self.as_ref()).iter().sum(); (len, stride) } @@ -1649,7 +1585,7 @@ where /// This is equivalent to `.ensure_unique()` if `S: DataMut`. /// /// This method is mostly only useful with unsafe code. - pub(crate) fn try_ensure_unique(&mut self) + fn try_ensure_unique(&mut self) where S: RawDataMut { debug_assert!(self.pointer_is_inbounds()); @@ -1660,7 +1596,7 @@ where /// Make the array unshared. /// /// This method is mostly only useful with unsafe code. - fn ensure_unique(&mut self) + pub(crate) fn ensure_unique(&mut self) where S: DataMut { debug_assert!(self.pointer_is_inbounds()); @@ -1688,7 +1624,7 @@ impl LayoutRef } } -impl RefBase +impl ArrayRef { /// Return a standard-layout array containing the data, cloning if /// necessary. @@ -1713,9 +1649,7 @@ impl RefBase /// assert!(cow_owned.is_standard_layout()); /// ``` pub fn as_standard_layout(&self) -> CowArray<'_, A, D> - where - R: Referent, - A: Clone, + where A: Clone { if self.is_standard_layout() { CowArray::from(self.view()) @@ -1731,7 +1665,10 @@ impl RefBase } } } +} +impl RawRef +{ /// Return a pointer to the first element in the array. /// /// Raw access to array elements needs to follow the strided indexing @@ -1775,11 +1712,11 @@ where where S: RawDataMut { self.try_ensure_unique(); // for ArcArray - self.ptr.as_ptr() + self.layout.ptr.as_ptr() } } -impl RefBase +impl RawRef { /// Return a raw view of the array. #[inline] @@ -1810,7 +1747,7 @@ where where S: RawDataMut { self.try_ensure_unique(); // for ArcArray - unsafe { RawArrayViewMut::new(self.ptr, self.dim.clone(), self.strides.clone()) } + unsafe { RawArrayViewMut::new(self.layout.ptr, self.layout.dim.clone(), self.layout.strides.clone()) } } /// Return a raw mutable view of the array. @@ -1863,7 +1800,7 @@ where } } -impl RefBase +impl ArrayRef { /// Return the array’s data as a slice, if it is contiguous and in standard order. /// Return `None` otherwise. @@ -1871,7 +1808,6 @@ impl RefBase /// If this function returns `Some(_)`, then the element order in the slice /// corresponds to the logical order of the array’s elements. pub fn as_slice(&self) -> Option<&[A]> - where R: Referent { if self.is_standard_layout() { unsafe { Some(slice::from_raw_parts(self.ptr.as_ptr(), self.len())) } @@ -1883,7 +1819,6 @@ impl RefBase /// Return the array’s data as a slice, if it is contiguous and in standard order. /// Return `None` otherwise. pub fn as_slice_mut(&mut self) -> Option<&mut [A]> - where R: Referent { if self.is_standard_layout() { unsafe { Some(slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len())) } @@ -1898,7 +1833,6 @@ impl RefBase /// If this function returns `Some(_)`, then the elements in the slice /// have whatever order the elements have in memory. pub fn as_slice_memory_order(&self) -> Option<&[A]> - where R: Referent { if self.is_contiguous() { let offset = offset_from_low_addr_ptr_to_logical_ptr(&self.dim, &self.strides); @@ -1915,7 +1849,6 @@ impl RefBase /// method unshares the data if necessary, but it preserves the existing /// strides. pub fn as_slice_memory_order_mut(&mut self) -> Option<&mut [A]> - where R: Referent { self.try_as_slice_memory_order_mut().ok() } @@ -1923,7 +1856,6 @@ impl RefBase /// Return the array’s data as a slice if it is contiguous, otherwise /// return `self` in the `Err` variant. pub(crate) fn try_as_slice_memory_order_mut(&mut self) -> Result<&mut [A], &mut Self> - where R: Referent { if self.is_contiguous() { let offset = offset_from_low_addr_ptr_to_logical_ptr(&self.dim, &self.strides); @@ -1992,7 +1924,6 @@ impl RefBase where E: ShapeArg, A: Clone, - R: Referent, { let (shape, order) = new_shape.into_shape_and_order(); self.to_shape_order(shape, order.unwrap_or(Order::RowMajor)) @@ -2002,7 +1933,6 @@ impl RefBase where E: Dimension, A: Clone, - R: Referent, { let len = self.dim.size(); if size_of_shape_checked(&shape) != Ok(len) { @@ -2099,8 +2029,8 @@ where where E: Dimension { let shape = shape.into_dimension(); - if size_of_shape_checked(&shape) != Ok(self.dim.size()) { - return Err(error::incompatible_shapes(&self.dim, &shape)); + if size_of_shape_checked(&shape) != Ok(self.layout.dim.size()) { + return Err(error::incompatible_shapes(&self.layout.dim, &shape)); } // Check if contiguous, then we can change shape @@ -2109,7 +2039,12 @@ where match order { Order::RowMajor if self.is_standard_layout() => Ok(self.with_strides_dim(shape.default_strides(), shape)), - Order::ColumnMajor if self.raw_view().reversed_axes().is_standard_layout() => + Order::ColumnMajor + if self + .as_ref() + .raw_view() + .reversed_axes() + .is_standard_layout() => Ok(self.with_strides_dim(shape.fortran_strides(), shape)), _otherwise => Err(error::from_kind(error::ErrorKind::IncompatibleLayout)), } @@ -2144,15 +2079,21 @@ where where E: IntoDimension { let shape = shape.into_dimension(); - if size_of_shape_checked(&shape) != Ok(self.dim.size()) { - return Err(error::incompatible_shapes(&self.dim, &shape)); + if size_of_shape_checked(&shape) != Ok(self.layout.dim.size()) { + return Err(error::incompatible_shapes(&self.layout.dim, &shape)); } // Check if contiguous, if not => copy all, else just adapt strides unsafe { // safe because arrays are contiguous and len is unchanged if self.is_standard_layout() { Ok(self.with_strides_dim(shape.default_strides(), shape)) - } else if self.ndim() > 1 && self.raw_view().reversed_axes().is_standard_layout() { + } else if self.as_ref().ndim() > 1 + && self + .as_ref() + .raw_view() + .reversed_axes() + .is_standard_layout() + { Ok(self.with_strides_dim(shape.fortran_strides(), shape)) } else { Err(error::from_kind(error::ErrorKind::IncompatibleLayout)) @@ -2178,7 +2119,6 @@ where S: DataOwned, A: Clone, E: ShapeArg, - S::RefType: Referent, { let (shape, order) = shape.into_shape_and_order(); let order = order.unwrap_or(Order::RowMajor); @@ -2190,7 +2130,6 @@ where S: DataOwned, A: Clone, E: Dimension, - S::RefType: Referent, { let len = self.dim.size(); if size_of_shape_checked(&shape) != Ok(len) { @@ -2256,7 +2195,6 @@ where S: DataShared + DataOwned, A: Clone, E: IntoDimension, - S::RefType: Referent, { let shape = shape.into_dimension(); if size_of_shape_checked(&shape) != Ok(self.dim.size()) { @@ -2278,7 +2216,7 @@ where } } -impl RefBase +impl ArrayRef { /// Flatten the array to a one-dimensional array. /// @@ -2292,9 +2230,7 @@ impl RefBase /// assert_eq!(flattened, arr1(&[1, 2, 3, 4, 5, 6, 7, 8])); /// ``` pub fn flatten(&self) -> CowArray<'_, A, Ix1> - where - A: Clone, - R: Referent, + where A: Clone { self.flatten_with_order(Order::RowMajor) } @@ -2315,9 +2251,7 @@ impl RefBase /// assert_eq!(flattened, arr1(&[1, 3, 5, 7, 2, 4, 6, 8])); /// ``` pub fn flatten_with_order(&self, order: Order) -> CowArray<'_, A, Ix1> - where - A: Clone, - R: Referent, + where A: Clone { self.to_shape((self.len(), order)).unwrap() } @@ -2344,7 +2278,6 @@ where where A: Clone, S: DataOwned, - S::RefType: Referent, { let len = self.len(); self.into_shape_clone(Ix1(len)).unwrap() @@ -2396,8 +2329,8 @@ where } else if D::NDIM.is_none() || D2::NDIM.is_none() { // one is dynamic dim // safe because dim, strides are equivalent under a different type - if let Some(dim) = D2::from_dimension(&self.dim) { - if let Some(strides) = D2::from_dimension(&self.strides) { + if let Some(dim) = D2::from_dimension(&self.layout.dim) { + if let Some(strides) = D2::from_dimension(&self.layout.strides) { return Ok(self.with_strides_dim(strides, dim)); } } @@ -2407,7 +2340,7 @@ where } } -impl RefBase +impl ArrayRef { /// Act like a larger size and/or shape array by *broadcasting* /// into a larger shape, if possible. @@ -2439,9 +2372,7 @@ impl RefBase /// ); /// ``` pub fn broadcast(&self, dim: E) -> Option> - where - E: IntoDimension, - R: Referent, + where E: IntoDimension { /// Return new stride when trying to grow `from` into shape `to` /// @@ -2509,12 +2440,10 @@ impl RefBase /// /// Return `ShapeError` if their shapes can not be broadcast together. #[allow(clippy::type_complexity)] - pub(crate) fn broadcast_with<'a, 'b, B, R2, E>( - &'a self, other: &'b RefBase, + pub(crate) fn broadcast_with<'a, 'b, B, E>( + &'a self, other: &'b ArrayRef, ) -> Result<(ArrayView<'a, A, DimMaxOf>, ArrayView<'b, B, DimMaxOf>), ShapeError> where - R: Referent, - R2: Referent, D: Dimension + DimMax, E: Dimension, { @@ -2601,7 +2530,7 @@ where { let axes = axes.into_dimension(); // Ensure that each axis is used exactly once. - let mut usage_counts = D::zeros(self.ndim()); + let mut usage_counts = D::zeros(self.as_ref().ndim()); for axis in axes.slice() { usage_counts[*axis] += 1; } @@ -2610,10 +2539,10 @@ where } // Determine the new shape and strides. let mut new_dim = usage_counts; // reuse to avoid an allocation - let mut new_strides = D::zeros(self.ndim()); + let mut new_strides = D::zeros(self.as_ref().ndim()); { - let dim = self.dim.slice(); - let strides = self.strides.slice(); + let dim = self.layout.dim.slice(); + let strides = self.layout.strides.slice(); for (new_axis, &axis) in axes.slice().iter().enumerate() { new_dim[new_axis] = dim[axis]; new_strides[new_axis] = strides[axis]; @@ -2635,7 +2564,7 @@ where } } -impl RefBase +impl ArrayRef { /// Return a transposed view of the array. /// @@ -2643,7 +2572,6 @@ impl RefBase /// /// See also the more general methods `.reversed_axes()` and `.swap_axes()`. pub fn t(&self) -> ArrayView<'_, A, D> - where R: Referent { self.view().reversed_axes() } @@ -2758,11 +2686,11 @@ where #[track_caller] pub fn insert_axis(self, axis: Axis) -> ArrayBase { - assert!(axis.index() <= self.ndim()); + assert!(axis.index() <= self.as_ref().ndim()); // safe because a new axis of length one does not affect memory layout unsafe { - let strides = self.strides.insert_axis(axis); - let dim = self.dim.insert_axis(axis); + let strides = self.layout.strides.insert_axis(axis); + let dim = self.layout.dim.insert_axis(axis); self.with_strides_dim(strides, dim) } } @@ -2782,11 +2710,11 @@ where pub(crate) fn pointer_is_inbounds(&self) -> bool { - self.data._is_pointer_inbounds(self.as_ptr()) + self.data._is_pointer_inbounds(self.as_ref().as_ptr()) } } -impl RefBase +impl ArrayRef { /// Perform an elementwise assigment to `self` from `rhs`. /// @@ -2794,11 +2722,8 @@ impl RefBase /// /// **Panics** if broadcasting isn’t possible. #[track_caller] - pub fn assign(&mut self, rhs: &RefBase) - where - R: Referent, - A: Clone, - R2: Referent, + pub fn assign(&mut self, rhs: &ArrayRef) + where A: Clone { self.zip_mut_with(rhs, |x, y| x.clone_from(y)); } @@ -2812,7 +2737,6 @@ impl RefBase #[track_caller] pub fn assign_to

(&self, to: P) where - R: Referent, P: IntoNdProducer, P::Item: AssignElem, A: Clone, @@ -2822,17 +2746,13 @@ impl RefBase /// Perform an elementwise assigment to `self` from element `x`. pub fn fill(&mut self, x: A) - where - R: Referent, - A: Clone, + where A: Clone { self.map_inplace(move |elt| elt.clone_from(&x)); } - pub(crate) fn zip_mut_with_same_shape(&mut self, rhs: &RefBase, mut f: F) + pub(crate) fn zip_mut_with_same_shape(&mut self, rhs: &ArrayRef, mut f: F) where - R: Referent, - R2: Referent, E: Dimension, F: FnMut(&mut A, &B), { @@ -2855,10 +2775,8 @@ impl RefBase // zip two arrays where they have different layout or strides #[inline(always)] - fn zip_mut_with_by_rows(&mut self, rhs: &RefBase, mut f: F) + fn zip_mut_with_by_rows(&mut self, rhs: &ArrayRef, mut f: F) where - R: Referent, - R2: Referent, E: Dimension, F: FnMut(&mut A, &B), { @@ -2874,9 +2792,7 @@ impl RefBase } fn zip_mut_with_elem(&mut self, rhs_elem: &B, mut f: F) - where - R: Referent, - F: FnMut(&mut A, &B), + where F: FnMut(&mut A, &B) { self.map_inplace(move |elt| f(elt, rhs_elem)); } @@ -2889,10 +2805,8 @@ impl RefBase /// **Panics** if broadcasting isn’t possible. #[track_caller] #[inline] - pub fn zip_mut_with(&mut self, rhs: &RefBase, f: F) + pub fn zip_mut_with(&mut self, rhs: &ArrayRef, f: F) where - R: Referent, - R2: Referent, E: Dimension, F: FnMut(&mut A, &B), { @@ -2915,7 +2829,6 @@ impl RefBase where F: FnMut(B, &'a A) -> B, A: 'a, - R: Referent, { if let Some(slc) = self.as_slice_memory_order() { slc.iter().fold(init, f) @@ -2948,7 +2861,6 @@ impl RefBase where F: FnMut(&'a A) -> B, A: 'a, - R: Referent, { unsafe { if let Some(slc) = self.as_slice_memory_order() { @@ -2973,7 +2885,6 @@ impl RefBase where F: FnMut(&'a mut A) -> B, A: 'a, - R: Referent, { let dim = self.dim.clone(); if self.is_contiguous() { @@ -3006,7 +2917,6 @@ impl RefBase where F: FnMut(A) -> B, A: Clone, - R: Referent, { self.map(move |x| f(x.clone())) } @@ -3026,7 +2936,6 @@ where S: DataMut, F: FnMut(A) -> A, A: Clone, - S::RefType: Referent, { self.mapv_inplace(f); self @@ -3052,7 +2961,6 @@ where F: FnMut(A) -> B, A: Clone + 'static, B: 'static, - S::RefType: Referent, { if core::any::TypeId::of::() == core::any::TypeId::of::() { // A and B are the same type. @@ -3076,14 +2984,13 @@ where } } -impl RefBase +impl ArrayRef { /// Modify the array in place by calling `f` by mutable reference on each element. /// /// Elements are visited in arbitrary order. pub fn map_inplace<'a, F>(&'a mut self, f: F) where - R: Referent, A: 'a, F: FnMut(&'a mut A), { @@ -3120,7 +3027,6 @@ impl RefBase /// ``` pub fn mapv_inplace(&mut self, mut f: F) where - R: Referent, F: FnMut(A) -> A, A: Clone, { @@ -3134,7 +3040,6 @@ impl RefBase where F: FnMut(&'a A), A: 'a, - R: Referent, { self.fold((), move |(), elt| f(elt)) } @@ -3153,7 +3058,6 @@ impl RefBase D: RemoveAxis, F: FnMut(&B, &A) -> B, B: Clone, - R: Referent, { let mut res = Array::from_elem(self.raw_dim().remove_axis(axis), init); for subview in self.axis_iter(axis) { @@ -3176,7 +3080,6 @@ impl RefBase D: RemoveAxis, F: FnMut(ArrayView1<'a, A>) -> B, A: 'a, - R: Referent, { if self.len_of(axis) == 0 { let new_dim = self.dim.remove_axis(axis); @@ -3202,7 +3105,6 @@ impl RefBase D: RemoveAxis, F: FnMut(ArrayViewMut1<'a, A>) -> B, A: 'a, - R: Referent, { if self.len_of(axis) == 0 { let new_dim = self.dim.remove_axis(axis); @@ -3224,7 +3126,7 @@ impl RefBase /// ***Panics*** if `axis` is out of bounds
/// ***Panics*** if not `index < self.len_of(axis)`. pub fn remove_index(&mut self, axis: Axis, index: usize) - where R: Referent // TODO: Check whether this needed to be DataOwned + // TODO: Check whether this needed to be DataOwned { assert!(index < self.len_of(axis), "index {} must be less than length of Axis({})", index, axis.index()); @@ -3264,15 +3166,13 @@ impl RefBase /// ); /// ``` pub fn accumulate_axis_inplace(&mut self, axis: Axis, mut f: F) - where - F: FnMut(&A, &mut A), - R: Referent, + where F: FnMut(&A, &mut A) { if self.len_of(axis) <= 1 { return; } let mut curr = self.raw_view_mut(); // mut borrow of the array here - let mut prev = curr.raw_view(); // derive further raw views from the same borrow + let mut prev = curr.as_ref().raw_view(); // derive further raw views from the same borrow prev.slice_axis_inplace(axis, Slice::from(..-1)); curr.slice_axis_inplace(axis, Slice::from(1..)); // This implementation relies on `Zip` iterating along `axis` in order. diff --git a/src/impl_ops.rs b/src/impl_ops.rs index ef2ffc80f..46ea18a7c 100644 --- a/src/impl_ops.rs +++ b/src/impl_ops.rs @@ -7,7 +7,6 @@ // except according to those terms. use crate::dimension::DimMax; -use crate::Referent; use crate::Zip; use num_complex::Complex; @@ -71,9 +70,6 @@ where S2: Data, D: Dimension + DimMax, E: Dimension, - S::RefType: Referent, - S2::RefType: Referent, - <::MaybeUninit as RawData>::RefType: Referent, { type Output = ArrayBase>::Output>; #[track_caller] @@ -102,9 +98,6 @@ where S2: Data, D: Dimension + DimMax, E: Dimension, - S::RefType: Referent, - S2::RefType: Referent, - <::MaybeUninit as RawData>::RefType: Referent, { type Output = ArrayBase>::Output>; #[track_caller] @@ -146,9 +139,6 @@ where S2: DataOwned + DataMut, D: Dimension, E: Dimension + DimMax, - S::RefType: Referent, - S2::RefType: Referent, - <::MaybeUninit as RawData>::RefType: Referent, { type Output = ArrayBase>::Output>; #[track_caller] @@ -189,8 +179,6 @@ where S2: Data, D: Dimension + DimMax, E: Dimension, - S::RefType: Referent, - S2::RefType: Referent, { type Output = Array>::Output>; #[track_caller] @@ -217,7 +205,6 @@ impl $trt for ArrayBase S: DataOwned + DataMut, D: Dimension, B: ScalarOperand, - S::RefType: Referent, { type Output = ArrayBase; fn $mth(mut self, x: B) -> ArrayBase { @@ -237,7 +224,6 @@ impl<'a, A, S, D, B> $trt for &'a ArrayBase S: Data, D: Dimension, B: ScalarOperand, - S::RefType: Referent, { type Output = Array; fn $mth(self, x: B) -> Self::Output { @@ -268,7 +254,6 @@ macro_rules! impl_scalar_lhs_op { impl $trt> for $scalar where S: DataOwned + DataMut, D: Dimension, - S::RefType: Referent, { type Output = ArrayBase; fn $mth(self, rhs: ArrayBase) -> ArrayBase { @@ -290,7 +275,6 @@ impl $trt> for $scalar impl<'a, S, D> $trt<&'a ArrayBase> for $scalar where S: Data, D: Dimension, - S::RefType: Referent, { type Output = Array<$scalar, D>; fn $mth(self, rhs: &ArrayBase) -> Self::Output { @@ -395,7 +379,6 @@ mod arithmetic_ops A: Clone + Neg, S: DataOwned + DataMut, D: Dimension, - S::RefType: Referent, { type Output = Self; /// Perform an elementwise negation of `self` and return the result. @@ -413,7 +396,6 @@ mod arithmetic_ops &'a A: 'a + Neg, S: Data, D: Dimension, - S::RefType: Referent, { type Output = Array; /// Perform an elementwise negation of reference `self` and return the @@ -429,7 +411,6 @@ mod arithmetic_ops A: Clone + Not, S: DataOwned + DataMut, D: Dimension, - S::RefType: Referent, { type Output = Self; /// Perform an elementwise unary not of `self` and return the result. @@ -447,7 +428,6 @@ mod arithmetic_ops &'a A: 'a + Not, S: Data, D: Dimension, - S::RefType: Referent, { type Output = Array; /// Perform an elementwise unary not of reference `self` and return the @@ -479,8 +459,6 @@ mod assign_ops S2: Data, D: Dimension, E: Dimension, - S::RefType: Referent, - S2::RefType: Referent, { #[track_caller] fn $method(&mut self, rhs: &ArrayBase) { @@ -496,7 +474,6 @@ mod assign_ops A: ScalarOperand + $trt
, S: DataMut, D: Dimension, - S::RefType: Referent, { fn $method(&mut self, rhs: A) { self.map_inplace(move |elt| { diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs index bef6d0498..7a6d34fbe 100644 --- a/src/impl_owned_array.rs +++ b/src/impl_owned_array.rs @@ -743,11 +743,11 @@ where D: Dimension let tail_ptr = self.data.as_end_nonnull(); let mut tail_view = RawArrayViewMut::new(tail_ptr, array_dim, tail_strides); - if tail_view.ndim() > 1 { + if tail_view.as_ref().ndim() > 1 { sort_axes_in_default_order_tandem(&mut tail_view, &mut array); debug_assert!(tail_view.is_standard_layout(), "not std layout dim: {:?}, strides: {:?}", - tail_view.shape(), LayoutRef::strides(&tail_view)); + tail_view.as_ref().shape(), LayoutRef::strides(&tail_view.as_ref())); } // Keep track of currently filled length of `self.data` and update it @@ -872,16 +872,16 @@ pub(crate) unsafe fn drop_unreachable_raw( mut self_: RawArrayViewMut, data_ptr: NonNull, data_len: usize, ) where D: Dimension { - let self_len = self_.len(); + let self_len = self_.as_ref().len(); - for i in 0..self_.ndim() { - if self_.stride_of(Axis(i)) < 0 { + for i in 0..self_.as_ref().ndim() { + if self_.as_ref().stride_of(Axis(i)) < 0 { self_.invert_axis(Axis(i)); } } sort_axes_in_default_order(&mut self_); // with uninverted axes this is now the element with lowest address - let array_memory_head_ptr = self_.ptr; + let array_memory_head_ptr = self_.layout.ptr; let data_end_ptr = data_ptr.add(data_len); debug_assert!(data_ptr <= array_memory_head_ptr); debug_assert!(array_memory_head_ptr <= data_end_ptr); @@ -898,12 +898,12 @@ pub(crate) unsafe fn drop_unreachable_raw( // As an optimization, the innermost axis is removed if it has stride 1, because // we then have a long stretch of contiguous elements we can skip as one. let inner_lane_len; - if self_.ndim() > 1 && self_.strides.last_elem() == 1 { - self_.dim.slice_mut().rotate_right(1); - self_.strides.slice_mut().rotate_right(1); - inner_lane_len = self_.dim[0]; - self_.dim[0] = 1; - self_.strides[0] = 1; + if self_.as_ref().ndim() > 1 && self_.layout.strides.last_elem() == 1 { + self_.layout.dim.slice_mut().rotate_right(1); + self_.layout.strides.slice_mut().rotate_right(1); + inner_lane_len = self_.layout.dim[0]; + self_.layout.dim[0] = 1; + self_.layout.strides[0] = 1; } else { inner_lane_len = 1; } @@ -946,7 +946,7 @@ where S: RawData, D: Dimension, { - if a.ndim() <= 1 { + if a.as_ref().ndim() <= 1 { return; } sort_axes1_impl(&mut a.layout.dim, &mut a.layout.strides); @@ -986,7 +986,7 @@ where S2: RawData, D: Dimension, { - if a.ndim() <= 1 { + if a.as_ref().ndim() <= 1 { return; } sort_axes2_impl(&mut a.layout.dim, &mut a.layout.strides, &mut b.layout.dim, &mut b.layout.strides); diff --git a/src/impl_raw_views.rs b/src/impl_raw_views.rs index 9ea69e2d2..049bdc536 100644 --- a/src/impl_raw_views.rs +++ b/src/impl_raw_views.rs @@ -98,7 +98,7 @@ where D: Dimension pub unsafe fn deref_into_view<'a>(self) -> ArrayView<'a, A, D> { debug_assert!( - is_aligned(self.ptr.as_ptr()), + is_aligned(self.layout.ptr.as_ptr()), "The pointer must be aligned." ); ArrayView::new(self.layout.ptr, self.layout.dim, self.layout.strides) @@ -112,19 +112,19 @@ where D: Dimension #[inline] pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self) { - assert!(index <= self.len_of(axis)); - let left_ptr = self.ptr.as_ptr(); - let right_ptr = if index == self.len_of(axis) { - self.ptr.as_ptr() + assert!(index <= self.as_ref().len_of(axis)); + let left_ptr = self.layout.ptr.as_ptr(); + let right_ptr = if index == self.as_ref().len_of(axis) { + self.layout.ptr.as_ptr() } else { - let offset = stride_offset(index, self.strides.axis(axis)); + let offset = stride_offset(index, self.layout.strides.axis(axis)); // The `.offset()` is safe due to the guarantees of `RawData`. - unsafe { self.ptr.as_ptr().offset(offset) } + unsafe { self.layout.ptr.as_ptr().offset(offset) } }; - let mut dim_left = self.dim.clone(); + let mut dim_left = self.layout.dim.clone(); dim_left.set_axis(axis, index); - let left = unsafe { Self::new_(left_ptr, dim_left, self.strides.clone()) }; + let left = unsafe { Self::new_(left_ptr, dim_left, self.layout.strides.clone()) }; let mut dim_right = self.layout.dim; let right_len = dim_right.axis(axis) - index; @@ -152,7 +152,7 @@ where D: Dimension mem::size_of::(), "size mismatch in raw view cast" ); - let ptr = self.ptr.cast::(); + let ptr = self.layout.ptr.cast::(); unsafe { RawArrayView::new(ptr, self.layout.dim, self.layout.strides) } } } @@ -172,11 +172,11 @@ where D: Dimension ); assert_eq!(mem::align_of::>(), mem::align_of::()); - let dim = self.dim.clone(); + let dim = self.layout.dim.clone(); // Double the strides. In the zero-sized element case and for axes of // length <= 1, we leave the strides as-is to avoid possible overflow. - let mut strides = self.strides.clone(); + let mut strides = self.layout.strides.clone(); if mem::size_of::() != 0 { for ax in 0..strides.ndim() { if dim[ax] > 1 { @@ -185,8 +185,8 @@ where D: Dimension } } - let ptr_re: *mut T = self.ptr.as_ptr().cast(); - let ptr_im: *mut T = if self.is_empty() { + let ptr_re: *mut T = self.layout.ptr.as_ptr().cast(); + let ptr_im: *mut T = if self.as_ref().is_empty() { // In the empty case, we can just reuse the existing pointer since // it won't be dereferenced anyway. It is not safe to offset by // one, since the allocation may be empty. @@ -308,7 +308,7 @@ where D: Dimension #[inline] pub(crate) fn into_raw_view(self) -> RawArrayView { - unsafe { RawArrayView::new(self.ptr, self.layout.dim, self.layout.strides) } + unsafe { RawArrayView::new(self.layout.ptr, self.layout.dim, self.layout.strides) } } /// Converts to a read-only view of the array. @@ -323,10 +323,10 @@ where D: Dimension pub unsafe fn deref_into_view<'a>(self) -> ArrayView<'a, A, D> { debug_assert!( - is_aligned(self.ptr.as_ptr()), + is_aligned(self.layout.ptr.as_ptr()), "The pointer must be aligned." ); - ArrayView::new(self.ptr, self.layout.dim, self.layout.strides) + ArrayView::new(self.layout.ptr, self.layout.dim, self.layout.strides) } /// Converts to a mutable view of the array. @@ -341,7 +341,7 @@ where D: Dimension pub unsafe fn deref_into_view_mut<'a>(self) -> ArrayViewMut<'a, A, D> { debug_assert!( - is_aligned(self.ptr.as_ptr()), + is_aligned(self.layout.ptr.as_ptr()), "The pointer must be aligned." ); ArrayViewMut::new(self.layout.ptr, self.layout.dim, self.layout.strides) @@ -382,7 +382,7 @@ where D: Dimension mem::size_of::(), "size mismatch in raw view cast" ); - let ptr = self.ptr.cast::(); + let ptr = self.layout.ptr.cast::(); unsafe { RawArrayViewMut::new(ptr, self.layout.dim, self.layout.strides) } } } @@ -397,8 +397,8 @@ where D: Dimension let Complex { re, im } = self.into_raw_view().split_complex(); unsafe { Complex { - re: RawArrayViewMut::new(re.ptr, re.layout.dim, re.layout.strides), - im: RawArrayViewMut::new(im.ptr, im.layout.dim, im.layout.strides), + re: RawArrayViewMut::new(re.layout.ptr, re.layout.dim, re.layout.strides), + im: RawArrayViewMut::new(im.layout.ptr, im.layout.dim, im.layout.strides), } } } diff --git a/src/layoutref.rs b/src/impl_ref_types.rs similarity index 51% rename from src/layoutref.rs rename to src/impl_ref_types.rs index 749c5bb8a..48cb027fc 100644 --- a/src/layoutref.rs +++ b/src/impl_ref_types.rs @@ -1,29 +1,15 @@ -//! Reference type for layouts +//! Code for the array reference type use core::ops::{Deref, DerefMut}; -use crate::{ArrayBase, LayoutRef, RawData, RefBase}; +use crate::{ArrayBase, ArrayRef, Data, DataMut, Dimension, LayoutRef, RawData, RawRef}; -impl AsRef> for LayoutRef +impl Deref for ArrayBase +where S: Data { - fn as_ref(&self) -> &LayoutRef - { - self - } -} + type Target = ArrayRef; -impl AsMut> for LayoutRef -{ - fn as_mut(&mut self) -> &mut LayoutRef - { - self - } -} - -impl AsRef> for ArrayBase -where S: RawData -{ - fn as_ref(&self) -> &LayoutRef + fn deref(&self) -> &Self::Target { // SAFETY: The pointer will hold all the guarantees of `as_ref`: // - The pointer is aligned because neither type use repr(align) @@ -31,82 +17,137 @@ where S: RawData // - For the same reason, it is initialized unsafe { (&self.layout as *const LayoutRef) - .cast::>() + .cast::>() .as_ref() } - .expect("Pointer to self will always be non-null") + .expect("References are always non-null") } } -impl AsMut> for ArrayBase -where S: RawData +impl DerefMut for ArrayBase +where + S: DataMut, + D: Dimension, { - fn as_mut(&mut self) -> &mut LayoutRef + fn deref_mut(&mut self) -> &mut Self::Target { + self.ensure_unique(); // SAFETY: The pointer will hold all the guarantees of `as_ref`: // - The pointer is aligned because neither type use repr(align) // - It is "dereferencable" because it just points to self // - For the same reason, it is initialized unsafe { (&mut self.layout as *mut LayoutRef) - .cast::>() + .cast::>() .as_mut() } - .expect("Pointer to self will always be non-null") + .expect("References are always non-null") } } -impl Deref for RefBase +impl AsRef> for ArrayBase +where S: RawData { - type Target = LayoutRef; + fn as_ref(&self) -> &RawRef + { + unsafe { + (&self.layout as *const LayoutRef) + .cast::>() + .as_ref() + } + .expect("References are always non-null") + } +} + +impl AsMut> for ArrayBase +where S: RawData +{ + fn as_mut(&mut self) -> &mut RawRef + { + unsafe { + (&mut self.layout as *mut LayoutRef) + .cast::>() + .as_mut() + } + .expect("References are always non-null") + } +} + +impl AsRef> for RawRef +{ + fn as_ref(&self) -> &RawRef + { + self + } +} + +impl AsMut> for RawRef +{ + fn as_mut(&mut self) -> &mut RawRef + { + self + } +} + +impl Deref for ArrayRef +{ + type Target = RawRef; fn deref(&self) -> &Self::Target { unsafe { - (&self.layout as *const LayoutRef) - .cast::>() + (self as *const ArrayRef) + .cast::>() .as_ref() } - .expect("Pointers to parts will never be null") + .expect("References are always non-null") } } -impl DerefMut for RefBase +impl DerefMut for ArrayRef { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { - (&mut self.layout as *mut LayoutRef) - .cast::>() + (self as *mut ArrayRef) + .cast::>() .as_mut() } - .expect("Pointers to parts will never be null") + .expect("References are always non-null") } } -// Blanket impl for AsRef, so that functions that take -// AsRef can take RefBase -impl AsRef for RefBase -where - T: ?Sized, - as Deref>::Target: AsRef, +impl AsRef> for LayoutRef +{ + fn as_ref(&self) -> &LayoutRef + { + self + } +} + +impl AsMut> for LayoutRef { - fn as_ref(&self) -> &T + fn as_mut(&mut self) -> &mut LayoutRef { - self.deref().as_ref() + self } } -// Blanket impl for AsMut, so that functions that take -// AsMut can take RefBase -impl AsMut for RefBase -where - T: ?Sized, - as Deref>::Target: AsMut, +impl Deref for RawRef { - fn as_mut(&mut self) -> &mut T + type Target = LayoutRef; + + fn deref(&self) -> &Self::Target + { + &self.0 + } +} + +impl DerefMut for RawRef +{ + fn deref_mut(&mut self) -> &mut Self::Target { - self.deref_mut().as_mut() + &mut self.0 } } diff --git a/src/iterators/chunks.rs b/src/iterators/chunks.rs index 9da13e024..909377d5e 100644 --- a/src/iterators/chunks.rs +++ b/src/iterators/chunks.rs @@ -49,19 +49,19 @@ impl<'a, A, D: Dimension> ExactChunks<'a, A, D> let mut a = a.into_raw_view(); let chunk = chunk.into_dimension(); ndassert!( - a.ndim() == chunk.ndim(), + AsRef::as_ref(&a).ndim() == chunk.ndim(), concat!( "Chunk dimension {} does not match array dimension {} ", "(with array of shape {:?})" ), chunk.ndim(), - a.ndim(), - a.shape() + AsRef::as_ref(&a).ndim(), + AsRef::as_ref(&a).shape() ); - for i in 0..a.ndim() { + for i in 0..AsRef::as_ref(&a).ndim() { a.layout.dim[i] /= chunk[i]; } - let inner_strides = a.strides.clone(); + let inner_strides = a.layout.strides.clone(); a.layout.strides *= &chunk; ExactChunks { @@ -148,20 +148,20 @@ impl<'a, A, D: Dimension> ExactChunksMut<'a, A, D> let mut a = a.into_raw_view_mut(); let chunk = chunk.into_dimension(); ndassert!( - a.ndim() == chunk.ndim(), + AsRef::as_ref(&a).ndim() == chunk.ndim(), concat!( "Chunk dimension {} does not match array dimension {} ", "(with array of shape {:?})" ), chunk.ndim(), - a.ndim(), - a.shape() + AsRef::as_ref(&a).ndim(), + AsRef::as_ref(&a).shape() ); - for i in 0..a.ndim() { - a.dim[i] /= chunk[i]; + for i in 0..AsRef::as_ref(&a).ndim() { + a.layout.dim[i] /= chunk[i]; } - let inner_strides = a.strides.clone(); - a.strides *= &chunk; + let inner_strides = a.layout.strides.clone(); + a.layout.strides *= &chunk; ExactChunksMut { base: a, diff --git a/src/lib.rs b/src/lib.rs index 2c5e4a352..7183c096f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -126,8 +126,6 @@ pub mod doc; #[cfg(target_has_atomic = "ptr")] use alloc::sync::Arc; -use arrayref::{Raw, Safe}; -pub use arrayref::{RawReferent, Referent}; #[cfg(not(target_has_atomic = "ptr"))] use portable_atomic_util::Arc; @@ -162,8 +160,7 @@ pub use crate::shape_builder::{Shape, ShapeArg, ShapeBuilder, StrideShape}; mod macro_utils; #[macro_use] mod private; -mod arrayref; -mod layoutref; +mod impl_ref_types; mod aliases; #[macro_use] mod itertools; @@ -536,7 +533,7 @@ pub type Ixs = isize; /// [`.multi_slice_move()`]: ArrayViewMut#method.multi_slice_move /// /// ``` -/// use ndarray::{arr2, arr3, s, ArrayBase, DataMut, Dimension, NewAxis, Slice, Referent}; +/// use ndarray::{arr2, arr3, s, ArrayBase, DataMut, Dimension, NewAxis, Slice}; /// /// // 2 submatrices of 2 rows with 3 elements per row, means a shape of `[2, 2, 3]`. /// @@ -604,7 +601,6 @@ pub type Ixs = isize; /// S: DataMut, /// S::Elem: Clone, /// D: Dimension, -/// S::RefType: Referent, /// { /// arr.slice_each_axis_mut(|ax| Slice::from(0..ax.len / 2)).fill(x); /// } @@ -1320,70 +1316,10 @@ pub struct LayoutRef strides: D, } -/// A reference to an *n*-dimensional array. -/// -/// `RefBase`'s relationship to [`ArrayBase`] is akin to the relationship -/// between `[T]` and `Vec`: it can only be obtained by reference, and -/// represents a subset of an existing array (possibly the entire array). -/// -/// There are two variants of this type, [`RawRef`] and [`ArrRef`]; raw -/// references are obtained from raw views, and `ArrRef`s are obtained -/// from all other array types. See those types for more information. -/// -/// ## Writing Functions -/// Generally speaking, functions that operate on arrays should accept -/// this type over an `ArrayBase`. The following conventions must be -/// followed: -/// - Functions that need to safely read an array's data should accept `&ArrRef` -/// ```rust -/// use ndarray::ArrRef; -/// -/// #[allow(dead_code)] -/// fn read(arr: &ArrRef) {} -/// ``` -/// - Functions that need to safely write to an array's data should accept `&mut ArrRef` -/// ```rust -/// use ndarray::ArrRef; -/// -/// #[allow(dead_code)] -/// fn write(arr: &mut ArrRef) {} -/// ``` -/// - Functions that only need to read an array's shape and strides -/// (or that want to unsafely read data) should accept `&RefBase` -/// with a bound of [`RawReferent`]: -/// ```rust -/// use ndarray::{RefBase, RawReferent}; -/// -/// #[allow(dead_code)] -/// fn read_layout(arr: &RefBase) {} -/// #[allow(dead_code)] -/// unsafe fn read_unchecked(arr: &RefBase) {} -/// ``` -/// - Functions that want to write to an array's shape and strides -/// (or that want to unsafely write to its data) should accept -/// `&mut RefBase` with the same bound: -/// ```rust -/// use ndarray::{RefBase, RawReferent}; -/// -/// #[allow(dead_code)] -/// fn write_layout(arr: &mut RefBase) {} -/// #[allow(dead_code)] -/// unsafe fn write_unchecked(arr: &mut RefBase) {} -/// ``` #[repr(transparent)] -pub struct RefBase -{ - /// The parts of the array - layout: LayoutRef, - /// The referent safety marker - phantom: PhantomData, -} - -/// An reference to an array whose data may be unaligned or unsafe to read. -pub type RawRef = RefBase; +pub struct ArrayRef(LayoutRef); -/// A reference to an array whose data can be read safely. -pub type ArrRef = RefBase; +pub struct RawRef(LayoutRef); /// An array where the data has shared ownership and is copy on write. /// @@ -1626,7 +1562,7 @@ mod impl_owned_array; mod impl_special_element_types; /// Private Methods -impl RefBase +impl ArrayRef { #[inline] fn broadcast_unwrap(&self, dim: E) -> ArrayView<'_, A, E> @@ -1644,7 +1580,7 @@ impl RefBase match self.broadcast(dim.clone()) { Some(it) => it, - None => broadcast_panic(&self.layout.dim, &dim), + None => broadcast_panic(&self.dim, &dim), } } @@ -1656,11 +1592,9 @@ impl RefBase { let dim = dim.into_dimension(); debug_assert_eq!(self.shape(), dim.slice()); - let ptr = self.layout.ptr; + let ptr = self.ptr; let mut strides = dim.clone(); - strides - .slice_mut() - .copy_from_slice(self.layout.strides.slice()); + strides.slice_mut().copy_from_slice(self.strides.slice()); unsafe { ArrayView::new(ptr, dim, strides) } } } @@ -1669,7 +1603,6 @@ impl ArrayBase where S: Data, D: Dimension, - ::RefType: Referent, { /// Remove array axis `axis` and return the result. fn try_remove_axis(self, axis: Axis) -> ArrayBase diff --git a/src/linalg/impl_linalg.rs b/src/linalg/impl_linalg.rs index 9cbc19224..b4967e20d 100644 --- a/src/linalg/impl_linalg.rs +++ b/src/linalg/impl_linalg.rs @@ -6,7 +6,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::arrayref::Referent; use crate::imp_prelude::*; #[cfg(feature = "blas")] @@ -42,9 +41,7 @@ const GEMM_BLAS_CUTOFF: usize = 7; type blas_index = c_int; // blas index type impl ArrayBase -where - S: Data, - S::RefType: Referent, +where S: Data { /// Perform dot product or matrix multiplication of arrays `self` and `rhs`. /// @@ -74,7 +71,6 @@ where where S2: Data, A: LinalgScalar, - S2::RefType: Referent, { debug_assert_eq!(self.len(), rhs.len()); assert!(self.len() == rhs.len()); @@ -97,7 +93,6 @@ where where S2: Data, A: LinalgScalar, - S2::RefType: Referent, { self.dot_generic(rhs) } @@ -107,7 +102,6 @@ where where S2: Data, A: LinalgScalar, - S2::RefType: Referent, { // Use only if the vector is large enough to be worth it if self.len() >= DOT_BLAS_CUTOFF { @@ -179,8 +173,6 @@ where S: Data, S2: Data, A: LinalgScalar, - S::RefType: Referent, - S2::RefType: Referent, { type Output = A; @@ -204,8 +196,6 @@ where S: Data, S2: Data, A: LinalgScalar, - S::RefType: Referent, - S2::RefType: Referent, { type Output = Array; @@ -226,9 +216,7 @@ where } impl ArrayBase -where - S: Data, - S::RefType: Referent, +where S: Data { /// Perform matrix multiplication of rectangular arrays `self` and `rhs`. /// @@ -272,8 +260,6 @@ where S: Data, S2: Data, A: LinalgScalar, - S::RefType: Referent, - S2::RefType: Referent, { type Output = Array2; fn dot(&self, b: &ArrayBase) -> Array2 @@ -337,8 +323,6 @@ where S: Data, S2: Data, A: LinalgScalar, - S::RefType: Referent, - S2::RefType: Referent, { type Output = Array; #[track_caller] @@ -362,7 +346,6 @@ impl ArrayBase where S: Data, D: Dimension, - S::RefType: Referent, { /// Perform the operation `self += alpha * rhs` efficiently, where /// `alpha` is a scalar and `rhs` is another array. This operation is @@ -378,8 +361,6 @@ where S2: Data, A: LinalgScalar, E: Dimension, - S::RefType: Referent, - S2::RefType: Referent, { self.zip_mut_with(rhs, move |y, &x| *y = *y + (alpha * x)); } @@ -618,9 +599,6 @@ pub fn general_mat_mul( S2: Data, S3: DataMut, A: LinalgScalar, - S1::RefType: Referent, - S2::RefType: Referent, - S3::RefType: Referent, { let ((m, k), (k2, n)) = (a.dim(), b.dim()); let (m2, n2) = c.dim(); @@ -650,9 +628,6 @@ pub fn general_mat_vec_mul( S2: Data, S3: DataMut, A: LinalgScalar, - S1::RefType: Referent, - S2::RefType: Referent, - S3::RefType: Referent, { unsafe { general_mat_vec_mul_impl(alpha, a, x, beta, y.raw_view_mut()) } } @@ -672,11 +647,9 @@ unsafe fn general_mat_vec_mul_impl( S1: Data, S2: Data, A: LinalgScalar, - S1::RefType: Referent, - S2::RefType: Referent, { let ((m, k), k2) = (a.dim(), x.dim()); - let m2 = y.dim(); + let m2 = y.as_ref().dim(); if k != k2 || m != m2 { general_dot_shape_error(m, k, k2, 1, m2, 1); } else { @@ -696,10 +669,10 @@ unsafe fn general_mat_vec_mul_impl( let cblas_layout = layout.to_cblas_layout(); // Low addr in memory pointers required for x, y - let x_offset = offset_from_low_addr_ptr_to_logical_ptr(&x.dim, &x.strides); + let x_offset = offset_from_low_addr_ptr_to_logical_ptr(&x.layout.dim, &x.layout.strides); let x_ptr = x.ptr.as_ptr().sub(x_offset); - let y_offset = offset_from_low_addr_ptr_to_logical_ptr(&y.dim, &y.strides); - let y_ptr = y.ptr.as_ptr().sub(y_offset); + let y_offset = offset_from_low_addr_ptr_to_logical_ptr(&y.layout.dim, &y.layout.strides); + let y_ptr = y.layout.ptr.as_ptr().sub(y_offset); let x_stride = x.strides()[0] as blas_index; let y_stride = y.strides()[0] as blas_index; @@ -753,8 +726,6 @@ where S1: Data, S2: Data, A: LinalgScalar, - S1::RefType: Referent, - S2::RefType: Referent, { let dimar = a.shape()[0]; let dimac = a.shape()[1]; @@ -812,7 +783,7 @@ where if !same_type::() { return false; } - if a.len() > blas_index::MAX as usize { + if a.as_ref().len() > blas_index::MAX as usize { return false; } let stride = a.strides()[0]; diff --git a/src/numeric/impl_float_maths.rs b/src/numeric/impl_float_maths.rs index 6a276dfab..54fed49c2 100644 --- a/src/numeric/impl_float_maths.rs +++ b/src/numeric/impl_float_maths.rs @@ -3,7 +3,7 @@ #[cfg(feature = "std")] use num_traits::Float; -use crate::{arrayref::Referent, imp_prelude::*}; +use crate::imp_prelude::*; #[cfg(feature = "std")] macro_rules! boolean_ops { @@ -59,7 +59,6 @@ where A: 'static + Float, S: Data, D: Dimension, - S::RefType: Referent, { boolean_ops! { /// If the number is `NaN` (not a number), then `true` is returned for each element. @@ -149,7 +148,6 @@ where A: 'static + PartialOrd + Clone, S: Data, D: Dimension, - S::RefType: Referent, { /// Limit the values for each element, similar to NumPy's `clip` function. /// diff --git a/src/numeric/impl_numeric.rs b/src/numeric/impl_numeric.rs index a8e45541d..6c67b9135 100644 --- a/src/numeric/impl_numeric.rs +++ b/src/numeric/impl_numeric.rs @@ -12,7 +12,6 @@ use num_traits::One; use num_traits::{FromPrimitive, Zero}; use std::ops::{Add, Div, Mul, Sub}; -use crate::arrayref::Referent; use crate::imp_prelude::*; use crate::numeric_util; use crate::Slice; @@ -22,7 +21,6 @@ impl ArrayBase where S: Data, D: Dimension, - S::RefType: Referent, { /// Return the sum of all elements in the array. /// diff --git a/src/tri.rs b/src/tri.rs index 87d4e4495..d756aac21 100644 --- a/src/tri.rs +++ b/src/tri.rs @@ -11,7 +11,6 @@ use core::cmp::min; use num_traits::Zero; use crate::{ - arrayref::Referent, dimension::{is_layout_c, is_layout_f}, Array, ArrayBase, @@ -26,7 +25,6 @@ where S: Data, D: Dimension, A: Clone + Zero, - S::RefType: Referent, { /// Upper triangular of an array. /// diff --git a/src/zip/mod.rs b/src/zip/mod.rs index a6b6ad45a..df043b3ec 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -19,7 +19,6 @@ use crate::AssignElem; use crate::IntoDimension; use crate::Layout; use crate::LayoutRef; -use crate::Referent; use crate::dimension; use crate::indexes::{indices, Indices}; @@ -764,7 +763,6 @@ macro_rules! map_impl { -> ArrayBase where S: DataOwned, - <::MaybeUninit as RawData>::RefType: Referent, { // safe because: all elements are written before the array is completed diff --git a/src/zip/ndproducer.rs b/src/zip/ndproducer.rs index 7adf5b18c..91fb8602a 100644 --- a/src/zip/ndproducer.rs +++ b/src/zip/ndproducer.rs @@ -1,8 +1,7 @@ -use crate::arrayref::Referent; use crate::imp_prelude::*; +use crate::ArrayRef; use crate::Layout; use crate::NdIndex; -use crate::RefBase; #[cfg(not(feature = "std"))] use alloc::vec::Vec; @@ -132,7 +131,6 @@ impl<'a, A: 'a, S, D> IntoNdProducer for &'a ArrayBase where D: Dimension, S: Data, - S::RefType: Referent, { type Item = &'a A; type Dim = D; @@ -149,7 +147,6 @@ impl<'a, A: 'a, S, D> IntoNdProducer for &'a mut ArrayBase where D: Dimension, S: DataMut, - S::RefType: Referent, { type Item = &'a mut A; type Dim = D; @@ -162,7 +159,7 @@ where /// An array reference is an n-dimensional producer of element references /// (like ArrayView). -impl<'a, A: 'a, D, R: Referent> IntoNdProducer for &'a RefBase +impl<'a, A: 'a, D> IntoNdProducer for &'a ArrayRef where D: Dimension { type Item = &'a A; @@ -176,7 +173,7 @@ where D: Dimension /// A mutable array reference is an n-dimensional producer of mutable element /// references (like ArrayViewMut). -impl<'a, A: 'a, D, R: Referent> IntoNdProducer for &'a mut RefBase +impl<'a, A: 'a, D> IntoNdProducer for &'a mut ArrayRef where D: Dimension { type Item = &'a mut A; @@ -383,22 +380,22 @@ impl NdProducer for RawArrayView fn raw_dim(&self) -> Self::Dim { - (***self).raw_dim() + AsRef::as_ref(self).raw_dim() } fn equal_dim(&self, dim: &Self::Dim) -> bool { - self.dim.equal(dim) + self.layout.dim.equal(dim) } fn as_ptr(&self) -> *const A { - (**self).as_ptr() as _ + AsRef::as_ref(self).as_ptr() as _ } fn layout(&self) -> Layout { - self.layout_impl() + AsRef::as_ref(self).layout_impl() } unsafe fn as_ref(&self, ptr: *const A) -> *const A @@ -408,12 +405,15 @@ impl NdProducer for RawArrayView unsafe fn uget_ptr(&self, i: &Self::Dim) -> *const A { - self.ptr.as_ptr().offset(i.index_unchecked(&self.strides)) + self.layout + .ptr + .as_ptr() + .offset(i.index_unchecked(&self.layout.strides)) } fn stride_of(&self, axis: Axis) -> isize { - (**self).stride_of(axis) + AsRef::as_ref(self).stride_of(axis) } #[inline(always)] @@ -439,22 +439,22 @@ impl NdProducer for RawArrayViewMut fn raw_dim(&self) -> Self::Dim { - (***self).raw_dim() + AsRef::as_ref(self).raw_dim() } fn equal_dim(&self, dim: &Self::Dim) -> bool { - self.dim.equal(dim) + self.layout.dim.equal(dim) } fn as_ptr(&self) -> *mut A { - (**self).as_ptr() as _ + AsRef::as_ref(self).as_ptr() as _ } fn layout(&self) -> Layout { - self.layout_impl() + AsRef::as_ref(self).layout_impl() } unsafe fn as_ref(&self, ptr: *mut A) -> *mut A @@ -464,12 +464,15 @@ impl NdProducer for RawArrayViewMut unsafe fn uget_ptr(&self, i: &Self::Dim) -> *mut A { - self.ptr.as_ptr().offset(i.index_unchecked(&self.strides)) + self.layout + .ptr + .as_ptr() + .offset(i.index_unchecked(&self.layout.strides)) } fn stride_of(&self, axis: Axis) -> isize { - (***self).stride_of(axis) + AsRef::as_ref(self).stride_of(axis) } #[inline(always)] diff --git a/tests/array.rs b/tests/array.rs index 13244483c..696904dab 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -2482,7 +2482,7 @@ fn array_macros() mod as_standard_layout_tests { use super::*; - use ndarray::{Data, Referent}; + use ndarray::Data; use std::fmt::Debug; fn test_as_standard_layout_for(orig: ArrayBase) @@ -2490,7 +2490,6 @@ mod as_standard_layout_tests S: Data, S::Elem: Clone + Debug + PartialEq, D: Dimension, - S::RefType: Referent, { let orig_is_standard = orig.is_standard_layout(); let out = orig.as_standard_layout(); diff --git a/tests/iterators.rs b/tests/iterators.rs index 3466dbb66..908b64d15 100644 --- a/tests/iterators.rs +++ b/tests/iterators.rs @@ -103,14 +103,13 @@ fn indexed() #[cfg(feature = "std")] fn as_slice() { - use ndarray::{Data, Referent}; + use ndarray::Data; fn assert_slice_correct(v: &ArrayBase) where S: Data, D: Dimension, A: PartialEq + std::fmt::Debug, - S::RefType: Referent, { let slc = v.as_slice(); assert!(slc.is_some()); diff --git a/tests/oper.rs b/tests/oper.rs index 3e5d9eef3..5e3e669d0 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -7,7 +7,6 @@ use ndarray::linalg::kron; use ndarray::prelude::*; #[cfg(feature = "approx")] use ndarray::Order; -use ndarray::Referent; use ndarray::{rcarr1, rcarr2}; use ndarray::{Data, LinalgScalar}; use ndarray::{Ix, Ixs}; @@ -298,8 +297,6 @@ where A: LinalgScalar, S: Data, S2: Data, - S::RefType: Referent, - S2::RefType: Referent, { let ((m, k), (k2, n)) = (lhs.dim(), rhs.dim()); assert!(m.checked_mul(n).is_some()); @@ -695,8 +692,6 @@ fn gen_mat_vec_mul() A: LinalgScalar, S: Data, S2: Data, - S::RefType: Referent, - S2::RefType: Referent, { let ((m, _), k) = (lhs.dim(), rhs.dim()); reference_mat_mul( @@ -762,8 +757,6 @@ fn vec_mat_mul() A: LinalgScalar, S: Data, S2: Data, - S::RefType: Referent, - S2::RefType: Referent, { let (m, (_, n)) = (lhs.dim(), rhs.dim()); reference_mat_mul( diff --git a/tests/raw_views.rs b/tests/raw_views.rs index 929e969d7..be20aff52 100644 --- a/tests/raw_views.rs +++ b/tests/raw_views.rs @@ -39,8 +39,8 @@ fn raw_view_cast_zst() let a = Array::<(), _>::default((250, 250)); let b: RawArrayView = a.raw_view().cast::(); - assert_eq!(a.shape(), b.shape()); - assert_eq!(a.as_ptr() as *const u8, b.as_ptr() as *const u8); + assert_eq!(a.shape(), b.as_ref().shape()); + assert_eq!(a.as_ptr() as *const u8, b.as_ref().as_ptr() as *const u8); } #[test] diff --git a/tests/test_ref_structure.rs b/tests/test_ref_structure.rs new file mode 100644 index 000000000..a2f2be440 --- /dev/null +++ b/tests/test_ref_structure.rs @@ -0,0 +1,31 @@ +use ndarray::{array, ArrayBase, ArrayRef, Data, LayoutRef, RawData, RawRef}; + +fn takes_base_raw(arr: &ArrayBase) +{ + takes_rawref(arr.as_ref()); // Doesn't work + takes_layout(arr.as_ref()); +} + +fn takes_base(arr: &ArrayBase) +{ + takes_base_raw(arr); + takes_arrref(arr); // Doesn't work + takes_rawref(arr); // Doesn't work + takes_layout(arr); +} + +fn takes_arrref(arr: &ArrayRef) {} + +fn takes_rawref(arr: &RawRef) {} + +fn takes_layout(arr: &LayoutRef) {} + +#[test] +fn tester() +{ + let arr = array![1, 2, 3]; + takes_base_raw(&arr); + takes_arrref(&arr); + takes_rawref(&arr); // Doesn't work + takes_layout(&arr); +} From 476dac5e6b1a2a09e9fd97e2c5afe79cbfe51584 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 13 Oct 2024 19:23:32 -0400 Subject: [PATCH 12/33] Satisfying CI/CD --- src/alias_slicing.rs | 2 +- src/impl_owned_array.rs | 2 +- tests/test_ref_structure.rs | 14 +++++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/alias_slicing.rs b/src/alias_slicing.rs index 4d685601d..7c9b3d26b 100644 --- a/src/alias_slicing.rs +++ b/src/alias_slicing.rs @@ -95,7 +95,7 @@ impl ArrayBase /// preferring axes with len > 1. pub fn max_stride_axis(&self) -> Axis { - LayoutRef::max_stride_axis(&self.as_ref()) + LayoutRef::max_stride_axis(self.as_ref()) } /// Reverse the stride of `axis`. diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs index 7a6d34fbe..3b0ef02be 100644 --- a/src/impl_owned_array.rs +++ b/src/impl_owned_array.rs @@ -747,7 +747,7 @@ where D: Dimension sort_axes_in_default_order_tandem(&mut tail_view, &mut array); debug_assert!(tail_view.is_standard_layout(), "not std layout dim: {:?}, strides: {:?}", - tail_view.as_ref().shape(), LayoutRef::strides(&tail_view.as_ref())); + tail_view.as_ref().shape(), LayoutRef::strides(tail_view.as_ref())); } // Keep track of currently filled length of `self.data` and update it diff --git a/tests/test_ref_structure.rs b/tests/test_ref_structure.rs index a2f2be440..6778097a9 100644 --- a/tests/test_ref_structure.rs +++ b/tests/test_ref_structure.rs @@ -6,6 +6,7 @@ fn takes_base_raw(arr: &ArrayBase) takes_layout(arr.as_ref()); } +#[allow(dead_code)] fn takes_base(arr: &ArrayBase) { takes_base_raw(arr); @@ -14,11 +15,18 @@ fn takes_base(arr: &ArrayBase) takes_layout(arr); } -fn takes_arrref(arr: &ArrayRef) {} +fn takes_arrref(_arr: &ArrayRef) +{ + takes_rawref(_arr); + takes_layout(_arr); +} -fn takes_rawref(arr: &RawRef) {} +fn takes_rawref(_arr: &RawRef) +{ + takes_layout(_arr); +} -fn takes_layout(arr: &LayoutRef) {} +fn takes_layout(_arr: &LayoutRef) {} #[test] fn tester() From 68d6f5322448c208783b57fc911b7a126dc91334 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 13 Oct 2024 19:53:41 -0400 Subject: [PATCH 13/33] Adds Index, equality, IntoIterator, and Hash traits, plus approximates --- src/array_approx.rs | 95 ++++++++++++++++++++++------ src/arraytraits.rs | 147 +++++++++++++++++++++++++++++++++++++++----- src/prelude.rs | 13 +++- 3 files changed, 220 insertions(+), 35 deletions(-) diff --git a/src/array_approx.rs b/src/array_approx.rs index 493864c7e..0081323cb 100644 --- a/src/array_approx.rs +++ b/src/array_approx.rs @@ -3,20 +3,16 @@ mod approx_methods { use crate::imp_prelude::*; - impl ArrayBase - where - S: Data, - D: Dimension, + impl ArrayRef { /// A test for equality that uses the elementwise absolute difference to compute the /// approximate equality of two arrays. /// /// **Requires crate feature `"approx"`** - pub fn abs_diff_eq(&self, other: &ArrayBase, epsilon: A::Epsilon) -> bool + pub fn abs_diff_eq(&self, other: &ArrayRef, epsilon: A::Epsilon) -> bool where - A: ::approx::AbsDiffEq, + A: ::approx::AbsDiffEq, A::Epsilon: Clone, - S2: Data, { >::abs_diff_eq(self, other, epsilon) } @@ -25,11 +21,10 @@ mod approx_methods /// apart; and the absolute difference otherwise. /// /// **Requires crate feature `"approx"`** - pub fn relative_eq(&self, other: &ArrayBase, epsilon: A::Epsilon, max_relative: A::Epsilon) -> bool + pub fn relative_eq(&self, other: &ArrayRef, epsilon: A::Epsilon, max_relative: A::Epsilon) -> bool where - A: ::approx::RelativeEq, + A: ::approx::RelativeEq, A::Epsilon: Clone, - S2: Data, { >::relative_eq(self, other, epsilon, max_relative) } @@ -44,12 +39,10 @@ macro_rules! impl_approx_traits { use $approx::{AbsDiffEq, RelativeEq, UlpsEq}; #[doc = $doc] - impl AbsDiffEq> for ArrayBase + impl AbsDiffEq> for ArrayRef where A: AbsDiffEq, A::Epsilon: Clone, - S: Data, - S2: Data, D: Dimension, { type Epsilon = A::Epsilon; @@ -58,7 +51,7 @@ macro_rules! impl_approx_traits { A::default_epsilon() } - fn abs_diff_eq(&self, other: &ArrayBase, epsilon: A::Epsilon) -> bool { + fn abs_diff_eq(&self, other: &ArrayRef, epsilon: A::Epsilon) -> bool { if self.shape() != other.shape() { return false; } @@ -70,13 +63,31 @@ macro_rules! impl_approx_traits { } #[doc = $doc] - impl RelativeEq> for ArrayBase + impl AbsDiffEq> for ArrayBase where - A: RelativeEq, + A: AbsDiffEq, A::Epsilon: Clone, S: Data, S2: Data, D: Dimension, + { + type Epsilon = A::Epsilon; + + fn default_epsilon() -> A::Epsilon { + A::default_epsilon() + } + + fn abs_diff_eq(&self, other: &ArrayBase, epsilon: A::Epsilon) -> bool { + (&**self).abs_diff_eq(other, epsilon) + } + } + + #[doc = $doc] + impl RelativeEq> for ArrayRef + where + A: RelativeEq, + A::Epsilon: Clone, + D: Dimension, { fn default_max_relative() -> A::Epsilon { A::default_max_relative() @@ -84,7 +95,7 @@ macro_rules! impl_approx_traits { fn relative_eq( &self, - other: &ArrayBase, + other: &ArrayRef, epsilon: A::Epsilon, max_relative: A::Epsilon, ) -> bool { @@ -99,13 +110,34 @@ macro_rules! impl_approx_traits { } #[doc = $doc] - impl UlpsEq> for ArrayBase + impl RelativeEq> for ArrayBase where - A: UlpsEq, + A: RelativeEq, A::Epsilon: Clone, S: Data, S2: Data, D: Dimension, + { + fn default_max_relative() -> A::Epsilon { + A::default_max_relative() + } + + fn relative_eq( + &self, + other: &ArrayBase, + epsilon: A::Epsilon, + max_relative: A::Epsilon, + ) -> bool { + (&**self).relative_eq(other, epsilon, max_relative) + } + } + + #[doc = $doc] + impl UlpsEq> for ArrayRef + where + A: UlpsEq, + A::Epsilon: Clone, + D: Dimension, { fn default_max_ulps() -> u32 { A::default_max_ulps() @@ -113,7 +145,7 @@ macro_rules! impl_approx_traits { fn ulps_eq( &self, - other: &ArrayBase, + other: &ArrayRef, epsilon: A::Epsilon, max_ulps: u32, ) -> bool { @@ -127,6 +159,29 @@ macro_rules! impl_approx_traits { } } + #[doc = $doc] + impl UlpsEq> for ArrayBase + where + A: UlpsEq, + A::Epsilon: Clone, + S: Data, + S2: Data, + D: Dimension, + { + fn default_max_ulps() -> u32 { + A::default_max_ulps() + } + + fn ulps_eq( + &self, + other: &ArrayBase, + epsilon: A::Epsilon, + max_ulps: u32, + ) -> bool { + (&**self).ulps_eq(other, epsilon, max_ulps) + } + } + #[cfg(test)] mod tests { use crate::prelude::*; diff --git a/src/arraytraits.rs b/src/arraytraits.rs index 67ab05700..9d06ea8ce 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -49,15 +49,15 @@ where /// Access the element at **index**. /// /// **Panics** if index is out of bounds. -impl Index for ArrayBase +impl Index for ArrayRef where D: Dimension, I: NdIndex, - S: Data, { - type Output = S::Elem; + type Output = A; + #[inline] - fn index(&self, index: I) -> &S::Elem + fn index(&self, index: I) -> &Self::Output { debug_bounds_check!(self, index); unsafe { @@ -73,14 +73,13 @@ where /// Access the element at **index** mutably. /// /// **Panics** if index is out of bounds. -impl IndexMut for ArrayBase +impl IndexMut for ArrayRef where D: Dimension, I: NdIndex, - S: DataMut, { #[inline] - fn index_mut(&mut self, index: I) -> &mut S::Elem + fn index_mut(&mut self, index: I) -> &mut A { debug_bounds_check!(self, index); unsafe { @@ -93,16 +92,48 @@ where } } +/// Access the element at **index**. +/// +/// **Panics** if index is out of bounds. +impl Index for ArrayBase +where + D: Dimension, + I: NdIndex, + S: Data, +{ + type Output = S::Elem; + + #[inline] + fn index(&self, index: I) -> &S::Elem + { + Index::index(&**self, index) + } +} + +/// Access the element at **index** mutably. +/// +/// **Panics** if index is out of bounds. +impl IndexMut for ArrayBase +where + D: Dimension, + I: NdIndex, + S: DataMut, +{ + #[inline] + fn index_mut(&mut self, index: I) -> &mut S::Elem + { + IndexMut::index_mut(&mut (**self), index) + } +} + /// Return `true` if the array shapes and all elements of `self` and /// `rhs` are equal. Return `false` otherwise. -impl PartialEq> for ArrayBase +impl PartialEq> for ArrayRef where A: PartialEq, - S: Data, - S2: Data, D: Dimension, { - fn eq(&self, rhs: &ArrayBase) -> bool + fn eq(&self, rhs: &ArrayRef) -> bool { if self.shape() != rhs.shape() { return false; @@ -125,6 +156,56 @@ where } } +/// Return `true` if the array shapes and all elements of `self` and +/// `rhs` are equal. Return `false` otherwise. +#[allow(clippy::unconditional_recursion)] // false positive +impl<'a, A, B, D> PartialEq<&'a ArrayRef> for ArrayRef +where + A: PartialEq, + D: Dimension, +{ + fn eq(&self, rhs: &&ArrayRef) -> bool + { + *self == **rhs + } +} + +/// Return `true` if the array shapes and all elements of `self` and +/// `rhs` are equal. Return `false` otherwise. +#[allow(clippy::unconditional_recursion)] // false positive +impl<'a, A, B, D> PartialEq> for &'a ArrayRef +where + A: PartialEq, + D: Dimension, +{ + fn eq(&self, rhs: &ArrayRef) -> bool + { + **self == *rhs + } +} + +impl Eq for ArrayRef +where + D: Dimension, + A: Eq, +{ +} + +/// Return `true` if the array shapes and all elements of `self` and +/// `rhs` are equal. Return `false` otherwise. +impl PartialEq> for ArrayBase +where + A: PartialEq, + S: Data, + S2: Data, + D: Dimension, +{ + fn eq(&self, rhs: &ArrayBase) -> bool + { + PartialEq::eq(&**self, &**rhs) + } +} + /// Return `true` if the array shapes and all elements of `self` and /// `rhs` are equal. Return `false` otherwise. #[allow(clippy::unconditional_recursion)] // false positive @@ -216,6 +297,32 @@ where S: DataOwned } } +impl<'a, A, D> IntoIterator for &'a ArrayRef +where D: Dimension +{ + type Item = &'a A; + + type IntoIter = Iter<'a, A, D>; + + fn into_iter(self) -> Self::IntoIter + { + self.iter() + } +} + +impl<'a, A, D> IntoIterator for &'a mut ArrayRef +where D: Dimension +{ + type Item = &'a mut A; + + type IntoIter = IterMut<'a, A, D>; + + fn into_iter(self) -> Self::IntoIter + { + self.iter_mut() + } +} + impl<'a, S, D> IntoIterator for &'a ArrayBase where D: Dimension, @@ -268,11 +375,10 @@ where D: Dimension } } -impl hash::Hash for ArrayBase +impl hash::Hash for ArrayRef where D: Dimension, - S: Data, - S::Elem: hash::Hash, + A: hash::Hash, { // Note: elements are hashed in the logical order fn hash(&self, state: &mut H) @@ -294,6 +400,19 @@ where } } +impl hash::Hash for ArrayBase +where + D: Dimension, + S: Data, + S::Elem: hash::Hash, +{ + // Note: elements are hashed in the logical order + fn hash(&self, state: &mut H) + { + (&**self).hash(state) + } +} + // NOTE: ArrayBase keeps an internal raw pointer that always // points into the storage. This is Sync & Send as long as we // follow the usual inherited mutability rules, as we do with diff --git a/src/prelude.rs b/src/prelude.rs index acf39da1a..998640988 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -18,7 +18,18 @@ //! ``` #[doc(no_inline)] -pub use crate::{ArcArray, Array, ArrayBase, ArrayView, ArrayViewMut, CowArray, RawArrayView, RawArrayViewMut}; +pub use crate::{ + ArcArray, + Array, + ArrayBase, + ArrayRef, + ArrayView, + ArrayViewMut, + CowArray, + RawArrayView, + RawArrayViewMut, + RawRef, +}; #[doc(no_inline)] pub use crate::{Axis, Dim, Dimension}; From 2fde9980a2ab2550012c8a276b4095182e9ca59f Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Mon, 14 Oct 2024 00:20:50 -0400 Subject: [PATCH 14/33] Finishes conversions of all possible ArrayBase impls to ArrayRef --- src/aliases.rs | 19 ++- src/array_approx.rs | 6 +- src/arraytraits.rs | 2 +- src/impl_1d.rs | 8 +- src/impl_2d.rs | 16 ++- src/impl_dyn.rs | 15 ++- src/impl_ops.rs | 177 +++++++++++++++++++++++++++ src/linalg/impl_linalg.rs | 203 ++++++++++++++++--------------- src/numeric/impl_float_maths.rs | 6 +- src/numeric/impl_numeric.rs | 6 +- src/parallel/impl_par_methods.rs | 3 +- src/prelude.rs | 1 + src/tri.rs | 6 +- 13 files changed, 335 insertions(+), 133 deletions(-) diff --git a/src/aliases.rs b/src/aliases.rs index 5df0c95ec..aef0452f3 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -2,7 +2,7 @@ //! use crate::dimension::Dim; -use crate::{ArcArray, Array, ArrayView, ArrayViewMut, Ix, IxDynImpl}; +use crate::{ArcArray, Array, ArrayRef, ArrayView, ArrayViewMut, Ix, IxDynImpl}; /// Create a zero-dimensional index #[allow(non_snake_case)] @@ -123,6 +123,23 @@ pub type Array6 = Array; /// dynamic-dimensional array pub type ArrayD = Array; +/// zero-dimensional array reference +pub type ArrayRef0 = ArrayRef; +/// one-dimensional array reference +pub type ArrayRef1 = ArrayRef; +/// two-dimensional array reference +pub type ArrayRef2 = ArrayRef; +/// three-dimensional array reference +pub type ArrayRef3 = ArrayRef; +/// four-dimensional array reference +pub type ArrayRef4 = ArrayRef; +/// five-dimensional array reference +pub type ArrayRef5 = ArrayRef; +/// six-dimensional array reference +pub type ArrayRef6 = ArrayRef; +/// dynamic-dimensional array reference +pub type ArrayRefD = ArrayRef; + /// zero-dimensional array view pub type ArrayView0<'a, A> = ArrayView<'a, A, Ix0>; /// one-dimensional array view diff --git a/src/array_approx.rs b/src/array_approx.rs index 0081323cb..e350c3883 100644 --- a/src/array_approx.rs +++ b/src/array_approx.rs @@ -78,7 +78,7 @@ macro_rules! impl_approx_traits { } fn abs_diff_eq(&self, other: &ArrayBase, epsilon: A::Epsilon) -> bool { - (&**self).abs_diff_eq(other, epsilon) + (**self).abs_diff_eq(other, epsilon) } } @@ -128,7 +128,7 @@ macro_rules! impl_approx_traits { epsilon: A::Epsilon, max_relative: A::Epsilon, ) -> bool { - (&**self).relative_eq(other, epsilon, max_relative) + (**self).relative_eq(other, epsilon, max_relative) } } @@ -178,7 +178,7 @@ macro_rules! impl_approx_traits { epsilon: A::Epsilon, max_ulps: u32, ) -> bool { - (&**self).ulps_eq(other, epsilon, max_ulps) + (**self).ulps_eq(other, epsilon, max_ulps) } } diff --git a/src/arraytraits.rs b/src/arraytraits.rs index 9d06ea8ce..1a843af56 100644 --- a/src/arraytraits.rs +++ b/src/arraytraits.rs @@ -409,7 +409,7 @@ where // Note: elements are hashed in the logical order fn hash(&self, state: &mut H) { - (&**self).hash(state) + (**self).hash(state) } } diff --git a/src/impl_1d.rs b/src/impl_1d.rs index e49fdd731..bd34ba2ca 100644 --- a/src/impl_1d.rs +++ b/src/impl_1d.rs @@ -15,14 +15,11 @@ use crate::imp_prelude::*; use crate::low_level_util::AbortIfPanic; /// # Methods For 1-D Arrays -impl ArrayBase -where S: RawData +impl ArrayRef { /// Return an vector with the elements of the one-dimensional array. pub fn to_vec(&self) -> Vec - where - A: Clone, - S: Data, + where A: Clone { if let Some(slc) = self.as_slice() { slc.to_vec() @@ -34,7 +31,6 @@ where S: RawData /// Rotate the elements of the array by 1 element towards the front; /// the former first element becomes the last. pub(crate) fn rotate1_front(&mut self) - where S: DataMut { // use swapping to keep all elements initialized (as required by owned storage) let mut lane_iter = self.iter_mut(); diff --git a/src/impl_2d.rs b/src/impl_2d.rs index 2e5f9c31e..061bf45fd 100644 --- a/src/impl_2d.rs +++ b/src/impl_2d.rs @@ -10,8 +10,7 @@ use crate::imp_prelude::*; /// # Methods For 2-D Arrays -impl ArrayBase -where S: RawData +impl ArrayRef { /// Return an array view of row `index`. /// @@ -24,7 +23,6 @@ where S: RawData /// ``` #[track_caller] pub fn row(&self, index: Ix) -> ArrayView1<'_, A> - where S: Data { self.index_axis(Axis(0), index) } @@ -41,11 +39,13 @@ where S: RawData /// ``` #[track_caller] pub fn row_mut(&mut self, index: Ix) -> ArrayViewMut1<'_, A> - where S: DataMut { self.index_axis_mut(Axis(0), index) } +} +impl LayoutRef +{ /// Return the number of rows (length of `Axis(0)`) in the two-dimensional array. /// /// ``` @@ -67,7 +67,10 @@ where S: RawData { self.as_ref().len_of(Axis(0)) } +} +impl ArrayRef +{ /// Return an array view of column `index`. /// /// **Panics** if `index` is out of bounds. @@ -79,7 +82,6 @@ where S: RawData /// ``` #[track_caller] pub fn column(&self, index: Ix) -> ArrayView1<'_, A> - where S: Data { self.index_axis(Axis(1), index) } @@ -96,11 +98,13 @@ where S: RawData /// ``` #[track_caller] pub fn column_mut(&mut self, index: Ix) -> ArrayViewMut1<'_, A> - where S: DataMut { self.index_axis_mut(Axis(1), index) } +} +impl LayoutRef +{ /// Return the number of columns (length of `Axis(1)`) in the two-dimensional array. /// /// ``` diff --git a/src/impl_dyn.rs b/src/impl_dyn.rs index 840d31c69..2470967d2 100644 --- a/src/impl_dyn.rs +++ b/src/impl_dyn.rs @@ -10,8 +10,7 @@ use crate::imp_prelude::*; /// # Methods for Dynamic-Dimensional Arrays -impl ArrayBase -where S: Data +impl LayoutRef { /// Insert new array axis of length 1 at `axis`, modifying the shape and /// strides in-place. @@ -32,8 +31,8 @@ where S: Data pub fn insert_axis_inplace(&mut self, axis: Axis) { assert!(axis.index() <= self.ndim()); - self.layout.dim = self.layout.dim.insert_axis(axis); - self.layout.strides = self.layout.strides.insert_axis(axis); + self.dim = self.dim.insert_axis(axis); + self.strides = self.strides.insert_axis(axis); } /// Collapses the array to `index` along the axis and removes the axis, @@ -55,10 +54,14 @@ where S: Data pub fn index_axis_inplace(&mut self, axis: Axis, index: usize) { self.collapse_axis(axis, index); - self.layout.dim = self.layout.dim.remove_axis(axis); - self.layout.strides = self.layout.strides.remove_axis(axis); + self.dim = self.dim.remove_axis(axis); + self.strides = self.strides.remove_axis(axis); } +} +impl ArrayBase +where S: Data +{ /// Remove axes of length 1 and return the modified array. /// /// If the array has more the one dimension, the result array will always diff --git a/src/impl_ops.rs b/src/impl_ops.rs index 46ea18a7c..53f49cc43 100644 --- a/src/impl_ops.rs +++ b/src/impl_ops.rs @@ -72,6 +72,7 @@ where E: Dimension, { type Output = ArrayBase>::Output>; + #[track_caller] fn $mth(self, rhs: ArrayBase) -> Self::Output { @@ -100,8 +101,37 @@ where E: Dimension, { type Output = ArrayBase>::Output>; + #[track_caller] fn $mth(self, rhs: &ArrayBase) -> Self::Output + { + self.$mth(&**rhs) + } +} + +/// Perform elementwise +#[doc=$doc] +/// between `self` and reference `rhs`, +/// and return the result. +/// +/// `rhs` must be an `Array` or `ArcArray`. +/// +/// If their shapes disagree, `self` is broadcast to their broadcast shape, +/// cloning the data if needed. +/// +/// **Panics** if broadcasting isn’t possible. +impl<'a, A, B, S, D, E> $trt<&'a ArrayRef> for ArrayBase +where + A: Clone + $trt, + B: Clone, + S: DataOwned + DataMut, + D: Dimension + DimMax, + E: Dimension, +{ + type Output = ArrayBase>::Output>; + + #[track_caller] + fn $mth(self, rhs: &ArrayRef) -> Self::Output { if self.ndim() == rhs.ndim() && self.shape() == rhs.shape() { let mut out = self.into_dimensionality::<>::Output>().unwrap(); @@ -141,6 +171,36 @@ where E: Dimension + DimMax, { type Output = ArrayBase>::Output>; + + #[track_caller] + fn $mth(self, rhs: ArrayBase) -> Self::Output + where + { + (&**self).$mth(rhs) + } +} + +/// Perform elementwise +#[doc=$doc] +/// between reference `self` and `rhs`, +/// and return the result. +/// +/// `rhs` must be an `Array` or `ArcArray`. +/// +/// If their shapes disagree, `self` is broadcast to their broadcast shape, +/// cloning the data if needed. +/// +/// **Panics** if broadcasting isn’t possible. +impl<'a, A, B, S2, D, E> $trt> for &'a ArrayRef +where + A: Clone + $trt, + B: Clone, + S2: DataOwned + DataMut, + D: Dimension, + E: Dimension + DimMax, +{ + type Output = ArrayBase>::Output>; + #[track_caller] fn $mth(self, rhs: ArrayBase) -> Self::Output where @@ -181,8 +241,33 @@ where E: Dimension, { type Output = Array>::Output>; + #[track_caller] fn $mth(self, rhs: &'a ArrayBase) -> Self::Output { + (&**self).$mth(&**rhs) + } +} + +/// Perform elementwise +#[doc=$doc] +/// between references `self` and `rhs`, +/// and return the result as a new `Array`. +/// +/// If their shapes disagree, `self` and `rhs` is broadcast to their broadcast shape, +/// cloning the data if needed. +/// +/// **Panics** if broadcasting isn’t possible. +impl<'a, A, B, D, E> $trt<&'a ArrayRef> for &'a ArrayRef +where + A: Clone + $trt, + B: Clone, + D: Dimension + DimMax, + E: Dimension, +{ + type Output = Array>::Output>; + + #[track_caller] + fn $mth(self, rhs: &'a ArrayRef) -> Self::Output { let (lhs, rhs) = if self.ndim() == rhs.ndim() && self.shape() == rhs.shape() { let lhs = self.view().into_dimensionality::<>::Output>().unwrap(); let rhs = rhs.view().into_dimensionality::<>::Output>().unwrap(); @@ -226,6 +311,23 @@ impl<'a, A, S, D, B> $trt for &'a ArrayBase B: ScalarOperand, { type Output = Array; + + fn $mth(self, x: B) -> Self::Output { + (&**self).$mth(x) + } +} + +/// Perform elementwise +#[doc=$doc] +/// between the reference `self` and the scalar `x`, +/// and return the result as a new `Array`. +impl<'a, A, D, B> $trt for &'a ArrayRef + where A: Clone + $trt, + D: Dimension, + B: ScalarOperand, +{ + type Output = Array; + fn $mth(self, x: B) -> Self::Output { self.map(move |elt| elt.clone() $operator x.clone()) } @@ -277,7 +379,21 @@ impl<'a, S, D> $trt<&'a ArrayBase> for $scalar D: Dimension, { type Output = Array<$scalar, D>; + fn $mth(self, rhs: &ArrayBase) -> Self::Output { + self.$mth(&**rhs) + } +} + +// Perform elementwise +// between the scalar `self` and array `rhs`, +// and return the result as a new `Array`. +impl<'a, D> $trt<&'a ArrayRef<$scalar, D>> for $scalar + where D: Dimension +{ + type Output = Array<$scalar, D>; + + fn $mth(self, rhs: &ArrayRef<$scalar, D>) -> Self::Output { if_commutative!($commutative { rhs.$mth(self) } or { @@ -381,6 +497,7 @@ mod arithmetic_ops D: Dimension, { type Output = Self; + /// Perform an elementwise negation of `self` and return the result. fn neg(mut self) -> Self { @@ -398,6 +515,22 @@ mod arithmetic_ops D: Dimension, { type Output = Array; + + /// Perform an elementwise negation of reference `self` and return the + /// result as a new `Array`. + fn neg(self) -> Array + { + (&**self).neg() + } + } + + impl<'a, A, D> Neg for &'a ArrayRef + where + &'a A: 'a + Neg, + D: Dimension, + { + type Output = Array; + /// Perform an elementwise negation of reference `self` and return the /// result as a new `Array`. fn neg(self) -> Array @@ -413,6 +546,7 @@ mod arithmetic_ops D: Dimension, { type Output = Self; + /// Perform an elementwise unary not of `self` and return the result. fn not(mut self) -> Self { @@ -430,6 +564,22 @@ mod arithmetic_ops D: Dimension, { type Output = Array; + + /// Perform an elementwise unary not of reference `self` and return the + /// result as a new `Array`. + fn not(self) -> Array + { + (&**self).not() + } + } + + impl<'a, A, D> Not for &'a ArrayRef + where + &'a A: 'a + Not, + D: Dimension, + { + type Output = Array; + /// Perform an elementwise unary not of reference `self` and return the /// result as a new `Array`. fn not(self) -> Array @@ -462,6 +612,22 @@ mod assign_ops { #[track_caller] fn $method(&mut self, rhs: &ArrayBase) { + (**self).$method(&**rhs) + } + } + + #[doc=$doc] + /// If their shapes disagree, `rhs` is broadcast to the shape of `self`. + /// + /// **Panics** if broadcasting isn’t possible. + impl<'a, A, D, E> $trt<&'a ArrayRef> for ArrayRef + where + A: Clone + $trt, + D: Dimension, + E: Dimension, + { + #[track_caller] + fn $method(&mut self, rhs: &ArrayRef) { self.zip_mut_with(rhs, |x, y| { x.$method(y.clone()); }); @@ -474,6 +640,17 @@ mod assign_ops A: ScalarOperand + $trt, S: DataMut, D: Dimension, + { + fn $method(&mut self, rhs: A) { + (**self).$method(rhs) + } + } + + #[doc=$doc] + impl $trt for ArrayRef + where + A: ScalarOperand + $trt, + D: Dimension, { fn $method(&mut self, rhs: A) { self.map_inplace(move |elt| { diff --git a/src/linalg/impl_linalg.rs b/src/linalg/impl_linalg.rs index b4967e20d..32112c896 100644 --- a/src/linalg/impl_linalg.rs +++ b/src/linalg/impl_linalg.rs @@ -11,6 +11,8 @@ use crate::imp_prelude::*; #[cfg(feature = "blas")] use crate::dimension::offset_from_low_addr_ptr_to_logical_ptr; use crate::numeric_util; +use crate::ArrayRef1; +use crate::ArrayRef2; use crate::{LinalgScalar, Zip}; @@ -40,8 +42,7 @@ const GEMM_BLAS_CUTOFF: usize = 7; #[allow(non_camel_case_types)] type blas_index = c_int; // blas index type -impl ArrayBase -where S: Data +impl ArrayRef { /// Perform dot product or matrix multiplication of arrays `self` and `rhs`. /// @@ -67,10 +68,8 @@ where S: Data Dot::dot(self, rhs) } - fn dot_generic(&self, rhs: &ArrayBase) -> A - where - S2: Data, - A: LinalgScalar, + fn dot_generic(&self, rhs: &ArrayRef) -> A + where A: LinalgScalar { debug_assert_eq!(self.len(), rhs.len()); assert!(self.len() == rhs.len()); @@ -89,19 +88,15 @@ where S: Data } #[cfg(not(feature = "blas"))] - fn dot_impl(&self, rhs: &ArrayBase) -> A - where - S2: Data, - A: LinalgScalar, + fn dot_impl(&self, rhs: &ArrayRef) -> A + where A: LinalgScalar { self.dot_generic(rhs) } #[cfg(feature = "blas")] - fn dot_impl(&self, rhs: &ArrayBase) -> A - where - S2: Data, - A: LinalgScalar, + fn dot_impl(&self, rhs: &ArrayRef) -> A + where A: LinalgScalar { // Use only if the vector is large enough to be worth it if self.len() >= DOT_BLAS_CUTOFF { @@ -165,14 +160,64 @@ pub trait Dot /// /// For two-dimensional arrays: a rectangular array. type Output; + fn dot(&self, rhs: &Rhs) -> Self::Output; } -impl Dot> for ArrayBase -where - S: Data, - S2: Data, - A: LinalgScalar, +macro_rules! impl_dots { + ( + $shape1:ty, + $shape2:ty + ) => { + impl Dot> for ArrayBase + where + S: Data, + S2: Data, + A: LinalgScalar, + { + type Output = as Dot>>::Output; + + fn dot(&self, rhs: &ArrayBase) -> Self::Output + { + Dot::dot(&**self, &**rhs) + } + } + + impl Dot> for ArrayBase + where + S: Data, + A: LinalgScalar, + { + type Output = as Dot>>::Output; + + fn dot(&self, rhs: &ArrayRef) -> Self::Output + { + (**self).dot(rhs) + } + } + + impl Dot> for ArrayRef + where + S: Data, + A: LinalgScalar, + { + type Output = as Dot>>::Output; + + fn dot(&self, rhs: &ArrayBase) -> Self::Output + { + self.dot(&**rhs) + } + } + }; +} + +impl_dots!(Ix1, Ix1); +impl_dots!(Ix1, Ix2); +impl_dots!(Ix2, Ix1); +impl_dots!(Ix2, Ix2); + +impl Dot> for ArrayRef +where A: LinalgScalar { type Output = A; @@ -185,17 +230,14 @@ where /// *Note:* If enabled, uses blas `dot` for elements of `f32, f64` when memory /// layout allows. #[track_caller] - fn dot(&self, rhs: &ArrayBase) -> A + fn dot(&self, rhs: &ArrayRef) -> A { self.dot_impl(rhs) } } -impl Dot> for ArrayBase -where - S: Data, - S2: Data, - A: LinalgScalar, +impl Dot> for ArrayRef +where A: LinalgScalar { type Output = Array; @@ -209,14 +251,13 @@ where /// /// **Panics** if shapes are incompatible. #[track_caller] - fn dot(&self, rhs: &ArrayBase) -> Array + fn dot(&self, rhs: &ArrayRef) -> Array { - rhs.t().dot(self) + (*rhs.t()).dot(self) } } -impl ArrayBase -where S: Data +impl ArrayRef { /// Perform matrix multiplication of rectangular arrays `self` and `rhs`. /// @@ -255,14 +296,12 @@ where S: Data } } -impl Dot> for ArrayBase -where - S: Data, - S2: Data, - A: LinalgScalar, +impl Dot> for ArrayRef +where A: LinalgScalar { type Output = Array2; - fn dot(&self, b: &ArrayBase) -> Array2 + + fn dot(&self, b: &ArrayRef) -> Array2 { let a = self.view(); let b = b.view(); @@ -318,15 +357,13 @@ fn general_dot_shape_error(m: usize, k: usize, k2: usize, n: usize, c1: usize, c /// Return a result array with shape *M*. /// /// **Panics** if shapes are incompatible. -impl Dot> for ArrayBase -where - S: Data, - S2: Data, - A: LinalgScalar, +impl Dot> for ArrayRef +where A: LinalgScalar { type Output = Array; + #[track_caller] - fn dot(&self, rhs: &ArrayBase) -> Array + fn dot(&self, rhs: &ArrayRef) -> Array { let ((m, a), n) = (self.dim(), rhs.dim()); if a != n { @@ -342,10 +379,8 @@ where } } -impl ArrayBase -where - S: Data, - D: Dimension, +impl ArrayRef +where D: Dimension { /// Perform the operation `self += alpha * rhs` efficiently, where /// `alpha` is a scalar and `rhs` is another array. This operation is @@ -355,10 +390,8 @@ where /// /// **Panics** if broadcasting isn’t possible. #[track_caller] - pub fn scaled_add(&mut self, alpha: A, rhs: &ArrayBase) + pub fn scaled_add(&mut self, alpha: A, rhs: &ArrayRef) where - S: DataMut, - S2: Data, A: LinalgScalar, E: Dimension, { @@ -372,7 +405,7 @@ where use self::mat_mul_general as mat_mul_impl; #[cfg(feature = "blas")] -fn mat_mul_impl(alpha: A, a: &ArrayView2<'_, A>, b: &ArrayView2<'_, A>, beta: A, c: &mut ArrayViewMut2<'_, A>) +fn mat_mul_impl(alpha: A, a: &ArrayRef2, b: &ArrayRef2, beta: A, c: &mut ArrayRef2) where A: LinalgScalar { let ((m, k), (k2, n)) = (a.dim(), b.dim()); @@ -458,9 +491,8 @@ where A: LinalgScalar } /// C ← α A B + β C -fn mat_mul_general( - alpha: A, lhs: &ArrayView2<'_, A>, rhs: &ArrayView2<'_, A>, beta: A, c: &mut ArrayViewMut2<'_, A>, -) where A: LinalgScalar +fn mat_mul_general(alpha: A, lhs: &ArrayRef2, rhs: &ArrayRef2, beta: A, c: &mut ArrayRef2) +where A: LinalgScalar { let ((m, k), (_, n)) = (lhs.dim(), rhs.dim()); @@ -592,13 +624,8 @@ fn mat_mul_general( /// layout allows. The default matrixmultiply backend is otherwise used for /// `f32, f64` for all memory layouts. #[track_caller] -pub fn general_mat_mul( - alpha: A, a: &ArrayBase, b: &ArrayBase, beta: A, c: &mut ArrayBase, -) where - S1: Data, - S2: Data, - S3: DataMut, - A: LinalgScalar, +pub fn general_mat_mul(alpha: A, a: &ArrayRef2, b: &ArrayRef2, beta: A, c: &mut ArrayRef2) +where A: LinalgScalar { let ((m, k), (k2, n)) = (a.dim(), b.dim()); let (m2, n2) = c.dim(); @@ -621,13 +648,8 @@ pub fn general_mat_mul( /// layout allows. #[track_caller] #[allow(clippy::collapsible_if)] -pub fn general_mat_vec_mul( - alpha: A, a: &ArrayBase, x: &ArrayBase, beta: A, y: &mut ArrayBase, -) where - S1: Data, - S2: Data, - S3: DataMut, - A: LinalgScalar, +pub fn general_mat_vec_mul(alpha: A, a: &ArrayRef2, x: &ArrayRef1, beta: A, y: &mut ArrayRef1) +where A: LinalgScalar { unsafe { general_mat_vec_mul_impl(alpha, a, x, beta, y.raw_view_mut()) } } @@ -641,12 +663,9 @@ pub fn general_mat_vec_mul( /// The caller must ensure that the raw view is valid for writing. /// the destination may be uninitialized iff beta is zero. #[allow(clippy::collapsible_else_if)] -unsafe fn general_mat_vec_mul_impl( - alpha: A, a: &ArrayBase, x: &ArrayBase, beta: A, y: RawArrayViewMut, -) where - S1: Data, - S2: Data, - A: LinalgScalar, +unsafe fn general_mat_vec_mul_impl( + alpha: A, a: &ArrayRef2, x: &ArrayRef1, beta: A, y: RawArrayViewMut, +) where A: LinalgScalar { let ((m, k), k2) = (a.dim(), x.dim()); let m2 = y.as_ref().dim(); @@ -658,7 +677,7 @@ unsafe fn general_mat_vec_mul_impl( ($ty:ty, $gemv:ident) => { if same_type::() { if let Some(layout) = get_blas_compatible_layout(&a) { - if blas_compat_1d::<$ty, _>(&x) && blas_compat_1d::<$ty, _>(&y) { + if blas_compat_1d::<$ty, _>(&x) && blas_compat_1d::<$ty, _>(&y.as_ref()) { // Determine stride between rows or columns. Note that the stride is // adjusted to at least `k` or `m` to handle the case of a matrix with a // trivial (length 1) dimension, since the stride for the trivial dimension @@ -669,7 +688,7 @@ unsafe fn general_mat_vec_mul_impl( let cblas_layout = layout.to_cblas_layout(); // Low addr in memory pointers required for x, y - let x_offset = offset_from_low_addr_ptr_to_logical_ptr(&x.layout.dim, &x.layout.strides); + let x_offset = offset_from_low_addr_ptr_to_logical_ptr(&x.dim, &x.strides); let x_ptr = x.ptr.as_ptr().sub(x_offset); let y_offset = offset_from_low_addr_ptr_to_logical_ptr(&y.layout.dim, &y.layout.strides); let y_ptr = y.layout.ptr.as_ptr().sub(y_offset); @@ -721,11 +740,8 @@ unsafe fn general_mat_vec_mul_impl( /// /// The kronecker product of a LxN matrix A and a MxR matrix B is a (L*M)x(N*R) /// matrix K formed by the block multiplication A_ij * B. -pub fn kron(a: &ArrayBase, b: &ArrayBase) -> Array -where - S1: Data, - S2: Data, - A: LinalgScalar, +pub fn kron(a: &ArrayRef2, b: &ArrayRef2) -> Array +where A: LinalgScalar { let dimar = a.shape()[0]; let dimac = a.shape()[1]; @@ -774,16 +790,15 @@ fn complex_array(z: Complex) -> [A; 2] } #[cfg(feature = "blas")] -fn blas_compat_1d(a: &ArrayBase) -> bool +fn blas_compat_1d(a: &LayoutRef) -> bool where - S: RawData, A: 'static, - S::Elem: 'static, + B: 'static, { - if !same_type::() { + if !same_type::() { return false; } - if a.as_ref().len() > blas_index::MAX as usize { + if a.len() > blas_index::MAX as usize { return false; } let stride = a.strides()[0]; @@ -886,8 +901,7 @@ fn is_blas_2d(dim: &Ix2, stride: &Ix2, order: BlasOrder) -> bool /// Get BLAS compatible layout if any (C or F, preferring the former) #[cfg(feature = "blas")] -fn get_blas_compatible_layout(a: &ArrayBase) -> Option -where S: Data +fn get_blas_compatible_layout(a: &ArrayRef) -> Option { if is_blas_2d(&a.dim, &a.strides, BlasOrder::C) { Some(BlasOrder::C) @@ -903,8 +917,7 @@ where S: Data /// /// Return leading stride (lda, ldb, ldc) of array #[cfg(feature = "blas")] -fn blas_stride(a: &ArrayBase, order: BlasOrder) -> blas_index -where S: Data +fn blas_stride(a: &ArrayRef, order: BlasOrder) -> blas_index { let axis = order.get_blas_lead_axis(); let other_axis = 1 - axis; @@ -925,13 +938,12 @@ where S: Data #[cfg(test)] #[cfg(feature = "blas")] -fn blas_row_major_2d(a: &ArrayBase) -> bool +fn blas_row_major_2d(a: &ArrayRef2) -> bool where - S: Data, A: 'static, - S::Elem: 'static, + B: 'static, { - if !same_type::() { + if !same_type::() { return false; } is_blas_2d(&a.dim, &a.strides, BlasOrder::C) @@ -939,13 +951,12 @@ where #[cfg(test)] #[cfg(feature = "blas")] -fn blas_column_major_2d(a: &ArrayBase) -> bool +fn blas_column_major_2d(a: &ArrayRef2) -> bool where - S: Data, A: 'static, - S::Elem: 'static, + B: 'static, { - if !same_type::() { + if !same_type::() { return false; } is_blas_2d(&a.dim, &a.strides, BlasOrder::F) diff --git a/src/numeric/impl_float_maths.rs b/src/numeric/impl_float_maths.rs index 54fed49c2..7f6731ab8 100644 --- a/src/numeric/impl_float_maths.rs +++ b/src/numeric/impl_float_maths.rs @@ -54,10 +54,9 @@ macro_rules! binary_ops { /// /// Element-wise math functions for any array type that contains float number. #[cfg(feature = "std")] -impl ArrayBase +impl ArrayRef where A: 'static + Float, - S: Data, D: Dimension, { boolean_ops! { @@ -143,10 +142,9 @@ where } } -impl ArrayBase +impl ArrayRef where A: 'static + PartialOrd + Clone, - S: Data, D: Dimension, { /// Limit the values for each element, similar to NumPy's `clip` function. diff --git a/src/numeric/impl_numeric.rs b/src/numeric/impl_numeric.rs index 6c67b9135..0f209fa33 100644 --- a/src/numeric/impl_numeric.rs +++ b/src/numeric/impl_numeric.rs @@ -17,10 +17,8 @@ use crate::numeric_util; use crate::Slice; /// # Numerical Methods for Arrays -impl ArrayBase -where - S: Data, - D: Dimension, +impl ArrayRef +where D: Dimension { /// Return the sum of all elements in the array. /// diff --git a/src/parallel/impl_par_methods.rs b/src/parallel/impl_par_methods.rs index c6af4e8f3..51f668bcc 100644 --- a/src/parallel/impl_par_methods.rs +++ b/src/parallel/impl_par_methods.rs @@ -10,9 +10,8 @@ use crate::partial::Partial; /// # Parallel methods /// /// These methods require crate feature `rayon`. -impl ArrayBase +impl ArrayRef where - S: DataMut, D: Dimension, A: Send + Sync, { diff --git a/src/prelude.rs b/src/prelude.rs index 998640988..43e583b56 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -26,6 +26,7 @@ pub use crate::{ ArrayView, ArrayViewMut, CowArray, + LayoutRef, RawArrayView, RawArrayViewMut, RawRef, diff --git a/src/tri.rs b/src/tri.rs index d756aac21..e0681b32c 100644 --- a/src/tri.rs +++ b/src/tri.rs @@ -13,16 +13,14 @@ use num_traits::Zero; use crate::{ dimension::{is_layout_c, is_layout_f}, Array, - ArrayBase, + ArrayRef, Axis, - Data, Dimension, Zip, }; -impl ArrayBase +impl ArrayRef where - S: Data, D: Dimension, A: Clone + Zero, { From d63d26e1657d87382efe757b2dbb7094e7015b56 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Mon, 14 Oct 2024 00:27:12 -0400 Subject: [PATCH 15/33] Satisfying CI/CD --- src/parallel/impl_par_methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parallel/impl_par_methods.rs b/src/parallel/impl_par_methods.rs index 51f668bcc..0a2f41c8e 100644 --- a/src/parallel/impl_par_methods.rs +++ b/src/parallel/impl_par_methods.rs @@ -1,5 +1,5 @@ use crate::AssignElem; -use crate::{Array, ArrayBase, DataMut, Dimension, IntoNdProducer, NdProducer, Zip}; +use crate::{Array, ArrayRef, Dimension, IntoNdProducer, NdProducer, Zip}; use super::send_producer::SendProducer; use crate::parallel::par::ParallelSplits; From b7281f532f3a92933eb3896974ab43d995895383 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Mon, 14 Oct 2024 16:56:08 -0400 Subject: [PATCH 16/33] Adds some aliases to avoid breaking changes, and adds an example of how to write functionality with the new types --- .gitignore | 3 + examples/functions_and_traits.rs | 178 ++++++++++++++++++++++ src/{alias_slicing.rs => alias_asref.rs} | 142 +++++++++++++++++- src/impl_2d.rs | 6 +- src/impl_methods.rs | 33 ++-- src/impl_owned_array.rs | 16 +- src/impl_raw_views.rs | 6 +- src/impl_ref_types.rs | 183 ++++++++++++++++++----- src/iterators/chunks.rs | 16 +- src/lib.rs | 2 +- src/linalg/impl_linalg.rs | 4 +- src/zip/mod.rs | 1 - src/zip/ndproducer.rs | 16 +- tests/raw_views.rs | 4 +- tests/test_ref_structure.rs | 39 ----- 15 files changed, 513 insertions(+), 136 deletions(-) create mode 100644 examples/functions_and_traits.rs rename src/{alias_slicing.rs => alias_asref.rs} (56%) delete mode 100644 tests/test_ref_structure.rs diff --git a/.gitignore b/.gitignore index e9b5ca25b..44b22a5e8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ target/ # Editor settings .vscode .idea + +# Apple details +**/.DS_Store diff --git a/examples/functions_and_traits.rs b/examples/functions_and_traits.rs new file mode 100644 index 000000000..dc8f73da4 --- /dev/null +++ b/examples/functions_and_traits.rs @@ -0,0 +1,178 @@ +//! Examples of how to write functions and traits that operate on `ndarray` types. +//! +//! `ndarray` has four kinds of array types that users may interact with: +//! 1. [`ArrayBase`], the owner of the layout that describes an array in memory; +//! this includes [`ndarray::Array`], [`ndarray::ArcArray`], [`ndarray::ArrayView`], +//! [`ndarray::RawArrayView`], and other variants. +//! 2. [`ArrayRef`], which represents a read-safe, uniquely-owned look at an array. +//! 3. [`RawRef`], which represents a read-unsafe, possibly-shared look at an array. +//! 4. [`LayoutRef`], which represents a look at an array's underlying structure, +//! but does not allow data reading of any kind. +//! +//! Below, we illustrate how to write functions and traits for most variants of these types. + +use ndarray::{ArrayBase, ArrayRef, Data, DataMut, Dimension, LayoutRef, RawData, RawDataMut, RawRef}; + +/// Take an array with the most basic requirements. +/// +/// This function takes its data as owning. It is very rare that a user will need to specifically +/// take a reference to an `ArrayBase`, rather than to one of the other four types. +#[rustfmt::skip] +fn takes_base_raw(arr: ArrayBase) -> ArrayBase +{ + // These skip from a possibly-raw array to `RawRef` and `LayoutRef`, and so must go through `AsRef` + takes_rawref(arr.as_ref()); // Caller uses `.as_ref` + takes_rawref_asref(&arr); // Implementor uses `.as_ref` + takes_layout(arr.as_ref()); // Caller uses `.as_ref` + takes_layout_asref(&arr); // Implementor uses `.as_ref` + + arr +} + +/// Similar to above, but allow us to read the underlying data. +#[rustfmt::skip] +fn takes_base_raw_mut(mut arr: ArrayBase) -> ArrayBase +{ + // These skip from a possibly-raw array to `RawRef` and `LayoutRef`, and so must go through `AsMut` + takes_rawref_mut(arr.as_mut()); // Caller uses `.as_mut` + takes_rawref_asmut(&mut arr); // Implementor uses `.as_mut` + takes_layout_mut(arr.as_mut()); // Caller uses `.as_mut` + takes_layout_asmut(&mut arr); // Implementor uses `.as_mut` + + arr +} + +/// Now take an array whose data is safe to read. +#[allow(dead_code)] +fn takes_base(mut arr: ArrayBase) -> ArrayBase +{ + // Raw call + arr = takes_base_raw(arr); + + // No need for AsRef, since data is safe + takes_arrref(&arr); + takes_rawref(&arr); + takes_rawref_asref(&arr); + takes_layout(&arr); + takes_layout_asref(&arr); + + arr +} + +/// Now, an array whose data is safe to read and that we can mutate. +/// +/// Notice that we include now a trait bound on `D: Dimension`; this is necessary in order +/// for the `ArrayBase` to dereference to an `ArrayRef` (or to any of the other types). +#[allow(dead_code)] +fn takes_base_mut(mut arr: ArrayBase) -> ArrayBase +{ + // Raw call + arr = takes_base_raw_mut(arr); + + // No need for AsMut, since data is safe + takes_arrref_mut(&mut arr); + takes_rawref_mut(&mut arr); + takes_rawref_asmut(&mut arr); + takes_layout_mut(&mut arr); + takes_layout_asmut(&mut arr); + + arr +} + +/// Now for new stuff: we want to read (but not alter) any array whose data is safe to read. +/// +/// This is probably the most common functionality that one would want to write. +/// As we'll see below, calling this function is very simple for `ArrayBase`. +fn takes_arrref(arr: &ArrayRef) +{ + // No need for AsRef, since data is safe + takes_rawref(arr); + takes_rawref_asref(arr); + takes_layout(arr); + takes_layout_asref(arr); +} + +/// Now we want any array whose data is safe to mutate. +/// +/// **Importantly**, any array passed to this function is guaranteed to uniquely point to its data. +/// As a result, passing a shared array to this function will **silently** un-share the array. +#[allow(dead_code)] +fn takes_arrref_mut(arr: &mut ArrayRef) +{ + // Immutable call + takes_arrref(arr); + + // No need for AsMut, since data is safe + takes_rawref_mut(arr); + takes_rawref_asmut(arr); + takes_layout_mut(arr); + takes_rawref_asmut(arr); +} + +/// Now, we no longer care about whether we can safely read data. +/// +/// This is probably the rarest type to deal with, since `LayoutRef` can access and modify an array's +/// shape and strides, and even do in-place slicing. As a result, `RawRef` is only for functionality +/// that requires unsafe data access, something that `LayoutRef` can't do. +/// +/// Writing functions and traits that deal with `RawRef`s and `LayoutRef`s can be done two ways: +/// 1. Directly on the types; calling these functions on arrays whose data are not known to be safe +/// to dereference (i.e., raw array views or `ArrayBase`) must explicitly call `.as_ref()`. +/// 2. Via a generic with `: AsRef>`; doing this will allow direct calling for all `ArrayBase` and +/// `ArrayRef` instances. +/// We'll demonstrate #1 here for both immutable and mutable references, then #2 directly below. +#[allow(dead_code)] +fn takes_rawref(arr: &RawRef) +{ + takes_layout(arr); + takes_layout_asref(arr); +} + +/// Mutable, directly take `RawRef` +#[allow(dead_code)] +fn takes_rawref_mut(arr: &mut RawRef) +{ + takes_layout(arr); + takes_layout_asmut(arr); +} + +/// Immutable, take a generic that implements `AsRef` to `RawRef` +#[allow(dead_code)] +fn takes_rawref_asref(_arr: &T) +where T: AsRef> +{ + takes_layout(_arr.as_ref()); + takes_layout_asref(_arr.as_ref()); +} + +/// Mutable, take a generic that implements `AsMut` to `RawRef` +#[allow(dead_code)] +fn takes_rawref_asmut(_arr: &mut T) +where T: AsMut> +{ + takes_layout_mut(_arr.as_mut()); + takes_layout_asmut(_arr.as_mut()); +} + +/// Finally, there's `LayoutRef`: this type provides read and write access to an array's *structure*, but not its *data*. +/// +/// Practically, this means that functions that only read/modify an array's shape or strides, +/// such as checking dimensionality or slicing, should take `LayoutRef`. +/// +/// Like `RawRef`, functions can be written either directly on `LayoutRef` or as generics with `: AsRef>>`. +#[allow(dead_code)] +fn takes_layout(_arr: &LayoutRef) {} + +/// Mutable, directly take `LayoutRef` +#[allow(dead_code)] +fn takes_layout_mut(_arr: &mut LayoutRef) {} + +/// Immutable, take a generic that implements `AsRef` to `LayoutRef` +#[allow(dead_code)] +fn takes_layout_asref>, A, D>(_arr: &T) {} + +/// Mutable, take a generic that implements `AsMut` to `LayoutRef` +#[allow(dead_code)] +fn takes_layout_asmut>, A, D>(_arr: &mut T) {} + +fn main() {} diff --git a/src/alias_slicing.rs b/src/alias_asref.rs similarity index 56% rename from src/alias_slicing.rs rename to src/alias_asref.rs index 7c9b3d26b..60435177c 100644 --- a/src/alias_slicing.rs +++ b/src/alias_asref.rs @@ -1,4 +1,16 @@ -use crate::{iter::Axes, ArrayBase, Axis, AxisDescription, Dimension, LayoutRef, RawData, Slice, SliceArg}; +use crate::{ + iter::Axes, + ArrayBase, + Axis, + AxisDescription, + Dimension, + LayoutRef, + RawArrayView, + RawData, + RawRef, + Slice, + SliceArg, +}; impl ArrayBase { @@ -69,19 +81,19 @@ impl ArrayBase /// contiguous in memory, it has custom strides, etc. pub fn is_standard_layout(&self) -> bool { - self.as_ref().is_standard_layout() + >>::as_ref(self).is_standard_layout() } /// Return true if the array is known to be contiguous. pub(crate) fn is_contiguous(&self) -> bool { - self.as_ref().is_contiguous() + >>::as_ref(self).is_contiguous() } /// Return an iterator over the length and stride of each axis. pub fn axes(&self) -> Axes<'_, D> { - self.as_ref().axes() + >>::as_ref(self).axes() } /* @@ -170,9 +182,129 @@ impl ArrayBase self.as_mut().merge_axes(take, into) } + /// Return a raw view of the array. + #[inline] + pub fn raw_view(&self) -> RawArrayView + { + >>::as_ref(self).raw_view() + } + + /// Return a pointer to the first element in the array. + /// + /// Raw access to array elements needs to follow the strided indexing + /// scheme: an element at multi-index *I* in an array with strides *S* is + /// located at offset + /// + /// *Σ0 ≤ k < d Ik × Sk* + /// + /// where *d* is `self.ndim()`. + #[inline(always)] + pub fn as_ptr(&self) -> *const S::Elem + { + >>::as_ref(self).as_ptr() + } + + /// Return the total number of elements in the array. + pub fn len(&self) -> usize + { + >>::as_ref(self).len() + } + + /// Return the length of `axis`. + /// + /// The axis should be in the range `Axis(` 0 .. *n* `)` where *n* is the + /// number of dimensions (axes) of the array. + /// + /// ***Panics*** if the axis is out of bounds. + #[track_caller] + pub fn len_of(&self, axis: Axis) -> usize + { + >>::as_ref(self).len_of(axis) + } + + /// Return whether the array has any elements + pub fn is_empty(&self) -> bool + { + >>::as_ref(self).is_empty() + } + + /// Return the number of dimensions (axes) in the array + pub fn ndim(&self) -> usize + { + >>::as_ref(self).ndim() + } + + /// Return the shape of the array in its “pattern” form, + /// an integer in the one-dimensional case, tuple in the n-dimensional cases + /// and so on. + pub fn dim(&self) -> D::Pattern + { + >>::as_ref(self).dim() + } + + /// Return the shape of the array as it's stored in the array. + /// + /// This is primarily useful for passing to other `ArrayBase` + /// functions, such as when creating another array of the same + /// shape and dimensionality. + /// + /// ``` + /// use ndarray::Array; + /// + /// let a = Array::from_elem((2, 3), 5.); + /// + /// // Create an array of zeros that's the same shape and dimensionality as `a`. + /// let b = Array::::zeros(a.raw_dim()); + /// ``` + pub fn raw_dim(&self) -> D + { + >>::as_ref(self).raw_dim() + } + + /// Return the shape of the array as a slice. + /// + /// Note that you probably don't want to use this to create an array of the + /// same shape as another array because creating an array with e.g. + /// [`Array::zeros()`](ArrayBase::zeros) using a shape of type `&[usize]` + /// results in a dynamic-dimensional array. If you want to create an array + /// that has the same shape and dimensionality as another array, use + /// [`.raw_dim()`](ArrayBase::raw_dim) instead: + /// + /// ```rust + /// use ndarray::{Array, Array2}; + /// + /// let a = Array2::::zeros((3, 4)); + /// let shape = a.shape(); + /// assert_eq!(shape, &[3, 4]); + /// + /// // Since `a.shape()` returned `&[usize]`, we get an `ArrayD` instance: + /// let b = Array::zeros(shape); + /// assert_eq!(a.clone().into_dyn(), b); + /// + /// // To get the same dimension type, use `.raw_dim()` instead: + /// let c = Array::zeros(a.raw_dim()); + /// assert_eq!(a, c); + /// ``` + pub fn shape(&self) -> &[usize] + { + >>::as_ref(self).shape() + } + /// Return the strides of the array as a slice. pub fn strides(&self) -> &[isize] { - self.as_ref().strides() + >>::as_ref(self).strides() + } + + /// Return the stride of `axis`. + /// + /// The axis should be in the range `Axis(` 0 .. *n* `)` where *n* is the + /// number of dimensions (axes) of the array. + /// + /// ***Panics*** if the axis is out of bounds. + #[track_caller] + pub fn stride_of(&self, axis: Axis) -> isize + { + >>::as_ref(self).stride_of(axis) } } diff --git a/src/impl_2d.rs b/src/impl_2d.rs index 061bf45fd..27358dca9 100644 --- a/src/impl_2d.rs +++ b/src/impl_2d.rs @@ -65,7 +65,7 @@ impl LayoutRef /// ``` pub fn nrows(&self) -> usize { - self.as_ref().len_of(Axis(0)) + self.len_of(Axis(0)) } } @@ -124,7 +124,7 @@ impl LayoutRef /// ``` pub fn ncols(&self) -> usize { - self.as_ref().len_of(Axis(1)) + self.len_of(Axis(1)) } /// Return true if the array is square, false otherwise. @@ -144,7 +144,7 @@ impl LayoutRef /// ``` pub fn is_square(&self) -> bool { - let (m, n) = self.as_ref().dim(); + let (m, n) = self.dim(); m == n } } diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 7cdf7d3bc..3a6c53265 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -578,7 +578,7 @@ where { assert_eq!( info.in_ndim(), - self.as_ref().ndim(), + self.ndim(), "The input dimension of `info` must match the array to be sliced.", ); let out_ndim = info.out_ndim(); @@ -599,7 +599,7 @@ where } SliceInfoElem::Index(index) => { // Collapse the axis in-place to update the `ptr`. - let i_usize = abs_index(self.as_ref().len_of(Axis(old_axis)), index); + let i_usize = abs_index(self.len_of(Axis(old_axis)), index); self.collapse_axis(Axis(old_axis), i_usize); // Skip copying the axis since it should be removed. Note that // removing this axis is safe because `.collapse_axis()` panics @@ -614,7 +614,7 @@ where new_axis += 1; } }); - debug_assert_eq!(old_axis, self.as_ref().ndim()); + debug_assert_eq!(old_axis, self.ndim()); debug_assert_eq!(new_axis, out_ndim); // safe because new dimension, strides allow access to a subset of old data @@ -1568,7 +1568,7 @@ where { /* empty shape has len 1 */ let len = self.layout.dim.slice().iter().cloned().min().unwrap_or(1); - let stride = LayoutRef::strides(self.as_ref()).iter().sum(); + let stride = self.strides().iter().sum(); (len, stride) } @@ -2039,12 +2039,7 @@ where match order { Order::RowMajor if self.is_standard_layout() => Ok(self.with_strides_dim(shape.default_strides(), shape)), - Order::ColumnMajor - if self - .as_ref() - .raw_view() - .reversed_axes() - .is_standard_layout() => + Order::ColumnMajor if self.raw_view().reversed_axes().is_standard_layout() => Ok(self.with_strides_dim(shape.fortran_strides(), shape)), _otherwise => Err(error::from_kind(error::ErrorKind::IncompatibleLayout)), } @@ -2087,13 +2082,7 @@ where // safe because arrays are contiguous and len is unchanged if self.is_standard_layout() { Ok(self.with_strides_dim(shape.default_strides(), shape)) - } else if self.as_ref().ndim() > 1 - && self - .as_ref() - .raw_view() - .reversed_axes() - .is_standard_layout() - { + } else if self.ndim() > 1 && self.raw_view().reversed_axes().is_standard_layout() { Ok(self.with_strides_dim(shape.fortran_strides(), shape)) } else { Err(error::from_kind(error::ErrorKind::IncompatibleLayout)) @@ -2530,7 +2519,7 @@ where { let axes = axes.into_dimension(); // Ensure that each axis is used exactly once. - let mut usage_counts = D::zeros(self.as_ref().ndim()); + let mut usage_counts = D::zeros(self.ndim()); for axis in axes.slice() { usage_counts[*axis] += 1; } @@ -2539,7 +2528,7 @@ where } // Determine the new shape and strides. let mut new_dim = usage_counts; // reuse to avoid an allocation - let mut new_strides = D::zeros(self.as_ref().ndim()); + let mut new_strides = D::zeros(self.ndim()); { let dim = self.layout.dim.slice(); let strides = self.layout.strides.slice(); @@ -2686,7 +2675,7 @@ where #[track_caller] pub fn insert_axis(self, axis: Axis) -> ArrayBase { - assert!(axis.index() <= self.as_ref().ndim()); + assert!(axis.index() <= self.ndim()); // safe because a new axis of length one does not affect memory layout unsafe { let strides = self.layout.strides.insert_axis(axis); @@ -2710,7 +2699,7 @@ where pub(crate) fn pointer_is_inbounds(&self) -> bool { - self.data._is_pointer_inbounds(self.as_ref().as_ptr()) + self.data._is_pointer_inbounds(self.as_ptr()) } } @@ -3172,7 +3161,7 @@ impl ArrayRef return; } let mut curr = self.raw_view_mut(); // mut borrow of the array here - let mut prev = curr.as_ref().raw_view(); // derive further raw views from the same borrow + let mut prev = curr.raw_view(); // derive further raw views from the same borrow prev.slice_axis_inplace(axis, Slice::from(..-1)); curr.slice_axis_inplace(axis, Slice::from(1..)); // This implementation relies on `Zip` iterating along `axis` in order. diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs index 3b0ef02be..dc79ecda0 100644 --- a/src/impl_owned_array.rs +++ b/src/impl_owned_array.rs @@ -743,11 +743,11 @@ where D: Dimension let tail_ptr = self.data.as_end_nonnull(); let mut tail_view = RawArrayViewMut::new(tail_ptr, array_dim, tail_strides); - if tail_view.as_ref().ndim() > 1 { + if tail_view.ndim() > 1 { sort_axes_in_default_order_tandem(&mut tail_view, &mut array); debug_assert!(tail_view.is_standard_layout(), "not std layout dim: {:?}, strides: {:?}", - tail_view.as_ref().shape(), LayoutRef::strides(tail_view.as_ref())); + tail_view.shape(), LayoutRef::strides(tail_view.as_ref())); } // Keep track of currently filled length of `self.data` and update it @@ -872,10 +872,10 @@ pub(crate) unsafe fn drop_unreachable_raw( mut self_: RawArrayViewMut, data_ptr: NonNull, data_len: usize, ) where D: Dimension { - let self_len = self_.as_ref().len(); + let self_len = self_.len(); - for i in 0..self_.as_ref().ndim() { - if self_.as_ref().stride_of(Axis(i)) < 0 { + for i in 0..self_.ndim() { + if self_.stride_of(Axis(i)) < 0 { self_.invert_axis(Axis(i)); } } @@ -898,7 +898,7 @@ pub(crate) unsafe fn drop_unreachable_raw( // As an optimization, the innermost axis is removed if it has stride 1, because // we then have a long stretch of contiguous elements we can skip as one. let inner_lane_len; - if self_.as_ref().ndim() > 1 && self_.layout.strides.last_elem() == 1 { + if self_.ndim() > 1 && self_.layout.strides.last_elem() == 1 { self_.layout.dim.slice_mut().rotate_right(1); self_.layout.strides.slice_mut().rotate_right(1); inner_lane_len = self_.layout.dim[0]; @@ -946,7 +946,7 @@ where S: RawData, D: Dimension, { - if a.as_ref().ndim() <= 1 { + if a.ndim() <= 1 { return; } sort_axes1_impl(&mut a.layout.dim, &mut a.layout.strides); @@ -986,7 +986,7 @@ where S2: RawData, D: Dimension, { - if a.as_ref().ndim() <= 1 { + if a.ndim() <= 1 { return; } sort_axes2_impl(&mut a.layout.dim, &mut a.layout.strides, &mut b.layout.dim, &mut b.layout.strides); diff --git a/src/impl_raw_views.rs b/src/impl_raw_views.rs index 049bdc536..5bb2a0e42 100644 --- a/src/impl_raw_views.rs +++ b/src/impl_raw_views.rs @@ -112,9 +112,9 @@ where D: Dimension #[inline] pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self) { - assert!(index <= self.as_ref().len_of(axis)); + assert!(index <= self.len_of(axis)); let left_ptr = self.layout.ptr.as_ptr(); - let right_ptr = if index == self.as_ref().len_of(axis) { + let right_ptr = if index == self.len_of(axis) { self.layout.ptr.as_ptr() } else { let offset = stride_offset(index, self.layout.strides.axis(axis)); @@ -186,7 +186,7 @@ where D: Dimension } let ptr_re: *mut T = self.layout.ptr.as_ptr().cast(); - let ptr_im: *mut T = if self.as_ref().is_empty() { + let ptr_im: *mut T = if self.is_empty() { // In the empty case, we can just reuse the existing pointer since // it won't be dereferenced anyway. It is not safe to offset by // one, since the allocation may be empty. diff --git a/src/impl_ref_types.rs b/src/impl_ref_types.rs index 48cb027fc..92e916887 100644 --- a/src/impl_ref_types.rs +++ b/src/impl_ref_types.rs @@ -1,9 +1,39 @@ -//! Code for the array reference type +//! Implementations that connect arrays to their reference types. +//! +//! `ndarray` has four kinds of array types that users may interact with: +//! 1. [`ArrayBase`], which represents arrays which own their layout (shape and strides) +//! 2. [`ArrayRef`], which represents a read-safe, uniquely-owned look at an array +//! 3. [`RawRef`], which represents a read-unsafe, possibly-shared look at an array +//! 4. [`LayoutRef`], which represents a look at an array's underlying structure, +//! but does not allow data reading of any kind +//! +//! These types are connected through a number of `Deref` and `AsRef` implementations. +//! 1. `ArrayBase` dereferences to `ArrayRef` when `S: Data` +//! 2. `ArrayBase` mutably dereferences to `ArrayRef` when `S: DataMut`, and ensures uniqueness +//! 3. `ArrayRef` mutably dereferences to `RawRef` +//! 4. `RawRef` mutably dereferences to `LayoutRef` +//! This chain works very well for arrays whose data is safe to read and is uniquely held. +//! Because raw views do not meet `S: Data`, they cannot dereference to `ArrayRef`; furthermore, +//! technical limitations of Rust's compiler means that `ArrayBase` cannot have multiple `Deref` implementations. +//! In addition, shared-data arrays do not want to go down the `Deref` path to get to methods on `RawRef` +//! or `LayoutRef`, since that would unecessarily ensure their uniqueness. +//! +//! To mitigate these problems, `ndarray` also provides `AsRef` and `AsMut` implementations as follows: +//! 1. `ArrayBase` implements `AsRef` to `RawRef` and `LayoutRef` when `S: RawData` +//! 2. `ArrayBase` implements `AsMut` to `RawRef` when `S: RawDataMut` +//! 3. `ArrayBase` implements `AsMut` to `LayoutRef` unconditionally +//! 4. `ArrayRef` implements `AsMut` to `RawRef` and `LayoutRef` unconditionally +//! 5. `RawRef` implements `AsMut` to `LayoutRef` +//! 6. `RawRef` and `LayoutRef` implement `AsMut` to themselves +//! +//! This allows users to write a single method or trait implementation that takes `T: AsRef>` +//! or `T: AsRef>` and have that functionality work on any of the relevant array types. use core::ops::{Deref, DerefMut}; -use crate::{ArrayBase, ArrayRef, Data, DataMut, Dimension, LayoutRef, RawData, RawRef}; +use crate::{ArrayBase, ArrayRef, Data, DataMut, Dimension, LayoutRef, RawData, RawDataMut, RawRef}; +// D1: &ArrayBase -> &ArrayRef when data is safe to read impl Deref for ArrayBase where S: Data { @@ -24,6 +54,7 @@ where S: Data } } +// D2: &mut ArrayBase -> &mut ArrayRef when data is safe to read; ensure uniqueness impl DerefMut for ArrayBase where S: DataMut, @@ -45,13 +76,15 @@ where } } -impl AsRef> for ArrayBase -where S: RawData +// D3: &ArrayRef -> &RawRef +impl Deref for ArrayRef { - fn as_ref(&self) -> &RawRef + type Target = RawRef; + + fn deref(&self) -> &Self::Target { unsafe { - (&self.layout as *const LayoutRef) + (self as *const ArrayRef) .cast::>() .as_ref() } @@ -59,13 +92,13 @@ where S: RawData } } -impl AsMut> for ArrayBase -where S: RawData +// D4: &mut ArrayRef -> &mut RawRef +impl DerefMut for ArrayRef { - fn as_mut(&mut self) -> &mut RawRef + fn deref_mut(&mut self) -> &mut Self::Target { unsafe { - (&mut self.layout as *mut LayoutRef) + (self as *mut ArrayRef) .cast::>() .as_mut() } @@ -73,30 +106,34 @@ where S: RawData } } -impl AsRef> for RawRef +// D5: &RawRef -> &LayoutRef +impl Deref for RawRef { - fn as_ref(&self) -> &RawRef + type Target = LayoutRef; + + fn deref(&self) -> &Self::Target { - self + &self.0 } } -impl AsMut> for RawRef +// D5: &mut RawRef -> &mut LayoutRef +impl DerefMut for RawRef { - fn as_mut(&mut self) -> &mut RawRef + fn deref_mut(&mut self) -> &mut Self::Target { - self + &mut self.0 } } -impl Deref for ArrayRef +// A1: &ArrayBase -AR-> &RawRef +impl AsRef> for ArrayBase +where S: RawData { - type Target = RawRef; - - fn deref(&self) -> &Self::Target + fn as_ref(&self) -> &RawRef { unsafe { - (self as *const ArrayRef) + (&self.layout as *const LayoutRef) .cast::>() .as_ref() } @@ -104,12 +141,14 @@ impl Deref for ArrayRef } } -impl DerefMut for ArrayRef +// A2: &mut ArrayBase -AM-> &mut RawRef +impl AsMut> for ArrayBase +where S: RawDataMut { - fn deref_mut(&mut self) -> &mut Self::Target + fn as_mut(&mut self) -> &mut RawRef { unsafe { - (self as *mut ArrayRef) + (&mut self.layout as *mut LayoutRef) .cast::>() .as_mut() } @@ -117,37 +156,113 @@ impl DerefMut for ArrayRef } } -impl AsRef> for LayoutRef +// A3: &ArrayBase -AR-> &LayoutRef +impl AsRef> for ArrayBase +where S: RawData { fn as_ref(&self) -> &LayoutRef { - self + &self.layout } } -impl AsMut> for LayoutRef +// A3: &mut ArrayBase -AM-> &mut LayoutRef +impl AsMut> for ArrayBase +where S: RawData { fn as_mut(&mut self) -> &mut LayoutRef + { + &mut self.layout + } +} + +// A4: &ArrayRef -AR-> &RawRef +impl AsRef> for ArrayRef +{ + fn as_ref(&self) -> &RawRef + { + &**self + } +} + +// A4: &mut ArrayRef -AM-> &mut RawRef +impl AsMut> for ArrayRef +{ + fn as_mut(&mut self) -> &mut RawRef + { + &mut **self + } +} + +// A4: &ArrayRef -AR-> &LayoutRef +impl AsRef> for ArrayRef +{ + fn as_ref(&self) -> &LayoutRef + { + &***self + } +} + +// A4: &mut ArrayRef -AM-> &mut LayoutRef +impl AsMut> for ArrayRef +{ + fn as_mut(&mut self) -> &mut LayoutRef + { + &mut ***self + } +} + +// A5: &RawRef -AR-> &LayoutRef +impl AsRef> for RawRef +{ + fn as_ref(&self) -> &LayoutRef + { + &**self + } +} + +// A5: &mut RawRef -AM-> &mut LayoutRef +impl AsMut> for RawRef +{ + fn as_mut(&mut self) -> &mut LayoutRef + { + &mut **self + } +} + +// A6: &RawRef -AR-> &RawRef +impl AsRef> for RawRef +{ + fn as_ref(&self) -> &RawRef { self } } -impl Deref for RawRef +// A6: &mut RawRef -AM-> &mut RawRef +impl AsMut> for RawRef { - type Target = LayoutRef; + fn as_mut(&mut self) -> &mut RawRef + { + self + } +} - fn deref(&self) -> &Self::Target +// A6: &LayoutRef -AR-> &LayoutRef +impl AsRef> for LayoutRef +{ + fn as_ref(&self) -> &LayoutRef { - &self.0 + self } } -impl DerefMut for RawRef +// A6: &mut LayoutRef -AR-> &mut LayoutRef +impl AsMut> for LayoutRef { - fn deref_mut(&mut self) -> &mut Self::Target + fn as_mut(&mut self) -> &mut LayoutRef { - &mut self.0 + self } } diff --git a/src/iterators/chunks.rs b/src/iterators/chunks.rs index 909377d5e..be6a763a7 100644 --- a/src/iterators/chunks.rs +++ b/src/iterators/chunks.rs @@ -49,16 +49,16 @@ impl<'a, A, D: Dimension> ExactChunks<'a, A, D> let mut a = a.into_raw_view(); let chunk = chunk.into_dimension(); ndassert!( - AsRef::as_ref(&a).ndim() == chunk.ndim(), + a.ndim() == chunk.ndim(), concat!( "Chunk dimension {} does not match array dimension {} ", "(with array of shape {:?})" ), chunk.ndim(), - AsRef::as_ref(&a).ndim(), - AsRef::as_ref(&a).shape() + a.ndim(), + a.shape() ); - for i in 0..AsRef::as_ref(&a).ndim() { + for i in 0..a.ndim() { a.layout.dim[i] /= chunk[i]; } let inner_strides = a.layout.strides.clone(); @@ -148,16 +148,16 @@ impl<'a, A, D: Dimension> ExactChunksMut<'a, A, D> let mut a = a.into_raw_view_mut(); let chunk = chunk.into_dimension(); ndassert!( - AsRef::as_ref(&a).ndim() == chunk.ndim(), + a.ndim() == chunk.ndim(), concat!( "Chunk dimension {} does not match array dimension {} ", "(with array of shape {:?})" ), chunk.ndim(), - AsRef::as_ref(&a).ndim(), - AsRef::as_ref(&a).shape() + a.ndim(), + a.shape() ); - for i in 0..AsRef::as_ref(&a).ndim() { + for i in 0..a.ndim() { a.layout.dim[i] /= chunk[i]; } let inner_strides = a.layout.strides.clone(); diff --git a/src/lib.rs b/src/lib.rs index 7183c096f..bbf88bf2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1557,7 +1557,7 @@ mod impl_internal_constructors; mod impl_constructors; mod impl_methods; -mod alias_slicing; +mod alias_asref; mod impl_owned_array; mod impl_special_element_types; diff --git a/src/linalg/impl_linalg.rs b/src/linalg/impl_linalg.rs index 32112c896..04584ed0f 100644 --- a/src/linalg/impl_linalg.rs +++ b/src/linalg/impl_linalg.rs @@ -668,7 +668,7 @@ unsafe fn general_mat_vec_mul_impl( ) where A: LinalgScalar { let ((m, k), k2) = (a.dim(), x.dim()); - let m2 = y.as_ref().dim(); + let m2 = y.dim(); if k != k2 || m != m2 { general_dot_shape_error(m, k, k2, 1, m2, 1); } else { @@ -790,7 +790,7 @@ fn complex_array(z: Complex) -> [A; 2] } #[cfg(feature = "blas")] -fn blas_compat_1d(a: &LayoutRef) -> bool +fn blas_compat_1d(a: &RawRef) -> bool where A: 'static, B: 'static, diff --git a/src/zip/mod.rs b/src/zip/mod.rs index df043b3ec..640a74d1b 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -18,7 +18,6 @@ use crate::partial::Partial; use crate::AssignElem; use crate::IntoDimension; use crate::Layout; -use crate::LayoutRef; use crate::dimension; use crate::indexes::{indices, Indices}; diff --git a/src/zip/ndproducer.rs b/src/zip/ndproducer.rs index 91fb8602a..82f3f43a7 100644 --- a/src/zip/ndproducer.rs +++ b/src/zip/ndproducer.rs @@ -380,7 +380,7 @@ impl NdProducer for RawArrayView fn raw_dim(&self) -> Self::Dim { - AsRef::as_ref(self).raw_dim() + self.raw_dim() } fn equal_dim(&self, dim: &Self::Dim) -> bool @@ -390,12 +390,12 @@ impl NdProducer for RawArrayView fn as_ptr(&self) -> *const A { - AsRef::as_ref(self).as_ptr() as _ + self.as_ptr() as _ } fn layout(&self) -> Layout { - AsRef::as_ref(self).layout_impl() + AsRef::>::as_ref(self).layout_impl() } unsafe fn as_ref(&self, ptr: *const A) -> *const A @@ -413,7 +413,7 @@ impl NdProducer for RawArrayView fn stride_of(&self, axis: Axis) -> isize { - AsRef::as_ref(self).stride_of(axis) + self.stride_of(axis) } #[inline(always)] @@ -439,7 +439,7 @@ impl NdProducer for RawArrayViewMut fn raw_dim(&self) -> Self::Dim { - AsRef::as_ref(self).raw_dim() + self.raw_dim() } fn equal_dim(&self, dim: &Self::Dim) -> bool @@ -449,12 +449,12 @@ impl NdProducer for RawArrayViewMut fn as_ptr(&self) -> *mut A { - AsRef::as_ref(self).as_ptr() as _ + self.as_ptr() as _ } fn layout(&self) -> Layout { - AsRef::as_ref(self).layout_impl() + AsRef::>::as_ref(self).layout_impl() } unsafe fn as_ref(&self, ptr: *mut A) -> *mut A @@ -472,7 +472,7 @@ impl NdProducer for RawArrayViewMut fn stride_of(&self, axis: Axis) -> isize { - AsRef::as_ref(self).stride_of(axis) + self.stride_of(axis) } #[inline(always)] diff --git a/tests/raw_views.rs b/tests/raw_views.rs index be20aff52..929e969d7 100644 --- a/tests/raw_views.rs +++ b/tests/raw_views.rs @@ -39,8 +39,8 @@ fn raw_view_cast_zst() let a = Array::<(), _>::default((250, 250)); let b: RawArrayView = a.raw_view().cast::(); - assert_eq!(a.shape(), b.as_ref().shape()); - assert_eq!(a.as_ptr() as *const u8, b.as_ref().as_ptr() as *const u8); + assert_eq!(a.shape(), b.shape()); + assert_eq!(a.as_ptr() as *const u8, b.as_ptr() as *const u8); } #[test] diff --git a/tests/test_ref_structure.rs b/tests/test_ref_structure.rs deleted file mode 100644 index 6778097a9..000000000 --- a/tests/test_ref_structure.rs +++ /dev/null @@ -1,39 +0,0 @@ -use ndarray::{array, ArrayBase, ArrayRef, Data, LayoutRef, RawData, RawRef}; - -fn takes_base_raw(arr: &ArrayBase) -{ - takes_rawref(arr.as_ref()); // Doesn't work - takes_layout(arr.as_ref()); -} - -#[allow(dead_code)] -fn takes_base(arr: &ArrayBase) -{ - takes_base_raw(arr); - takes_arrref(arr); // Doesn't work - takes_rawref(arr); // Doesn't work - takes_layout(arr); -} - -fn takes_arrref(_arr: &ArrayRef) -{ - takes_rawref(_arr); - takes_layout(_arr); -} - -fn takes_rawref(_arr: &RawRef) -{ - takes_layout(_arr); -} - -fn takes_layout(_arr: &LayoutRef) {} - -#[test] -fn tester() -{ - let arr = array![1, 2, 3]; - takes_base_raw(&arr); - takes_arrref(&arr); - takes_rawref(&arr); // Doesn't work - takes_layout(&arr); -} From 663e2f9d3e6408368c9b1595a00f2e45e511230d Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Mon, 14 Oct 2024 18:21:52 -0400 Subject: [PATCH 17/33] Adds Borrow and ToOwned --- src/impl_ref_types.rs | 71 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/src/impl_ref_types.rs b/src/impl_ref_types.rs index 92e916887..6907ddcd8 100644 --- a/src/impl_ref_types.rs +++ b/src/impl_ref_types.rs @@ -21,17 +21,20 @@ //! To mitigate these problems, `ndarray` also provides `AsRef` and `AsMut` implementations as follows: //! 1. `ArrayBase` implements `AsRef` to `RawRef` and `LayoutRef` when `S: RawData` //! 2. `ArrayBase` implements `AsMut` to `RawRef` when `S: RawDataMut` -//! 3. `ArrayBase` implements `AsMut` to `LayoutRef` unconditionally -//! 4. `ArrayRef` implements `AsMut` to `RawRef` and `LayoutRef` unconditionally -//! 5. `RawRef` implements `AsMut` to `LayoutRef` -//! 6. `RawRef` and `LayoutRef` implement `AsMut` to themselves +//! 3. `ArrayBase` implements `AsRef` and `AsMut` to `LayoutRef` unconditionally +//! 4. `ArrayRef` implements `AsRef` and `AsMut` to `RawRef` and `LayoutRef` unconditionally +//! 5. `RawRef` implements `AsRef` and `AsMut` to `LayoutRef` +//! 6. `RawRef` and `LayoutRef` implement `AsRef` and `AsMut` to themselves //! //! This allows users to write a single method or trait implementation that takes `T: AsRef>` //! or `T: AsRef>` and have that functionality work on any of the relevant array types. -use core::ops::{Deref, DerefMut}; +use core::{ + borrow::{Borrow, BorrowMut}, + ops::{Deref, DerefMut}, +}; -use crate::{ArrayBase, ArrayRef, Data, DataMut, Dimension, LayoutRef, RawData, RawDataMut, RawRef}; +use crate::{Array, ArrayBase, ArrayRef, Data, DataMut, Dimension, LayoutRef, RawData, RawDataMut, RawRef}; // D1: &ArrayBase -> &ArrayRef when data is safe to read impl Deref for ArrayBase @@ -286,3 +289,59 @@ impl Clone for LayoutRef } impl Copy for LayoutRef {} + +impl Borrow> for ArrayBase +where S: RawData +{ + fn borrow(&self) -> &RawRef + { + self.as_ref() + } +} + +impl BorrowMut> for ArrayBase +where S: RawDataMut +{ + fn borrow_mut(&mut self) -> &mut RawRef + { + self.as_mut() + } +} + +impl Borrow> for ArrayBase +where S: Data +{ + fn borrow(&self) -> &ArrayRef + { + &**self + } +} + +impl BorrowMut> for ArrayBase +where + S: DataMut, + D: Dimension, +{ + fn borrow_mut(&mut self) -> &mut ArrayRef + { + &mut **self + } +} + +impl ToOwned for ArrayRef +where + A: Clone, + D: Dimension, +{ + type Owned = Array; + + fn to_owned(&self) -> Self::Owned + { + self.to_owned() + } + + fn clone_into(&self, target: &mut Array) + { + target.zip_mut_with(self, |tgt, src| tgt.clone_from(src)); + } +} From 5204f6837d1b8b795ab6c905c9bc301f3b2f5964 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Mon, 14 Oct 2024 18:24:38 -0400 Subject: [PATCH 18/33] Tests that the *Assign operators work for slices via deref --- tests/array.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/array.rs b/tests/array.rs index 696904dab..9b4e4cc90 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -2819,3 +2819,11 @@ fn test_split_complex_invert_axis() assert_eq!(cmplx.re, a.mapv(|z| z.re)); assert_eq!(cmplx.im, a.mapv(|z| z.im)); } + +#[test] +fn test_slice_assing() +{ + let mut a = array![0, 1, 2, 3, 4]; + *a.slice_mut(s![1..3]) += 1; + assert_eq!(a, array![0, 2, 3, 3, 4]); +} From 6a3d1313b73be9be1b5772983db20401ad09a04d Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Mon, 14 Oct 2024 18:31:25 -0400 Subject: [PATCH 19/33] Somehow missed a `use` for `ToOwned` --- src/impl_ref_types.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/impl_ref_types.rs b/src/impl_ref_types.rs index 6907ddcd8..7489f82e3 100644 --- a/src/impl_ref_types.rs +++ b/src/impl_ref_types.rs @@ -29,6 +29,7 @@ //! This allows users to write a single method or trait implementation that takes `T: AsRef>` //! or `T: AsRef>` and have that functionality work on any of the relevant array types. +use alloc::borrow::ToOwned; use core::{ borrow::{Borrow, BorrowMut}, ops::{Deref, DerefMut}, From 289130d6006a4af0fae0c0a7ff2cdebb5960b22b Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Mon, 14 Oct 2024 18:36:10 -0400 Subject: [PATCH 20/33] Implicitly use deref --- src/impl_ref_types.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/impl_ref_types.rs b/src/impl_ref_types.rs index 7489f82e3..8ae3c90f9 100644 --- a/src/impl_ref_types.rs +++ b/src/impl_ref_types.rs @@ -185,7 +185,7 @@ impl AsRef> for ArrayRef { fn as_ref(&self) -> &RawRef { - &**self + self } } @@ -194,7 +194,7 @@ impl AsMut> for ArrayRef { fn as_mut(&mut self) -> &mut RawRef { - &mut **self + self } } @@ -203,7 +203,7 @@ impl AsRef> for ArrayRef { fn as_ref(&self) -> &LayoutRef { - &***self + self } } @@ -212,7 +212,7 @@ impl AsMut> for ArrayRef { fn as_mut(&mut self) -> &mut LayoutRef { - &mut ***self + self } } @@ -221,7 +221,7 @@ impl AsRef> for RawRef { fn as_ref(&self) -> &LayoutRef { - &**self + self } } @@ -230,7 +230,7 @@ impl AsMut> for RawRef { fn as_mut(&mut self) -> &mut LayoutRef { - &mut **self + self } } @@ -314,7 +314,7 @@ where S: Data { fn borrow(&self) -> &ArrayRef { - &**self + self } } @@ -325,7 +325,7 @@ where { fn borrow_mut(&mut self) -> &mut ArrayRef { - &mut **self + self } } From db52eabc4226638086f7bed16b0057a1161f7be6 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 20 Oct 2024 00:06:18 -0400 Subject: [PATCH 21/33] Adds documentation and aliases for `LayoutRef` --- src/aliases.rs | 19 ++++++++++- src/lib.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/src/aliases.rs b/src/aliases.rs index aef0452f3..7f897304b 100644 --- a/src/aliases.rs +++ b/src/aliases.rs @@ -2,7 +2,7 @@ //! use crate::dimension::Dim; -use crate::{ArcArray, Array, ArrayRef, ArrayView, ArrayViewMut, Ix, IxDynImpl}; +use crate::{ArcArray, Array, ArrayRef, ArrayView, ArrayViewMut, Ix, IxDynImpl, LayoutRef}; /// Create a zero-dimensional index #[allow(non_snake_case)] @@ -140,6 +140,23 @@ pub type ArrayRef6 = ArrayRef; /// dynamic-dimensional array reference pub type ArrayRefD = ArrayRef; +/// zero-dimensional layout reference +pub type LayoutRef0 = LayoutRef; +/// one-dimensional layout reference +pub type LayoutRef1 = LayoutRef; +/// two-dimensional layout reference +pub type LayoutRef2 = LayoutRef; +/// three-dimensional layout reference +pub type LayoutRef3 = LayoutRef; +/// four-dimensional layout reference +pub type LayoutRef4 = LayoutRef; +/// five-dimensional layout reference +pub type LayoutRef5 = LayoutRef; +/// six-dimensional layout reference +pub type LayoutRef6 = LayoutRef; +/// dynamic-dimensional layout reference +pub type LayoutRefD = LayoutRef; + /// zero-dimensional array view pub type ArrayView0<'a, A> = ArrayView<'a, A, Ix0>; /// one-dimensional array view diff --git a/src/lib.rs b/src/lib.rs index bbf88bf2c..a67e3930d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1292,6 +1292,92 @@ where S: RawData } /// A reference to the layout of an *n*-dimensional array. +/// +/// This type can be used to read and write to the layout of an array; +/// that is to say, its shape and strides. It does not provide any read +/// or write access to the array's underlying data. It is generic on two +/// types: `D`, its dimensionality, and `A`, the element type of its data. +/// +/// ## Example +/// Say we wanted to write a function that provides the aspect ratio +/// of any 2D array: the ratio of its width (number of columns) to its +/// height (number of rows). We would write that as follows: +/// ```rust +/// use ndarray::{LayoutRef2, array}; +/// +/// fn aspect_ratio(layout: &T) -> (usize, usize) +/// where T: AsRef> +/// { +/// let layout = layout.as_ref(); +/// (layout.ncols(), layout.nrows()) +/// } +/// +/// let arr = array![[1, 2], [3, 4]]; +/// assert_eq!(aspect_ratio(&arr), (2, 2)); +/// ``` +/// Similarly, new traits that provide functions that only depend on +/// or alter the layout of an array should do so via a blanket +/// implementation. Lets write a trait that both provides the aspect ratio +/// and lets users cut down arrays to a desired aspect ratio. +/// For simplicity, we'll panic if the user provides an aspect ratio +/// where either element is larger than the array's size. +/// ```rust +/// use ndarray::{LayoutRef2, array, s}; +/// +/// trait Ratioable { +/// fn aspect_ratio(&self) -> (usize, usize) +/// where Self: AsRef>; +/// +/// fn cut_to_ratio(&mut self, ratio: (usize, usize)) +/// where Self: AsMut>; +/// } +/// +/// impl Ratioable for T +/// where T: AsRef> + AsMut> +/// { +/// fn aspect_ratio(&self) -> (usize, usize) +/// { +/// let layout = self.as_ref(); +/// (layout.ncols(), layout.nrows()) +/// } +/// +/// fn cut_to_ratio(&mut self, ratio: (usize, usize)) +/// { +/// let layout = self.as_mut(); +/// layout.slice_collapse(s![..ratio.1, ..ratio.0]); +/// } +/// } +/// +/// let mut arr = array![[1, 2, 3], [4, 5, 6]]; +/// assert_eq!(arr.aspect_ratio(), (3, 2)); +/// arr.cut_to_ratio((2, 2)); +/// assert_eq!(arr, array![[1, 2], [4, 5]]); +/// ``` +/// Continue reading for why we use `AsRef` instead of taking `&LayoutRef` directly. +/// +/// ## Writing Functions +/// Writing functions that accept `LayoutRef` is not as simple as taking +/// a `&LayoutRef` argument, as the above examples show. This is because +/// `LayoutRef` can be obtained either cheaply or expensively, depending +/// on the method used. `LayoutRef` can be obtained from all kinds of arrays +/// -- [owned](Array), [shared](ArcArray), [viewed](ArrayView), [referenced](ArrayRef), +/// and [raw referenced](RawRef) -- via `.as_ref()`. Critically, this way of +/// obtaining a `LayoutRef` is cheap, as it does not guarantee that the +/// underlying data is uniquely held. +/// +/// However, `LayoutRef`s can be obtained a second way: they sit at the bottom +/// of a "deref chain" going from shared arrays, through `ArrayRef`, through +/// `RawRef`, and finally to `LayoutRef`. As a result, `LayoutRef`s can also +/// be obtained via auto-dereferencing. When requesting a mutable reference -- +/// `&mut LayoutRef` -- the `deref_mut` to `ArrayRef` triggers a (possibly +/// expensive) guarantee that the data is uniquely held (see [`ArrayRef`] +/// for more information). +/// +/// To help users avoid this error cost, functions that operate on `LayoutRef`s +/// should take their parameters as a generic type `T: AsRef>`, +/// as the above examples show. This aids the caller in two ways: they can pass +/// their arrays by reference (`&arr`) instead of explicitly calling `as_ref`, +/// and they will avoid paying a performance penalty for mutating the shape. // // # Safety for Implementors // From 2b34bf88cd2f13506b1e82cf14e921e16504b1a0 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 20 Oct 2024 01:12:31 -0400 Subject: [PATCH 22/33] Fixes doc links --- src/alias_asref.rs | 2 +- src/doc/ndarray_for_numpy_users/mod.rs | 97 +++++++++++----------- src/doc/ndarray_for_numpy_users/rk_step.rs | 2 +- src/impl_methods.rs | 16 ++-- src/impl_views/conversions.rs | 4 +- src/impl_views/indexing.rs | 20 ++--- src/impl_views/splitting.rs | 2 +- src/iterators/chunks.rs | 8 +- src/iterators/lanes.rs | 4 +- src/iterators/mod.rs | 24 +++--- src/iterators/windows.rs | 6 +- src/lib.rs | 72 ++++++++-------- src/math_cell.rs | 2 +- src/parallel/mod.rs | 4 +- src/shape_builder.rs | 2 +- src/slice.rs | 12 +-- src/tri.rs | 4 +- 17 files changed, 142 insertions(+), 139 deletions(-) diff --git a/src/alias_asref.rs b/src/alias_asref.rs index 60435177c..f2e2133a9 100644 --- a/src/alias_asref.rs +++ b/src/alias_asref.rs @@ -31,7 +31,7 @@ impl ArrayBase /// /// - if an index is out of bounds /// - if a step size is zero - /// - if [`SliceInfoElem::NewAxis`] is in `info`, e.g. if [`NewAxis`] was + /// - if [`NewAxis`](`crate::SliceInfoElem::NewAxis`) is in `info`, e.g. if `NewAxis` was /// used in the [`s!`] macro /// - if `D` is `IxDyn` and `info` does not match the number of array axes #[track_caller] diff --git a/src/doc/ndarray_for_numpy_users/mod.rs b/src/doc/ndarray_for_numpy_users/mod.rs index eba96cdd0..bb6b7ae83 100644 --- a/src/doc/ndarray_for_numpy_users/mod.rs +++ b/src/doc/ndarray_for_numpy_users/mod.rs @@ -322,7 +322,7 @@ //! //! //! -//! [`mat1.dot(&mat2)`][matrix-* dot] +//! [`mat1.dot(&mat2)`][dot-2-2] //! //! //! @@ -336,7 +336,7 @@ //! //! //! -//! [`mat.dot(&vec)`][matrix-* dot] +//! [`mat.dot(&vec)`][dot-2-1] //! //! //! @@ -350,7 +350,7 @@ //! //! //! -//! [`vec.dot(&mat)`][vec-* dot] +//! [`vec.dot(&mat)`][dot-1-2] //! //! //! @@ -364,7 +364,7 @@ //! //! //! -//! [`vec1.dot(&vec2)`][vec-* dot] +//! [`vec1.dot(&vec2)`][dot-1-1] //! //! //! @@ -670,22 +670,22 @@ //! `a[:,4]` | [`a.column(4)`][.column()] or [`a.column_mut(4)`][.column_mut()] | view (or mutable view) of column 4 in a 2-D array //! `a.shape[0] == a.shape[1]` | [`a.is_square()`][.is_square()] | check if the array is square //! -//! [.abs_diff_eq()]: ArrayBase#impl-AbsDiffEq> -//! [.assign()]: ArrayBase::assign -//! [.axis_iter()]: ArrayBase::axis_iter -//! [.ncols()]: ArrayBase::ncols -//! [.column()]: ArrayBase::column -//! [.column_mut()]: ArrayBase::column_mut +//! [.abs_diff_eq()]: ArrayRef#impl-AbsDiffEq%3CArrayRef%3CB,+D%3E%3E +//! [.assign()]: ArrayRef::assign +//! [.axis_iter()]: ArrayRef::axis_iter +//! [.ncols()]: LayoutRef::ncols +//! [.column()]: ArrayRef::column +//! [.column_mut()]: ArrayRef::column_mut //! [concatenate()]: crate::concatenate() //! [concatenate!]: crate::concatenate! //! [stack!]: crate::stack! //! [::default()]: ArrayBase::default -//! [.diag()]: ArrayBase::diag -//! [.dim()]: ArrayBase::dim +//! [.diag()]: ArrayRef::diag +//! [.dim()]: LayoutRef::dim //! [::eye()]: ArrayBase::eye -//! [.fill()]: ArrayBase::fill -//! [.fold()]: ArrayBase::fold -//! [.fold_axis()]: ArrayBase::fold_axis +//! [.fill()]: ArrayRef::fill +//! [.fold()]: ArrayRef::fold +//! [.fold_axis()]: ArrayRef::fold_axis //! [::from_elem()]: ArrayBase::from_elem //! [::from_iter()]: ArrayBase::from_iter //! [::from_diag()]: ArrayBase::from_diag @@ -694,48 +694,51 @@ //! [::from_shape_vec_unchecked()]: ArrayBase::from_shape_vec_unchecked //! [::from_vec()]: ArrayBase::from_vec //! [.index()]: ArrayBase#impl-Index -//! [.indexed_iter()]: ArrayBase::indexed_iter +//! [.indexed_iter()]: ArrayRef::indexed_iter //! [.insert_axis()]: ArrayBase::insert_axis -//! [.is_empty()]: ArrayBase::is_empty -//! [.is_square()]: ArrayBase::is_square -//! [.iter()]: ArrayBase::iter -//! [.len()]: ArrayBase::len -//! [.len_of()]: ArrayBase::len_of +//! [.is_empty()]: LayoutRef::is_empty +//! [.is_square()]: LayoutRef::is_square +//! [.iter()]: ArrayRef::iter +//! [.len()]: LayoutRef::len +//! [.len_of()]: LayoutRef::len_of //! [::linspace()]: ArrayBase::linspace //! [::logspace()]: ArrayBase::logspace //! [::geomspace()]: ArrayBase::geomspace -//! [.map()]: ArrayBase::map -//! [.map_axis()]: ArrayBase::map_axis -//! [.map_inplace()]: ArrayBase::map_inplace -//! [.mapv()]: ArrayBase::mapv -//! [.mapv_inplace()]: ArrayBase::mapv_inplace +//! [.map()]: ArrayRef::map +//! [.map_axis()]: ArrayRef::map_axis +//! [.map_inplace()]: ArrayRef::map_inplace +//! [.mapv()]: ArrayRef::mapv +//! [.mapv_inplace()]: ArrayRef::mapv_inplace //! [.mapv_into()]: ArrayBase::mapv_into -//! [matrix-* dot]: ArrayBase::dot-1 -//! [.mean()]: ArrayBase::mean -//! [.mean_axis()]: ArrayBase::mean_axis -//! [.ndim()]: ArrayBase::ndim +//! [dot-2-2]: ArrayRef#impl-Dot>>-for-ArrayRef> +//! [dot-1-1]: ArrayRef#impl-Dot>>-for-ArrayRef> +//! [dot-1-2]: ArrayRef#impl-Dot>>-for-ArrayRef> +//! [dot-2-1]: ArrayRef#impl-Dot>>-for-ArrayRef> +//! [.mean()]: ArrayRef::mean +//! [.mean_axis()]: ArrayRef::mean_axis +//! [.ndim()]: LayoutRef::ndim //! [::ones()]: ArrayBase::ones -//! [.outer_iter()]: ArrayBase::outer_iter +//! [.outer_iter()]: ArrayRef::outer_iter //! [::range()]: ArrayBase::range -//! [.raw_dim()]: ArrayBase::raw_dim +//! [.raw_dim()]: LayoutRef::raw_dim //! [.reversed_axes()]: ArrayBase::reversed_axes -//! [.row()]: ArrayBase::row -//! [.row_mut()]: ArrayBase::row_mut -//! [.nrows()]: ArrayBase::nrows -//! [.sum()]: ArrayBase::sum -//! [.slice()]: ArrayBase::slice -//! [.slice_axis()]: ArrayBase::slice_axis -//! [.slice_collapse()]: ArrayBase::slice_collapse +//! [.row()]: ArrayRef::row +//! [.row_mut()]: ArrayRef::row_mut +//! [.nrows()]: LayoutRef::nrows +//! [.sum()]: ArrayRef::sum +//! [.slice()]: ArrayRef::slice +//! [.slice_axis()]: ArrayRef::slice_axis +//! [.slice_collapse()]: LayoutRef::slice_collapse //! [.slice_move()]: ArrayBase::slice_move -//! [.slice_mut()]: ArrayBase::slice_mut -//! [.shape()]: ArrayBase::shape +//! [.slice_mut()]: ArrayRef::slice_mut +//! [.shape()]: LayoutRef::shape //! [stack()]: crate::stack() -//! [.strides()]: ArrayBase::strides -//! [.index_axis()]: ArrayBase::index_axis -//! [.sum_axis()]: ArrayBase::sum_axis -//! [.t()]: ArrayBase::t -//! [vec-* dot]: ArrayBase::dot -//! [.for_each()]: ArrayBase::for_each +//! [.strides()]: LayoutRef::strides +//! [.index_axis()]: ArrayRef::index_axis +//! [.sum_axis()]: ArrayRef::sum_axis +//! [.t()]: ArrayRef::t +//! [vec-* dot]: ArrayRef::dot +//! [.for_each()]: ArrayRef::for_each //! [::zeros()]: ArrayBase::zeros //! [`Zip`]: crate::Zip diff --git a/src/doc/ndarray_for_numpy_users/rk_step.rs b/src/doc/ndarray_for_numpy_users/rk_step.rs index c882a3d00..820c71d9c 100644 --- a/src/doc/ndarray_for_numpy_users/rk_step.rs +++ b/src/doc/ndarray_for_numpy_users/rk_step.rs @@ -122,7 +122,7 @@ //! //! * Use [`c.mul_add(h, t)`](f64::mul_add) instead of `t + c * h`. This is //! faster and reduces the floating-point error. It might also be beneficial -//! to use [`.scaled_add()`] or a combination of +//! to use [`.scaled_add()`](crate::ArrayRef::scaled_add) or a combination of //! [`azip!()`] and [`.mul_add()`](f64::mul_add) on the arrays in //! some places, but that's not demonstrated in the example below. //! diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 3a6c53265..97808884b 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -253,7 +253,7 @@ where /// If the input array is contiguous, then the output array will have the same /// memory layout. Otherwise, the layout of the output array is unspecified. /// If you need a particular layout, you can allocate a new array with the - /// desired memory layout and [`.assign()`](Self::assign) the data. + /// desired memory layout and [`.assign()`](ArrayRef::assign) the data. /// Alternatively, you can collectan iterator, like this for a result in /// standard layout: /// @@ -630,9 +630,9 @@ impl LayoutRef /// collapsed, as in [`.collapse_axis()`], rather than removed, as in /// [`.slice_move()`] or [`.index_axis_move()`]. /// - /// [`.collapse_axis()`]: Self::collapse_axis - /// [`.slice_move()`]: Self::slice_move - /// [`.index_axis_move()`]: Self::index_axis_move + /// [`.collapse_axis()`]: LayoutRef::collapse_axis + /// [`.slice_move()`]: ArrayBase::slice_move + /// [`.index_axis_move()`]: ArrayBase::index_axis_move /// /// See [*Slicing*](#slicing) for full documentation. /// See also [`s!`], [`SliceArg`], and [`SliceInfo`](crate::SliceInfo). @@ -1056,7 +1056,7 @@ where { /// Collapses the array to `index` along the axis and removes the axis. /// - /// See [`.index_axis()`](Self::index_axis) and [*Subviews*](#subviews) for full documentation. + /// See [`.index_axis()`](ArrayRef::index_axis) and [*Subviews*](#subviews) for full documentation. /// /// **Panics** if `axis` or `index` is out of bounds. #[track_caller] @@ -1468,13 +1468,13 @@ impl ArrayRef /// `window_size`. /// /// Note that passing a stride of only ones is similar to - /// calling [`ArrayBase::windows()`]. + /// calling [`ArrayRef::windows()`]. /// /// **Panics** if any dimension of `window_size` or `stride` is zero.
/// (**Panics** if `D` is `IxDyn` and `window_size` or `stride` does not match the /// number of array axes.) /// - /// This is the same illustration found in [`ArrayBase::windows()`], + /// This is the same illustration found in [`ArrayRef::windows()`], /// 2×2 windows in a 3×4 array, but now with a (1, 2) stride: /// /// ```text @@ -2943,7 +2943,7 @@ where /// Elements are visited in arbitrary order. /// /// [`mapv_into`]: ArrayBase::mapv_into - /// [`mapv`]: ArrayBase::mapv + /// [`mapv`]: ArrayRef::mapv pub fn mapv_into_any(self, mut f: F) -> Array where S: DataMut, diff --git a/src/impl_views/conversions.rs b/src/impl_views/conversions.rs index ce852da5e..efd876f7a 100644 --- a/src/impl_views/conversions.rs +++ b/src/impl_views/conversions.rs @@ -35,7 +35,7 @@ where D: Dimension /// Return the array’s data as a slice, if it is contiguous and in standard order. /// Return `None` otherwise. /// - /// Note that while the method is similar to [`ArrayBase::as_slice()`], this method transfers + /// Note that while the method is similar to [`ArrayRef::as_slice()`], this method transfers /// the view's lifetime to the slice, so it is a bit more powerful. pub fn to_slice(&self) -> Option<&'a [A]> { @@ -50,7 +50,7 @@ where D: Dimension /// Return `None` otherwise. /// /// Note that while the method is similar to - /// [`ArrayBase::as_slice_memory_order()`], this method transfers the view's + /// [`ArrayRef::as_slice_memory_order()`], this method transfers the view's /// lifetime to the slice, so it is a bit more powerful. pub fn to_slice_memory_order(&self) -> Option<&'a [A]> { diff --git a/src/impl_views/indexing.rs b/src/impl_views/indexing.rs index 2b72c2142..12a47e46a 100644 --- a/src/impl_views/indexing.rs +++ b/src/impl_views/indexing.rs @@ -60,7 +60,7 @@ pub trait IndexLonger /// See also [the `get` method][1] which works for all arrays and array /// views. /// - /// [1]: ArrayBase::get + /// [1]: ArrayRef::get /// /// **Panics** if index is out of bounds. #[track_caller] @@ -68,15 +68,15 @@ pub trait IndexLonger /// Get a reference of a element through the view. /// - /// This method is like `ArrayBase::get` but with a longer lifetime (matching + /// This method is like `ArrayRef::get` but with a longer lifetime (matching /// the array view); which we can only do for the array view and not in the /// `Index` trait. /// /// See also [the `get` method][1] (and [`get_mut`][2]) which works for all arrays and array /// views. /// - /// [1]: ArrayBase::get - /// [2]: ArrayBase::get_mut + /// [1]: ArrayRef::get + /// [2]: ArrayRef::get_mut /// /// **Panics** if index is out of bounds. #[track_caller] @@ -90,7 +90,7 @@ pub trait IndexLonger /// See also [the `uget` method][1] which works for all arrays and array /// views. /// - /// [1]: ArrayBase::uget + /// [1]: ArrayRef::uget /// /// **Note:** only unchecked for non-debug builds of ndarray. /// @@ -116,7 +116,7 @@ where /// See also [the `get` method][1] which works for all arrays and array /// views. /// - /// [1]: ArrayBase::get + /// [1]: ArrayRef::get /// /// **Panics** if index is out of bounds. #[track_caller] @@ -139,7 +139,7 @@ where /// See also [the `uget` method][1] which works for all arrays and array /// views. /// - /// [1]: ArrayBase::uget + /// [1]: ArrayRef::uget /// /// **Note:** only unchecked for non-debug builds of ndarray. unsafe fn uget(self, index: I) -> &'a A @@ -165,7 +165,7 @@ where /// See also [the `get_mut` method][1] which works for all arrays and array /// views. /// - /// [1]: ArrayBase::get_mut + /// [1]: ArrayRef::get_mut /// /// **Panics** if index is out of bounds. #[track_caller] @@ -186,7 +186,7 @@ where /// See also [the `get_mut` method][1] which works for all arrays and array /// views. /// - /// [1]: ArrayBase::get_mut + /// [1]: ArrayRef::get_mut /// fn get(mut self, index: I) -> Option<&'a mut A> { @@ -205,7 +205,7 @@ where /// See also [the `uget_mut` method][1] which works for all arrays and array /// views. /// - /// [1]: ArrayBase::uget_mut + /// [1]: ArrayRef::uget_mut /// /// **Note:** only unchecked for non-debug builds of ndarray. unsafe fn uget(mut self, index: I) -> &'a mut A diff --git a/src/impl_views/splitting.rs b/src/impl_views/splitting.rs index 6d6ea275b..d4ccb9552 100644 --- a/src/impl_views/splitting.rs +++ b/src/impl_views/splitting.rs @@ -157,7 +157,7 @@ where D: Dimension /// [`MultiSliceArg`], [`s!`], [`SliceArg`](crate::SliceArg), and /// [`SliceInfo`](crate::SliceInfo). /// - /// [`.multi_slice_mut()`]: ArrayBase::multi_slice_mut + /// [`.multi_slice_mut()`]: ArrayRef::multi_slice_mut /// /// **Panics** if any of the following occur: /// diff --git a/src/iterators/chunks.rs b/src/iterators/chunks.rs index be6a763a7..4dd99f002 100644 --- a/src/iterators/chunks.rs +++ b/src/iterators/chunks.rs @@ -27,7 +27,7 @@ impl_ndproducer! { /// Exact chunks producer and iterable. /// -/// See [`.exact_chunks()`](ArrayBase::exact_chunks) for more +/// See [`.exact_chunks()`](crate::ArrayRef::exact_chunks) for more /// information. //#[derive(Debug)] pub struct ExactChunks<'a, A, D> @@ -93,7 +93,7 @@ where /// Exact chunks iterator. /// -/// See [`.exact_chunks()`](ArrayBase::exact_chunks) for more +/// See [`.exact_chunks()`](crate::ArrayRef::exact_chunks) for more /// information. pub struct ExactChunksIter<'a, A, D> { @@ -126,7 +126,7 @@ impl_ndproducer! { /// Exact chunks producer and iterable. /// -/// See [`.exact_chunks_mut()`](ArrayBase::exact_chunks_mut) +/// See [`.exact_chunks_mut()`](crate::ArrayRef::exact_chunks_mut) /// for more information. //#[derive(Debug)] pub struct ExactChunksMut<'a, A, D> @@ -237,7 +237,7 @@ impl_iterator! { /// Exact chunks iterator. /// -/// See [`.exact_chunks_mut()`](ArrayBase::exact_chunks_mut) +/// See [`.exact_chunks_mut()`](crate::ArrayRef::exact_chunks_mut) /// for more information. pub struct ExactChunksIterMut<'a, A, D> { diff --git a/src/iterators/lanes.rs b/src/iterators/lanes.rs index 11c83d002..0f9678872 100644 --- a/src/iterators/lanes.rs +++ b/src/iterators/lanes.rs @@ -23,7 +23,7 @@ impl_ndproducer! { } } -/// See [`.lanes()`](ArrayBase::lanes) +/// See [`.lanes()`](crate::ArrayRef::lanes) /// for more information. pub struct Lanes<'a, A, D> { @@ -92,7 +92,7 @@ where D: Dimension } } -/// See [`.lanes_mut()`](ArrayBase::lanes_mut) +/// See [`.lanes_mut()`](crate::ArrayRef::lanes_mut) /// for more information. pub struct LanesMut<'a, A, D> { diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index cf3153b14..b779d2be5 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -336,7 +336,7 @@ pub enum ElementsRepr /// /// Iterator element type is `&'a A`. /// -/// See [`.iter()`](ArrayBase::iter) for more information. +/// See [`.iter()`](crate::ArrayRef::iter) for more information. #[derive(Debug)] pub struct Iter<'a, A, D> { @@ -355,7 +355,7 @@ pub struct ElementsBase<'a, A, D> /// /// Iterator element type is `&'a mut A`. /// -/// See [`.iter_mut()`](ArrayBase::iter_mut) for more information. +/// See [`.iter_mut()`](crate::ArrayRef::iter_mut) for more information. #[derive(Debug)] pub struct IterMut<'a, A, D> { @@ -385,12 +385,12 @@ impl<'a, A, D: Dimension> ElementsBaseMut<'a, A, D> /// An iterator over the indexes and elements of an array. /// -/// See [`.indexed_iter()`](ArrayBase::indexed_iter) for more information. +/// See [`.indexed_iter()`](crate::ArrayRef::indexed_iter) for more information. #[derive(Clone)] pub struct IndexedIter<'a, A, D>(ElementsBase<'a, A, D>); /// An iterator over the indexes and elements of an array (mutable). /// -/// See [`.indexed_iter_mut()`](ArrayBase::indexed_iter_mut) for more information. +/// See [`.indexed_iter_mut()`](crate::ArrayRef::indexed_iter_mut) for more information. pub struct IndexedIterMut<'a, A, D>(ElementsBaseMut<'a, A, D>); impl<'a, A, D> IndexedIter<'a, A, D> @@ -729,7 +729,7 @@ where D: Dimension /// An iterator that traverses over all axes but one, and yields a view for /// each lane along that axis. /// -/// See [`.lanes()`](ArrayBase::lanes) for more information. +/// See [`.lanes()`](crate::ArrayRef::lanes) for more information. pub struct LanesIter<'a, A, D> { inner_len: Ix, @@ -792,7 +792,7 @@ impl<'a, A> DoubleEndedIterator for LanesIter<'a, A, Ix1> /// An iterator that traverses over all dimensions but the innermost, /// and yields each inner row (mutable). /// -/// See [`.lanes_mut()`](ArrayBase::lanes_mut) +/// See [`.lanes_mut()`](crate::ArrayRef::lanes_mut) /// for more information. pub struct LanesIterMut<'a, A, D> { @@ -1007,8 +1007,8 @@ where D: Dimension /// /// Iterator element type is `ArrayView<'a, A, D>`. /// -/// See [`.outer_iter()`](ArrayBase::outer_iter) -/// or [`.axis_iter()`](ArrayBase::axis_iter) +/// See [`.outer_iter()`](crate::ArrayRef::outer_iter) +/// or [`.axis_iter()`](crate::ArrayRef::axis_iter) /// for more information. #[derive(Debug)] pub struct AxisIter<'a, A, D> @@ -1108,8 +1108,8 @@ where D: Dimension /// /// Iterator element type is `ArrayViewMut<'a, A, D>`. /// -/// See [`.outer_iter_mut()`](ArrayBase::outer_iter_mut) -/// or [`.axis_iter_mut()`](ArrayBase::axis_iter_mut) +/// See [`.outer_iter_mut()`](crate::ArrayRef::outer_iter_mut) +/// or [`.axis_iter_mut()`](crate::ArrayRef::axis_iter_mut) /// for more information. pub struct AxisIterMut<'a, A, D> { @@ -1314,7 +1314,7 @@ impl<'a, A, D: Dimension> NdProducer for AxisIterMut<'a, A, D> /// /// Iterator element type is `ArrayView<'a, A, D>`. /// -/// See [`.axis_chunks_iter()`](ArrayBase::axis_chunks_iter) for more information. +/// See [`.axis_chunks_iter()`](crate::ArrayRef::axis_chunks_iter) for more information. pub struct AxisChunksIter<'a, A, D> { iter: AxisIterCore, @@ -1496,7 +1496,7 @@ macro_rules! chunk_iter_impl { /// /// Iterator element type is `ArrayViewMut<'a, A, D>`. /// -/// See [`.axis_chunks_iter_mut()`](ArrayBase::axis_chunks_iter_mut) +/// See [`.axis_chunks_iter_mut()`](crate::ArrayRef::axis_chunks_iter_mut) /// for more information. pub struct AxisChunksIterMut<'a, A, D> { diff --git a/src/iterators/windows.rs b/src/iterators/windows.rs index 1c2ab6a85..afdaaa895 100644 --- a/src/iterators/windows.rs +++ b/src/iterators/windows.rs @@ -9,7 +9,7 @@ use crate::Slice; /// Window producer and iterable /// -/// See [`.windows()`](ArrayBase::windows) for more +/// See [`.windows()`](crate::ArrayRef::windows) for more /// information. pub struct Windows<'a, A, D> { @@ -91,7 +91,7 @@ where /// Window iterator. /// -/// See [`.windows()`](ArrayBase::windows) for more +/// See [`.windows()`](crate::ArrayRef::windows) for more /// information. pub struct WindowsIter<'a, A, D> { @@ -129,7 +129,7 @@ send_sync_read_only!(WindowsIter); /// Window producer and iterable /// -/// See [`.axis_windows()`](ArrayBase::axis_windows) for more +/// See [`.axis_windows()`](crate::ArrayRef::axis_windows) for more /// information. pub struct AxisWindows<'a, A, D> { diff --git a/src/lib.rs b/src/lib.rs index a67e3930d..b16cb75fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,8 +60,8 @@ //! - Performance: //! + Prefer higher order methods and arithmetic operations on arrays first, //! then iteration, and as a last priority using indexed algorithms. -//! + The higher order functions like [`.map()`](ArrayBase::map), -//! [`.map_inplace()`](ArrayBase::map_inplace), [`.zip_mut_with()`](ArrayBase::zip_mut_with), +//! + The higher order functions like [`.map()`](ArrayRef::map), +//! [`.map_inplace()`](ArrayRef::map_inplace), [`.zip_mut_with()`](ArrayRef::zip_mut_with), //! [`Zip`] and [`azip!()`](azip) are the most efficient ways //! to perform single traversal and lock step traversal respectively. //! + Performance of an operation depends on the memory layout of the array @@ -308,7 +308,7 @@ pub type Ixs = isize; /// data (shared ownership). /// Sharing requires that it uses copy-on-write for mutable operations. /// Calling a method for mutating elements on `ArcArray`, for example -/// [`view_mut()`](Self::view_mut) or [`get_mut()`](Self::get_mut), +/// [`view_mut()`](ArrayRef::view_mut) or [`get_mut()`](ArrayRef::get_mut), /// will break sharing and require a clone of the data (if it is not uniquely held). /// /// ## `CowArray` @@ -332,9 +332,9 @@ pub type Ixs = isize; /// Please see the documentation for the respective array view for an overview /// of methods specific to array views: [`ArrayView`], [`ArrayViewMut`]. /// -/// A view is created from an array using [`.view()`](ArrayBase::view), -/// [`.view_mut()`](ArrayBase::view_mut), using -/// slicing ([`.slice()`](ArrayBase::slice), [`.slice_mut()`](ArrayBase::slice_mut)) or from one of +/// A view is created from an array using [`.view()`](ArrayRef::view), +/// [`.view_mut()`](ArrayRef::view_mut), using +/// slicing ([`.slice()`](ArrayRef::slice), [`.slice_mut()`](ArrayRef::slice_mut)) or from one of /// the many iterators that yield array views. /// /// You can also create an array view from a regular slice of data not @@ -476,12 +476,12 @@ pub type Ixs = isize; /// [`.columns()`][gc], [`.columns_mut()`][gcm], /// [`.lanes(axis)`][l], [`.lanes_mut(axis)`][lm]. /// -/// [gr]: Self::rows -/// [grm]: Self::rows_mut -/// [gc]: Self::columns -/// [gcm]: Self::columns_mut -/// [l]: Self::lanes -/// [lm]: Self::lanes_mut +/// [gr]: ArrayRef::rows +/// [grm]: ArrayRef::rows_mut +/// [gc]: ArrayRef::columns +/// [gcm]: ArrayRef::columns_mut +/// [l]: ArrayRef::lanes +/// [lm]: ArrayRef::lanes_mut /// /// Yes, for 2D arrays `.rows()` and `.outer_iter()` have about the same /// effect: @@ -507,10 +507,10 @@ pub type Ixs = isize; /// [`.slice_collapse()`] panics on `NewAxis` elements and behaves like /// [`.collapse_axis()`] by preserving the number of dimensions. /// -/// [`.slice()`]: Self::slice -/// [`.slice_mut()`]: Self::slice_mut +/// [`.slice()`]: ArrayRef::slice +/// [`.slice_mut()`]: ArrayRef::slice_mut /// [`.slice_move()`]: Self::slice_move -/// [`.slice_collapse()`]: Self::slice_collapse +/// [`.slice_collapse()`]: LayoutRef::slice_collapse /// /// When slicing arrays with generic dimensionality, creating an instance of /// [`SliceInfo`] to pass to the multi-axis slicing methods like [`.slice()`] @@ -519,17 +519,17 @@ pub type Ixs = isize; /// or to create a view and then slice individual axes of the view using /// methods such as [`.slice_axis_inplace()`] and [`.collapse_axis()`]. /// -/// [`.slice_each_axis()`]: Self::slice_each_axis -/// [`.slice_each_axis_mut()`]: Self::slice_each_axis_mut +/// [`.slice_each_axis()`]: ArrayRef::slice_each_axis +/// [`.slice_each_axis_mut()`]: ArrayRef::slice_each_axis_mut /// [`.slice_each_axis_inplace()`]: Self::slice_each_axis_inplace /// [`.slice_axis_inplace()`]: Self::slice_axis_inplace -/// [`.collapse_axis()`]: Self::collapse_axis +/// [`.collapse_axis()`]: LayoutRef::collapse_axis /// /// It's possible to take multiple simultaneous *mutable* slices with /// [`.multi_slice_mut()`] or (for [`ArrayViewMut`] only) /// [`.multi_slice_move()`]. /// -/// [`.multi_slice_mut()`]: Self::multi_slice_mut +/// [`.multi_slice_mut()`]: ArrayRef::multi_slice_mut /// [`.multi_slice_move()`]: ArrayViewMut#method.multi_slice_move /// /// ``` @@ -628,16 +628,16 @@ pub type Ixs = isize; /// Methods for selecting an individual subview take two arguments: `axis` and /// `index`. /// -/// [`.axis_iter()`]: Self::axis_iter -/// [`.axis_iter_mut()`]: Self::axis_iter_mut -/// [`.fold_axis()`]: Self::fold_axis -/// [`.index_axis()`]: Self::index_axis -/// [`.index_axis_inplace()`]: Self::index_axis_inplace -/// [`.index_axis_mut()`]: Self::index_axis_mut +/// [`.axis_iter()`]: ArrayRef::axis_iter +/// [`.axis_iter_mut()`]: ArrayRef::axis_iter_mut +/// [`.fold_axis()`]: ArrayRef::fold_axis +/// [`.index_axis()`]: ArrayRef::index_axis +/// [`.index_axis_inplace()`]: LayoutRef::index_axis_inplace +/// [`.index_axis_mut()`]: ArrayRef::index_axis_mut /// [`.index_axis_move()`]: Self::index_axis_move -/// [`.collapse_axis()`]: Self::collapse_axis -/// [`.outer_iter()`]: Self::outer_iter -/// [`.outer_iter_mut()`]: Self::outer_iter_mut +/// [`.collapse_axis()`]: LayoutRef::collapse_axis +/// [`.outer_iter()`]: ArrayRef::outer_iter +/// [`.outer_iter_mut()`]: ArrayRef::outer_iter_mut /// /// ``` /// @@ -743,7 +743,7 @@ pub type Ixs = isize; /// Arrays support limited *broadcasting*, where arithmetic operations with /// array operands of different sizes can be carried out by repeating the /// elements of the smaller dimension array. See -/// [`.broadcast()`](Self::broadcast) for a more detailed +/// [`.broadcast()`](ArrayRef::broadcast) for a more detailed /// description. /// /// ``` @@ -1044,9 +1044,9 @@ pub type Ixs = isize; /// `&[A]` | `ArrayView` | [`::from_shape()`](ArrayView#method.from_shape) /// `&mut [A]` | `ArrayViewMut1
` | [`::from()`](ArrayViewMut#method.from) /// `&mut [A]` | `ArrayViewMut` | [`::from_shape()`](ArrayViewMut#method.from_shape) -/// `&ArrayBase` | `Vec` | [`.to_vec()`](Self::to_vec) +/// `&ArrayBase` | `Vec` | [`.to_vec()`](ArrayRef::to_vec) /// `Array` | `Vec` | [`.into_raw_vec()`](Array#method.into_raw_vec)[1](#into_raw_vec) -/// `&ArrayBase` | `&[A]` | [`.as_slice()`](Self::as_slice)[2](#req_contig_std), [`.as_slice_memory_order()`](Self::as_slice_memory_order)[3](#req_contig) +/// `&ArrayBase` | `&[A]` | [`.as_slice()`](ArrayRef::as_slice)[2](#req_contig_std), [`.as_slice_memory_order()`](ArrayRef::as_slice_memory_order)[3](#req_contig) /// `&mut ArrayBase` | `&mut [A]` | [`.as_slice_mut()`](Self::as_slice_mut)[2](#req_contig_std), [`.as_slice_memory_order_mut()`](Self::as_slice_memory_order_mut)[3](#req_contig) /// `ArrayView` | `&[A]` | [`.to_slice()`](ArrayView#method.to_slice)[2](#req_contig_std) /// `ArrayViewMut` | `&mut [A]` | [`.into_slice()`](ArrayViewMut#method.into_slice)[2](#req_contig_std) @@ -1070,9 +1070,9 @@ pub type Ixs = isize; /// [.into_owned()]: Self::into_owned /// [.into_shared()]: Self::into_shared /// [.to_owned()]: Self::to_owned -/// [.map()]: Self::map -/// [.view()]: Self::view -/// [.view_mut()]: Self::view_mut +/// [.map()]: ArrayRef::map +/// [.view()]: ArrayRef::view +/// [.view_mut()]: ArrayRef::view_mut /// /// ### Conversions from Nested `Vec`s/`Array`s /// @@ -1415,8 +1415,8 @@ pub struct RawRef(LayoutRef); /// It can act as both an owner as the data as well as a shared reference (view /// like). /// Calling a method for mutating elements on `ArcArray`, for example -/// [`view_mut()`](ArrayBase::view_mut) or -/// [`get_mut()`](ArrayBase::get_mut), will break sharing and +/// [`view_mut()`](ArrayRef::view_mut) or +/// [`get_mut()`](ArrayRef::get_mut), will break sharing and /// require a clone of the data (if it is not uniquely held). /// /// `ArcArray` uses atomic reference counting like `Arc`, so it is `Send` and diff --git a/src/math_cell.rs b/src/math_cell.rs index 6ed1ed71f..629e5575d 100644 --- a/src/math_cell.rs +++ b/src/math_cell.rs @@ -7,7 +7,7 @@ use std::ops::{Deref, DerefMut}; /// A transparent wrapper of [`Cell`](std::cell::Cell) which is identical in every way, except /// it will implement arithmetic operators as well. /// -/// The purpose of `MathCell` is to be used from [.cell_view()](crate::ArrayBase::cell_view). +/// The purpose of `MathCell` is to be used from [.cell_view()](crate::ArrayRef::cell_view). /// The `MathCell` derefs to `Cell`, so all the cell's methods are available. #[repr(transparent)] #[derive(Default)] diff --git a/src/parallel/mod.rs b/src/parallel/mod.rs index 0c84baa91..2eef69307 100644 --- a/src/parallel/mod.rs +++ b/src/parallel/mod.rs @@ -19,8 +19,8 @@ //! //! The following other parallelized methods exist: //! -//! - [`ArrayBase::par_map_inplace()`] -//! - [`ArrayBase::par_mapv_inplace()`] +//! - [`ArrayRef::par_map_inplace()`](crate::ArrayRef::par_map_inplace) +//! - [`ArrayRef::par_mapv_inplace()`](crate::ArrayRef::par_mapv_inplace) //! - [`Zip::par_for_each()`] (all arities) //! - [`Zip::par_map_collect()`] (all arities) //! - [`Zip::par_map_assign_into()`] (all arities) diff --git a/src/shape_builder.rs b/src/shape_builder.rs index cd790a25f..b9a4b0ab6 100644 --- a/src/shape_builder.rs +++ b/src/shape_builder.rs @@ -210,7 +210,7 @@ where D: Dimension /// This is an argument conversion trait that is used to accept an array shape and /// (optionally) an ordering argument. /// -/// See for example [`.to_shape()`](crate::ArrayBase::to_shape). +/// See for example [`.to_shape()`](crate::ArrayRef::to_shape). pub trait ShapeArg { type Dim: Dimension; diff --git a/src/slice.rs b/src/slice.rs index e6c237a92..e2ce1e727 100644 --- a/src/slice.rs +++ b/src/slice.rs @@ -430,7 +430,7 @@ unsafe impl SliceArg for [SliceInfoElem] /// `SliceInfo` instance can still be used to slice an array with dimension /// `IxDyn` as long as the number of axes matches. /// -/// [`.slice()`]: crate::ArrayBase::slice +/// [`.slice()`]: crate::ArrayRef::slice #[derive(Debug)] pub struct SliceInfo { @@ -521,7 +521,7 @@ where } /// Returns the number of dimensions of the input array for - /// [`.slice()`](crate::ArrayBase::slice). + /// [`.slice()`](crate::ArrayRef::slice). /// /// If `Din` is a fixed-size dimension type, then this is equivalent to /// `Din::NDIM.unwrap()`. Otherwise, the value is calculated by iterating @@ -536,7 +536,7 @@ where } /// Returns the number of dimensions after calling - /// [`.slice()`](crate::ArrayBase::slice) (including taking + /// [`.slice()`](crate::ArrayRef::slice) (including taking /// subviews). /// /// If `Dout` is a fixed-size dimension type, then this is equivalent to @@ -755,10 +755,10 @@ impl_slicenextdim!((), NewAxis, Ix0, Ix1); /// panic. Without the `NewAxis`, i.e. `s![0..4;2, 6, 1..5]`, /// [`.slice_collapse()`] would result in an array of shape `[2, 1, 4]`. /// -/// [`.slice()`]: crate::ArrayBase::slice -/// [`.slice_mut()`]: crate::ArrayBase::slice_mut +/// [`.slice()`]: crate::ArrayRef::slice +/// [`.slice_mut()`]: crate::ArrayRef::slice_mut /// [`.slice_move()`]: crate::ArrayBase::slice_move -/// [`.slice_collapse()`]: crate::ArrayBase::slice_collapse +/// [`.slice_collapse()`]: crate::LayoutRef::slice_collapse /// /// See also [*Slicing*](crate::ArrayBase#slicing). /// diff --git a/src/tri.rs b/src/tri.rs index e0681b32c..6e3b90b5b 100644 --- a/src/tri.rs +++ b/src/tri.rs @@ -30,7 +30,7 @@ where /// For arrays with `ndim` exceeding 2, `triu` will apply to the final two axes. /// For 0D and 1D arrays, `triu` will return an unchanged clone. /// - /// See also [`ArrayBase::tril`] + /// See also [`ArrayRef::tril`] /// /// ``` /// use ndarray::array; @@ -95,7 +95,7 @@ where /// For arrays with `ndim` exceeding 2, `tril` will apply to the final two axes. /// For 0D and 1D arrays, `tril` will return an unchanged clone. /// - /// See also [`ArrayBase::triu`] + /// See also [`ArrayRef::triu`] /// /// ``` /// use ndarray::array; From a40307bd04d08483bed606e1dfcd67e363477ad1 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 20 Oct 2024 01:29:06 -0400 Subject: [PATCH 23/33] Adds formatting for ArrayRef --- src/arrayformat.rs | 83 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/src/arrayformat.rs b/src/arrayformat.rs index 1a3b714c3..7e5e1b1c9 100644 --- a/src/arrayformat.rs +++ b/src/arrayformat.rs @@ -6,7 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use super::{ArrayBase, ArrayView, Axis, Data, Dimension, NdProducer}; -use crate::aliases::{Ix1, IxDyn}; +use crate::{ + aliases::{Ix1, IxDyn}, + ArrayRef, +}; use alloc::format; use std::fmt; @@ -112,13 +115,12 @@ fn format_with_overflow( Ok(()) } -fn format_array( - array: &ArrayBase, f: &mut fmt::Formatter<'_>, format: F, fmt_opt: &FormatOptions, +fn format_array( + array: &ArrayRef, f: &mut fmt::Formatter<'_>, format: F, fmt_opt: &FormatOptions, ) -> fmt::Result where F: FnMut(&A, &mut fmt::Formatter<'_>) -> fmt::Result + Clone, D: Dimension, - S: Data, { // Cast into a dynamically dimensioned view // This is required to be able to use `index_axis` for the recursive case @@ -174,6 +176,18 @@ where /// The array is shown in multiline style. impl fmt::Display for ArrayBase where S: Data +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + (**self).fmt(f) + } +} + +/// Format the array reference using `Display` and apply the formatting parameters +/// used to each element. +/// +/// The array is shown in multiline style. +impl fmt::Display for ArrayRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -188,6 +202,18 @@ where S: Data /// The array is shown in multiline style. impl fmt::Debug for ArrayBase where S: Data +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + (**self).fmt(f) + } +} + +/// Format the array reference using `Debug` and apply the formatting parameters used +/// to each element. +/// +/// The array is shown in multiline style. +impl fmt::Debug for ArrayRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -216,6 +242,18 @@ where S: Data /// The array is shown in multiline style. impl fmt::LowerExp for ArrayBase where S: Data +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + (**self).fmt(f) + } +} + +/// Format the array reference using `LowerExp` and apply the formatting parameters used +/// to each element. +/// +/// The array is shown in multiline style. +impl fmt::LowerExp for ArrayRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -230,6 +268,18 @@ where S: Data /// The array is shown in multiline style. impl fmt::UpperExp for ArrayBase where S: Data +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + (**self).fmt(f) + } +} + +/// Format the array using `UpperExp` and apply the formatting parameters used +/// to each element. +/// +/// The array is shown in multiline style. +impl fmt::UpperExp for ArrayRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -237,12 +287,25 @@ where S: Data format_array(self, f, <_>::fmt, &fmt_opt) } } + /// Format the array using `LowerHex` and apply the formatting parameters used /// to each element. /// /// The array is shown in multiline style. impl fmt::LowerHex for ArrayBase where S: Data +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + (**self).fmt(f) + } +} + +/// Format the array using `LowerHex` and apply the formatting parameters used +/// to each element. +/// +/// The array is shown in multiline style. +impl fmt::LowerHex for ArrayRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -257,6 +320,18 @@ where S: Data /// The array is shown in multiline style. impl fmt::Binary for ArrayBase where S: Data +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + (**self).fmt(f) + } +} + +/// Format the array using `Binary` and apply the formatting parameters used +/// to each element. +/// +/// The array is shown in multiline style. +impl fmt::Binary for ArrayRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { From 5adbb313849eefcdd4af20eb0267c2b09a5e3dd6 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 20 Oct 2024 01:34:21 -0400 Subject: [PATCH 24/33] Change some examples over to ArrayRef --- examples/axis_ops.rs | 2 +- examples/convo.rs | 2 +- src/prelude.rs | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/axis_ops.rs b/examples/axis_ops.rs index 3a54a52fb..7f80a637f 100644 --- a/examples/axis_ops.rs +++ b/examples/axis_ops.rs @@ -13,7 +13,7 @@ use ndarray::prelude::*; /// it corresponds to their order in memory. /// /// Errors if array has a 0-stride axis -fn regularize(a: &mut Array) -> Result<(), &'static str> +fn regularize(a: &mut ArrayRef) -> Result<(), &'static str> where D: Dimension, A: ::std::fmt::Debug, diff --git a/examples/convo.rs b/examples/convo.rs index a59795e12..79e8ab6b6 100644 --- a/examples/convo.rs +++ b/examples/convo.rs @@ -14,7 +14,7 @@ type Kernel3x3 = [[A; 3]; 3]; #[inline(never)] #[cfg(feature = "std")] -fn conv_3x3(a: &ArrayView2<'_, F>, out: &mut ArrayViewMut2<'_, F>, kernel: &Kernel3x3) +fn conv_3x3(a: &ArrayRef2, out: &mut ArrayRef2, kernel: &Kernel3x3) where F: Float { let (n, m) = a.dim(); diff --git a/src/prelude.rs b/src/prelude.rs index 43e583b56..072eb4825 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -35,6 +35,9 @@ pub use crate::{ #[doc(no_inline)] pub use crate::{Axis, Dim, Dimension}; +#[doc(no_inline)] +pub use crate::{ArrayRef0, ArrayRef1, ArrayRef2, ArrayRef3, ArrayRef4, ArrayRef5, ArrayRef6, ArrayRefD}; + #[doc(no_inline)] pub use crate::{Array0, Array1, Array2, Array3, Array4, Array5, Array6, ArrayD}; From 6e61e836ae3264bece0a72ddf870ca9f9feb494b Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 20 Oct 2024 11:02:14 -0400 Subject: [PATCH 25/33] Adds missed #[repr(transparent)] for RawRef --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index b16cb75fb..085a52488 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1405,6 +1405,7 @@ pub struct LayoutRef #[repr(transparent)] pub struct ArrayRef(LayoutRef); +#[repr(transparent)] pub struct RawRef(LayoutRef); /// An array where the data has shared ownership and is copy on write. From 0cd43347c5d7f0c40805aef7a666e7e735ded26a Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 20 Oct 2024 11:02:37 -0400 Subject: [PATCH 26/33] Simplifies deref logic and avoids null check --- src/impl_ref_types.rs | 76 +++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 42 deletions(-) diff --git a/src/impl_ref_types.rs b/src/impl_ref_types.rs index 8ae3c90f9..9c86c8bc8 100644 --- a/src/impl_ref_types.rs +++ b/src/impl_ref_types.rs @@ -45,16 +45,12 @@ where S: Data fn deref(&self) -> &Self::Target { - // SAFETY: The pointer will hold all the guarantees of `as_ref`: - // - The pointer is aligned because neither type use repr(align) - // - It is "dereferencable" because it just points to self + // SAFETY: + // - The pointer is aligned because neither type uses repr(align) + // - It is "dereferencable" because it comes from a reference // - For the same reason, it is initialized - unsafe { - (&self.layout as *const LayoutRef) - .cast::>() - .as_ref() - } - .expect("References are always non-null") + // - The cast is valid because ArrayRef uses #[repr(transparent)] + unsafe { &*(&self.layout as *const LayoutRef).cast::>() } } } @@ -67,16 +63,12 @@ where fn deref_mut(&mut self) -> &mut Self::Target { self.ensure_unique(); - // SAFETY: The pointer will hold all the guarantees of `as_ref`: - // - The pointer is aligned because neither type use repr(align) - // - It is "dereferencable" because it just points to self + // SAFETY: + // - The pointer is aligned because neither type uses repr(align) + // - It is "dereferencable" because it comes from a reference // - For the same reason, it is initialized - unsafe { - (&mut self.layout as *mut LayoutRef) - .cast::>() - .as_mut() - } - .expect("References are always non-null") + // - The cast is valid because ArrayRef uses #[repr(transparent)] + unsafe { &mut *(&mut self.layout as *mut LayoutRef).cast::>() } } } @@ -87,12 +79,12 @@ impl Deref for ArrayRef fn deref(&self) -> &Self::Target { - unsafe { - (self as *const ArrayRef) - .cast::>() - .as_ref() - } - .expect("References are always non-null") + // SAFETY: + // - The pointer is aligned because neither type uses repr(align) + // - It is "dereferencable" because it comes from a reference + // - For the same reason, it is initialized + // - The cast is valid because ArrayRef uses #[repr(transparent)] + unsafe { &*(self as *const ArrayRef).cast::>() } } } @@ -101,12 +93,12 @@ impl DerefMut for ArrayRef { fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { - (self as *mut ArrayRef) - .cast::>() - .as_mut() - } - .expect("References are always non-null") + // SAFETY: + // - The pointer is aligned because neither type uses repr(align) + // - It is "dereferencable" because it comes from a reference + // - For the same reason, it is initialized + // - The cast is valid because ArrayRef uses #[repr(transparent)] + unsafe { &mut *(self as *mut ArrayRef).cast::>() } } } @@ -136,12 +128,12 @@ where S: RawData { fn as_ref(&self) -> &RawRef { - unsafe { - (&self.layout as *const LayoutRef) - .cast::>() - .as_ref() - } - .expect("References are always non-null") + // SAFETY: + // - The pointer is aligned because neither type uses repr(align) + // - It is "dereferencable" because it comes from a reference + // - For the same reason, it is initialized + // - The cast is valid because ArrayRef uses #[repr(transparent)] + unsafe { &*(&self.layout as *const LayoutRef).cast::>() } } } @@ -151,12 +143,12 @@ where S: RawDataMut { fn as_mut(&mut self) -> &mut RawRef { - unsafe { - (&mut self.layout as *mut LayoutRef) - .cast::>() - .as_mut() - } - .expect("References are always non-null") + // SAFETY: + // - The pointer is aligned because neither type uses repr(align) + // - It is "dereferencable" because it comes from a reference + // - For the same reason, it is initialized + // - The cast is valid because ArrayRef uses #[repr(transparent)] + unsafe { &mut *(&mut self.layout as *mut LayoutRef).cast::>() } } } From f77ad96414e0fc52aab468812fef950de0bee3e3 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 20 Oct 2024 11:02:48 -0400 Subject: [PATCH 27/33] Adds documentation to ArrayRef --- src/lib.rs | 68 +++++++++++++++++++++++++++++++++++++++ src/linalg/impl_linalg.rs | 2 +- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 085a52488..d0f61214d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1402,6 +1402,74 @@ pub struct LayoutRef strides: D, } +/// A reference to an *n*-dimensional array whose data is safe to read and write. +/// +/// This type's relationship to [`ArrayBase`] can be thought of a bit like the +/// relationship between [`Vec`] and [`std::slice`]: it represents a look into the +/// array, and is the [`Deref`](std::ops::Deref) target for owned, shared, and viewed +/// arrays. Most functionality is implemented on `ArrayRef`, and most functions +/// should take `&ArrayRef` instead of `&ArrayBase`. +/// +/// ## Relationship to Views +/// `ArrayRef` and [`ArrayView`] are very similar types: they both represent a +/// "look" into an array. There is one key difference: views have their own +/// shape and strides, while `ArrayRef` just points to the shape and strides of +/// whatever array it came from. +/// +/// As an example, let's write a function that takes an array, trims it +/// down to a square in-place, and then returns the sum: +/// ```rust +/// use std::cmp; +/// use std::ops::Add; +/// +/// use ndarray::{ArrayRef2, array, s}; +/// use num_traits::Zero; +/// +/// fn square_and_sum(arr: &mut ArrayRef2) -> A +/// where A: Clone + Add + Zero +/// { +/// let side_len = cmp::min(arr.nrows(), arr.ncols()); +/// arr.slice_collapse(s![..side_len, ..side_len]); +/// arr.sum() +/// } +/// +/// let mut arr = array![ +/// [ 1, 2, 3], +/// [ 4, 5, 6], +/// [ 7, 8, 9], +/// [10, 11, 12] +/// ]; +/// // Take a view of the array, excluding the first column +/// let mut view = arr.slice_mut(s![.., 1..]); +/// let sum_view = square_and_sum(&mut view); +/// assert_eq!(sum_view, 16); +/// assert_eq!(view.ncols(), 2usize); // The view has changed shape... +/// assert_eq!(view.nrows(), 2usize); +/// assert_eq!(arr.ncols(), 3usize); // ... but the original array has not +/// assert_eq!(arr.nrows(), 4usize); +/// +/// let sum_all = square_and_sum(&mut arr); +/// assert_eq!(sum_all, 45); +/// assert_eq!(arr.ncols(), 3usize); // Now the original array has changed shape +/// assert_eq!(arr.nrows(), 3usize); // because we passed it directly to the function +/// ``` +/// Critically, we can call the same function on both the view and the array itself. +/// We can see that, because the view has its own shape and strides, "squaring" it does +/// not affect the shape of the original array. Those only change when we pass the array +/// itself into the function. +/// +/// Also notice that the output of `slice_mut` is a *view*, not an `ArrayRef`. +/// This is where the analogy to `Vec`/`slice` breaks down a bit: due to limitations of +/// the Rust language, `ArrayRef` *cannot* have a different shape / stride from the +/// array from which it is dereferenced. So slicing still produces an `ArrayView`, +/// not an `ArrayRef`. +/// +/// ## Uniqueness +/// `ndarray` has copy-on-write shared data; see [`ArcArray`], for example. +/// When a copy-on-write array is passed to a function that takes `ArrayRef` as mutable +/// (i.e., `&mut ArrayRef`, like above), that array will be un-shared when it is dereferenced +/// into `ArrayRef`. In other words, having a `&mut ArrayRef` guarantees that the underlying +/// data is un-shared and safe to write to. #[repr(transparent)] pub struct ArrayRef(LayoutRef); diff --git a/src/linalg/impl_linalg.rs b/src/linalg/impl_linalg.rs index 04584ed0f..df7e26abc 100644 --- a/src/linalg/impl_linalg.rs +++ b/src/linalg/impl_linalg.rs @@ -399,7 +399,7 @@ where D: Dimension } } -// mat_mul_impl uses ArrayView arguments to send all array kinds into +// mat_mul_impl uses ArrayRef arguments to send all array kinds into // the same instantiated implementation. #[cfg(not(feature = "blas"))] use self::mat_mul_general as mat_mul_impl; From 3888399079c692743680cc8df0dbdb36a6633099 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Mon, 21 Oct 2024 18:28:14 -0400 Subject: [PATCH 28/33] Adds missing aliases to ArrayBase from RawRef and LayoutRef --- src/alias_asref.rs | 95 +++++++++++++++++++++++++++++++++++----------- src/impl_2d.rs | 67 ++++++++++++++++++++++++++++++++ src/impl_dyn.rs | 45 ++++++++++++++++++++++ 3 files changed, 185 insertions(+), 22 deletions(-) diff --git a/src/alias_asref.rs b/src/alias_asref.rs index f2e2133a9..7e9239b01 100644 --- a/src/alias_asref.rs +++ b/src/alias_asref.rs @@ -5,13 +5,86 @@ use crate::{ AxisDescription, Dimension, LayoutRef, + NdIndex, RawArrayView, RawData, + RawDataMut, RawRef, Slice, SliceArg, }; +/// Functions coming from RawRef +impl, D: Dimension> ArrayBase +{ + /// Return a raw pointer to the element at `index`, or return `None` + /// if the index is out of bounds. + /// + /// ``` + /// use ndarray::arr2; + /// + /// let a = arr2(&[[1., 2.], [3., 4.]]); + /// + /// let v = a.raw_view(); + /// let p = a.get_ptr((0, 1)).unwrap(); + /// + /// assert_eq!(unsafe { *p }, 2.); + /// ``` + pub fn get_ptr(&self, index: I) -> Option<*const A> + where I: NdIndex + { + >>::as_ref(self).get_ptr(index) + } + + /// Return a raw pointer to the element at `index`, or return `None` + /// if the index is out of bounds. + /// + /// ``` + /// use ndarray::arr2; + /// + /// let mut a = arr2(&[[1., 2.], [3., 4.]]); + /// + /// let v = a.raw_view_mut(); + /// let p = a.get_mut_ptr((0, 1)).unwrap(); + /// + /// unsafe { + /// *p = 5.; + /// } + /// + /// assert_eq!(a.get((0, 1)), Some(&5.)); + /// ``` + pub fn get_mut_ptr(&mut self, index: I) -> Option<*mut A> + where + S: RawDataMut, + I: NdIndex, + { + >>::as_mut(self).get_mut_ptr(index) + } + + /// Return a pointer to the first element in the array. + /// + /// Raw access to array elements needs to follow the strided indexing + /// scheme: an element at multi-index *I* in an array with strides *S* is + /// located at offset + /// + /// *Σ0 ≤ k < d Ik × Sk* + /// + /// where *d* is `self.ndim()`. + #[inline(always)] + pub fn as_ptr(&self) -> *const A + { + >>::as_ref(self).as_ptr() + } + + /// Return a raw view of the array. + #[inline] + pub fn raw_view(&self) -> RawArrayView + { + >>::as_ref(self).raw_view() + } +} + +/// Functions coming from LayoutRef impl ArrayBase { /// Slice the array in place without changing the number of dimensions. @@ -182,28 +255,6 @@ impl ArrayBase self.as_mut().merge_axes(take, into) } - /// Return a raw view of the array. - #[inline] - pub fn raw_view(&self) -> RawArrayView - { - >>::as_ref(self).raw_view() - } - - /// Return a pointer to the first element in the array. - /// - /// Raw access to array elements needs to follow the strided indexing - /// scheme: an element at multi-index *I* in an array with strides *S* is - /// located at offset - /// - /// *Σ0 ≤ k < d Ik × Sk* - /// - /// where *d* is `self.ndim()`. - #[inline(always)] - pub fn as_ptr(&self) -> *const S::Elem - { - >>::as_ref(self).as_ptr() - } - /// Return the total number of elements in the array. pub fn len(&self) -> usize { diff --git a/src/impl_2d.rs b/src/impl_2d.rs index 27358dca9..5d0981480 100644 --- a/src/impl_2d.rs +++ b/src/impl_2d.rs @@ -148,3 +148,70 @@ impl LayoutRef m == n } } + +impl ArrayBase +{ + /// Return the number of rows (length of `Axis(0)`) in the two-dimensional array. + /// + /// ``` + /// use ndarray::{array, Axis}; + /// + /// let array = array![[1., 2.], + /// [3., 4.], + /// [5., 6.]]; + /// assert_eq!(array.nrows(), 3); + /// + /// // equivalent ways of getting the dimensions + /// // get nrows, ncols by using dim: + /// let (m, n) = array.dim(); + /// assert_eq!(m, array.nrows()); + /// // get length of any particular axis with .len_of() + /// assert_eq!(m, array.len_of(Axis(0))); + /// ``` + pub fn nrows(&self) -> usize + { + >>::as_ref(self).nrows() + } + + /// Return the number of columns (length of `Axis(1)`) in the two-dimensional array. + /// + /// ``` + /// use ndarray::{array, Axis}; + /// + /// let array = array![[1., 2.], + /// [3., 4.], + /// [5., 6.]]; + /// assert_eq!(array.ncols(), 2); + /// + /// // equivalent ways of getting the dimensions + /// // get nrows, ncols by using dim: + /// let (m, n) = array.dim(); + /// assert_eq!(n, array.ncols()); + /// // get length of any particular axis with .len_of() + /// assert_eq!(n, array.len_of(Axis(1))); + /// ``` + pub fn ncols(&self) -> usize + { + >>::as_ref(self).ncols() + } + + /// Return true if the array is square, false otherwise. + /// + /// # Examples + /// Square: + /// ``` + /// use ndarray::array; + /// let array = array![[1., 2.], [3., 4.]]; + /// assert!(array.is_square()); + /// ``` + /// Not square: + /// ``` + /// use ndarray::array; + /// let array = array![[1., 2., 5.], [3., 4., 6.]]; + /// assert!(!array.is_square()); + /// ``` + pub fn is_square(&self) -> bool + { + >>::as_ref(self).is_square() + } +} diff --git a/src/impl_dyn.rs b/src/impl_dyn.rs index 2470967d2..409fe991a 100644 --- a/src/impl_dyn.rs +++ b/src/impl_dyn.rs @@ -59,6 +59,51 @@ impl LayoutRef } } +impl ArrayBase +{ + /// Insert new array axis of length 1 at `axis`, modifying the shape and + /// strides in-place. + /// + /// **Panics** if the axis is out of bounds. + /// + /// ``` + /// use ndarray::{Axis, arr2, arr3}; + /// + /// let mut a = arr2(&[[1, 2, 3], [4, 5, 6]]).into_dyn(); + /// assert_eq!(a.shape(), &[2, 3]); + /// + /// a.insert_axis_inplace(Axis(1)); + /// assert_eq!(a, arr3(&[[[1, 2, 3]], [[4, 5, 6]]]).into_dyn()); + /// assert_eq!(a.shape(), &[2, 1, 3]); + /// ``` + #[track_caller] + pub fn insert_axis_inplace(&mut self, axis: Axis) + { + self.as_mut().insert_axis_inplace(axis) + } + + /// Collapses the array to `index` along the axis and removes the axis, + /// modifying the shape and strides in-place. + /// + /// **Panics** if `axis` or `index` is out of bounds. + /// + /// ``` + /// use ndarray::{Axis, arr1, arr2}; + /// + /// let mut a = arr2(&[[1, 2, 3], [4, 5, 6]]).into_dyn(); + /// assert_eq!(a.shape(), &[2, 3]); + /// + /// a.index_axis_inplace(Axis(1), 1); + /// assert_eq!(a, arr1(&[2, 5]).into_dyn()); + /// assert_eq!(a.shape(), &[2]); + /// ``` + #[track_caller] + pub fn index_axis_inplace(&mut self, axis: Axis, index: usize) + { + self.as_mut().index_axis_inplace(axis, index) + } +} + impl ArrayBase where S: Data { From 0a3cad3fc02f8e78e202d0c155ce68de92559edd Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Mon, 21 Oct 2024 18:43:56 -0400 Subject: [PATCH 29/33] Adds a short snippet of documentation for `RawRef` and some top-level bullets on the new types --- src/lib.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index d0f61214d..599ca59a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,12 +29,17 @@ //! dimensions, then an element in the array is accessed by using that many indices. //! Each dimension is also called an *axis*. //! +//! To get started, functionality is provided in the following core types: //! - **[`ArrayBase`]**: //! The *n*-dimensional array type itself.
//! It is used to implement both the owned arrays and the views; see its docs //! for an overview of all array features.
//! - The main specific array type is **[`Array`]**, which owns //! its elements. +//! - A reference type, **[`ArrayRef`]**, that contains most of the functionality +//! for reading and writing to arrays. +//! - A reference type, **[`LayoutRef`]**, that contains most of the functionality +//! for reading and writing to array layouts: their shape and strides. //! //! ## Highlights //! @@ -1473,6 +1478,17 @@ pub struct LayoutRef #[repr(transparent)] pub struct ArrayRef(LayoutRef); +/// A reference to an *n*-dimensional array whose data is not safe to read or write. +/// +/// This type is similar to [`ArrayRef`] but does not guarantee that its data is safe +/// to read or write; i.e., the underlying data may come from a shared array or be otherwise +/// unsafe to dereference. This type should be used sparingly and with extreme caution; +/// most of its methods either provide pointers or return [`RawArrayView`], both of +/// which tend to be full of unsafety. +/// +/// For the few times when this type is appropriate, it has the same `AsRef` semantics +/// as [`LayoutRef`]; see [its documentation on writing functions](LayoutRef#writing-functions) +/// for information on how to properly handle functionality on this type. #[repr(transparent)] pub struct RawRef(LayoutRef); From cbed83789991fa4f90b0ab0848409c82f8add49e Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sat, 26 Oct 2024 11:25:13 -0400 Subject: [PATCH 30/33] Makes as_ref more explicit through methods on ArrayBase --- src/alias_asref.rs | 48 ++++++++++++++++++++--------------------- src/impl_2d.rs | 6 +++--- src/impl_owned_array.rs | 2 +- src/impl_ref_types.rs | 30 ++++++++++++++++++++++++++ tests/array.rs | 2 +- 5 files changed, 59 insertions(+), 29 deletions(-) diff --git a/src/alias_asref.rs b/src/alias_asref.rs index 7e9239b01..af4ca17b0 100644 --- a/src/alias_asref.rs +++ b/src/alias_asref.rs @@ -33,7 +33,7 @@ impl, D: Dimension> ArrayBase pub fn get_ptr(&self, index: I) -> Option<*const A> where I: NdIndex { - >>::as_ref(self).get_ptr(index) + self.as_raw_ref().get_ptr(index) } /// Return a raw pointer to the element at `index`, or return `None` @@ -58,7 +58,7 @@ impl, D: Dimension> ArrayBase S: RawDataMut, I: NdIndex, { - >>::as_mut(self).get_mut_ptr(index) + self.as_raw_ref_mut().get_mut_ptr(index) } /// Return a pointer to the first element in the array. @@ -73,14 +73,14 @@ impl, D: Dimension> ArrayBase #[inline(always)] pub fn as_ptr(&self) -> *const A { - >>::as_ref(self).as_ptr() + self.as_raw_ref().as_ptr() } /// Return a raw view of the array. #[inline] pub fn raw_view(&self) -> RawArrayView { - >>::as_ref(self).raw_view() + self.as_raw_ref().raw_view() } } @@ -111,7 +111,7 @@ impl ArrayBase pub fn slice_collapse(&mut self, info: I) where I: SliceArg { - self.as_mut().slice_collapse(info); + self.as_layout_ref_mut().slice_collapse(info); } /// Slice the array in place along the specified axis. @@ -121,7 +121,7 @@ impl ArrayBase #[track_caller] pub fn slice_axis_inplace(&mut self, axis: Axis, indices: Slice) { - self.as_mut().slice_axis_inplace(axis, indices); + self.as_layout_ref_mut().slice_axis_inplace(axis, indices); } /// Slice the array in place, with a closure specifying the slice for each @@ -135,7 +135,7 @@ impl ArrayBase pub fn slice_each_axis_inplace(&mut self, f: F) where F: FnMut(AxisDescription) -> Slice { - self.as_mut().slice_each_axis_inplace(f); + self.as_layout_ref_mut().slice_each_axis_inplace(f); } /// Selects `index` along the axis, collapsing the axis into length one. @@ -144,7 +144,7 @@ impl ArrayBase #[track_caller] pub fn collapse_axis(&mut self, axis: Axis, index: usize) { - self.as_mut().collapse_axis(axis, index); + self.as_layout_ref_mut().collapse_axis(axis, index); } /// Return `true` if the array data is laid out in contiguous “C order” in @@ -154,19 +154,19 @@ impl ArrayBase /// contiguous in memory, it has custom strides, etc. pub fn is_standard_layout(&self) -> bool { - >>::as_ref(self).is_standard_layout() + self.as_layout_ref().is_standard_layout() } /// Return true if the array is known to be contiguous. pub(crate) fn is_contiguous(&self) -> bool { - >>::as_ref(self).is_contiguous() + self.as_layout_ref().is_contiguous() } /// Return an iterator over the length and stride of each axis. pub fn axes(&self) -> Axes<'_, D> { - >>::as_ref(self).axes() + self.as_layout_ref().axes() } /* @@ -180,7 +180,7 @@ impl ArrayBase /// preferring axes with len > 1. pub fn max_stride_axis(&self) -> Axis { - LayoutRef::max_stride_axis(self.as_ref()) + self.as_layout_ref().max_stride_axis() } /// Reverse the stride of `axis`. @@ -189,7 +189,7 @@ impl ArrayBase #[track_caller] pub fn invert_axis(&mut self, axis: Axis) { - self.as_mut().invert_axis(axis); + self.as_layout_ref_mut().invert_axis(axis); } /// Swap axes `ax` and `bx`. @@ -211,7 +211,7 @@ impl ArrayBase #[track_caller] pub fn swap_axes(&mut self, ax: usize, bx: usize) { - self.as_mut().swap_axes(ax, bx); + self.as_layout_ref_mut().swap_axes(ax, bx); } /// If possible, merge in the axis `take` to `into`. @@ -252,13 +252,13 @@ impl ArrayBase #[track_caller] pub fn merge_axes(&mut self, take: Axis, into: Axis) -> bool { - self.as_mut().merge_axes(take, into) + self.as_layout_ref_mut().merge_axes(take, into) } /// Return the total number of elements in the array. pub fn len(&self) -> usize { - >>::as_ref(self).len() + self.as_layout_ref().len() } /// Return the length of `axis`. @@ -270,19 +270,19 @@ impl ArrayBase #[track_caller] pub fn len_of(&self, axis: Axis) -> usize { - >>::as_ref(self).len_of(axis) + self.as_layout_ref().len_of(axis) } /// Return whether the array has any elements pub fn is_empty(&self) -> bool { - >>::as_ref(self).is_empty() + self.as_layout_ref().is_empty() } /// Return the number of dimensions (axes) in the array pub fn ndim(&self) -> usize { - >>::as_ref(self).ndim() + self.as_layout_ref().ndim() } /// Return the shape of the array in its “pattern” form, @@ -290,7 +290,7 @@ impl ArrayBase /// and so on. pub fn dim(&self) -> D::Pattern { - >>::as_ref(self).dim() + self.as_layout_ref().dim() } /// Return the shape of the array as it's stored in the array. @@ -309,7 +309,7 @@ impl ArrayBase /// ``` pub fn raw_dim(&self) -> D { - >>::as_ref(self).raw_dim() + self.as_layout_ref().raw_dim() } /// Return the shape of the array as a slice. @@ -338,13 +338,13 @@ impl ArrayBase /// ``` pub fn shape(&self) -> &[usize] { - >>::as_ref(self).shape() + self.as_layout_ref().shape() } /// Return the strides of the array as a slice. pub fn strides(&self) -> &[isize] { - >>::as_ref(self).strides() + self.as_layout_ref().strides() } /// Return the stride of `axis`. @@ -356,6 +356,6 @@ impl ArrayBase #[track_caller] pub fn stride_of(&self, axis: Axis) -> isize { - >>::as_ref(self).stride_of(axis) + self.as_layout_ref().stride_of(axis) } } diff --git a/src/impl_2d.rs b/src/impl_2d.rs index 5d0981480..b6379e67b 100644 --- a/src/impl_2d.rs +++ b/src/impl_2d.rs @@ -170,7 +170,7 @@ impl ArrayBase /// ``` pub fn nrows(&self) -> usize { - >>::as_ref(self).nrows() + self.as_layout_ref().nrows() } /// Return the number of columns (length of `Axis(1)`) in the two-dimensional array. @@ -192,7 +192,7 @@ impl ArrayBase /// ``` pub fn ncols(&self) -> usize { - >>::as_ref(self).ncols() + self.as_layout_ref().ncols() } /// Return true if the array is square, false otherwise. @@ -212,6 +212,6 @@ impl ArrayBase /// ``` pub fn is_square(&self) -> bool { - >>::as_ref(self).is_square() + self.as_layout_ref().is_square() } } diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs index dc79ecda0..004668046 100644 --- a/src/impl_owned_array.rs +++ b/src/impl_owned_array.rs @@ -747,7 +747,7 @@ where D: Dimension sort_axes_in_default_order_tandem(&mut tail_view, &mut array); debug_assert!(tail_view.is_standard_layout(), "not std layout dim: {:?}, strides: {:?}", - tail_view.shape(), LayoutRef::strides(tail_view.as_ref())); + tail_view.shape(), tail_view.strides()); } // Keep track of currently filled length of `self.data` and update it diff --git a/src/impl_ref_types.rs b/src/impl_ref_types.rs index 9c86c8bc8..d93a996bf 100644 --- a/src/impl_ref_types.rs +++ b/src/impl_ref_types.rs @@ -338,3 +338,33 @@ where target.zip_mut_with(self, |tgt, src| tgt.clone_from(src)); } } + +/// Shortcuts for the various as_ref calls +impl ArrayBase +where S: RawData +{ + /// Cheaply convert a reference to the array to an &LayoutRef + pub fn as_layout_ref(&self) -> &LayoutRef + { + self.as_ref() + } + + /// Cheaply and mutably convert a reference to the array to an &LayoutRef + pub fn as_layout_ref_mut(&mut self) -> &mut LayoutRef + { + self.as_mut() + } + + /// Cheaply convert a reference to the array to an &RawRef + pub fn as_raw_ref(&self) -> &RawRef + { + self.as_ref() + } + + /// Cheaply and mutably convert a reference to the array to an &RawRef + pub fn as_raw_ref_mut(&mut self) -> &mut RawRef + where S: RawDataMut + { + self.as_mut() + } +} diff --git a/tests/array.rs b/tests/array.rs index 9b4e4cc90..fbc7b4d11 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -2821,7 +2821,7 @@ fn test_split_complex_invert_axis() } #[test] -fn test_slice_assing() +fn test_slice_assign() { let mut a = array![0, 1, 2, 3, 4]; *a.slice_mut(s![1..3]) += 1; From 945f70de8138e80cce290345edaabff9db0b21cd Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sat, 26 Oct 2024 11:34:25 -0400 Subject: [PATCH 31/33] Restore remove_index to DataOwned I think I accidentally moved this over to ArrayRef, but we're not sure it should still require DataOwned --- src/impl_methods.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 97808884b..3bd1a8b68 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -3102,7 +3102,13 @@ impl ArrayRef Zip::from(self.lanes_mut(axis)).map_collect(mapping) } } +} +impl ArrayBase +where + S: DataOwned + DataMut, + D: Dimension, +{ /// Remove the `index`th elements along `axis` and shift down elements from higher indexes. /// /// Note that this "removes" the elements by swapping them around to the end of the axis and @@ -3115,7 +3121,6 @@ impl ArrayRef /// ***Panics*** if `axis` is out of bounds
/// ***Panics*** if not `index < self.len_of(axis)`. pub fn remove_index(&mut self, axis: Axis, index: usize) - // TODO: Check whether this needed to be DataOwned { assert!(index < self.len_of(axis), "index {} must be less than length of Axis({})", index, axis.index()); @@ -3125,7 +3130,10 @@ impl ArrayRef // then slice the axis in place to cut out the removed final element self.slice_axis_inplace(axis, Slice::new(0, Some(-1), 1)); } +} +impl ArrayRef +{ /// Iterates over pairs of consecutive elements along the axis. /// /// The first argument to the closure is an element, and the second From 93dfb3887dce25c58e87daaa6fcf499aad5ffc5c Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sat, 26 Oct 2024 15:39:09 -0400 Subject: [PATCH 32/33] Fixes unused imports --- src/alias_asref.rs | 2 -- src/impl_owned_array.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/src/alias_asref.rs b/src/alias_asref.rs index af4ca17b0..ab78af605 100644 --- a/src/alias_asref.rs +++ b/src/alias_asref.rs @@ -4,12 +4,10 @@ use crate::{ Axis, AxisDescription, Dimension, - LayoutRef, NdIndex, RawArrayView, RawData, RawDataMut, - RawRef, Slice, SliceArg, }; diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs index 004668046..023e9ebb4 100644 --- a/src/impl_owned_array.rs +++ b/src/impl_owned_array.rs @@ -13,7 +13,6 @@ use crate::dimension; use crate::error::{ErrorKind, ShapeError}; use crate::iterators::Baseiter; use crate::low_level_util::AbortIfPanic; -use crate::LayoutRef; use crate::OwnedRepr; use crate::Zip; From 1d5d6f4223be2e6bcf3c84c1edc649d9d2517cf7 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 22 Dec 2024 16:45:44 -0800 Subject: [PATCH 33/33] Generalize ref-to-ref ops to work with arbitrary output types --- src/impl_ops.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/impl_ops.rs b/src/impl_ops.rs index 53f49cc43..cb5249479 100644 --- a/src/impl_ops.rs +++ b/src/impl_ops.rs @@ -233,14 +233,14 @@ where /// **Panics** if broadcasting isn’t possible. impl<'a, A, B, S, S2, D, E> $trt<&'a ArrayBase> for &'a ArrayBase where - A: Clone + $trt, + A: Clone + $trt, B: Clone, S: Data, S2: Data, D: Dimension + DimMax, E: Dimension, { - type Output = Array>::Output>; + type Output = Array<
>::Output, >::Output>; #[track_caller] fn $mth(self, rhs: &'a ArrayBase) -> Self::Output { @@ -259,12 +259,12 @@ where /// **Panics** if broadcasting isn’t possible. impl<'a, A, B, D, E> $trt<&'a ArrayRef> for &'a ArrayRef where - A: Clone + $trt, + A: Clone + $trt, B: Clone, D: Dimension + DimMax, E: Dimension, { - type Output = Array>::Output>; + type Output = Array<>::Output, >::Output>; #[track_caller] fn $mth(self, rhs: &'a ArrayRef) -> Self::Output { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy