Skip to content

Commit 6616dbf

Browse files
committed
auto merge of #10739 : DaGenix/rust/mut-chunks, r=alexcrichton
mut_chunks() returns an iterator that produces mutable slices. This is the mutable version of the existing chunks() method on the ImmutableVector trait. EDIT: This uses only safe code now. PREVIOUSLY: I tried to get this working with safe code only, but I couldn't figure out how to make that work. Before #8624, the exact same code worked without the need for the transmute() call. With that fix and without the transmute() call, the compiler complains about the call to mut_slice(). I think the issue is that the mutable slice that is returned will live longer than the self parameter since the self parameter doesn't have an explicit lifetime. However, that is the way that the Iterator trait defines the next() method. I'm sure there is a good reason for that, although I don't quite understand why. Anyway, I think the interface is safe, since the MutChunkIter will only hand out non-overlapping pointers and there is no way to get it to hand out the same pointer twice.
2 parents 7c889a2 + 2a8dfc3 commit 6616dbf

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

src/libstd/vec.rs

+102
Original file line numberDiff line numberDiff line change
@@ -1933,6 +1933,18 @@ pub trait MutableVector<'self, T> {
19331933
/// Returns a reversed iterator that allows modifying each value
19341934
fn mut_rev_iter(self) -> MutRevIterator<'self, T>;
19351935

1936+
/**
1937+
* Returns an iterator over `size` elements of the vector at a time.
1938+
* The chunks are mutable and do not overlap. If `size` does not divide the
1939+
* length of the vector, then the last chunk will not have length
1940+
* `size`.
1941+
*
1942+
* # Failure
1943+
*
1944+
* Fails if `size` is 0.
1945+
*/
1946+
fn mut_chunks(self, chunk_size: uint) -> MutChunkIter<'self, T>;
1947+
19361948
/**
19371949
* Returns a mutable reference to the first element in this slice
19381950
* and adjusts the slice in place so that it no longer contains
@@ -2069,6 +2081,13 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] {
20692081
self.mut_iter().invert()
20702082
}
20712083

2084+
#[inline]
2085+
fn mut_chunks(self, chunk_size: uint) -> MutChunkIter<'self, T> {
2086+
assert!(chunk_size > 0);
2087+
let len = self.len();
2088+
MutChunkIter { v: self, chunk_size: chunk_size, remaining: len }
2089+
}
2090+
20722091
fn mut_shift_ref(&mut self) -> &'self mut T {
20732092
unsafe {
20742093
let s: &mut Slice<T> = cast::transmute(self);
@@ -2556,6 +2575,59 @@ impl<'self, T> Clone for VecIterator<'self, T> {
25562575
iterator!{struct VecMutIterator -> *mut T, &'self mut T}
25572576
pub type MutRevIterator<'self, T> = Invert<VecMutIterator<'self, T>>;
25582577

2578+
/// An iterator over a vector in (non-overlapping) mutable chunks (`size` elements at a time). When
2579+
/// the vector len is not evenly divided by the chunk size, the last slice of the iteration will be
2580+
/// the remainder.
2581+
pub struct MutChunkIter<'self, T> {
2582+
priv v: &'self mut [T],
2583+
priv chunk_size: uint,
2584+
priv remaining: uint
2585+
}
2586+
2587+
impl<'self, T> Iterator<&'self mut [T]> for MutChunkIter<'self, T> {
2588+
#[inline]
2589+
fn next(&mut self) -> Option<&'self mut [T]> {
2590+
if self.remaining == 0 {
2591+
None
2592+
} else {
2593+
let sz = cmp::min(self.remaining, self.chunk_size);
2594+
let tmp = util::replace(&mut self.v, &mut []);
2595+
let (head, tail) = tmp.mut_split(sz);
2596+
self.v = tail;
2597+
self.remaining -= sz;
2598+
Some(head)
2599+
}
2600+
}
2601+
2602+
#[inline]
2603+
fn size_hint(&self) -> (uint, Option<uint>) {
2604+
if self.remaining == 0 {
2605+
(0, Some(0))
2606+
} else {
2607+
let (n, rem) = self.remaining.div_rem(&self.chunk_size);
2608+
let n = if rem > 0 { n + 1 } else { n };
2609+
(n, Some(n))
2610+
}
2611+
}
2612+
}
2613+
2614+
impl<'self, T> DoubleEndedIterator<&'self mut [T]> for MutChunkIter<'self, T> {
2615+
#[inline]
2616+
fn next_back(&mut self) -> Option<&'self mut [T]> {
2617+
if self.remaining == 0 {
2618+
None
2619+
} else {
2620+
let remainder = self.remaining % self.chunk_size;
2621+
let sz = if remainder != 0 { remainder } else { self.chunk_size };
2622+
let tmp = util::replace(&mut self.v, &mut []);
2623+
let (head, tail) = tmp.mut_split(self.remaining - sz);
2624+
self.v = head;
2625+
self.remaining -= sz;
2626+
Some(tail)
2627+
}
2628+
}
2629+
}
2630+
25592631
/// An iterator that moves out of a vector.
25602632
#[deriving(Clone)]
25612633
pub struct MoveIterator<T> {
@@ -3966,6 +4038,36 @@ mod tests {
39664038
x.pop_ref();
39674039
}
39684040

4041+
#[test]
4042+
fn test_mut_chunks() {
4043+
let mut v = [0u8, 1, 2, 3, 4, 5, 6];
4044+
for (i, chunk) in v.mut_chunks(3).enumerate() {
4045+
for x in chunk.mut_iter() {
4046+
*x = i as u8;
4047+
}
4048+
}
4049+
let result = [0u8, 0, 0, 1, 1, 1, 2];
4050+
assert_eq!(v, result);
4051+
}
4052+
4053+
#[test]
4054+
fn test_mut_chunks_invert() {
4055+
let mut v = [0u8, 1, 2, 3, 4, 5, 6];
4056+
for (i, chunk) in v.mut_chunks(3).invert().enumerate() {
4057+
for x in chunk.mut_iter() {
4058+
*x = i as u8;
4059+
}
4060+
}
4061+
let result = [2u8, 2, 2, 1, 1, 1, 0];
4062+
assert_eq!(v, result);
4063+
}
4064+
4065+
#[test]
4066+
#[should_fail]
4067+
fn test_mut_chunks_0() {
4068+
let mut v = [1, 2, 3, 4];
4069+
let _it = v.mut_chunks(0);
4070+
}
39694071

39704072
#[test]
39714073
fn test_mut_shift_ref() {

0 commit comments

Comments
 (0)