diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9b6622a7127..9de723f38ee 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -59,7 +59,7 @@ #![allow(unknown_features, raw_pointer_deriving)] #![feature(globs, intrinsics, lang_items, macro_rules, phase)] #![feature(simd, unsafe_destructor, slicing_syntax)] -#![feature(default_type_params, unboxed_closures)] +#![feature(default_type_params, unboxed_closures, associated_types)] #![deny(missing_docs)] mod macros; diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index e752fd11ee5..63451d06cb5 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -51,7 +51,12 @@ //! See the documentation for each trait for a minimum implementation that prints //! something to the screen. +use clone::Clone; +use cmp::Ord; +use iter::{Iterator,DoubleEndedIterator}; use kinds::Sized; +use kinds::Copy; +use option::Option::{mod, Some, None}; /// The `Drop` trait is used to run some code when a value goes out of scope. This /// is sometimes called a 'destructor'. @@ -833,6 +838,114 @@ pub trait SliceMut for Sized? { fn slice_or_fail_mut<'a>(&'a mut self, from: &Idx, to: &Idx) -> &'a mut Result; } + + +/// REVIEW could be in a better module +/// The `Countable` trait identifies objects which are countable, i.e., are +/// analogous to the natural numbers. A countable object can be incremented and +/// and decremented and ordered. The `difference` function provides a way to +/// compare two Countable objects (it could be provided using increment and Ord, +/// but the implementation would be so inefficient as to be useless). +#[unstable = "Trait is unstable."] +pub trait Countable: Ord { + // FIXME(#19391) needs a snapshot + //type T; + + /// Change self to the next object. + fn increment(&mut self); + /// Change self to the previous object. + fn decrement(&mut self); + /// The difference between two countable objects. + /// Temporarily a uint, should be an associated type, but + // FIXME(#19391) needs a snapshot + fn difference(a: &Self, b: &Self) -> uint; + //fn difference(a: &Self, b: &Self) -> ::T; +} + +macro_rules! countable_impl( + ($($t:ty)*) => ($( + #[unstable = "Trait is unstable."] + impl Countable for $t { + // FIXME(#19391) needs a snapshot + //type T = uint; + + #[inline] + fn increment(&mut self) { *self += 1; } + #[inline] + fn decrement(&mut self) { *self -= 1; } + #[inline] + fn difference(a: &$t, b: &$t) -> uint { (*a - *b) as uint } + } + )*) +) + +countable_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64) + +/// An unbounded range. +pub struct FullRange; + +/// A range which i bounded at both ends. +pub struct Range { + /// The lower bound of the range (inclusive). + pub start: Idx, + /// The upper bound of the range (exclusive). + pub end: Idx, +} + +// FIXME(#19391) needs a snapshot +//impl> Iterator for Range { +impl Iterator for Range { + #[inline] + fn next(&mut self) -> Option { + if self.start < self.end { + let result = self.start.clone(); + self.start.increment(); + return Some(result); + } + + return None; + } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + let hint = Countable::difference(&self.end, &self.start); + (hint, Some(hint)) + } +} + +impl DoubleEndedIterator for Range { + #[inline] + fn next_back(&mut self) -> Option { + if self.start < self.end { + self.end.decrement(); + return Some(self.end.clone()); + } + + return None; + } +} + +/// A range which is only bounded below. +pub struct RangeFrom { + /// The lower bound of the range (inclusive). + pub start: Idx, +} + +impl Iterator for RangeFrom { + #[inline] + fn next(&mut self) -> Option { + // Deliberately overflow so we loop forever. + let result = self.start.clone(); + self.start.increment(); + return Some(result); + } +} + +impl Copy for Range {} +impl Copy for RangeFrom {} +impl Copy for FullRange {} + + /// The `Deref` trait is used to specify the functionality of dereferencing /// operations like `*v`. /// diff --git a/src/libcoretest/ops.rs b/src/libcoretest/ops.rs index 447fd1c699d..c4acef32ee8 100644 --- a/src/libcoretest/ops.rs +++ b/src/libcoretest/ops.rs @@ -9,6 +9,7 @@ // except according to those terms. use test::Bencher; +use core::ops::{Range, FullRange, RangeFrom}; // Overhead of dtors @@ -27,3 +28,29 @@ fn alloc_obj_with_dtor(b: &mut Bencher) { HasDtor { _x : 10 }; }) } + +// Test the Range structs without the syntactic sugar. + +#[test] +fn test_range() { + let r = Range { start: 2u, end: 10 }; + for (i, ri) in r.enumerate() { + assert!(ri == i + 2); + assert!(ri >= 2u && ri < 10u); + } +} + +#[test] +fn test_range_from() { + let r = RangeFrom { start: 2u }; + for (i, ri) in r.take(10).enumerate() { + assert!(ri == i + 2); + assert!(ri >= 2u && ri < 12u); + } +} + +#[test] +fn test_full_range() { + // Not much to test. + let _ = FullRange; +}