GenericList

Struct GenericList 

Source
pub struct GenericList<T: Clone + 'static, P: PointerFamily = RcPointer, const N: usize = 256, const G: usize = 1, D: DropHandler<Self> = DefaultDropHandler>(/* private fields */);
Expand description

A persistent list.

This list is suitable for either a single threaded or multi threaded environment. The list accepts the smart pointer that you would like to use as a type parameter. There are sensible type aliases for implementations that you can use:

SharedList is simply a type alias for GenericList<T, ArcPointer, 256, 1>, which is both Send + Sync Similarly, List is just a type alias for GenericList<T, RcPointer, 256, 1>. SharedVList and VList are type aliases, as well, using the same backing of GenericList, however they have a growth factor of 2 - meaning bucket sizes will grow exponentially.

It’s implemented as an unrolled linked list, which is a single linked list which stores a variable amount of elements in each node. The capacity of any individual node for now is set to to be N elements, which means that until more than N elements are cons’d onto a list, it will remain a vector under the hood. By default, N is sset to 256. There is also a growth rate, G, which describes how each successive node will grow in size. With N = 2, and G = 2, the list will look something like this:

[0, 1, 2, 3, 4, 5, 6, 7] -> [8, 9, 10, 11] -> [12, 13]

The list is also designed to leverage in place mutations whenever possible - if the number of references pointing to either a cell containing a vector or the shared vector is one, then that mutation is done in place. Otherwise, it is copy-on-write, maintaining our persistent invariant.

§Performance Notes

The algorithmic complexity of an unrolled linked list matches that of a normal linked list - however in practice we have a decrease by the factor of the capacity of a node that gives us practical performance wins. For a list that is fully filled, iteration over nodes becomes O(n / N), rather than the typical O(n). If the growth rate is set to 2 (or more), over individual nodes becomes O(log(n)) - which means indexing or finding the last element is O(log(n)) as well. In addition, the unrolled linked list is able to avoid the costly cache misses that a typical linked list suffers from, seeing very realistic performance gains.

Let n be the number of elements in the list, and m is the capacity of a node. In the worst case, a node will be on average half filled. In the best case, all nodes are completely full. This means for operations that for a normal linked list may take linear time Θ(n), we get a constant factor decrease of either a factor of m or m / 2. Similarly, we will see O(log(n)) performance characteristics if the growth rate is set to be larger than 1.

Implementations§

Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> GenericList<T, P, N, G, D>

Source

pub fn new() -> Self

Construct an empty list.

Source

pub fn new_with_capacity() -> Self

Constructs an empty list with capacity N

Source

pub fn strong_count(&self) -> usize

Get the number of strong references pointing to this list

Time: O(1)

Source

pub fn ptr_eq(&self, other: &Self) -> bool

Compare this list to another for pointer equality

Source

pub fn len(&self) -> usize

Get the length of the list

§Examples
let list = list![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(list.len(), 10);
Source

pub fn reverse(self) -> Self

Reverses the input list and returns a new list

§Examples
let list = list![1, 2, 3, 4, 5].reverse();
assert_eq!(list, list![5, 4, 3, 2, 1])
Source

pub fn last(&self) -> Option<&T>

Get the last element of the list. Returns None if the list is empty.

§Examples
let list = list![1, 2, 3, 4, 5];
assert_eq!(list.last().cloned(), Some(5));
Source

pub fn car(&self) -> Option<T>

Get the first element of the list. Returns None if the list is empty.

§Examples
let list = list![1, 2, 3, 4, 5];
let car = list.car();
assert_eq!(car, Some(1));

let list: List<usize> = list![];
let car = list.car();
assert!(car.is_none());
Source

pub fn first(&self) -> Option<&T>

Returns a reference to the first element of the list. Returns None if the list is empty.

§Examples
let list = list![1, 2, 3, 4, 5];
let first = list.first().cloned();
assert_eq!(first, Some(1));

let list: List<usize> = list![];
let first = list.first();
assert!(first.is_none());
Source

pub fn cdr(&self) -> Option<GenericList<T, P, N, G, D>>

Get the “rest” of the elements as a list, excluding the first element

§Examples
let list = list![1, 2, 3, 4, 5];
let cdr = list.cdr().unwrap();
assert_eq!(cdr, list![2, 3, 4, 5]);

let list = list![5];
let cdr = list.cdr();
assert!(cdr.is_none());
Source

pub fn rest(&self) -> Option<GenericList<T, P, N, G, D>>

Get the “rest” of the elements as a list. Alias for cdr

Source

pub fn cdr_mut(&mut self) -> Option<&mut Self>

Gets the cdr of the list, mutably. Returns None if the next is empty - otherwise updates self to be the rest

§Examples
let mut list = list![1, 2, 3, 4, 5];
list.cdr_mut().expect("This list has a tail");
assert_eq!(list, list![2, 3, 4, 5]);


let mut list = list![1, 2, 3];
assert!(list.cdr_mut().is_some());
assert_eq!(list, list![2, 3]);
assert!(list.cdr_mut().is_some());
assert_eq!(list, list![3]);
assert!(list.cdr_mut().is_none());
assert_eq!(list, list![]);
Source

pub fn rest_mut(&mut self) -> Option<&mut Self>

Gets the rest of the list, mutably. Alias for cdr_mut

Source

pub fn cons( value: T, other: GenericList<T, P, N, G, D>, ) -> GenericList<T, P, N, G, D>

Pushes an element onto the front of the list, returning a new list

§Examples
let list = List::cons(1, List::cons(2, List::cons(3, List::cons(4, List::new()))));
assert_eq!(list, list![1, 2, 3, 4]);
Source

pub fn cons_mut(&mut self, value: T)

Mutably pushes an element onto the front of the list, in place

§Examples
let mut list = list![];
list.cons_mut(3);
list.cons_mut(2);
list.cons_mut(1);
list.cons_mut(0);
assert_eq!(list, list![0, 1, 2, 3])
Source

pub fn push_front(&mut self, value: T)

Alias for cons_mut

§Examples
let mut list = list![];
list.push_front(3);
list.push_front(2);
list.push_front(1);
list.push_front(0);
assert_eq!(list, list![0, 1, 2, 3])
Source

pub fn pop_front(&mut self) -> Option<T>

Mutably pop the first value off of the list

§Examples
let mut list = list![1, 2, 3];
assert_eq!(list.pop_front().unwrap(), 1);
assert_eq!(list.pop_front().unwrap(), 2);
assert_eq!(list.pop_front().unwrap(), 3);
assert!(list.pop_front().is_none())
Source

pub fn push_back(&mut self, value: T)

Push one value to the back of the list

Time: O(n)

§Examples
let mut list = list![];
list.push_back(0);
list.push_back(1);
list.push_back(2);
list.push_back(3);
assert_eq!(list, list![0, 1, 2, 3])
Source

pub fn take(&self, count: usize) -> Self

Construct a new list from the first count elements from the current list

§Examples
let list = list![0, 1, 2, 3, 4, 5];
let new_list = list.take(3);
assert_eq!(new_list, list![0, 1, 2]);
Source

pub fn tail(&self, len: usize) -> Option<Self>

Returns the list after the first len elements of lst. If the list has fewer then len elements, then this returns None.

§Examples
let list = list![0, 1, 2, 3, 4, 5];
let new_list = list.tail(2);
assert_eq!(new_list.unwrap(), list![2, 3, 4, 5]);

let no_list = list.tail(100);
assert!(no_list.is_none())
Source

pub fn iter(&self) -> impl Iterator<Item = &T>

Constructs an iterator over the list

Source

pub fn get(&self, index: usize) -> Option<&T>

Get a reference to the value at index index in a list. Returns None if the index is out of bounds.

Source

pub fn append(self, other: Self) -> Self

Append the list other to the end of the current list. Returns a new list.

§Examples
let left = list![1usize, 2, 3];
let right = list![4usize, 5, 6];
assert_eq!(left.append(right), list![1, 2, 3, 4, 5, 6])
Source

pub fn append_mut(&mut self, other: Self)

Append the list ‘other’ to the end of the current list in place.

§Examples
let mut left = list![1usize, 2, 3];
let right = list![4usize, 5, 6];
left.append_mut(right);
assert_eq!(left, list![1, 2, 3, 4, 5, 6])
Source

pub fn is_empty(&self) -> bool

Checks whether a list is empty

§Examples
let mut list = List::new();
assert!(list.is_empty());
list.cons_mut("applesauce");
assert!(!list.is_empty());
Source

pub fn sort(&mut self)
where T: Ord,

Sorts the list

§Examples
let mut list = list![4, 2, 6, 3, 1, 5];
list.sort();
assert_eq!(list, list![1, 2, 3, 4, 5, 6]);
Source

pub fn sort_by<F>(&mut self, cmp: F)
where F: Fn(&T, &T) -> Ordering,

Sorts the list according to the ordering

§Examples
let mut list = list![4, 2, 6, 3, 1, 5];
list.sort_by(Ord::cmp);
assert_eq!(list, list![1, 2, 3, 4, 5, 6]);

Trait Implementations§

Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<GenericList<T, P, N, G, D>>> Add for &GenericList<T, P, N, G, D>

Source§

fn add(self, other: Self) -> Self::Output

Concatenate two lists

Source§

type Output = GenericList<T, P, N, G, D>

The resulting type after applying the + operator.
Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> Add for GenericList<T, P, N, G, D>

Source§

fn add(self, other: Self) -> Self::Output

Concatenate two lists

Source§

type Output = GenericList<T, P, N, G, D>

The resulting type after applying the + operator.
Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> Clone for GenericList<T, P, N, G, D>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Clone + Debug, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> Debug for GenericList<T, P, N, G, D>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> Default for GenericList<T, P, N, G, D>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> Drop for GenericList<T, P, N, G, D>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> Extend<T> for GenericList<T, P, N, G, D>

Source§

fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I)

Extends a collection with the contents of an iterator. Read more
Source§

fn extend_one(&mut self, item: A)

🔬This is a nightly-only experimental API. (extend_one)
Extends a collection with exactly one element.
Source§

fn extend_reserve(&mut self, additional: usize)

🔬This is a nightly-only experimental API. (extend_one)
Reserves capacity in a collection for the given number of additional elements. Read more
Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> From<&[T]> for GenericList<T, P, N, G, D>

Source§

fn from(vec: &[T]) -> Self

Converts to this type from the input type.
Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> From<Vec<T>> for GenericList<T, P, N, G, D>

Source§

fn from(vec: Vec<T>) -> Self

Converts to this type from the input type.
Source§

impl<'a, T: 'a + Clone, P: 'a + PointerFamily, const N: usize, const G: usize, D: 'a + DropHandler<Self>> FromIterator<&'a GenericList<T, P, N, G, D>> for GenericList<T, P, N, G, D>

Source§

fn from_iter<I: IntoIterator<Item = &'a GenericList<T, P, N, G, D>>>( iter: I, ) -> Self

Creates a value from an iterator. Read more
Source§

impl<'a, T: 'a + Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> FromIterator<&'a T> for GenericList<T, P, N, G, D>

Source§

fn from_iter<I: IntoIterator<Item = &'a T>>(iter: I) -> Self

Creates a value from an iterator. Read more
Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> FromIterator<GenericList<T, P, N, G, D>> for GenericList<T, P, N, G, D>

Source§

fn from_iter<I: IntoIterator<Item = GenericList<T, P, N, G, D>>>( iter: I, ) -> Self

Creates a value from an iterator. Read more
Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> FromIterator<T> for GenericList<T, P, N, G, D>

Source§

fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self

Creates a value from an iterator. Read more
Source§

impl<T: Clone + Hash, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> Hash for GenericList<T, P, N, G, D>

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> Index<usize> for GenericList<T, P, N, G, D>

Source§

fn index(&self, index: usize) -> &Self::Output

Get a reference to the value at index index in the vector.

Time: O(log n)

Source§

type Output = T

The returned type after indexing.
Source§

impl<'a, T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<GenericList<T, P, N, G, D>>> IntoIterator for &'a GenericList<T, P, N, G, D>

Source§

type Item = &'a T

The type of the elements being iterated over.
Source§

type IntoIter = Iter<'a, T, P, N, G, D>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> IntoIterator for GenericList<T, P, N, G, D>

Source§

type Item = T

The type of the elements being iterated over.
Source§

type IntoIter = ConsumingIter<T, P, N, G, D>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<T: Clone + Ord, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> Ord for GenericList<T, P, N, G, D>

Source§

fn cmp(&self, other: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl<T: Clone + PartialEq, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> PartialEq for GenericList<T, P, N, G, D>

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T: Clone + PartialOrd, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> PartialOrd for GenericList<T, P, N, G, D>

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl<T: Clone, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> Sum for GenericList<T, P, N, G, D>

Source§

fn sum<I>(it: I) -> Self
where I: Iterator<Item = Self>,

Takes an iterator and generates Self from the elements by “summing up” the items.
Source§

impl<T: Clone + Eq, P: PointerFamily, const N: usize, const G: usize, D: DropHandler<Self>> Eq for GenericList<T, P, N, G, D>

Auto Trait Implementations§

§

impl<T, P, const N: usize, const G: usize, D> Freeze for GenericList<T, P, N, G, D>
where <P as PointerFamily>::Pointer<UnrolledCell<T, P, N, G>>: Freeze,

§

impl<T, P, const N: usize, const G: usize, D> RefUnwindSafe for GenericList<T, P, N, G, D>
where <P as PointerFamily>::Pointer<UnrolledCell<T, P, N, G>>: RefUnwindSafe, D: RefUnwindSafe,

§

impl<T, P, const N: usize, const G: usize, D> Send for GenericList<T, P, N, G, D>
where <P as PointerFamily>::Pointer<UnrolledCell<T, P, N, G>>: Send, D: Send,

§

impl<T, P, const N: usize, const G: usize, D> Sync for GenericList<T, P, N, G, D>
where <P as PointerFamily>::Pointer<UnrolledCell<T, P, N, G>>: Sync, D: Sync,

§

impl<T, P, const N: usize, const G: usize, D> Unpin for GenericList<T, P, N, G, D>
where <P as PointerFamily>::Pointer<UnrolledCell<T, P, N, G>>: Unpin, D: Unpin,

§

impl<T, P, const N: usize, const G: usize, D> UnwindSafe for GenericList<T, P, N, G, D>
where <P as PointerFamily>::Pointer<UnrolledCell<T, P, N, G>>: UnwindSafe, D: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> CloneAny for T
where T: Any + Clone,