Skip to content

Commit de8c79a

Browse files
committed
Implement O(1) slice::Iter methods.
Instead of using the O(n) defaults, define O(1) shortcuts.
1 parent e9e9279 commit de8c79a

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

src/libcore/slice.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,60 @@ macro_rules! iterator {
666666
let exact = diff / (if size == 0 {1} else {size});
667667
(exact, Some(exact))
668668
}
669+
670+
#[inline]
671+
fn count(self) -> usize {
672+
self.size_hint().0
673+
}
674+
675+
#[inline]
676+
fn nth(&mut self, n: usize) -> Option<$elem> {
677+
// could be implemented with slices, but this avoids bounds checks
678+
unsafe {
679+
::intrinsics::assume(!self.ptr.is_null());
680+
::intrinsics::assume(!self.end.is_null());
681+
// There should be some way to use offset and optimize this to LEA but I don't
682+
// know how to do that AND detect overflow...
683+
let size = mem::size_of::<T>();
684+
if size == 0 {
685+
if let Some(new_ptr) = (self.ptr as usize).checked_add(n) {
686+
if new_ptr < (self.end as usize) {
687+
self.ptr = transmute(new_ptr + 1);
688+
return Some(&mut *(1 as *mut _))
689+
}
690+
}
691+
} else {
692+
if let Some(new_ptr) = n.checked_mul(size).and_then(|offset| {
693+
(self.ptr as usize).checked_add(offset)
694+
}) {
695+
if new_ptr < (self.end as usize) {
696+
self.ptr = transmute(new_ptr + size);
697+
return Some(transmute(new_ptr))
698+
}
699+
}
700+
}
701+
None
702+
}
703+
}
704+
705+
#[inline]
706+
fn last(self) -> Option<$elem> {
707+
// We could just call next_back but this avoids the memory write.
708+
unsafe {
709+
::intrinsics::assume(!self.ptr.is_null());
710+
::intrinsics::assume(!self.end.is_null());
711+
if self.end == self.ptr {
712+
None
713+
} else {
714+
if mem::size_of::<T>() == 0 {
715+
// Use a non-null pointer value
716+
Some(&mut *(1 as *mut _))
717+
} else {
718+
Some(transmute(self.end.offset(-1)))
719+
}
720+
}
721+
}
722+
}
669723
}
670724

671725
#[stable(feature = "rust1", since = "1.0.0")]

src/libcoretest/slice.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,34 @@ fn iterator_to_slice() {
8282
test!([1u8,2,3]);
8383
test!([(),(),()]);
8484
}
85+
86+
#[test]
87+
fn test_iterator_nth() {
88+
let v: &[_] = &[0, 1, 2, 3, 4];
89+
for i in 0..v.len() {
90+
assert_eq!(v.iter().nth(i).unwrap(), &v[i]);
91+
}
92+
assert_eq!(v.iter().nth(v.len()), None);
93+
94+
let mut iter = v.iter();
95+
assert_eq!(iter.nth(2).unwrap(), &v[2]);
96+
assert_eq!(iter.nth(1).unwrap(), &v[4]);
97+
}
98+
99+
#[test]
100+
fn test_iterator_last() {
101+
let v: &[_] = &[0, 1, 2, 3, 4];
102+
assert_eq!(v.iter().last().unwrap(), &4);
103+
assert_eq!(v[..1].iter().last().unwrap(), &0);
104+
}
105+
106+
#[test]
107+
fn test_iterator_count() {
108+
let v: &[_] = &[0, 1, 2, 3, 4];
109+
assert_eq!(v.iter().count(), 5);
110+
111+
let mut iter2 = v.iter();
112+
iter2.next();
113+
iter2.next();
114+
assert_eq!(iter2.count(), 3);
115+
}

0 commit comments

Comments
 (0)