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}