Skip to content

Commit cd0a956

Browse files
authored
Merge pull request #1132 from jturner314/const-constructors
Make the aview0, aview1, and aview2 free functions be const fns
2 parents eb12613 + cab158f commit cd0a956

File tree

8 files changed

+103
-50
lines changed

8 files changed

+103
-50
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
- stable
3535
- beta
3636
- nightly
37-
- 1.51.0 # MSRV
37+
- 1.57.0 # MSRV
3838

3939
name: tests/${{ matrix.rust }}
4040
steps:

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
name = "ndarray"
44
version = "0.15.6"
55
edition = "2018"
6-
rust-version = "1.51"
6+
rust-version = "1.57"
77
authors = [
88
"Ulrik Sverdrup \"bluss\"",
99
"Jim Turner"

scripts/all-tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ set -e
66
FEATURES=$1
77
CHANNEL=$2
88

9-
if [ "$CHANNEL" = "1.51.0" ]; then
9+
if [ "$CHANNEL" = "1.57.0" ]; then
1010
cargo update --package openblas-src --precise 0.10.5
1111
cargo update --package openblas-build --precise 0.10.5
1212
cargo update --package once_cell --precise 1.14.0

src/aliases.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,43 @@ use crate::{ArcArray, Array, ArrayView, ArrayViewMut, Ix, IxDynImpl};
77
/// Create a zero-dimensional index
88
#[allow(non_snake_case)]
99
#[inline(always)]
10-
pub fn Ix0() -> Ix0 {
10+
pub const fn Ix0() -> Ix0 {
1111
Dim::new([])
1212
}
1313
/// Create a one-dimensional index
1414
#[allow(non_snake_case)]
1515
#[inline(always)]
16-
pub fn Ix1(i0: Ix) -> Ix1 {
16+
pub const fn Ix1(i0: Ix) -> Ix1 {
1717
Dim::new([i0])
1818
}
1919
/// Create a two-dimensional index
2020
#[allow(non_snake_case)]
2121
#[inline(always)]
22-
pub fn Ix2(i0: Ix, i1: Ix) -> Ix2 {
22+
pub const fn Ix2(i0: Ix, i1: Ix) -> Ix2 {
2323
Dim::new([i0, i1])
2424
}
2525
/// Create a three-dimensional index
2626
#[allow(non_snake_case)]
2727
#[inline(always)]
28-
pub fn Ix3(i0: Ix, i1: Ix, i2: Ix) -> Ix3 {
28+
pub const fn Ix3(i0: Ix, i1: Ix, i2: Ix) -> Ix3 {
2929
Dim::new([i0, i1, i2])
3030
}
3131
/// Create a four-dimensional index
3232
#[allow(non_snake_case)]
3333
#[inline(always)]
34-
pub fn Ix4(i0: Ix, i1: Ix, i2: Ix, i3: Ix) -> Ix4 {
34+
pub const fn Ix4(i0: Ix, i1: Ix, i2: Ix, i3: Ix) -> Ix4 {
3535
Dim::new([i0, i1, i2, i3])
3636
}
3737
/// Create a five-dimensional index
3838
#[allow(non_snake_case)]
3939
#[inline(always)]
40-
pub fn Ix5(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix) -> Ix5 {
40+
pub const fn Ix5(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix) -> Ix5 {
4141
Dim::new([i0, i1, i2, i3, i4])
4242
}
4343
/// Create a six-dimensional index
4444
#[allow(non_snake_case)]
4545
#[inline(always)]
46-
pub fn Ix6(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix, i5: Ix) -> Ix6 {
46+
pub const fn Ix6(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix, i5: Ix) -> Ix6 {
4747
Dim::new([i0, i1, i2, i3, i4, i5])
4848
}
4949

src/arraytraits.rs

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,10 @@ pub const ARRAY_FORMAT_VERSION: u8 = 1u8;
307307

308308
// use "raw" form instead of type aliases here so that they show up in docs
309309
/// Implementation of `ArrayView::from(&S)` where `S` is a slice or sliceable.
310+
///
311+
/// **Panics** if the length of the slice overflows `isize`. (This can only
312+
/// occur if `A` is zero-sized, because slices cannot contain more than
313+
/// `isize::MAX` number of bytes.)
310314
impl<'a, A, Slice: ?Sized> From<&'a Slice> for ArrayView<'a, A, Ix1>
311315
where
312316
Slice: AsRef<[A]>,
@@ -315,14 +319,7 @@ where
315319
///
316320
/// **Panics** if the slice length is greater than `isize::MAX`.
317321
fn from(slice: &'a Slice) -> Self {
318-
let xs = slice.as_ref();
319-
if mem::size_of::<A>() == 0 {
320-
assert!(
321-
xs.len() <= ::std::isize::MAX as usize,
322-
"Slice length must fit in `isize`.",
323-
);
324-
}
325-
unsafe { Self::from_shape_ptr(xs.len(), xs.as_ptr()) }
322+
aview1(slice.as_ref())
326323
}
327324
}
328325

@@ -334,25 +331,7 @@ where
334331
impl<'a, A, const N: usize> From<&'a [[A; N]]> for ArrayView<'a, A, Ix2> {
335332
/// Create a two-dimensional read-only array view of the data in `slice`
336333
fn from(xs: &'a [[A; N]]) -> Self {
337-
let cols = N;
338-
let rows = xs.len();
339-
let dim = Ix2(rows, cols);
340-
if size_of::<A>() == 0 {
341-
dimension::size_of_shape_checked(&dim)
342-
.expect("Product of non-zero axis lengths must not overflow isize.");
343-
} else if N == 0 {
344-
assert!(
345-
xs.len() <= isize::MAX as usize,
346-
"Product of non-zero axis lengths must not overflow isize.",
347-
);
348-
}
349-
350-
// `cols * rows` is guaranteed to fit in `isize` because we checked that it fits in
351-
// `isize::MAX`
352-
unsafe {
353-
let data = slice::from_raw_parts(xs.as_ptr() as *const A, cols * rows);
354-
ArrayView::from_shape_ptr(dim, data.as_ptr())
355-
}
334+
aview2(xs)
356335
}
357336
}
358337

src/dimension/dim.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub struct Dim<I: ?Sized> {
4242

4343
impl<I> Dim<I> {
4444
/// Private constructor and accessors for Dim
45-
pub(crate) fn new(index: I) -> Dim<I> {
45+
pub(crate) const fn new(index: I) -> Dim<I> {
4646
Dim { index }
4747
}
4848
#[inline(always)]

src/free_functions.rs

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use alloc::vec;
1010
#[cfg(not(feature = "std"))]
1111
use alloc::vec::Vec;
1212
use std::mem::{forget, size_of};
13+
use std::ptr::NonNull;
1314

1415
use crate::imp_prelude::*;
1516
use crate::{dimension, ArcArray1, ArcArray2};
@@ -65,32 +66,105 @@ pub fn rcarr1<A: Clone>(xs: &[A]) -> ArcArray1<A> {
6566
}
6667

6768
/// Create a zero-dimensional array view borrowing `x`.
68-
pub fn aview0<A>(x: &A) -> ArrayView0<'_, A> {
69-
unsafe { ArrayView::from_shape_ptr(Ix0(), x) }
69+
pub const fn aview0<A>(x: &A) -> ArrayView0<'_, A> {
70+
ArrayBase {
71+
data: ViewRepr::new(),
72+
// Safe because references are always non-null.
73+
ptr: unsafe { NonNull::new_unchecked(x as *const A as *mut A) },
74+
dim: Ix0(),
75+
strides: Ix0(),
76+
}
7077
}
7178

7279
/// Create a one-dimensional array view with elements borrowing `xs`.
7380
///
81+
/// **Panics** if the length of the slice overflows `isize`. (This can only
82+
/// occur if `A` is zero-sized, because slices cannot contain more than
83+
/// `isize::MAX` number of bytes.)
84+
///
7485
/// ```
75-
/// use ndarray::aview1;
86+
/// use ndarray::{aview1, ArrayView1};
7687
///
7788
/// let data = [1.0; 1024];
7889
///
7990
/// // Create a 2D array view from borrowed data
8091
/// let a2d = aview1(&data).into_shape((32, 32)).unwrap();
8192
///
8293
/// assert_eq!(a2d.sum(), 1024.0);
94+
///
95+
/// // Create a const 1D array view
96+
/// const C: ArrayView1<'static, f64> = aview1(&[1., 2., 3.]);
97+
///
98+
/// assert_eq!(C.sum(), 6.);
8399
/// ```
84-
pub fn aview1<A>(xs: &[A]) -> ArrayView1<'_, A> {
85-
ArrayView::from(xs)
100+
pub const fn aview1<A>(xs: &[A]) -> ArrayView1<'_, A> {
101+
if size_of::<A>() == 0 {
102+
assert!(
103+
xs.len() <= isize::MAX as usize,
104+
"Slice length must fit in `isize`.",
105+
);
106+
}
107+
ArrayBase {
108+
data: ViewRepr::new(),
109+
// Safe because references are always non-null.
110+
ptr: unsafe { NonNull::new_unchecked(xs.as_ptr() as *mut A) },
111+
dim: Ix1(xs.len()),
112+
strides: Ix1(1),
113+
}
86114
}
87115

88116
/// Create a two-dimensional array view with elements borrowing `xs`.
89117
///
90-
/// **Panics** if the product of non-zero axis lengths overflows `isize` (This can only occur if A
91-
/// is zero-sized because slices cannot contain more than `isize::MAX` number of bytes).
92-
pub fn aview2<A, const N: usize>(xs: &[[A; N]]) -> ArrayView2<'_, A> {
93-
ArrayView2::from(xs)
118+
/// **Panics** if the product of non-zero axis lengths overflows `isize` (This
119+
/// can only occur if A is zero-sized or if `N` is zero, because slices cannot
120+
/// contain more than `isize::MAX` number of bytes).
121+
///
122+
/// ```
123+
/// use ndarray::{aview2, ArrayView2};
124+
///
125+
/// let data = vec![[1., 2., 3.], [4., 5., 6.]];
126+
///
127+
/// let view = aview2(&data);
128+
/// assert_eq!(view.sum(), 21.);
129+
///
130+
/// // Create a const 2D array view
131+
/// const C: ArrayView2<'static, f64> = aview2(&[[1., 2., 3.], [4., 5., 6.]]);
132+
/// assert_eq!(C.sum(), 21.);
133+
/// ```
134+
pub const fn aview2<A, const N: usize>(xs: &[[A; N]]) -> ArrayView2<'_, A> {
135+
let cols = N;
136+
let rows = xs.len();
137+
if size_of::<A>() == 0 {
138+
if let Some(n_elems) = rows.checked_mul(cols) {
139+
assert!(
140+
rows <= isize::MAX as usize
141+
&& cols <= isize::MAX as usize
142+
&& n_elems <= isize::MAX as usize,
143+
"Product of non-zero axis lengths must not overflow isize.",
144+
);
145+
} else {
146+
panic!("Overflow in number of elements.");
147+
}
148+
} else if N == 0 {
149+
assert!(
150+
rows <= isize::MAX as usize,
151+
"Product of non-zero axis lengths must not overflow isize.",
152+
);
153+
}
154+
// Safe because references are always non-null.
155+
let ptr = unsafe { NonNull::new_unchecked(xs.as_ptr() as *mut A) };
156+
let dim = Ix2(rows, cols);
157+
let strides = if rows == 0 || cols == 0 {
158+
Ix2(0, 0)
159+
} else {
160+
Ix2(cols, 1)
161+
};
162+
ArrayBase {
163+
data: ViewRepr::new(),
164+
ptr,
165+
dim,
166+
strides,
167+
}
94168
}
95169

96170
/// Create a one-dimensional read-write array view with elements borrowing `xs`.

src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
//! needs matching memory layout to be efficient (with some exceptions).
7272
//! + Efficient floating point matrix multiplication even for very large
7373
//! matrices; can optionally use BLAS to improve it further.
74-
//! - **Requires Rust 1.51 or later**
74+
//! - **Requires Rust 1.57 or later**
7575
//!
7676
//! ## Crate Feature Flags
7777
//!
@@ -1450,7 +1450,7 @@ pub struct RawViewRepr<A> {
14501450

14511451
impl<A> RawViewRepr<A> {
14521452
#[inline(always)]
1453-
fn new() -> Self {
1453+
const fn new() -> Self {
14541454
RawViewRepr { ptr: PhantomData }
14551455
}
14561456
}
@@ -1467,7 +1467,7 @@ pub struct ViewRepr<A> {
14671467

14681468
impl<A> ViewRepr<A> {
14691469
#[inline(always)]
1470-
fn new() -> Self {
1470+
const fn new() -> Self {
14711471
ViewRepr { life: PhantomData }
14721472
}
14731473
}

0 commit comments

Comments
 (0)