Skip to content

Commit f58a8c9

Browse files
author
Jonathan S
committed
Provide an implementation of DoubleEndedIterator for the results of &[T]::split and &[T]::rsplit
This makes the splitting functions in std::slice return DoubleEndedIterators. Unfortunately, splitn and rsplitn cannot provide such an interface and so must return different types. As a result, the following changes were made: * RevSplits was removed in favor of explicitly using Rev * Splits can no longer bound the number of splits done * Splits now implements DoubleEndedIterator * SplitsN was added, taking the role of what both Splits and RevSplits used to be * rsplit returns Rev<Splits<'a, T>> instead of RevSplits<'a, T> * splitn returns SplitsN<'a, T> instead of Splits<'a, T> * rsplitn returns SplitsN<'a, T> instead of RevSplits<'a, T> All functions that were previously implemented on each return value still are, so outside of changing of type annotations, existing code should work out of the box. In the rare case that code relied on the return types of split and splitn or of rsplit and rsplitn being the same, the previous behavior can be emulated by calling splitn or rsplitn with a bount of uint::MAX. The value of this change comes in multiple parts: * Consistency. The splitting code in std::str is structured similarly to the new slice splitting code, having separate CharSplits and CharSplitsN types. * Smaller API. Although this commit doesn't implement it, using a DoubleEndedIterator for splitting means that rsplit, path::RevComponents, path::RevStrComponents, Path::rev_components, and Path::rev_str_components are no longer needed - they can be emulated simply with .rev(). * Power. DoubleEndedIterators are able to traverse the list from both sides at once instead of only forwards or backwards. * Efficiency. For the common case of using split instead of splitn, the iterator is slightly smaller and slightly faster. [breaking-change]
1 parent 23262a8 commit f58a8c9

File tree

3 files changed

+64
-84
lines changed

3 files changed

+64
-84
lines changed

src/libstd/path/posix.rs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -16,11 +16,11 @@ use clone::Clone;
1616
use cmp::{Eq, TotalEq};
1717
use from_str::FromStr;
1818
use io::Writer;
19-
use iter::{AdditiveIterator, Extendable, Iterator, Map};
19+
use iter::{DoubleEndedIterator, Rev, AdditiveIterator, Extendable, Iterator, Map};
2020
use option::{Option, None, Some};
2121
use str;
2222
use str::Str;
23-
use slice::{CloneableVector, RevSplits, Splits, Vector, VectorVector,
23+
use slice::{CloneableVector, Splits, Vector, VectorVector,
2424
ImmutableEqVector, OwnedVector, ImmutableVector};
2525
use vec::Vec;
2626

@@ -29,14 +29,13 @@ use super::{BytesContainer, GenericPath, GenericPathUnsafe};
2929
/// Iterator that yields successive components of a Path as &[u8]
3030
pub type Components<'a> = Splits<'a, u8>;
3131
/// Iterator that yields components of a Path in reverse as &[u8]
32-
pub type RevComponents<'a> = RevSplits<'a, u8>;
32+
pub type RevComponents<'a> = Rev<Components<'a>>;
3333

3434
/// Iterator that yields successive components of a Path as Option<&str>
3535
pub type StrComponents<'a> = Map<'a, &'a [u8], Option<&'a str>,
3636
Components<'a>>;
3737
/// Iterator that yields components of a Path in reverse as Option<&str>
38-
pub type RevStrComponents<'a> = Map<'a, &'a [u8], Option<&'a str>,
39-
RevComponents<'a>>;
38+
pub type RevStrComponents<'a> = Rev<StrComponents<'a>>;
4039

4140
/// Represents a POSIX file path
4241
#[deriving(Clone)]
@@ -397,15 +396,7 @@ impl Path {
397396
/// Returns an iterator that yields each component of the path in reverse.
398397
/// See components() for details.
399398
pub fn rev_components<'a>(&'a self) -> RevComponents<'a> {
400-
let v = if *self.repr.get(0) == SEP_BYTE {
401-
self.repr.slice_from(1)
402-
} else { self.repr.as_slice() };
403-
let mut ret = v.rsplit(is_sep_byte);
404-
if v.is_empty() {
405-
// consume the empty "" component
406-
ret.next();
407-
}
408-
ret
399+
self.components().rev()
409400
}
410401

411402
/// Returns an iterator that yields each component of the path as Option<&str>.
@@ -417,7 +408,7 @@ impl Path {
417408
/// Returns an iterator that yields each component of the path in reverse as Option<&str>.
418409
/// See components() for details.
419410
pub fn rev_str_components<'a>(&'a self) -> RevStrComponents<'a> {
420-
self.rev_components().map(str::from_utf8)
411+
self.str_components().rev()
421412
}
422413
}
423414

src/libstd/path/windows.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -37,15 +37,13 @@ pub type StrComponents<'a> = Map<'a, &'a str, Option<&'a str>,
3737
///
3838
/// Each component is yielded as Option<&str> for compatibility with PosixPath, but
3939
/// every component in WindowsPath is guaranteed to be Some.
40-
pub type RevStrComponents<'a> = Rev<Map<'a, &'a str, Option<&'a str>,
41-
CharSplits<'a, char>>>;
40+
pub type RevStrComponents<'a> = Rev<StrComponents<'a>>;
4241

4342
/// Iterator that yields successive components of a Path as &[u8]
4443
pub type Components<'a> = Map<'a, Option<&'a str>, &'a [u8],
4544
StrComponents<'a>>;
4645
/// Iterator that yields components of a Path in reverse as &[u8]
47-
pub type RevComponents<'a> = Map<'a, Option<&'a str>, &'a [u8],
48-
RevStrComponents<'a>>;
46+
pub type RevComponents<'a> = Rev<Components<'a>>;
4947

5048
/// Represents a Windows path
5149
// Notes for Windows path impl:
@@ -650,11 +648,7 @@ impl Path {
650648
/// Returns an iterator that yields each component of the path in reverse as a &[u8].
651649
/// See str_components() for details.
652650
pub fn rev_components<'a>(&'a self) -> RevComponents<'a> {
653-
fn convert<'a>(x: Option<&'a str>) -> &'a [u8] {
654-
#![inline]
655-
x.unwrap().as_bytes()
656-
}
657-
self.rev_str_components().map(convert)
651+
self.components().rev()
658652
}
659653

660654
fn equiv_prefix(&self, other: &Path) -> bool {

src/libstd/slice.rs

Lines changed: 53 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ use result::{Ok, Err};
119119
use mem;
120120
use mem::size_of;
121121
use kinds::marker;
122-
use uint;
123122
use unstable::finally::try_finally;
124123
use raw::{Repr, Slice};
125124
use RawVec = raw::Vec;
@@ -148,7 +147,6 @@ pub fn mut_ref_slice<'a, A>(s: &'a mut A) -> &'a mut [A] {
148147
/// match a predicate function.
149148
pub struct Splits<'a, T> {
150149
v: &'a [T],
151-
n: uint,
152150
pred: |t: &T|: 'a -> bool,
153151
finished: bool
154152
}
@@ -158,11 +156,6 @@ impl<'a, T> Iterator<&'a [T]> for Splits<'a, T> {
158156
fn next(&mut self) -> Option<&'a [T]> {
159157
if self.finished { return None; }
160158

161-
if self.n == 0 {
162-
self.finished = true;
163-
return Some(self.v);
164-
}
165-
166159
match self.v.iter().position(|x| (self.pred)(x)) {
167160
None => {
168161
self.finished = true;
@@ -171,7 +164,6 @@ impl<'a, T> Iterator<&'a [T]> for Splits<'a, T> {
171164
Some(idx) => {
172165
let ret = Some(self.v.slice(0, idx));
173166
self.v = self.v.slice(idx + 1, self.v.len());
174-
self.n -= 1;
175167
ret
176168
}
177169
}
@@ -180,38 +172,18 @@ impl<'a, T> Iterator<&'a [T]> for Splits<'a, T> {
180172
#[inline]
181173
fn size_hint(&self) -> (uint, Option<uint>) {
182174
if self.finished {
183-
return (0, Some(0))
184-
}
185-
// if the predicate doesn't match anything, we yield one slice
186-
// if it matches every element, we yield N+1 empty slices where
187-
// N is either the number of elements or the number of splits.
188-
match (self.v.len(), self.n) {
189-
(0,_) => (1, Some(1)),
190-
(_,0) => (1, Some(1)),
191-
(l,n) => (1, cmp::min(l,n).checked_add(&1u))
175+
(0, Some(0))
176+
} else {
177+
(1, Some(self.v.len() + 1))
192178
}
193179
}
194180
}
195181

196-
/// An iterator over the slices of a vector separated by elements that
197-
/// match a predicate function, from back to front.
198-
pub struct RevSplits<'a, T> {
199-
v: &'a [T],
200-
n: uint,
201-
pred: |t: &T|: 'a -> bool,
202-
finished: bool
203-
}
204-
205-
impl<'a, T> Iterator<&'a [T]> for RevSplits<'a, T> {
182+
impl<'a, T> DoubleEndedIterator<&'a [T]> for Splits<'a, T> {
206183
#[inline]
207-
fn next(&mut self) -> Option<&'a [T]> {
184+
fn next_back(&mut self) -> Option<&'a [T]> {
208185
if self.finished { return None; }
209186

210-
if self.n == 0 {
211-
self.finished = true;
212-
return Some(self.v);
213-
}
214-
215187
match self.v.iter().rposition(|x| (self.pred)(x)) {
216188
None => {
217189
self.finished = true;
@@ -220,21 +192,42 @@ impl<'a, T> Iterator<&'a [T]> for RevSplits<'a, T> {
220192
Some(idx) => {
221193
let ret = Some(self.v.slice(idx + 1, self.v.len()));
222194
self.v = self.v.slice(0, idx);
223-
self.n -= 1;
224195
ret
225196
}
226197
}
227198
}
199+
}
228200

201+
/// An iterator over the slices of a vector separated by elements that
202+
/// match a predicate function, splitting at most a fixed number of times.
203+
pub struct SplitsN<'a, T> {
204+
iter: Splits<'a, T>,
205+
count: uint,
206+
invert: bool
207+
}
208+
209+
impl<'a, T> Iterator<&'a [T]> for SplitsN<'a, T> {
229210
#[inline]
230-
fn size_hint(&self) -> (uint, Option<uint>) {
231-
if self.finished {
232-
return (0, Some(0))
211+
fn next(&mut self) -> Option<&'a [T]> {
212+
if self.count == 0 {
213+
if self.iter.finished {
214+
None
215+
} else {
216+
self.iter.finished = true;
217+
Some(self.iter.v)
218+
}
219+
} else {
220+
self.count -= 1;
221+
if self.invert { self.iter.next_back() } else { self.iter.next() }
233222
}
234-
match (self.v.len(), self.n) {
235-
(0,_) => (1, Some(1)),
236-
(_,0) => (1, Some(1)),
237-
(l,n) => (1, cmp::min(l,n).checked_add(&1u))
223+
}
224+
225+
#[inline]
226+
fn size_hint(&self) -> (uint, Option<uint>) {
227+
if self.iter.finished {
228+
(0, Some(0))
229+
} else {
230+
(1, Some(cmp::min(self.count, self.iter.v.len()) + 1))
238231
}
239232
}
240233
}
@@ -747,18 +740,18 @@ pub trait ImmutableVector<'a, T> {
747740
/// separated by elements that match `pred`, limited to splitting
748741
/// at most `n` times. The matched element is not contained in
749742
/// the subslices.
750-
fn splitn(self, n: uint, pred: |&T|: 'a -> bool) -> Splits<'a, T>;
743+
fn splitn(self, n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T>;
751744
/// Returns an iterator over the subslices of the vector which are
752745
/// separated by elements that match `pred`. This starts at the
753746
/// end of the vector and works backwards. The matched element is
754747
/// not contained in the subslices.
755-
fn rsplit(self, pred: |&T|: 'a -> bool) -> RevSplits<'a, T>;
748+
fn rsplit(self, pred: |&T|: 'a -> bool) -> Rev<Splits<'a, T>>;
756749
/// Returns an iterator over the subslices of the vector which are
757750
/// separated by elements that match `pred` limited to splitting
758751
/// at most `n` times. This starts at the end of the vector and
759752
/// works backwards. The matched element is not contained in the
760753
/// subslices.
761-
fn rsplitn(self, n: uint, pred: |&T|: 'a -> bool) -> RevSplits<'a, T>;
754+
fn rsplitn(self, n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T>;
762755

763756
/**
764757
* Returns an iterator over all contiguous windows of length
@@ -936,31 +929,33 @@ impl<'a,T> ImmutableVector<'a, T> for &'a [T] {
936929

937930
#[inline]
938931
fn split(self, pred: |&T|: 'a -> bool) -> Splits<'a, T> {
939-
self.splitn(uint::MAX, pred)
940-
}
941-
942-
#[inline]
943-
fn splitn(self, n: uint, pred: |&T|: 'a -> bool) -> Splits<'a, T> {
944932
Splits {
945933
v: self,
946-
n: n,
947934
pred: pred,
948935
finished: false
949936
}
950937
}
951938

952939
#[inline]
953-
fn rsplit(self, pred: |&T|: 'a -> bool) -> RevSplits<'a, T> {
954-
self.rsplitn(uint::MAX, pred)
940+
fn splitn(self, n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T> {
941+
SplitsN {
942+
iter: self.split(pred),
943+
count: n,
944+
invert: false
945+
}
955946
}
956947

957948
#[inline]
958-
fn rsplitn(self, n: uint, pred: |&T|: 'a -> bool) -> RevSplits<'a, T> {
959-
RevSplits {
960-
v: self,
961-
n: n,
962-
pred: pred,
963-
finished: false
949+
fn rsplit(self, pred: |&T|: 'a -> bool) -> Rev<Splits<'a, T>> {
950+
self.split(pred).rev()
951+
}
952+
953+
#[inline]
954+
fn rsplitn(self, n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T> {
955+
SplitsN {
956+
iter: self.split(pred),
957+
count: n,
958+
invert: true
964959
}
965960
}
966961

0 commit comments

Comments
 (0)