Skip to content

Commit 71fba9b

Browse files
authored
Merge pull request #1004 from rust-ndarray/layout
Reduce instantiated code (measured by cargo llvm-lines)
2 parents f81e7ca + 2ddc9db commit 71fba9b

File tree

4 files changed

+132
-49
lines changed

4 files changed

+132
-49
lines changed

src/data_traits.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ pub unsafe trait RawData: Sized {
3333

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

39+
#[doc(hidden)]
40+
fn _is_pointer_inbounds(&self, ptr: *const Self::Elem) -> bool;
41+
3842
private_decl! {}
3943
}
4044

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

147151
unsafe impl<A> RawData for RawViewRepr<*const A> {
148152
type Elem = A;
153+
154+
#[inline]
149155
fn _data_slice(&self) -> Option<&[A]> {
150156
None
151157
}
158+
159+
#[inline(always)]
160+
fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool { true }
161+
152162
private_impl! {}
153163
}
154164

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

161171
unsafe impl<A> RawData for RawViewRepr<*mut A> {
162172
type Elem = A;
173+
174+
#[inline]
163175
fn _data_slice(&self) -> Option<&[A]> {
164176
None
165177
}
178+
179+
#[inline(always)]
180+
fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool { true }
181+
166182
private_impl! {}
167183
}
168184

@@ -192,6 +208,11 @@ unsafe impl<A> RawData for OwnedArcRepr<A> {
192208
fn _data_slice(&self) -> Option<&[A]> {
193209
Some(self.0.as_slice())
194210
}
211+
212+
fn _is_pointer_inbounds(&self, self_ptr: *const Self::Elem) -> bool {
213+
self.0._is_pointer_inbounds(self_ptr)
214+
}
215+
195216
private_impl! {}
196217
}
197218

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

275296
unsafe impl<A> RawData for OwnedRepr<A> {
276297
type Elem = A;
298+
277299
fn _data_slice(&self) -> Option<&[A]> {
278300
Some(self.as_slice())
279301
}
302+
303+
fn _is_pointer_inbounds(&self, self_ptr: *const Self::Elem) -> bool {
304+
let slc = self.as_slice();
305+
let ptr = slc.as_ptr() as *mut A;
306+
let end = unsafe { ptr.add(slc.len()) };
307+
self_ptr >= ptr && self_ptr <= end
308+
}
309+
280310
private_impl! {}
281311
}
282312

@@ -340,9 +370,15 @@ where
340370

341371
unsafe impl<'a, A> RawData for ViewRepr<&'a A> {
342372
type Elem = A;
373+
374+
#[inline]
343375
fn _data_slice(&self) -> Option<&[A]> {
344376
None
345377
}
378+
379+
#[inline(always)]
380+
fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool { true }
381+
346382
private_impl! {}
347383
}
348384

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

365401
unsafe impl<'a, A> RawData for ViewRepr<&'a mut A> {
366402
type Elem = A;
403+
404+
#[inline]
367405
fn _data_slice(&self) -> Option<&[A]> {
368406
None
369407
}
408+
409+
#[inline(always)]
410+
fn _is_pointer_inbounds(&self, _ptr: *const Self::Elem) -> bool { true }
411+
370412
private_impl! {}
371413
}
372414

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

459501
unsafe impl<'a, A> RawData for CowRepr<'a, A> {
460502
type Elem = A;
503+
461504
fn _data_slice(&self) -> Option<&[A]> {
505+
#[allow(deprecated)]
462506
match self {
463507
CowRepr::View(view) => view._data_slice(),
464508
CowRepr::Owned(data) => data._data_slice(),
465509
}
466510
}
511+
512+
#[inline]
513+
fn _is_pointer_inbounds(&self, ptr: *const Self::Elem) -> bool {
514+
match self {
515+
CowRepr::View(view) => view._is_pointer_inbounds(ptr),
516+
CowRepr::Owned(data) => data._is_pointer_inbounds(ptr),
517+
}
518+
}
519+
467520
private_impl! {}
468521
}
469522

src/dimension/mod.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,56 @@ pub fn slices_intersect<D: Dimension>(
668668
true
669669
}
670670

671+
pub(crate) fn is_layout_c<D: Dimension>(dim: &D, strides: &D) -> bool {
672+
if let Some(1) = D::NDIM {
673+
return strides[0] == 1 || dim[0] <= 1;
674+
}
675+
676+
for &d in dim.slice() {
677+
if d == 0 {
678+
return true;
679+
}
680+
}
681+
682+
let mut contig_stride = 1_isize;
683+
// check all dimensions -- a dimension of length 1 can have unequal strides
684+
for (&dim, &s) in izip!(dim.slice().iter().rev(), strides.slice().iter().rev()) {
685+
if dim != 1 {
686+
let s = s as isize;
687+
if s != contig_stride {
688+
return false;
689+
}
690+
contig_stride *= dim as isize;
691+
}
692+
}
693+
true
694+
}
695+
696+
pub(crate) fn is_layout_f<D: Dimension>(dim: &D, strides: &D) -> bool {
697+
if let Some(1) = D::NDIM {
698+
return strides[0] == 1 || dim[0] <= 1;
699+
}
700+
701+
for &d in dim.slice() {
702+
if d == 0 {
703+
return true;
704+
}
705+
}
706+
707+
let mut contig_stride = 1_isize;
708+
// check all dimensions -- a dimension of length 1 can have unequal strides
709+
for (&dim, &s) in izip!(dim.slice(), strides.slice()) {
710+
if dim != 1 {
711+
let s = s as isize;
712+
if s != contig_stride {
713+
return false;
714+
}
715+
contig_stride *= dim as isize;
716+
}
717+
}
718+
true
719+
}
720+
671721
pub fn merge_axes<D>(dim: &mut D, strides: &mut D, take: Axis, into: Axis) -> bool
672722
where
673723
D: Dimension,

src/impl_methods.rs

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,23 +1382,7 @@ where
13821382
/// Return `false` otherwise, i.e. the array is possibly not
13831383
/// contiguous in memory, it has custom strides, etc.
13841384
pub fn is_standard_layout(&self) -> bool {
1385-
fn is_standard_layout<D: Dimension>(dim: &D, strides: &D) -> bool {
1386-
if let Some(1) = D::NDIM {
1387-
return strides[0] == 1 || dim[0] <= 1;
1388-
}
1389-
if dim.slice().iter().any(|&d| d == 0) {
1390-
return true;
1391-
}
1392-
let defaults = dim.default_strides();
1393-
// check all dimensions -- a dimension of length 1 can have unequal strides
1394-
for (&dim, &s, &ds) in izip!(dim.slice(), strides.slice(), defaults.slice()) {
1395-
if dim != 1 && s != ds {
1396-
return false;
1397-
}
1398-
}
1399-
true
1400-
}
1401-
is_standard_layout(&self.dim, &self.strides)
1385+
dimension::is_layout_c(&self.dim, &self.strides)
14021386
}
14031387

14041388
/// Return true if the array is known to be contiguous.
@@ -2151,17 +2135,7 @@ where
21512135
}
21522136

21532137
pub(crate) fn pointer_is_inbounds(&self) -> bool {
2154-
match self.data._data_slice() {
2155-
None => {
2156-
// special case for non-owned views
2157-
true
2158-
}
2159-
Some(slc) => {
2160-
let ptr = slc.as_ptr() as *mut A;
2161-
let end = unsafe { ptr.add(slc.len()) };
2162-
self.ptr.as_ptr() >= ptr && self.ptr.as_ptr() <= end
2163-
}
2164-
}
2138+
self.data._is_pointer_inbounds(self.as_ptr())
21652139
}
21662140

21672141
/// Perform an elementwise assigment to `self` from `rhs`.

src/zip/mod.rs

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::partial::Partial;
2121

2222
use crate::indexes::{indices, Indices};
2323
use crate::split_at::{SplitPreference, SplitAt};
24+
use crate::dimension;
2425

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

@@ -51,33 +52,38 @@ where
5152
private_decl! {}
5253
}
5354

55+
/// Compute `Layout` hints for array shape dim, strides
56+
fn array_layout<D: Dimension>(dim: &D, strides: &D) -> Layout {
57+
let n = dim.ndim();
58+
if dimension::is_layout_c(dim, strides) {
59+
// effectively one-dimensional => C and F layout compatible
60+
if n <= 1 || dim.slice().iter().filter(|&&len| len > 1).count() <= 1 {
61+
Layout::one_dimensional()
62+
} else {
63+
Layout::c()
64+
}
65+
} else if n > 1 && dimension::is_layout_f(dim, strides) {
66+
Layout::f()
67+
} else if n > 1 {
68+
if dim[0] > 1 && strides[0] == 1 {
69+
Layout::fpref()
70+
} else if dim[n - 1] > 1 && strides[n - 1] == 1 {
71+
Layout::cpref()
72+
} else {
73+
Layout::none()
74+
}
75+
} else {
76+
Layout::none()
77+
}
78+
}
79+
5480
impl<S, D> ArrayBase<S, D>
5581
where
5682
S: RawData,
5783
D: Dimension,
5884
{
5985
pub(crate) fn layout_impl(&self) -> Layout {
60-
let n = self.ndim();
61-
if self.is_standard_layout() {
62-
// effectively one-dimensional => C and F layout compatible
63-
if n <= 1 || self.shape().iter().filter(|&&len| len > 1).count() <= 1 {
64-
Layout::one_dimensional()
65-
} else {
66-
Layout::c()
67-
}
68-
} else if n > 1 && self.raw_view().reversed_axes().is_standard_layout() {
69-
Layout::f()
70-
} else if n > 1 {
71-
if self.len_of(Axis(0)) > 1 && self.stride_of(Axis(0)) == 1 {
72-
Layout::fpref()
73-
} else if self.len_of(Axis(n - 1)) > 1 && self.stride_of(Axis(n - 1)) == 1 {
74-
Layout::cpref()
75-
} else {
76-
Layout::none()
77-
}
78-
} else {
79-
Layout::none()
80-
}
86+
array_layout(&self.dim, &self.strides)
8187
}
8288
}
8389

0 commit comments

Comments
 (0)