1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! # orx-linked-list
//!
//! An efficient doubly linked list using regular `&` references with a focus to avoid smart pointers and improve cache locality.
//!
//! ## A. Motivation
//!
//! Self referential, often recursive, collections contain an important set of useful data structures including linked lists. However, building these structures with references `&` is not possible in safe rust.
//!
//! Alternatively, these collections can be built using reference counted smart pointers such as `std::rc::Rc` and independent heap allocations. However, independent heap allocations is a drawback as the elements do not live close to each other leading to poor cache locality. Further, reference counted pointers have a runtime overhead. This crate makes use of [`orx_imp_vec::ImpVec`](https://crates.io/crates/orx-imp-vec) as the underlying storage which specializes in building such collections.
//!
//! ### Standard LinkedList
//!
//! `std::collections::LinkedList` implementation avoids reference counted pointers and uses `NonNull` instead, most likely to avoid this overhead. However, this leads to a risky and difficult implementation that feels more low level than it should. You may see the implementation [here](https://doc.rust-lang.org/src/alloc/collections/linked_list.rs.html). The `unsafe` keyword is used more than 60 times in this file. These are usually related to reading from and writing to memory through raw pointers.
//!
//! ***Motivation:*** We do not need to count references provided that all elements and inter-element references belong to the same owner or container. This is because all elements will be dropped at the same time together with their inter-element references when the container `ImpVec` is dropped.
//!
//! ***Motivation:*** We should be able to define these structures without directly accessing memory through raw pointers. This is unnecessarily powerful and risky. Instead, unsafe code must be limited to methods which are specialized for and only allow defining required connections of self referential collections.
//!
//! ### orx_linked_list::LinkedList
//!
//! Linked list implementation in this crate uses an `ImpVec` as the underlying storage and makes use of its specialized methods. This brings the following advantages:
//!
//! * Allows for a higher level implementation without any use of raw pointers.
//! * Avoids smart pointers.
//! * Avoids almost completely accessing through integer indices.
//! * All nodes belong to the same `ImpVec` living close to each other. This allows for better cache locality.
//! * Full fetched doubly-linked-list implementation uses the `unsafe` keyword seven times, which are repeated uses of three methods:
//!   * `ImpVec::push_get_ref`
//!   * `ImpVec::move_get_ref`
//!   * `ImpVec::unsafe_truncate` (*a deref method from [`PinnedVec`](https://crates.io/crates/orx-pinned-vec)*)
//!
//! Furthermore, this implementation is more performant than the standard library implementation, a likely indicator of better cache locality. You may below the benchmark results for a series of random push/pop mutations after pushing "number of elements" elements to the list.
//!
//! <img src="https://raw.githubusercontent.com/orxfun/orx-linked-list/main/docs/img/bench_mutation_ends.PNG" alt="https://raw.githubusercontent.com/orxfun/orx-linked-list/main/docs/img/bench_mutation_ends.PNG" />
//!
//! ## B. Features
//!
//! `orx_linked_list::LinkedList` implementation provides standard linked list opeartions such as constant time insertions and removals. Further, it reflects the **recursive** nature of the data structure through so called `LinkedListSlice`s. The caller can move to the desired element of the linked list and get the rest of the list as a linked list slice; which is nothing but an immutable linked list. Furthermore, slices can simply be `collect`ed as an owned linked list.
//!
//! ```rust
//! use orx_linked_list::*;
//!
//! // BASIC
//! let mut list = LinkedList::new();
//! list.extend(vec!['a', 'b', 'c']);
//!
//! assert_eq!(list.len(), 3);
//! assert!(list.contains(&'b'));
//! assert_eq!(list.index_of(&'c'), Some(2));
//! assert_eq!(list.from_back_index_of(&'c'), Some(0));
//!
//! list.push_back('d');
//! assert_eq!(Some(&'d'), list.back());
//!
//! *list.get_at_mut(0).unwrap() = 'x';
//!
//! list.push_front('e');
//! *list.front_mut().unwrap() = 'f';
//!
//! _ = list.remove_at(1);
//! _ = list.pop_back();
//! list.insert_at(0, 'x');
//! list.clear();
//! list.push_front('y');
//! list.pop_front();
//!
//! // ITER
//! let list: LinkedList<_> = ['a', 'b', 'c', 'd', 'e'].into_iter().collect();
//!
//! let forward: Vec<_> = list.iter().copied().collect();
//! assert_eq!(forward, &['a', 'b', 'c', 'd', 'e']);
//!
//! let backward: Vec<_> = list.iter_from_back().copied().collect();
//! assert_eq!(backward, &['e', 'd', 'c', 'b', 'a']);
//!
//! // SPLITS
//! let (left, right) = list.split(2).unwrap();
//! assert_eq!(left, &['a', 'b']);
//! assert_eq!(right, &['c', 'd', 'e']);
//! // left & right are also nothing but immutable linked lists
//! assert_eq!(right.front(), Some(&'c'));
//! assert_eq!(left.back(), Some(&'b'));
//!
//! let (front, after) = list.split_front().unwrap();
//! assert_eq!(front, &'a');
//! assert_eq!(after, &['b', 'c', 'd', 'e']);
//!
//! let (before, back) = list.split_back().unwrap();
//! assert_eq!(before, &['a', 'b', 'c', 'd']);
//! assert_eq!(back, &'e');
//!
//! let (left, right) = list.split_before(&'d').unwrap();
//! assert_eq!(left, &['a', 'b', 'c']);
//! assert_eq!(right, &['d', 'e']);
//!
//! let (left, right) = list.split_after(&'d').unwrap();
//! assert_eq!(left, &['a', 'b', 'c', 'd']);
//! assert_eq!(right, &['e']);
//!
//! // RECURSIVE SPLITS
//! let (left1, left2) = left.split(1).unwrap();
//! assert_eq!(left1, &['a']);
//! assert_eq!(left2, &['b', 'c', 'd']);
//!
//! // SPLIT TO OWNED
//! let mut left_list = left.collect();
//!
//! assert_eq!(left_list, &['a', 'b', 'c', 'd']);
//! _ = left_list.pop_front();
//! _ = left_list.pop_back();
//! assert_eq!(left_list, &['b', 'c']);
//! ```
//!
//! ## License
//!
//! This library is licensed under MIT license. See LICENSE for details.

#![warn(
    missing_docs,
    clippy::unwrap_in_result,
    clippy::unwrap_used,
    clippy::panic,
    clippy::panic_in_result_fn,
    clippy::float_cmp,
    clippy::float_cmp_const,
    clippy::missing_panics_doc,
    clippy::todo
)]

mod eq;
mod extend;
mod from_iter;
mod iter;
mod linked_list;
mod linked_list_slice;
mod linked_list_view;
mod mem;
mod node;

pub use linked_list::LinkedList;
pub use linked_list_view::LinkedListView;
pub use mem::{MemoryStatus, MemoryUtilization};