1use crate::core::id::{Eid, Vid};
13use fxhash::FxBuildHasher;
14use std::collections::HashMap;
15
16#[derive(Clone, Copy, Debug)]
20pub struct EdgeEntry {
21 pub eid: Eid,
22 pub src_vid: Vid,
23 pub dst_vid: Vid,
24 pub edge_type: u32,
25}
26
27type FxHashMap<K, V> = HashMap<K, V, FxBuildHasher>;
29
30#[derive(Debug)]
35pub struct SimpleGraph {
36 vertices: FxHashMap<Vid, ()>,
38 outgoing: FxHashMap<Vid, Vec<EdgeEntry>>,
40 incoming: FxHashMap<Vid, Vec<EdgeEntry>>,
42 edge_map: FxHashMap<Eid, EdgeEntry>,
44}
45
46#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub enum Direction {
49 Outgoing,
50 Incoming,
51}
52
53impl Default for SimpleGraph {
54 fn default() -> Self {
55 Self {
56 vertices: HashMap::with_hasher(FxBuildHasher::default()),
57 outgoing: HashMap::with_hasher(FxBuildHasher::default()),
58 incoming: HashMap::with_hasher(FxBuildHasher::default()),
59 edge_map: HashMap::with_hasher(FxBuildHasher::default()),
60 }
61 }
62}
63
64impl SimpleGraph {
65 pub fn new() -> Self {
67 Self::default()
68 }
69
70 pub fn with_capacity(vertices: usize, edges: usize) -> Self {
72 Self {
73 vertices: HashMap::with_capacity_and_hasher(vertices, FxBuildHasher::default()),
74 outgoing: HashMap::with_capacity_and_hasher(vertices, FxBuildHasher::default()),
75 incoming: HashMap::with_capacity_and_hasher(vertices, FxBuildHasher::default()),
76 edge_map: HashMap::with_capacity_and_hasher(edges, FxBuildHasher::default()),
77 }
78 }
79
80 pub fn add_vertex(&mut self, vid: Vid) -> bool {
82 if self.vertices.contains_key(&vid) {
83 return false;
84 }
85 self.vertices.insert(vid, ());
86 true
87 }
88
89 pub fn remove_vertex(&mut self, vid: Vid) {
91 self.vertices.remove(&vid);
92
93 if let Some(edges) = self.outgoing.remove(&vid) {
95 for edge in edges {
97 self.edge_map.remove(&edge.eid);
98 if let Some(incoming_list) = self.incoming.get_mut(&edge.dst_vid) {
99 incoming_list.retain(|e| e.eid != edge.eid);
100 }
101 }
102 }
103
104 if let Some(edges) = self.incoming.remove(&vid) {
106 for edge in edges {
108 self.edge_map.remove(&edge.eid);
109 if let Some(outgoing_list) = self.outgoing.get_mut(&edge.src_vid) {
110 outgoing_list.retain(|e| e.eid != edge.eid);
111 }
112 }
113 }
114 }
115
116 pub fn contains_vertex(&self, vid: Vid) -> bool {
118 self.vertices.contains_key(&vid)
119 }
120
121 pub fn vertex_count(&self) -> usize {
123 self.vertices.len()
124 }
125
126 pub fn add_edge(&mut self, src_vid: Vid, dst_vid: Vid, eid: Eid, edge_type: u32) {
128 self.add_vertex(src_vid);
130 self.add_vertex(dst_vid);
131
132 self.add_edge_unchecked(src_vid, dst_vid, eid, edge_type);
133 }
134
135 #[inline]
137 pub fn add_edge_unchecked(&mut self, src_vid: Vid, dst_vid: Vid, eid: Eid, edge_type: u32) {
138 let entry = EdgeEntry {
139 eid,
140 src_vid,
141 dst_vid,
142 edge_type,
143 };
144
145 self.outgoing.entry(src_vid).or_default().push(entry);
147
148 self.incoming.entry(dst_vid).or_default().push(entry);
150
151 self.edge_map.insert(eid, entry);
153 }
154
155 pub fn remove_edge(&mut self, eid: Eid) -> Option<EdgeEntry> {
159 let entry = self.edge_map.remove(&eid)?;
161
162 if let Some(outgoing_list) = self.outgoing.get_mut(&entry.src_vid) {
164 outgoing_list.retain(|e| e.eid != eid);
165 }
166
167 if let Some(incoming_list) = self.incoming.get_mut(&entry.dst_vid) {
169 incoming_list.retain(|e| e.eid != eid);
170 }
171
172 Some(entry)
173 }
174
175 pub fn neighbors(&self, vid: Vid, direction: Direction) -> &[EdgeEntry] {
178 let map = match direction {
179 Direction::Outgoing => &self.outgoing,
180 Direction::Incoming => &self.incoming,
181 };
182 map.get(&vid).map(|v| v.as_slice()).unwrap_or(&[])
183 }
184
185 pub fn edges(&self) -> impl Iterator<Item = &EdgeEntry> {
187 self.outgoing.values().flat_map(|v| v.iter())
188 }
189
190 pub fn edge(&self, eid: Eid) -> Option<&EdgeEntry> {
192 self.edge_map.get(&eid)
193 }
194
195 pub fn vertex(&self, vid: Vid) -> Option<Vid> {
197 if self.vertices.contains_key(&vid) {
198 Some(vid)
199 } else {
200 None
201 }
202 }
203
204 pub fn edge_count(&self) -> usize {
206 self.outgoing.values().map(|v| v.len()).sum()
207 }
208
209 pub fn vertices(&self) -> impl Iterator<Item = Vid> + '_ {
211 self.vertices.keys().copied()
212 }
213
214 pub fn clear(&mut self) {
216 self.vertices.clear();
217 self.outgoing.clear();
218 self.incoming.clear();
219 self.edge_map.clear();
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226
227 #[test]
228 fn test_add_remove_vertex() {
229 let mut g = SimpleGraph::new();
230 let v1 = Vid::new(1);
231 let v2 = Vid::new(2);
232
233 assert!(g.add_vertex(v1));
234 assert!(!g.add_vertex(v1)); assert!(g.add_vertex(v2));
236
237 assert_eq!(g.vertex_count(), 2);
238 assert!(g.contains_vertex(v1));
239
240 g.remove_vertex(v1);
241 assert_eq!(g.vertex_count(), 1);
242 assert!(!g.contains_vertex(v1));
243 }
244
245 #[test]
246 fn test_add_remove_edge() {
247 let mut g = SimpleGraph::new();
248 let v1 = Vid::new(1);
249 let v2 = Vid::new(2);
250 let v3 = Vid::new(3);
251 let e1 = Eid::new(101);
252 let e2 = Eid::new(102);
253
254 g.add_edge(v1, v2, e1, 1);
255 g.add_edge(v1, v3, e2, 1);
256
257 assert_eq!(g.edge_count(), 2);
258
259 let out = g.neighbors(v1, Direction::Outgoing);
261 assert_eq!(out.len(), 2);
262
263 let inc = g.neighbors(v2, Direction::Incoming);
265 assert_eq!(inc.len(), 1);
266 assert_eq!(inc[0].src_vid, v1);
267
268 let removed = g.remove_edge(e1);
270 assert!(removed.is_some());
271 assert_eq!(removed.unwrap().dst_vid, v2);
272
273 assert_eq!(g.edge_count(), 1);
274 assert_eq!(g.neighbors(v1, Direction::Outgoing).len(), 1);
275 assert_eq!(g.neighbors(v2, Direction::Incoming).len(), 0);
276 }
277
278 #[test]
279 fn test_remove_vertex_with_edges() {
280 let mut g = SimpleGraph::new();
281 let v1 = Vid::new(1);
282 let v2 = Vid::new(2);
283 let v3 = Vid::new(3);
284 let e1 = Eid::new(101);
285 let e2 = Eid::new(102);
286
287 g.add_edge(v1, v2, e1, 1);
288 g.add_edge(v2, v3, e2, 1);
289
290 g.remove_vertex(v2);
292
293 assert_eq!(g.vertex_count(), 2);
294 assert_eq!(g.edge_count(), 0);
295 assert_eq!(g.neighbors(v1, Direction::Outgoing).len(), 0);
296 assert_eq!(g.neighbors(v3, Direction::Incoming).len(), 0);
297 }
298
299 #[test]
300 fn test_edge_iteration() {
301 let mut g = SimpleGraph::new();
302 let v1 = Vid::new(1);
303 let v2 = Vid::new(2);
304 let v3 = Vid::new(3);
305 let e1 = Eid::new(101);
306 let e2 = Eid::new(102);
307
308 g.add_edge(v1, v2, e1, 1);
309 g.add_edge(v2, v3, e2, 2);
310
311 let edges: Vec<_> = g.edges().collect();
312 assert_eq!(edges.len(), 2);
313 }
314
315 #[test]
316 fn test_neighbor_iteration_after_deletion() {
317 let mut g = SimpleGraph::new();
319 let v1 = Vid::new(1);
320 let v2 = Vid::new(2);
321 let v3 = Vid::new(3);
322 let e1 = Eid::new(101);
323 let e2 = Eid::new(102);
324
325 g.add_edge(v1, v2, e1, 1);
326 g.add_edge(v1, v3, e2, 1);
327
328 g.remove_edge(e1);
330
331 let neighbors = g.neighbors(v1, Direction::Outgoing);
333 assert_eq!(neighbors.len(), 1);
334 assert_eq!(neighbors[0].dst_vid, v3);
335 }
336
337 #[test]
338 fn test_edge_lookup_o1() {
339 let mut g = SimpleGraph::new();
341 let v1 = Vid::new(1);
342 let v2 = Vid::new(2);
343 let v3 = Vid::new(3);
344 let e1 = Eid::new(101);
345 let e2 = Eid::new(102);
346
347 g.add_edge(v1, v2, e1, 1);
348 g.add_edge(v2, v3, e2, 2);
349
350 let edge = g.edge(e1);
352 assert!(edge.is_some());
353 let edge = edge.unwrap();
354 assert_eq!(edge.src_vid, v1);
355 assert_eq!(edge.dst_vid, v2);
356 assert_eq!(edge.edge_type, 1);
357
358 let non_existent = Eid::new(999);
360 assert!(g.edge(non_existent).is_none());
361
362 g.remove_edge(e1);
364 assert!(g.edge(e1).is_none());
365 assert!(g.edge(e2).is_some()); }
367}