use std::collections::HashMap;
use crate::graph::{self};
pub struct FilterMap<
'g,
BaseNodeWeight,
BaseEdgeWeight,
NodeWeight,
EdgeWeight,
Graph: graph::Graph<BaseNodeWeight, BaseEdgeWeight>,
> {
base_graph: &'g Graph,
node_map: HashMap<Graph::NodeRef, NodeWeight>,
edge_map: HashMap<Graph::EdgeRef, EdgeWeight>,
}
impl<
'g,
BaseNodeWeight,
BaseEdgeWeight,
NodeWeight,
EdgeWeight,
Graph: graph::Graph<BaseNodeWeight, BaseEdgeWeight>,
> FilterMap<'g, BaseNodeWeight, BaseEdgeWeight, NodeWeight, EdgeWeight, Graph>
{
pub fn new(
base_graph: &'g Graph,
node_map: HashMap<Graph::NodeRef, NodeWeight>,
edge_map: HashMap<Graph::EdgeRef, EdgeWeight>,
) -> Self {
assert!(edge_map.keys().all(|edge| {
let (a, b) = base_graph.adjacent_nodes(*edge);
node_map.contains_key(&a) && node_map.contains_key(&b)
}));
Self {
base_graph,
node_map,
edge_map,
}
}
pub fn general_filter_map<NodeFn, EdgeFn>(
base_graph: &'g Graph,
node_fn: NodeFn,
edge_fn: EdgeFn,
) -> Self
where
NodeFn: Fn(&'g Graph, Graph::NodeRef) -> Option<NodeWeight>,
EdgeFn: Fn(&'g Graph, Graph::EdgeRef) -> Option<EdgeWeight>,
{
let node_map: HashMap<Graph::NodeRef, NodeWeight> = base_graph
.nodes()
.filter_map(|n| {
let weight = node_fn(base_graph, n)?;
Some((n, weight))
})
.collect();
let edge_map: HashMap<Graph::EdgeRef, EdgeWeight> = base_graph
.edges()
.filter(|e| {
let (a, b) = base_graph.adjacent_nodes(*e);
node_map.contains_key(&a) && node_map.contains_key(&b)
})
.filter_map(|e| {
let weight = edge_fn(base_graph, e)?;
Some((e, weight))
})
.collect();
Self {
base_graph,
node_map,
edge_map,
}
}
pub fn weight_filter_map<NodeFn, EdgeFn>(
base_graph: &'g Graph,
node_fn: NodeFn,
edge_fn: EdgeFn,
) -> Self
where
NodeFn: Fn(&'g BaseNodeWeight) -> Option<NodeWeight>,
EdgeFn: Fn(&'g BaseEdgeWeight) -> Option<EdgeWeight>,
BaseNodeWeight: 'g,
BaseEdgeWeight: 'g,
{
Self::general_filter_map(
base_graph,
|_, n| node_fn(base_graph.node_weight(n)),
|_, e| edge_fn(base_graph.edge_weight(e)),
)
}
pub fn weight_map<NodeFn, EdgeFn>(
base_graph: &'g Graph,
node_fn: NodeFn,
edge_fn: EdgeFn,
) -> Self
where
NodeFn: Fn(&'g BaseNodeWeight) -> NodeWeight,
EdgeFn: Fn(&'g BaseEdgeWeight) -> EdgeWeight,
BaseNodeWeight: 'g,
BaseEdgeWeight: 'g,
{
Self::general_filter_map(
base_graph,
|_, n| Some(node_fn(base_graph.node_weight(n))),
|_, e| Some(edge_fn(base_graph.edge_weight(e))),
)
}
}
impl<'g, NodeWeight, EdgeWeight, Graph: graph::Graph<NodeWeight, EdgeWeight>>
FilterMap<'g, NodeWeight, EdgeWeight, &'g NodeWeight, &'g EdgeWeight, Graph>
{
pub fn weight_filter<NodeFn, EdgeFn>(
base_graph: &'g Graph,
node_fn: NodeFn,
edge_fn: EdgeFn,
) -> Self
where
NodeFn: Fn(&'g NodeWeight) -> bool,
EdgeFn: Fn(&'g EdgeWeight) -> bool,
NodeWeight: 'g,
EdgeWeight: 'g,
{
Self::weight_filter_map(
base_graph,
|n| {
if node_fn(n) {
Some(n)
} else {
None
}
},
|e| {
if edge_fn(e) {
Some(e)
} else {
None
}
},
)
}
}
#[macro_export]
macro_rules! filter_pattern {
($graph:expr, node_pattern: $node_pattern:pat, edge_pattern: $edge_pattern:pat) => {
FilterMap::weight_filter_map(
$graph,
|node| match node {
$node_pattern => Some(node),
_ => None,
},
|edge| match edge {
$edge_pattern => Some(edge),
_ => None,
},
)
};
($graph:expr, node_pattern: $node_pattern:pat) => {
filter_pattern!($graph, node_pattern: $node_pattern, edge_pattern: _)
};
($graph:expr, edge_pattern: $edge_pattern:pat) => {
filter_pattern!($graph, node_pattern: _, edge_pattern: $edge_pattern)
};
}
pub use filter_pattern;
impl<
'g,
BaseNodeWeight,
BaseEdgeWeight,
NodeWeight,
EdgeWeight,
Graph: graph::Graph<BaseNodeWeight, BaseEdgeWeight>,
> graph::Graph<NodeWeight, EdgeWeight>
for FilterMap<'g, BaseNodeWeight, BaseEdgeWeight, NodeWeight, EdgeWeight, Graph>
{
type NodeRef = Graph::NodeRef;
type EdgeRef = Graph::EdgeRef;
fn is_directed(&self) -> bool {
self.base_graph.is_directed()
}
fn is_directed_edge(&self, edge: Self::EdgeRef) -> bool {
assert!(self.edge_map.contains_key(&edge));
self.base_graph.is_directed_edge(edge)
}
type AdjacentEdgesIterator<'a>
= impl Iterator<Item = Graph::EdgeRef> + 'a where Self: 'a;
fn adjacent_edges(&self, node: Self::NodeRef) -> Self::AdjacentEdgesIterator<'_> {
assert!(self.node_map.contains_key(&node));
self.base_graph
.adjacent_edges(node)
.filter(|e| self.edge_map.contains_key(e))
}
type IncomingEdgesIterator<'a> = impl Iterator<Item = Graph::EdgeRef> + 'a where Self: 'a;
fn incoming_edges(&self, node: Self::NodeRef) -> Self::IncomingEdgesIterator<'_> {
assert!(self.node_map.contains_key(&node));
self.base_graph
.incoming_edges(node)
.filter(|e| self.edge_map.contains_key(e))
}
type OutgoingEdgesIterator<'a> = impl Iterator<Item = Graph::EdgeRef> + 'a where Self: 'a;
fn outgoing_edges(&self, node: Self::NodeRef) -> Self::OutgoingEdgesIterator<'_> {
assert!(self.node_map.contains_key(&node));
self.base_graph
.outgoing_edges(node)
.filter(|e| self.edge_map.contains_key(e))
}
fn adjacent_nodes(&self, edge: Self::EdgeRef) -> (Self::NodeRef, Self::NodeRef) {
assert!(self.edge_map.contains_key(&edge));
let (a, b) = self.base_graph.adjacent_nodes(edge);
assert!(self.node_map.contains_key(&a));
assert!(self.node_map.contains_key(&b));
(a, b)
}
fn node_weight(&self, node: Self::NodeRef) -> &NodeWeight {
assert!(self.node_map.contains_key(&node));
&self.node_map[&node]
}
fn edge_weight(&self, edge: Self::EdgeRef) -> &EdgeWeight {
assert!(self.edge_map.contains_key(&edge));
&self.edge_map[&edge]
}
type NodeWeightsIterator<'a> = impl Iterator<Item =&'a NodeWeight>
where
Self: 'a,
NodeWeight: 'a;
fn node_weights(&self) -> Self::NodeWeightsIterator<'_> {
self.node_map.values()
}
type EdgeWeightsIterator<'a> = impl Iterator<Item =&'a EdgeWeight>
where
Self: 'a,
EdgeWeight: 'a;
fn edge_weights(&self) -> Self::EdgeWeightsIterator<'_> {
self.edge_map.values()
}
type NodesIterator<'a> = impl Iterator<Item = Graph::NodeRef> + 'a
where
Self: 'a;
fn nodes(&self) -> Self::NodesIterator<'_> {
self.node_map.keys().copied()
}
type EdgesIterator<'a> = impl Iterator<Item = Graph::EdgeRef> + 'a
where
Self: 'a;
fn edges(&self) -> Self::EdgesIterator<'_> {
self.edge_map.keys().copied()
}
fn count_edges(&self) -> usize {
self.edge_map.len()
}
fn count_nodes(&self) -> usize {
self.node_map.len()
}
}