]> git.lizzy.rs Git - rust.git/blob - src/libcore/iter/range.rs
66a76a24df45afc983395776ad5c69f83c651d38
[rust.git] / src / libcore / iter / range.rs
1 // Copyright 2013-2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use convert::TryFrom;
12 use mem;
13 use ops::{self, Add, Sub};
14 use usize;
15
16 use super::{FusedIterator, TrustedLen};
17
18 /// Objects that can be stepped over in both directions.
19 ///
20 /// The `steps_between` function provides a way to efficiently compare
21 /// two `Step` objects.
22 #[unstable(feature = "step_trait",
23            reason = "likely to be replaced by finer-grained traits",
24            issue = "42168")]
25 pub trait Step: Clone + PartialOrd + Sized {
26     /// Returns the number of steps between two step objects. The count is
27     /// inclusive of `start` and exclusive of `end`.
28     ///
29     /// Returns `None` if it is not possible to calculate `steps_between`
30     /// without overflow.
31     fn steps_between(start: &Self, end: &Self) -> Option<usize>;
32
33     /// Replaces this step with `1`, returning itself
34     fn replace_one(&mut self) -> Self;
35
36     /// Replaces this step with `0`, returning itself
37     fn replace_zero(&mut self) -> Self;
38
39     /// Adds one to this step, returning the result
40     fn add_one(&self) -> Self;
41
42     /// Subtracts one to this step, returning the result
43     fn sub_one(&self) -> Self;
44
45     /// Add an usize, returning None on overflow
46     fn add_usize(&self, n: usize) -> Option<Self>;
47 }
48
49 // These are still macro-generated because the integer literals resolve to different types.
50 macro_rules! step_identical_methods {
51     () => {
52         #[inline]
53         fn replace_one(&mut self) -> Self {
54             mem::replace(self, 1)
55         }
56
57         #[inline]
58         fn replace_zero(&mut self) -> Self {
59             mem::replace(self, 0)
60         }
61
62         #[inline]
63         fn add_one(&self) -> Self {
64             Add::add(*self, 1)
65         }
66
67         #[inline]
68         fn sub_one(&self) -> Self {
69             Sub::sub(*self, 1)
70         }
71     }
72 }
73
74 macro_rules! step_impl_unsigned {
75     ($($t:ty)*) => ($(
76         #[unstable(feature = "step_trait",
77                    reason = "likely to be replaced by finer-grained traits",
78                    issue = "42168")]
79         impl Step for $t {
80             #[inline]
81             #[allow(trivial_numeric_casts)]
82             fn steps_between(start: &$t, end: &$t) -> Option<usize> {
83                 if *start < *end {
84                     // Note: We assume $t <= usize here
85                     Some((*end - *start) as usize)
86                 } else {
87                     Some(0)
88                 }
89             }
90
91             #[inline]
92             #[allow(unreachable_patterns)]
93             fn add_usize(&self, n: usize) -> Option<Self> {
94                 match <$t>::try_from(n) {
95                     Ok(n_as_t) => self.checked_add(n_as_t),
96                     Err(_) => None,
97                 }
98             }
99
100             step_identical_methods!();
101         }
102     )*)
103 }
104 macro_rules! step_impl_signed {
105     ($( [$t:ty : $unsigned:ty] )*) => ($(
106         #[unstable(feature = "step_trait",
107                    reason = "likely to be replaced by finer-grained traits",
108                    issue = "42168")]
109         impl Step for $t {
110             #[inline]
111             #[allow(trivial_numeric_casts)]
112             fn steps_between(start: &$t, end: &$t) -> Option<usize> {
113                 if *start < *end {
114                     // Note: We assume $t <= isize here
115                     // Use .wrapping_sub and cast to usize to compute the
116                     // difference that may not fit inside the range of isize.
117                     Some((*end as isize).wrapping_sub(*start as isize) as usize)
118                 } else {
119                     Some(0)
120                 }
121             }
122
123             #[inline]
124             #[allow(unreachable_patterns)]
125             fn add_usize(&self, n: usize) -> Option<Self> {
126                 match <$unsigned>::try_from(n) {
127                     Ok(n_as_unsigned) => {
128                         // Wrapping in unsigned space handles cases like
129                         // `-120_i8.add_usize(200) == Some(80_i8)`,
130                         // even though 200_usize is out of range for i8.
131                         let wrapped = (*self as $unsigned).wrapping_add(n_as_unsigned) as $t;
132                         if wrapped >= *self {
133                             Some(wrapped)
134                         } else {
135                             None  // Addition overflowed
136                         }
137                     }
138                     Err(_) => None,
139                 }
140             }
141
142             step_identical_methods!();
143         }
144     )*)
145 }
146
147 macro_rules! step_impl_no_between {
148     ($($t:ty)*) => ($(
149         #[unstable(feature = "step_trait",
150                    reason = "likely to be replaced by finer-grained traits",
151                    issue = "42168")]
152         impl Step for $t {
153             #[inline]
154             fn steps_between(_start: &Self, _end: &Self) -> Option<usize> {
155                 None
156             }
157
158             #[inline]
159             fn add_usize(&self, n: usize) -> Option<Self> {
160                 self.checked_add(n as $t)
161             }
162
163             step_identical_methods!();
164         }
165     )*)
166 }
167
168 step_impl_unsigned!(usize u8 u16 u32);
169 step_impl_signed!([isize: usize] [i8: u8] [i16: u16] [i32: u32]);
170 #[cfg(target_pointer_width = "64")]
171 step_impl_unsigned!(u64);
172 #[cfg(target_pointer_width = "64")]
173 step_impl_signed!([i64: u64]);
174 // If the target pointer width is not 64-bits, we
175 // assume here that it is less than 64-bits.
176 #[cfg(not(target_pointer_width = "64"))]
177 step_impl_no_between!(u64 i64);
178 step_impl_no_between!(u128 i128);
179
180 macro_rules! range_exact_iter_impl {
181     ($($t:ty)*) => ($(
182         #[stable(feature = "rust1", since = "1.0.0")]
183         impl ExactSizeIterator for ops::Range<$t> { }
184     )*)
185 }
186
187 macro_rules! range_incl_exact_iter_impl {
188     ($($t:ty)*) => ($(
189         #[unstable(feature = "inclusive_range",
190                    reason = "recently added, follows RFC",
191                    issue = "28237")]
192         impl ExactSizeIterator for ops::RangeInclusive<$t> { }
193     )*)
194 }
195
196 macro_rules! range_trusted_len_impl {
197     ($($t:ty)*) => ($(
198         #[unstable(feature = "trusted_len", issue = "37572")]
199         unsafe impl TrustedLen for ops::Range<$t> { }
200     )*)
201 }
202
203 macro_rules! range_incl_trusted_len_impl {
204     ($($t:ty)*) => ($(
205         #[unstable(feature = "inclusive_range",
206                    reason = "recently added, follows RFC",
207                    issue = "28237")]
208         unsafe impl TrustedLen for ops::RangeInclusive<$t> { }
209     )*)
210 }
211
212 #[stable(feature = "rust1", since = "1.0.0")]
213 impl<A: Step> Iterator for ops::Range<A> {
214     type Item = A;
215
216     #[inline]
217     fn next(&mut self) -> Option<A> {
218         if self.start < self.end {
219             // We check for overflow here, even though it can't actually
220             // happen. Adding this check does however help llvm vectorize loops
221             // for some ranges that don't get vectorized otherwise,
222             // and this won't actually result in an extra check in an optimized build.
223             if let Some(mut n) = self.start.add_usize(1) {
224                 mem::swap(&mut n, &mut self.start);
225                 Some(n)
226             } else {
227                 None
228             }
229         } else {
230             None
231         }
232     }
233
234     #[inline]
235     fn size_hint(&self) -> (usize, Option<usize>) {
236         match Step::steps_between(&self.start, &self.end) {
237             Some(hint) => (hint, Some(hint)),
238             None => (0, None)
239         }
240     }
241
242     #[inline]
243     fn nth(&mut self, n: usize) -> Option<A> {
244         if let Some(plus_n) = self.start.add_usize(n) {
245             if plus_n < self.end {
246                 self.start = plus_n.add_one();
247                 return Some(plus_n)
248             }
249         }
250
251         self.start = self.end.clone();
252         None
253     }
254
255     #[inline]
256     fn last(mut self) -> Option<A> {
257         self.next_back()
258     }
259
260     #[inline]
261     fn min(mut self) -> Option<A> {
262         self.next()
263     }
264
265     #[inline]
266     fn max(mut self) -> Option<A> {
267         self.next_back()
268     }
269 }
270
271 // These macros generate `ExactSizeIterator` impls for various range types.
272 // Range<{u,i}64> and RangeInclusive<{u,i}{32,64,size}> are excluded
273 // because they cannot guarantee having a length <= usize::MAX, which is
274 // required by ExactSizeIterator.
275 range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32);
276 range_incl_exact_iter_impl!(u8 u16 i8 i16);
277
278 // These macros generate `TrustedLen` impls.
279 //
280 // They need to guarantee that .size_hint() is either exact, or that
281 // the upper bound is None when it does not fit the type limits.
282 range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
283 range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
284
285 #[stable(feature = "rust1", since = "1.0.0")]
286 impl<A: Step> DoubleEndedIterator for ops::Range<A> {
287     #[inline]
288     fn next_back(&mut self) -> Option<A> {
289         if self.start < self.end {
290             self.end = self.end.sub_one();
291             Some(self.end.clone())
292         } else {
293             None
294         }
295     }
296 }
297
298 #[unstable(feature = "fused", issue = "35602")]
299 impl<A: Step> FusedIterator for ops::Range<A> {}
300
301 #[stable(feature = "rust1", since = "1.0.0")]
302 impl<A: Step> Iterator for ops::RangeFrom<A> {
303     type Item = A;
304
305     #[inline]
306     fn next(&mut self) -> Option<A> {
307         let mut n = self.start.add_one();
308         mem::swap(&mut n, &mut self.start);
309         Some(n)
310     }
311
312     #[inline]
313     fn size_hint(&self) -> (usize, Option<usize>) {
314         (usize::MAX, None)
315     }
316
317     #[inline]
318     fn nth(&mut self, n: usize) -> Option<A> {
319         let plus_n = self.start.add_usize(n).expect("overflow in RangeFrom::nth");
320         self.start = plus_n.add_one();
321         Some(plus_n)
322     }
323 }
324
325 #[unstable(feature = "fused", issue = "35602")]
326 impl<A: Step> FusedIterator for ops::RangeFrom<A> {}
327
328 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
329 impl<A: Step> Iterator for ops::RangeInclusive<A> {
330     type Item = A;
331
332     #[inline]
333     fn next(&mut self) -> Option<A> {
334         use cmp::Ordering::*;
335
336         match self.start.partial_cmp(&self.end) {
337             Some(Less) => {
338                 let n = self.start.add_one();
339                 Some(mem::replace(&mut self.start, n))
340             },
341             Some(Equal) => {
342                 let last = self.start.replace_one();
343                 self.end.replace_zero();
344                 Some(last)
345             },
346             _ => None,
347         }
348     }
349
350     #[inline]
351     fn size_hint(&self) -> (usize, Option<usize>) {
352         if !(self.start <= self.end) {
353             return (0, Some(0));
354         }
355
356         match Step::steps_between(&self.start, &self.end) {
357             Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
358             None => (0, None),
359         }
360     }
361
362     #[inline]
363     fn nth(&mut self, n: usize) -> Option<A> {
364         if let Some(plus_n) = self.start.add_usize(n) {
365             use cmp::Ordering::*;
366
367             match plus_n.partial_cmp(&self.end) {
368                 Some(Less) => {
369                     self.start = plus_n.add_one();
370                     return Some(plus_n)
371                 }
372                 Some(Equal) => {
373                     self.start.replace_one();
374                     self.end.replace_zero();
375                     return Some(plus_n)
376                 }
377                 _ => {}
378             }
379         }
380
381         self.start.replace_one();
382         self.end.replace_zero();
383         None
384     }
385
386     #[inline]
387     fn last(mut self) -> Option<A> {
388         self.next_back()
389     }
390
391     #[inline]
392     fn min(mut self) -> Option<A> {
393         self.next()
394     }
395
396     #[inline]
397     fn max(mut self) -> Option<A> {
398         self.next_back()
399     }
400 }
401
402 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
403 impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
404     #[inline]
405     fn next_back(&mut self) -> Option<A> {
406         use cmp::Ordering::*;
407
408         match self.start.partial_cmp(&self.end) {
409             Some(Less) => {
410                 let n = self.end.sub_one();
411                 Some(mem::replace(&mut self.end, n))
412             },
413             Some(Equal) => {
414                 let last = self.end.replace_zero();
415                 self.start.replace_one();
416                 Some(last)
417             },
418             _ => None,
419         }
420     }
421 }
422
423 #[unstable(feature = "fused", issue = "35602")]
424 impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}