mirror of
https://github.com/Noratrieb/datastructures.git
synced 2026-01-14 17:35:02 +01:00
benches
This commit is contained in:
parent
a0b2f91a18
commit
e41d110dd7
3 changed files with 144 additions and 60 deletions
|
|
@ -6,4 +6,9 @@ edition = "2018"
|
|||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
[dev-dependencies]
|
||||
criterion = "0.3.5"
|
||||
|
||||
[[bench]]
|
||||
name = "linked_list"
|
||||
harness = false
|
||||
59
benches/linked_list.rs
Normal file
59
benches/linked_list.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use datastructures::linked_list::LinkedList;
|
||||
|
||||
fn create_random_list(size: usize) -> LinkedList<i32> {
|
||||
let mut number = 837582573;
|
||||
let mut list = LinkedList::new();
|
||||
for _ in 0..size {
|
||||
// just random stuff I cam up with, does not need to be actually random
|
||||
number = (number ^ (number << 5)) >> 3;
|
||||
list.push_back(number);
|
||||
}
|
||||
list
|
||||
}
|
||||
|
||||
fn create_random_std_list(size: usize) -> std::collections::LinkedList<i32> {
|
||||
let mut number = 837582573;
|
||||
let mut list = std::collections::LinkedList::new();
|
||||
for _ in 0..size {
|
||||
// just random stuff I cam up with, does not need to be actually random
|
||||
number = (number ^ (number << 5)) >> 3;
|
||||
list.push_back(number);
|
||||
}
|
||||
list
|
||||
}
|
||||
|
||||
fn list_length(list: &LinkedList<i32>) -> usize {
|
||||
list.len()
|
||||
}
|
||||
|
||||
fn bench_list_length(c: &mut Criterion) {
|
||||
let list = create_random_list(100);
|
||||
c.bench_function("Short list length", |b| {
|
||||
b.iter(|| list_length(black_box(&list)))
|
||||
});
|
||||
let list = create_random_list(10_000_000);
|
||||
c.bench_function("Long list length", |b| {
|
||||
b.iter(|| list_length(black_box(&list)))
|
||||
});
|
||||
}
|
||||
|
||||
fn push_back(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("push_back");
|
||||
for i in [100, 10_000_000].iter() {
|
||||
group.bench_with_input(BenchmarkId::new("create_random_std_list", i), i, |b, i| {
|
||||
b.iter(|| create_random_std_list(*i))
|
||||
});
|
||||
group.bench_with_input(BenchmarkId::new("create_random_list", i), i, |b, i| {
|
||||
b.iter(|| create_random_list(*i))
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
name = benches;
|
||||
config = Criterion::default();
|
||||
targets = bench_list_length, push_back
|
||||
);
|
||||
criterion_main!(benches);
|
||||
|
|
@ -11,27 +11,28 @@ use std::ptr::NonNull;
|
|||
///
|
||||
/// # How to use
|
||||
/// ```
|
||||
/// use datastructures::linked_list::LinkedList;
|
||||
///
|
||||
/// # use datastructures::linked_list::LinkedList;
|
||||
/// #
|
||||
/// let mut list = LinkedList::new();
|
||||
/// list.push_front("hello");
|
||||
/// assert_eq!(list.get(0), Some(&"hello"));
|
||||
/// list.push_end("bye");
|
||||
/// list.push_back("bye");
|
||||
/// assert_eq!(list.get(1), Some(&"bye"));
|
||||
/// ```
|
||||
///
|
||||
/// The list can also be edited using the `Node` methods
|
||||
/// ```
|
||||
/// use datastructures::linked_list::LinkedList;
|
||||
///
|
||||
/// # use datastructures::linked_list::LinkedList;
|
||||
/// #
|
||||
/// let mut list = LinkedList::new();
|
||||
///
|
||||
/// list.push_front(1);
|
||||
/// let mut node = list.get_head_node_mut().unwrap();
|
||||
/// let mut node = list.get_mut_head_node().unwrap();
|
||||
/// node.push_after(3);
|
||||
/// node.push_after(2);
|
||||
/// let next = node.get_next().unwrap();
|
||||
/// let next = next.get_next().unwrap();
|
||||
/// assert_eq!(*next.get_value(), 3);
|
||||
/// let next = node.next().unwrap();
|
||||
/// let next = next.next().unwrap();
|
||||
/// assert_eq!(*next.get(), 3);
|
||||
/// ```
|
||||
///
|
||||
/// # Note
|
||||
|
|
@ -61,7 +62,6 @@ impl<T> LinkedList<T> {
|
|||
value: element,
|
||||
next: None,
|
||||
prev: None,
|
||||
_marker: PhantomData,
|
||||
});
|
||||
self.start = Some(new_node);
|
||||
self.end = Some(new_node);
|
||||
|
|
@ -72,7 +72,6 @@ impl<T> LinkedList<T> {
|
|||
value: element,
|
||||
next: Some(old_start),
|
||||
prev: None,
|
||||
_marker: PhantomData,
|
||||
});
|
||||
// SAFETY: All pointers should always be valid
|
||||
unsafe { old_start.as_mut() }.prev = Some(new_node);
|
||||
|
|
@ -82,14 +81,13 @@ impl<T> LinkedList<T> {
|
|||
}
|
||||
|
||||
/// Push an element to the end of the list (O(1))
|
||||
pub fn push_end(&mut self, element: T) {
|
||||
pub fn push_back(&mut self, element: T) {
|
||||
match self.end {
|
||||
None => {
|
||||
let new_node = allocate_nonnull(Node {
|
||||
value: element,
|
||||
next: None,
|
||||
prev: None,
|
||||
_marker: PhantomData,
|
||||
});
|
||||
self.start = Some(new_node);
|
||||
self.end = Some(new_node);
|
||||
|
|
@ -99,7 +97,6 @@ impl<T> LinkedList<T> {
|
|||
value: element,
|
||||
next: None,
|
||||
prev: Some(old_end),
|
||||
_marker: PhantomData,
|
||||
});
|
||||
// SAFETY: All pointers should always be valid
|
||||
unsafe { old_end.as_mut() }.next = Some(new_node);
|
||||
|
|
@ -162,17 +159,17 @@ impl<T> LinkedList<T> {
|
|||
self.end.as_ref().map(|nn| unsafe { nn.as_ref() })
|
||||
}
|
||||
/// Get the head node from the list that can be used the edit the list
|
||||
pub fn get_head_node_mut(&mut self) -> Option<&mut Node<T>> {
|
||||
pub fn get_mut_head_node(&mut self) -> Option<&mut Node<T>> {
|
||||
self.start.as_mut().map(|nn| unsafe { nn.as_mut() })
|
||||
}
|
||||
|
||||
/// Get the tail node from the list that can be used the edit the list
|
||||
pub fn get_tail_node_mut(&mut self) -> Option<&mut Node<T>> {
|
||||
pub fn get_mut_tail_node(&mut self) -> Option<&mut Node<T>> {
|
||||
self.end.as_mut().map(|nn| unsafe { nn.as_mut() })
|
||||
}
|
||||
|
||||
/// Get a node from the list that can be used the edit the list
|
||||
pub fn get_node_mut(&mut self, mut index: usize) -> Option<&mut Node<T>> {
|
||||
pub fn get_mut_node(&mut self, mut index: usize) -> Option<&mut Node<T>> {
|
||||
let mut node = &mut self.start;
|
||||
let mut result = None;
|
||||
while let Some(ref mut content) = node {
|
||||
|
|
@ -188,6 +185,15 @@ impl<T> LinkedList<T> {
|
|||
result
|
||||
}
|
||||
|
||||
/// Calculates the length of the list
|
||||
/// # Important
|
||||
/// This implementation is O(n), since unlike in `std::collections::LinkedList`, the length of the list is not stored
|
||||
/// (and can't be because the list can be modified through nodes - a node could theoretically have a reference to the list,
|
||||
/// but that would make node extraction slower because you'd always have to construct a new struct.
|
||||
pub fn len(&self) -> usize {
|
||||
self.iter().count()
|
||||
}
|
||||
|
||||
/// Returns an iterator over the items
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
Iter::new(self)
|
||||
|
|
@ -225,11 +231,11 @@ impl<T> Drop for LinkedList<T> {
|
|||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use datastructures::linked_list::*;
|
||||
///
|
||||
/// # use datastructures::linked_list::*;
|
||||
/// #
|
||||
/// let mut list = LinkedList::new();
|
||||
/// list.push_front(1);
|
||||
/// let mut node = list.get_node_mut(0);
|
||||
/// let mut node = list.get_mut_node(0);
|
||||
/// ```
|
||||
///
|
||||
#[derive(Debug)]
|
||||
|
|
@ -237,7 +243,6 @@ pub struct Node<T> {
|
|||
value: T,
|
||||
next: Option<NonNull<Node<T>>>,
|
||||
prev: Option<NonNull<Node<T>>>,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Node<T> {
|
||||
|
|
@ -247,7 +252,6 @@ impl<T> Node<T> {
|
|||
value: element,
|
||||
next: self.next,
|
||||
prev: NonNull::new(self as _),
|
||||
_marker: PhantomData,
|
||||
}));
|
||||
self.next.map(|mut next| {
|
||||
// SAFETY: All pointers should always be valid and created from a box
|
||||
|
|
@ -262,7 +266,6 @@ impl<T> Node<T> {
|
|||
value: element,
|
||||
next: NonNull::new(self as _),
|
||||
prev: self.prev,
|
||||
_marker: PhantomData,
|
||||
}));
|
||||
self.prev.map(|mut next| {
|
||||
// SAFETY: All pointers should always be valid and created from a box
|
||||
|
|
@ -272,43 +275,32 @@ impl<T> Node<T> {
|
|||
}
|
||||
|
||||
/// Get the next node
|
||||
pub fn get_next(&self) -> Option<&Node<T>> {
|
||||
match &self.next {
|
||||
None => None,
|
||||
Some(nn) => unsafe { Some(nn.as_ref()) },
|
||||
}
|
||||
pub fn next(&self) -> Option<&Node<T>> {
|
||||
self.next.as_ref().map(|nn| unsafe { nn.as_ref() })
|
||||
}
|
||||
|
||||
/// Get the next node mutably
|
||||
pub fn get_next_mut(&mut self) -> Option<&mut Node<T>> {
|
||||
match &mut self.next {
|
||||
None => None,
|
||||
Some(nn) => unsafe { Some(nn.as_mut()) },
|
||||
}
|
||||
pub fn next_mut(&mut self) -> Option<&mut Node<T>> {
|
||||
self.next.as_mut().map(|nn| unsafe { nn.as_mut() })
|
||||
}
|
||||
|
||||
/// Get the previous node
|
||||
pub fn get_previous(&self) -> Option<&Node<T>> {
|
||||
match &self.prev {
|
||||
None => None,
|
||||
Some(nn) => unsafe { Some(nn.as_ref()) },
|
||||
}
|
||||
pub fn previous(&self) -> Option<&Node<T>> {
|
||||
self.prev.as_ref().map(|nn| unsafe { nn.as_ref() })
|
||||
}
|
||||
|
||||
/// Get the previous node mutably
|
||||
pub fn get_previous_mut(&mut self) -> Option<&mut Node<T>> {
|
||||
match &mut self.prev {
|
||||
None => None,
|
||||
Some(nn) => unsafe { Some(nn.as_mut()) },
|
||||
}
|
||||
pub fn previous_mut(&mut self) -> Option<&mut Node<T>> {
|
||||
self.prev.as_mut().map(|nn| unsafe { nn.as_mut() })
|
||||
}
|
||||
|
||||
/// Gets the value from the node
|
||||
pub fn get_value(&self) -> &T {
|
||||
pub fn get(&self) -> &T {
|
||||
&self.value
|
||||
}
|
||||
|
||||
/// Gets the value from the node
|
||||
pub fn set_value(&mut self, value: T) {
|
||||
pub fn set(&mut self, value: T) {
|
||||
self.value = value;
|
||||
}
|
||||
|
||||
|
|
@ -316,6 +308,19 @@ impl<T> Node<T> {
|
|||
pub fn replace_value(&mut self, value: T) -> T {
|
||||
std::mem::replace(&mut self.value, value)
|
||||
}
|
||||
|
||||
/// Removes a value from the List and returns it
|
||||
pub fn remove(&mut self) -> T {
|
||||
// SAFETY: All pointers should always be valid
|
||||
unsafe {
|
||||
self.next.map(|mut next| next.as_mut().prev = self.prev);
|
||||
self.prev.map(|mut prev| prev.as_mut().next = self.next);
|
||||
}
|
||||
|
||||
// SAFETY: A reference is always valid and we have the only one now
|
||||
let node = unsafe { Box::from_raw(self) };
|
||||
node.value
|
||||
}
|
||||
}
|
||||
|
||||
fn allocate_nonnull<T>(element: T) -> NonNull<T> {
|
||||
|
|
@ -377,11 +382,11 @@ mod test {
|
|||
#[test]
|
||||
fn push_start_end() {
|
||||
let mut list = LinkedList::new();
|
||||
list.push_end(3);
|
||||
list.push_back(3);
|
||||
list.push_front(2);
|
||||
list.push_front(1);
|
||||
list.push_end(4);
|
||||
list.push_end(5);
|
||||
list.push_back(4);
|
||||
list.push_back(5);
|
||||
let vec = list.iter().cloned().collect::<Vec<_>>();
|
||||
assert_eq!(&vec[..], &[1, 2, 3, 4, 5]);
|
||||
}
|
||||
|
|
@ -426,13 +431,13 @@ mod test {
|
|||
fn node_operations() {
|
||||
let mut list = LinkedList::new();
|
||||
list.push_front(1);
|
||||
list.push_end(2);
|
||||
list.push_back(2);
|
||||
{
|
||||
let node = list.get_node_mut(1).unwrap();
|
||||
assert_eq!(*node.get_value(), 2);
|
||||
let node = list.get_mut_node(1).unwrap();
|
||||
assert_eq!(*node.get(), 2);
|
||||
node.push_after(4);
|
||||
let next = node.get_next_mut().unwrap();
|
||||
assert!(matches!(next.get_next(), None));
|
||||
let next = node.next_mut().unwrap();
|
||||
assert!(matches!(next.next(), None));
|
||||
next.push_before(3)
|
||||
}
|
||||
let vec = list.iter().cloned().collect::<Vec<_>>();
|
||||
|
|
@ -443,13 +448,28 @@ mod test {
|
|||
fn node_values() {
|
||||
let mut list = LinkedList::new();
|
||||
list.push_front(1);
|
||||
let node = list.get_node_mut(0).unwrap();
|
||||
assert_eq!(*node.get_value(), 1);
|
||||
let node = list.get_mut_node(0).unwrap();
|
||||
assert_eq!(*node.get(), 1);
|
||||
assert_eq!(node.replace_value(2), 1);
|
||||
assert_eq!(*node.get_value(), 2);
|
||||
assert_eq!(*node.get(), 2);
|
||||
node.push_after(3);
|
||||
let node = node.get_next_mut().unwrap();
|
||||
node.set_value(4);
|
||||
assert_eq!(*node.get_value(), 4);
|
||||
let node = node.next_mut().unwrap();
|
||||
node.set(4);
|
||||
assert_eq!(*node.get(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn node_removal() {
|
||||
let mut list = LinkedList::new();
|
||||
list.push_back(1);
|
||||
list.push_back(2);
|
||||
list.push_back(4);
|
||||
let node_two = list.get_mut_head_node().unwrap().next_mut().unwrap();
|
||||
node_two.replace_value(3);
|
||||
let three = node_two.remove();
|
||||
assert_eq!(three, 3);
|
||||
assert_eq!(list.get_head(), Some(&1));
|
||||
assert_eq!(list.get_tail(), Some(&4));
|
||||
assert_eq!(*list.get_head_node().unwrap().next().unwrap().get(), 4);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue