Skip to content

Commit 4d0bbc0

Browse files
committed
Use FiniteBounds to only allow a..b and a..=b ranges.
1 parent 3dfe114 commit 4d0bbc0

File tree

6 files changed

+79
-51
lines changed

6 files changed

+79
-51
lines changed

benches/iter.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fn iter_sum_2d_transpose(bench: &mut Bencher)
4747
#[bench]
4848
fn iter_filter_sum_2d_u32(bench: &mut Bencher)
4949
{
50-
let a = Array::linspace(0., 1., 256)
50+
let a = Array::linspace(0.0..=1.0, 256)
5151
.into_shape_with_order((16, 16))
5252
.unwrap();
5353
let b = a.mapv(|x| (x * 100.) as u32);
@@ -58,7 +58,7 @@ fn iter_filter_sum_2d_u32(bench: &mut Bencher)
5858
#[bench]
5959
fn iter_filter_sum_2d_f32(bench: &mut Bencher)
6060
{
61-
let a = Array::linspace(0., 1., 256)
61+
let a = Array::linspace(0.0..=1.0, 256)
6262
.into_shape_with_order((16, 16))
6363
.unwrap();
6464
let b = a * 100.;
@@ -69,7 +69,7 @@ fn iter_filter_sum_2d_f32(bench: &mut Bencher)
6969
#[bench]
7070
fn iter_filter_sum_2d_stride_u32(bench: &mut Bencher)
7171
{
72-
let a = Array::linspace(0., 1., 256)
72+
let a = Array::linspace(0.0..=1.0, 256)
7373
.into_shape_with_order((16, 16))
7474
.unwrap();
7575
let b = a.mapv(|x| (x * 100.) as u32);
@@ -81,7 +81,7 @@ fn iter_filter_sum_2d_stride_u32(bench: &mut Bencher)
8181
#[bench]
8282
fn iter_filter_sum_2d_stride_f32(bench: &mut Bencher)
8383
{
84-
let a = Array::linspace(0., 1., 256)
84+
let a = Array::linspace(0.0..=1.0, 256)
8585
.into_shape_with_order((16, 16))
8686
.unwrap();
8787
let b = a * 100.;
@@ -93,7 +93,7 @@ fn iter_filter_sum_2d_stride_f32(bench: &mut Bencher)
9393
#[bench]
9494
fn iter_rev_step_by_contiguous(bench: &mut Bencher)
9595
{
96-
let a = Array::linspace(0., 1., 512);
96+
let a = Array::linspace(0.0..=1.0, 512);
9797
bench.iter(|| {
9898
a.iter().rev().step_by(2).for_each(|x| {
9999
black_box(x);
@@ -105,7 +105,7 @@ fn iter_rev_step_by_contiguous(bench: &mut Bencher)
105105
#[bench]
106106
fn iter_rev_step_by_discontiguous(bench: &mut Bencher)
107107
{
108-
let mut a = Array::linspace(0., 1., 1024);
108+
let mut a = Array::linspace(0.0..=1.0, 1024);
109109
a.slice_axis_inplace(Axis(0), Slice::new(0, None, 2));
110110
bench.iter(|| {
111111
a.iter().rev().step_by(2).for_each(|x| {

src/finite_bounds.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use num_traits::Float;
2+
3+
pub enum Bound<F> {
4+
Included(F),
5+
Excluded(F),
6+
}
7+
8+
/// A version of std::ops::RangeBounds that only implements a..b and a..=b ranges.
9+
pub trait FiniteBounds<F> {
10+
fn start_bound(&self) -> F;
11+
fn end_bound(&self) -> Bound<F>;
12+
}
13+
14+
impl<F> FiniteBounds<F> for std::ops::Range<F>
15+
where
16+
F: Float,
17+
{
18+
fn start_bound(&self) -> F {
19+
self.start
20+
}
21+
22+
fn end_bound(&self) -> Bound<F> {
23+
Bound::Excluded(self.end)
24+
}
25+
}
26+
27+
impl<F> FiniteBounds<F> for std::ops::RangeInclusive<F>
28+
where
29+
F: Float,
30+
{
31+
fn start_bound(&self) -> F {
32+
*self.start()
33+
}
34+
35+
fn end_bound(&self) -> Bound<F> {
36+
Bound::Included(*self.end())
37+
}
38+
}

src/impl_constructors.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ where S: DataOwned<Elem = A>
9898
#[cfg(feature = "std")]
9999
pub fn linspace<R>(range: R, n: usize) -> Self
100100
where
101-
R: std::ops::RangeBounds<A>,
101+
R: crate::finite_bounds::FiniteBounds<A>,
102102
A: Float,
103103
{
104104
Self::from(to_vec(linspace::linspace(range, n)))
@@ -146,7 +146,7 @@ where S: DataOwned<Elem = A>
146146
#[cfg(feature = "std")]
147147
pub fn logspace<R>(base: A, range: R, n: usize) -> Self
148148
where
149-
R: std::ops::RangeBounds<A>,
149+
R: crate::finite_bounds::FiniteBounds<A>,
150150
A: Float,
151151
{
152152
Self::from(to_vec(logspace::logspace(base, range, n)))

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ mod indexes;
199199
mod iterators;
200200
mod layout;
201201
mod linalg_traits;
202+
#[cfg(feature = "std")]
203+
mod finite_bounds;
202204
mod linspace;
203205
#[cfg(feature = "std")]
204206
pub use crate::linspace::{linspace, range, Linspace};

src/linspace.rs

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,28 @@
77
// except according to those terms.
88
#![cfg(feature = "std")]
99

10-
use std::ops::{Bound, RangeBounds};
10+
use crate::finite_bounds::{Bound, FiniteBounds};
1111

1212
use num_traits::Float;
1313

1414
/// An iterator of a sequence of evenly spaced floats.
1515
///
1616
/// Iterator element type is `F`.
17-
pub struct Linspace<F>
18-
{
17+
pub struct Linspace<F> {
1918
start: F,
2019
step: F,
2120
index: usize,
2221
len: usize,
2322
}
2423

2524
impl<F> Iterator for Linspace<F>
26-
where F: Float
25+
where
26+
F: Float,
2727
{
2828
type Item = F;
2929

3030
#[inline]
31-
fn next(&mut self) -> Option<F>
32-
{
31+
fn next(&mut self) -> Option<F> {
3332
if self.index >= self.len {
3433
None
3534
} else {
@@ -41,19 +40,18 @@ where F: Float
4140
}
4241

4342
#[inline]
44-
fn size_hint(&self) -> (usize, Option<usize>)
45-
{
43+
fn size_hint(&self) -> (usize, Option<usize>) {
4644
let n = self.len - self.index;
4745
(n, Some(n))
4846
}
4947
}
5048

5149
impl<F> DoubleEndedIterator for Linspace<F>
52-
where F: Float
50+
where
51+
F: Float,
5352
{
5453
#[inline]
55-
fn next_back(&mut self) -> Option<F>
56-
{
54+
fn next_back(&mut self) -> Option<F> {
5755
if self.index >= self.len {
5856
None
5957
} else {
@@ -80,15 +78,12 @@ impl<F> ExactSizeIterator for Linspace<F> where Linspace<F>: Iterator {}
8078
#[inline]
8179
pub fn linspace<R, F>(range: R, n: usize) -> Linspace<F>
8280
where
83-
R: RangeBounds<F>,
81+
R: FiniteBounds<F>,
8482
F: Float,
8583
{
8684
let (a, b, num_steps) = match (range.start_bound(), range.end_bound()) {
87-
(Bound::Included(a), Bound::Included(b)) =>
88-
(*a, *b, F::from(n - 1).expect("Converting number of steps to `A` must not fail.")),
89-
(Bound::Included(a), Bound::Excluded(b)) =>
90-
(*a, *b, F::from(n).expect("Converting number of steps to `A` must not fail.")),
91-
_ => panic!("Only a..b and a..=b ranges are supported."),
85+
(a, Bound::Included(b)) => (a, b, F::from(n - 1).expect("Converting number of steps to `A` must not fail.")),
86+
(a, Bound::Excluded(b)) => (a, b, F::from(n).expect("Converting number of steps to `A` must not fail.")),
9287
};
9388

9489
let step = if num_steps > F::zero() {
@@ -116,7 +111,8 @@ where
116111
/// **Panics** if converting `((b - a) / step).ceil()` to type `F` fails.
117112
#[inline]
118113
pub fn range<F>(a: F, b: F, step: F) -> Linspace<F>
119-
where F: Float
114+
where
115+
F: Float,
120116
{
121117
let len = b - a;
122118
let steps = F::ceil(len / step);

src/logspace.rs

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
// except according to those terms.
88
#![cfg(feature = "std")]
99

10+
use crate::finite_bounds::{Bound, FiniteBounds};
11+
1012
use num_traits::Float;
11-
use std::ops::{Bound, RangeBounds};
1213

1314
/// An iterator of a sequence of logarithmically spaced number.
1415
///
1516
/// Iterator element type is `F`.
16-
pub struct Logspace<F>
17-
{
17+
pub struct Logspace<F> {
1818
sign: F,
1919
base: F,
2020
start: F,
@@ -24,13 +24,13 @@ pub struct Logspace<F>
2424
}
2525

2626
impl<F> Iterator for Logspace<F>
27-
where F: Float
27+
where
28+
F: Float,
2829
{
2930
type Item = F;
3031

3132
#[inline]
32-
fn next(&mut self) -> Option<F>
33-
{
33+
fn next(&mut self) -> Option<F> {
3434
if self.index >= self.len {
3535
None
3636
} else {
@@ -43,19 +43,18 @@ where F: Float
4343
}
4444

4545
#[inline]
46-
fn size_hint(&self) -> (usize, Option<usize>)
47-
{
46+
fn size_hint(&self) -> (usize, Option<usize>) {
4847
let n = self.len - self.index;
4948
(n, Some(n))
5049
}
5150
}
5251

5352
impl<F> DoubleEndedIterator for Logspace<F>
54-
where F: Float
53+
where
54+
F: Float,
5555
{
5656
#[inline]
57-
fn next_back(&mut self) -> Option<F>
58-
{
57+
fn next_back(&mut self) -> Option<F> {
5958
if self.index >= self.len {
6059
None
6160
} else {
@@ -83,15 +82,12 @@ impl<F> ExactSizeIterator for Logspace<F> where Logspace<F>: Iterator {}
8382
#[inline]
8483
pub fn logspace<R, F>(base: F, range: R, n: usize) -> Logspace<F>
8584
where
86-
R: RangeBounds<F>,
85+
R: FiniteBounds<F>,
8786
F: Float,
8887
{
8988
let (a, b, num_steps) = match (range.start_bound(), range.end_bound()) {
90-
(Bound::Included(a), Bound::Included(b)) =>
91-
(*a, *b, F::from(n - 1).expect("Converting number of steps to `A` must not fail.")),
92-
(Bound::Included(a), Bound::Excluded(b)) =>
93-
(*a, *b, F::from(n).expect("Converting number of steps to `A` must not fail.")),
94-
_ => panic!("Only a..b and a..=b ranges are supported."),
89+
(a, Bound::Included(b)) => (a, b, F::from(n - 1).expect("Converting number of steps to `A` must not fail.")),
90+
(a, Bound::Excluded(b)) => (a, b, F::from(n).expect("Converting number of steps to `A` must not fail.")),
9591
};
9692

9793
let step = if num_steps > F::zero() {
@@ -111,14 +107,12 @@ where
111107
}
112108

113109
#[cfg(test)]
114-
mod tests
115-
{
110+
mod tests {
116111
use super::logspace;
117112

118113
#[test]
119114
#[cfg(feature = "approx")]
120-
fn valid()
121-
{
115+
fn valid() {
122116
use crate::{arr1, Array1};
123117
use approx::assert_abs_diff_eq;
124118

@@ -136,8 +130,7 @@ mod tests
136130
}
137131

138132
#[test]
139-
fn iter_forward()
140-
{
133+
fn iter_forward() {
141134
let mut iter = logspace(10.0f64, 0.0..=3.0, 4);
142135

143136
assert!(iter.size_hint() == (4, Some(4)));
@@ -152,8 +145,7 @@ mod tests
152145
}
153146

154147
#[test]
155-
fn iter_backward()
156-
{
148+
fn iter_backward() {
157149
let mut iter = logspace(10.0f64, 0.0..=3.0, 4);
158150

159151
assert!(iter.size_hint() == (4, Some(4)));

0 commit comments

Comments
 (0)