2014-11-26 02:17:11 +00:00
|
|
|
//! A graph module for use in dataflow, region resolution, and elsewhere.
|
|
|
|
//!
|
|
|
|
//! # Interface details
|
|
|
|
//!
|
|
|
|
//! You customize the graph by specifying a "node data" type `N` and an
|
|
|
|
//! "edge data" type `E`. You can then later gain access (mutable or
|
|
|
|
//! immutable) to these "user-data" bits. Currently, you can only add
|
|
|
|
//! nodes or edges to the graph. You cannot remove or modify them once
|
|
|
|
//! added. This could be changed if we have a need.
|
|
|
|
//!
|
|
|
|
//! # Implementation details
|
|
|
|
//!
|
|
|
|
//! The main tricky thing about this code is the way that edges are
|
|
|
|
//! stored. The edges are stored in a central array, but they are also
|
|
|
|
//! threaded onto two linked lists for each node, one for incoming edges
|
|
|
|
//! and one for outgoing edges. Note that every edge is a member of some
|
2019-02-08 13:53:55 +00:00
|
|
|
//! incoming list and some outgoing list. Basically you can load the
|
2014-11-26 02:17:11 +00:00
|
|
|
//! first index of the linked list from the node data structures (the
|
|
|
|
//! field `first_edge`) and then, for each edge, load the next index from
|
|
|
|
//! the field `next_edge`). Each of those fields is an array that should
|
|
|
|
//! be indexed by the direction (see the type `Direction`).
|
2013-05-09 15:29:17 +00:00
|
|
|
|
2019-02-08 16:36:22 +00:00
|
|
|
use crate::snapshot_vec::{SnapshotVec, SnapshotVecDelegate};
|
2019-09-26 05:30:10 +00:00
|
|
|
use rustc_index::bit_set::BitSet;
|
2017-10-09 18:09:08 +00:00
|
|
|
use std::fmt::Debug;
|
2015-04-07 10:12:13 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
2015-04-24 15:30:41 +00:00
|
|
|
mod tests;
|
2013-05-09 15:29:17 +00:00
|
|
|
|
2016-03-05 13:40:33 +00:00
|
|
|
pub struct Graph<N, E> {
|
|
|
|
nodes: SnapshotVec<Node<N>>,
|
|
|
|
edges: SnapshotVec<Edge<E>>,
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Node<N> {
|
2014-12-30 08:19:41 +00:00
|
|
|
first_edge: [EdgeIndex; 2], // see module comment
|
2014-03-28 17:05:27 +00:00
|
|
|
pub data: N,
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 18:09:08 +00:00
|
|
|
#[derive(Debug)]
|
2013-05-09 15:29:17 +00:00
|
|
|
pub struct Edge<E> {
|
2014-12-30 08:19:41 +00:00
|
|
|
next_edge: [EdgeIndex; 2], // see module comment
|
2014-03-28 17:05:27 +00:00
|
|
|
source: NodeIndex,
|
|
|
|
target: NodeIndex,
|
|
|
|
pub data: E,
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2015-04-07 10:12:13 +00:00
|
|
|
impl<N> SnapshotVecDelegate for Node<N> {
|
|
|
|
type Value = Node<N>;
|
|
|
|
type Undo = ();
|
|
|
|
|
|
|
|
fn reverse(_: &mut Vec<Node<N>>, _: ()) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<N> SnapshotVecDelegate for Edge<N> {
|
|
|
|
type Value = Edge<N>;
|
|
|
|
type Undo = ();
|
|
|
|
|
|
|
|
fn reverse(_: &mut Vec<Edge<N>>, _: ()) {}
|
|
|
|
}
|
|
|
|
|
2019-10-20 04:54:53 +00:00
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
2015-03-26 00:06:52 +00:00
|
|
|
pub struct NodeIndex(pub usize);
|
2013-05-09 15:29:17 +00:00
|
|
|
|
2019-10-20 04:54:53 +00:00
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
2015-03-26 00:06:52 +00:00
|
|
|
pub struct EdgeIndex(pub usize);
|
2015-04-07 10:12:13 +00:00
|
|
|
|
|
|
|
pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX);
|
2013-05-09 15:29:17 +00:00
|
|
|
|
|
|
|
// Use a private field here to guarantee no more instances are created:
|
2016-01-05 18:02:57 +00:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
2016-03-05 13:40:33 +00:00
|
|
|
pub struct Direction {
|
|
|
|
repr: usize,
|
|
|
|
}
|
2015-04-07 10:12:13 +00:00
|
|
|
|
|
|
|
pub const OUTGOING: Direction = Direction { repr: 0 };
|
|
|
|
|
|
|
|
pub const INCOMING: Direction = Direction { repr: 1 };
|
2013-05-09 15:29:17 +00:00
|
|
|
|
2013-11-02 01:06:31 +00:00
|
|
|
impl NodeIndex {
|
2019-02-08 13:53:55 +00:00
|
|
|
/// Returns unique ID (unique with respect to the graph holding associated node).
|
2018-08-09 15:00:14 +00:00
|
|
|
pub fn node_id(self) -> usize {
|
2016-03-05 13:40:33 +00:00
|
|
|
self.0
|
|
|
|
}
|
2013-11-02 01:06:31 +00:00
|
|
|
}
|
|
|
|
|
2016-03-05 13:40:33 +00:00
|
|
|
impl<N: Debug, E: Debug> Graph<N, E> {
|
|
|
|
pub fn new() -> Graph<N, E> {
|
2015-04-07 10:12:13 +00:00
|
|
|
Graph { nodes: SnapshotVec::new(), edges: SnapshotVec::new() }
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2017-09-15 04:28:55 +00:00
|
|
|
pub fn with_capacity(nodes: usize, edges: usize) -> Graph<N, E> {
|
|
|
|
Graph { nodes: SnapshotVec::with_capacity(nodes), edges: SnapshotVec::with_capacity(edges) }
|
|
|
|
}
|
|
|
|
|
2016-03-05 11:54:24 +00:00
|
|
|
// # Simple accessors
|
2013-05-09 15:29:17 +00:00
|
|
|
|
|
|
|
#[inline]
|
2016-02-18 01:20:41 +00:00
|
|
|
pub fn all_nodes(&self) -> &[Node<N>] {
|
2015-02-02 02:53:25 +00:00
|
|
|
&self.nodes
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 21:56:25 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn len_nodes(&self) -> usize {
|
|
|
|
self.nodes.len()
|
|
|
|
}
|
|
|
|
|
2013-05-09 15:29:17 +00:00
|
|
|
#[inline]
|
2016-02-18 01:20:41 +00:00
|
|
|
pub fn all_edges(&self) -> &[Edge<E>] {
|
2015-02-02 02:53:25 +00:00
|
|
|
&self.edges
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 21:56:25 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn len_edges(&self) -> usize {
|
|
|
|
self.edges.len()
|
|
|
|
}
|
|
|
|
|
2016-03-05 11:54:24 +00:00
|
|
|
// # Node construction
|
2013-05-09 15:29:17 +00:00
|
|
|
|
|
|
|
pub fn next_node_index(&self) -> NodeIndex {
|
|
|
|
NodeIndex(self.nodes.len())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_node(&mut self, data: N) -> NodeIndex {
|
|
|
|
let idx = self.next_node_index();
|
2015-04-07 10:12:13 +00:00
|
|
|
self.nodes.push(Node { first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], data });
|
2013-05-09 15:29:17 +00:00
|
|
|
idx
|
|
|
|
}
|
|
|
|
|
2016-02-18 01:20:41 +00:00
|
|
|
pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N {
|
2015-04-07 10:12:13 +00:00
|
|
|
&mut self.nodes[idx.0].data
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2016-02-18 01:20:41 +00:00
|
|
|
pub fn node_data(&self, idx: NodeIndex) -> &N {
|
2015-04-07 10:12:13 +00:00
|
|
|
&self.nodes[idx.0].data
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2016-02-18 01:20:41 +00:00
|
|
|
pub fn node(&self, idx: NodeIndex) -> &Node<N> {
|
2015-04-07 10:12:13 +00:00
|
|
|
&self.nodes[idx.0]
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2016-03-05 11:54:24 +00:00
|
|
|
// # Edge construction and queries
|
2013-05-09 15:29:17 +00:00
|
|
|
|
|
|
|
pub fn next_edge_index(&self) -> EdgeIndex {
|
|
|
|
EdgeIndex(self.edges.len())
|
|
|
|
}
|
|
|
|
|
2016-03-05 13:40:33 +00:00
|
|
|
pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex {
|
2015-04-07 10:12:13 +00:00
|
|
|
debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data);
|
|
|
|
|
2013-05-09 15:29:17 +00:00
|
|
|
let idx = self.next_edge_index();
|
|
|
|
|
|
|
|
// read current first of the list of edges from each node
|
2016-03-05 13:40:33 +00:00
|
|
|
let source_first = self.nodes[source.0].first_edge[OUTGOING.repr];
|
|
|
|
let target_first = self.nodes[target.0].first_edge[INCOMING.repr];
|
2013-05-09 15:29:17 +00:00
|
|
|
|
|
|
|
// create the new edge, with the previous firsts from each node
|
|
|
|
// as the next pointers
|
|
|
|
self.edges.push(Edge { next_edge: [source_first, target_first], source, target, data });
|
|
|
|
|
|
|
|
// adjust the firsts for each node target be the next object.
|
2015-04-07 10:12:13 +00:00
|
|
|
self.nodes[source.0].first_edge[OUTGOING.repr] = idx;
|
|
|
|
self.nodes[target.0].first_edge[INCOMING.repr] = idx;
|
2013-05-09 15:29:17 +00:00
|
|
|
|
2018-08-09 15:00:14 +00:00
|
|
|
idx
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2016-02-18 01:20:41 +00:00
|
|
|
pub fn edge(&self, idx: EdgeIndex) -> &Edge<E> {
|
2015-04-07 10:12:13 +00:00
|
|
|
&self.edges[idx.0]
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2016-03-05 11:54:24 +00:00
|
|
|
// # Iterating over nodes, edges
|
2013-05-09 15:29:17 +00:00
|
|
|
|
2018-03-03 15:22:07 +00:00
|
|
|
pub fn enumerated_nodes(&self) -> impl Iterator<Item = (NodeIndex, &Node<N>)> {
|
|
|
|
self.nodes.iter().enumerate().map(|(idx, n)| (NodeIndex(idx), n))
|
2016-11-02 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
2018-03-03 15:22:07 +00:00
|
|
|
pub fn enumerated_edges(&self) -> impl Iterator<Item = (EdgeIndex, &Edge<E>)> {
|
|
|
|
self.edges.iter().enumerate().map(|(idx, e)| (EdgeIndex(idx), e))
|
2016-11-02 08:35:44 +00:00
|
|
|
}
|
|
|
|
|
2018-03-03 15:24:29 +00:00
|
|
|
pub fn each_node<'a>(&'a self, mut f: impl FnMut(NodeIndex, &'a Node<N>) -> bool) -> bool {
|
2013-05-09 15:29:17 +00:00
|
|
|
//! Iterates over all edges defined in the graph.
|
2018-03-03 15:24:29 +00:00
|
|
|
self.enumerated_nodes().all(|(node_idx, node)| f(node_idx, node))
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2018-03-03 15:24:29 +00:00
|
|
|
pub fn each_edge<'a>(&'a self, mut f: impl FnMut(EdgeIndex, &'a Edge<E>) -> bool) -> bool {
|
2013-08-07 17:29:19 +00:00
|
|
|
//! Iterates over all edges defined in the graph
|
2018-03-03 15:24:29 +00:00
|
|
|
self.enumerated_edges().all(|(edge_idx, edge)| f(edge_idx, edge))
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2019-02-08 16:36:22 +00:00
|
|
|
pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges<'_, N, E> {
|
2015-04-07 10:12:13 +00:00
|
|
|
self.adjacent_edges(source, OUTGOING)
|
|
|
|
}
|
2013-05-09 15:29:17 +00:00
|
|
|
|
2019-02-08 16:36:22 +00:00
|
|
|
pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges<'_, N, E> {
|
2015-04-07 10:12:13 +00:00
|
|
|
self.adjacent_edges(source, INCOMING)
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2019-02-08 16:36:22 +00:00
|
|
|
pub fn adjacent_edges(
|
|
|
|
&self,
|
|
|
|
source: NodeIndex,
|
|
|
|
direction: Direction,
|
|
|
|
) -> AdjacentEdges<'_, N, E> {
|
2015-04-07 10:12:13 +00:00
|
|
|
let first_edge = self.node(source).first_edge[direction.repr];
|
2016-03-05 13:40:33 +00:00
|
|
|
AdjacentEdges { graph: self, direction, next: first_edge }
|
2015-04-07 10:12:13 +00:00
|
|
|
}
|
2013-05-09 15:29:17 +00:00
|
|
|
|
2021-10-15 09:24:20 +00:00
|
|
|
pub fn successor_nodes<'a>(
|
|
|
|
&'a self,
|
|
|
|
source: NodeIndex,
|
|
|
|
) -> impl Iterator<Item = NodeIndex> + 'a {
|
2015-04-07 10:12:13 +00:00
|
|
|
self.outgoing_edges(source).targets()
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2021-10-15 09:24:20 +00:00
|
|
|
pub fn predecessor_nodes<'a>(
|
|
|
|
&'a self,
|
|
|
|
target: NodeIndex,
|
|
|
|
) -> impl Iterator<Item = NodeIndex> + 'a {
|
2015-04-07 10:12:13 +00:00
|
|
|
self.incoming_edges(target).sources()
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2019-06-21 18:05:14 +00:00
|
|
|
pub fn depth_traverse(
|
|
|
|
&self,
|
2018-03-03 15:24:29 +00:00
|
|
|
start: NodeIndex,
|
|
|
|
direction: Direction,
|
2019-06-21 18:05:14 +00:00
|
|
|
) -> DepthFirstTraversal<'_, N, E> {
|
2016-08-05 23:42:41 +00:00
|
|
|
DepthFirstTraversal::with_start_node(self, start, direction)
|
2015-04-07 10:12:13 +00:00
|
|
|
}
|
2016-11-02 09:38:36 +00:00
|
|
|
|
2018-08-09 15:00:14 +00:00
|
|
|
pub fn nodes_in_postorder(
|
|
|
|
&self,
|
2018-03-03 15:24:29 +00:00
|
|
|
direction: Direction,
|
|
|
|
entry_node: NodeIndex,
|
|
|
|
) -> Vec<NodeIndex> {
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
let mut visited = BitSet::new_empty(self.len_nodes());
|
2017-08-07 12:56:43 +00:00
|
|
|
let mut stack = vec![];
|
|
|
|
let mut result = Vec::with_capacity(self.len_nodes());
|
|
|
|
let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| {
|
|
|
|
if visited.insert(node.0) {
|
|
|
|
stack.push((node, self.adjacent_edges(node, direction)));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-03-03 15:24:29 +00:00
|
|
|
for node in
|
2017-08-07 12:56:43 +00:00
|
|
|
Some(entry_node).into_iter().chain(self.enumerated_nodes().map(|(node, _)| node))
|
|
|
|
{
|
|
|
|
push_node(&mut stack, node);
|
|
|
|
while let Some((node, mut iter)) = stack.pop() {
|
|
|
|
if let Some((_, child)) = iter.next() {
|
|
|
|
let target = child.source_or_target(direction);
|
|
|
|
// the current node needs more processing, so
|
|
|
|
// add it back to the stack
|
|
|
|
stack.push((node, iter));
|
|
|
|
// and then push the new node
|
|
|
|
push_node(&mut stack, target);
|
|
|
|
} else {
|
|
|
|
result.push(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_eq!(result.len(), self.len_nodes());
|
|
|
|
result
|
|
|
|
}
|
2015-04-07 10:12:13 +00:00
|
|
|
}
|
|
|
|
|
2016-03-05 11:54:24 +00:00
|
|
|
// # Iterators
|
2015-04-07 10:12:13 +00:00
|
|
|
|
2019-02-08 16:36:22 +00:00
|
|
|
pub struct AdjacentEdges<'g, N, E> {
|
2015-04-07 10:12:13 +00:00
|
|
|
graph: &'g Graph<N, E>,
|
|
|
|
direction: Direction,
|
|
|
|
next: EdgeIndex,
|
|
|
|
}
|
|
|
|
|
2018-03-03 15:22:07 +00:00
|
|
|
impl<'g, N: Debug, E: Debug> AdjacentEdges<'g, N, E> {
|
|
|
|
fn targets(self) -> impl Iterator<Item = NodeIndex> + 'g {
|
2019-10-01 04:43:30 +00:00
|
|
|
self.map(|(_, edge)| edge.target)
|
2015-04-07 10:12:13 +00:00
|
|
|
}
|
|
|
|
|
2018-03-03 15:22:07 +00:00
|
|
|
fn sources(self) -> impl Iterator<Item = NodeIndex> + 'g {
|
2019-10-01 04:43:30 +00:00
|
|
|
self.map(|(_, edge)| edge.source)
|
2015-04-07 10:12:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-05 13:40:33 +00:00
|
|
|
impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> {
|
2015-04-07 10:12:13 +00:00
|
|
|
type Item = (EdgeIndex, &'g Edge<E>);
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<(EdgeIndex, &'g Edge<E>)> {
|
|
|
|
let edge_index = self.next;
|
|
|
|
if edge_index == INVALID_EDGE_INDEX {
|
|
|
|
return None;
|
2014-12-15 23:21:08 +00:00
|
|
|
}
|
2015-04-07 10:12:13 +00:00
|
|
|
|
|
|
|
let edge = self.graph.edge(edge_index);
|
|
|
|
self.next = edge.next_edge[self.direction.repr];
|
|
|
|
Some((edge_index, edge))
|
|
|
|
}
|
2018-03-20 09:33:59 +00:00
|
|
|
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
|
|
// At most, all the edges in the graph.
|
|
|
|
(0, Some(self.graph.len_edges()))
|
|
|
|
}
|
2015-04-07 10:12:13 +00:00
|
|
|
}
|
|
|
|
|
2019-02-08 16:36:22 +00:00
|
|
|
pub struct DepthFirstTraversal<'g, N, E> {
|
2014-12-15 23:21:08 +00:00
|
|
|
graph: &'g Graph<N, E>,
|
|
|
|
stack: Vec<NodeIndex>,
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
visited: BitSet<usize>,
|
2016-04-06 21:28:59 +00:00
|
|
|
direction: Direction,
|
2014-12-15 23:21:08 +00:00
|
|
|
}
|
|
|
|
|
2016-08-05 23:42:41 +00:00
|
|
|
impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> {
|
2018-03-03 15:24:29 +00:00
|
|
|
pub fn with_start_node(
|
|
|
|
graph: &'g Graph<N, E>,
|
|
|
|
start_node: NodeIndex,
|
|
|
|
direction: Direction,
|
|
|
|
) -> Self {
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
let mut visited = BitSet::new_empty(graph.len_nodes());
|
2016-08-05 23:42:41 +00:00
|
|
|
visited.insert(start_node.node_id());
|
|
|
|
DepthFirstTraversal { graph, stack: vec![start_node], visited, direction }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit(&mut self, node: NodeIndex) {
|
|
|
|
if self.visited.insert(node.node_id()) {
|
|
|
|
self.stack.push(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-05 13:40:33 +00:00
|
|
|
impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> {
|
2015-04-17 14:01:45 +00:00
|
|
|
type Item = NodeIndex;
|
2015-01-02 04:26:38 +00:00
|
|
|
|
2015-04-17 14:01:45 +00:00
|
|
|
fn next(&mut self) -> Option<NodeIndex> {
|
2016-08-05 23:42:41 +00:00
|
|
|
let next = self.stack.pop();
|
|
|
|
if let Some(idx) = next {
|
2016-04-06 21:28:59 +00:00
|
|
|
for (_, edge) in self.graph.adjacent_edges(idx, self.direction) {
|
|
|
|
let target = edge.source_or_target(self.direction);
|
2016-08-05 23:42:41 +00:00
|
|
|
self.visit(target);
|
2015-04-07 10:12:13 +00:00
|
|
|
}
|
2014-12-15 23:21:08 +00:00
|
|
|
}
|
2016-08-05 23:42:41 +00:00
|
|
|
next
|
2014-12-15 23:21:08 +00:00
|
|
|
}
|
2018-03-20 09:33:59 +00:00
|
|
|
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
|
|
// We will visit every node in the graph exactly once.
|
|
|
|
let remaining = self.graph.len_nodes() - self.visited.count();
|
|
|
|
(remaining, Some(remaining))
|
|
|
|
}
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
2018-03-20 09:33:59 +00:00
|
|
|
impl<'g, N: Debug, E: Debug> ExactSizeIterator for DepthFirstTraversal<'g, N, E> {}
|
|
|
|
|
2013-05-09 15:29:17 +00:00
|
|
|
impl<E> Edge<E> {
|
|
|
|
pub fn source(&self) -> NodeIndex {
|
|
|
|
self.source
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn target(&self) -> NodeIndex {
|
|
|
|
self.target
|
|
|
|
}
|
2016-01-05 18:02:57 +00:00
|
|
|
|
|
|
|
pub fn source_or_target(&self, direction: Direction) -> NodeIndex {
|
|
|
|
if direction == OUTGOING { self.target } else { self.source }
|
|
|
|
}
|
2013-05-09 15:29:17 +00:00
|
|
|
}
|