Skip to content

Commit a62b541

Browse files
committed
FIX: Add fast case for .into_dimensionality() no-op.
This case has most impact for IxDyn, the benchmark for const dims is unchanged (it was already fast).
1 parent 5ff79b1 commit a62b541

File tree

1 file changed

+37
-4
lines changed

1 file changed

+37
-4
lines changed

src/impl_methods.rs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9+
use std::mem::{size_of, ManuallyDrop};
910
use alloc::slice;
1011
use alloc::vec;
1112
use alloc::vec::Vec;
@@ -1583,8 +1584,11 @@ where
15831584
}
15841585
}
15851586

1586-
/// Convert an array or array view to another with the same type, but
1587-
/// different dimensionality type. Errors if the dimensions don't agree.
1587+
/// Convert an array or array view to another with the same type, but different dimensionality
1588+
/// type. Errors if the dimensions don't agree (the number of axes must match).
1589+
///
1590+
/// Note that conversion to a dynamic dimensional array will never fail (and is equivalent to
1591+
/// the `into_dyn` method).
15881592
///
15891593
/// ```
15901594
/// use ndarray::{ArrayD, Ix2, IxDyn};
@@ -1600,15 +1604,29 @@ where
16001604
where
16011605
D2: Dimension,
16021606
{
1603-
if let Some(dim) = D2::from_dimension(&self.dim) {
1604-
if let Some(strides) = D2::from_dimension(&self.strides) {
1607+
if D::NDIM == D2::NDIM {
1608+
// safe because D == D2
1609+
unsafe {
1610+
let dim = unlimited_transmute::<D, D2>(self.dim);
1611+
let strides = unlimited_transmute::<D, D2>(self.strides);
16051612
return Ok(ArrayBase {
16061613
data: self.data,
16071614
ptr: self.ptr,
16081615
dim,
16091616
strides,
16101617
});
16111618
}
1619+
} else if D::NDIM == None || D2::NDIM == None { // one is dynamic dim
1620+
if let Some(dim) = D2::from_dimension(&self.dim) {
1621+
if let Some(strides) = D2::from_dimension(&self.strides) {
1622+
return Ok(ArrayBase {
1623+
data: self.data,
1624+
ptr: self.ptr,
1625+
dim,
1626+
strides,
1627+
});
1628+
}
1629+
}
16121630
}
16131631
Err(ShapeError::from_kind(ErrorKind::IncompatibleShape))
16141632
}
@@ -2375,3 +2393,18 @@ where
23752393
});
23762394
}
23772395
}
2396+
2397+
2398+
/// Transmute from A to B.
2399+
///
2400+
/// Like transmute, but does not have the compile-time size check which blocks
2401+
/// using regular transmute in some cases.
2402+
///
2403+
/// **Panics** if the size of A and B are different.
2404+
#[inline]
2405+
unsafe fn unlimited_transmute<A, B>(data: A) -> B {
2406+
// safe when sizes are equal and caller guarantees that representations are equal
2407+
assert_eq!(size_of::<A>(), size_of::<B>());
2408+
let old_data = ManuallyDrop::new(data);
2409+
(&*old_data as *const A as *const B).read()
2410+
}

0 commit comments

Comments
 (0)