Skip to content

Commit 97d4e76

Browse files
committed
Auto merge of rust-lang#24701 - Stebalien:slice, r=alexcrichton
Instead of using the O(n) defaults, define O(1) shortcuts. I also copied (and slightly modified) the relevant tests from the iter tests into the slice tests just in case someone comes along and changes them in the future. Partially implements rust-lang#24214.
2 parents 9c88f3b + e129b92 commit 97d4e76

File tree

2 files changed

+110
-25
lines changed

2 files changed

+110
-25
lines changed

src/libcore/slice.rs

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,36 @@ impl<'a, T> IntoIterator for &'a mut [T] {
625625
}
626626
}
627627

628+
#[inline(always)]
629+
fn size_from_ptr<T>(_: *const T) -> usize {
630+
mem::size_of::<T>()
631+
}
632+
633+
634+
// Use macro to be generic over const/mut
635+
macro_rules! slice_offset {
636+
($ptr:expr, $by:expr) => {{
637+
let ptr = $ptr;
638+
if size_from_ptr(ptr) == 0 {
639+
transmute(ptr as usize + $by)
640+
} else {
641+
ptr.offset($by)
642+
}
643+
}};
644+
}
645+
646+
macro_rules! slice_ref {
647+
($ptr:expr) => {{
648+
let ptr = $ptr;
649+
if size_from_ptr(ptr) == 0 {
650+
// Use a non-null pointer value
651+
&mut *(1 as *mut _)
652+
} else {
653+
transmute(ptr)
654+
}
655+
}};
656+
}
657+
628658
// The shared definition of the `Iter` and `IterMut` iterators
629659
macro_rules! iterator {
630660
(struct $name:ident -> $ptr:ty, $elem:ty) => {
@@ -641,20 +671,9 @@ macro_rules! iterator {
641671
if self.ptr == self.end {
642672
None
643673
} else {
644-
if mem::size_of::<T>() == 0 {
645-
// purposefully don't use 'ptr.offset' because for
646-
// vectors with 0-size elements this would return the
647-
// same pointer.
648-
self.ptr = transmute(self.ptr as usize + 1);
649-
650-
// Use a non-null pointer value
651-
Some(&mut *(1 as *mut _))
652-
} else {
653-
let old = self.ptr;
654-
self.ptr = self.ptr.offset(1);
655-
656-
Some(transmute(old))
657-
}
674+
let old = self.ptr;
675+
self.ptr = slice_offset!(self.ptr, 1);
676+
Some(slice_ref!(old))
658677
}
659678
}
660679
}
@@ -666,6 +685,22 @@ macro_rules! iterator {
666685
let exact = diff / (if size == 0 {1} else {size});
667686
(exact, Some(exact))
668687
}
688+
689+
#[inline]
690+
fn count(self) -> usize {
691+
self.size_hint().0
692+
}
693+
694+
#[inline]
695+
fn nth(&mut self, n: usize) -> Option<$elem> {
696+
// Call helper method. Can't put the definition here because mut versus const.
697+
self.iter_nth(n)
698+
}
699+
700+
#[inline]
701+
fn last(mut self) -> Option<$elem> {
702+
self.next_back()
703+
}
669704
}
670705

671706
#[stable(feature = "rust1", since = "1.0.0")]
@@ -679,17 +714,8 @@ macro_rules! iterator {
679714
if self.end == self.ptr {
680715
None
681716
} else {
682-
if mem::size_of::<T>() == 0 {
683-
// See above for why 'ptr.offset' isn't used
684-
self.end = transmute(self.end as usize - 1);
685-
686-
// Use a non-null pointer value
687-
Some(&mut *(1 as *mut _))
688-
} else {
689-
self.end = self.end.offset(-1);
690-
691-
Some(transmute(self.end))
692-
}
717+
self.end = slice_offset!(self.end, -1);
718+
Some(slice_ref!(self.end))
693719
}
694720
}
695721
}
@@ -785,6 +811,20 @@ impl<'a, T> Iter<'a, T> {
785811
pub fn as_slice(&self) -> &'a [T] {
786812
make_slice!(T => &'a [T]: self.ptr, self.end)
787813
}
814+
815+
// Helper function for Iter::nth
816+
fn iter_nth(&mut self, n: usize) -> Option<&'a T> {
817+
match self.as_slice().get(n) {
818+
Some(elem_ref) => unsafe {
819+
self.ptr = slice_offset!(elem_ref as *const _, 1);
820+
Some(slice_ref!(elem_ref))
821+
},
822+
None => {
823+
self.ptr = self.end;
824+
None
825+
}
826+
}
827+
}
788828
}
789829

790830
iterator!{struct Iter -> *const T, &'a T}
@@ -914,6 +954,20 @@ impl<'a, T> IterMut<'a, T> {
914954
pub fn into_slice(self) -> &'a mut [T] {
915955
make_mut_slice!(T => &'a mut [T]: self.ptr, self.end)
916956
}
957+
958+
// Helper function for IterMut::nth
959+
fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
960+
match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) {
961+
Some(elem_ref) => unsafe {
962+
self.ptr = slice_offset!(elem_ref as *mut _, 1);
963+
Some(slice_ref!(elem_ref))
964+
},
965+
None => {
966+
self.ptr = self.end;
967+
None
968+
}
969+
}
970+
}
917971
}
918972

919973
iterator!{struct IterMut -> *mut T, &'a mut T}

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)