1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use rustc_data_structures
::fnv
::{FnvHashMap, FnvHashSet}
;
14 use super::{DepGraphQuery, DepNode}
;
16 pub struct DepGraphEdges
<D
: Clone
+ Debug
+ Eq
+ Hash
> {
17 nodes
: Vec
<DepNode
<D
>>,
18 indices
: FnvHashMap
<DepNode
<D
>, IdIndex
>,
19 edges
: FnvHashSet
<(IdIndex
, IdIndex
)>,
20 open_nodes
: Vec
<OpenNode
>,
23 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
29 fn new(v
: usize) -> IdIndex
{
30 assert
!((v
& 0xFFFF_FFFF) == v
);
31 IdIndex { index: v as u32 }
34 fn index(self) -> usize {
39 #[derive(Clone, Debug, PartialEq)]
45 impl<D
: Clone
+ Debug
+ Eq
+ Hash
> DepGraphEdges
<D
> {
46 pub fn new() -> DepGraphEdges
<D
> {
49 indices
: FnvHashMap(),
51 open_nodes
: Vec
::new()
55 fn id(&self, index
: IdIndex
) -> DepNode
<D
> {
56 self.nodes
[index
.index()].clone()
59 /// Creates a node for `id` in the graph.
60 fn make_node(&mut self, id
: DepNode
<D
>) -> IdIndex
{
61 if let Some(&i
) = self.indices
.get(&id
) {
65 let index
= IdIndex
::new(self.nodes
.len());
66 self.nodes
.push(id
.clone());
67 self.indices
.insert(id
, index
);
71 /// Top of the stack of open nodes.
72 fn current_node(&self) -> Option
<OpenNode
> {
73 self.open_nodes
.last().cloned()
76 pub fn push_ignore(&mut self) {
77 self.open_nodes
.push(OpenNode
::Ignore
);
80 pub fn pop_ignore(&mut self) {
81 let popped_node
= self.open_nodes
.pop().unwrap();
82 assert_eq
!(popped_node
, OpenNode
::Ignore
);
85 pub fn push_task(&mut self, key
: DepNode
<D
>) {
86 let top_node
= self.current_node();
88 let new_node
= self.make_node(key
);
89 self.open_nodes
.push(OpenNode
::Node(new_node
));
91 // if we are in the midst of doing task T, then this new task
92 // N is a subtask of T, so add an edge N -> T.
93 if let Some(top_node
) = top_node
{
94 self.add_edge_from_open_node(top_node
, |t
| (new_node
, t
));
98 pub fn pop_task(&mut self, key
: DepNode
<D
>) {
99 let popped_node
= self.open_nodes
.pop().unwrap();
100 assert_eq
!(OpenNode
::Node(self.indices
[&key
]), popped_node
);
103 /// Indicates that the current task `C` reads `v` by adding an
104 /// edge from `v` to `C`. If there is no current task, panics. If
105 /// you want to suppress this edge, use `ignore`.
106 pub fn read(&mut self, v
: DepNode
<D
>) {
107 let source
= self.make_node(v
);
108 self.add_edge_from_current_node(|current
| (source
, current
))
111 /// Indicates that the current task `C` writes `v` by adding an
112 /// edge from `C` to `v`. If there is no current task, panics. If
113 /// you want to suppress this edge, use `ignore`.
114 pub fn write(&mut self, v
: DepNode
<D
>) {
115 let target
= self.make_node(v
);
116 self.add_edge_from_current_node(|current
| (current
, target
))
119 /// Invoke `add_edge_from_open_node` with the top of the stack, or
120 /// panic if stack is empty.
121 fn add_edge_from_current_node
<OP
>(&mut self,
123 where OP
: FnOnce(IdIndex
) -> (IdIndex
, IdIndex
)
125 match self.current_node() {
126 Some(open_node
) => self.add_edge_from_open_node(open_node
, op
),
127 None
=> bug
!("no current node, cannot add edge into dependency graph")
131 /// Adds an edge to or from the `open_node`, assuming `open_node`
132 /// is not `Ignore`. The direction of the edge is determined by
133 /// the closure `op` --- we pass as argument the open node `n`,
134 /// and the closure returns a (source, target) tuple, which should
135 /// include `n` in one spot or another.
136 fn add_edge_from_open_node
<OP
>(&mut self,
139 where OP
: FnOnce(IdIndex
) -> (IdIndex
, IdIndex
)
141 let (source
, target
) = match open_node
{
142 OpenNode
::Node(n
) => op(n
),
143 OpenNode
::Ignore
=> { return; }
146 // ignore trivial self edges, which are not very interesting
147 if source
== target
{
151 if self.edges
.insert((source
, target
)) {
152 debug
!("adding edge from {:?} to {:?}",
158 pub fn query(&self) -> DepGraphQuery
<D
> {
159 let edges
: Vec
<_
> = self.edges
.iter()
160 .map(|&(i
, j
)| (self.id(i
), self.id(j
)))
162 DepGraphQuery
::new(&self.nodes
, &edges
)