From 99722fa3e82564a183d8bad5e6b0683750a60e7a Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Thu, 3 Oct 2024 20:52:20 -0400 Subject: [PATCH 01/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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/32] 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;