Skip to content

Commit dde5c63

Browse files
committed
Add methods to go from a slice iterators to a slice.
A slice iterator is isomorphic to a slice, just with a slightly different form: storing start and end pointers rather than start pointer and length. This patch reflects this by making converting between them as easy as `iter.as_slice()` (or even `iter[]` if the shorter lifetime is ok). That is, `slice.iter().as_slice() == slice`.
1 parent bb2168c commit dde5c63

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed

src/libcore/slice.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,22 @@ macro_rules! iterator {
10921092
}
10931093
}
10941094

1095+
macro_rules! make_slice {
1096+
($t: ty -> $result: ty: $start: expr, $end: expr) => {{
1097+
let len = if mem::size_of::<T>() == 0 {
1098+
// zero-sized types just use the end "pointer" as the
1099+
// length directly
1100+
$end as uint
1101+
} else {
1102+
($end as uint - $start as uint) / mem::size_of::<$t>()
1103+
};
1104+
unsafe {
1105+
transmute::<_, $result>(RawSlice { data: $start as *const T, len: len })
1106+
}
1107+
}}
1108+
}
1109+
1110+
10951111
/// Immutable slice iterator
10961112
#[experimental = "needs review"]
10971113
pub struct Items<'a, T: 'a> {
@@ -1100,6 +1116,36 @@ pub struct Items<'a, T: 'a> {
11001116
marker: marker::ContravariantLifetime<'a>
11011117
}
11021118

1119+
#[experimental]
1120+
impl<'a, T> ops::Slice<uint, [T]> for Items<'a, T> {
1121+
fn as_slice_(&self) -> &[T] {
1122+
self.as_slice()
1123+
}
1124+
fn slice_from_or_fail<'b>(&'b self, from: &uint) -> &'b [T] {
1125+
use ops::Slice;
1126+
self.as_slice().slice_from_or_fail(from)
1127+
}
1128+
fn slice_to_or_fail<'b>(&'b self, to: &uint) -> &'b [T] {
1129+
use ops::Slice;
1130+
self.as_slice().slice_to_or_fail(to)
1131+
}
1132+
fn slice_or_fail<'b>(&'b self, from: &uint, to: &uint) -> &'b [T] {
1133+
use ops::Slice;
1134+
self.as_slice().slice_or_fail(from, to)
1135+
}
1136+
}
1137+
1138+
impl<'a, T> Items<'a, T> {
1139+
/// View the underlying data as a subslice of the original data.
1140+
///
1141+
/// This has the same lifetime as the original slice, and so the
1142+
/// iterator can continue to be used while this exists.
1143+
#[experimental]
1144+
pub fn as_slice(&self) -> &'a [T] {
1145+
make_slice!(T -> &'a [T]: self.ptr, self.end)
1146+
}
1147+
}
1148+
11031149
iterator!{struct Items -> *const T, &'a T}
11041150

11051151
#[experimental = "needs review"]
@@ -1144,6 +1190,57 @@ pub struct MutItems<'a, T: 'a> {
11441190
marker2: marker::NoCopy
11451191
}
11461192

1193+
#[experimental]
1194+
impl<'a, T> ops::Slice<uint, [T]> for MutItems<'a, T> {
1195+
fn as_slice_<'b>(&'b self) -> &'b [T] {
1196+
make_slice!(T -> &'b [T]: self.ptr, self.end)
1197+
}
1198+
fn slice_from_or_fail<'b>(&'b self, from: &uint) -> &'b [T] {
1199+
use ops::Slice;
1200+
self.as_slice_().slice_from_or_fail(from)
1201+
}
1202+
fn slice_to_or_fail<'b>(&'b self, to: &uint) -> &'b [T] {
1203+
use ops::Slice;
1204+
self.as_slice_().slice_to_or_fail(to)
1205+
}
1206+
fn slice_or_fail<'b>(&'b self, from: &uint, to: &uint) -> &'b [T] {
1207+
use ops::Slice;
1208+
self.as_slice_().slice_or_fail(from, to)
1209+
}
1210+
}
1211+
1212+
#[experimental]
1213+
impl<'a, T> ops::SliceMut<uint, [T]> for MutItems<'a, T> {
1214+
fn as_mut_slice_<'b>(&'b mut self) -> &'b mut [T] {
1215+
make_slice!(T -> &'b mut [T]: self.ptr, self.end)
1216+
}
1217+
fn slice_from_or_fail_mut<'b>(&'b mut self, from: &uint) -> &'b mut [T] {
1218+
use ops::SliceMut;
1219+
self.as_mut_slice_().slice_from_or_fail_mut(from)
1220+
}
1221+
fn slice_to_or_fail_mut<'b>(&'b mut self, to: &uint) -> &'b mut [T] {
1222+
use ops::SliceMut;
1223+
self.as_mut_slice_().slice_to_or_fail_mut(to)
1224+
}
1225+
fn slice_or_fail_mut<'b>(&'b mut self, from: &uint, to: &uint) -> &'b mut [T] {
1226+
use ops::SliceMut;
1227+
self.as_mut_slice_().slice_or_fail_mut(from, to)
1228+
}
1229+
}
1230+
1231+
impl<'a, T> MutItems<'a, T> {
1232+
/// View the underlying data as a subslice of the original data.
1233+
///
1234+
/// To avoid creating `&mut` references that alias, this is forced
1235+
/// to consume the iterator. Consider using the `Slice` and
1236+
/// `SliceMut` implementations for obtaining slices with more
1237+
/// restricted lifetimes that do not consume the iterator.
1238+
#[experimental]
1239+
pub fn into_slice(self) -> &'a mut [T] {
1240+
make_slice!(T -> &'a mut [T]: self.ptr, self.end)
1241+
}
1242+
}
1243+
11471244
iterator!{struct MutItems -> *mut T, &'a mut T}
11481245

11491246
#[experimental = "needs review"]

src/libcoretest/slice.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,52 @@ fn binary_search_not_found() {
3333
let b = [1i, 2, 4, 5, 6, 8];
3434
assert!(b.binary_search(|v| v.cmp(&9)) == NotFound(6));
3535
}
36+
37+
#[test]
38+
fn iterator_to_slice() {
39+
macro_rules! test {
40+
($data: expr) => {{
41+
let data: &mut [_] = &mut $data;
42+
let other_data: &mut [_] = &mut $data;
43+
44+
{
45+
let mut iter = data.iter();
46+
assert_eq!(iter[], other_data[]);
47+
48+
iter.next();
49+
assert_eq!(iter[], other_data[1..]);
50+
51+
iter.next_back();
52+
assert_eq!(iter[], other_data[1..2]);
53+
54+
let s = iter.as_slice();
55+
iter.next();
56+
assert_eq!(s, other_data[1..2]);
57+
}
58+
{
59+
let mut iter = data.iter_mut();
60+
assert_eq!(iter[], other_data[]);
61+
// mutability:
62+
assert!(iter[mut] == other_data);
63+
64+
iter.next();
65+
assert_eq!(iter[], other_data[1..]);
66+
assert!(iter[mut] == other_data[mut 1..]);
67+
68+
iter.next_back();
69+
70+
assert_eq!(iter[], other_data[1..2]);
71+
assert!(iter[mut] == other_data[mut 1..2]);
72+
73+
let s = iter.into_slice();
74+
assert!(s == other_data[mut 1..2]);
75+
}
76+
}}
77+
}
78+
79+
// try types of a variety of sizes
80+
test!([(1u64, 1u64, 1u8), (2, 2, 2), (3, 3, 3)]);
81+
test!([1u64,2,3]);
82+
test!([1u8,2,3]);
83+
test!([(),(),()]);
84+
}

0 commit comments

Comments
 (0)