blob: 02459e1f7f281684da0e322e6219900a69a96e18 [file] [log] [blame]
Brian Silverman4e662aa2022-05-11 23:10:19 -07001// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use indexmap::set::IndexSet as HashSet;
10use std::collections::VecDeque;
11use std::fmt::Debug;
12
13use itertools::Itertools;
14
15use crate::types::QualifiedName;
16
17use super::deps::HasDependencies;
18
19/// Return APIs in a depth-first order, i.e. those with no dependencies first.
20pub(super) fn depth_first<'a, T: HasDependencies + Debug + 'a>(
21 inputs: impl Iterator<Item = &'a T> + 'a,
22) -> impl Iterator<Item = &'a T> {
23 let queue: VecDeque<_> = inputs.collect();
24 let yet_to_do = queue.iter().map(|api| api.name()).collect();
25 DepthFirstIter { queue, yet_to_do }
26}
27
28struct DepthFirstIter<'a, T: HasDependencies + Debug> {
29 queue: VecDeque<&'a T>,
30 yet_to_do: HashSet<&'a QualifiedName>,
31}
32
33impl<'a, T: HasDependencies + Debug> Iterator for DepthFirstIter<'a, T> {
34 type Item = &'a T;
35
36 fn next(&mut self) -> Option<Self::Item> {
37 let first_candidate = self.queue.get(0).map(|api| api.name());
38 while let Some(candidate) = self.queue.pop_front() {
39 if !candidate.deps().any(|d| self.yet_to_do.contains(&d)) {
40 self.yet_to_do.remove(candidate.name());
41 return Some(candidate);
42 }
43 self.queue.push_back(candidate);
44 if self.queue.get(0).map(|api| api.name()) == first_candidate {
45 panic!(
46 "Failed to find a candidate; there must be a circular dependency. Queue is {}",
47 self.queue
48 .iter()
49 .map(|item| format!("{}: {}", item.name(), item.deps().join(",")))
50 .join("\n")
51 );
52 }
53 }
54 None
55 }
56}
57
58#[cfg(test)]
59mod test {
60 use crate::types::QualifiedName;
61
62 use super::{depth_first, HasDependencies};
63
64 #[derive(Debug)]
65 struct Thing(QualifiedName, Vec<QualifiedName>);
66
67 impl HasDependencies for Thing {
68 fn name(&self) -> &QualifiedName {
69 &self.0
70 }
71
72 fn deps(&self) -> Box<dyn Iterator<Item = &QualifiedName> + '_> {
73 Box::new(self.1.iter())
74 }
75 }
76
77 #[test]
78 fn test() {
79 let a = Thing(QualifiedName::new_from_cpp_name("a"), vec![]);
80 let b = Thing(
81 QualifiedName::new_from_cpp_name("b"),
82 vec![
83 QualifiedName::new_from_cpp_name("a"),
84 QualifiedName::new_from_cpp_name("c"),
85 ],
86 );
87 let c = Thing(
88 QualifiedName::new_from_cpp_name("c"),
89 vec![QualifiedName::new_from_cpp_name("a")],
90 );
91 let api_list = vec![a, b, c];
92 let mut it = depth_first(api_list.iter());
93 assert_eq!(it.next().unwrap().0, QualifiedName::new_from_cpp_name("a"));
94 assert_eq!(it.next().unwrap().0, QualifiedName::new_from_cpp_name("c"));
95 assert_eq!(it.next().unwrap().0, QualifiedName::new_from_cpp_name("b"));
96 assert!(it.next().is_none());
97 }
98}