orx_linked_list/list/common_traits/
into.rs

1use crate::{
2    Doubly, DoublyList, DoublyListLazy, DoublyListThreshold, List, Singly, SinglyList,
3    SinglyListLazy, SinglyListThreshold, variant::ListVariant,
4};
5use orx_pinned_vec::PinnedVec;
6use orx_selfref_col::{MemoryReclaimNever, MemoryReclaimOnThreshold, MemoryReclaimer, Node};
7
8impl<const D: usize, R, V, P> From<List<V, MemoryReclaimNever, P>>
9    for List<V, MemoryReclaimOnThreshold<D, V, R>, P>
10where
11    V: ListVariant,
12    R: MemoryReclaimer<V>,
13    P: PinnedVec<Node<V>>,
14{
15    fn from(value: List<V, MemoryReclaimNever, P>) -> Self {
16        Self(value.0.into())
17    }
18}
19
20impl<const D: usize, R, V, P> From<List<V, MemoryReclaimOnThreshold<D, V, R>, P>>
21    for List<V, MemoryReclaimNever, P>
22where
23    V: ListVariant,
24    R: MemoryReclaimer<V>,
25    P: PinnedVec<Node<V>>,
26{
27    fn from(value: List<V, MemoryReclaimOnThreshold<D, V, R>, P>) -> Self {
28        Self(value.0.into())
29    }
30}
31
32// transitions
33
34impl<const D: usize, R, V, P> List<V, MemoryReclaimOnThreshold<D, V, R>, P>
35where
36    V: ListVariant,
37    R: MemoryReclaimer<V>,
38    P: PinnedVec<Node<V>>,
39{
40    /// Transforms the list into lazy memory reclaim mode, such as:
41    /// * `DoublyList` is transformed into `DoublyListLazy`
42    /// * `SinglyList` is transformed into `SinglyListLazy`
43    ///
44    /// This transformation has no cost, and can as well be reverted
45    /// with no cost calling the [`into_auto_reclaim`] method.
46    ///
47    /// The lazy mode will never automatically reorganize nodes;
48    /// and hence, will never invalidate node indices.
49    ///
50    /// It is still possible to manually call [`reclaim_closed_nodes`].
51    ///
52    /// [`reclaim_closed_nodes`]: crate::List::reclaim_closed_nodes
53    /// [`into_auto_reclaim`]: crate::List::into_auto_reclaim
54    ///
55    /// # Examples
56    ///
57    /// ```rust
58    /// use orx_linked_list::*;
59    ///
60    /// let mut list: DoublyList<_> = DoublyList::new();
61    ///
62    /// // growing will never invalidate indices
63    /// let a = list.push_back('a');
64    /// let b = list.push_back('b');
65    /// let c = list.push_front('c');
66    /// let d = list.push_front('d');
67    ///
68    /// assert_eq!(list.node_utilization().num_active_nodes, 4);
69    /// assert_eq!(list.node_utilization().num_closed_nodes, 0);
70    ///
71    /// // make lazy
72    /// let mut list: DoublyListLazy<_> = list.into_lazy_reclaim();
73    ///
74    /// // now removals will never lead to an automatic reorganization
75    /// // hence a, b, c, d will never be invalidated unless they are removed
76    /// let pop = list.pop_back();
77    /// assert_eq!(pop, Some('b'));
78    ///
79    /// assert_eq!(list.node_utilization().num_active_nodes, 3);
80    /// assert_eq!(list.node_utilization().num_closed_nodes, 1);
81    ///
82    /// // we can still use the indices to have constant time access to nodes
83    ///
84    /// assert_eq!(list.idx_err(a), None);
85    /// assert_eq!(list.idx_err(b), Some(NodeIdxError::RemovedNode));
86    /// assert_eq!(list.idx_err(c), None);
87    /// assert_eq!(list.idx_err(d), None);
88    ///
89    /// assert_eq!(list.get(a), Some(&'a'));
90    /// assert_eq!(list.get(b), None);
91    /// assert_eq!(list.get(c), Some(&'c'));
92    /// assert_eq!(list.get(d), Some(&'d'));
93    ///
94    /// // make auto again
95    /// let mut list: DoublyList<_> = list.into_auto_reclaim();
96    ///
97    /// // now removals might lead to reorganization if node utilization
98    /// // falls below a certain threshold (75% when D=2).
99    /// let pop = list.remove(d);
100    /// assert_eq!(pop, 'd');
101    ///
102    /// // 2 removed nodes reclaimed (b, d); 2 active nodes remains (c, a)
103    /// assert_eq!(list.node_utilization().num_active_nodes, 2);
104    /// assert_eq!(list.node_utilization().num_closed_nodes, 0);
105    ///
106    /// // node positions might have change during reorganization
107    /// assert_eq!(list.idx_err(a), Some(NodeIdxError::ReorganizedCollection));
108    /// assert_eq!(list.idx_err(b), Some(NodeIdxError::ReorganizedCollection));
109    /// // or prior position does not belong to the storage any more
110    /// assert_eq!(list.idx_err(c), Some(NodeIdxError::OutOfBounds));
111    /// assert_eq!(list.idx_err(d), Some(NodeIdxError::OutOfBounds));
112    ///
113    /// // indices can no longer be used to access the elements
114    /// assert_eq!(list.get(a), None);
115    /// assert_eq!(list.get(b), None);
116    /// assert_eq!(list.get(c), None);
117    /// assert_eq!(list.get(d), None);
118    ///
119    /// // we can recollect valid indices if necessary
120    /// let idx: Vec<_> = list.indices().collect();
121    /// assert_eq!(list.get(idx[0]), Some(&'c'));
122    /// assert_eq!(list.get(idx[1]), Some(&'a'));
123    /// ```
124    pub fn into_lazy_reclaim(self) -> List<V, MemoryReclaimNever, P> {
125        self.into()
126    }
127}
128
129impl<T, P> DoublyListLazy<T, P>
130where
131    P: PinnedVec<Node<Doubly<T>>>,
132{
133    /// Transforms the list into auto memory reclaim mode, such as:
134    /// * `DoublyListLazy` is transformed into `DoublyList`
135    /// * `SinglyListLazy` is transformed into `SinglyList`
136    ///
137    /// This transformation has no cost, and can as well be reverted
138    /// with no cost calling the [`into_lazy_reclaim`] method.
139    ///
140    /// The auto mode will reclaim memory whenever the ratio of
141    /// active nodes to total used nodes; i.e., node utilization,
142    /// falls below a certain threshold.
143    ///
144    /// [`reclaim_closed_nodes`]: crate::List::reclaim_closed_nodes
145    /// [`into_lazy_reclaim`]: crate::List::into_lazy_reclaim
146    ///
147    /// # Examples
148    ///
149    /// ```rust
150    /// use orx_linked_list::*;
151    ///
152    /// let mut list: DoublyList<_> = DoublyList::new();
153    ///
154    /// // growing will never invalidate indices
155    /// let a = list.push_back('a');
156    /// let b = list.push_back('b');
157    /// let c = list.push_front('c');
158    /// let d = list.push_front('d');
159    ///
160    /// assert_eq!(list.node_utilization().num_active_nodes, 4);
161    /// assert_eq!(list.node_utilization().num_closed_nodes, 0);
162    ///
163    /// // make lazy
164    /// let mut list: DoublyListLazy<_> = list.into_lazy_reclaim();
165    ///
166    /// // now removals will never lead to an automatic reorganization
167    /// // hence a, b, c, d will never be invalidated unless they are removed
168    /// let pop = list.pop_back();
169    /// assert_eq!(pop, Some('b'));
170    ///
171    /// assert_eq!(list.node_utilization().num_active_nodes, 3);
172    /// assert_eq!(list.node_utilization().num_closed_nodes, 1);
173    ///
174    /// // we can still use the indices to have constant time access to nodes
175    ///
176    /// assert_eq!(list.idx_err(a), None);
177    /// assert_eq!(list.idx_err(b), Some(NodeIdxError::RemovedNode));
178    /// assert_eq!(list.idx_err(c), None);
179    /// assert_eq!(list.idx_err(d), None);
180    ///
181    /// assert_eq!(list.get(a), Some(&'a'));
182    /// assert_eq!(list.get(b), None);
183    /// assert_eq!(list.get(c), Some(&'c'));
184    /// assert_eq!(list.get(d), Some(&'d'));
185    ///
186    /// // make auto again
187    /// let mut list: DoublyList<_> = list.into_auto_reclaim();
188    ///
189    /// // now removals might lead to reorganization if node utilization
190    /// // falls below a certain threshold (75% when D=2).
191    /// let pop = list.remove(d);
192    /// assert_eq!(pop, 'd');
193    ///
194    /// // 2 removed nodes reclaimed (b, d); 2 active nodes remains (c, a)
195    /// assert_eq!(list.node_utilization().num_active_nodes, 2);
196    /// assert_eq!(list.node_utilization().num_closed_nodes, 0);
197    ///
198    /// // node positions might have change during reorganization
199    /// assert_eq!(list.idx_err(a), Some(NodeIdxError::ReorganizedCollection));
200    /// assert_eq!(list.idx_err(b), Some(NodeIdxError::ReorganizedCollection));
201    /// // or prior position does not belong to the storage any more
202    /// assert_eq!(list.idx_err(c), Some(NodeIdxError::OutOfBounds));
203    /// assert_eq!(list.idx_err(d), Some(NodeIdxError::OutOfBounds));
204    ///
205    /// // indices can no longer be used to access the elements
206    /// assert_eq!(list.get(a), None);
207    /// assert_eq!(list.get(b), None);
208    /// assert_eq!(list.get(c), None);
209    /// assert_eq!(list.get(d), None);
210    ///
211    /// // we can recollect valid indices if necessary
212    /// let idx: Vec<_> = list.indices().collect();
213    /// assert_eq!(list.get(idx[0]), Some(&'c'));
214    /// assert_eq!(list.get(idx[1]), Some(&'a'));
215    /// ```
216    pub fn into_auto_reclaim(self) -> DoublyList<T, P> {
217        self.into()
218    }
219
220    /// Transforms the list into auto memory reclaim mode, such as:
221    /// * `DoublyListLazy` is transformed into `DoublyList`
222    /// * `SinglyListLazy` is transformed into `SinglyList`
223    ///
224    /// This transformation has no cost, and can as well be reverted
225    /// with no cost calling the [`into_lazy_reclaim`] method.
226    ///
227    /// The auto mode will reclaim memory whenever the ratio of
228    /// active nodes to total used nodes; i.e., node utilization,
229    /// falls below a certain threshold.
230    ///
231    /// [`reclaim_closed_nodes`]: crate::List::reclaim_closed_nodes
232    /// [`into_lazy_reclaim`]: crate::List::into_lazy_reclaim
233    ///
234    /// # Examples
235    ///
236    /// ```rust
237    /// use orx_linked_list::*;
238    ///
239    /// let mut list: DoublyList<_> = DoublyList::new();
240    ///
241    /// // growing will never invalidate indices
242    /// let a = list.push_back('a');
243    /// let b = list.push_back('b');
244    /// let c = list.push_front('c');
245    /// let d = list.push_front('d');
246    ///
247    /// assert_eq!(list.node_utilization().num_active_nodes, 4);
248    /// assert_eq!(list.node_utilization().num_closed_nodes, 0);
249    ///
250    /// // make lazy
251    /// let mut list: DoublyListLazy<_> = list.into_lazy_reclaim();
252    ///
253    /// // now removals will never lead to an automatic reorganization
254    /// // hence a, b, c, d will never be invalidated unless they are removed
255    /// let pop = list.pop_back();
256    /// assert_eq!(pop, Some('b'));
257    ///
258    /// assert_eq!(list.node_utilization().num_active_nodes, 3);
259    /// assert_eq!(list.node_utilization().num_closed_nodes, 1);
260    ///
261    /// // we can still use the indices to have constant time access to nodes
262    ///
263    /// assert_eq!(list.idx_err(a), None);
264    /// assert_eq!(list.idx_err(b), Some(NodeIdxError::RemovedNode));
265    /// assert_eq!(list.idx_err(c), None);
266    /// assert_eq!(list.idx_err(d), None);
267    ///
268    /// assert_eq!(list.get(a), Some(&'a'));
269    /// assert_eq!(list.get(b), None);
270    /// assert_eq!(list.get(c), Some(&'c'));
271    /// assert_eq!(list.get(d), Some(&'d'));
272    ///
273    /// // make auto again
274    /// let mut list: DoublyList<_> = list.into_auto_reclaim();
275    ///
276    /// // now removals might lead to reorganization if node utilization
277    /// // falls below a certain threshold (75% when D=2).
278    /// let pop = list.remove(d);
279    /// assert_eq!(pop, 'd');
280    ///
281    /// // 2 removed nodes reclaimed (b, d); 2 active nodes remains (c, a)
282    /// assert_eq!(list.node_utilization().num_active_nodes, 2);
283    /// assert_eq!(list.node_utilization().num_closed_nodes, 0);
284    ///
285    /// // node positions might have change during reorganization
286    /// assert_eq!(list.idx_err(a), Some(NodeIdxError::ReorganizedCollection));
287    /// assert_eq!(list.idx_err(b), Some(NodeIdxError::ReorganizedCollection));
288    /// // or prior position does not belong to the storage any more
289    /// assert_eq!(list.idx_err(c), Some(NodeIdxError::OutOfBounds));
290    /// assert_eq!(list.idx_err(d), Some(NodeIdxError::OutOfBounds));
291    ///
292    /// // indices can no longer be used to access the elements
293    /// assert_eq!(list.get(a), None);
294    /// assert_eq!(list.get(b), None);
295    /// assert_eq!(list.get(c), None);
296    /// assert_eq!(list.get(d), None);
297    ///
298    /// // we can recollect valid indices if necessary
299    /// let idx: Vec<_> = list.indices().collect();
300    /// assert_eq!(list.get(idx[0]), Some(&'c'));
301    /// assert_eq!(list.get(idx[1]), Some(&'a'));
302    /// ```
303    pub fn into_auto_reclaim_with_threshold<const D: usize>(self) -> DoublyListThreshold<D, T, P> {
304        self.into()
305    }
306}
307
308impl<T, P> SinglyListLazy<T, P>
309where
310    P: PinnedVec<Node<Singly<T>>>,
311{
312    /// Transforms the list into auto memory reclaim mode, such as:
313    /// * `DoublyListLazy` is transformed into `DoublyList`
314    /// * `SinglyListLazy` is transformed into `SinglyList`
315    ///
316    /// This transformation has no cost, and can as well be reverted
317    /// with no cost calling the [`into_lazy_reclaim`] method.
318    ///
319    /// The auto mode will reclaim memory whenever the ratio of
320    /// active nodes to total used nodes; i.e., node utilization,
321    /// falls below a certain threshold.
322    ///
323    /// [`reclaim_closed_nodes`]: crate::List::reclaim_closed_nodes
324    /// [`into_lazy_reclaim`]: crate::List::into_lazy_reclaim
325    ///
326    /// # Examples
327    ///
328    /// ```rust
329    /// use orx_linked_list::*;
330    ///
331    /// let mut list: DoublyList<_> = DoublyList::new();
332    ///
333    /// // growing will never invalidate indices
334    /// let a = list.push_back('a');
335    /// let b = list.push_back('b');
336    /// let c = list.push_front('c');
337    /// let d = list.push_front('d');
338    ///
339    /// assert_eq!(list.node_utilization().num_active_nodes, 4);
340    /// assert_eq!(list.node_utilization().num_closed_nodes, 0);
341    ///
342    /// // make lazy
343    /// let mut list: DoublyListLazy<_> = list.into_lazy_reclaim();
344    ///
345    /// // now removals will never lead to an automatic reorganization
346    /// // hence a, b, c, d will never be invalidated unless they are removed
347    /// let pop = list.pop_back();
348    /// assert_eq!(pop, Some('b'));
349    ///
350    /// assert_eq!(list.node_utilization().num_active_nodes, 3);
351    /// assert_eq!(list.node_utilization().num_closed_nodes, 1);
352    ///
353    /// // we can still use the indices to have constant time access to nodes
354    ///
355    /// assert_eq!(list.idx_err(a), None);
356    /// assert_eq!(list.idx_err(b), Some(NodeIdxError::RemovedNode));
357    /// assert_eq!(list.idx_err(c), None);
358    /// assert_eq!(list.idx_err(d), None);
359    ///
360    /// assert_eq!(list.get(a), Some(&'a'));
361    /// assert_eq!(list.get(b), None);
362    /// assert_eq!(list.get(c), Some(&'c'));
363    /// assert_eq!(list.get(d), Some(&'d'));
364    ///
365    /// // make auto again
366    /// let mut list: DoublyList<_> = list.into_auto_reclaim();
367    ///
368    /// // now removals might lead to reorganization if node utilization
369    /// // falls below a certain threshold (75% when D=2).
370    /// let pop = list.remove(d);
371    /// assert_eq!(pop, 'd');
372    ///
373    /// // 2 removed nodes reclaimed (b, d); 2 active nodes remains (c, a)
374    /// assert_eq!(list.node_utilization().num_active_nodes, 2);
375    /// assert_eq!(list.node_utilization().num_closed_nodes, 0);
376    ///
377    /// // node positions might have change during reorganization
378    /// assert_eq!(list.idx_err(a), Some(NodeIdxError::ReorganizedCollection));
379    /// assert_eq!(list.idx_err(b), Some(NodeIdxError::ReorganizedCollection));
380    /// // or prior position does not belong to the storage any more
381    /// assert_eq!(list.idx_err(c), Some(NodeIdxError::OutOfBounds));
382    /// assert_eq!(list.idx_err(d), Some(NodeIdxError::OutOfBounds));
383    ///
384    /// // indices can no longer be used to access the elements
385    /// assert_eq!(list.get(a), None);
386    /// assert_eq!(list.get(b), None);
387    /// assert_eq!(list.get(c), None);
388    /// assert_eq!(list.get(d), None);
389    ///
390    /// // we can recollect valid indices if necessary
391    /// let idx: Vec<_> = list.indices().collect();
392    /// assert_eq!(list.get(idx[0]), Some(&'c'));
393    /// assert_eq!(list.get(idx[1]), Some(&'a'));
394    /// ```
395    pub fn into_auto_reclaim(self) -> SinglyList<T, P> {
396        self.into()
397    }
398
399    /// Transforms the list into auto memory reclaim mode, such as:
400    /// * `DoublyListLazy` is transformed into `DoublyList`
401    /// * `SinglyListLazy` is transformed into `SinglyList`
402    ///
403    /// This transformation has no cost, and can as well be reverted
404    /// with no cost calling the [`into_lazy_reclaim`] method.
405    ///
406    /// The auto mode will reclaim memory whenever the ratio of
407    /// active nodes to total used nodes; i.e., node utilization,
408    /// falls below a certain threshold.
409    ///
410    /// [`reclaim_closed_nodes`]: crate::List::reclaim_closed_nodes
411    /// [`into_lazy_reclaim`]: crate::List::into_lazy_reclaim
412    ///
413    /// # Examples
414    ///
415    /// ```rust
416    /// use orx_linked_list::*;
417    ///
418    /// let mut list: DoublyList<_> = DoublyList::new();
419    ///
420    /// // growing will never invalidate indices
421    /// let a = list.push_back('a');
422    /// let b = list.push_back('b');
423    /// let c = list.push_front('c');
424    /// let d = list.push_front('d');
425    ///
426    /// assert_eq!(list.node_utilization().num_active_nodes, 4);
427    /// assert_eq!(list.node_utilization().num_closed_nodes, 0);
428    ///
429    /// // make lazy
430    /// let mut list: DoublyListLazy<_> = list.into_lazy_reclaim();
431    ///
432    /// // now removals will never lead to an automatic reorganization
433    /// // hence a, b, c, d will never be invalidated unless they are removed
434    /// let pop = list.pop_back();
435    /// assert_eq!(pop, Some('b'));
436    ///
437    /// assert_eq!(list.node_utilization().num_active_nodes, 3);
438    /// assert_eq!(list.node_utilization().num_closed_nodes, 1);
439    ///
440    /// // we can still use the indices to have constant time access to nodes
441    ///
442    /// assert_eq!(list.idx_err(a), None);
443    /// assert_eq!(list.idx_err(b), Some(NodeIdxError::RemovedNode));
444    /// assert_eq!(list.idx_err(c), None);
445    /// assert_eq!(list.idx_err(d), None);
446    ///
447    /// assert_eq!(list.get(a), Some(&'a'));
448    /// assert_eq!(list.get(b), None);
449    /// assert_eq!(list.get(c), Some(&'c'));
450    /// assert_eq!(list.get(d), Some(&'d'));
451    ///
452    /// // make auto again
453    /// let mut list: DoublyList<_> = list.into_auto_reclaim();
454    ///
455    /// // now removals might lead to reorganization if node utilization
456    /// // falls below a certain threshold (75% when D=2).
457    /// let pop = list.remove(d);
458    /// assert_eq!(pop, 'd');
459    ///
460    /// // 2 removed nodes reclaimed (b, d); 2 active nodes remains (c, a)
461    /// assert_eq!(list.node_utilization().num_active_nodes, 2);
462    /// assert_eq!(list.node_utilization().num_closed_nodes, 0);
463    ///
464    /// // node positions might have change during reorganization
465    /// assert_eq!(list.idx_err(a), Some(NodeIdxError::ReorganizedCollection));
466    /// assert_eq!(list.idx_err(b), Some(NodeIdxError::ReorganizedCollection));
467    /// // or prior position does not belong to the storage any more
468    /// assert_eq!(list.idx_err(c), Some(NodeIdxError::OutOfBounds));
469    /// assert_eq!(list.idx_err(d), Some(NodeIdxError::OutOfBounds));
470    ///
471    /// // indices can no longer be used to access the elements
472    /// assert_eq!(list.get(a), None);
473    /// assert_eq!(list.get(b), None);
474    /// assert_eq!(list.get(c), None);
475    /// assert_eq!(list.get(d), None);
476    ///
477    /// // we can recollect valid indices if necessary
478    /// let idx: Vec<_> = list.indices().collect();
479    /// assert_eq!(list.get(idx[0]), Some(&'c'));
480    /// assert_eq!(list.get(idx[1]), Some(&'a'));
481    /// ```
482    pub fn into_auto_reclaim_with_threshold<const D: usize>(self) -> SinglyListThreshold<D, T, P> {
483        self.into()
484    }
485}