Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "orx-linked-list"
version = "4.0.0"
version = "4.1.0"
edition = "2024"
authors = ["orxfun <[email protected]>"]
description = "A linked list implementation with unique features and an extended list of constant time methods providing high performance traversals and mutations."
Expand All @@ -16,7 +16,7 @@ orx-pinned-vec = { version = "3.21.0", default-features = false }
orx-fixed-vec = { version = "3.22.0", default-features = false }
orx-split-vec = { version = "3.22.0", default-features = false }
orx-concurrent-iter = { version = "3.3.0", default-features = false }
orx-selfref-col = { version = "3.0.0", default-features = false }
orx-selfref-col = { version = "3.1.0", default-features = false }
orx-parallel = { version = "3.4.0", default-features = false, optional = true }

[dev-dependencies]
Expand Down
20 changes: 12 additions & 8 deletions examples/bench_parallelization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,46 +33,50 @@ fn main() {
let args = Args::parse();

let expected_output = {
let list: DoublyList<_> = (0..args.len as usize).collect();
let list: DoublyList<_> = (0..args.len).collect();

list.iter()
.filter(|x| *x % 3 != 0)
.map(|x| x + fibonacci(x % 1000))
.filter_map(|x| (x % 2 == 0).then(|| x.to_string()))
.filter(|&x| x % 2 == 0)
.map(|x| x.to_string())
.collect::<Vec<_>>()
};

let computations: Vec<(&str, Box<dyn Fn() -> Vec<String>>)> = vec![
type Compute = dyn Fn() -> Vec<String>;
let computations: Vec<(&str, Box<Compute>)> = vec![
(
"Sequential computation over std::collections::LinkedList",
Box::new(move || {
let list: std::collections::LinkedList<_> = (0..args.len as usize).collect();
let list: std::collections::LinkedList<_> = (0..args.len).collect();

list.iter()
.filter(|x| *x % 3 != 0)
.map(|x| x + fibonacci(x % 1000))
.filter_map(|x| (x % 2 == 0).then(|| x.to_string()))
.filter(|&x| x % 2 == 0)
.map(|x| x.to_string())
.collect::<Vec<_>>()
}),
),
#[cfg(feature = "orx-parallel")]
(
"Sequential computation over DoublyList",
Box::new(move || {
let list: DoublyList<_> = (0..args.len as usize).collect();
let list: DoublyList<_> = (0..args.len).collect();

list.iter_x()
.filter(|x| *x % 3 != 0)
.map(|x| x + fibonacci(x % 1000))
.filter_map(|x| (x % 2 == 0).then(|| x.to_string()))
.filter(|&x| x % 2 == 0)
.map(|x| x.to_string())
.collect::<Vec<_>>()
}),
),
#[cfg(feature = "orx-parallel")]
(
"Parallelized over DoublyList using orx_parallel",
Box::new(move || {
let list: DoublyList<_> = (0..args.len as usize).collect();
let list: DoublyList<_> = (0..args.len).collect();

list.par_x() // replace iter_x (into_iter_x) with par_x (into_par_x) to parallelize !
.filter(|x| *x % 3 != 0)
Expand Down
2 changes: 1 addition & 1 deletion examples/tour_mutations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use clap::Parser;
use orx_linked_list::*;
use rand::prelude::*;
use rand_chacha::ChaCha8Rng;
use std::{fmt::Debug, time::Instant, usize};
use std::{fmt::Debug, time::Instant};

fn get_cities(num_cities: usize) -> impl Iterator<Item = City> {
(0..num_cities).map(|id| City {
Expand Down
6 changes: 4 additions & 2 deletions examples/utils/benchmark_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ where
now.elapsed().unwrap()
}

type Compute<O> = dyn Fn() -> O;

pub fn timed_reduce_all<O>(
benchmark_name: &str,
num_repetitions: usize,
expected_output: Option<O>,
computations: &[(&str, Box<dyn Fn() -> O>)],
computations: &[(&str, Box<Compute<O>>)],
) where
O: PartialEq + Debug + Clone,
{
Expand Down Expand Up @@ -80,7 +82,7 @@ pub fn timed_collect_all<Out, O>(
benchmark_name: &str,
num_repetitions: usize,
expected_output: &[O],
computations: &[(&str, Box<dyn Fn() -> Out>)],
computations: &[(&str, Box<Compute<Out>>)],
) where
Out: IntoIterator<Item = O>,
O: PartialEq + Debug,
Expand Down
40 changes: 18 additions & 22 deletions src/tests/doubly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,22 @@ where
assert_ne!(self.0.ends().get(BACK_IDX), self.0.ends().get(FRONT_IDX));

let mut fwd_pointers = alloc::vec![];
let mut ptr = self.0.ends().get(FRONT_IDX).cloned().unwrap();
fwd_pointers.push(ptr.clone());
while let Some((next_ptr, next)) = self.next(&ptr) {
assert_eq!(next.prev().get(), Some(&ptr));
let mut ptr = self.0.ends().get(FRONT_IDX).unwrap();
fwd_pointers.push(ptr);
while let Some((next_ptr, next)) = self.next(ptr) {
assert_eq!(next.prev().get(), Some(ptr));
ptr = next_ptr;
fwd_pointers.push(ptr.clone());
fwd_pointers.push(ptr);
}
assert_eq!(fwd_pointers.len(), num_active_nodes);

let mut bwd_pointers = alloc::vec![];
let mut ptr = self.0.ends().get(BACK_IDX).cloned().unwrap();
bwd_pointers.push(ptr.clone());
while let Some((prev_ptr, prev)) = self.prev(&ptr) {
assert_eq!(prev.next().get(), Some(&ptr));
let mut ptr = self.0.ends().get(BACK_IDX).unwrap();
bwd_pointers.push(ptr);
while let Some((prev_ptr, prev)) = self.prev(ptr) {
assert_eq!(prev.next().get(), Some(ptr));
ptr = prev_ptr;
bwd_pointers.push(ptr.clone());
bwd_pointers.push(ptr);
}

bwd_pointers.reverse();
Expand All @@ -79,14 +79,12 @@ where

assert_eq!(iter.next(), self.front());

let mut maybe_ptr = self.0.ends().get(FRONT_IDX).cloned();
let mut maybe_ptr = self.0.ends().get(FRONT_IDX);
for _ in 1..num_active_nodes {
let ptr = maybe_ptr.clone().unwrap();
maybe_ptr = self.next(&ptr).map(|x| x.0);
let ptr = maybe_ptr.unwrap();
maybe_ptr = self.next(ptr).map(|x| x.0);

let data = maybe_ptr
.clone()
.map(|p| unsafe { self.0.data_unchecked(&p) });
let data = maybe_ptr.map(|p| unsafe { self.0.data_unchecked(p) });
assert_eq!(iter.next(), data);
}
assert!(iter.next().is_none());
Expand All @@ -96,14 +94,12 @@ where

assert_eq!(iter.next(), self.back());

let mut maybe_ptr = self.0.ends().get(BACK_IDX).cloned();
let mut maybe_ptr = self.0.ends().get(BACK_IDX);
for _ in 1..num_active_nodes {
let ptr = maybe_ptr.clone().unwrap();
maybe_ptr = self.prev(&ptr).map(|x| x.0);
let ptr = maybe_ptr.unwrap();
maybe_ptr = self.prev(ptr).map(|x| x.0);

let data = maybe_ptr
.clone()
.map(|p| unsafe { self.0.data_unchecked(&p) });
let data = maybe_ptr.map(|p| unsafe { self.0.data_unchecked(p) });
assert_eq!(iter.next(), data);
}
assert!(iter.next().is_none());
Expand Down
18 changes: 8 additions & 10 deletions src/tests/singly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ where
assert!(self.front().is_some());

let mut fwd_pointers = alloc::vec![];
let mut ptr = self.0.ends().get().cloned().unwrap();
fwd_pointers.push(ptr.clone());
while let Some((next_ptr, _)) = self.next(&ptr) {
let mut ptr = self.0.ends().get().unwrap();
fwd_pointers.push(ptr);
while let Some((next_ptr, _)) = self.next(ptr) {
ptr = next_ptr;
fwd_pointers.push(ptr.clone());
fwd_pointers.push(ptr);
}
assert_eq!(fwd_pointers.len(), num_active_nodes);
}
Expand All @@ -54,14 +54,12 @@ where

assert_eq!(iter.next(), self.front());

let mut maybe_ptr = self.0.ends().get().cloned();
let mut maybe_ptr = self.0.ends().get();
for _ in 1..num_active_nodes {
let ptr = maybe_ptr.clone().unwrap();
maybe_ptr = self.next(&ptr).map(|x| x.0);
let ptr = maybe_ptr.unwrap();
maybe_ptr = self.next(ptr).map(|x| x.0);

let data = maybe_ptr
.clone()
.map(|p| unsafe { self.0.data_unchecked(&p) });
let data = maybe_ptr.map(|p| unsafe { self.0.data_unchecked(p) });
assert_eq!(iter.next(), data);
}
assert!(iter.next().is_none());
Expand Down
10 changes: 10 additions & 0 deletions src/variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ pub struct Singly<T> {
p: PhantomData<T>,
}

/// # SAFETY
///
/// List variants do not hold any data, safe to send or sync.
unsafe impl<T> Sync for Singly<T> {}

impl<T> Variant for Singly<T> {
type Item = T;

Expand All @@ -32,6 +37,11 @@ pub struct Doubly<T> {
p: PhantomData<T>,
}

/// # SAFETY
///
/// List variants do not hold any data, safe to send or sync.
unsafe impl<T> Sync for Doubly<T> {}

impl<T> Variant for Doubly<T> {
type Item = T;

Expand Down
4 changes: 2 additions & 2 deletions tests/list_move_next_to.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn list_move_next_to_front() {
let (mut list, idx) = list_and_indices(n);
list.move_next_to(idx[i], idx[0]);

let mut vec: Vec<_> = (0..n).into_iter().filter(|x| x != &i).collect();
let mut vec: Vec<_> = (0..n).filter(|x| x != &i).collect();
vec.insert(1, i);

#[cfg(feature = "validation")]
Expand All @@ -29,7 +29,7 @@ fn list_move_next_to_back() {
let (mut list, idx) = list_and_indices(n);
list.move_next_to(idx[i], idx[n - 1]);

let mut vec: Vec<_> = (0..n).into_iter().filter(|x| x != &i).collect();
let mut vec: Vec<_> = (0..n).filter(|x| x != &i).collect();
vec.insert(n - 1, i);

#[cfg(feature = "validation")]
Expand Down
4 changes: 2 additions & 2 deletions tests/list_move_prev_to.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn list_move_prev_to_front() {
let (mut list, idx) = list_and_indices(n);
list.move_prev_to(idx[i], idx[0]);

let mut vec: Vec<_> = (0..n).into_iter().filter(|x| x != &i).collect();
let mut vec: Vec<_> = (0..n).filter(|x| x != &i).collect();
vec.insert(0, i);

#[cfg(feature = "validation")]
Expand All @@ -29,7 +29,7 @@ fn list_move_prev_to_back() {
let (mut list, idx) = list_and_indices(n);
list.move_prev_to(idx[i], idx[n - 1]);

let mut vec: Vec<_> = (0..n).into_iter().filter(|x| x != &i).collect();
let mut vec: Vec<_> = (0..n).filter(|x| x != &i).collect();
match i != n - 1 {
true => vec.insert(n - 2, i),
false => vec.push(i),
Expand Down
10 changes: 5 additions & 5 deletions tests/reverse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn list_reverse() {
#[test]
fn slice_reverse_empty() {
for i in 0..20 {
let mut list = doubly::new_doubly(&mut &mut doubly::rng_with_seed(100 * i as u64), 20, 50);
let mut list = doubly::new_doubly(&mut doubly::rng_with_seed(100 * i as u64), 20, 50);
let expected: Vec<_> = list.iter().cloned().collect();
let idx: Vec<_> = list.indices().collect();

Expand All @@ -30,7 +30,7 @@ fn slice_reverse_empty() {
#[test]
fn slice_reverse_single() {
for i in 0..20 {
let mut list = doubly::new_doubly(&mut &mut doubly::rng_with_seed(100 * i as u64), 20, 50);
let mut list = doubly::new_doubly(&mut doubly::rng_with_seed(100 * i as u64), 20, 50);
let expected: Vec<_> = list.iter().cloned().collect();
let idx: Vec<_> = list.indices().collect();

Expand All @@ -46,7 +46,7 @@ fn slice_reverse_single() {
#[test]
fn slice_reverse_from_front() {
for i in 0..20 {
let mut list = doubly::new_doubly(&mut &mut doubly::rng_with_seed(100 * i as u64), 20, 50);
let mut list = doubly::new_doubly(&mut doubly::rng_with_seed(100 * i as u64), 20, 50);
let mut expected: Vec<_> = list.iter().cloned().collect();
let idx: Vec<_> = list.indices().collect();

Expand All @@ -65,7 +65,7 @@ fn slice_reverse_from_front() {
#[test]
fn slice_reverse_until_back() {
for i in 0..20 {
let mut list = doubly::new_doubly(&mut &mut doubly::rng_with_seed(100 * i as u64), 20, 50);
let mut list = doubly::new_doubly(&mut doubly::rng_with_seed(100 * i as u64), 20, 50);
let mut expected: Vec<_> = list.iter().cloned().collect();
let idx: Vec<_> = list.indices().collect();

Expand All @@ -84,7 +84,7 @@ fn slice_reverse_until_back() {
#[test]
fn slice_reverse_middle() {
for i in 0..20 {
let mut list = doubly::new_doubly(&mut &mut doubly::rng_with_seed(100 * i as u64), 20, 50);
let mut list = doubly::new_doubly(&mut doubly::rng_with_seed(100 * i as u64), 20, 50);
let mut expected: Vec<_> = list.iter().cloned().collect();
let idx: Vec<_> = list.indices().collect();

Expand Down
2 changes: 1 addition & 1 deletion tests/ring_iter_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ fn ring_iter_mut_demo() {
fn scan<'a, I: Iterator<Item = &'a mut i32>>(mut values: I) {
if let Some(first) = values.next() {
let mut acc = *first;
while let Some(x) = values.next() {
for x in values {
let new_acc = acc + *x;
*x += acc;
acc = new_acc;
Expand Down
8 changes: 4 additions & 4 deletions tests/slice_doubly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn empty_from_nonempty() {
let c = list.push_back('c');
assert!(list.eq_to_iter_vals(['a', 'b', 'c']));

let indices = [a, b, c.clone()];
let indices = [a, b, c];

for x in &indices {
assert_empty_slice(&list.slice(x..x));
Expand All @@ -40,7 +40,7 @@ fn singleton_slice() {
let expected = ['a', 'b', 'c'];
assert!(list.eq_to_iter_refs(expected.iter()));

let indices = [a, b, c.clone()];
let indices = [a, b, c];

for (i, x) in indices.iter().enumerate() {
let slice = list.slice(x..=x);
Expand Down Expand Up @@ -119,8 +119,8 @@ fn doubly_slice() {
let idx: Vec<_> = list.indices().collect();

// empty
for i in 0..n {
assert_empty_slice(&list.slice(idx[i]..idx[i]));
for id in idx.iter().take(n) {
assert_empty_slice(&list.slice(id..id));
}

// single
Expand Down
4 changes: 2 additions & 2 deletions tests/slice_move_next_to.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn slice_move_next_to_front() {
#[cfg(feature = "validation")]
list.validate();

let mut vec: Vec<_> = (0..n).into_iter().filter(|x| x != &i).collect();
let mut vec: Vec<_> = (0..n).filter(|x| x != &i).collect();
vec.insert(a + 1, i);

assert_eq!(slice, &vec[a..=b]);
Expand All @@ -48,7 +48,7 @@ fn slice_move_next_to_back() {
#[cfg(feature = "validation")]
list.validate();

let mut vec: Vec<_> = (0..n).into_iter().filter(|x| x != &i).collect();
let mut vec: Vec<_> = (0..n).filter(|x| x != &i).collect();
vec.insert(b, i);

assert_eq!(slice, &vec[a..=b]);
Expand Down
4 changes: 2 additions & 2 deletions tests/slice_move_prev_to.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn slice_move_prev_to_front() {
#[cfg(feature = "validation")]
list.validate();

let mut vec: Vec<_> = (0..n).into_iter().filter(|x| x != &i).collect();
let mut vec: Vec<_> = (0..n).filter(|x| x != &i).collect();
vec.insert(a, i);

assert_eq!(slice, &vec[a..=b]);
Expand All @@ -48,7 +48,7 @@ fn slice_move_prev_to_back() {
#[cfg(feature = "validation")]
list.validate();

let mut vec: Vec<_> = (0..n).into_iter().filter(|x| x != &i).collect();
let mut vec: Vec<_> = (0..n).filter(|x| x != &i).collect();
match i != b {
true => vec.insert(b - 1, i),
false => vec.insert(b, i),
Expand Down
Loading