Skip to content

Commit

Permalink
Merge pull request #1004 from rust-ndarray/layout
Browse files Browse the repository at this point in the history
Reduce instantiated code (measured by cargo llvm-lines)
  • Loading branch information
bluss committed May 17, 2021
2 parents f81e7ca + 2ddc9db commit 71fba9b
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 49 deletions.
53 changes: 53 additions & 0 deletions src/data_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@ pub unsafe trait RawData: Sized {

#[doc(hidden)]
// This method is only used for debugging
#[deprecated(note="Unused", since="0.15.2")]
fn _data_slice(&self) -> Option<&[Self::Elem]>;

#[doc(hidden)]
fn _is_pointer_inbounds(&self, ptr: *const Self::Elem) -> bool;

private_decl! {}
}

Expand Down Expand Up @@ -146,9 +150,15 @@ pub unsafe trait DataMut: Data + RawDataMut {

unsafe impl<A> RawData for RawViewRepr<*const A> {
type Elem = A;

#[inline]
fn _data_slice(&self) -> Option<&[A]> {
None
}

#[inline(always)]
fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool { true }

private_impl! {}
}

Expand All @@ -160,9 +170,15 @@ unsafe impl<A> RawDataClone for RawViewRepr<*const A> {

unsafe impl<A> RawData for RawViewRepr<*mut A> {
type Elem = A;

#[inline]
fn _data_slice(&self) -> Option<&[A]> {
None
}

#[inline(always)]
fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool { true }

private_impl! {}
}

Expand Down Expand Up @@ -192,6 +208,11 @@ unsafe impl<A> RawData for OwnedArcRepr<A> {
fn _data_slice(&self) -> Option<&[A]> {
Some(self.0.as_slice())
}

fn _is_pointer_inbounds(&self, self_ptr: *const Self::Elem) -> bool {
self.0._is_pointer_inbounds(self_ptr)
}

private_impl! {}
}

Expand Down Expand Up @@ -274,9 +295,18 @@ unsafe impl<A> RawDataClone for OwnedArcRepr<A> {

unsafe impl<A> RawData for OwnedRepr<A> {
type Elem = A;

fn _data_slice(&self) -> Option<&[A]> {
Some(self.as_slice())
}

fn _is_pointer_inbounds(&self, self_ptr: *const Self::Elem) -> bool {
let slc = self.as_slice();
let ptr = slc.as_ptr() as *mut A;
let end = unsafe { ptr.add(slc.len()) };
self_ptr >= ptr && self_ptr <= end
}

private_impl! {}
}

Expand Down Expand Up @@ -340,9 +370,15 @@ where

unsafe impl<'a, A> RawData for ViewRepr<&'a A> {
type Elem = A;

#[inline]
fn _data_slice(&self) -> Option<&[A]> {
None
}

#[inline(always)]
fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool { true }

private_impl! {}
}

Expand All @@ -364,9 +400,15 @@ unsafe impl<'a, A> RawDataClone for ViewRepr<&'a A> {

unsafe impl<'a, A> RawData for ViewRepr<&'a mut A> {
type Elem = A;

#[inline]
fn _data_slice(&self) -> Option<&[A]> {
None
}

#[inline(always)]
fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool { true }

private_impl! {}
}

Expand Down Expand Up @@ -458,12 +500,23 @@ unsafe impl<A> DataOwned for OwnedArcRepr<A> {

unsafe impl<'a, A> RawData for CowRepr<'a, A> {
type Elem = A;

fn _data_slice(&self) -> Option<&[A]> {
#[allow(deprecated)]
match self {
CowRepr::View(view) => view._data_slice(),
CowRepr::Owned(data) => data._data_slice(),
}
}

#[inline]
fn _is_pointer_inbounds(&self, ptr: *const Self::Elem) -> bool {
match self {
CowRepr::View(view) => view._is_pointer_inbounds(ptr),
CowRepr::Owned(data) => data._is_pointer_inbounds(ptr),
}
}

private_impl! {}
}

Expand Down
50 changes: 50 additions & 0 deletions src/dimension/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,56 @@ pub fn slices_intersect<D: Dimension>(
true
}

pub(crate) fn is_layout_c<D: Dimension>(dim: &D, strides: &D) -> bool {
if let Some(1) = D::NDIM {
return strides[0] == 1 || dim[0] <= 1;
}

for &d in dim.slice() {
if d == 0 {
return true;
}
}

let mut contig_stride = 1_isize;
// check all dimensions -- a dimension of length 1 can have unequal strides
for (&dim, &s) in izip!(dim.slice().iter().rev(), strides.slice().iter().rev()) {
if dim != 1 {
let s = s as isize;
if s != contig_stride {
return false;
}
contig_stride *= dim as isize;
}
}
true
}

pub(crate) fn is_layout_f<D: Dimension>(dim: &D, strides: &D) -> bool {
if let Some(1) = D::NDIM {
return strides[0] == 1 || dim[0] <= 1;
}

for &d in dim.slice() {
if d == 0 {
return true;
}
}

let mut contig_stride = 1_isize;
// check all dimensions -- a dimension of length 1 can have unequal strides
for (&dim, &s) in izip!(dim.slice(), strides.slice()) {
if dim != 1 {
let s = s as isize;
if s != contig_stride {
return false;
}
contig_stride *= dim as isize;
}
}
true
}

pub fn merge_axes<D>(dim: &mut D, strides: &mut D, take: Axis, into: Axis) -> bool
where
D: Dimension,
Expand Down
30 changes: 2 additions & 28 deletions src/impl_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1382,23 +1382,7 @@ where
/// 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 {
fn is_standard_layout<D: Dimension>(dim: &D, strides: &D) -> bool {
if let Some(1) = D::NDIM {
return strides[0] == 1 || dim[0] <= 1;
}
if dim.slice().iter().any(|&d| d == 0) {
return true;
}
let defaults = dim.default_strides();
// check all dimensions -- a dimension of length 1 can have unequal strides
for (&dim, &s, &ds) in izip!(dim.slice(), strides.slice(), defaults.slice()) {
if dim != 1 && s != ds {
return false;
}
}
true
}
is_standard_layout(&self.dim, &self.strides)
dimension::is_layout_c(&self.dim, &self.strides)
}

/// Return true if the array is known to be contiguous.
Expand Down Expand Up @@ -2151,17 +2135,7 @@ where
}

pub(crate) fn pointer_is_inbounds(&self) -> bool {
match self.data._data_slice() {
None => {
// special case for non-owned views
true
}
Some(slc) => {
let ptr = slc.as_ptr() as *mut A;
let end = unsafe { ptr.add(slc.len()) };
self.ptr.as_ptr() >= ptr && self.ptr.as_ptr() <= end
}
}
self.data._is_pointer_inbounds(self.as_ptr())
}

/// Perform an elementwise assigment to `self` from `rhs`.
Expand Down
48 changes: 27 additions & 21 deletions src/zip/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::partial::Partial;

use crate::indexes::{indices, Indices};
use crate::split_at::{SplitPreference, SplitAt};
use crate::dimension;

pub use self::ndproducer::{NdProducer, IntoNdProducer, Offset};

Expand Down Expand Up @@ -51,33 +52,38 @@ where
private_decl! {}
}

/// Compute `Layout` hints for array shape dim, strides
fn array_layout<D: Dimension>(dim: &D, strides: &D) -> Layout {
let n = dim.ndim();
if dimension::is_layout_c(dim, strides) {
// effectively one-dimensional => C and F layout compatible
if n <= 1 || dim.slice().iter().filter(|&&len| len > 1).count() <= 1 {
Layout::one_dimensional()
} else {
Layout::c()
}
} else if n > 1 && dimension::is_layout_f(dim, strides) {
Layout::f()
} else if n > 1 {
if dim[0] > 1 && strides[0] == 1 {
Layout::fpref()
} else if dim[n - 1] > 1 && strides[n - 1] == 1 {
Layout::cpref()
} else {
Layout::none()
}
} else {
Layout::none()
}
}

impl<S, D> ArrayBase<S, D>
where
S: RawData,
D: Dimension,
{
pub(crate) fn layout_impl(&self) -> Layout {
let n = self.ndim();
if self.is_standard_layout() {
// effectively one-dimensional => C and F layout compatible
if n <= 1 || self.shape().iter().filter(|&&len| len > 1).count() <= 1 {
Layout::one_dimensional()
} else {
Layout::c()
}
} else if n > 1 && self.raw_view().reversed_axes().is_standard_layout() {
Layout::f()
} else if n > 1 {
if self.len_of(Axis(0)) > 1 && self.stride_of(Axis(0)) == 1 {
Layout::fpref()
} else if self.len_of(Axis(n - 1)) > 1 && self.stride_of(Axis(n - 1)) == 1 {
Layout::cpref()
} else {
Layout::none()
}
} else {
Layout::none()
}
array_layout(&self.dim, &self.strides)
}
}

Expand Down

0 comments on commit 71fba9b

Please sign in to comment.