par_iter/iter/
walk_tree.rs

1use std::iter::once;
2
3use crate::{
4    iter::plumbing::{bridge_unindexed, Folder, UnindexedConsumer, UnindexedProducer},
5    prelude::*,
6};
7
8#[derive(Debug)]
9struct WalkTreePrefixProducer<'b, S, B> {
10    to_explore: Vec<S>, // nodes (and subtrees) we have to process
11    seen: Vec<S>,       // nodes which have already been explored
12    children_of: &'b B, // function generating children
13}
14
15impl<S, B, I> UnindexedProducer for WalkTreePrefixProducer<'_, S, B>
16where
17    S: Send,
18    B: Fn(&S) -> I + Send + Sync,
19    I: IntoIterator<Item = S>,
20    I::IntoIter: DoubleEndedIterator,
21{
22    type Item = S;
23
24    fn split(mut self) -> (Self, Option<Self>) {
25        // explore while front is of size one.
26        while self.to_explore.len() == 1 {
27            let front_node = self.to_explore.pop().unwrap();
28            self.to_explore
29                .extend((self.children_of)(&front_node).into_iter().rev());
30            self.seen.push(front_node);
31        }
32        // now take half of the front.
33        let right_children = split_vec(&mut self.to_explore);
34        let right = right_children
35            .map(|mut c| {
36                std::mem::swap(&mut c, &mut self.to_explore);
37                WalkTreePrefixProducer {
38                    to_explore: c,
39                    seen: Vec::new(),
40                    children_of: self.children_of,
41                }
42            })
43            .or_else(|| {
44                // we can still try to divide 'seen'
45                let right_seen = split_vec(&mut self.seen);
46                right_seen.map(|s| WalkTreePrefixProducer {
47                    to_explore: Default::default(),
48                    seen: s,
49                    children_of: self.children_of,
50                })
51            });
52        (self, right)
53    }
54
55    fn fold_with<F>(mut self, mut folder: F) -> F
56    where
57        F: Folder<Self::Item>,
58    {
59        // start by consuming everything seen
60        folder = folder.consume_iter(self.seen);
61        if folder.full() {
62            return folder;
63        }
64        // now do all remaining explorations
65        while let Some(e) = self.to_explore.pop() {
66            self.to_explore
67                .extend((self.children_of)(&e).into_iter().rev());
68            folder = folder.consume(e);
69            if folder.full() {
70                return folder;
71            }
72        }
73        folder
74    }
75}
76
77/// ParallelIterator for arbitrary tree-shaped patterns.
78/// Returned by the [`walk_tree_prefix()`] function.
79#[derive(Debug)]
80pub struct WalkTreePrefix<S, B> {
81    initial_state: S,
82    children_of: B,
83}
84
85impl<S, B, I> ParallelIterator for WalkTreePrefix<S, B>
86where
87    S: Send,
88    B: Fn(&S) -> I + Send + Sync,
89    I: IntoIterator<Item = S>,
90    I::IntoIter: DoubleEndedIterator,
91{
92    type Item = S;
93
94    fn drive_unindexed<C>(self, consumer: C) -> C::Result
95    where
96        C: UnindexedConsumer<Self::Item>,
97    {
98        let producer = WalkTreePrefixProducer {
99            to_explore: once(self.initial_state).collect(),
100            seen: Vec::new(),
101            children_of: &self.children_of,
102        };
103        bridge_unindexed(producer, consumer)
104    }
105}
106
107/// Create a tree-like prefix parallel iterator from an initial root node.
108/// The `children_of` function should take a node and return an iterator over
109/// its child nodes. The best parallelization is obtained when the tree is
110/// balanced but we should also be able to handle harder cases.
111///
112/// # Ordering
113///
114/// This function guarantees a prefix ordering. See also [`walk_tree_postfix`],
115/// which guarantees a postfix order.
116/// If you don't care about ordering, you should use [`walk_tree`],
117/// which will use whatever is believed to be fastest.
118/// For example a perfect binary tree of 7 nodes will reduced in the following
119/// order:
120///
121/// ```text
122///      a
123///     / \
124///    /   \
125///   b     c
126///  / \   / \
127/// d   e f   g
128///
129/// reduced as a,b,d,e,c,f,g
130/// ```
131///
132/// # Example
133///
134/// ```text
135///      4
136///     / \
137///    /   \
138///   2     3
139///        / \
140///       1   2
141/// ```
142///
143/// ```
144/// use par_iter::iter::walk_tree_prefix;
145/// use par_iter::prelude::*;
146///
147/// let par_iter = walk_tree_prefix(4, |&e| {
148///     if e <= 2 {
149///         Vec::new()
150///     } else {
151///         vec![e / 2, e / 2 + 1]
152///     }
153/// });
154/// assert_eq!(par_iter.sum::<u32>(), 12);
155/// ```
156///
157/// # Example
158///
159/// ```
160/// use par_iter::prelude::*;
161/// use par_iter::iter::walk_tree_prefix;
162///
163/// struct Node {
164///     content: u32,
165///     left: Option<Box<Node>>,
166///     right: Option<Box<Node>>,
167/// }
168///
169/// // Here we loop on the following tree:
170/// //
171/// //       10
172/// //      /  \
173/// //     /    \
174/// //    3     14
175/// //            \
176/// //             \
177/// //              18
178///
179/// let root = Node {
180///     content: 10,
181///     left: Some(Box::new(Node {
182///         content: 3,
183///         left: None,
184///         right: None,
185///     })),
186///     right: Some(Box::new(Node {
187///         content: 14,
188///         left: None,
189///         right: Some(Box::new(Node {
190///             content: 18,
191///             left: None,
192///             right: None,
193///         })),
194///     })),
195/// };
196///
197/// let mut v: Vec<u32> = walk_tree_prefix(&root, |r| {
198///     r.left
199///         .as_ref()
200///         .into_iter()
201///         .chain(r.right.as_ref())
202///         .map(|n| &**n)
203/// })
204/// .map(|node| node.content)
205/// .collect();
206/// assert_eq!(v, vec![10, 3, 14, 18]);
207/// ```
208pub fn walk_tree_prefix<S, B, I>(root: S, children_of: B) -> WalkTreePrefix<S, B>
209where
210    S: Send,
211    B: Fn(&S) -> I + Send + Sync,
212    I: IntoIterator<Item = S>,
213    I::IntoIter: DoubleEndedIterator,
214{
215    WalkTreePrefix {
216        initial_state: root,
217        children_of,
218    }
219}
220
221// post fix
222
223#[derive(Debug)]
224struct WalkTreePostfixProducer<'b, S, B> {
225    to_explore: Vec<S>, // nodes (and subtrees) we have to process
226    seen: Vec<S>,       // nodes which have already been explored
227    children_of: &'b B, // function generating children
228}
229
230impl<S, B, I> UnindexedProducer for WalkTreePostfixProducer<'_, S, B>
231where
232    S: Send,
233    B: Fn(&S) -> I + Send + Sync,
234    I: IntoIterator<Item = S>,
235{
236    type Item = S;
237
238    fn split(mut self) -> (Self, Option<Self>) {
239        // explore while front is of size one.
240        while self.to_explore.len() == 1 {
241            let front_node = self.to_explore.pop().unwrap();
242            self.to_explore
243                .extend((self.children_of)(&front_node).into_iter());
244            self.seen.push(front_node);
245        }
246        // now take half of the front.
247        let right_children = split_vec(&mut self.to_explore);
248        let right = right_children
249            .map(|c| {
250                let right_seen = std::mem::take(&mut self.seen); // postfix -> upper nodes are processed last
251                WalkTreePostfixProducer {
252                    to_explore: c,
253                    seen: right_seen,
254                    children_of: self.children_of,
255                }
256            })
257            .or_else(|| {
258                // we can still try to divide 'seen'
259                let right_seen = split_vec(&mut self.seen);
260                right_seen.map(|mut s| {
261                    std::mem::swap(&mut self.seen, &mut s);
262                    WalkTreePostfixProducer {
263                        to_explore: Default::default(),
264                        seen: s,
265                        children_of: self.children_of,
266                    }
267                })
268            });
269        (self, right)
270    }
271
272    fn fold_with<F>(self, mut folder: F) -> F
273    where
274        F: Folder<Self::Item>,
275    {
276        // now do all remaining explorations
277        for e in self.to_explore {
278            folder = consume_rec_postfix(&self.children_of, e, folder);
279            if folder.full() {
280                return folder;
281            }
282        }
283        // end by consuming everything seen
284        folder.consume_iter(self.seen.into_iter().rev())
285    }
286}
287
288fn consume_rec_postfix<F, S, B, I>(children_of: &B, s: S, mut folder: F) -> F
289where
290    F: Folder<S>,
291    B: Fn(&S) -> I,
292    I: IntoIterator<Item = S>,
293{
294    let children = (children_of)(&s).into_iter();
295    for child in children {
296        folder = consume_rec_postfix(children_of, child, folder);
297        if folder.full() {
298            return folder;
299        }
300    }
301    folder.consume(s)
302}
303
304/// ParallelIterator for arbitrary tree-shaped patterns.
305/// Returned by the [`walk_tree_postfix()`] function.
306#[derive(Debug)]
307pub struct WalkTreePostfix<S, B> {
308    initial_state: S,
309    children_of: B,
310}
311
312impl<S, B, I> ParallelIterator for WalkTreePostfix<S, B>
313where
314    S: Send,
315    B: Fn(&S) -> I + Send + Sync,
316    I: IntoIterator<Item = S>,
317{
318    type Item = S;
319
320    fn drive_unindexed<C>(self, consumer: C) -> C::Result
321    where
322        C: UnindexedConsumer<Self::Item>,
323    {
324        let producer = WalkTreePostfixProducer {
325            to_explore: once(self.initial_state).collect(),
326            seen: Vec::new(),
327            children_of: &self.children_of,
328        };
329        bridge_unindexed(producer, consumer)
330    }
331}
332
333/// Divide given vector in two equally sized vectors.
334/// Return `None` if initial size is <=1.
335/// We return the first half and keep the last half in `v`.
336fn split_vec<T>(v: &mut Vec<T>) -> Option<Vec<T>> {
337    if v.len() <= 1 {
338        None
339    } else {
340        let n = v.len() / 2;
341        Some(v.split_off(n))
342    }
343}
344
345/// Create a tree like postfix parallel iterator from an initial root node.
346/// The `children_of` function should take a node and iterate on all of its
347/// child nodes. The best parallelization is obtained when the tree is balanced
348/// but we should also be able to handle harder cases.
349///
350/// # Ordering
351///
352/// This function guarantees a postfix ordering. See also [`walk_tree_prefix`]
353/// which guarantees a prefix order. If you don't care about ordering, you
354/// should use [`walk_tree`], which will use whatever is believed to be fastest.
355///
356/// Between siblings, children are reduced in order -- that is first children
357/// are reduced first.
358///
359/// For example a perfect binary tree of 7 nodes will reduced in the following
360/// order:
361///
362/// ```text
363///      a
364///     / \
365///    /   \
366///   b     c
367///  / \   / \
368/// d   e f   g
369///
370/// reduced as d,e,b,f,g,c,a
371/// ```
372///
373/// # Example
374///
375/// ```text
376///      4
377///     / \
378///    /   \
379///   2     3
380///        / \
381///       1   2
382/// ```
383///
384/// ```
385/// use par_iter::iter::walk_tree_postfix;
386/// use par_iter::prelude::*;
387///
388/// let par_iter = walk_tree_postfix(4, |&e| {
389///     if e <= 2 {
390///         Vec::new()
391///     } else {
392///         vec![e / 2, e / 2 + 1]
393///     }
394/// });
395/// assert_eq!(par_iter.sum::<u32>(), 12);
396/// ```
397///
398/// # Example
399///
400/// ```
401/// use par_iter::prelude::*;
402/// use par_iter::iter::walk_tree_postfix;
403///
404/// struct Node {
405///     content: u32,
406///     left: Option<Box<Node>>,
407///     right: Option<Box<Node>>,
408/// }
409///
410/// // Here we loop on the following tree:
411/// //
412/// //       10
413/// //      /  \
414/// //     /    \
415/// //    3     14
416/// //            \
417/// //             \
418/// //              18
419///
420/// let root = Node {
421///     content: 10,
422///     left: Some(Box::new(Node {
423///         content: 3,
424///         left: None,
425///         right: None,
426///     })),
427///     right: Some(Box::new(Node {
428///         content: 14,
429///         left: None,
430///         right: Some(Box::new(Node {
431///             content: 18,
432///             left: None,
433///             right: None,
434///         })),
435///     })),
436/// };
437///
438/// let mut v: Vec<u32> = walk_tree_postfix(&root, |r| {
439///     r.left
440///         .as_ref()
441///         .into_iter()
442///         .chain(r.right.as_ref())
443///         .map(|n| &**n)
444/// })
445/// .map(|node| node.content)
446/// .collect();
447/// assert_eq!(v, vec![3, 18, 14, 10]);
448/// ```
449pub fn walk_tree_postfix<S, B, I>(root: S, children_of: B) -> WalkTreePostfix<S, B>
450where
451    S: Send,
452    B: Fn(&S) -> I + Send + Sync,
453    I: IntoIterator<Item = S>,
454{
455    WalkTreePostfix {
456        initial_state: root,
457        children_of,
458    }
459}
460
461/// ParallelIterator for arbitrary tree-shaped patterns.
462/// Returned by the [`walk_tree()`] function.
463#[derive(Debug)]
464pub struct WalkTree<S, B>(WalkTreePostfix<S, B>);
465
466/// Create a tree like parallel iterator from an initial root node.
467/// The `children_of` function should take a node and iterate on all of its
468/// child nodes. The best parallelization is obtained when the tree is balanced
469/// but we should also be able to handle harder cases.
470///
471/// # Ordering
472///
473/// This function does not guarantee any ordering but will
474/// use whatever algorithm is thought to achieve the fastest traversal.
475/// See also [`walk_tree_prefix`] which guarantees a
476/// prefix order and [`walk_tree_postfix`] which guarantees a postfix order.
477///
478/// # Example
479///
480/// ```text
481///      4
482///     / \
483///    /   \
484///   2     3
485///        / \
486///       1   2
487/// ```
488///
489/// ```
490/// use par_iter::iter::walk_tree;
491/// use par_iter::prelude::*;
492///
493/// let par_iter = walk_tree(4, |&e| {
494///     if e <= 2 {
495///         Vec::new()
496///     } else {
497///         vec![e / 2, e / 2 + 1]
498///     }
499/// });
500/// assert_eq!(par_iter.sum::<u32>(), 12);
501/// ```
502pub fn walk_tree<S, B, I>(root: S, children_of: B) -> WalkTree<S, B>
503where
504    S: Send,
505    B: Fn(&S) -> I + Send + Sync,
506    I: IntoIterator<Item = S>,
507    I::IntoIter: DoubleEndedIterator,
508{
509    let walker = WalkTreePostfix {
510        initial_state: root,
511        children_of,
512    };
513    WalkTree(walker)
514}
515
516impl<S, B, I> ParallelIterator for WalkTree<S, B>
517where
518    S: Send,
519    B: Fn(&S) -> I + Send + Sync,
520    I: IntoIterator<Item = S> + Send,
521    I::IntoIter: DoubleEndedIterator,
522{
523    type Item = S;
524
525    fn drive_unindexed<C>(self, consumer: C) -> C::Result
526    where
527        C: UnindexedConsumer<Self::Item>,
528    {
529        self.0.drive_unindexed(consumer)
530    }
531}