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}