Skip to content

Commit 0e4b8ae

Browse files
committed
shape: Reimplement into_shape()
1 parent 27b49b9 commit 0e4b8ae

File tree

1 file changed

+211
-27
lines changed

1 file changed

+211
-27
lines changed

src/impl_methods.rs

Lines changed: 211 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::imp_prelude::*;
1616

1717
use crate::{arraytraits, DimMax};
1818
use crate::argument_traits::AssignElem;
19+
use crate::data_traits::IfOwnedCb;
1920
use crate::dimension;
2021
use crate::dimension::IntoDimension;
2122
use crate::dimension::{
@@ -1646,18 +1647,7 @@ where
16461647
}
16471648
let layout = self.layout_impl();
16481649
if order == Order::Automatic {
1649-
// the order of the conditionals is significant for preference
1650-
if layout.is(Layout::CORDER) {
1651-
order = Order::RowMajor;
1652-
} else if layout.is(Layout::FORDER) {
1653-
order = Order::ColumnMajor;
1654-
} else if layout.is(Layout::CPREFER) {
1655-
order = Order::RowMajor;
1656-
} else if layout.is(Layout::FPREFER) {
1657-
order = Order::ColumnMajor;
1658-
} else {
1659-
order = Order::RowMajor;
1660-
}
1650+
order = preferred_order_for_layout(layout);
16611651
}
16621652

16631653
unsafe {
@@ -1682,43 +1672,183 @@ where
16821672
}
16831673
}
16841674

1685-
/// Transform the array into `shape`; any shape with the same number of
1686-
/// elements is accepted, but the source array or view must be in standard
1687-
/// or column-major (Fortran) layout.
1675+
/// Transform the array into `shape`; any shape with the same number of elements is accepted,
1676+
/// but the source array or view must be in contiguous and stored in standard row-major (C) or
1677+
/// column-major (Fortran) memory order.
1678+
///
1679+
/// **Warning:** this method will automatically decide which ordering (row-major or
1680+
/// column-major) to use for rearranging the elements. Use `as_shape` if more
1681+
/// control is needed. Note that one-dimensional contiguous arrays will be regarded
1682+
/// as row major.
16881683
///
1689-
/// **Errors** if the shapes don't have the same number of elements.<br>
1690-
/// **Errors** if the input array is not c- or f-contiguous.
1684+
/// **Errors** if the new shape doesn't have the same number of elements as the array's current
1685+
/// shape.<br>
1686+
/// **Errors** if the input array is not C- or F-contiguous.
16911687
///
16921688
/// ```
1693-
/// use ndarray::{aview1, aview2};
1689+
/// use ndarray::array;
16941690
///
16951691
/// assert!(
1696-
/// aview1(&[1., 2., 3., 4.]).into_shape((2, 2)).unwrap()
1697-
/// == aview2(&[[1., 2.],
1698-
/// [3., 4.]])
1692+
/// array![1., 2., 3., 4.].coerce_shape_c((2, 2)).unwrap()
1693+
/// == array![[1., 2.],
1694+
/// [3., 4.]]
16991695
/// );
17001696
/// ```
1701-
pub fn into_shape<E>(self, shape: E) -> Result<ArrayBase<S, E::Dim>, ShapeError>
1697+
#[deprecated(note="Replaced by one of `to_shape`, `coerce_shape_c`, `coerce_shape_f` \
1698+
and `into_shape_owned`.", since="0.15.0")]
1699+
pub fn into_shape_<E>(self, shape: E) -> Result<ArrayBase<S, E::Dim>, ShapeError>
1700+
where
1701+
E: IntoDimension,
1702+
{
1703+
self.coerce_shape_with_order(shape, Order::Automatic)
1704+
}
1705+
1706+
/// Transform the array into `shape`; any shape with the same number of elements is accepted,
1707+
/// but the source array or view must be contiguous and stored in standard row-major (C) memory
1708+
/// order.
1709+
///
1710+
/// This method allows any array, view or raw view and never copies elements.
1711+
///
1712+
/// **Errors** if the new shape doesn't have the same number of elements as the array's current
1713+
/// shape.<br>
1714+
/// **Errors** if the input array is not C-contiguous.
1715+
///
1716+
/// ```
1717+
/// use ndarray::array;
1718+
///
1719+
/// assert!(
1720+
/// array![1., 2., 3., 4.].coerce_shape_c((2, 2)).unwrap()
1721+
/// == array![[1., 2.],
1722+
/// [3., 4.]]
1723+
/// );
1724+
/// ```
1725+
pub fn coerce_shape_c<E>(self, shape: E) -> Result<ArrayBase<S, E::Dim>, ShapeError>
1726+
where
1727+
E: IntoDimension,
1728+
{
1729+
self.coerce_shape_with_order(shape, Order::RowMajor)
1730+
}
1731+
1732+
/// Transform the array into `shape`; any shape with the same number of elements is accepted,
1733+
/// but the source array or view must be contiguous and stored in column-major (F) memory
1734+
/// order.
1735+
///
1736+
/// This method allows any array, view or raw view and never copies elements.
1737+
///
1738+
/// **Errors** if the new shape doesn't have the same number of elements as the array's current
1739+
/// shape.<br>
1740+
/// **Errors** if the input array is not F-contiguous.
1741+
///
1742+
/// ```
1743+
/// use ndarray::array;
1744+
///
1745+
/// assert!(
1746+
/// array![1., 2., 3., 4.].coerce_shape_f((2, 2)).unwrap()
1747+
/// == array![[1., 3.],
1748+
/// [2., 4.]]
1749+
/// );
1750+
/// ```
1751+
pub fn coerce_shape_f<E>(self, shape: E) -> Result<ArrayBase<S, E::Dim>, ShapeError>
1752+
where
1753+
E: IntoDimension,
1754+
{
1755+
self.coerce_shape_with_order(shape, Order::ColumnMajor)
1756+
}
1757+
1758+
fn coerce_shape_with_order<E>(self, shape: E, mut order: Order)
1759+
-> Result<ArrayBase<S, E::Dim>, ShapeError>
17021760
where
17031761
E: IntoDimension,
17041762
{
17051763
let shape = shape.into_dimension();
17061764
if size_of_shape_checked(&shape) != Ok(self.dim.size()) {
17071765
return Err(error::incompatible_shapes(&self.dim, &shape));
17081766
}
1709-
// Check if contiguous, if not => copy all, else just adapt strides
1767+
1768+
let layout = self.layout_impl();
1769+
if order == Order::Automatic {
1770+
order = preferred_order_for_layout(layout);
1771+
}
1772+
1773+
// safe because: the number of elements is preserved and it's contiguous
17101774
unsafe {
1711-
// safe because arrays are contiguous and len is unchanged
1712-
if self.is_standard_layout() {
1775+
if layout.is(Layout::CORDER) && order == Order::RowMajor {
17131776
Ok(self.with_strides_dim(shape.default_strides(), shape))
1714-
} else if self.ndim() > 1 && self.raw_view().reversed_axes().is_standard_layout() {
1777+
} else if layout.is(Layout::FORDER) && order == Order::ColumnMajor {
17151778
Ok(self.with_strides_dim(shape.fortran_strides(), shape))
17161779
} else {
17171780
Err(error::from_kind(error::ErrorKind::IncompatibleLayout))
17181781
}
17191782
}
17201783
}
17211784

1785+
/// Transform the array into `new_shape`; any shape with the same number of elements is
1786+
/// accepted.
1787+
///
1788+
/// `order` specifies the *logical* order in which the array is to be read and reshaped. The
1789+
/// input array must be an owned array. It is updated and returned if possible, otherwise
1790+
/// elements are copied to be rearranged for the new shape and the new array returned.
1791+
///
1792+
/// **Panics** if shapes are incompatible.
1793+
///
1794+
/// **Errors** if the new shape doesn't have the same number of elements as the array's current
1795+
/// shape.
1796+
///
1797+
/// ```
1798+
/// use ndarray::array;
1799+
/// use ndarray::Order;
1800+
///
1801+
/// assert!(
1802+
/// array![1., 2., 3., 4., 5., 6.].into_shape((2, 3)).unwrap()
1803+
/// == array![[1., 2., 3.],
1804+
/// [4., 5., 6.]]
1805+
/// );
1806+
///
1807+
/// assert!(
1808+
/// array![1., 2., 3., 4., 5., 6.].into_shape(((2, 3), Order::ColumnMajor)).unwrap()
1809+
/// == array![[1., 3., 5.],
1810+
/// [2., 4., 6.]]
1811+
/// );
1812+
/// ```
1813+
pub fn into_shape<E>(self, new_shape: E) -> Result<ArrayBase<S, E::Dim>, ShapeError>
1814+
where
1815+
E: ShapeArg<StrideType = Contiguous>,
1816+
{
1817+
let (new_shape, order) = new_shape.into_shape_and_order(Order::RowMajor);
1818+
self.into_shape_order(new_shape, order)
1819+
}
1820+
1821+
fn into_shape_order<E>(self, shape: E, mut order: Order)
1822+
-> Result<ArrayBase<S, E>, ShapeError>
1823+
where
1824+
E: Dimension,
1825+
{
1826+
if size_of_shape_checked(&shape) != Ok(self.dim.size()) {
1827+
return Err(error::incompatible_shapes(&self.dim, &shape));
1828+
}
1829+
1830+
let layout = self.layout_impl();
1831+
if order == Order::Automatic {
1832+
order = preferred_order_for_layout(layout);
1833+
}
1834+
1835+
// safe because: the number of elements is preserved and it's contiguous
1836+
unsafe {
1837+
if layout.is(Layout::CORDER) && order == Order::RowMajor {
1838+
Ok(self.with_strides_dim(shape.default_strides(), shape))
1839+
} else if layout.is(Layout::FORDER) && order == Order::ColumnMajor {
1840+
Ok(self.with_strides_dim(shape.fortran_strides(), shape))
1841+
} else {
1842+
// Try to adapt shape as `Array` if applicable
1843+
if let Some(res) = S::map_if_owned(self, IntoShapeOwnedCb { order, shape }) {
1844+
res
1845+
} else {
1846+
Err(error::from_kind(error::ErrorKind::IncompatibleLayout))
1847+
}
1848+
}
1849+
}
1850+
}
1851+
17221852
/// *Note: Reshape is for `ArcArray` only. Use `.into_shape()` for
17231853
/// other arrays and array views.*
17241854
///
@@ -2651,7 +2781,6 @@ where
26512781
}
26522782
}
26532783

2654-
26552784
/// Transmute from A to B.
26562785
///
26572786
/// Like transmute, but does not have the compile-time size check which blocks
@@ -2667,3 +2796,58 @@ unsafe fn unlimited_transmute<A, B>(data: A) -> B {
26672796
}
26682797

26692798
type DimMaxOf<A, B> = <A as DimMax<B>>::Output;
2799+
2800+
#[inline]
2801+
fn preferred_order_for_layout(layout: Layout) -> Order {
2802+
// the order of the conditionals is significant for preference
2803+
if layout.is(Layout::CORDER) {
2804+
Order::RowMajor
2805+
} else if layout.is(Layout::FORDER) {
2806+
Order::ColumnMajor
2807+
} else if layout.is(Layout::CPREFER) {
2808+
Order::RowMajor
2809+
} else if layout.is(Layout::FPREFER) {
2810+
Order::ColumnMajor
2811+
} else {
2812+
Order::RowMajor
2813+
}
2814+
}
2815+
2816+
struct IntoShapeOwnedCb<E> {
2817+
order: Order,
2818+
shape: E,
2819+
}
2820+
2821+
impl<S, D, E> IfOwnedCb<S, D> for IntoShapeOwnedCb<E>
2822+
where
2823+
S: RawData,
2824+
D: Dimension,
2825+
E: Dimension,
2826+
{
2827+
type Output = Result<ArrayBase<S, E>, ShapeError>;
2828+
fn cb(self, array: Array<S::Elem, D>) -> Self::Output
2829+
where
2830+
S: DataOwned,
2831+
D: Dimension,
2832+
{
2833+
let shape = self.shape;
2834+
let order = self.order;
2835+
2836+
unsafe {
2837+
let (iter, shape) = match order {
2838+
Order::RowMajor => {
2839+
let iter = array.into_iter();
2840+
(iter, shape.set_f(false))
2841+
}
2842+
Order::ColumnMajor => {
2843+
let iter = array.reversed_axes().into_iter();
2844+
(iter, shape.set_f(true))
2845+
},
2846+
/* order automatic ruled out */
2847+
Order::Automatic => unreachable!(),
2848+
};
2849+
Ok(ArrayBase::from_shape_trusted_iter_unchecked(
2850+
shape, iter, |x| x))
2851+
}
2852+
}
2853+
}

0 commit comments

Comments
 (0)