diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 754da272c24..6625d19781a 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1104,6 +1104,21 @@ macro_rules! iterator { } } +macro_rules! make_slice { + ($t: ty -> $result: ty: $start: expr, $end: expr) => {{ + let diff = $end as uint - $start as uint; + let len = if mem::size_of::() == 0 { + diff + } else { + diff / mem::size_of::<$t>() + }; + unsafe { + transmute::<_, $result>(RawSlice { data: $start as *const T, len: len }) + } + }} +} + + /// Immutable slice iterator #[experimental = "needs review"] pub struct Items<'a, T: 'a> { @@ -1112,6 +1127,36 @@ pub struct Items<'a, T: 'a> { marker: marker::ContravariantLifetime<'a> } +#[experimental] +impl<'a, T> ops::Slice for Items<'a, T> { + fn as_slice_(&self) -> &[T] { + self.as_slice() + } + fn slice_from_or_fail<'b>(&'b self, from: &uint) -> &'b [T] { + use ops::Slice; + self.as_slice().slice_from_or_fail(from) + } + fn slice_to_or_fail<'b>(&'b self, to: &uint) -> &'b [T] { + use ops::Slice; + self.as_slice().slice_to_or_fail(to) + } + fn slice_or_fail<'b>(&'b self, from: &uint, to: &uint) -> &'b [T] { + use ops::Slice; + self.as_slice().slice_or_fail(from, to) + } +} + +impl<'a, T> Items<'a, T> { + /// View the underlying data as a subslice of the original data. + /// + /// This has the same lifetime as the original slice, and so the + /// iterator can continue to be used while this exists. + #[experimental] + pub fn as_slice(&self) -> &'a [T] { + make_slice!(T -> &'a [T]: self.ptr, self.end) + } +} + iterator!{struct Items -> *const T, &'a T} #[experimental = "needs review"] @@ -1156,6 +1201,57 @@ pub struct MutItems<'a, T: 'a> { marker2: marker::NoCopy } +#[experimental] +impl<'a, T> ops::Slice for MutItems<'a, T> { + fn as_slice_<'b>(&'b self) -> &'b [T] { + make_slice!(T -> &'b [T]: self.ptr, self.end) + } + fn slice_from_or_fail<'b>(&'b self, from: &uint) -> &'b [T] { + use ops::Slice; + self.as_slice_().slice_from_or_fail(from) + } + fn slice_to_or_fail<'b>(&'b self, to: &uint) -> &'b [T] { + use ops::Slice; + self.as_slice_().slice_to_or_fail(to) + } + fn slice_or_fail<'b>(&'b self, from: &uint, to: &uint) -> &'b [T] { + use ops::Slice; + self.as_slice_().slice_or_fail(from, to) + } +} + +#[experimental] +impl<'a, T> ops::SliceMut for MutItems<'a, T> { + fn as_mut_slice_<'b>(&'b mut self) -> &'b mut [T] { + make_slice!(T -> &'b mut [T]: self.ptr, self.end) + } + fn slice_from_or_fail_mut<'b>(&'b mut self, from: &uint) -> &'b mut [T] { + use ops::SliceMut; + self.as_mut_slice_().slice_from_or_fail_mut(from) + } + fn slice_to_or_fail_mut<'b>(&'b mut self, to: &uint) -> &'b mut [T] { + use ops::SliceMut; + self.as_mut_slice_().slice_to_or_fail_mut(to) + } + fn slice_or_fail_mut<'b>(&'b mut self, from: &uint, to: &uint) -> &'b mut [T] { + use ops::SliceMut; + self.as_mut_slice_().slice_or_fail_mut(from, to) + } +} + +impl<'a, T> MutItems<'a, T> { + /// View the underlying data as a subslice of the original data. + /// + /// To avoid creating `&mut` references that alias, this is forced + /// to consume the iterator. Consider using the `Slice` and + /// `SliceMut` implementations for obtaining slices with more + /// restricted lifetimes that do not consume the iterator. + #[experimental] + pub fn into_slice(self) -> &'a mut [T] { + make_slice!(T -> &'a mut [T]: self.ptr, self.end) + } +} + iterator!{struct MutItems -> *mut T, &'a mut T} #[experimental = "needs review"] diff --git a/src/libcoretest/slice.rs b/src/libcoretest/slice.rs index 1288756dea4..29253c50ed0 100644 --- a/src/libcoretest/slice.rs +++ b/src/libcoretest/slice.rs @@ -33,3 +33,52 @@ fn binary_search_not_found() { let b = [1i, 2, 4, 5, 6, 8]; assert!(b.binary_search(|v| v.cmp(&9)) == NotFound(6)); } + +#[test] +fn iterator_to_slice() { + macro_rules! test { + ($data: expr) => {{ + let data: &mut [_] = &mut $data; + let other_data: &mut [_] = &mut $data; + + { + let mut iter = data.iter(); + assert_eq!(iter[], other_data[]); + + iter.next(); + assert_eq!(iter[], other_data[1..]); + + iter.next_back(); + assert_eq!(iter[], other_data[1..2]); + + let s = iter.as_slice(); + iter.next(); + assert_eq!(s, other_data[1..2]); + } + { + let mut iter = data.iter_mut(); + assert_eq!(iter[], other_data[]); + // mutability: + assert!(iter[mut] == other_data); + + iter.next(); + assert_eq!(iter[], other_data[1..]); + assert!(iter[mut] == other_data[mut 1..]); + + iter.next_back(); + + assert_eq!(iter[], other_data[1..2]); + assert!(iter[mut] == other_data[mut 1..2]); + + let s = iter.into_slice(); + assert!(s == other_data[mut 1..2]); + } + }} + } + + // try types of a variety of sizes + test!([(1u64, 1u64, 1u8), (2, 2, 2), (3, 3, 3)]); + test!([1u64,2,3]); + test!([1u8,2,3]); + test!([(),(),()]); +}