Skip to content

Commit a05a9a1

Browse files
author
blake2-ppc
committed
std: Improve vec::ChunkIter
Implement clone, bidirectionality and random access for this iterator
1 parent 872d15d commit a05a9a1

File tree

1 file changed

+51
-8
lines changed

1 file changed

+51
-8
lines changed

src/libstd/vec.rs

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ pub fn each_permutation<T:Clone>(values: &[T], fun: &fn(perm : &[T]) -> bool) ->
479479

480480
/// An iterator over the (overlapping) slices of length `size` within
481481
/// a vector.
482+
#[deriving(Clone)]
482483
pub struct WindowIter<'self, T> {
483484
priv v: &'self [T],
484485
priv size: uint
@@ -498,23 +499,57 @@ impl<'self, T> Iterator<&'self [T]> for WindowIter<'self, T> {
498499

499500
/// An iterator over a vector in (non-overlapping) chunks (`size`
500501
/// elements at a time).
502+
///
503+
/// When the vector len is not evenly divided by the chunk size,
504+
/// the last slice of the iteration will be the remainer.
505+
#[deriving(Clone)]
501506
pub struct ChunkIter<'self, T> {
502507
priv v: &'self [T],
503508
priv size: uint
504509
}
505510

506511
impl<'self, T> Iterator<&'self [T]> for ChunkIter<'self, T> {
507512
fn next(&mut self) -> Option<&'self [T]> {
508-
if self.size == 0 {
513+
if self.v.len() == 0 {
509514
None
510-
} else if self.size >= self.v.len() {
511-
// finished
512-
self.size = 0;
513-
Some(self.v)
514515
} else {
515-
let ret = Some(self.v.slice(0, self.size));
516-
self.v = self.v.slice(self.size, self.v.len());
517-
ret
516+
let chunksz = cmp::min(self.v.len(), self.size);
517+
let (fst, snd) = (self.v.slice_to(chunksz),
518+
self.v.slice_from(chunksz));
519+
self.v = snd;
520+
Some(fst)
521+
}
522+
}
523+
}
524+
525+
impl<'self, T> DoubleEndedIterator<&'self [T]> for ChunkIter<'self, T> {
526+
fn next_back(&mut self) -> Option<&'self [T]> {
527+
if self.v.len() == 0 {
528+
None
529+
} else {
530+
let remainder = self.v.len() % self.size;
531+
let chunksz = if remainder != 0 { remainder } else { self.size };
532+
let (fst, snd) = (self.v.slice_to(self.v.len() - chunksz),
533+
self.v.slice_from(self.v.len() - chunksz));
534+
self.v = fst;
535+
Some(snd)
536+
}
537+
}
538+
}
539+
540+
impl<'self, T> RandomAccessIterator<&'self [T]> for ChunkIter<'self, T> {
541+
#[inline]
542+
fn indexable(&self) -> uint {
543+
self.v.len()/self.size + if self.v.len() % self.size != 0 { 1 } else { 0 }
544+
}
545+
546+
#[inline]
547+
fn idx(&self, index: uint) -> Option<&'self [T]> {
548+
if index < self.indexable() {
549+
let lo = index * self.size;
550+
Some(self.v.slice(lo, cmp::min(lo, self.v.len() - self.size) + self.size))
551+
} else {
552+
None
518553
}
519554
}
520555
}
@@ -3378,6 +3413,14 @@ mod tests {
33783413
assert_eq!(v.chunk_iter(2).collect::<~[&[int]]>(), ~[&[1i,2], &[3,4], &[5]]);
33793414
assert_eq!(v.chunk_iter(3).collect::<~[&[int]]>(), ~[&[1i,2,3], &[4,5]]);
33803415
assert_eq!(v.chunk_iter(6).collect::<~[&[int]]>(), ~[&[1i,2,3,4,5]]);
3416+
3417+
assert_eq!(v.chunk_iter(2).invert().collect::<~[&[int]]>(), ~[&[5i], &[3,4], &[1,2]]);
3418+
let it = v.chunk_iter(2);
3419+
assert_eq!(it.indexable(), 3);
3420+
assert_eq!(it.idx(0).unwrap(), &[1,2]);
3421+
assert_eq!(it.idx(1).unwrap(), &[3,4]);
3422+
assert_eq!(it.idx(2).unwrap(), &[5]);
3423+
assert_eq!(it.idx(3), None);
33813424
}
33823425

33833426
#[test]

0 commit comments

Comments
 (0)