orx-linked-list

Implements a doubly-linked list.

As opposed to the note of std::collections::LinkedList, orx_linked_list::LinkedList provides the main theoretical benefits of a linked list; i.e.,

while aiming to avoid the practical drawbacks related with allocations and CPU cache due to the following:

Usage

Basic usage of the linked list is demonstrated below.

```rust use orxlinkedlist::prelude::*;

let mut list = LinkedList::new();

list.pushback('y'); list.pushfront('x'); list.pushback('z'); asserteq!(vec!['x', 'y', 'z'], list.collect_vec());

asserteq!(list.popback(), Some('z')); asserteq!(list.popfront(), Some('x')); asserteq!(vec!['y'], list.collectvec());

list.pushfront('x'); list.pushback('z'); asserteq!(vec!['x', 'y', 'z'], list.collectvec());

list.insertat(1, '?'); asserteq!(vec!['x', '?', 'y', 'z'], list.collect_vec());

asserteq!(Some(&'?'), list.getat(1)); *list.getmutat(1).unwrap() = '!';

asserteq!('!', list.removeat(1)); asserteq!(vec!['x', 'y', 'z'], list.collectvec()); ```

Memory

LinkedList provides different levels of control on memory strategies; it can be used by the simplest type signature relying on the defaults or as detailed as possible by determining the tradeoff between time complexity and memory utilization, as well as, the growth stretegies of the backing storage.

Defaults

The list can be directly used by the default memory management settings by only specifying the element data type.

```rust use orxlinkedlist::prelude::*;

// char list let mut list = LinkedList::new(); list.push_back('x');

// i32 list with an initial capacity let mut list = LinkedList::withinitialcapacity(42); list.push_back(42); ```

Default values of the configurable settings defined in the following subsections are as follows:

Tradeoff between Memory Utilization & Time Complexity

LinkedList holds all elements close to each other in a PinnedVec aiming for better cache locality while using thin references rather than wide pointers and to reduce heap allocations. In order to achieve O(1) time complexity while avoiding smart pointers, remove and pop operations are designed to be semi-lazy.

In the lazy case; i.e., when the strategy is set to MemoryReclaimStrategy::Lazy, every pop_back, pop_front or remove_at operation leaves a gap in the underlying vector. Status of utilization of the underlying vector can be queried using the memory_status method and the gaps can completely be reclaimed by manually calling the memory_reclaim method which has a time complexity of O(n) where n is the length of the underlying vector.

Being able to be lazy and to reclaim the gaps, it is possible to define and use different automated strategies which would fit better in different situations:

Memory utilization stategy is defined by a field which can be modified any time.

```rust use orxlinkedlist::prelude::*;

let list = LinkedList::::new() .withmemoryutilization(MemoryUtilization::Eager) .withmemoryutilization(MemoryUtilization::Lazy) .withmemoryutilization(MemoryUtilization::WithThreshold(0.5)); ```

Underlying PinnedVec

LinkedList uses an ImpVec to establish and maintain the interconnections among elements of the list. An ImpVec can use any vector implementing PinnedVec which guarantees that the memory locations of elements stay intact. There are two major implementations of PinnedVec: a FixedVec and a SplitVec. Finally, a split vec can be created with different Growth strategies.

This means that a LinkedList can use a variety of backing storage. This is apparent from the complete signature without the default type paremeter value:

rust ignore LinkedList<'a, T, P> where P: PinnedVec<LinkedListNode<'a, T>>

Please see the relevant crates for details; however, below are brief rules of thumbs:

The following type aliases are defined for convenience to simplify the type signatures:

```rust ignore pub type LinkedListFixed<'a, T> = LinkedList<'a, T, FixedVec>>;

pub type LinkedListLinear<'a, T> = LinkedList<'a, T, SplitVec, Linear>>;

pub type LinkedListDoubling<'a, T> = LinkedList<'a, T, SplitVec, Doubling>>;

pub type LinkedListExponential<'a, T> = LinkedList<'a, T, SplitVec, Exponential>>; ```

These variants can be constructed with corresponding associated functions:

```rust use orxlinkedlist::prelude::*;

let list: LinkedListFixed = LinkedList::withfixedcapacity(100); let list: LinkedListLinear = LinkedList::withlineargrowth(32); let list: LinkedListDoubling = LinkedList::withdoublinggrowth(4); let list: LinkedListExponential = LinkedList::withexponentialgrowth(4, 1.5); ```