Parcourir la source

Bad Safe Deque

runningwater il y a 2 ans
Parent
commit
858a99b6d7
5 fichiers modifiés avec 151 ajouts et 3 suppressions
  1. 1 1
      src/first.rs
  2. 147 0
      src/fourth.rs
  3. 1 0
      src/lib.rs
  4. 1 1
      src/second.rs
  5. 1 1
      src/third.rs

+ 1 - 1
src/first.rs

@@ -19,7 +19,7 @@ impl List {
     }
     pub fn push(&mut self, elem: i32) {
         let new_node = Box::new(Node {
-            elem: elem,
+            elem,
             next: mem::replace(&mut self.head, Link::Empty),
         });
 

+ 147 - 0
src/fourth.rs

@@ -0,0 +1,147 @@
+use std::cell::RefCell;
+use std::rc::Rc;
+
+/// Doubly-linked list
+///
+/// # example
+///
+/// ```rust
+///  use lists::fourth::List;
+///
+///  let mut list: List<i32> = List::new();
+///
+///  // Check empty list behaves right
+///  assert_eq!(list.pop_front(), None);
+///
+///  // Populate list
+///  list.push_front(1);
+///  list.push_front(2);
+///  list.push_front(3);
+///
+///  // Check normal removal
+///  assert_eq!(list.pop_front(), Some(3));
+///  assert_eq!(list.pop_front(), Some(2));
+///
+///  // Push some more just to make sure nothing's corrupted
+///  list.push_front(4);
+///  list.push_front(5);
+///
+///  // Check normal removal
+///  assert_eq!(list.pop_front(), Some(5));
+///  assert_eq!(list.pop_front(), Some(4));
+///
+///  // Check exhaustion
+///  assert_eq!(list.pop_front(), Some(1));
+///  assert_eq!(list.pop_front(), None);
+/// ```
+pub struct List<T> {
+    head: Link<T>,
+    tail: Link<T>,
+}
+
+type Link<T> = Option<Rc<RefCell<Node<T>>>>;
+
+struct Node<T> {
+    elem: T,
+    next: Link<T>,
+    prev: Link<T>,
+}
+
+impl<T> Node<T> {
+    fn new(elem: T) -> Rc<RefCell<Self>> {
+        Rc::new(RefCell::new(Node {
+            elem,
+            prev: None,
+            next: None,
+        }))
+    }
+}
+
+impl<T> List<T> {
+    pub fn new() -> Self {
+        List {
+            head: None,
+            tail: None,
+        }
+    }
+    pub fn push_front(&mut self, elem: T) {
+        // new node needs +2 links, everything else should be +0
+        let new_head = Node::new(elem);
+        match self.head.take() {
+            Some(old_head) => {
+                // non-empty list, need to connect the old_head
+                old_head.borrow_mut().prev = Some(new_head.clone()); // +1 new_head
+                new_head.borrow_mut().next = Some(old_head); // +1 old_head
+                self.head = Some(new_head); // +1 new_head, -1 old_head
+                                            // total: +2 new_head, +0 old_head -- OK!
+            }
+            None => {
+                // empty list, need to set the tail
+                self.tail = Some(new_head.clone()); // +1 new_head
+                self.head = Some(new_head); // +1 new_head
+                                            // total: +2 new_head -- OK!
+            }
+        }
+    }
+    pub fn pop_front(&mut self) -> Option<T> {
+        // need to take the old head, ensuring it's -2
+        self.head.take().map(|old_head| {
+            // -1 old
+            match old_head.borrow_mut().next.take() {
+                Some(new_head) => {
+                    // -1 new
+                    // not emptying list
+                    new_head.borrow_mut().prev.take(); // -1 old
+                    self.head = Some(new_head); // +1 new
+                                                // total: -2 old, +0 new
+                }
+                None => {
+                    // empty list
+                    self.tail.take(); // -1 old
+                                      // total: -2 old, (no new)
+                }
+            }
+            Rc::try_unwrap(old_head).ok().unwrap().into_inner().elem
+        })
+    }
+}
+
+impl<T> Drop for List<T> {
+    fn drop(&mut self) {
+        while self.pop_front().is_some() {}
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::List;
+
+    #[test]
+    fn basics() {
+        let mut list = List::new();
+
+        // Check empty
+        assert_eq!(list.pop_front(), None);
+
+        // Populate list
+        list.push_front(1);
+        list.push_front(2);
+        list.push_front(3);
+
+        // Check normal removal
+        assert_eq!(list.pop_front(), Some(3));
+        assert_eq!(list.pop_front(), Some(2));
+
+        // Push some more just to make sure nothing's corrupted
+        list.push_front(4);
+        list.push_front(5);
+
+        // Check normal removal
+        assert_eq!(list.pop_front(), Some(5));
+        assert_eq!(list.pop_front(), Some(4));
+
+        // Check exhaustion
+        assert_eq!(list.pop_front(), Some(1));
+        assert_eq!(list.pop_front(), None);
+    }
+}

+ 1 - 0
src/lib.rs

@@ -1,3 +1,4 @@
 pub mod first;
+pub mod fourth;
 pub mod second;
 pub mod third;

+ 1 - 1
src/second.rs

@@ -14,7 +14,7 @@ impl<T> List<T> {
     }
     pub fn push(&mut self, elem: T) {
         let new_node = Box::new(Node {
-            elem: elem,
+            elem,
             next: self.head.take(),
         });
 

+ 1 - 1
src/third.rs

@@ -15,7 +15,7 @@ impl<T> List<T> {
     pub fn prepend(&self, elem: T) -> List<T> {
         List {
             head: Some(Rc::new(Node {
-                elem: elem,
+                elem,
                 next: self.head.clone(),
             })),
         }