matecito_dll/
lib.rs

1use std::ptr::NonNull;
2
3#[derive(Debug)]
4pub struct DoublyLinkedList<T> {
5    head: Option<NonNull<Node<T>>>,
6    tail: Option<NonNull<Node<T>>>,
7    elements: usize,
8}
9
10#[derive(Debug)]
11pub struct Node<T> {
12    pub elem: T,
13    pub next: Option<NonNull<Node<T>>>,
14    pub prev: Option<NonNull<Node<T>>>,
15}
16
17// OBS: we need this in order to use it for matecito
18#[cfg(feature = "matecito")]
19unsafe impl<T> Send for DoublyLinkedList<T> {}
20#[cfg(feature = "matecito")]
21unsafe impl<T> Sync for DoublyLinkedList<T> {}
22
23impl<T> DoublyLinkedList<T> {
24    pub fn new() -> Self {
25        Self {
26            head: None,
27            tail: None,
28            elements: 0,
29        }
30    }
31
32    pub fn delete(&mut self, non_null_node: NonNull<Node<T>>) -> Option<T> {
33        let mut non_null_node = non_null_node; // we need to make it mutable
34        let node = unsafe { non_null_node.as_mut() };
35
36        let prev_node = match node.prev {
37            None => None,
38            Some(mut pnode) => NonNull::new(unsafe { pnode.as_mut() }),
39        };
40
41        let next_node = match node.next {
42            None => None,
43            Some(mut pnode) => NonNull::new(unsafe { pnode.as_mut() }),
44        };
45
46        match next_node {
47            // the current node was the head. This is because we expect that there is always
48            // a previous node. The only case where this happen is when we're working with the head.
49            None => {
50                self.tail = prev_node;
51            }
52            Some(mut nnode_opt) => {
53                let next_node = unsafe { nnode_opt.as_mut() };
54                next_node.prev = prev_node;
55            }
56        }
57
58        match prev_node {
59            // the current node was the head. This is because we expect that there is always
60            // a previous node. The only case where this happen is when we're working with the head.
61            None => {
62                self.head = next_node;
63            }
64            Some(nnode_opt) => {
65                let prev_node = unsafe { nnode_opt.as_ptr().as_mut().unwrap() };
66                prev_node.next = next_node;
67            }
68        }
69
70        // Free node's memory
71        let node = unsafe { Box::from_raw(node) };
72
73        self.elements -= 1;
74        Some(node.elem)
75    }
76
77    pub fn push_back(&mut self, elem: T) -> NonNull<Node<T>> {
78        // a. if head is none, then head becomes the node
79        //    also tail becomes then node
80        // b. head becomes the node.
81        //    The previous head.prev points to the node.
82        //    head.next points to the previous head.
83
84        let node = Node {
85            elem,
86            next: None,
87            prev: None,
88        };
89        let boxed_node = Box::into_raw(Box::new(node));
90        let node = NonNull::new(boxed_node);
91
92        let raw_old_head = self.head;
93
94        // scenario (a)
95        if self.head.is_none() {
96            self.head = node;
97            self.tail = node;
98            self.elements += 1;
99            return self.head.unwrap();
100        }
101
102        // scenario (b)
103        self.head = node;
104
105        match raw_old_head {
106            None => (),
107            Some(mut non_null_node) => unsafe {
108                non_null_node.as_mut().prev = node;
109                self.head.unwrap().as_mut().next = raw_old_head;
110            },
111        };
112        self.elements += 1;
113        return self.head.unwrap();
114    }
115
116    pub fn pop_front(&mut self) -> Option<T> {
117        // no nodes in the tail
118        if self.tail.is_none() {
119            return None;
120        }
121        // there is at least one node.
122        // return the old tail.
123        let old_tail = self.tail;
124
125        self.tail = match old_tail {
126            None => return None,
127            Some(mut non_null_node) => unsafe { non_null_node.as_mut().prev },
128        };
129
130        if self.tail.is_none() {
131            self.head = None;
132        }
133
134        let old_tail = unsafe { Box::from_raw(old_tail.unwrap().as_ptr()) };
135        self.elements -= 1;
136        Some(old_tail.elem)
137    }
138
139    #[allow(dead_code)]
140    pub fn pop_back(&mut self) -> Option<T> {
141        // no nodes in the tail
142        if self.head.is_none() {
143            return None;
144        }
145        // there is at least one node.
146        // return the old head.
147        let old_head = self.head;
148
149        self.head = match old_head {
150            None => return None,
151            Some(mut non_null_node) => unsafe { non_null_node.as_mut().next },
152        };
153
154        if self.head.is_none() {
155            self.tail = None;
156        }
157
158        let result = unsafe { Box::from_raw(old_head.unwrap().as_ptr()) };
159        self.elements -= 1;
160        Some(result.elem)
161    }
162
163    #[allow(dead_code)]
164    pub fn peek_front(&self) -> Option<&NonNull<Node<T>>> {
165        if self.tail.is_none() {
166            return None;
167        }
168        self.tail.as_ref()
169    }
170
171    pub fn is_empty(&self) -> bool {
172        self.elements == 0
173    }
174
175    pub fn num_elements(&self) -> usize {
176        self.elements
177    }
178}
179
180impl<T> Drop for DoublyLinkedList<T> {
181    fn drop(&mut self) {
182        while !self.is_empty() {
183            self.pop_front();
184        }
185    }
186}
187#[cfg(test)]
188mod tests {
189    use super::*;
190
191    #[test]
192    fn push_front_and_pop_front() {
193        let mut dll = DoublyLinkedList::new();
194        assert_eq!(None, dll.pop_front());
195        let range = std::ops::Range {
196            start: 10,
197            end: 100,
198        };
199
200        for num in 0..range.len() {
201            dll.push_back(num);
202        }
203
204        for num in 0..range.len() {
205            assert_eq!(Some(num), dll.pop_front());
206        }
207        assert_eq!(None, dll.pop_front());
208    }
209
210    #[test]
211    fn push_front_and_pop_back() {
212        let mut dll = DoublyLinkedList::new();
213        assert_eq!(None, dll.pop_back());
214        let range = std::ops::Range {
215            start: 10,
216            end: 100,
217        };
218        for num in range.clone() {
219            dll.push_back(num);
220        }
221
222        for num in range.clone().rev().clone() {
223            assert_eq!(Some(num), dll.pop_back());
224        }
225        assert_eq!(None, dll.pop_back());
226    }
227
228    #[test]
229    fn populate_and_delete() {
230        let mut dll = DoublyLinkedList::new();
231        let range = std::ops::Range { start: 0, end: 3 };
232
233        let mut elements = vec![];
234        for num in range.clone() {
235            let node = dll.push_back(num as i32);
236            elements.push(node);
237        }
238
239        dll.delete(elements[1]);
240        dll.delete(elements[0]);
241        assert_eq!(Some(2), dll.pop_front());
242        assert!(dll.is_empty());
243        assert_eq!(None, dll.pop_front());
244    }
245
246    #[test]
247    fn num_elements() {
248        let mut dll = DoublyLinkedList::new();
249        let range = std::ops::Range { start: 0, end: 3 };
250
251        // with delete
252        let mut num_elements = range.len();
253        let mut elements = vec![];
254        for num in range.clone() {
255            let node = dll.push_back(num as i32);
256            elements.push(node);
257        }
258        for num in range.clone() {
259            dll.delete(elements[num]);
260            num_elements -= 1;
261            assert_eq!(num_elements, dll.num_elements());
262        }
263
264        // pop_front
265        let mut num_elements = range.len();
266        for num in range.clone() {
267            dll.push_back(num as i32);
268        }
269        for _ in range.clone() {
270            dll.pop_front();
271            num_elements -= 1;
272            assert_eq!(num_elements, dll.num_elements());
273        }
274
275        // // pop_back
276        let mut num_elements = range.len();
277        for num in range.clone() {
278            dll.push_back(num as i32);
279        }
280        for _ in range.clone() {
281            dll.pop_back();
282            num_elements -= 1;
283            assert_eq!(num_elements, dll.num_elements());
284        }
285    }
286
287    #[test]
288    fn edge_case_push_after_emptied_delete_and_empty_again() {
289        let mut dll = DoublyLinkedList::new();
290        let n1 = dll.push_back(1);
291        let n2 = dll.push_back(2);
292        let n3 = dll.push_back(3);
293
294        dll.delete(n1);
295        assert_eq!(2, dll.num_elements());
296
297        dll.delete(n2);
298        assert_eq!(1, dll.num_elements());
299
300        dll.delete(n3);
301        assert_eq!(0, dll.num_elements());
302        assert!(dll.is_empty());
303
304        let n1 = dll.push_back(1);
305        assert_eq!(1, dll.num_elements());
306        dll.delete(n1);
307        assert_eq!(0, dll.num_elements());
308        assert!(dll.is_empty());
309    }
310
311    #[test]
312    fn edge_case_push_after_emptied_pop_front_and_empty_again() {
313        let mut dll = DoublyLinkedList::new();
314        dll.push_back(1);
315        dll.push_back(2);
316        dll.push_back(3);
317
318        dll.pop_front();
319        assert_eq!(2, dll.num_elements());
320
321        dll.pop_front();
322        assert_eq!(1, dll.num_elements());
323
324        dll.pop_front();
325        assert_eq!(0, dll.num_elements());
326        assert!(dll.is_empty());
327
328        dll.push_back(1);
329        assert_eq!(1, dll.num_elements());
330        dll.pop_front();
331        assert_eq!(0, dll.num_elements());
332        assert!(dll.is_empty());
333    }
334
335    #[test]
336    fn edge_case_push_after_emptied_pop_back_and_empty_again() {
337        let mut dll = DoublyLinkedList::new();
338        dll.push_back(1);
339        dll.push_back(2);
340        dll.push_back(3);
341
342        dll.pop_back();
343        assert_eq!(2, dll.num_elements());
344
345        dll.pop_back();
346        assert_eq!(1, dll.num_elements());
347
348        dll.pop_back();
349        assert_eq!(0, dll.num_elements());
350        assert!(dll.is_empty());
351
352        dll.push_back(1);
353        assert_eq!(1, dll.num_elements());
354        dll.pop_back();
355        assert_eq!(0, dll.num_elements());
356        assert_eq!(None, dll.pop_back());
357        assert!(dll.is_empty());
358    }
359}