about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-12-20 20:00:36 +0000
committerbors <bors@rust-lang.org>2014-12-20 20:00:36 +0000
commitcc19e3380b4b7c63b6f1f79d1dfc213ea00e16cf (patch)
treeee49930dbe4843c652894dd46c877ba69f857353
parent8a33de89c4a7acf04a2f3fa5d6ba4aa3fe3f8dc0 (diff)
parent525f65ebbf67283c13e3cd25c44e95f64fbc57c9 (diff)
downloadrust-cc19e3380b4b7c63b6f1f79d1dfc213ea00e16cf.tar.gz
rust-cc19e3380b4b7c63b6f1f79d1dfc213ea00e16cf.zip
auto merge of #19903 : cgaebel/rust/ringbuf-as-slice, r=Gankro
See: https://github.com/rust-lang/rfcs/pull/509

Not sure if this is allowed to land before the RFC. Either way,
it's here for review.

r? @Gankro
cc: @bfops
-rw-r--r--src/libcollections/ring_buf.rs113
1 files changed, 111 insertions, 2 deletions
diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs
index b0228593923..c807ef611e2 100644
--- a/src/libcollections/ring_buf.rs
+++ b/src/libcollections/ring_buf.rs
@@ -78,7 +78,13 @@ impl<T> Default for RingBuf<T> {
 impl<T> RingBuf<T> {
     /// Turn ptr into a slice
     #[inline]
-    unsafe fn buffer_as_slice(&self) -> &[T] {
+    unsafe fn buffer_as_slice<'a>(&'a self) -> &'a [T] {
+        mem::transmute(RawSlice { data: self.ptr as *const T, len: self.cap })
+    }
+
+    /// Turn ptr into a mut slice
+    #[inline]
+    unsafe fn buffer_as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
         mem::transmute(RawSlice { data: self.ptr as *const T, len: self.cap })
     }
 
@@ -413,6 +419,48 @@ impl<T> RingBuf<T> {
         }
     }
 
+    /// Returns a pair of slices which contain, in order, the contents of the
+    /// `RingBuf`.
+    #[inline]
+    #[unstable = "matches collection reform specification, waiting for dust to settle"]
+    pub fn as_slices<'a>(&'a self) -> (&'a [T], &'a [T]) {
+        unsafe {
+            let contiguous = self.is_contiguous();
+            let buf = self.buffer_as_slice();
+            if contiguous {
+                let (empty, buf) = buf.split_at(0);
+                (buf[self.tail..self.head], empty)
+            } else {
+                let (mid, right) = buf.split_at(self.tail);
+                let (left, _) = mid.split_at(self.head);
+                (right, left)
+            }
+        }
+    }
+
+    /// Returns a pair of slices which contain, in order, the contents of the
+    /// `RingBuf`.
+    #[inline]
+    #[unstable = "matches collection reform specification, waiting for dust to settle"]
+    pub fn as_mut_slices<'a>(&'a mut self) -> (&'a mut [T], &'a mut [T]) {
+        unsafe {
+            let contiguous = self.is_contiguous();
+            let head = self.head;
+            let tail = self.tail;
+            let buf = self.buffer_as_mut_slice();
+
+            if contiguous {
+                let (empty, buf) = buf.split_at_mut(0);
+                (buf[mut tail..head], empty)
+            } else {
+                let (mid, right) = buf.split_at_mut(tail);
+                let (left, _) = mid.split_at_mut(head);
+
+                (right, left)
+            }
+        }
+    }
+
     /// Returns the number of elements in the `RingBuf`.
     ///
     /// # Examples
@@ -663,6 +711,11 @@ impl<T> RingBuf<T> {
         }
     }
 
+    #[inline]
+    fn is_contiguous(&self) -> bool {
+        self.tail <= self.head
+    }
+
     /// Inserts an element at position `i` within the ringbuf. Whichever
     /// end is closer to the insertion point will be moved to make room,
     /// and all the affected elements will be moved to new positions.
@@ -715,7 +768,7 @@ impl<T> RingBuf<T> {
         let distance_to_tail = i;
         let distance_to_head = self.len() - i;
 
-        let contiguous = self.tail <= self.head;
+        let contiguous = self.is_contiguous();
 
         match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) {
             (true, true, _) if i == 0 => {
@@ -2131,4 +2184,60 @@ mod tests {
         ring.pop_front();
         assert_eq!(ring.front(), None);
     }
+
+    #[test]
+    fn test_as_slices() {
+        let mut ring: RingBuf<int> = RingBuf::with_capacity(127);
+        let cap = ring.capacity() as int;
+        let first = cap/2;
+        let last  = cap - first;
+        for i in range(0, first) {
+            ring.push_back(i);
+
+            let (left, right) = ring.as_slices();
+            let expected: Vec<_> = range(0, i+1).collect();
+            assert_eq!(left, expected);
+            assert_eq!(right, []);
+        }
+
+        for j in range(-last, 0) {
+            ring.push_front(j);
+            let (left, right) = ring.as_slices();
+            let expected_left: Vec<_> = range(-last, j+1).rev().collect();
+            let expected_right: Vec<_> = range(0, first).collect();
+            assert_eq!(left, expected_left);
+            assert_eq!(right, expected_right);
+        }
+
+        assert_eq!(ring.len() as int, cap);
+        assert_eq!(ring.capacity() as int, cap);
+    }
+
+    #[test]
+    fn test_as_mut_slices() {
+        let mut ring: RingBuf<int> = RingBuf::with_capacity(127);
+        let cap = ring.capacity() as int;
+        let first = cap/2;
+        let last  = cap - first;
+        for i in range(0, first) {
+            ring.push_back(i);
+
+            let (left, right) = ring.as_mut_slices();
+            let expected: Vec<_> = range(0, i+1).collect();
+            assert_eq!(left, expected);
+            assert_eq!(right, []);
+        }
+
+        for j in range(-last, 0) {
+            ring.push_front(j);
+            let (left, right) = ring.as_mut_slices();
+            let expected_left: Vec<_> = range(-last, j+1).rev().collect();
+            let expected_right: Vec<_> = range(0, first).collect();
+            assert_eq!(left, expected_left);
+            assert_eq!(right, expected_right);
+        }
+
+        assert_eq!(ring.len() as int, cap);
+        assert_eq!(ring.capacity() as int, cap);
+    }
 }