evmil/util/digraph.rs
1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12use crate::util::{Seq,SortedVec};
13
14pub type EdgeSet = SortedVec<usize>;
15
16/// Represents a _bidirectional_ directed graph over a sequence of
17/// _nodes_. Edges can be added/removed, and iterated over in the
18/// _forwards_ or _backwards_ direction. The underlying datastructure
19/// is that of an adjacency list.
20pub struct Digraph<T>
21where T:Seq {
22 /// Node sequence underlying this representation.
23 nodes: T,
24 /// For each block, the corresponding set of incoming edges
25 /// (i.e. edges which transfer control into this block).
26 incoming: Vec<EdgeSet>,
27 /// For each block, the corresponding set of outgoing edges
28 /// (i.e. edges which transfer control out of this block).
29 outgoing: Vec<EdgeSet>
30}
31
32impl<T> Digraph<T>
33where T:Seq {
34 pub fn new(n: usize, nodes: T) -> Self {
35 let incoming = vec![SortedVec::new();n];
36 let outgoing = vec![SortedVec::new();n];
37 Self{nodes,incoming,outgoing}
38 }
39
40 /// Returns the number of nodes stored within this graph.
41 pub fn len(&self) -> usize {
42 self.nodes.len()
43 }
44
45 /// Returns `true` if the node set for this graph is empty.
46 pub fn is_empty(&self) -> bool {
47 self.nodes.is_empty()
48 }
49
50 /// Returns `true` if there is an edge from node `from` to node
51 /// `to`.
52 pub fn is_connected(&self, from: usize, to: usize) -> bool {
53 self.outgoing[from].contains(to)
54 }
55
56 /// Returns the ith block within this graph.
57 pub fn get(&self, index: usize) -> T::Output {
58 self.nodes.get(index).unwrap()
59 }
60
61 /// Get the underlying nodes of this graph (in whatever form they
62 /// are provided).
63 pub fn nodes(&self) -> &T {
64 &self.nodes
65 }
66
67 /// Returns the set of blocks which can transfer control _into_ a
68 /// given block (`blk`).
69 pub fn incoming(&self, blk: usize) -> &EdgeSet {
70 &self.incoming[blk]
71 }
72
73 /// Returns the set of blocks to which a given block (`blk`) can
74 /// transfer control.
75 pub fn outgoing(&self, blk: usize) -> &EdgeSet {
76 &self.outgoing[blk]
77 }
78
79 /// Returns an iterator over the _outgoing edges_ in this graph
80 pub fn out_iter(&self) -> DigraphIterator {
81 DigraphIterator::new(true,&self.outgoing)
82 }
83
84 /// Returns an iterator over the _incoming edges_ in this graph
85 pub fn in_iter(&self) -> DigraphIterator {
86 DigraphIterator::new(false,&self.incoming)
87 }
88
89 /// Connect one basic block to another which forms a directed edge
90 /// in the graph. Returns `true` if a connection was added.
91 pub fn connect(&mut self, from: usize, to: usize) -> bool {
92 self.incoming[to].insert(from);
93 self.outgoing[from].insert(to)
94 }
95
96 /// Remove a connection between two basic blocks from the graph.
97 /// Returns `true` if a connection was removed.
98 pub fn disconnect(&mut self, from: usize, to: usize) -> bool {
99 self.incoming[to].remove(&from);
100 self.outgoing[from].remove(&to)
101 }
102}
103
104/// An iterator over the edges of a graph which iterates over the
105/// incoming or outgoing edges of the graph.
106pub struct DigraphIterator<'a> {
107 // Direction of edges which is either `true` (i.e. outgoing) or
108 // `false` (i.e. incoming).
109 dir: bool,
110 // Edge sets being iterated over.
111 items: &'a [EdgeSet],
112 // Current edgeset being considered.
113 i: usize,
114 // Current position within edgeset being considered.
115 j: usize
116}
117
118impl<'a> DigraphIterator<'a> {
119 pub fn new(dir: bool, items: &'a [EdgeSet]) -> Self {
120 Self{dir,items,i:0,j:0}
121 }
122}
123
124impl<'a> Iterator for DigraphIterator<'a> {
125 // An edge
126 type Item = (usize,usize);
127
128 fn next(&mut self) -> Option<Self::Item> {
129 //
130 while self.i < self.items.len() {
131 let head = &self.items[self.i];
132 // sanity check position
133 if self.j >= head.len() {
134 self.j = 0;
135 self.i += 1;
136 } else {
137 // Found an edge
138 let k = head[self.j];
139 self.j += 1;
140 // Construct edge
141 let edge = if self.dir { (self.i,k) } else { (k,self.i) };
142 // Done
143 return Some(edge);
144 }
145 }
146 // Empty
147 None
148 }
149}