Skip to content

Commit de4afc6

Browse files
committed
Implement O(1)-time Iterator::nth for Range*
1 parent 8e8fd02 commit de4afc6

File tree

2 files changed

+89
-18
lines changed

2 files changed

+89
-18
lines changed

src/libcore/iter/range.rs

+84-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use convert::TryFrom;
1112
use mem;
1213
use ops::{self, Add, Sub};
1314
use usize;
@@ -21,7 +22,7 @@ use super::{FusedIterator, TrustedLen};
2122
#[unstable(feature = "step_trait",
2223
reason = "likely to be replaced by finer-grained traits",
2324
issue = "42168")]
24-
pub trait Step: PartialOrd + Sized {
25+
pub trait Step: Clone + PartialOrd + Sized {
2526
/// Returns the number of steps between two step objects. The count is
2627
/// inclusive of `start` and exclusive of `end`.
2728
///
@@ -40,6 +41,9 @@ pub trait Step: PartialOrd + Sized {
4041

4142
/// Subtracts one to this step, returning the result
4243
fn sub_one(&self) -> Self;
44+
45+
/// Add an usize, returning None on overflow
46+
fn add_usize(&self, n: usize) -> Option<Self>;
4347
}
4448

4549
// These are still macro-generated because the integer literals resolve to different types.
@@ -84,12 +88,20 @@ macro_rules! step_impl_unsigned {
8488
}
8589
}
8690

91+
#[inline]
92+
fn add_usize(&self, n: usize) -> Option<Self> {
93+
match <$t>::try_from(n) {
94+
Ok(n_as_t) => self.checked_add(n_as_t),
95+
Err(_) => None,
96+
}
97+
}
98+
8799
step_identical_methods!();
88100
}
89101
)*)
90102
}
91103
macro_rules! step_impl_signed {
92-
($($t:ty)*) => ($(
104+
($( [$t:ty : $unsigned:ty] )*) => ($(
93105
#[unstable(feature = "step_trait",
94106
reason = "likely to be replaced by finer-grained traits",
95107
issue = "42168")]
@@ -107,6 +119,24 @@ macro_rules! step_impl_signed {
107119
}
108120
}
109121

122+
#[inline]
123+
fn add_usize(&self, n: usize) -> Option<Self> {
124+
match <$unsigned>::try_from(n) {
125+
Ok(n_as_unsigned) => {
126+
// Wrapping in unsigned space handles cases like
127+
// `-120_i8.add_usize(200) == Some(80_i8)`,
128+
// even though 200_usize is out of range for i8.
129+
let wrapped = (*self as $unsigned).wrapping_add(n_as_unsigned) as $t;
130+
if wrapped >= *self {
131+
Some(wrapped)
132+
} else {
133+
None // Addition overflowed
134+
}
135+
}
136+
Err(_) => None,
137+
}
138+
}
139+
110140
step_identical_methods!();
111141
}
112142
)*)
@@ -123,17 +153,22 @@ macro_rules! step_impl_no_between {
123153
None
124154
}
125155

156+
#[inline]
157+
fn add_usize(&self, n: usize) -> Option<Self> {
158+
self.checked_add(n as $t)
159+
}
160+
126161
step_identical_methods!();
127162
}
128163
)*)
129164
}
130165

131166
step_impl_unsigned!(usize u8 u16 u32);
132-
step_impl_signed!(isize i8 i16 i32);
167+
step_impl_signed!([isize: usize] [i8: u8] [i16: u16] [i32: u32]);
133168
#[cfg(target_pointer_width = "64")]
134169
step_impl_unsigned!(u64);
135170
#[cfg(target_pointer_width = "64")]
136-
step_impl_signed!(i64);
171+
step_impl_signed!([i64: u64]);
137172
// If the target pointer width is not 64-bits, we
138173
// assume here that it is less than 64-bits.
139174
#[cfg(not(target_pointer_width = "64"))]
@@ -194,6 +229,19 @@ impl<A: Step> Iterator for ops::Range<A> {
194229
None => (0, None)
195230
}
196231
}
232+
233+
#[inline]
234+
fn nth(&mut self, n: usize) -> Option<A> {
235+
if let Some(plus_n) = self.start.add_usize(n) {
236+
if plus_n < self.end {
237+
self.start = plus_n.add_one();
238+
return Some(plus_n)
239+
}
240+
}
241+
242+
self.start = self.end.clone();
243+
None
244+
}
197245
}
198246

199247
// These macros generate `ExactSizeIterator` impls for various range types.
@@ -211,7 +259,7 @@ range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
211259
range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
212260

213261
#[stable(feature = "rust1", since = "1.0.0")]
214-
impl<A: Step + Clone> DoubleEndedIterator for ops::Range<A> {
262+
impl<A: Step> DoubleEndedIterator for ops::Range<A> {
215263
#[inline]
216264
fn next_back(&mut self) -> Option<A> {
217265
if self.start < self.end {
@@ -241,6 +289,13 @@ impl<A: Step> Iterator for ops::RangeFrom<A> {
241289
fn size_hint(&self) -> (usize, Option<usize>) {
242290
(usize::MAX, None)
243291
}
292+
293+
#[inline]
294+
fn nth(&mut self, n: usize) -> Option<A> {
295+
let plus_n = self.start.add_usize(n).expect("overflow in RangeFrom::nth");
296+
self.start = plus_n.add_one();
297+
Some(plus_n)
298+
}
244299
}
245300

246301
#[unstable(feature = "fused", issue = "35602")]
@@ -279,6 +334,30 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
279334
None => (0, None),
280335
}
281336
}
337+
338+
#[inline]
339+
fn nth(&mut self, n: usize) -> Option<A> {
340+
if let Some(plus_n) = self.start.add_usize(n) {
341+
use cmp::Ordering::*;
342+
343+
match plus_n.partial_cmp(&self.end) {
344+
Some(Less) => {
345+
self.start = plus_n.add_one();
346+
return Some(plus_n)
347+
}
348+
Some(Equal) => {
349+
self.start.replace_one();
350+
self.end.replace_zero();
351+
return Some(plus_n)
352+
}
353+
_ => {}
354+
}
355+
}
356+
357+
self.start.replace_one();
358+
self.end.replace_zero();
359+
None
360+
}
282361
}
283362

284363
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]

src/test/run-pass/impl-trait/example-calendar.rs

+5-13
Original file line numberDiff line numberDiff line change
@@ -162,22 +162,10 @@ impl<'a, 'b> std::ops::Add<&'b NaiveDate> for &'a NaiveDate {
162162
}
163163

164164
impl std::iter::Step for NaiveDate {
165-
fn step(&self, by: &Self) -> Option<Self> {
166-
Some(self + by)
167-
}
168-
169-
fn steps_between(_: &Self, _: &Self, _: &Self) -> Option<usize> {
170-
unimplemented!()
171-
}
172-
173-
fn steps_between_by_one(_: &Self, _: &Self) -> Option<usize> {
165+
fn steps_between(_: &Self, _: &Self) -> Option<usize> {
174166
unimplemented!()
175167
}
176168

177-
fn is_negative(&self) -> bool {
178-
false
179-
}
180-
181169
fn replace_one(&mut self) -> Self {
182170
mem::replace(self, NaiveDate(0, 0, 1))
183171
}
@@ -193,6 +181,10 @@ impl std::iter::Step for NaiveDate {
193181
fn sub_one(&self) -> Self {
194182
unimplemented!()
195183
}
184+
185+
fn add_usize(&self, _: usize) -> Option<Self> {
186+
unimplemented!()
187+
}
196188
}
197189

198190
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]

0 commit comments

Comments
 (0)