about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-08-13 00:26:29 +0000
committerbors <bors@rust-lang.org>2015-08-13 00:26:29 +0000
commit021389f6adbb215bb8fe267c93bc1a9daeb2ec14 (patch)
tree0695e164b30fdb2c7017d55f5858f948593c23b6 /src/libcore
parent82169afba773828ddb8a7e3770ba62d90c711079 (diff)
parente09f83ea4491ae7c1e48d667b9c552641de0ce5b (diff)
downloadrust-021389f6adbb215bb8fe267c93bc1a9daeb2ec14.tar.gz
rust-021389f6adbb215bb8fe267c93bc1a9daeb2ec14.zip
Auto merge of #27652 - alex-ozdemir:iter, r=bluss
Provides a custom implementation of Iterator methods `count`, `nth`, and `last` for the structures `slice::{Windows,Chunks,ChunksMut}` in the core module.

These implementations run in constant time as opposed to the default implementations which run in linear time.

Addresses Issue #24214 

r? @aturon 
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/slice.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index aa34b651157..f6220a74b24 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -50,6 +50,7 @@ use ptr;
 use mem;
 use mem::size_of;
 use marker::{Send, Sync, self};
+use num::wrapping::OverflowingOps;
 use raw::Repr;
 // Avoid conflicts with *both* the Slice trait (buggy) and the `slice::raw` module.
 use raw::Slice as RawSlice;
@@ -1180,6 +1181,34 @@ impl<'a, T> Iterator for Windows<'a, T> {
             (size, Some(size))
         }
     }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.size_hint().0
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        let (end, overflow) = self.size.overflowing_add(n);
+        if end > self.v.len() || overflow {
+            self.v = &[];
+            None
+        } else {
+            let nth = &self.v[n..end];
+            self.v = &self.v[n+1..];
+            Some(nth)
+        }
+    }
+
+    #[inline]
+    fn last(self) -> Option<Self::Item> {
+        if self.size > self.v.len() {
+            None
+        } else {
+            let start = self.v.len() - self.size;
+            Some(&self.v[start..])
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1266,6 +1295,38 @@ impl<'a, T> Iterator for Chunks<'a, T> {
             (n, Some(n))
         }
     }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.size_hint().0
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        let (start, overflow) = n.overflowing_mul(self.size);
+        if start >= self.v.len() || overflow {
+            self.v = &[];
+            None
+        } else {
+            let end = match start.checked_add(self.size) {
+                Some(sum) => cmp::min(self.v.len(), sum),
+                None => self.v.len(),
+            };
+            let nth = &self.v[start..end];
+            self.v = &self.v[end..];
+            Some(nth)
+        }
+    }
+
+    #[inline]
+    fn last(self) -> Option<Self::Item> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let start = (self.v.len() - 1) / self.size * self.size;
+            Some(&self.v[start..])
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1346,6 +1407,40 @@ impl<'a, T> Iterator for ChunksMut<'a, T> {
             (n, Some(n))
         }
     }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.size_hint().0
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
+        let (start, overflow) = n.overflowing_mul(self.chunk_size);
+        if start >= self.v.len() || overflow {
+            self.v = &mut [];
+            None
+        } else {
+            let end = match start.checked_add(self.chunk_size) {
+                Some(sum) => cmp::min(self.v.len(), sum),
+                None => self.v.len(),
+            };
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let (head, tail) = tmp.split_at_mut(end);
+            let (_, nth) =  head.split_at_mut(start);
+            self.v = tail;
+            Some(nth)
+        }
+    }
+
+    #[inline]
+    fn last(self) -> Option<Self::Item> {
+        if self.v.is_empty() {
+            None
+        } else {
+            let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
+            Some(&mut self.v[start..])
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]