Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@steveklabnik
Created September 5, 2018 19:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steveklabnik/a7c53ddc3e357ad5cdba8559b0adfa0c to your computer and use it in GitHub Desktop.
Save steveklabnik/a7c53ddc3e357ad5cdba8559b0adfa0c to your computer and use it in GitHub Desktop.
yeah it's a linked list
use std::ptr;
pub struct DoubleLinkedList<T> {
head: *mut Entry<T>,
tail: *mut Entry<T>,
}
pub struct Entry<T> {
item: T,
next: *mut Entry<T>,
prev: *mut Entry<T>,
}
impl<T> Entry<T> {
fn alloc_new(item: T) -> *mut Entry<T> {
let entry = Entry {
item,
next: ptr::null_mut(),
prev: ptr::null_mut(),
};
Box::into_raw(Box::new(entry))
}
fn alloc_with_previous(item: T, prev: *mut Entry<T>) -> *mut Entry<T> {
let entry = Entry {
item,
next: ptr::null_mut(),
prev,
};
Box::into_raw(Box::new(entry))
}
pub fn item(&mut self) -> *mut T {
&mut self.item as *mut _
}
}
impl<T> DoubleLinkedList<T> {
pub fn new() -> DoubleLinkedList<T> {
DoubleLinkedList {
head: ptr::null_mut(),
tail: ptr::null_mut(),
}
}
pub fn insert(&mut self, item: T) {
if self.head.is_null() {
let raw = Entry::alloc_new(item);
self.head = raw;
self.tail = raw;
} else {
let tail = self.tail;
let raw = Entry::alloc_with_previous(item, tail);
unsafe {
(*tail).next = raw;
self.tail = raw;
};
}
}
}
impl<T> Drop for DoubleLinkedList<T> {
fn drop(&mut self) {
let mut current = self.head;
loop {
if current.is_null() {
break;
}
unsafe {
let next = (*current).next;
let b = Box::from_raw(current);
drop(b);
current = next;
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn insert_one() {
let mut list = DoubleLinkedList::new();
list.insert(5);
unsafe {
let five = list.head;
assert!(!five.is_null());
assert_eq!((*five).item, 5);
assert!((*five).next.is_null());
assert!((*five).prev.is_null());
let five = list.tail;
assert!(!five.is_null());
assert_eq!((*five).item, 5);
assert!((*five).next.is_null());
assert!((*five).prev.is_null());
}
}
#[test]
fn insert_two() {
let mut list = DoubleLinkedList::new();
list.insert(5);
list.insert(10);
unsafe {
let five = list.head;
assert!(!(*five).next.is_null());
let ten = (*five).next;
assert!(!ten.is_null());
assert_eq!((*ten).item, 10);
assert!((*ten).next.is_null());
assert_eq!((*ten).prev, five);
let ten = list.tail;
assert!(!ten.is_null());
assert_eq!((*ten).item, 10);
assert!((*ten).next.is_null());
assert_eq!((*ten).prev, five);
}
}
#[test]
fn insert_three() {
let mut list = DoubleLinkedList::new();
list.insert(5);
list.insert(10);
list.insert(15);
unsafe {
let five = list.head;
let ten = (*five).next;
assert!(!(*ten).next.is_null());
let fifteen = (*ten).next;
assert!(!fifteen.is_null());
assert_eq!((*fifteen).item, 15);
assert!((*fifteen).next.is_null());
assert_eq!((*fifteen).prev, ten);
let fifteen = list.tail;
assert!(!fifteen.is_null());
assert_eq!((*fifteen).item, 15);
assert!((*fifteen).next.is_null());
assert_eq!((*fifteen).prev, ten);
}
}
#[test]
fn free() {
static mut COUNT: u32 = 0;
struct Boom;
impl Drop for Boom {
fn drop(&mut self) {
unsafe {
COUNT += 1;
}
}
}
let mut list = DoubleLinkedList::new();
list.insert(Boom);
list.insert(Boom);
list.insert(Boom);
drop(list);
unsafe {
assert_eq!(COUNT, 3);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment