Skip to content

Commit 18d4afc

Browse files
authored
Merge pull request #182 from orxfun/leaves_into_with
Leaves into with
2 parents 1782ea0 + 15e3a5b commit 18d4afc

File tree

12 files changed

+648
-9
lines changed

12 files changed

+648
-9
lines changed

src/node_mut.rs

Lines changed: 195 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2142,7 +2142,7 @@ where
21422142
/// * [`Dfs`] for (pre-order) depth-first ([wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#Depth-first_search))
21432143
/// * [`PostOrder`] for post-order ([wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#Post-order,_LRN))
21442144
///
2145-
/// As opposed to [`walk_mut`], this method does require internal allocation.
2145+
/// As opposed to [`walk_mut`], this method does not require internal allocation.
21462146
/// Furthermore, it allows to attach node depths or sibling indices to the yield values.
21472147
/// Please see the examples below.
21482148
///
@@ -2371,7 +2371,7 @@ where
23712371
/// assert!(tree.is_empty());
23722372
/// assert_eq!(tree.get_root(), None);
23732373
/// ```
2374-
pub fn into_walk<T>(self) -> impl Iterator<Item = V::Item> + use<'a, T, V, M, P, MO>
2374+
pub fn into_walk<T>(self) -> impl Iterator<Item = V::Item>
23752375
where
23762376
T: Traverser<OverData>,
23772377
{
@@ -2390,7 +2390,7 @@ where
23902390
/// * [`Dfs`] for (pre-order) depth-first ([wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#Depth-first_search))
23912391
/// * [`PostOrder`] for post-order ([wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#Post-order,_LRN))
23922392
///
2393-
/// As opposed to [`into_walk`], this method does require internal allocation.
2393+
/// As opposed to [`into_walk`], this method does not require internal allocation.
23942394
/// Furthermore, it allows to attach node depths or sibling indices to the yield values.
23952395
/// Please see the examples below.
23962396
///
@@ -2623,7 +2623,7 @@ where
26232623
/// * [`Dfs`] for (pre-order) depth-first ([wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#Depth-first_search))
26242624
/// * [`PostOrder`] for post-order ([wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#Post-order,_LRN))
26252625
///
2626-
/// As opposed to [`leaves_mut`], this method does require internal allocation.
2626+
/// As opposed to [`leaves_mut`], this method does not require internal allocation.
26272627
/// Furthermore, it allows to attach node depths or sibling indices to the yield values.
26282628
/// Please see the examples below.
26292629
///
@@ -2755,6 +2755,197 @@ where
27552755
})
27562756
}
27572757

2758+
/// Creates an iterator that yields owned (removed) data of all leaves of the subtree rooted at this node.
2759+
///
2760+
/// Note that once the returned iterator is dropped, regardless of whether it is completely used up or not,
2761+
/// the subtree rooted at this node will be **removed** from the tree it belongs to.
2762+
/// If this node is the root of the tree, the tree will be left empty.
2763+
///
2764+
/// The order of the elements is determined by the generic [`Traverser`] parameter `T`.
2765+
/// Available implementations are:
2766+
/// * [`Bfs`] for breadth-first ([wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#Breadth-first_search))
2767+
/// * [`Dfs`] for (pre-order) depth-first ([wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#Depth-first_search))
2768+
/// * [`PostOrder`] for post-order ([wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#Post-order,_LRN))
2769+
///
2770+
/// See also [`leaves`] and [`leaves_mut`] for iterators over shared and mutable references, respectively.
2771+
///
2772+
/// Note that tree traversing methods typically allocate a temporary data structure that is dropped once the
2773+
/// iterator is dropped.
2774+
/// In use cases where we repeatedly iterate using any of the **leaves** methods over different nodes or different
2775+
/// trees, we can avoid the allocation by creating the traverser only once and using [`leaves_with`], [`leaves_mut_with`]
2776+
/// and [`into_leaves_with`] methods instead.
2777+
/// These methods additionally allow for iterating over nodes rather than data; and yielding node depths and sibling
2778+
/// indices in addition to node data.
2779+
///
2780+
/// > **(!)** As a method that removes nodes from the tree, this method might result in invalidating indices that are
2781+
/// > cached earlier in the [`Auto`] mode, but not in the [`Lazy`] mode. Please see the documentation of [MemoryPolicy]
2782+
/// > for details of node index validity. Specifically, the examples in the "Lazy Memory Claim: Preventing Invalid Indices"
2783+
/// > section presents a convenient way that allows us to make sure that the indices are valid.
2784+
///
2785+
/// [`Auto`]: crate::Auto
2786+
/// [`Lazy`]: crate::Lazy
2787+
/// [`MemoryPolicy`]: crate::MemoryPolicy
2788+
///
2789+
/// [`Bfs`]: crate::Bfs
2790+
/// [`Dfs`]: crate::Dfs
2791+
/// [`PostOrder`]: crate::PostOrder
2792+
/// [`leaves`]: crate::NodeRef::leaves
2793+
/// [`leaves_mut`]: crate::NodeMut::walk_mut
2794+
/// [`leaves_with`]: crate::NodeRef::leaves_with
2795+
/// [`leaves_mut_with`]: crate::NodeMut::leaves_mut_with
2796+
/// [`into_leaves_with`]: crate::NodeMut::into_leaves_with
2797+
///
2798+
/// # Examples
2799+
///
2800+
/// ```
2801+
/// use orx_tree::*;
2802+
///
2803+
/// // 1
2804+
/// // ╱ ╲
2805+
/// // ╱ ╲
2806+
/// // 2 3
2807+
/// // ╱ ╲ ╱ ╲
2808+
/// // 4 5 6 7
2809+
/// // | | ╱ ╲
2810+
/// // 8 9 10 11
2811+
///
2812+
/// let mut tree = DynTree::new(1);
2813+
/// let [id2, id3] = tree.root_mut().push_children([2, 3]);
2814+
/// let [id4, _] = tree.node_mut(id2).push_children([4, 5]);
2815+
/// tree.node_mut(id4).push_child(8);
2816+
/// let [id6, id7] = tree.node_mut(id3).push_children([6, 7]);
2817+
/// tree.node_mut(id6).push_child(9);
2818+
/// tree.node_mut(id7).push_children([10, 11]);
2819+
///
2820+
/// // keep indices valid during removals
2821+
/// let mut tree = tree.into_lazy_reclaim();
2822+
///
2823+
/// let n3 = tree.node_mut(id3);
2824+
/// let leaves: Vec<_> = n3.into_leaves::<Dfs>().collect();
2825+
/// assert_eq!(leaves, [9, 10, 11]);
2826+
///
2827+
/// // 1
2828+
/// // ╱
2829+
/// // ╱
2830+
/// // 2
2831+
/// // ╱ ╲
2832+
/// // 4 5
2833+
/// // |
2834+
/// // 8
2835+
/// let remaining: Vec<_> = tree.root().walk::<Dfs>().copied().collect();
2836+
/// assert_eq!(remaining, [1, 2, 4, 8, 5]);
2837+
///
2838+
/// let leaves: Vec<_> = tree.root_mut().into_leaves::<Dfs>().collect();
2839+
/// assert_eq!(leaves, [8, 5]);
2840+
///
2841+
/// assert!(tree.is_empty());
2842+
/// ```
2843+
pub fn into_leaves<T>(self) -> impl Iterator<Item = V::Item>
2844+
where
2845+
T: Traverser<OverData>,
2846+
{
2847+
let storage = T::Storage::<V>::default();
2848+
T::into_iter_with_storage_filtered(self, storage, |x| {
2849+
let ptr = <<OverData as Over>::Enumeration as Enumeration>::node_data(&x);
2850+
unsafe { &*ptr.ptr() }.next().is_empty()
2851+
})
2852+
}
2853+
2854+
/// Creates an iterator that yields owned (removed) data of all leaves of the subtree rooted at this node.
2855+
///
2856+
/// Note that once the returned iterator is dropped, regardless of whether it is completely used up or not,
2857+
/// the subtree rooted at this node will be **removed** from the tree it belongs to.
2858+
/// If this node is the root of the tree, the tree will be left empty.
2859+
///
2860+
/// The order of the elements is determined by the type of the `traverser` which implements [`Traverser`].
2861+
/// Available implementations are:
2862+
/// * [`Bfs`] for breadth-first ([wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#Breadth-first_search))
2863+
/// * [`Dfs`] for (pre-order) depth-first ([wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#Depth-first_search))
2864+
/// * [`PostOrder`] for post-order ([wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#Post-order,_LRN))
2865+
///
2866+
/// As opposed to [`into_leaves`], this method does not require internal allocation.
2867+
/// Furthermore, it allows to attach node depths or sibling indices to the yield values.
2868+
/// Please see the examples below.
2869+
///
2870+
/// [`into_leaves`]: crate::NodeMut::into_leaves
2871+
/// [`Bfs`]: crate::Bfs
2872+
/// [`Dfs`]: crate::Dfs
2873+
/// [`PostOrder`]: crate::PostOrder
2874+
///
2875+
/// > **(!)** As a method that removes nodes from the tree, this method might result in invalidating indices that are
2876+
/// > cached earlier in the [`Auto`] mode, but not in the [`Lazy`] mode. Please see the documentation of [MemoryPolicy]
2877+
/// > for details of node index validity. Specifically, the examples in the "Lazy Memory Claim: Preventing Invalid Indices"
2878+
/// > section presents a convenient way that allows us to make sure that the indices are valid.
2879+
///
2880+
/// [`Auto`]: crate::Auto
2881+
/// [`Lazy`]: crate::Lazy
2882+
/// [`MemoryPolicy`]: crate::MemoryPolicy
2883+
///
2884+
/// # Examples
2885+
///
2886+
/// ```
2887+
/// use orx_tree::*;
2888+
///
2889+
/// // 1
2890+
/// // ╱ ╲
2891+
/// // ╱ ╲
2892+
/// // 2 3
2893+
/// // ╱ ╲ ╱ ╲
2894+
/// // 4 5 6 7
2895+
/// // | | ╱ ╲
2896+
/// // 8 9 10 11
2897+
///
2898+
/// let mut tree = DynTree::new(1);
2899+
/// let [id2, id3] = tree.root_mut().push_children([2, 3]);
2900+
/// let [id4, _] = tree.node_mut(id2).push_children([4, 5]);
2901+
/// tree.node_mut(id4).push_child(8);
2902+
/// let [id6, id7] = tree.node_mut(id3).push_children([6, 7]);
2903+
/// tree.node_mut(id6).push_child(9);
2904+
/// tree.node_mut(id7).push_children([10, 11]);
2905+
///
2906+
/// // create the traverser 'dfs' only once, use it many times
2907+
/// // to walk over references, mutable references or removed values
2908+
/// // without additional allocation
2909+
///
2910+
/// let mut dfs = Dfs::default();
2911+
///
2912+
/// // keep indices valid during removals
2913+
/// let mut tree = tree.into_lazy_reclaim();
2914+
///
2915+
/// let n3 = tree.node_mut(id3);
2916+
/// let leaves: Vec<_> = n3.into_leaves_with(&mut dfs).collect();
2917+
/// assert_eq!(leaves, [9, 10, 11]);
2918+
///
2919+
/// // 1
2920+
/// // ╱
2921+
/// // ╱
2922+
/// // 2
2923+
/// // ╱ ╲
2924+
/// // 4 5
2925+
/// // |
2926+
/// // 8
2927+
/// let remaining: Vec<_> = tree.root().walk_with(&mut dfs).copied().collect();
2928+
/// assert_eq!(remaining, [1, 2, 4, 8, 5]);
2929+
///
2930+
/// let leaves: Vec<_> = tree.root_mut().into_leaves_with(&mut dfs).collect();
2931+
/// assert_eq!(leaves, [8, 5]);
2932+
///
2933+
/// assert!(tree.is_empty());
2934+
/// ```
2935+
pub fn into_leaves_with<T, O>(
2936+
self,
2937+
traverser: &'a mut T,
2938+
) -> impl Iterator<Item = OverItemInto<'a, V, O>>
2939+
where
2940+
O: OverMut,
2941+
T: Traverser<O>,
2942+
{
2943+
T::into_iter_with_storage_filtered(self, traverser.storage_mut(), |x| {
2944+
let ptr = <O::Enumeration as Enumeration>::node_data(x);
2945+
unsafe { &*ptr.ptr() }.next().is_empty()
2946+
})
2947+
}
2948+
27582949
// recursive
27592950

27602951
/// Recursively sets the data of all nodes belonging to the subtree rooted at this node using the `compute_data`
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
use super::BreadthFirstEnumeration;
2+
use super::iter_ptr::BfsIterPtr;
3+
use super::queue::Item;
4+
use crate::TreeVariant;
5+
use crate::aliases::Col;
6+
use crate::memory::MemoryPolicy;
7+
use crate::pinned_storage::PinnedStorage;
8+
use alloc::collections::VecDeque;
9+
use orx_self_or::SoM;
10+
use orx_selfref_col::{NodePtr, Refs};
11+
12+
pub struct BfsIterIntoFiltered<'a, V, M, P, E, S, F>
13+
where
14+
V: TreeVariant,
15+
M: MemoryPolicy,
16+
P: PinnedStorage,
17+
E: BreadthFirstEnumeration,
18+
S: SoM<VecDeque<Item<V, E>>>,
19+
F: Fn(&E::Item<NodePtr<V>>) -> bool,
20+
{
21+
col: &'a mut Col<V, M, P>,
22+
root_ptr: NodePtr<V>,
23+
iter: BfsIterPtr<V, E, S>,
24+
filter: F,
25+
}
26+
27+
impl<'a, V, M, P, E, S, F> BfsIterIntoFiltered<'a, V, M, P, E, S, F>
28+
where
29+
V: TreeVariant,
30+
M: MemoryPolicy,
31+
P: PinnedStorage,
32+
E: BreadthFirstEnumeration,
33+
S: SoM<VecDeque<Item<V, E>>>,
34+
F: Fn(&E::Item<NodePtr<V>>) -> bool,
35+
{
36+
/// # Safety
37+
///
38+
/// We are creating a mutable iterator over nodes of the collection `col`.
39+
/// This is safe only when the second argument `iter` makes sure that there exists only one mutable
40+
/// reference to the collection.
41+
///
42+
/// This is the case how this method is used, as follows:
43+
/// * Mutable iterators are created through the `Dfs` traverser's `TraverserMut::iter_mut` method.
44+
/// * This method requires a mutable reference to a mutable node `NodeMut` which is guaranteed to
45+
/// be the only reference to the collection.
46+
/// * Finally, this iterator's lifetime is equal to the borrow duration of the mutable node.
47+
#[allow(clippy::type_complexity)]
48+
pub(crate) unsafe fn from(
49+
(col, iter, root_ptr): (&'a mut Col<V, M, P>, BfsIterPtr<V, E, S>, NodePtr<V>),
50+
filter: F,
51+
) -> Self {
52+
let node = unsafe { &mut *root_ptr.ptr_mut() };
53+
54+
match node.prev().get() {
55+
Some(parent) => {
56+
let parent = unsafe { &mut *parent.ptr_mut() };
57+
let sibling_idx = parent.next_mut().remove(unsafe { root_ptr.ptr() as usize });
58+
debug_assert!(sibling_idx.is_some());
59+
60+
node.prev_mut().clear();
61+
}
62+
None => {
63+
// node_ptr points to the root node
64+
col.ends_mut().clear();
65+
}
66+
}
67+
68+
Self {
69+
col,
70+
root_ptr,
71+
iter,
72+
filter,
73+
}
74+
}
75+
76+
fn take_element(&mut self, element: E::Item<NodePtr<V>>) -> E::Item<V::Item> {
77+
E::map_node_data(element, |ptr| {
78+
let col = unsafe { &mut *(self.col as *mut Col<V, M, P>) };
79+
col.close(ptr)
80+
})
81+
}
82+
}
83+
84+
impl<V, M, P, E, S, F> Iterator for BfsIterIntoFiltered<'_, V, M, P, E, S, F>
85+
where
86+
V: TreeVariant,
87+
M: MemoryPolicy,
88+
P: PinnedStorage,
89+
E: BreadthFirstEnumeration,
90+
S: SoM<VecDeque<Item<V, E>>>,
91+
F: Fn(&E::Item<NodePtr<V>>) -> bool,
92+
{
93+
type Item = E::Item<V::Item>;
94+
95+
fn next(&mut self) -> Option<Self::Item> {
96+
loop {
97+
match self.iter.next() {
98+
Some(ptr) => {
99+
let included = (self.filter)(&ptr);
100+
let element = self.take_element(ptr);
101+
if included {
102+
return Some(element);
103+
}
104+
}
105+
None => return None,
106+
}
107+
}
108+
}
109+
}
110+
111+
impl<V, M, P, E, S, F> Drop for BfsIterIntoFiltered<'_, V, M, P, E, S, F>
112+
where
113+
V: TreeVariant,
114+
M: MemoryPolicy,
115+
P: PinnedStorage,
116+
E: BreadthFirstEnumeration,
117+
S: SoM<VecDeque<Item<V, E>>>,
118+
F: Fn(&E::Item<NodePtr<V>>) -> bool,
119+
{
120+
fn drop(&mut self) {
121+
while let Some(element) = self.iter.next() {
122+
self.take_element(element);
123+
}
124+
self.col.reclaim_from_closed_node(self.root_ptr);
125+
}
126+
}

src/traversal/breadth_first/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod tests;
33

44
mod bfs_enumeration;
55
pub(crate) mod into_iter;
6+
pub(crate) mod into_iter_filtered;
67
pub(crate) mod iter_mut;
78
pub(crate) mod iter_ptr;
89
pub(crate) mod iter_ref;

src/traversal/breadth_first/traverser_core.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::{
88
pinned_storage::PinnedStorage,
99
traversal::{
1010
Over, OverMut,
11+
breadth_first::into_iter_filtered::BfsIterIntoFiltered,
1112
enumeration::Enumeration,
1213
over::OverItem,
1314
over_mut::{OverItemInto, OverItemMut},
@@ -126,4 +127,22 @@ impl<O: Over> TraverserCore<O> for Bfs<O> {
126127
let iter_ptr = BfsIterPtr::<V, O::Enumeration, _>::from((storage, root));
127128
unsafe { BfsIterInto::<V, M, P, _, _>::from((col, iter_ptr, root)) }
128129
}
130+
131+
fn into_iter_with_storage_filtered<'a, V, M, P, MO, F>(
132+
node_mut: NodeMut<'a, V, M, P, MO>,
133+
storage: impl SoM<Self::Storage<V>>,
134+
filter: F,
135+
) -> impl Iterator<Item = OverItemInto<'a, V, O>>
136+
where
137+
V: TreeVariant + 'a,
138+
M: MemoryPolicy,
139+
P: PinnedStorage,
140+
MO: NodeMutOrientation,
141+
O: Over,
142+
F: Fn(&<<O as Over>::Enumeration as Enumeration>::Item<NodePtr<V>>) -> bool,
143+
{
144+
let (col, root) = node_mut.into_inner();
145+
let iter_ptr = BfsIterPtr::<V, O::Enumeration, _>::from((storage, root));
146+
unsafe { BfsIterIntoFiltered::<V, M, P, _, _, _>::from((col, iter_ptr, root), filter) }
147+
}
129148
}

0 commit comments

Comments
 (0)