Skip to content

Commit 9d0905c

Browse files
authored
refactor(graph): make graph labels generic (alexfertel#56)
1 parent ee2ee89 commit 9d0905c

File tree

1 file changed

+155
-106
lines changed

1 file changed

+155
-106
lines changed

src/data_structures/graph.rs

Lines changed: 155 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use std::collections::{HashMap, HashSet};
1+
use std::collections::{hash_map::Entry::Vacant, HashMap, HashSet};
22
use std::fmt;
3+
use std::hash::Hash;
34

45
#[derive(Debug, Clone)]
56
pub struct NodeNotInGraph;
@@ -10,147 +11,157 @@ impl fmt::Display for NodeNotInGraph {
1011
}
1112
}
1213

13-
pub struct DirectedGraph {
14-
adjacency_table: HashMap<String, Vec<(String, i32)>>,
14+
pub struct DirectedGraph<'a, T> {
15+
adjacency_table: HashMap<&'a T, Vec<(&'a T, i32)>>,
1516
}
1617

17-
impl Graph for DirectedGraph {
18-
fn new() -> DirectedGraph {
18+
impl<'a, T> Graph<'a, T> for DirectedGraph<'a, T>
19+
where
20+
T: 'a + Eq + Hash,
21+
{
22+
fn new() -> DirectedGraph<'a, T> {
1923
DirectedGraph {
2024
adjacency_table: HashMap::new(),
2125
}
2226
}
23-
fn adjacency_table_mutable(&mut self) -> &mut HashMap<String, Vec<(String, i32)>> {
27+
fn adjacency_table_mutable(&mut self) -> &mut HashMap<&'a T, Vec<(&'a T, i32)>> {
2428
&mut self.adjacency_table
2529
}
26-
fn adjacency_table(&self) -> &HashMap<String, Vec<(String, i32)>> {
30+
fn adjacency_table(&self) -> &HashMap<&'a T, Vec<(&'a T, i32)>> {
2731
&self.adjacency_table
2832
}
2933
}
3034

31-
pub struct UndirectedGraph {
32-
adjacency_table: HashMap<String, Vec<(String, i32)>>,
35+
pub struct UndirectedGraph<'a, T> {
36+
adjacency_table: HashMap<&'a T, Vec<(&'a T, i32)>>,
3337
}
3438

35-
impl Graph for UndirectedGraph {
36-
fn new() -> UndirectedGraph {
39+
impl<'a, T> Graph<'a, T> for UndirectedGraph<'a, T>
40+
where
41+
T: 'a + Eq + Hash,
42+
{
43+
fn new() -> UndirectedGraph<'a, T> {
3744
UndirectedGraph {
3845
adjacency_table: HashMap::new(),
3946
}
4047
}
41-
fn adjacency_table_mutable(&mut self) -> &mut HashMap<String, Vec<(String, i32)>> {
48+
fn adjacency_table_mutable(&mut self) -> &mut HashMap<&'a T, Vec<(&'a T, i32)>> {
4249
&mut self.adjacency_table
4350
}
44-
fn adjacency_table(&self) -> &HashMap<String, Vec<(String, i32)>> {
51+
fn adjacency_table(&self) -> &HashMap<&'a T, Vec<(&'a T, i32)>> {
4552
&self.adjacency_table
4653
}
47-
fn add_edge(&mut self, edge: (&str, &str, i32)) {
54+
fn add_edge(&mut self, edge: (&'a T, &'a T, i32)) {
4855
self.add_node(edge.0);
4956
self.add_node(edge.1);
5057

51-
self.adjacency_table
52-
.entry(edge.0.to_string())
53-
.and_modify(|e| {
54-
e.push((edge.1.to_string(), edge.2));
55-
});
56-
self.adjacency_table
57-
.entry(edge.1.to_string())
58-
.and_modify(|e| {
59-
e.push((edge.0.to_string(), edge.2));
60-
});
58+
self.adjacency_table.entry(edge.0).and_modify(|e| {
59+
e.push((edge.1, edge.2));
60+
});
61+
self.adjacency_table.entry(edge.1).and_modify(|e| {
62+
e.push((edge.0, edge.2));
63+
});
6164
}
6265
}
6366

64-
pub trait Graph {
67+
pub trait Graph<'a, T>
68+
where
69+
T: 'a + Eq + Hash,
70+
{
6571
fn new() -> Self;
66-
fn adjacency_table_mutable(&mut self) -> &mut HashMap<String, Vec<(String, i32)>>;
67-
fn adjacency_table(&self) -> &HashMap<String, Vec<(String, i32)>>;
72+
fn adjacency_table_mutable(&mut self) -> &mut HashMap<&'a T, Vec<(&'a T, i32)>>;
73+
fn adjacency_table(&self) -> &HashMap<&'a T, Vec<(&'a T, i32)>>;
6874

69-
fn add_node(&mut self, node: &str) -> bool {
70-
match self.adjacency_table().get(node) {
71-
None => {
72-
self.adjacency_table_mutable()
73-
.insert((*node).to_string(), Vec::new());
74-
true
75-
}
76-
_ => false,
75+
fn add_node(&mut self, node: &'a T) -> bool {
76+
if let Vacant(entry) = self.adjacency_table_mutable().entry(node) {
77+
entry.insert(Vec::new());
78+
true
79+
} else {
80+
false
7781
}
7882
}
7983

80-
fn add_edge(&mut self, edge: (&str, &str, i32)) {
84+
fn add_edge(&mut self, edge: (&'a T, &'a T, i32)) {
8185
self.add_node(edge.0);
8286
self.add_node(edge.1);
8387

8488
self.adjacency_table_mutable()
85-
.entry(edge.0.to_string())
89+
.entry(edge.0)
8690
.and_modify(|e| {
87-
e.push((edge.1.to_string(), edge.2));
91+
e.push((edge.1, edge.2));
8892
});
8993
}
9094

91-
fn neighbours(&self, node: &str) -> Result<&Vec<(String, i32)>, NodeNotInGraph> {
95+
fn neighbours(&self, node: &'a T) -> Result<&Vec<(&'a T, i32)>, NodeNotInGraph> {
9296
match self.adjacency_table().get(node) {
9397
None => Err(NodeNotInGraph),
9498
Some(i) => Ok(i),
9599
}
96100
}
97101

98-
fn contains(&self, node: &str) -> bool {
102+
fn contains(&self, node: &'a T) -> bool {
99103
self.adjacency_table().get(node).is_some()
100104
}
101105

102-
fn nodes(&self) -> HashSet<&String> {
103-
self.adjacency_table().keys().collect()
106+
fn nodes(&self) -> HashSet<&'a T> {
107+
self.adjacency_table().keys().copied().collect()
104108
}
105109

106-
fn edges(&self) -> Vec<(&String, &String, i32)> {
107-
let mut edges = Vec::new();
108-
for (from_node, from_node_neighbours) in self.adjacency_table() {
109-
for (to_node, weight) in from_node_neighbours {
110-
edges.push((from_node, to_node, *weight));
111-
}
112-
}
113-
edges
110+
fn edges(&self) -> Vec<(&'a T, &'a T, i32)> {
111+
self.adjacency_table()
112+
.iter()
113+
.flat_map(|(from_node, from_node_neighbours)| {
114+
from_node_neighbours
115+
.iter()
116+
.map(move |(to_node, weight)| (*from_node, *to_node, *weight))
117+
})
118+
.collect()
114119
}
115120
}
116121

117122
#[cfg(test)]
118123
mod test_undirected_graph {
119124
use super::Graph;
120125
use super::UndirectedGraph;
126+
121127
#[test]
122128
fn test_add_edge() {
123-
let mut graph = UndirectedGraph::new();
129+
let mut graph: UndirectedGraph<String> = UndirectedGraph::new();
124130

125-
graph.add_edge(("a", "b", 5));
126-
graph.add_edge(("b", "c", 10));
127-
graph.add_edge(("c", "a", 7));
131+
let a = String::from("a");
132+
let b = String::from("b");
133+
let c = String::from("c");
134+
135+
graph.add_edge((&a, &b, 5));
136+
graph.add_edge((&b, &c, 10));
137+
graph.add_edge((&c, &a, 7));
128138

129139
let expected_edges = [
130-
(&String::from("a"), &String::from("b"), 5),
131-
(&String::from("b"), &String::from("a"), 5),
132-
(&String::from("c"), &String::from("a"), 7),
133-
(&String::from("a"), &String::from("c"), 7),
134-
(&String::from("b"), &String::from("c"), 10),
135-
(&String::from("c"), &String::from("b"), 10),
140+
(&a, &b, 5),
141+
(&b, &a, 5),
142+
(&c, &a, 7),
143+
(&a, &c, 7),
144+
(&b, &c, 10),
145+
(&c, &b, 10),
136146
];
137147
for edge in expected_edges.iter() {
138-
assert_eq!(graph.edges().contains(edge), true);
148+
assert!(graph.edges().contains(edge));
139149
}
140150
}
141151

142152
#[test]
143153
fn test_neighbours() {
144-
let mut graph = UndirectedGraph::new();
154+
let mut graph: UndirectedGraph<String> = UndirectedGraph::new();
155+
156+
let a = String::from("a");
157+
let b = String::from("b");
158+
let c = String::from("c");
145159

146-
graph.add_edge(("a", "b", 5));
147-
graph.add_edge(("b", "c", 10));
148-
graph.add_edge(("c", "a", 7));
160+
graph.add_edge((&a, &b, 5));
161+
graph.add_edge((&b, &c, 10));
162+
graph.add_edge((&c, &a, 7));
149163

150-
assert_eq!(
151-
graph.neighbours("a").unwrap(),
152-
&vec![(String::from("b"), 5), (String::from("c"), 7)]
153-
);
164+
assert_eq!(graph.neighbours(&a).unwrap(), &vec![(&b, 5), (&c, 7)]);
154165
}
155166
}
156167

@@ -161,60 +172,98 @@ mod test_directed_graph {
161172

162173
#[test]
163174
fn test_add_node() {
164-
let mut graph = DirectedGraph::new();
165-
graph.add_node("a");
166-
graph.add_node("b");
167-
graph.add_node("c");
168-
assert_eq!(
169-
graph.nodes(),
170-
[&String::from("a"), &String::from("b"), &String::from("c")]
171-
.iter()
172-
.cloned()
173-
.collect()
174-
);
175+
let mut graph: DirectedGraph<String> = DirectedGraph::new();
176+
177+
let a = String::from("a");
178+
let b = String::from("b");
179+
let c = String::from("c");
180+
181+
graph.add_node(&a);
182+
graph.add_node(&b);
183+
graph.add_node(&c);
184+
185+
assert_eq!(graph.nodes(), [&a, &b, &c].iter().cloned().collect());
186+
}
187+
188+
#[test]
189+
fn test_add_node_with_struct() {
190+
#[derive(PartialEq, Eq, Hash, Debug)]
191+
struct Node {
192+
name: String,
193+
value: i32,
194+
}
195+
196+
let mut graph: DirectedGraph<Node> = DirectedGraph::new();
197+
198+
let a = Node {
199+
name: String::from("a"),
200+
value: 1,
201+
};
202+
let b = Node {
203+
name: String::from("b"),
204+
value: 2,
205+
};
206+
let c = Node {
207+
name: String::from("c"),
208+
value: 3,
209+
};
210+
211+
graph.add_node(&a);
212+
graph.add_node(&b);
213+
graph.add_node(&c);
214+
215+
assert_eq!(graph.nodes(), [&a, &b, &c].iter().cloned().collect());
175216
}
176217

177218
#[test]
178219
fn test_add_edge() {
179-
let mut graph = DirectedGraph::new();
220+
let mut graph: DirectedGraph<String> = DirectedGraph::new();
180221

181-
graph.add_edge(("a", "b", 5));
182-
graph.add_edge(("c", "a", 7));
183-
graph.add_edge(("b", "c", 10));
222+
let a = String::from("a");
223+
let b = String::from("b");
224+
let c = String::from("c");
184225

185-
let expected_edges = [
186-
(&String::from("a"), &String::from("b"), 5),
187-
(&String::from("c"), &String::from("a"), 7),
188-
(&String::from("b"), &String::from("c"), 10),
189-
];
226+
graph.add_edge((&a, &b, 5));
227+
graph.add_edge((&c, &a, 7));
228+
graph.add_edge((&b, &c, 10));
229+
230+
let expected_edges = [(&a, &b, 5), (&c, &a, 7), (&b, &c, 10)];
190231
for edge in expected_edges.iter() {
191-
assert_eq!(graph.edges().contains(edge), true);
232+
assert!(graph.edges().contains(edge));
192233
}
193234
}
194235

195236
#[test]
196237
fn test_neighbours() {
197-
let mut graph = DirectedGraph::new();
238+
let mut graph: DirectedGraph<String> = DirectedGraph::new();
239+
240+
let a = String::from("a");
241+
let b = String::from("b");
242+
let c = String::from("c");
198243

199-
graph.add_edge(("a", "b", 5));
200-
graph.add_edge(("b", "c", 10));
201-
graph.add_edge(("c", "a", 7));
244+
graph.add_edge((&a, &b, 5));
245+
graph.add_edge((&b, &c, 10));
246+
graph.add_edge((&c, &a, 7));
202247

203-
assert_eq!(
204-
graph.neighbours("a").unwrap(),
205-
&vec![(String::from("b"), 5)]
206-
);
248+
assert_eq!(graph.neighbours(&a).unwrap(), &vec![(&b, 5)]);
207249
}
208250

209251
#[test]
210252
fn test_contains() {
211-
let mut graph = DirectedGraph::new();
212-
graph.add_node("a");
213-
graph.add_node("b");
214-
graph.add_node("c");
215-
assert_eq!(graph.contains("a"), true);
216-
assert_eq!(graph.contains("b"), true);
217-
assert_eq!(graph.contains("c"), true);
218-
assert_eq!(graph.contains("d"), false);
253+
let mut graph: DirectedGraph<String> = DirectedGraph::new();
254+
255+
let a = String::from("a");
256+
let b = String::from("b");
257+
let c = String::from("c");
258+
let d = String::from("d");
259+
260+
graph.add_node(&a);
261+
graph.add_node(&b);
262+
graph.add_node(&c);
263+
264+
assert!(graph.contains(&a));
265+
assert!(graph.contains(&b));
266+
assert!(graph.contains(&c));
267+
assert!(!graph.contains(&d));
219268
}
220269
}

0 commit comments

Comments
 (0)