]> git.lizzy.rs Git - rust.git/commitdiff
dlist: Expose ListInsertion trait with insert_before and peek_next
authorblake2-ppc <blake2-ppc>
Wed, 10 Jul 2013 01:49:32 +0000 (03:49 +0200)
committerblake2-ppc <blake2-ppc>
Thu, 11 Jul 2013 13:54:35 +0000 (15:54 +0200)
An iterator that allows mutating the list is very useful but needs care
to not be unsound. ListIteration exposes only insert_before (used for
insert_ordered) and peek_next so far.

src/libextra/dlist.rs

index 7cca33dbbd3493d8ba005f924a78f2f9e4fde892..5722e39eb0f5c888bb6f4225cd2a40e1ab6c3a3d 100644 (file)
@@ -272,7 +272,7 @@ pub fn prepend(&mut self, mut other: List<T>) {
     ///
     /// O(N)
     #[inline]
-    pub fn insert_before(&mut self, elt: T, f: &fn(&T, &T) -> bool) {
+    pub fn insert_when(&mut self, elt: T, f: &fn(&T, &T) -> bool) {
         {
             let mut it = self.mut_iter();
             loop {
@@ -341,7 +341,7 @@ pub fn consume_rev_iter(self) -> ConsumeRevIterator<T> {
 /// O(N)
 impl<T: cmp::TotalOrd> List<T> {
     fn insert_ordered(&mut self, elt: T) {
-        self.insert_before(elt, |a, b| a.cmp(b) != cmp::Less);
+        self.insert_when(elt, |a, b| a.cmp(b) != cmp::Less);
     }
 }
 
@@ -363,7 +363,7 @@ fn size_hint(&self) -> (uint, Option<uint>) {
     }
 }
 
-// MutForwardIterator is different because it implements ListInsertCursor,
+// MutForwardIterator is different because it implements ListInsertion,
 // and can modify the list during traversal, used in insert_when and merge.
 impl<'self, A> Iterator<&'self mut A> for MutForwardIterator<'self, A> {
     #[inline]
@@ -433,19 +433,22 @@ fn size_hint(&self) -> (uint, Option<uint>) {
     }
 }
 
-// XXX: Should this be `pub`?
-trait ListInsertCursor<A> {
+/// Allow mutating the List while iterating
+pub trait ListInsertion<A> {
     /// Insert `elt` just previous to the most recently yielded element
     fn insert_before(&mut self, elt: A);
+
+    /// Provide a reference to the next element, without changing the iterator
+    fn peek_next<'a>(&'a mut self) -> Option<&'a mut A>;
 }
 
-impl<'self, A> ListInsertCursor<A> for MutForwardIterator<'self, A> {
+impl<'self, A> ListInsertion<A> for MutForwardIterator<'self, A> {
     fn insert_before(&mut self, elt: A) {
         match self.curs.resolve() {
-            None => self.list.push_front(elt),
+            None => { self.list.push_front(elt); self.next(); }
             Some(node) => {
                 let prev_node = match node.prev.resolve() {
-                    None => return self.list.push_front(elt),  // at head
+                    None => return self.list.push_front(elt),
                     Some(prev) => prev,
                 };
                 let mut ins_node = ~Node{value: elt, next: None, prev: Rawlink::none()};
@@ -456,6 +459,16 @@ fn insert_before(&mut self, elt: A) {
             }
         }
     }
+
+    fn peek_next<'a>(&'a mut self) -> Option<&'a mut A> {
+        match self.curs.resolve() {
+            None => self.list.peek_front_mut(),
+            Some(curs) => match curs.next {
+                None => None,
+                Some(ref mut node) => Some(&mut node.value),
+            }
+        }
+    }
 }
 
 impl<A> Iterator<A> for ConsumeIterator<A> {
@@ -695,20 +708,30 @@ fn test_mut_iter() {
     }
 
     #[test]
-    fn test_list_cursor() {
-        let mut m = generate_test();
+    fn test_insert_prev() {
+        let mut m = list_from(&[0,2,4,6,8]);
         let len = m.len();
         {
             let mut it = m.mut_iter();
+            it.insert_before(-2);
             loop {
                 match it.next() {
                     None => break,
-                    Some(elt) => it.insert_before(*elt * 2),
+                    Some(elt) => {
+                        it.insert_before(*elt + 1);
+                        match it.peek_next() {
+                            Some(x) => assert_eq!(*x, *elt + 2),
+                            None => assert_eq!(8, *elt),
+                        }
+                    }
                 }
             }
+            it.insert_before(0);
+            it.insert_before(1);
         }
-        assert_eq!(m.len(), len * 2);
         check_links(&m);
+        assert_eq!(m.len(), 3 + len * 2);
+        assert_eq!(m.consume_iter().collect::<~[int]>(), ~[-2,1,0,3,2,5,4,7,6,9,0,1,8]);
     }
 
     #[test]