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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
//! # orx-linked-list
//!
//! [![orx-linked-list crate](https://img.shields.io/crates/v/orx-linked-list.svg)](https://crates.io/crates/orx-linked-list)
//! [![orx-linked-list documentation](https://docs.rs/orx-linked-list/badge.svg)](https://docs.rs/orx-linked-list)
//!
//! An efficient and recursive singly and doubly linked list implementation.
//!
//! * *efficient*: Please see <a href="#section-benchmarks">benchmarks</a> section for performance reports of common linked list operations. Furthermore, `List` implementation emphasizes safe constant time access and mutations through usage of `NodeIndex`.
//! * *singly or doubly*: This is a generic parameter of the `List`. As expected, `Doubly` allows for more operations than `Singly`; however, it keeps two references per node rather than one.
//! * *recursive*: `List` allows creating a list by combining two lists in constant time.
//!
//!
//! ## Variants
//!
//! * **`List<Variant, T>`** where `T` is the type of elements:
//!   * **`List<Singly, T>`**: is the singly linked list, where each node holds a reference to the next node.
//!     * This is equivalent to `List<Singly<MemoryReclaimOnThreshold<2>>, T>`.
//!     * The alternative memory policy is `List<Singly<MemoryReclaimNever>, T>`.
//!   * **`List<Doubly, T>`**: is the doubly linked list, where each node holds references to the previous and next nodes.
//!     * This is equivalent to `List<Doubly<MemoryReclaimOnThreshold<2>>, T>`.
//!     * The alternative memory policy is `List<Doubly<MemoryReclaimNever>, T>`.
//!
//! *For possible memory management policies, please see <a href="#section-advanced">advanced usage</a> section.*
//!
//! ## Time Complexity of Methods
//!
//! In order to indicate the methods available only for the `Doubly` linked list, but not `Singly`, **(*d*)** indicator is used.
//!
//! The following is the list of methods with constant time **O(1)** time complexity.
//!
//! | ***O(1)*** Methods |
//! | -------- |
//! | **`front`, `back`**: access to front and back of the list  |
//! | **`get`**: access to to any node with a given index |
//! | **`push_front`, `push_back`**: push to front or back (*d*) of the list |
//! | **`pop_front`, `pop_back`**: pop from front and back (*d*) of the list |
//! | **`insert_prev_to`, `insert_next_to`**: insert a value previous or next to an existing node with a given index (*d*) |
//! | **`append_front`, `append_back`**: append another list to front or back of the list |
//! | **`iter`, `iter_from_back`**: create an iterator from the front or back (*d*) of the list; iterating has O(n) time complexity |
//! | **`iter_forward_from`, `iter_backward_from`**: create a forward or backward (*d*) iterator from any intermediate node with a given index; iterating has O(n) time complexity |
//!
//! | ***O(n)*** Methods |
//! | -------- |
//! | **`index_of`**: get the index of an element, which can later be used for ***O(1)*** methods |
//! | **`contains`, `position_of`**: check the existence or position of a value |
//! | **`insert_at`**: insert an element to an arbitrary position of the list |
//! | **`remove_at`**: remove an element from an arbitrary position of the list |
//! | **`iter`, `iter_from_back`**: iterate from the front or back (*d*) of the list |
//! | **`iter_forward_from`, `iter_backward_from`**: iterate in forward or backward (*d*) direction from any intermediate node with a given index |
//! | **`retain`, `retain_collect`**: retain keeping elements satisfying a predicate and optionally collect removed elements |
//!
//!
//! ## Examples
//!
//! ### Common Usage
//!
//! `orx_linked_list::List` provides common linked list functionalities, with a special emphasis on maintaining the recursive nature of the data structure which allows for constant time merging of lists.
//!
//! ```rust
//! use orx_linked_list::*;
//!
//! fn eq<'a, I: Iterator<Item = &'a u32> + Clone>(iter: I, slice: &[u32]) -> bool {
//!     iter.clone().count() == slice.len() && iter.zip(slice.iter()).all(|(a, b)| a == b)
//! }
//!
//! let _list: List<Singly, u32> = List::new();
//! let _list: List<Doubly, u32> = List::new();
//!
//! let mut list = List::<Doubly, _>::from_iter([3, 4, 5]);
//! assert_eq!(list.front(), Some(&3));
//! assert_eq!(list.back(), Some(&5));
//! assert!(eq(list.iter(), &[3, 4, 5]));
//! assert!(eq(list.iter_from_back(), &[5, 4, 3]));
//!
//! assert_eq!(list.pop_front(), Some(3));
//! assert_eq!(list.pop_back(), Some(5));
//!
//! list.push_back(5);
//! list.push_front(3);
//! assert!(eq(list.iter(), &[3, 4, 5]));
//!
//! let other = List::<Doubly, _>::from_iter([6, 7, 8, 9]);
//! list.append_back(other);
//! assert!(eq(list.iter(), &[3, 4, 5, 6, 7, 8, 9]));
//!
//! let other = List::<Doubly, _>::from_iter([0, 1, 2]);
//! list.append_front(other);
//! assert!(eq(list.iter(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
//!
//! list.retain(&|x| x < &5);
//! assert!(eq(list.iter(), &[0, 1, 2, 3, 4]));
//!
//! let mut odds = vec![];
//! let mut collect_odds = |x| odds.push(x);
//! list.retain_collect(&|x| x % 2 == 0, &mut collect_odds);
//!
//! assert!(eq(list.iter(), &[0, 2, 4]));
//! assert!(eq(odds.iter(), &[1, 3]));
//! ```
//!
//! ### `NodeIndex` Usage
//!
//! `NodeIndex` allows indexing into the collection in constant time with safety guarantees. The indices returned by growth methods, such as `push_back` or `append_next_to`, can be stored externally. Otherwise, an index for a value can be searched and obtained in linear time with `index_of` method. You may see below that these indices enable constant time access and mutation methods.
//!
//! ```rust
//! use orx_linked_list::*;
//!
//! fn eq<'a, I: Iterator<Item = &'a char> + Clone>(iter: I, slice: &[char]) -> bool {
//!     iter.clone().count() == slice.len() && iter.zip(slice.iter()).all(|(a, b)| a == b)
//! }
//!
//! let mut list = List::<Doubly, _>::from_iter(['a', 'b', 'c', 'd']);
//!
//! let x = list.index_of(&'x');
//! assert!(x.is_none());
//!
//! let maybe_b = list.index_of(&'b'); // O(n)
//! assert!(maybe_b.is_some());
//!
//! let b = maybe_b.unwrap();
//!
//! let data_b = list.get(b); // O(1)
//! assert_eq!(data_b, Some(&'b'));
//!
//! // O(1) to create the iterators from the index
//! assert!(eq(list.iter_forward_from(b).unwrap(), &['b', 'c', 'd']));
//! assert!(eq(list.iter_backward_from(b).unwrap(), &['b', 'a']));
//!
//! list.insert_prev_to(b, 'X').unwrap(); // O(1)
//! list.insert_next_to(b, 'Y').unwrap(); // O(1)
//! assert!(eq(list.iter(), &['a', 'X', 'b', 'Y', 'c', 'd']));
//!
//! let removed = list.remove(b); // O(1)
//! assert_eq!(removed, Ok('b'));
//! assert!(eq(list.iter(), &['a', 'X', 'Y', 'c', 'd']));
//!
//! // not possible to wrongly use the index
//! assert_eq!(list.get(b), None);
//! assert_eq!(
//!     list.get_or_error(b).err(),
//!     Some(NodeIndexError::RemovedNode)
//! );
//!
//! // indices can also be stored on insertion
//! let mut list = List::<Doubly, _>::from_iter(['a', 'b', 'c', 'd']);
//!
//! let x = list.push_back('x'); // grab index of x in O(1) on insertion
//!
//! _ = list.push_back('e');
//! _ = list.push_back('f');
//! assert!(eq(list.iter(), &['a', 'b', 'c', 'd', 'x', 'e', 'f']));
//!
//! let data_x = list.get(x); // O(1)
//! assert_eq!(data_x, Some(&'x'));
//!
//! list.insert_prev_to(x, 'w').unwrap(); // O(1)
//! list.insert_next_to(x, 'y').unwrap(); // O(1)
//! assert!(eq(list.iter(), &['a', 'b', 'c', 'd', 'w', 'x', 'y', 'e', 'f']));
//! ```
//!
//! <div id="section-advanced"></div>
//!
//! ### Advanced Usage
//!
//! `NodeIndex` is useful in overcoming the major drawback of linked lists that it requires O(n) time to reach the location to apply the O(1) mutation. With holding the required `NodeIndex`, these mutations can be achieved in O(1). However, in order to use these constant time methods, the node index must be valid.
//!
//! There are three possible reasons why a node index can be invalid and using it in relevant methods returns `NodeIndexError`:
//! - **a.** We are using the `NodeIndex` on a different `List`.
//! - **b.** We are using the `NodeIndex` while the corresponding element is removed from the `List`.
//! - **c.** `List` executed a memory reclaim under the hood in order to improve memory utilization.
//!
//! Notice that **a** and **b** are obviously mistakes, and hence, receiving an error is straightforward. Actually, we can see that using a `NodeIndex` on a `List` is much safer than using a `usize` on a `Vec`, as we are not protected against these mistakes in standard vector.
//!
//! However, **c** is completely related with underlying memory management of the `List`. There are two available policies, which are set as the generic argument of both `Singly` and `Doubly`:
//! * `MemoryReclaimOnThreshold<D>`
//! * `MemoryReclaimNever`
//!
//! #### Default Policy: `MemoryReclaimOnThreshold<2>`
//!
//! Adding elements to the `List` leads the underlying storage to grow, as expected. On the other hand, removing elements from the list leaves holes in the corresponding positions. In other words, the values are taken out but the memory location where the value is taken out is not immediately used for new elements.
//!
//! The `MemoryReclaimOnThreshold<D>` policy automatically reclaims these holes whenever the utilization falls below a threshold. The threshold is a function of the constant generic parameter `D`. Specifically, memory of closed nodes will be reclaimed whenever the ratio of closed nodes to all nodes exceeds one over `2^D`.
//! * when `D = 0`: memory will be reclaimed when utilization is below 0.00% (equivalent to never).
//! * when `D = 1`: memory will be reclaimed when utilization is below 50.00%.
//! * when `D = 2`: memory will be reclaimed when utilization is below 75.00%.
//! * when `D = 3`: memory will be reclaimed when utilization is below 87.50%.
//! * ...
//!
//! Underlying `PinnedVec` does not reallocate on memory reclaim operations. Instead, it efficiently moves around the elements within already claimed memory to fill the gaps and repairs the links among the nodes. However, since the positions of the elements will be moved, already obtained `NodeIndex`es might potentially be pointing to wrong positions.
//! * Fortunately, `NodeIndex` is aware of this operation. Therefore, it is **not** possible to wrongly use the index. If we obtain a node index, then the list reclaims memory, and then we try to use this node index on this list, we receive `NodeIndexError::ReorganizedCollection`.
//! * Unfortunately, the `NodeIndex` now is not useful. All we can do is re-obtain the index by a linear search with methods such as `index_of`.
//!
//! ```rust
//! use orx_linked_list::*;
//!
//! fn float_eq(x: f32, y: f32) -> bool {
//!     (x - y).abs() < f32::EPSILON
//! }
//!
//! // MemoryReclaimOnThreshold<2> -> memory will be reclaimed when utilization is below 75%
//! let mut list = List::<Doubly, _>::new();
//! let a = list.push_back('a');
//! list.push_back('b');
//! list.push_back('c');
//! list.push_back('d');
//! list.push_back('e');
//!
//! assert!(float_eq(list.node_utilization(), 1.00)); // utilization = 5/5 = 100%
//!
//! // no reorganization; 'a' is still valid
//! assert_eq!(list.get_or_error(a), Ok(&'a'));
//! assert_eq!(list.get(a), Some(&'a'));
//!
//! _ = list.pop_back(); // leaves a hole
//!
//! assert!(float_eq(list.node_utilization(), 0.80)); // utilization = 4/5 = 80%
//!
//! // no reorganization; 'a' is still valid
//! assert_eq!(list.get_or_error(a), Ok(&'a'));
//! assert_eq!(list.get(a), Some(&'a'));
//!
//! _ = list.pop_back(); // leaves the second hole; we have utilization = 3/5 = 60%
//!                       // this is below the threshold 75%, and triggers reclaim
//!                       // we claim the two unused nodes / holes
//!
//! assert!(float_eq(list.node_utilization(), 1.00)); // utilization = 3/3 = 100%
//!
//! // nodes reorganized; 'a' is no more valid
//! assert_eq!(
//!     list.get_or_error(a),
//!     Err(NodeIndexError::ReorganizedCollection)
//! );
//! assert_eq!(list.get(a), None);
//!
//! // re-obtain the index
//! let a = list.index_of(&'a').unwrap();
//! assert_eq!(list.get_or_error(a), Ok(&'a'));
//! assert_eq!(list.get(a), Some(&'a'));
//! ```
//!
//! #### Alternative Policy: `MemoryReclaimNever`
//!
//! However, it is possible to make sure that the node indices will always be valid, unless we manually invalidate them, by simply eliminating the case **c**. Setting the memory reclaim policy to `MemoryReclaimNever` guarantees that there will be no automatic or implicit memory reorganizations:
//! * use `List<Singly<MemoryReclaimNever>, T>` instead of `List<Singly, T>`, or
//! * use `List<Doubly<MemoryReclaimNever>, T>` instead of `List<Doubly, T>`.
//!
//! The drawback of this approach is that memory utilization can be low if there is a large number of pop or remove operations. However, `List` gives caller the control to manage memory by the following two methods:
//! * `List::node_utilization(&self) -> f32` method can be used to see the ratio of number of active/utilized nodes to the number of used nodes. The caller can decide when to take action by the following.
//! * `List::reclaim_closed_nodes(&mut self)` method can be used to manually run memory reclaim operation which will bring `node_utilization` to 100% while invalidating already created node indices.
//!
//! ```rust
//! use orx_linked_list::*;
//!
//! fn float_eq(x: f32, y: f32) -> bool {
//!     (x - y).abs() < f32::EPSILON
//! }
//!
//! // MemoryReclaimNever -> memory will never be reclaimed automatically
//! let mut list = List::<Doubly<MemoryReclaimNever>, _>::new();
//! let a = list.push_back('a');
//! list.push_back('b');
//! list.push_back('c');
//! list.push_back('d');
//! list.push_back('e');
//!
//! assert!(float_eq(list.node_utilization(), 1.00)); // utilization = 5/5 = 100%
//!
//! // no reorganization; 'a' is still valid
//! assert_eq!(list.get_or_error(a), Ok(&'a'));
//! assert_eq!(list.get(a), Some(&'a'));
//!
//! _ = list.pop_back(); // leaves a hole
//! _ = list.pop_back(); // leaves the second hole
//! _ = list.pop_back(); // leaves the third hole
//!
//! assert!(float_eq(list.node_utilization(), 0.40)); // utilization = 2/5 = 40%
//!
//! // still no reorganization; 'a' is and will always be valid unless we manually reclaim
//! assert_eq!(list.get_or_error(a), Ok(&'a'));
//! assert_eq!(list.get(a), Some(&'a'));
//!
//! list.reclaim_closed_nodes();
//!
//! // we can manually reclaim memory any time we want to maximize utilization
//! assert!(float_eq(list.node_utilization(), 1.00)); // utilization = 2/2 = 100%
//!
//! // we are still protected by list & index validation
//! // nodes reorganized; 'a' is no more valid, we cannot wrongly use the index
//! assert_eq!(
//!     list.get_or_error(a),
//!     Err(NodeIndexError::ReorganizedCollection)
//! );
//! assert_eq!(list.get(a), None);
//!
//! // re-obtain the index
//! let a = list.index_of(&'a').unwrap();
//! assert_eq!(list.get_or_error(a), Ok(&'a'));
//! assert_eq!(list.get(a), Some(&'a'));
//! ```
//!
//! ## Internal Features
//!
//! `orx_linked_list::List` makes use of the safety guarantees and efficiency features of [SelfRefCol](https://crates.io/crates/orx-selfref-col).
//! * `SelfRefCol` constructs its safety guarantees around the fact that all references will be among elements of the same collection. By preventing bringing in external references or leaking out references, it is safe to build the self referential collection with **regular `&` references**.
//! * With careful encapsulation, `SelfRefCol` prevents passing in external references to the list and leaking within list node references to outside. Once this is established, it provides methods to easily mutate inter list node references. These features allowed a very convenient implementation of the linked list in this crate with almost no use of the `unsafe` keyword, no read or writes through pointers and no access by indices. Compared to the `std::collections::LinkedList` implementation, it can be observed that `orx_linked_list::List` is a much **higher level implementation**.
//! * Furthermore, `orx_linked_list::List` is **significantly faster** than the standard linked list. One of the main reasons for this is the feature of `SelfRefCol` keeping all close to each other rather than at arbitrary locations in memory which leads to a better cache locality.
//!
//! <div id="section-benchmarks"></div>
//!
//! ## Benchmarks
//!
//! ### Mutation Ends
//!
//! *You may see the benchmark at [benches/mutation_ends.rs](https://github.com/orxfun/orx-linked-list/blob/main/benches/mutation_ends.rs).*
//!
//! This benchmark compares time performance of calls to `push_front`, `push_back`, `pop_front` and `pop_back` methods.
//!
//! <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" />
//!
//! ### Iteration
//!
//! *You may see the benchmark at [benches/iter.rs](https://github.com/orxfun/orx-linked-list/blob/main/benches/iter.rs).*
//!
//! This benchmark compares time performance of iteration through the `iter` method.
//!
//! <img src="https://raw.githubusercontent.com/orxfun/orx-linked-list/main/docs/img/iter.PNG" alt="https://raw.githubusercontent.com/orxfun/orx-linked-list/main/docs/img/iter.PNG" />
//!
//! ## Contributing
//!
//! Contributions are welcome! If you notice an error, have a question or think something could be improved, please open an [issue](https://github.com/orxfun/orx-linked-list/issues/new) or create a PR.
//!
//! ## 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 common_traits;
mod iterators;
mod list;
mod option_utils;
mod variants;

pub use list::{DoublyLinkedList, List, SinglyLinkedList};
pub use orx_selfref_col::{
    MemoryReclaimNever, MemoryReclaimOnThreshold, MemoryReclaimPolicy, NodeIndexError,
};
pub use variants::{doubly::Doubly, singly::Singly};