about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-11-11 04:26:12 -0800
committerbors <bors@rust-lang.org>2013-11-11 04:26:12 -0800
commitbe79d7ecdc9a44d13a226a99e7066d57419ccd7c (patch)
treee5701475d3fa1ce039c35d944ee5d1c2f46c5c9d /src/libstd
parent46100c06223f737a7604b46667800ed42cf20d3b (diff)
parentfc01f20c4242fa7cd94ba6676cea6e4913e2b7be (diff)
downloadrust-be79d7ecdc9a44d13a226a99e7066d57419ccd7c.tar.gz
rust-be79d7ecdc9a44d13a226a99e7066d57419ccd7c.zip
auto merge of #10416 : cmr/rust/range_size_hint, r=huonw
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/iter.rs88
-rw-r--r--src/libstd/rt/io/timer.rs2
2 files changed, 80 insertions, 10 deletions
diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs
index 771be3b2a13..90195efeae9 100644
--- a/src/libstd/iter.rs
+++ b/src/libstd/iter.rs
@@ -65,7 +65,7 @@ the rest of the rust manuals.
 */
 
 use cmp;
-use num::{Zero, One, Integer, CheckedAdd, CheckedSub, Saturating};
+use num::{Zero, One, Integer, CheckedAdd, CheckedSub, Saturating, ToPrimitive};
 use option::{Option, Some, None};
 use ops::{Add, Mul, Sub};
 use cmp::{Eq, Ord};
@@ -1829,7 +1829,8 @@ pub fn range<A: Add<A, A> + Ord + Clone + One>(start: A, stop: A) -> Range<A> {
     Range{state: start, stop: stop, one: One::one()}
 }
 
-impl<A: Add<A, A> + Ord + Clone> Iterator<A> for Range<A> {
+// FIXME: #10414: Unfortunate type bound
+impl<A: Add<A, A> + Ord + Clone + ToPrimitive> Iterator<A> for Range<A> {
     #[inline]
     fn next(&mut self) -> Option<A> {
         if self.state < self.stop {
@@ -1841,13 +1842,42 @@ impl<A: Add<A, A> + Ord + Clone> Iterator<A> for Range<A> {
         }
     }
 
-    // FIXME: #8606 Implement size_hint() on Range
-    // Blocked on #8605 Need numeric trait for converting to `Option<uint>`
+    #[inline]
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        // This first checks if the elements are representable as i64. If they aren't, try u64 (to
+        // handle cases like range(huge, huger)). We don't use uint/int because the difference of
+        // the i64/u64 might lie within their range.
+        let bound = match self.state.to_i64() {
+            Some(a) => {
+                let sz = self.stop.to_i64().map(|b| b.checked_sub(&a));
+                match sz {
+                    Some(Some(bound)) => bound.to_uint(),
+                    _ => None,
+                }
+            },
+            None => match self.state.to_u64() {
+                Some(a) => {
+                    let sz = self.stop.to_u64().map(|b| b.checked_sub(&a));
+                    match sz {
+                        Some(Some(bound)) => bound.to_uint(),
+                        _ => None
+                    }
+                },
+                None => None
+            }
+        };
+
+        match bound {
+            Some(b) => (b, Some(b)),
+            // Standard fallback for unbounded/unrepresentable bounds
+            None => (0, None)
+        }
+    }
 }
 
 /// `Integer` is required to ensure the range will be the same regardless of
 /// the direction it is consumed.
-impl<A: Integer + Ord + Clone> DoubleEndedIterator<A> for Range<A> {
+impl<A: Integer + Ord + Clone + ToPrimitive> DoubleEndedIterator<A> for Range<A> {
     #[inline]
     fn next_back(&mut self) -> Option<A> {
         if self.stop > self.state {
@@ -1868,11 +1898,12 @@ pub struct RangeInclusive<A> {
 
 /// Return an iterator over the range [start, stop]
 #[inline]
-pub fn range_inclusive<A: Add<A, A> + Ord + Clone + One>(start: A, stop: A) -> RangeInclusive<A> {
+pub fn range_inclusive<A: Add<A, A> + Ord + Clone + One + ToPrimitive>(start: A, stop: A)
+    -> RangeInclusive<A> {
     RangeInclusive{range: range(start, stop), done: false}
 }
 
-impl<A: Add<A, A> + Eq + Ord + Clone> Iterator<A> for RangeInclusive<A> {
+impl<A: Add<A, A> + Eq + Ord + Clone + ToPrimitive> Iterator<A> for RangeInclusive<A> {
     #[inline]
     fn next(&mut self) -> Option<A> {
         match self.range.next() {
@@ -1904,7 +1935,8 @@ impl<A: Add<A, A> + Eq + Ord + Clone> Iterator<A> for RangeInclusive<A> {
     }
 }
 
-impl<A: Sub<A, A> + Integer + Ord + Clone> DoubleEndedIterator<A> for RangeInclusive<A> {
+impl<A: Sub<A, A> + Integer + Ord + Clone + ToPrimitive> DoubleEndedIterator<A>
+    for RangeInclusive<A> {
     #[inline]
     fn next_back(&mut self) -> Option<A> {
         if self.range.stop > self.range.state {
@@ -2184,6 +2216,7 @@ mod tests {
 
     use cmp;
     use uint;
+    use num;
 
     #[test]
     fn test_counter_from_iter() {
@@ -2801,12 +2834,51 @@ mod tests {
 
     #[test]
     fn test_range() {
+        /// A mock type to check Range when ToPrimitive returns None
+        struct Foo;
+
+        impl ToPrimitive for Foo {
+            fn to_i64(&self) -> Option<i64> { None }
+            fn to_u64(&self) -> Option<u64> { None }
+        }
+
+        impl Add<Foo, Foo> for Foo {
+            fn add(&self, _: &Foo) -> Foo {
+                Foo
+            }
+        }
+
+        impl Ord for Foo {
+            fn lt(&self, _: &Foo) -> bool {
+                false
+            }
+        }
+
+        impl Clone for Foo {
+            fn clone(&self) -> Foo {
+                Foo
+            }
+        }
+
+        impl num::One for Foo {
+            fn one() -> Foo {
+                Foo
+            }
+        }
+
         assert_eq!(range(0i, 5).collect::<~[int]>(), ~[0i, 1, 2, 3, 4]);
+        assert_eq!(range(-10i, -1).collect::<~[int]>(), ~[-10, -9, -8, -7, -6, -5, -4, -3, -2]);
         assert_eq!(range(0i, 5).invert().collect::<~[int]>(), ~[4, 3, 2, 1, 0]);
         assert_eq!(range(200, -5).collect::<~[int]>(), ~[]);
         assert_eq!(range(200, -5).invert().collect::<~[int]>(), ~[]);
         assert_eq!(range(200, 200).collect::<~[int]>(), ~[]);
         assert_eq!(range(200, 200).invert().collect::<~[int]>(), ~[]);
+
+        assert_eq!(range(0i, 100).size_hint(), (100, Some(100)));
+        // this test is only meaningful when sizeof uint < sizeof u64
+        assert_eq!(range(uint::max_value - 1, uint::max_value).size_hint(), (1, Some(1)));
+        assert_eq!(range(-10i, -1).size_hint(), (9, Some(9)));
+        assert_eq!(range(Foo, Foo).size_hint(), (0, None));
     }
 
     #[test]
diff --git a/src/libstd/rt/io/timer.rs b/src/libstd/rt/io/timer.rs
index b0cf7dee10a..48e0182354a 100644
--- a/src/libstd/rt/io/timer.rs
+++ b/src/libstd/rt/io/timer.rs
@@ -111,8 +111,6 @@ mod test {
     use prelude::*;
     use super::*;
     use rt::test::*;
-    use cell::Cell;
-    use task;
 
     #[test]
     fn test_io_timer_sleep_simple() {