From 1a3cbba9011bcae2fe72abe4f398977cab998b90 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 8 Jan 2023 19:06:35 +0100 Subject: [PATCH 001/183] Add AdjacencyMapGraph for `bevy_graph` --- crates/bevy_graph/Cargo.toml | 13 +++++ crates/bevy_graph/src/graphs/map.rs | 79 +++++++++++++++++++++++++++++ crates/bevy_graph/src/graphs/mod.rs | 5 ++ crates/bevy_graph/src/lib.rs | 1 + 4 files changed, 98 insertions(+) create mode 100644 crates/bevy_graph/Cargo.toml create mode 100644 crates/bevy_graph/src/graphs/map.rs create mode 100644 crates/bevy_graph/src/graphs/mod.rs create mode 100644 crates/bevy_graph/src/lib.rs diff --git a/crates/bevy_graph/Cargo.toml b/crates/bevy_graph/Cargo.toml new file mode 100644 index 0000000000000..a1337c7bcb97e --- /dev/null +++ b/crates/bevy_graph/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "bevy_graph" +version = "0.9.0" +edition = "2021" +description = "Bevy Engine Graph Structure" +homepage = "https://bevyengine.org" +repository = "https://github.com/bevyengine/bevy" +license = "MIT OR Apache-2.0" +keywords = ["bevy"] + +[dependencies] +hashbrown = "0.13.1" +slotmap = "1.0.6" diff --git a/crates/bevy_graph/src/graphs/map.rs b/crates/bevy_graph/src/graphs/map.rs new file mode 100644 index 0000000000000..46ff665d397be --- /dev/null +++ b/crates/bevy_graph/src/graphs/map.rs @@ -0,0 +1,79 @@ +use hashbrown::HashMap; +use slotmap::SlotMap; + +use super::{EdgeIdx, NodeIdx}; + +pub struct AdjacencyMapGraph { + nodes: SlotMap, + edges: SlotMap, + adjacencies: HashMap>, +} + +impl AdjacencyMapGraph { + pub fn new() -> Self { + Self { + nodes: SlotMap::new(), + edges: SlotMap::new(), + adjacencies: HashMap::new(), + } + } + + pub fn add_node(&mut self, node: N) -> NodeIdx { + let idx = self.nodes.insert(node); + self.adjacencies.insert(idx, HashMap::new()); + idx + } + + pub fn add_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(edge); + self.adjacencies.get_mut(&from).unwrap().insert(to, idx); + idx // TODO: does the end user really need the idx? + } + + #[inline] + pub fn node(&self, idx: NodeIdx) -> Option<&N> { + self.nodes.get(idx) + } + + #[inline] + pub fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N> { + self.nodes.get_mut(idx) + } + + #[inline] + pub fn edge(&self, from: NodeIdx, to: NodeIdx) -> Option<&E> { + let edge_idx = self.adjacencies.get(&from)?.get(&to)?; + self.edges.get(*edge_idx) + } + + #[inline] + pub fn edge_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E> { + let edge_idx = self.adjacencies.get(&from)?.get(&to)?; + self.edges.get_mut(*edge_idx) + } +} + +#[cfg(test)] +mod test { + use super::AdjacencyMapGraph; + + enum Person { + Jake, + Michael, + } + + #[test] + fn get_edge() { + const STRENGTH: i32 = 100; + + let mut map_graph = AdjacencyMapGraph::::new(); + + let jake = map_graph.add_node(Person::Jake); + let michael = map_graph.add_node(Person::Michael); + let _best_friends = map_graph.add_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? + + let stength = map_graph.edge(jake, michael); + assert!(stength.is_some()); + assert_eq!(stength.unwrap(), &STRENGTH); + } +} diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs new file mode 100644 index 0000000000000..8b57a8c64d3ad --- /dev/null +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -0,0 +1,5 @@ +pub type NodeIdx = slotmap::DefaultKey; +pub type EdgeIdx = slotmap::DefaultKey; + +mod map; +pub use map::*; diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs new file mode 100644 index 0000000000000..010ff385ddac3 --- /dev/null +++ b/crates/bevy_graph/src/lib.rs @@ -0,0 +1 @@ +pub mod graphs; From b091e36fc99113b1d1d49134b2821a919c25b2fe Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 8 Jan 2023 19:18:49 +0100 Subject: [PATCH 002/183] Make the CI happy :D and add Default trait --- crates/bevy_graph/src/graphs/map.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/bevy_graph/src/graphs/map.rs b/crates/bevy_graph/src/graphs/map.rs index 46ff665d397be..82fabb8f8913f 100644 --- a/crates/bevy_graph/src/graphs/map.rs +++ b/crates/bevy_graph/src/graphs/map.rs @@ -53,6 +53,13 @@ impl AdjacencyMapGraph { } } +impl Default for AdjacencyMapGraph { + #[inline] + fn default() -> Self { + Self::new() + } +} + #[cfg(test)] mod test { use super::AdjacencyMapGraph; From bb0f39cbb5c4b081112267ee06486a49c0aab79d Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 8 Jan 2023 19:34:02 +0100 Subject: [PATCH 003/183] Directed and Undirected Edges --- crates/bevy_graph/src/graphs/map.rs | 48 +++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/crates/bevy_graph/src/graphs/map.rs b/crates/bevy_graph/src/graphs/map.rs index 82fabb8f8913f..50e1c7b68d97d 100644 --- a/crates/bevy_graph/src/graphs/map.rs +++ b/crates/bevy_graph/src/graphs/map.rs @@ -24,7 +24,20 @@ impl AdjacencyMapGraph { idx } - pub fn add_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + pub fn add_undirected_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(edge); + self.adjacencies + .get_mut(&first) + .unwrap() + .insert(second, idx); + self.adjacencies + .get_mut(&second) + .unwrap() + .insert(first, idx); + idx // TODO: does the end user really need the idx? + } + + pub fn add_directed_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(edge); self.adjacencies.get_mut(&from).unwrap().insert(to, idx); idx // TODO: does the end user really need the idx? @@ -67,20 +80,43 @@ mod test { enum Person { Jake, Michael, + Jennifer, } #[test] - fn get_edge() { + fn undirected_edge() { const STRENGTH: i32 = 100; let mut map_graph = AdjacencyMapGraph::::new(); let jake = map_graph.add_node(Person::Jake); let michael = map_graph.add_node(Person::Michael); - let _best_friends = map_graph.add_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? + let _best_friends = map_graph.add_undirected_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? + + let strength_jake = map_graph.edge(jake, michael); + assert!(strength_jake.is_some()); + assert_eq!(strength_jake.unwrap(), &STRENGTH); + + let strength_michael = map_graph.edge(michael, jake); + assert!(strength_michael.is_some()); + assert_eq!(strength_michael.unwrap(), &STRENGTH); + } + + #[test] + fn directed_edge() { + const STRENGTH: i32 = 9999; + + let mut map_graph = AdjacencyMapGraph::::new(); + + let jake = map_graph.add_node(Person::Jake); + let jennifer = map_graph.add_node(Person::Jennifer); + let _oneway_crush = map_graph.add_directed_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? + + let strength_jake = map_graph.edge(jake, jennifer); + assert!(strength_jake.is_some()); + assert_eq!(strength_jake.unwrap(), &STRENGTH); - let stength = map_graph.edge(jake, michael); - assert!(stength.is_some()); - assert_eq!(stength.unwrap(), &STRENGTH); + let strength_jennifer = map_graph.edge(jennifer, jake); + assert!(strength_jennifer.is_none()); } } From 3b035c02d737ea01620f08fa495e80c6e9e303c6 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 8 Jan 2023 20:08:12 +0100 Subject: [PATCH 004/183] Moving files and modules --- crates/bevy_graph/src/graphs/mod.rs | 6 +----- crates/bevy_graph/src/graphs/{ => simple}/map.rs | 8 ++++---- crates/bevy_graph/src/graphs/simple/mod.rs | 5 +++++ 3 files changed, 10 insertions(+), 9 deletions(-) rename crates/bevy_graph/src/graphs/{ => simple}/map.rs (95%) create mode 100644 crates/bevy_graph/src/graphs/simple/mod.rs diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 8b57a8c64d3ad..b252f36bf9e71 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -1,5 +1 @@ -pub type NodeIdx = slotmap::DefaultKey; -pub type EdgeIdx = slotmap::DefaultKey; - -mod map; -pub use map::*; +pub mod simple; diff --git a/crates/bevy_graph/src/graphs/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs similarity index 95% rename from crates/bevy_graph/src/graphs/map.rs rename to crates/bevy_graph/src/graphs/simple/map.rs index 50e1c7b68d97d..d975f62117957 100644 --- a/crates/bevy_graph/src/graphs/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -3,13 +3,13 @@ use slotmap::SlotMap; use super::{EdgeIdx, NodeIdx}; -pub struct AdjacencyMapGraph { +pub struct SimpleMapGraph { nodes: SlotMap, edges: SlotMap, adjacencies: HashMap>, } -impl AdjacencyMapGraph { +impl SimpleMapGraph { pub fn new() -> Self { Self { nodes: SlotMap::new(), @@ -66,7 +66,7 @@ impl AdjacencyMapGraph { } } -impl Default for AdjacencyMapGraph { +impl Default for SimpleMapGraph { #[inline] fn default() -> Self { Self::new() @@ -75,7 +75,7 @@ impl Default for AdjacencyMapGraph { #[cfg(test)] mod test { - use super::AdjacencyMapGraph; + use super::SimpleMapGraph; enum Person { Jake, diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs new file mode 100644 index 0000000000000..8b57a8c64d3ad --- /dev/null +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -0,0 +1,5 @@ +pub type NodeIdx = slotmap::DefaultKey; +pub type EdgeIdx = slotmap::DefaultKey; + +mod map; +pub use map::*; From 9c5f2ea917a71b9213d82a88849713f30ceff87b Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 8 Jan 2023 20:10:15 +0100 Subject: [PATCH 005/183] Whoops was faster than cargo check --- crates/bevy_graph/src/graphs/simple/map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index d975f62117957..00ee06b135e3b 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -87,7 +87,7 @@ mod test { fn undirected_edge() { const STRENGTH: i32 = 100; - let mut map_graph = AdjacencyMapGraph::::new(); + let mut map_graph = SimpleMapGraph::::new(); let jake = map_graph.add_node(Person::Jake); let michael = map_graph.add_node(Person::Michael); @@ -106,7 +106,7 @@ mod test { fn directed_edge() { const STRENGTH: i32 = 9999; - let mut map_graph = AdjacencyMapGraph::::new(); + let mut map_graph = SimpleMapGraph::::new(); let jake = map_graph.add_node(Person::Jake); let jennifer = map_graph.add_node(Person::Jennifer); From 6a8d9024235d53fbc642af4968c999138cf9ed31 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 13:51:06 +0100 Subject: [PATCH 006/183] Make NodeIdx and EdgeIdx new keys --- crates/bevy_graph/src/graphs/simple/map.rs | 4 ++-- crates/bevy_graph/src/graphs/simple/mod.rs | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 00ee06b135e3b..9f948dee79522 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -12,8 +12,8 @@ pub struct SimpleMapGraph { impl SimpleMapGraph { pub fn new() -> Self { Self { - nodes: SlotMap::new(), - edges: SlotMap::new(), + nodes: SlotMap::with_key(), + edges: SlotMap::with_key(), adjacencies: HashMap::new(), } } diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index 8b57a8c64d3ad..f24a6b4298a05 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -1,5 +1,9 @@ -pub type NodeIdx = slotmap::DefaultKey; -pub type EdgeIdx = slotmap::DefaultKey; - mod map; pub use map::*; + +use slotmap::new_key_type; + +new_key_type! { + pub struct NodeIdx; + pub struct EdgeIdx; +} From c5157b88c91fcbefd2857fcb63804596c71c087e Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 14:21:13 +0100 Subject: [PATCH 007/183] Add basic SimpleListGraph --- crates/bevy_graph/src/graphs/simple/list.rs | 123 ++++++++++++++++++++ crates/bevy_graph/src/graphs/simple/mod.rs | 3 + 2 files changed, 126 insertions(+) create mode 100644 crates/bevy_graph/src/graphs/simple/list.rs diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs new file mode 100644 index 0000000000000..2153b48d9c294 --- /dev/null +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -0,0 +1,123 @@ +use slotmap::{SecondaryMap, SlotMap}; + +use super::{EdgeIdx, NodeIdx}; + +pub struct SimpleListGraph { + nodes: SlotMap, + edges: SlotMap, + adjacencies: SecondaryMap>, +} + +impl SimpleListGraph { + pub fn new() -> Self { + Self { + nodes: SlotMap::with_key(), + edges: SlotMap::with_key(), + adjacencies: SecondaryMap::new(), + } + } + + pub fn add_node(&mut self, node: N) -> NodeIdx { + let idx = self.nodes.insert(node); + self.adjacencies.insert(idx, Vec::new()); + idx + } + + pub fn add_undirected_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(edge); + self.adjacencies.get_mut(first).unwrap().push((second, idx)); + self.adjacencies.get_mut(second).unwrap().push((first, idx)); + idx // TODO: does the end user really need the idx? + } + + pub fn add_directed_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(edge); + self.adjacencies.get_mut(from).unwrap().push((to, idx)); + idx // TODO: does the end user really need the idx? + } + + #[inline] + pub fn node(&self, idx: NodeIdx) -> Option<&N> { + self.nodes.get(idx) + } + + #[inline] + pub fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N> { + self.nodes.get_mut(idx) + } + + #[inline] + pub fn edge(&self, from: NodeIdx, to: NodeIdx) -> Option<&E> { + let edge_idx = self + .adjacencies + .get(from)? + .iter() + .find_map(|(other_node, idx)| if *other_node == to { Some(idx) } else { None })?; + self.edges.get(*edge_idx) + } + + #[inline] + pub fn edge_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E> { + let edge_idx = self + .adjacencies + .get(from)? + .iter() + .find_map(|(other_node, idx)| if *other_node == to { Some(idx) } else { None })?; + self.edges.get_mut(*edge_idx) + } +} + +impl Default for SimpleListGraph { + #[inline] + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod test { + use super::SimpleListGraph; + + enum Person { + Jake, + Michael, + Jennifer, + } + + #[test] + fn undirected_edge() { + const STRENGTH: i32 = 100; + + let mut map_graph = SimpleListGraph::::new(); + + let jake = map_graph.add_node(Person::Jake); + let michael = map_graph.add_node(Person::Michael); + let _best_friends = map_graph.add_undirected_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? + + let strength_jake = map_graph.edge(jake, michael); + assert!(strength_jake.is_some()); + assert_eq!(strength_jake.unwrap(), &STRENGTH); + + let strength_michael = map_graph.edge(michael, jake); + assert!(strength_michael.is_some()); + assert_eq!(strength_michael.unwrap(), &STRENGTH); + } + + #[test] + fn directed_edge() { + const STRENGTH: i32 = 9999; + + let mut map_graph = SimpleListGraph::::new(); + + let jake = map_graph.add_node(Person::Jake); + let jennifer = map_graph.add_node(Person::Jennifer); + let _oneway_crush = map_graph.add_directed_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? + + let strength_jake = map_graph.edge(jake, jennifer); + assert!(strength_jake.is_some()); + assert_eq!(strength_jake.unwrap(), &STRENGTH); + + let strength_jennifer = map_graph.edge(jennifer, jake); + assert!(strength_jennifer.is_none()); + } +} diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index f24a6b4298a05..9bcf0e4c9895d 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -1,6 +1,9 @@ mod map; pub use map::*; +mod list; +pub use list::*; + use slotmap::new_key_type; new_key_type! { From 27c9fe0fb01b7bb8a545951f17b93c88aab3afe0 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 15:09:01 +0100 Subject: [PATCH 008/183] Set directed with const generic bool --- crates/bevy_graph/src/graphs/simple/list.rs | 44 ++++++++-------- crates/bevy_graph/src/graphs/simple/map.rs | 56 +++++++++++---------- 2 files changed, 54 insertions(+), 46 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 2153b48d9c294..3379dcd78a723 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -2,13 +2,13 @@ use slotmap::{SecondaryMap, SlotMap}; use super::{EdgeIdx, NodeIdx}; -pub struct SimpleListGraph { +pub struct SimpleListGraph { nodes: SlotMap, edges: SlotMap, adjacencies: SecondaryMap>, } -impl SimpleListGraph { +impl SimpleListGraph { pub fn new() -> Self { Self { nodes: SlotMap::with_key(), @@ -23,19 +23,6 @@ impl SimpleListGraph { idx } - pub fn add_undirected_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(edge); - self.adjacencies.get_mut(first).unwrap().push((second, idx)); - self.adjacencies.get_mut(second).unwrap().push((first, idx)); - idx // TODO: does the end user really need the idx? - } - - pub fn add_directed_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(edge); - self.adjacencies.get_mut(from).unwrap().push((to, idx)); - idx // TODO: does the end user really need the idx? - } - #[inline] pub fn node(&self, idx: NodeIdx) -> Option<&N> { self.nodes.get(idx) @@ -67,7 +54,24 @@ impl SimpleListGraph { } } -impl Default for SimpleListGraph { +impl SimpleListGraph { + pub fn add_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(edge); + self.adjacencies.get_mut(first).unwrap().push((second, idx)); + self.adjacencies.get_mut(second).unwrap().push((first, idx)); + idx // TODO: does the end user really need the idx? + } +} + +impl SimpleListGraph { + pub fn add_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(edge); + self.adjacencies.get_mut(from).unwrap().push((to, idx)); + idx // TODO: does the end user really need the idx? + } +} + +impl Default for SimpleListGraph { #[inline] fn default() -> Self { Self::new() @@ -88,11 +92,11 @@ mod test { fn undirected_edge() { const STRENGTH: i32 = 100; - let mut map_graph = SimpleListGraph::::new(); + let mut map_graph = SimpleListGraph::::new(); let jake = map_graph.add_node(Person::Jake); let michael = map_graph.add_node(Person::Michael); - let _best_friends = map_graph.add_undirected_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? + let _best_friends = map_graph.add_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? let strength_jake = map_graph.edge(jake, michael); assert!(strength_jake.is_some()); @@ -107,11 +111,11 @@ mod test { fn directed_edge() { const STRENGTH: i32 = 9999; - let mut map_graph = SimpleListGraph::::new(); + let mut map_graph = SimpleListGraph::::new(); let jake = map_graph.add_node(Person::Jake); let jennifer = map_graph.add_node(Person::Jennifer); - let _oneway_crush = map_graph.add_directed_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? + let _oneway_crush = map_graph.add_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? let strength_jake = map_graph.edge(jake, jennifer); assert!(strength_jake.is_some()); diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 9f948dee79522..7dd12303a5164 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -3,13 +3,13 @@ use slotmap::SlotMap; use super::{EdgeIdx, NodeIdx}; -pub struct SimpleMapGraph { +pub struct SimpleMapGraph { nodes: SlotMap, edges: SlotMap, adjacencies: HashMap>, } -impl SimpleMapGraph { +impl SimpleMapGraph { pub fn new() -> Self { Self { nodes: SlotMap::with_key(), @@ -24,25 +24,6 @@ impl SimpleMapGraph { idx } - pub fn add_undirected_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(edge); - self.adjacencies - .get_mut(&first) - .unwrap() - .insert(second, idx); - self.adjacencies - .get_mut(&second) - .unwrap() - .insert(first, idx); - idx // TODO: does the end user really need the idx? - } - - pub fn add_directed_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(edge); - self.adjacencies.get_mut(&from).unwrap().insert(to, idx); - idx // TODO: does the end user really need the idx? - } - #[inline] pub fn node(&self, idx: NodeIdx) -> Option<&N> { self.nodes.get(idx) @@ -66,7 +47,30 @@ impl SimpleMapGraph { } } -impl Default for SimpleMapGraph { +impl SimpleMapGraph { + pub fn add_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(edge); + self.adjacencies + .get_mut(&first) + .unwrap() + .insert(second, idx); + self.adjacencies + .get_mut(&second) + .unwrap() + .insert(first, idx); + idx // TODO: does the end user really need the idx? + } +} + +impl SimpleMapGraph { + pub fn add_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(edge); + self.adjacencies.get_mut(&from).unwrap().insert(to, idx); + idx // TODO: does the end user really need the idx? + } +} + +impl Default for SimpleMapGraph { #[inline] fn default() -> Self { Self::new() @@ -87,11 +91,11 @@ mod test { fn undirected_edge() { const STRENGTH: i32 = 100; - let mut map_graph = SimpleMapGraph::::new(); + let mut map_graph = SimpleMapGraph::::new(); let jake = map_graph.add_node(Person::Jake); let michael = map_graph.add_node(Person::Michael); - let _best_friends = map_graph.add_undirected_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? + let _best_friends = map_graph.add_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? let strength_jake = map_graph.edge(jake, michael); assert!(strength_jake.is_some()); @@ -106,11 +110,11 @@ mod test { fn directed_edge() { const STRENGTH: i32 = 9999; - let mut map_graph = SimpleMapGraph::::new(); + let mut map_graph = SimpleMapGraph::::new(); let jake = map_graph.add_node(Person::Jake); let jennifer = map_graph.add_node(Person::Jennifer); - let _oneway_crush = map_graph.add_directed_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? + let _oneway_crush = map_graph.add_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? let strength_jake = map_graph.edge(jake, jennifer); assert!(strength_jake.is_some()); From 3eabc1377c1aeeecd97dcca92dee95b2b815eed0 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 15:11:05 +0100 Subject: [PATCH 009/183] Let Map also use SecondaryMap instead of HashMap --- crates/bevy_graph/src/graphs/simple/map.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 7dd12303a5164..b7720e2ef323d 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -1,12 +1,12 @@ use hashbrown::HashMap; -use slotmap::SlotMap; +use slotmap::{SecondaryMap, SlotMap}; use super::{EdgeIdx, NodeIdx}; pub struct SimpleMapGraph { nodes: SlotMap, edges: SlotMap, - adjacencies: HashMap>, + adjacencies: SecondaryMap>, } impl SimpleMapGraph { @@ -14,7 +14,7 @@ impl SimpleMapGraph { Self { nodes: SlotMap::with_key(), edges: SlotMap::with_key(), - adjacencies: HashMap::new(), + adjacencies: SecondaryMap::new(), } } @@ -36,13 +36,13 @@ impl SimpleMapGraph { #[inline] pub fn edge(&self, from: NodeIdx, to: NodeIdx) -> Option<&E> { - let edge_idx = self.adjacencies.get(&from)?.get(&to)?; + let edge_idx = self.adjacencies.get(from)?.get(&to)?; self.edges.get(*edge_idx) } #[inline] pub fn edge_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E> { - let edge_idx = self.adjacencies.get(&from)?.get(&to)?; + let edge_idx = self.adjacencies.get(from)?.get(&to)?; self.edges.get_mut(*edge_idx) } } @@ -50,14 +50,8 @@ impl SimpleMapGraph { impl SimpleMapGraph { pub fn add_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(edge); - self.adjacencies - .get_mut(&first) - .unwrap() - .insert(second, idx); - self.adjacencies - .get_mut(&second) - .unwrap() - .insert(first, idx); + self.adjacencies.get_mut(first).unwrap().insert(second, idx); + self.adjacencies.get_mut(second).unwrap().insert(first, idx); idx // TODO: does the end user really need the idx? } } @@ -65,7 +59,7 @@ impl SimpleMapGraph { impl SimpleMapGraph { pub fn add_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(edge); - self.adjacencies.get_mut(&from).unwrap().insert(to, idx); + self.adjacencies.get_mut(from).unwrap().insert(to, idx); idx // TODO: does the end user really need the idx? } } From d6e0f9c7972cb0f83c118f9856e556fad13f09c1 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 15:25:00 +0100 Subject: [PATCH 010/183] Replace SlotMap with HopSlotMap --- crates/bevy_graph/src/graphs/simple/list.rs | 10 +++++----- crates/bevy_graph/src/graphs/simple/map.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 3379dcd78a723..f980c06521fb4 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -1,18 +1,18 @@ -use slotmap::{SecondaryMap, SlotMap}; +use slotmap::{HopSlotMap, SecondaryMap}; use super::{EdgeIdx, NodeIdx}; pub struct SimpleListGraph { - nodes: SlotMap, - edges: SlotMap, + nodes: HopSlotMap, + edges: HopSlotMap, adjacencies: SecondaryMap>, } impl SimpleListGraph { pub fn new() -> Self { Self { - nodes: SlotMap::with_key(), - edges: SlotMap::with_key(), + nodes: HopSlotMap::with_key(), + edges: HopSlotMap::with_key(), adjacencies: SecondaryMap::new(), } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index b7720e2ef323d..cc57b9b933f04 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -1,19 +1,19 @@ use hashbrown::HashMap; -use slotmap::{SecondaryMap, SlotMap}; +use slotmap::{HopSlotMap, SecondaryMap}; use super::{EdgeIdx, NodeIdx}; pub struct SimpleMapGraph { - nodes: SlotMap, - edges: SlotMap, + nodes: HopSlotMap, + edges: HopSlotMap, adjacencies: SecondaryMap>, } impl SimpleMapGraph { pub fn new() -> Self { Self { - nodes: SlotMap::with_key(), - edges: SlotMap::with_key(), + nodes: HopSlotMap::with_key(), + edges: HopSlotMap::with_key(), adjacencies: SecondaryMap::new(), } } From 817556c103bc683d150576d20e922b3c39853b2b Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 15:44:33 +0100 Subject: [PATCH 011/183] Extract basic Graph functions into `Graph` trait --- crates/bevy_graph/src/graphs/simple/list.rs | 24 ++++++++++++--------- crates/bevy_graph/src/graphs/simple/map.rs | 24 ++++++++++++--------- crates/bevy_graph/src/graphs/simple/mod.rs | 7 ------ crates/bevy_graph/src/lib.rs | 17 +++++++++++++++ 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index f980c06521fb4..b97222bd1dd5d 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -1,6 +1,6 @@ use slotmap::{HopSlotMap, SecondaryMap}; -use super::{EdgeIdx, NodeIdx}; +use crate::{EdgeIdx, Graph, NodeIdx}; pub struct SimpleListGraph { nodes: HopSlotMap, @@ -16,25 +16,27 @@ impl SimpleListGraph { adjacencies: SecondaryMap::new(), } } +} - pub fn add_node(&mut self, node: N) -> NodeIdx { +impl Graph for SimpleListGraph { + fn new_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, Vec::new()); idx } #[inline] - pub fn node(&self, idx: NodeIdx) -> Option<&N> { + fn node(&self, idx: NodeIdx) -> Option<&N> { self.nodes.get(idx) } #[inline] - pub fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N> { + fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N> { self.nodes.get_mut(idx) } #[inline] - pub fn edge(&self, from: NodeIdx, to: NodeIdx) -> Option<&E> { + fn edge(&self, from: NodeIdx, to: NodeIdx) -> Option<&E> { let edge_idx = self .adjacencies .get(from)? @@ -44,7 +46,7 @@ impl SimpleListGraph { } #[inline] - pub fn edge_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E> { + fn edge_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E> { let edge_idx = self .adjacencies .get(from)? @@ -80,6 +82,8 @@ impl Default for SimpleListGraph { #[cfg(test)] mod test { + use crate::Graph; + use super::SimpleListGraph; enum Person { @@ -94,8 +98,8 @@ mod test { let mut map_graph = SimpleListGraph::::new(); - let jake = map_graph.add_node(Person::Jake); - let michael = map_graph.add_node(Person::Michael); + let jake = map_graph.new_node(Person::Jake); + let michael = map_graph.new_node(Person::Michael); let _best_friends = map_graph.add_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? let strength_jake = map_graph.edge(jake, michael); @@ -113,8 +117,8 @@ mod test { let mut map_graph = SimpleListGraph::::new(); - let jake = map_graph.add_node(Person::Jake); - let jennifer = map_graph.add_node(Person::Jennifer); + let jake = map_graph.new_node(Person::Jake); + let jennifer = map_graph.new_node(Person::Jennifer); let _oneway_crush = map_graph.add_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? let strength_jake = map_graph.edge(jake, jennifer); diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index cc57b9b933f04..8a34485f211bb 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -1,7 +1,7 @@ use hashbrown::HashMap; use slotmap::{HopSlotMap, SecondaryMap}; -use super::{EdgeIdx, NodeIdx}; +use crate::{EdgeIdx, Graph, NodeIdx}; pub struct SimpleMapGraph { nodes: HopSlotMap, @@ -17,31 +17,33 @@ impl SimpleMapGraph { adjacencies: SecondaryMap::new(), } } +} - pub fn add_node(&mut self, node: N) -> NodeIdx { +impl Graph for SimpleMapGraph { + fn new_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, HashMap::new()); idx } #[inline] - pub fn node(&self, idx: NodeIdx) -> Option<&N> { + fn node(&self, idx: NodeIdx) -> Option<&N> { self.nodes.get(idx) } #[inline] - pub fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N> { + fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N> { self.nodes.get_mut(idx) } #[inline] - pub fn edge(&self, from: NodeIdx, to: NodeIdx) -> Option<&E> { + fn edge(&self, from: NodeIdx, to: NodeIdx) -> Option<&E> { let edge_idx = self.adjacencies.get(from)?.get(&to)?; self.edges.get(*edge_idx) } #[inline] - pub fn edge_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E> { + fn edge_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E> { let edge_idx = self.adjacencies.get(from)?.get(&to)?; self.edges.get_mut(*edge_idx) } @@ -73,6 +75,8 @@ impl Default for SimpleMapGraph { #[cfg(test)] mod test { + use crate::Graph; + use super::SimpleMapGraph; enum Person { @@ -87,8 +91,8 @@ mod test { let mut map_graph = SimpleMapGraph::::new(); - let jake = map_graph.add_node(Person::Jake); - let michael = map_graph.add_node(Person::Michael); + let jake = map_graph.new_node(Person::Jake); + let michael = map_graph.new_node(Person::Michael); let _best_friends = map_graph.add_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? let strength_jake = map_graph.edge(jake, michael); @@ -106,8 +110,8 @@ mod test { let mut map_graph = SimpleMapGraph::::new(); - let jake = map_graph.add_node(Person::Jake); - let jennifer = map_graph.add_node(Person::Jennifer); + let jake = map_graph.new_node(Person::Jake); + let jennifer = map_graph.new_node(Person::Jennifer); let _oneway_crush = map_graph.add_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? let strength_jake = map_graph.edge(jake, jennifer); diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index 9bcf0e4c9895d..4efa46e6469cb 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -3,10 +3,3 @@ pub use map::*; mod list; pub use list::*; - -use slotmap::new_key_type; - -new_key_type! { - pub struct NodeIdx; - pub struct EdgeIdx; -} diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index 010ff385ddac3..3f78a975bdc99 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -1 +1,18 @@ pub mod graphs; + +use slotmap::new_key_type; + +new_key_type! { + pub struct NodeIdx; + pub struct EdgeIdx; +} + +pub trait Graph { + fn new_node(&mut self, node: N) -> NodeIdx; + + fn node(&self, idx: NodeIdx) -> Option<&N>; + fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N>; + + fn edge(&self, from: NodeIdx, to: NodeIdx) -> Option<&E>; + fn edge_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E>; +} From 49582c77c31b4119afec42540f03e8df77d8af4a Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 15:51:28 +0100 Subject: [PATCH 012/183] `DirectedGraph` and `UndirectedGraph` traits --- crates/bevy_graph/src/graphs/simple/list.rs | 20 ++++++++++---------- crates/bevy_graph/src/graphs/simple/map.rs | 20 ++++++++++---------- crates/bevy_graph/src/lib.rs | 8 ++++++++ 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index b97222bd1dd5d..58496d362f991 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -1,6 +1,6 @@ use slotmap::{HopSlotMap, SecondaryMap}; -use crate::{EdgeIdx, Graph, NodeIdx}; +use crate::{DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph}; pub struct SimpleListGraph { nodes: HopSlotMap, @@ -56,20 +56,20 @@ impl Graph for SimpleListGraph } } -impl SimpleListGraph { - pub fn add_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { +impl UndirectedGraph for SimpleListGraph { + fn new_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(edge); self.adjacencies.get_mut(first).unwrap().push((second, idx)); self.adjacencies.get_mut(second).unwrap().push((first, idx)); - idx // TODO: does the end user really need the idx? + idx } } -impl SimpleListGraph { - pub fn add_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { +impl DirectedGraph for SimpleListGraph { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(edge); self.adjacencies.get_mut(from).unwrap().push((to, idx)); - idx // TODO: does the end user really need the idx? + idx } } @@ -82,7 +82,7 @@ impl Default for SimpleListGraph { #[cfg(test)] mod test { - use crate::Graph; + use crate::{DirectedGraph, Graph, UndirectedGraph}; use super::SimpleListGraph; @@ -100,7 +100,7 @@ mod test { let jake = map_graph.new_node(Person::Jake); let michael = map_graph.new_node(Person::Michael); - let _best_friends = map_graph.add_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? + let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? let strength_jake = map_graph.edge(jake, michael); assert!(strength_jake.is_some()); @@ -119,7 +119,7 @@ mod test { let jake = map_graph.new_node(Person::Jake); let jennifer = map_graph.new_node(Person::Jennifer); - let _oneway_crush = map_graph.add_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? + let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? let strength_jake = map_graph.edge(jake, jennifer); assert!(strength_jake.is_some()); diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 8a34485f211bb..4b0180b085a15 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -1,7 +1,7 @@ use hashbrown::HashMap; use slotmap::{HopSlotMap, SecondaryMap}; -use crate::{EdgeIdx, Graph, NodeIdx}; +use crate::{DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph}; pub struct SimpleMapGraph { nodes: HopSlotMap, @@ -49,20 +49,20 @@ impl Graph for SimpleMapGraph } } -impl SimpleMapGraph { - pub fn add_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { +impl UndirectedGraph for SimpleMapGraph { + fn new_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(edge); self.adjacencies.get_mut(first).unwrap().insert(second, idx); self.adjacencies.get_mut(second).unwrap().insert(first, idx); - idx // TODO: does the end user really need the idx? + idx } } -impl SimpleMapGraph { - pub fn add_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { +impl DirectedGraph for SimpleMapGraph { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(edge); self.adjacencies.get_mut(from).unwrap().insert(to, idx); - idx // TODO: does the end user really need the idx? + idx } } @@ -75,7 +75,7 @@ impl Default for SimpleMapGraph { #[cfg(test)] mod test { - use crate::Graph; + use crate::{DirectedGraph, Graph, UndirectedGraph}; use super::SimpleMapGraph; @@ -93,7 +93,7 @@ mod test { let jake = map_graph.new_node(Person::Jake); let michael = map_graph.new_node(Person::Michael); - let _best_friends = map_graph.add_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? + let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? let strength_jake = map_graph.edge(jake, michael); assert!(strength_jake.is_some()); @@ -112,7 +112,7 @@ mod test { let jake = map_graph.new_node(Person::Jake); let jennifer = map_graph.new_node(Person::Jennifer); - let _oneway_crush = map_graph.add_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? + let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? let strength_jake = map_graph.edge(jake, jennifer); assert!(strength_jake.is_some()); diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index 3f78a975bdc99..5ca17520e3424 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -16,3 +16,11 @@ pub trait Graph { fn edge(&self, from: NodeIdx, to: NodeIdx) -> Option<&E>; fn edge_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E>; } + +pub trait UndirectedGraph { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; // TODO: does the end user really need the idx? +} + +pub trait DirectedGraph { + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx; // TODO: does the end user really need the idx? +} From 8ffee13e33c5c56ed7cde55858431eec445451bc Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 16:07:34 +0100 Subject: [PATCH 013/183] More Edge util functions --- crates/bevy_graph/src/graphs/simple/list.rs | 36 ++++++++++----------- crates/bevy_graph/src/graphs/simple/map.rs | 29 +++++++++-------- crates/bevy_graph/src/lib.rs | 19 ++++++++--- 3 files changed, 48 insertions(+), 36 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 58496d362f991..dda00a48de523 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -36,31 +36,29 @@ impl Graph for SimpleListGraph } #[inline] - fn edge(&self, from: NodeIdx, to: NodeIdx) -> Option<&E> { - let edge_idx = self - .adjacencies + fn edge_id_between(&self, from: NodeIdx, to: NodeIdx) -> Option { + self.adjacencies .get(from)? .iter() - .find_map(|(other_node, idx)| if *other_node == to { Some(idx) } else { None })?; - self.edges.get(*edge_idx) + .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) } #[inline] - fn edge_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E> { - let edge_idx = self - .adjacencies - .get(from)? - .iter() - .find_map(|(other_node, idx)| if *other_node == to { Some(idx) } else { None })?; - self.edges.get_mut(*edge_idx) + fn edge_by_id(&self, edge: EdgeIdx) -> Option<&E> { + self.edges.get(edge) + } + + #[inline] + fn edge_by_id_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + self.edges.get_mut(edge) } } impl UndirectedGraph for SimpleListGraph { - fn new_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(edge); - self.adjacencies.get_mut(first).unwrap().push((second, idx)); - self.adjacencies.get_mut(second).unwrap().push((first, idx)); + self.adjacencies.get_mut(node).unwrap().push((other, idx)); + self.adjacencies.get_mut(other).unwrap().push((node, idx)); idx } } @@ -102,11 +100,11 @@ mod test { let michael = map_graph.new_node(Person::Michael); let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? - let strength_jake = map_graph.edge(jake, michael); + let strength_jake = map_graph.edge_between(jake, michael); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_michael = map_graph.edge(michael, jake); + let strength_michael = map_graph.edge_between(michael, jake); assert!(strength_michael.is_some()); assert_eq!(strength_michael.unwrap(), &STRENGTH); } @@ -121,11 +119,11 @@ mod test { let jennifer = map_graph.new_node(Person::Jennifer); let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? - let strength_jake = map_graph.edge(jake, jennifer); + let strength_jake = map_graph.edge_between(jake, jennifer); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_jennifer = map_graph.edge(jennifer, jake); + let strength_jennifer = map_graph.edge_between(jennifer, jake); assert!(strength_jennifer.is_none()); } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 4b0180b085a15..dfa05733956f7 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -37,23 +37,26 @@ impl Graph for SimpleMapGraph } #[inline] - fn edge(&self, from: NodeIdx, to: NodeIdx) -> Option<&E> { - let edge_idx = self.adjacencies.get(from)?.get(&to)?; - self.edges.get(*edge_idx) + fn edge_id_between(&self, from: NodeIdx, to: NodeIdx) -> Option { + self.adjacencies.get(from)?.get(&to).map(|idx| *idx) } #[inline] - fn edge_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E> { - let edge_idx = self.adjacencies.get(from)?.get(&to)?; - self.edges.get_mut(*edge_idx) + fn edge_by_id(&self, edge: EdgeIdx) -> Option<&E> { + self.edges.get(edge) + } + + #[inline] + fn edge_by_id_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + self.edges.get_mut(edge) } } impl UndirectedGraph for SimpleMapGraph { - fn new_edge(&mut self, first: NodeIdx, second: NodeIdx, edge: E) -> EdgeIdx { + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(edge); - self.adjacencies.get_mut(first).unwrap().insert(second, idx); - self.adjacencies.get_mut(second).unwrap().insert(first, idx); + self.adjacencies.get_mut(node).unwrap().insert(other, idx); + self.adjacencies.get_mut(other).unwrap().insert(node, idx); idx } } @@ -95,11 +98,11 @@ mod test { let michael = map_graph.new_node(Person::Michael); let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? - let strength_jake = map_graph.edge(jake, michael); + let strength_jake = map_graph.edge_between(jake, michael); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_michael = map_graph.edge(michael, jake); + let strength_michael = map_graph.edge_between(michael, jake); assert!(strength_michael.is_some()); assert_eq!(strength_michael.unwrap(), &STRENGTH); } @@ -114,11 +117,11 @@ mod test { let jennifer = map_graph.new_node(Person::Jennifer); let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? - let strength_jake = map_graph.edge(jake, jennifer); + let strength_jake = map_graph.edge_between(jake, jennifer); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_jennifer = map_graph.edge(jennifer, jake); + let strength_jennifer = map_graph.edge_between(jennifer, jake); assert!(strength_jennifer.is_none()); } } diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index 5ca17520e3424..016d64ca58742 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -13,14 +13,25 @@ pub trait Graph { fn node(&self, idx: NodeIdx) -> Option<&N>; fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N>; - fn edge(&self, from: NodeIdx, to: NodeIdx) -> Option<&E>; - fn edge_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E>; + fn edge_id_between(&self, from: NodeIdx, to: NodeIdx) -> Option; + + fn edge_by_id(&self, edge: EdgeIdx) -> Option<&E>; + fn edge_by_id_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; + + #[inline] + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Option<&E> { + self.edge_by_id(self.edge_id_between(from, to)?) + } + #[inline] + fn edge_between_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E> { + self.edge_by_id_mut(self.edge_id_between(from, to)?) + } } pub trait UndirectedGraph { - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; // TODO: does the end user really need the idx? + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; } pub trait DirectedGraph { - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx; // TODO: does the end user really need the idx? + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx; } From e239c99dd3b0e232ab620c8fc575e5bd4c63ea6c Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 16:32:23 +0100 Subject: [PATCH 014/183] Removing edges with `edge_between` --- crates/bevy_graph/src/graphs/simple/list.rs | 68 +++++++++++++++++---- crates/bevy_graph/src/graphs/simple/map.rs | 40 +++++++++++- crates/bevy_graph/src/lib.rs | 4 ++ 3 files changed, 98 insertions(+), 14 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index dda00a48de523..45087febc1f2a 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -61,6 +61,24 @@ impl UndirectedGraph for SimpleListGraph { self.adjacencies.get_mut(other).unwrap().push((node, idx)); idx } + + fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx) { + let list = self.adjacencies.get_mut(node).unwrap(); + + if let Some(index) = list + .iter() + .position(|(node_idx, _edge_idx)| *node_idx == other) + { + let (_, edge_idx) = list.swap_remove(index); // TODO: remove or swap_remove ? + + let list = self.adjacencies.get_mut(other).unwrap(); + if let Some(index) = list.iter().position(|(node_idx, _)| *node_idx == node) { + list.swap_remove(index); // TODO: remove or swap_remove ? + } + + self.edges.remove(edge_idx); + } + } } impl DirectedGraph for SimpleListGraph { @@ -69,6 +87,16 @@ impl DirectedGraph for SimpleListGraph { self.adjacencies.get_mut(from).unwrap().push((to, idx)); idx } + + fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) { + let list = self.adjacencies.get_mut(from).unwrap(); + + if let Some(index) = list.iter().position(|(node_idx, _)| *node_idx == to) { + let (_, edge_idx) = list.swap_remove(index); // TODO: remove or swap_remove ? + + self.edges.remove(edge_idx); + } + } } impl Default for SimpleListGraph { @@ -94,36 +122,52 @@ mod test { fn undirected_edge() { const STRENGTH: i32 = 100; - let mut map_graph = SimpleListGraph::::new(); + let mut list_graph = SimpleListGraph::::new(); - let jake = map_graph.new_node(Person::Jake); - let michael = map_graph.new_node(Person::Michael); - let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? + let jake = list_graph.new_node(Person::Jake); + let michael = list_graph.new_node(Person::Michael); + let _best_friends = list_graph.new_edge(jake, michael, STRENGTH); - let strength_jake = map_graph.edge_between(jake, michael); + let strength_jake = list_graph.edge_between(jake, michael); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_michael = map_graph.edge_between(michael, jake); + let strength_michael = list_graph.edge_between(michael, jake); assert!(strength_michael.is_some()); assert_eq!(strength_michael.unwrap(), &STRENGTH); + + list_graph.remove_edge_between(michael, jake); + + let strength_jake = list_graph.edge_between(jake, michael); + assert!(strength_jake.is_none()); + + let strength_michael = list_graph.edge_between(michael, jake); + assert!(strength_michael.is_none()); } #[test] fn directed_edge() { const STRENGTH: i32 = 9999; - let mut map_graph = SimpleListGraph::::new(); + let mut list_graph = SimpleListGraph::::new(); - let jake = map_graph.new_node(Person::Jake); - let jennifer = map_graph.new_node(Person::Jennifer); - let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? + let jake = list_graph.new_node(Person::Jake); + let jennifer = list_graph.new_node(Person::Jennifer); + let _oneway_crush = list_graph.new_edge(jake, jennifer, STRENGTH); - let strength_jake = map_graph.edge_between(jake, jennifer); + let strength_jake = list_graph.edge_between(jake, jennifer); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_jennifer = map_graph.edge_between(jennifer, jake); + let strength_jennifer = list_graph.edge_between(jennifer, jake); + assert!(strength_jennifer.is_none()); + + list_graph.remove_edge_between(jake, jennifer); + + let strength_jake = list_graph.edge_between(jake, jennifer); + assert!(strength_jake.is_none()); + + let strength_jennifer = list_graph.edge_between(jennifer, jake); assert!(strength_jennifer.is_none()); } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index dfa05733956f7..9e48b2e75a3a2 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -59,6 +59,19 @@ impl UndirectedGraph for SimpleMapGraph { self.adjacencies.get_mut(other).unwrap().insert(node, idx); idx } + + fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx) { + let edge_idx = self + .adjacencies + .get_mut(node) + .unwrap() + .remove(&other) + .unwrap(); + + self.adjacencies.get_mut(other).unwrap().remove(&node); + + self.edges.remove(edge_idx); + } } impl DirectedGraph for SimpleMapGraph { @@ -67,6 +80,11 @@ impl DirectedGraph for SimpleMapGraph { self.adjacencies.get_mut(from).unwrap().insert(to, idx); idx } + fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) { + let edge_idx = self.adjacencies.get_mut(from).unwrap().remove(&to).unwrap(); + + self.edges.remove(edge_idx); + } } impl Default for SimpleMapGraph { @@ -96,7 +114,8 @@ mod test { let jake = map_graph.new_node(Person::Jake); let michael = map_graph.new_node(Person::Michael); - let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); // TODO: does the end user really need the idx returned? + + let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); let strength_jake = map_graph.edge_between(jake, michael); assert!(strength_jake.is_some()); @@ -105,6 +124,14 @@ mod test { let strength_michael = map_graph.edge_between(michael, jake); assert!(strength_michael.is_some()); assert_eq!(strength_michael.unwrap(), &STRENGTH); + + map_graph.remove_edge_between(michael, jake); + + let strength_jake = map_graph.edge_between(jake, michael); + assert!(strength_jake.is_none()); + + let strength_michael = map_graph.edge_between(michael, jake); + assert!(strength_michael.is_none()); } #[test] @@ -115,7 +142,8 @@ mod test { let jake = map_graph.new_node(Person::Jake); let jennifer = map_graph.new_node(Person::Jennifer); - let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); // TODO: does the end user really need the idx returned? + + let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); let strength_jake = map_graph.edge_between(jake, jennifer); assert!(strength_jake.is_some()); @@ -123,5 +151,13 @@ mod test { let strength_jennifer = map_graph.edge_between(jennifer, jake); assert!(strength_jennifer.is_none()); + + map_graph.remove_edge_between(jake, jennifer); + + let strength_jake = map_graph.edge_between(jake, jennifer); + assert!(strength_jake.is_none()); + + let strength_jennifer = map_graph.edge_between(jennifer, jake); + assert!(strength_jennifer.is_none()); } } diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index 016d64ca58742..38e4252a90c70 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -30,8 +30,12 @@ pub trait Graph { pub trait UndirectedGraph { fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; + + fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx); } pub trait DirectedGraph { fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx; + + fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx); } From 9031134dd5fbc44a7c2c20496525d21fd9cc5af8 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 17:21:01 +0100 Subject: [PATCH 015/183] Make CI happy :D --- crates/bevy_graph/src/graphs/simple/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 9e48b2e75a3a2..0b00bc727aff2 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -38,7 +38,7 @@ impl Graph for SimpleMapGraph #[inline] fn edge_id_between(&self, from: NodeIdx, to: NodeIdx) -> Option { - self.adjacencies.get(from)?.get(&to).map(|idx| *idx) + self.adjacencies.get(from)?.get(&to).cloned() } #[inline] From ac4cdce541c60070d9b4d2c1bc6fae794c001a70 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 17:58:14 +0100 Subject: [PATCH 016/183] remove returns the Edge Data --- crates/bevy_graph/src/graphs/simple/list.rs | 16 ++++++++++------ crates/bevy_graph/src/graphs/simple/map.rs | 20 ++++++++------------ crates/bevy_graph/src/lib.rs | 4 ++-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 45087febc1f2a..7ee44d3301e9c 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -62,8 +62,8 @@ impl UndirectedGraph for SimpleListGraph { idx } - fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx) { - let list = self.adjacencies.get_mut(node).unwrap(); + fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx) -> Option { + let list = self.adjacencies.get_mut(node)?; if let Some(index) = list .iter() @@ -71,12 +71,14 @@ impl UndirectedGraph for SimpleListGraph { { let (_, edge_idx) = list.swap_remove(index); // TODO: remove or swap_remove ? - let list = self.adjacencies.get_mut(other).unwrap(); + let list = self.adjacencies.get_mut(other)?; if let Some(index) = list.iter().position(|(node_idx, _)| *node_idx == node) { list.swap_remove(index); // TODO: remove or swap_remove ? } - self.edges.remove(edge_idx); + self.edges.remove(edge_idx) + } else { + None } } } @@ -88,13 +90,15 @@ impl DirectedGraph for SimpleListGraph { idx } - fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) { + fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) -> Option { let list = self.adjacencies.get_mut(from).unwrap(); if let Some(index) = list.iter().position(|(node_idx, _)| *node_idx == to) { let (_, edge_idx) = list.swap_remove(index); // TODO: remove or swap_remove ? - self.edges.remove(edge_idx); + self.edges.remove(edge_idx) + } else { + None } } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 0b00bc727aff2..3f2a2f8e2186a 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -60,17 +60,12 @@ impl UndirectedGraph for SimpleMapGraph { idx } - fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx) { - let edge_idx = self - .adjacencies - .get_mut(node) - .unwrap() - .remove(&other) - .unwrap(); + fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx) -> Option { + let edge_idx = self.adjacencies.get_mut(node)?.remove(&other)?; - self.adjacencies.get_mut(other).unwrap().remove(&node); + self.adjacencies.get_mut(other)?.remove(&node); - self.edges.remove(edge_idx); + self.edges.remove(edge_idx) } } @@ -80,10 +75,11 @@ impl DirectedGraph for SimpleMapGraph { self.adjacencies.get_mut(from).unwrap().insert(to, idx); idx } - fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) { - let edge_idx = self.adjacencies.get_mut(from).unwrap().remove(&to).unwrap(); - self.edges.remove(edge_idx); + fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) -> Option { + let edge_idx = self.adjacencies.get_mut(from)?.remove(&to)?; + + self.edges.remove(edge_idx) } } diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index 38e4252a90c70..efc3b77460a24 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -31,11 +31,11 @@ pub trait Graph { pub trait UndirectedGraph { fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; - fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx); + fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx) -> Option; } pub trait DirectedGraph { fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx; - fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx); + fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) -> Option; } From 40c27c538b6eaaced0746b8bfb2793d1936f2d0f Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 18:58:53 +0100 Subject: [PATCH 017/183] Naming --- crates/bevy_graph/src/graphs/simple/list.rs | 6 +++--- crates/bevy_graph/src/graphs/simple/map.rs | 6 +++--- crates/bevy_graph/src/lib.rs | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 7ee44d3301e9c..6976f23dcd867 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -36,7 +36,7 @@ impl Graph for SimpleListGraph } #[inline] - fn edge_id_between(&self, from: NodeIdx, to: NodeIdx) -> Option { + fn edgeidx_between(&self, from: NodeIdx, to: NodeIdx) -> Option { self.adjacencies .get(from)? .iter() @@ -44,12 +44,12 @@ impl Graph for SimpleListGraph } #[inline] - fn edge_by_id(&self, edge: EdgeIdx) -> Option<&E> { + fn edge_by_idx(&self, edge: EdgeIdx) -> Option<&E> { self.edges.get(edge) } #[inline] - fn edge_by_id_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + fn edge_by_idx_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { self.edges.get_mut(edge) } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 3f2a2f8e2186a..91ded103daecc 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -37,17 +37,17 @@ impl Graph for SimpleMapGraph } #[inline] - fn edge_id_between(&self, from: NodeIdx, to: NodeIdx) -> Option { + fn edgeidx_between(&self, from: NodeIdx, to: NodeIdx) -> Option { self.adjacencies.get(from)?.get(&to).cloned() } #[inline] - fn edge_by_id(&self, edge: EdgeIdx) -> Option<&E> { + fn edge_by_idx(&self, edge: EdgeIdx) -> Option<&E> { self.edges.get(edge) } #[inline] - fn edge_by_id_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + fn edge_by_idx_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { self.edges.get_mut(edge) } } diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index efc3b77460a24..fc05604be2f61 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -13,18 +13,18 @@ pub trait Graph { fn node(&self, idx: NodeIdx) -> Option<&N>; fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N>; - fn edge_id_between(&self, from: NodeIdx, to: NodeIdx) -> Option; + fn edgeidx_between(&self, from: NodeIdx, to: NodeIdx) -> Option; - fn edge_by_id(&self, edge: EdgeIdx) -> Option<&E>; - fn edge_by_id_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; + fn edge_by_idx(&self, edge: EdgeIdx) -> Option<&E>; + fn edge_by_idx_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; #[inline] fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Option<&E> { - self.edge_by_id(self.edge_id_between(from, to)?) + self.edge_by_idx(self.edgeidx_between(from, to)?) } #[inline] fn edge_between_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E> { - self.edge_by_id_mut(self.edge_id_between(from, to)?) + self.edge_by_idx_mut(self.edgeidx_between(from, to)?) } } From 3a4d94d6e35d8db5c34ee7c0d01a72096a0920d0 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 19:25:10 +0100 Subject: [PATCH 018/183] API Design changes --- crates/bevy_graph/src/graphs/simple/list.rs | 35 ++++++++++++--------- crates/bevy_graph/src/graphs/simple/map.rs | 31 ++++++++++-------- crates/bevy_graph/src/lib.rs | 27 +++++++++------- 3 files changed, 54 insertions(+), 39 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 6976f23dcd867..718e94770e5c5 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -1,4 +1,4 @@ -use slotmap::{HopSlotMap, SecondaryMap}; +use slotmap::{HopSlotMap, Key, SecondaryMap}; use crate::{DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph}; @@ -36,20 +36,27 @@ impl Graph for SimpleListGraph } #[inline] - fn edgeidx_between(&self, from: NodeIdx, to: NodeIdx) -> Option { - self.adjacencies - .get(from)? + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + if let Some(idx) = self + .adjacencies + .get(from) + .unwrap() .iter() .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) + { + idx + } else { + EdgeIdx::null() + } } #[inline] - fn edge_by_idx(&self, edge: EdgeIdx) -> Option<&E> { + fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { self.edges.get(edge) } #[inline] - fn edge_by_idx_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { self.edges.get_mut(edge) } } @@ -132,20 +139,20 @@ mod test { let michael = list_graph.new_node(Person::Michael); let _best_friends = list_graph.new_edge(jake, michael, STRENGTH); - let strength_jake = list_graph.edge_between(jake, michael); + let strength_jake = list_graph.edge_between(jake, michael).get(&list_graph); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_michael = list_graph.edge_between(michael, jake); + let strength_michael = list_graph.edge_between(michael, jake).get(&list_graph); assert!(strength_michael.is_some()); assert_eq!(strength_michael.unwrap(), &STRENGTH); list_graph.remove_edge_between(michael, jake); - let strength_jake = list_graph.edge_between(jake, michael); + let strength_jake = list_graph.edge_between(jake, michael).get(&list_graph); assert!(strength_jake.is_none()); - let strength_michael = list_graph.edge_between(michael, jake); + let strength_michael = list_graph.edge_between(michael, jake).get(&list_graph); assert!(strength_michael.is_none()); } @@ -159,19 +166,19 @@ mod test { let jennifer = list_graph.new_node(Person::Jennifer); let _oneway_crush = list_graph.new_edge(jake, jennifer, STRENGTH); - let strength_jake = list_graph.edge_between(jake, jennifer); + let strength_jake = list_graph.edge_between(jake, jennifer).get(&list_graph); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_jennifer = list_graph.edge_between(jennifer, jake); + let strength_jennifer = list_graph.edge_between(jennifer, jake).get(&list_graph); assert!(strength_jennifer.is_none()); list_graph.remove_edge_between(jake, jennifer); - let strength_jake = list_graph.edge_between(jake, jennifer); + let strength_jake = list_graph.edge_between(jake, jennifer).get(&list_graph); assert!(strength_jake.is_none()); - let strength_jennifer = list_graph.edge_between(jennifer, jake); + let strength_jennifer = list_graph.edge_between(jennifer, jake).get(&list_graph); assert!(strength_jennifer.is_none()); } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 91ded103daecc..940aa04511ed6 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -1,5 +1,5 @@ use hashbrown::HashMap; -use slotmap::{HopSlotMap, SecondaryMap}; +use slotmap::{HopSlotMap, Key, SecondaryMap}; use crate::{DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph}; @@ -37,17 +37,22 @@ impl Graph for SimpleMapGraph } #[inline] - fn edgeidx_between(&self, from: NodeIdx, to: NodeIdx) -> Option { - self.adjacencies.get(from)?.get(&to).cloned() + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + self.adjacencies + .get(from) + .unwrap() + .get(&to) + .cloned() + .unwrap_or_else(|| EdgeIdx::null()) } #[inline] - fn edge_by_idx(&self, edge: EdgeIdx) -> Option<&E> { + fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { self.edges.get(edge) } #[inline] - fn edge_by_idx_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { self.edges.get_mut(edge) } } @@ -113,20 +118,20 @@ mod test { let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); - let strength_jake = map_graph.edge_between(jake, michael); + let strength_jake = map_graph.edge_between(jake, michael).get(&map_graph); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_michael = map_graph.edge_between(michael, jake); + let strength_michael = map_graph.edge_between(michael, jake).get(&map_graph); assert!(strength_michael.is_some()); assert_eq!(strength_michael.unwrap(), &STRENGTH); map_graph.remove_edge_between(michael, jake); - let strength_jake = map_graph.edge_between(jake, michael); + let strength_jake = map_graph.edge_between(jake, michael).get(&map_graph); assert!(strength_jake.is_none()); - let strength_michael = map_graph.edge_between(michael, jake); + let strength_michael = map_graph.edge_between(michael, jake).get(&map_graph); assert!(strength_michael.is_none()); } @@ -141,19 +146,19 @@ mod test { let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); - let strength_jake = map_graph.edge_between(jake, jennifer); + let strength_jake = map_graph.edge_between(jake, jennifer).get(&map_graph); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_jennifer = map_graph.edge_between(jennifer, jake); + let strength_jennifer = map_graph.edge_between(jennifer, jake).get(&map_graph); assert!(strength_jennifer.is_none()); map_graph.remove_edge_between(jake, jennifer); - let strength_jake = map_graph.edge_between(jake, jennifer); + let strength_jake = map_graph.edge_between(jake, jennifer).get(&map_graph); assert!(strength_jake.is_none()); - let strength_jennifer = map_graph.edge_between(jennifer, jake); + let strength_jennifer = map_graph.edge_between(jennifer, jake).get(&map_graph); assert!(strength_jennifer.is_none()); } } diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index fc05604be2f61..b75f6c55a3cd9 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -7,25 +7,28 @@ new_key_type! { pub struct EdgeIdx; } +impl EdgeIdx { + #[inline] + pub fn get(self, graph: &impl Graph) -> Option<&E> { + graph.get_edge(self) + } + + #[inline] + pub fn get_mut(self, graph: &mut impl Graph) -> Option<&mut E> { + graph.get_edge_mut(self) + } +} + pub trait Graph { fn new_node(&mut self, node: N) -> NodeIdx; fn node(&self, idx: NodeIdx) -> Option<&N>; fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N>; - fn edgeidx_between(&self, from: NodeIdx, to: NodeIdx) -> Option; - - fn edge_by_idx(&self, edge: EdgeIdx) -> Option<&E>; - fn edge_by_idx_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; - #[inline] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Option<&E> { - self.edge_by_idx(self.edgeidx_between(from, to)?) - } - #[inline] - fn edge_between_mut(&mut self, from: NodeIdx, to: NodeIdx) -> Option<&mut E> { - self.edge_by_idx_mut(self.edgeidx_between(from, to)?) - } + fn get_edge(&self, edge: EdgeIdx) -> Option<&E>; + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; } pub trait UndirectedGraph { From 602bd2b6d7461c404aa9237458e4f0356e9ceb17 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 9 Jan 2023 20:29:16 +0100 Subject: [PATCH 019/183] Add basic benchmark for `SimpleMapGraph` --- benches/Cargo.toml | 6 ++++ benches/benches/bevy_graph/map.rs | 48 +++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 benches/benches/bevy_graph/map.rs diff --git a/benches/Cargo.toml b/benches/Cargo.toml index bad48a02e1421..93d1ff4468327 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -13,6 +13,7 @@ rand_chacha = "0.3" criterion = { version = "0.3", features = ["html_reports"] } bevy_app = { path = "../crates/bevy_app" } bevy_ecs = { path = "../crates/bevy_ecs" } +bevy_graph = { path = "../crates/bevy_graph" } bevy_reflect = { path = "../crates/bevy_reflect" } bevy_tasks = { path = "../crates/bevy_tasks" } bevy_utils = { path = "../crates/bevy_utils" } @@ -31,6 +32,11 @@ name = "ecs" path = "benches/bevy_ecs/benches.rs" harness = false +[[bench]] +name = "map_graph" +path = "benches/bevy_graph/map.rs" +harness = false + [[bench]] name = "reflect_list" path = "benches/bevy_reflect/list.rs" diff --git a/benches/benches/bevy_graph/map.rs b/benches/benches/bevy_graph/map.rs new file mode 100644 index 0000000000000..7e3bce30d2e86 --- /dev/null +++ b/benches/benches/bevy_graph/map.rs @@ -0,0 +1,48 @@ +use bevy_graph::{graphs::simple::SimpleMapGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph}; +use bevy_utils::Duration; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +criterion_main!(benches); + +const WARM_UP_TIME: Duration = Duration::from_millis(3000); + +criterion_group! { + name = benches; + config = Criterion::default().warm_up_time(WARM_UP_TIME); + targets = nodes_10_000_undirected +} + +fn nodes_10_000_undirected(c: &mut Criterion) { + let mut map_graph = SimpleMapGraph::::new(); + + let mut nodes: Vec = Vec::with_capacity(10_000); + c.bench_function("nodes_10_000_new_node", |b| { + b.iter(|| { + for i in 1..=10_000 { + nodes.push(map_graph.new_node(i)); + } + }) + }); + let mut edges: Vec = Vec::with_capacity(10_000 - 1); + c.bench_function("nodes_10_000_new_edge", |b| { + b.iter(|| { + for i in 1..10_000 { + edges.push(map_graph.new_edge(nodes[i - 1], nodes[i], ())); + } + }) + }); + c.bench_function("nodes_10_000_get_edge", |b| { + b.iter(|| { + for edge in &edges { + black_box(edge.get(&map_graph)); + } + }) + }); + c.bench_function("nodes_10_000_remove_edge", |b| { + b.iter(|| { + for i in 1..10_000 { + black_box(map_graph.remove_edge_between(nodes[i - 1], nodes[i])); + } + }) + }); +} From a75bf1a3276cfd3f72d33a1c0046e7310d92d81c Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 9 Jan 2023 20:57:55 +0100 Subject: [PATCH 020/183] Another day of making the CI happy --- crates/bevy_graph/src/graphs/simple/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 940aa04511ed6..2af362ec70717 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -43,7 +43,7 @@ impl Graph for SimpleMapGraph .unwrap() .get(&to) .cloned() - .unwrap_or_else(|| EdgeIdx::null()) + .unwrap_or_else(EdgeIdx::null) } #[inline] From defb878dcbf9b5b48652debb449e3f10e30dbe42 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 14:30:41 +0100 Subject: [PATCH 021/183] Making Graphs clonable --- crates/bevy_graph/src/graphs/simple/list.rs | 1 + crates/bevy_graph/src/graphs/simple/map.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 718e94770e5c5..543f93cb3613d 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -2,6 +2,7 @@ use slotmap::{HopSlotMap, Key, SecondaryMap}; use crate::{DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph}; +#[derive(Clone)] pub struct SimpleListGraph { nodes: HopSlotMap, edges: HopSlotMap, diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 2af362ec70717..3ded7811b6dc8 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -3,6 +3,7 @@ use slotmap::{HopSlotMap, Key, SecondaryMap}; use crate::{DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph}; +#[derive(Clone)] pub struct SimpleMapGraph { nodes: HopSlotMap, edges: HopSlotMap, From b0cee313be51355cdd0c3b18620df690f7049495 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 16:16:38 +0100 Subject: [PATCH 022/183] naive implementation of `edges_of` --- crates/bevy_graph/src/graphs/simple/list.rs | 19 +++++++++++++++++-- crates/bevy_graph/src/graphs/simple/map.rs | 19 +++++++++++++++++-- crates/bevy_graph/src/lib.rs | 2 ++ 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 543f93cb3613d..a9354b9a89f2a 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -60,6 +60,15 @@ impl Graph for SimpleListGraph fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { self.edges.get_mut(edge) } + + fn edges_of(&self, node: NodeIdx) -> Vec { + self.adjacencies + .get(node) + .unwrap() + .iter() + .map(|(_, edge)| edge.clone()) + .collect() + } } impl UndirectedGraph for SimpleListGraph { @@ -138,7 +147,7 @@ mod test { let jake = list_graph.new_node(Person::Jake); let michael = list_graph.new_node(Person::Michael); - let _best_friends = list_graph.new_edge(jake, michael, STRENGTH); + let best_friends = list_graph.new_edge(jake, michael, STRENGTH); let strength_jake = list_graph.edge_between(jake, michael).get(&list_graph); assert!(strength_jake.is_some()); @@ -148,6 +157,9 @@ mod test { assert!(strength_michael.is_some()); assert_eq!(strength_michael.unwrap(), &STRENGTH); + assert_eq!(list_graph.edges_of(jake), vec![best_friends]); + assert_eq!(list_graph.edges_of(michael), vec![best_friends]); + list_graph.remove_edge_between(michael, jake); let strength_jake = list_graph.edge_between(jake, michael).get(&list_graph); @@ -165,7 +177,7 @@ mod test { let jake = list_graph.new_node(Person::Jake); let jennifer = list_graph.new_node(Person::Jennifer); - let _oneway_crush = list_graph.new_edge(jake, jennifer, STRENGTH); + let oneway_crush = list_graph.new_edge(jake, jennifer, STRENGTH); let strength_jake = list_graph.edge_between(jake, jennifer).get(&list_graph); assert!(strength_jake.is_some()); @@ -174,6 +186,9 @@ mod test { let strength_jennifer = list_graph.edge_between(jennifer, jake).get(&list_graph); assert!(strength_jennifer.is_none()); + assert_eq!(list_graph.edges_of(jake), vec![oneway_crush]); + assert_eq!(list_graph.edges_of(jennifer), vec![]); + list_graph.remove_edge_between(jake, jennifer); let strength_jake = list_graph.edge_between(jake, jennifer).get(&list_graph); diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 3ded7811b6dc8..6e801acacc85c 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -56,6 +56,15 @@ impl Graph for SimpleMapGraph fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { self.edges.get_mut(edge) } + + fn edges_of(&self, node: NodeIdx) -> Vec { + self.adjacencies + .get(node) + .unwrap() + .values() + .cloned() + .collect() + } } impl UndirectedGraph for SimpleMapGraph { @@ -117,7 +126,7 @@ mod test { let jake = map_graph.new_node(Person::Jake); let michael = map_graph.new_node(Person::Michael); - let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); + let best_friends = map_graph.new_edge(jake, michael, STRENGTH); let strength_jake = map_graph.edge_between(jake, michael).get(&map_graph); assert!(strength_jake.is_some()); @@ -127,6 +136,9 @@ mod test { assert!(strength_michael.is_some()); assert_eq!(strength_michael.unwrap(), &STRENGTH); + assert_eq!(map_graph.edges_of(jake), vec![best_friends]); + assert_eq!(map_graph.edges_of(michael), vec![best_friends]); + map_graph.remove_edge_between(michael, jake); let strength_jake = map_graph.edge_between(jake, michael).get(&map_graph); @@ -145,7 +157,7 @@ mod test { let jake = map_graph.new_node(Person::Jake); let jennifer = map_graph.new_node(Person::Jennifer); - let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); + let oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); let strength_jake = map_graph.edge_between(jake, jennifer).get(&map_graph); assert!(strength_jake.is_some()); @@ -154,6 +166,9 @@ mod test { let strength_jennifer = map_graph.edge_between(jennifer, jake).get(&map_graph); assert!(strength_jennifer.is_none()); + assert_eq!(map_graph.edges_of(jake), vec![oneway_crush]); + assert_eq!(map_graph.edges_of(jennifer), vec![]); + map_graph.remove_edge_between(jake, jennifer); let strength_jake = map_graph.edge_between(jake, jennifer).get(&map_graph); diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index b75f6c55a3cd9..5c0ec27a14727 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -29,6 +29,8 @@ pub trait Graph { fn get_edge(&self, edge: EdgeIdx) -> Option<&E>; fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; + + fn edges_of(&self, node: NodeIdx) -> Vec; // TODO: can we use other type than Vec? maybe directly iterator? } pub trait UndirectedGraph { From f427cd83656fe82c396f16e2cee1b69588e7dda2 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 16:23:40 +0100 Subject: [PATCH 023/183] Make `edges_of` also return destination of edge --- crates/bevy_graph/src/graphs/simple/list.rs | 10 +++++----- crates/bevy_graph/src/graphs/simple/map.rs | 12 ++++++------ crates/bevy_graph/src/lib.rs | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index a9354b9a89f2a..81954197ffda4 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -61,12 +61,12 @@ impl Graph for SimpleListGraph self.edges.get_mut(edge) } - fn edges_of(&self, node: NodeIdx) -> Vec { + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { self.adjacencies .get(node) .unwrap() .iter() - .map(|(_, edge)| edge.clone()) + .cloned() .collect() } } @@ -157,8 +157,8 @@ mod test { assert!(strength_michael.is_some()); assert_eq!(strength_michael.unwrap(), &STRENGTH); - assert_eq!(list_graph.edges_of(jake), vec![best_friends]); - assert_eq!(list_graph.edges_of(michael), vec![best_friends]); + assert_eq!(list_graph.edges_of(jake), vec![(michael, best_friends)]); + assert_eq!(list_graph.edges_of(michael), vec![(jake, best_friends)]); list_graph.remove_edge_between(michael, jake); @@ -186,7 +186,7 @@ mod test { let strength_jennifer = list_graph.edge_between(jennifer, jake).get(&list_graph); assert!(strength_jennifer.is_none()); - assert_eq!(list_graph.edges_of(jake), vec![oneway_crush]); + assert_eq!(list_graph.edges_of(jake), vec![(jennifer, oneway_crush)]); assert_eq!(list_graph.edges_of(jennifer), vec![]); list_graph.remove_edge_between(jake, jennifer); diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 6e801acacc85c..423ab99b1a796 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -57,12 +57,12 @@ impl Graph for SimpleMapGraph self.edges.get_mut(edge) } - fn edges_of(&self, node: NodeIdx) -> Vec { + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { self.adjacencies .get(node) .unwrap() - .values() - .cloned() + .iter() + .map(|(node, edge)| (node.clone(), edge.clone())) .collect() } } @@ -136,8 +136,8 @@ mod test { assert!(strength_michael.is_some()); assert_eq!(strength_michael.unwrap(), &STRENGTH); - assert_eq!(map_graph.edges_of(jake), vec![best_friends]); - assert_eq!(map_graph.edges_of(michael), vec![best_friends]); + assert_eq!(map_graph.edges_of(jake), vec![(michael, best_friends)]); + assert_eq!(map_graph.edges_of(michael), vec![(jake, best_friends)]); map_graph.remove_edge_between(michael, jake); @@ -166,7 +166,7 @@ mod test { let strength_jennifer = map_graph.edge_between(jennifer, jake).get(&map_graph); assert!(strength_jennifer.is_none()); - assert_eq!(map_graph.edges_of(jake), vec![oneway_crush]); + assert_eq!(map_graph.edges_of(jake), vec![(jennifer, oneway_crush)]); assert_eq!(map_graph.edges_of(jennifer), vec![]); map_graph.remove_edge_between(jake, jennifer); diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index 5c0ec27a14727..9b94aa675ae32 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -30,7 +30,7 @@ pub trait Graph { fn get_edge(&self, edge: EdgeIdx) -> Option<&E>; fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; - fn edges_of(&self, node: NodeIdx) -> Vec; // TODO: can we use other type than Vec? maybe directly iterator? + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? } pub trait UndirectedGraph { From c79ba21f47e77e02738cf6a8d6a16acbaf659f99 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 17:03:03 +0100 Subject: [PATCH 024/183] make clippy happy --- crates/bevy_graph/src/graphs/simple/list.rs | 7 +------ crates/bevy_graph/src/graphs/simple/map.rs | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 81954197ffda4..32d17c2bee9c7 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -62,12 +62,7 @@ impl Graph for SimpleListGraph } fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - self.adjacencies - .get(node) - .unwrap() - .iter() - .cloned() - .collect() + self.adjacencies.get(node).unwrap().to_vec() } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 423ab99b1a796..23458882d90ec 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -62,7 +62,7 @@ impl Graph for SimpleMapGraph .get(node) .unwrap() .iter() - .map(|(node, edge)| (node.clone(), edge.clone())) + .map(|(node, edge)| (*node, *edge)) .collect() } } From 3edc070ff7ea1d95c4f89406721e80369a5e8704 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 17:17:12 +0100 Subject: [PATCH 025/183] Better Error Handling with `GraphError` --- crates/bevy_graph/src/error.rs | 7 +++++++ crates/bevy_graph/src/graphs/simple/list.rs | 21 ++++++++++++++++----- crates/bevy_graph/src/graphs/simple/map.rs | 21 ++++++++++++++++----- crates/bevy_graph/src/lib.rs | 6 ++++-- 4 files changed, 43 insertions(+), 12 deletions(-) create mode 100644 crates/bevy_graph/src/error.rs diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs new file mode 100644 index 0000000000000..b3d45270e3e27 --- /dev/null +++ b/crates/bevy_graph/src/error.rs @@ -0,0 +1,7 @@ +use crate::NodeIdx; + +pub enum GraphError { + NodeDoesntExist(NodeIdx), +} + +pub type GraphResult = Result; diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 32d17c2bee9c7..adad4a6f86990 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -1,6 +1,9 @@ use slotmap::{HopSlotMap, Key, SecondaryMap}; -use crate::{DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph}; +use crate::{ + error::{GraphError, GraphResult}, + DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph, +}; #[derive(Clone)] pub struct SimpleListGraph { @@ -27,13 +30,21 @@ impl Graph for SimpleListGraph } #[inline] - fn node(&self, idx: NodeIdx) -> Option<&N> { - self.nodes.get(idx) + fn node(&self, idx: NodeIdx) -> GraphResult<&N> { + if let Some(node) = self.nodes.get(idx) { + Ok(node) + } else { + Err(GraphError::NodeDoesntExist(idx)) + } } #[inline] - fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N> { - self.nodes.get_mut(idx) + fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + if let Some(node) = self.nodes.get_mut(idx) { + Ok(node) + } else { + Err(GraphError::NodeDoesntExist(idx)) + } } #[inline] diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 23458882d90ec..3402f23afc2ff 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -1,7 +1,10 @@ use hashbrown::HashMap; use slotmap::{HopSlotMap, Key, SecondaryMap}; -use crate::{DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph}; +use crate::{ + error::{GraphError, GraphResult}, + DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph, +}; #[derive(Clone)] pub struct SimpleMapGraph { @@ -28,13 +31,21 @@ impl Graph for SimpleMapGraph } #[inline] - fn node(&self, idx: NodeIdx) -> Option<&N> { - self.nodes.get(idx) + fn node(&self, idx: NodeIdx) -> GraphResult<&N> { + if let Some(node) = self.nodes.get(idx) { + Ok(node) + } else { + Err(GraphError::NodeDoesntExist(idx)) + } } #[inline] - fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N> { - self.nodes.get_mut(idx) + fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + if let Some(node) = self.nodes.get_mut(idx) { + Ok(node) + } else { + Err(GraphError::NodeDoesntExist(idx)) + } } #[inline] diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index 9b94aa675ae32..e1788a559f08a 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -1,5 +1,7 @@ +pub mod error; pub mod graphs; +use error::GraphResult; use slotmap::new_key_type; new_key_type! { @@ -22,8 +24,8 @@ impl EdgeIdx { pub trait Graph { fn new_node(&mut self, node: N) -> NodeIdx; - fn node(&self, idx: NodeIdx) -> Option<&N>; - fn node_mut(&mut self, idx: NodeIdx) -> Option<&mut N>; + fn node(&self, idx: NodeIdx) -> GraphResult<&N>; + fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; From 69b9f594f2e3a300af5759ad88124fc45f64d5d4 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 18:11:04 +0100 Subject: [PATCH 026/183] Simple BFS --- crates/bevy_graph/src/algos/bfs.rs | 48 +++++++++++++++++++++ crates/bevy_graph/src/algos/mod.rs | 1 + crates/bevy_graph/src/error.rs | 1 + crates/bevy_graph/src/graphs/simple/list.rs | 5 +++ crates/bevy_graph/src/graphs/simple/map.rs | 5 +++ crates/bevy_graph/src/lib.rs | 3 ++ 6 files changed, 63 insertions(+) create mode 100644 crates/bevy_graph/src/algos/bfs.rs create mode 100644 crates/bevy_graph/src/algos/mod.rs diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs new file mode 100644 index 0000000000000..94aaca59b3322 --- /dev/null +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -0,0 +1,48 @@ +use std::collections::VecDeque; + +use hashbrown::HashSet; + +use crate::{Graph, NodeIdx}; + +pub fn breadth_first_search(start: NodeIdx, graph: &impl Graph, visitor: fn(&N)) { + let mut queue = VecDeque::new(); + let mut visited = HashSet::with_capacity(graph.len()); + + visited.insert(start); + queue.push_back(start); + + while let Some(node) = queue.pop_front() { + visitor(graph.node(node).unwrap()); + for (idx, _) in graph.edges_of(node) { + if !visited.contains(&idx) { + visited.insert(idx); + queue.push_back(idx); + } + } + } +} + +#[cfg(test)] +mod test { + use crate::{graphs::simple::SimpleMapGraph, DirectedGraph, Graph}; + + use super::breadth_first_search; + + #[test] + fn bfs() { + let mut map = SimpleMapGraph::::new(); + + let zero = map.new_node(0); + let one = map.new_node(1); + let two = map.new_node(2); + let three = map.new_node(3); + + map.new_edge(zero, one, ()); + map.new_edge(zero, two, ()); + map.new_edge(one, two, ()); + map.new_edge(two, zero, ()); + map.new_edge(two, three, ()); + + breadth_first_search(zero, &map, |value| println!("{value}")); + } +} diff --git a/crates/bevy_graph/src/algos/mod.rs b/crates/bevy_graph/src/algos/mod.rs new file mode 100644 index 0000000000000..02523080fe46f --- /dev/null +++ b/crates/bevy_graph/src/algos/mod.rs @@ -0,0 +1 @@ +pub mod bfs; diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs index b3d45270e3e27..3bbda3b295b59 100644 --- a/crates/bevy_graph/src/error.rs +++ b/crates/bevy_graph/src/error.rs @@ -1,5 +1,6 @@ use crate::NodeIdx; +#[derive(Debug)] pub enum GraphError { NodeDoesntExist(NodeIdx), } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index adad4a6f86990..342f1e49bfdb5 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -47,6 +47,11 @@ impl Graph for SimpleListGraph } } + #[inline] + fn len(&self) -> usize { + self.nodes.len() + } + #[inline] fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { if let Some(idx) = self diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 3402f23afc2ff..1c0f98f66abb0 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -48,6 +48,11 @@ impl Graph for SimpleMapGraph } } + #[inline] + fn len(&self) -> usize { + self.nodes.len() + } + #[inline] fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { self.adjacencies diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index e1788a559f08a..b633ea3eebaa6 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -1,3 +1,4 @@ +pub mod algos; pub mod error; pub mod graphs; @@ -27,6 +28,8 @@ pub trait Graph { fn node(&self, idx: NodeIdx) -> GraphResult<&N>; fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; + fn len(&self) -> usize; + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; fn get_edge(&self, edge: EdgeIdx) -> Option<&E>; From 803efc028f9ed87cd9068d0e0ac12ea0a58c18ab Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 18:19:45 +0100 Subject: [PATCH 027/183] Better BFS Api --- crates/bevy_graph/src/algos/bfs.rs | 52 +++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 94aaca59b3322..ba6e8cd9f7bd2 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -4,20 +4,33 @@ use hashbrown::HashSet; use crate::{Graph, NodeIdx}; -pub fn breadth_first_search(start: NodeIdx, graph: &impl Graph, visitor: fn(&N)) { - let mut queue = VecDeque::new(); - let mut visited = HashSet::with_capacity(graph.len()); - - visited.insert(start); - queue.push_back(start); - - while let Some(node) = queue.pop_front() { - visitor(graph.node(node).unwrap()); - for (idx, _) in graph.edges_of(node) { - if !visited.contains(&idx) { - visited.insert(idx); - queue.push_back(idx); +pub struct BreadthFirstSearch { + queue: VecDeque, + visited: HashSet, +} + +impl BreadthFirstSearch { + pub fn new(start: NodeIdx, graph: &impl Graph) -> Self { + let mut queue = VecDeque::new(); + let mut visited = HashSet::with_capacity(graph.len()); + + visited.insert(start); + queue.push_back(start); + + Self { queue, visited } + } + + pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { + if let Some(node) = self.queue.pop_front() { + for (idx, _) in graph.edges_of(node) { + if !self.visited.contains(&idx) { + self.visited.insert(idx); + self.queue.push_back(idx); + } } + Some(graph.node(node).unwrap()) + } else { + None } } } @@ -26,7 +39,7 @@ pub fn breadth_first_search(start: NodeIdx, graph: &impl Graph, visi mod test { use crate::{graphs::simple::SimpleMapGraph, DirectedGraph, Graph}; - use super::breadth_first_search; + use super::BreadthFirstSearch; #[test] fn bfs() { @@ -37,12 +50,21 @@ mod test { let two = map.new_node(2); let three = map.new_node(3); + let sum = 0 + 1 + 2 + 3; + map.new_edge(zero, one, ()); map.new_edge(zero, two, ()); map.new_edge(one, two, ()); map.new_edge(two, zero, ()); map.new_edge(two, three, ()); - breadth_first_search(zero, &map, |value| println!("{value}")); + let mut counter = 0; + + let mut bfs = BreadthFirstSearch::new(zero, &map); + while let Some(node) = bfs.next(&map) { + counter += node; + } + + assert_eq!(sum, counter); } } From 499db7075550ef28791d76d6c9e5c0d16c0d198e Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 18:20:34 +0100 Subject: [PATCH 028/183] Mutable Iteration for BFS --- crates/bevy_graph/src/algos/bfs.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index ba6e8cd9f7bd2..8ac01e01870a2 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -33,6 +33,20 @@ impl BreadthFirstSearch { None } } + + pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { + if let Some(node) = self.queue.pop_front() { + for (idx, _) in graph.edges_of(node) { + if !self.visited.contains(&idx) { + self.visited.insert(idx); + self.queue.push_back(idx); + } + } + Some(graph.node_mut(node).unwrap()) + } else { + None + } + } } #[cfg(test)] From 8b0031b4b78cd8b785312f27bf58f2557457058e Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 18:21:35 +0100 Subject: [PATCH 029/183] allow(clippy::len_without_is_empty) --- crates/bevy_graph/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index b633ea3eebaa6..9a382dfc4ebec 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -22,6 +22,7 @@ impl EdgeIdx { } } +#[allow(clippy::len_without_is_empty)] pub trait Graph { fn new_node(&mut self, node: N) -> NodeIdx; From 6e8725cbcd3c4a0f163bfb8c2695ee3fda81242b Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 18:26:13 +0100 Subject: [PATCH 030/183] ok clippy ill just write it --- crates/bevy_graph/src/algos/bfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 8ac01e01870a2..65ea576f8e3fa 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -64,7 +64,7 @@ mod test { let two = map.new_node(2); let three = map.new_node(3); - let sum = 0 + 1 + 2 + 3; + let sum = 6; // 0 + 1 + 2 + 3 map.new_edge(zero, one, ()); map.new_edge(zero, two, ()); From daa464612a659d70fdd96eed59f32ce503c63a10 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 18:36:59 +0100 Subject: [PATCH 031/183] Auto trait function for algos --- crates/bevy_graph/src/algos/bfs.rs | 8 +++----- crates/bevy_graph/src/lib.rs | 6 ++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 65ea576f8e3fa..cc53cd0b913f1 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -10,9 +10,9 @@ pub struct BreadthFirstSearch { } impl BreadthFirstSearch { - pub fn new(start: NodeIdx, graph: &impl Graph) -> Self { + pub fn new(start: NodeIdx, len: usize) -> Self { let mut queue = VecDeque::new(); - let mut visited = HashSet::with_capacity(graph.len()); + let mut visited = HashSet::with_capacity(len); visited.insert(start); queue.push_back(start); @@ -53,8 +53,6 @@ impl BreadthFirstSearch { mod test { use crate::{graphs::simple::SimpleMapGraph, DirectedGraph, Graph}; - use super::BreadthFirstSearch; - #[test] fn bfs() { let mut map = SimpleMapGraph::::new(); @@ -74,7 +72,7 @@ mod test { let mut counter = 0; - let mut bfs = BreadthFirstSearch::new(zero, &map); + let mut bfs = map.algo_bfs(zero); while let Some(node) = bfs.next(&map) { counter += node; } diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index 9a382dfc4ebec..090207c5cb9c9 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -2,6 +2,7 @@ pub mod algos; pub mod error; pub mod graphs; +use algos::bfs::BreadthFirstSearch; use error::GraphResult; use slotmap::new_key_type; @@ -37,6 +38,11 @@ pub trait Graph { fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? + + #[inline] + fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { + BreadthFirstSearch::new(start, self.len()) + } } pub trait UndirectedGraph { From b815eb3465466e564de8dbc28131ad17c332efab Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 20:00:03 +0100 Subject: [PATCH 032/183] Store connected Nodes for Edge --- crates/bevy_graph/src/graphs/mod.rs | 9 ++++++++ crates/bevy_graph/src/graphs/simple/list.rs | 23 ++++++++++++++------- crates/bevy_graph/src/graphs/simple/map.rs | 23 ++++++++++++++------- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index b252f36bf9e71..3d9a89014f08c 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -1 +1,10 @@ +use crate::NodeIdx; + pub mod simple; + +#[derive(Clone)] +pub struct Edge { + pub src: NodeIdx, + pub dst: NodeIdx, + pub data: E, +} diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 342f1e49bfdb5..57fb1c77af7ef 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -2,13 +2,14 @@ use slotmap::{HopSlotMap, Key, SecondaryMap}; use crate::{ error::{GraphError, GraphResult}, + graphs::Edge, DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph, }; #[derive(Clone)] pub struct SimpleListGraph { nodes: HopSlotMap, - edges: HopSlotMap, + edges: HopSlotMap>, adjacencies: SecondaryMap>, } @@ -69,12 +70,12 @@ impl Graph for SimpleListGraph #[inline] fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { - self.edges.get(edge) + self.edges.get(edge).map(|e| &e.data) } #[inline] fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { - self.edges.get_mut(edge) + self.edges.get_mut(edge).map(|e| &mut e.data) } fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { @@ -84,7 +85,11 @@ impl Graph for SimpleListGraph impl UndirectedGraph for SimpleListGraph { fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(edge); + let idx = self.edges.insert(Edge { + src: node, + dst: other, + data: edge, + }); self.adjacencies.get_mut(node).unwrap().push((other, idx)); self.adjacencies.get_mut(other).unwrap().push((node, idx)); idx @@ -104,7 +109,7 @@ impl UndirectedGraph for SimpleListGraph { list.swap_remove(index); // TODO: remove or swap_remove ? } - self.edges.remove(edge_idx) + self.edges.remove(edge_idx).map(|e| e.data) } else { None } @@ -113,7 +118,11 @@ impl UndirectedGraph for SimpleListGraph { impl DirectedGraph for SimpleListGraph { fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(edge); + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); self.adjacencies.get_mut(from).unwrap().push((to, idx)); idx } @@ -124,7 +133,7 @@ impl DirectedGraph for SimpleListGraph { if let Some(index) = list.iter().position(|(node_idx, _)| *node_idx == to) { let (_, edge_idx) = list.swap_remove(index); // TODO: remove or swap_remove ? - self.edges.remove(edge_idx) + self.edges.remove(edge_idx).map(|e| e.data) } else { None } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 1c0f98f66abb0..b194b08462481 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -3,13 +3,14 @@ use slotmap::{HopSlotMap, Key, SecondaryMap}; use crate::{ error::{GraphError, GraphResult}, + graphs::Edge, DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph, }; #[derive(Clone)] pub struct SimpleMapGraph { nodes: HopSlotMap, - edges: HopSlotMap, + edges: HopSlotMap>, adjacencies: SecondaryMap>, } @@ -65,12 +66,12 @@ impl Graph for SimpleMapGraph #[inline] fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { - self.edges.get(edge) + self.edges.get(edge).map(|e| &e.data) } #[inline] fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { - self.edges.get_mut(edge) + self.edges.get_mut(edge).map(|e| &mut e.data) } fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { @@ -85,7 +86,11 @@ impl Graph for SimpleMapGraph impl UndirectedGraph for SimpleMapGraph { fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(edge); + let idx = self.edges.insert(Edge { + src: node, + dst: other, + data: edge, + }); self.adjacencies.get_mut(node).unwrap().insert(other, idx); self.adjacencies.get_mut(other).unwrap().insert(node, idx); idx @@ -96,13 +101,17 @@ impl UndirectedGraph for SimpleMapGraph { self.adjacencies.get_mut(other)?.remove(&node); - self.edges.remove(edge_idx) + self.edges.remove(edge_idx).map(|e| e.data) } } impl DirectedGraph for SimpleMapGraph { fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(edge); + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); self.adjacencies.get_mut(from).unwrap().insert(to, idx); idx } @@ -110,7 +119,7 @@ impl DirectedGraph for SimpleMapGraph { fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) -> Option { let edge_idx = self.adjacencies.get_mut(from)?.remove(&to)?; - self.edges.remove(edge_idx) + self.edges.remove(edge_idx).map(|e| e.data) } } From bbbef820372db6b38cca68078878c8e9db76e45b Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 20:04:56 +0100 Subject: [PATCH 033/183] Restructuring crate --- crates/bevy_graph/src/algos/bfs.rs | 4 +- crates/bevy_graph/src/error.rs | 2 +- crates/bevy_graph/src/graphs/edge.rs | 8 +++ crates/bevy_graph/src/graphs/keys.rs | 20 ++++++++ crates/bevy_graph/src/graphs/mod.rs | 47 +++++++++++++++--- crates/bevy_graph/src/graphs/simple/list.rs | 9 ++-- crates/bevy_graph/src/graphs/simple/map.rs | 9 ++-- crates/bevy_graph/src/lib.rs | 55 --------------------- 8 files changed, 83 insertions(+), 71 deletions(-) create mode 100644 crates/bevy_graph/src/graphs/edge.rs create mode 100644 crates/bevy_graph/src/graphs/keys.rs diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index cc53cd0b913f1..e5fb7c6ab7df3 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -2,7 +2,7 @@ use std::collections::VecDeque; use hashbrown::HashSet; -use crate::{Graph, NodeIdx}; +use crate::graphs::{keys::NodeIdx, Graph}; pub struct BreadthFirstSearch { queue: VecDeque, @@ -51,7 +51,7 @@ impl BreadthFirstSearch { #[cfg(test)] mod test { - use crate::{graphs::simple::SimpleMapGraph, DirectedGraph, Graph}; + use crate::graphs::{simple::SimpleMapGraph, DirectedGraph, Graph}; #[test] fn bfs() { diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs index 3bbda3b295b59..c53df297d8fa4 100644 --- a/crates/bevy_graph/src/error.rs +++ b/crates/bevy_graph/src/error.rs @@ -1,4 +1,4 @@ -use crate::NodeIdx; +use crate::graphs::keys::NodeIdx; #[derive(Debug)] pub enum GraphError { diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs new file mode 100644 index 0000000000000..41f0075cdbc73 --- /dev/null +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -0,0 +1,8 @@ +use super::keys::NodeIdx; + +#[derive(Clone)] +pub struct Edge { + pub src: NodeIdx, + pub dst: NodeIdx, + pub data: E, +} diff --git a/crates/bevy_graph/src/graphs/keys.rs b/crates/bevy_graph/src/graphs/keys.rs new file mode 100644 index 0000000000000..bc5855bc78d4c --- /dev/null +++ b/crates/bevy_graph/src/graphs/keys.rs @@ -0,0 +1,20 @@ +use slotmap::new_key_type; + +use super::Graph; + +new_key_type! { + pub struct NodeIdx; + pub struct EdgeIdx; +} + +impl EdgeIdx { + #[inline] + pub fn get(self, graph: &impl Graph) -> Option<&E> { + graph.get_edge(self) + } + + #[inline] + pub fn get_mut(self, graph: &mut impl Graph) -> Option<&mut E> { + graph.get_edge_mut(self) + } +} diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 3d9a89014f08c..a6a92770e64bc 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -1,10 +1,43 @@ -use crate::NodeIdx; - pub mod simple; -#[derive(Clone)] -pub struct Edge { - pub src: NodeIdx, - pub dst: NodeIdx, - pub data: E, +pub mod edge; +pub mod keys; + +use crate::algos::bfs::BreadthFirstSearch; +use crate::error::GraphResult; + +use self::keys::{EdgeIdx, NodeIdx}; + +#[allow(clippy::len_without_is_empty)] +pub trait Graph { + fn new_node(&mut self, node: N) -> NodeIdx; + + fn node(&self, idx: NodeIdx) -> GraphResult<&N>; + fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; + + fn len(&self) -> usize; + + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; + + fn get_edge(&self, edge: EdgeIdx) -> Option<&E>; + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; + + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? + + #[inline] + fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { + BreadthFirstSearch::new(start, self.len()) + } +} + +pub trait UndirectedGraph { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; + + fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx) -> Option; +} + +pub trait DirectedGraph { + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx; + + fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) -> Option; } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 57fb1c77af7ef..e3b1aa4be5752 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -2,8 +2,11 @@ use slotmap::{HopSlotMap, Key, SecondaryMap}; use crate::{ error::{GraphError, GraphResult}, - graphs::Edge, - DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph, + graphs::{ + edge::Edge, + keys::{EdgeIdx, NodeIdx}, + DirectedGraph, Graph, UndirectedGraph, + }, }; #[derive(Clone)] @@ -149,7 +152,7 @@ impl Default for SimpleListGraph { #[cfg(test)] mod test { - use crate::{DirectedGraph, Graph, UndirectedGraph}; + use crate::graphs::{DirectedGraph, Graph, UndirectedGraph}; use super::SimpleListGraph; diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index b194b08462481..76dc6e6103378 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -3,8 +3,11 @@ use slotmap::{HopSlotMap, Key, SecondaryMap}; use crate::{ error::{GraphError, GraphResult}, - graphs::Edge, - DirectedGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph, + graphs::{ + edge::Edge, + keys::{EdgeIdx, NodeIdx}, + DirectedGraph, Graph, UndirectedGraph, + }, }; #[derive(Clone)] @@ -132,7 +135,7 @@ impl Default for SimpleMapGraph { #[cfg(test)] mod test { - use crate::{DirectedGraph, Graph, UndirectedGraph}; + use crate::graphs::{DirectedGraph, Graph, UndirectedGraph}; use super::SimpleMapGraph; diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index 090207c5cb9c9..fb18c8af9443d 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -1,58 +1,3 @@ pub mod algos; pub mod error; pub mod graphs; - -use algos::bfs::BreadthFirstSearch; -use error::GraphResult; -use slotmap::new_key_type; - -new_key_type! { - pub struct NodeIdx; - pub struct EdgeIdx; -} - -impl EdgeIdx { - #[inline] - pub fn get(self, graph: &impl Graph) -> Option<&E> { - graph.get_edge(self) - } - - #[inline] - pub fn get_mut(self, graph: &mut impl Graph) -> Option<&mut E> { - graph.get_edge_mut(self) - } -} - -#[allow(clippy::len_without_is_empty)] -pub trait Graph { - fn new_node(&mut self, node: N) -> NodeIdx; - - fn node(&self, idx: NodeIdx) -> GraphResult<&N>; - fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; - - fn len(&self) -> usize; - - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; - - fn get_edge(&self, edge: EdgeIdx) -> Option<&E>; - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; - - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? - - #[inline] - fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { - BreadthFirstSearch::new(start, self.len()) - } -} - -pub trait UndirectedGraph { - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; - - fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx) -> Option; -} - -pub trait DirectedGraph { - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx; - - fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) -> Option; -} From e19e3205eb635983edca6f9a62189496a114ddaf Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 20:27:10 +0100 Subject: [PATCH 034/183] Use the new data from edge to simplify edge-remove --- crates/bevy_graph/src/error.rs | 3 +- crates/bevy_graph/src/graphs/edge.rs | 7 +++ crates/bevy_graph/src/graphs/keys.rs | 16 +++++- crates/bevy_graph/src/graphs/mod.rs | 4 +- crates/bevy_graph/src/graphs/simple/list.rs | 60 +++++++++++++-------- crates/bevy_graph/src/graphs/simple/map.rs | 33 ++++++++---- 6 files changed, 88 insertions(+), 35 deletions(-) diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs index c53df297d8fa4..e17c8404ac2cf 100644 --- a/crates/bevy_graph/src/error.rs +++ b/crates/bevy_graph/src/error.rs @@ -1,8 +1,9 @@ -use crate::graphs::keys::NodeIdx; +use crate::graphs::keys::{EdgeIdx, NodeIdx}; #[derive(Debug)] pub enum GraphError { NodeDoesntExist(NodeIdx), + EdgeDoesntExist(EdgeIdx), } pub type GraphResult = Result; diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs index 41f0075cdbc73..5c2dff9a26f7a 100644 --- a/crates/bevy_graph/src/graphs/edge.rs +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -6,3 +6,10 @@ pub struct Edge { pub dst: NodeIdx, pub data: E, } + +impl Edge { + #[inline] + pub fn indices(&self) -> (NodeIdx, NodeIdx) { + (self.src, self.dst) + } +} diff --git a/crates/bevy_graph/src/graphs/keys.rs b/crates/bevy_graph/src/graphs/keys.rs index bc5855bc78d4c..3fd065c7e4f59 100644 --- a/crates/bevy_graph/src/graphs/keys.rs +++ b/crates/bevy_graph/src/graphs/keys.rs @@ -1,6 +1,8 @@ use slotmap::new_key_type; -use super::Graph; +use crate::error::GraphResult; + +use super::{DirectedGraph, Graph, UndirectedGraph}; new_key_type! { pub struct NodeIdx; @@ -17,4 +19,16 @@ impl EdgeIdx { pub fn get_mut(self, graph: &mut impl Graph) -> Option<&mut E> { graph.get_edge_mut(self) } + + #[inline] + // TODO: make them 1 function when reorganizing traits + pub fn remove_directed(self, graph: &mut impl DirectedGraph) -> GraphResult { + graph.remove_edge(self) + } + + #[inline] + // TODO: make them 1 function when reorganizing traits + pub fn remove_undirected(self, graph: &mut impl UndirectedGraph) -> GraphResult { + graph.remove_edge(self) + } } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index a6a92770e64bc..9831af377dd3c 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -33,11 +33,11 @@ pub trait Graph { pub trait UndirectedGraph { fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; - fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx) -> Option; + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; } pub trait DirectedGraph { fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx; - fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) -> Option; + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index e3b1aa4be5752..ef1f880e1b596 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -98,27 +98,35 @@ impl UndirectedGraph for SimpleListGraph { idx } - fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx) -> Option { - let list = self.adjacencies.get_mut(node)?; + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { + let list = self.adjacencies.get_mut(node).unwrap(); - if let Some(index) = list - .iter() - .position(|(node_idx, _edge_idx)| *node_idx == other) - { - let (_, edge_idx) = list.swap_remove(index); // TODO: remove or swap_remove ? - - let list = self.adjacencies.get_mut(other)?; - if let Some(index) = list.iter().position(|(node_idx, _)| *node_idx == node) { + if let Some(index) = find_edge(list, other) { list.swap_remove(index); // TODO: remove or swap_remove ? - } - self.edges.remove(edge_idx).map(|e| e.data) + let list = self.adjacencies.get_mut(other).unwrap(); + if let Some(index) = find_edge(list, node) { + list.swap_remove(index); // TODO: remove or swap_remove ? + } + + Ok(self.edges.remove(edge).unwrap().data) + } else { + Err(GraphError::EdgeDoesntExist(edge)) + } } else { - None + Err(GraphError::EdgeDoesntExist(edge)) } } } +// Util function TODO: move +#[inline] +fn find_edge(list: &Vec<(NodeIdx, EdgeIdx)>, node: NodeIdx) -> Option { + list.iter() + .position(|(node_idx, _edge_idx)| *node_idx == node) +} + impl DirectedGraph for SimpleListGraph { fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { @@ -130,15 +138,19 @@ impl DirectedGraph for SimpleListGraph { idx } - fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) -> Option { - let list = self.adjacencies.get_mut(from).unwrap(); + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if let Some((from, to)) = self.edges.get(edge).map(|e| e.indices()) { + let list = self.adjacencies.get_mut(from).unwrap(); - if let Some(index) = list.iter().position(|(node_idx, _)| *node_idx == to) { - let (_, edge_idx) = list.swap_remove(index); // TODO: remove or swap_remove ? + if let Some(index) = find_edge(list, to) { + list.swap_remove(index); // TODO: remove or swap_remove ? - self.edges.remove(edge_idx).map(|e| e.data) + Ok(self.edges.remove(edge).unwrap().data) + } else { + Err(GraphError::EdgeDoesntExist(edge)) + } } else { - None + Err(GraphError::EdgeDoesntExist(edge)) } } } @@ -183,7 +195,10 @@ mod test { assert_eq!(list_graph.edges_of(jake), vec![(michael, best_friends)]); assert_eq!(list_graph.edges_of(michael), vec![(jake, best_friends)]); - list_graph.remove_edge_between(michael, jake); + assert!(list_graph + .edge_between(michael, jake) + .remove_undirected(&mut list_graph) + .is_ok()); let strength_jake = list_graph.edge_between(jake, michael).get(&list_graph); assert!(strength_jake.is_none()); @@ -212,7 +227,10 @@ mod test { assert_eq!(list_graph.edges_of(jake), vec![(jennifer, oneway_crush)]); assert_eq!(list_graph.edges_of(jennifer), vec![]); - list_graph.remove_edge_between(jake, jennifer); + assert!(list_graph + .edge_between(jake, jennifer) + .remove_directed(&mut list_graph) + .is_ok()); let strength_jake = list_graph.edge_between(jake, jennifer).get(&list_graph); assert!(strength_jake.is_none()); diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 76dc6e6103378..9df52a76e6991 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -99,12 +99,15 @@ impl UndirectedGraph for SimpleMapGraph { idx } - fn remove_edge_between(&mut self, node: NodeIdx, other: NodeIdx) -> Option { - let edge_idx = self.adjacencies.get_mut(node)?.remove(&other)?; + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { + self.adjacencies.get_mut(node).unwrap().remove(&other); + self.adjacencies.get_mut(other).unwrap().remove(&node); - self.adjacencies.get_mut(other)?.remove(&node); - - self.edges.remove(edge_idx).map(|e| e.data) + Ok(self.edges.remove(edge).unwrap().data) + } else { + Err(GraphError::EdgeDoesntExist(edge)) + } } } @@ -119,10 +122,14 @@ impl DirectedGraph for SimpleMapGraph { idx } - fn remove_edge_between(&mut self, from: NodeIdx, to: NodeIdx) -> Option { - let edge_idx = self.adjacencies.get_mut(from)?.remove(&to)?; + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if let Some((from, to)) = self.edges.get(edge).map(|e| e.indices()) { + self.adjacencies.get_mut(from).unwrap().remove(&to); - self.edges.remove(edge_idx).map(|e| e.data) + Ok(self.edges.remove(edge).unwrap().data) + } else { + Err(GraphError::EdgeDoesntExist(edge)) + } } } @@ -167,7 +174,10 @@ mod test { assert_eq!(map_graph.edges_of(jake), vec![(michael, best_friends)]); assert_eq!(map_graph.edges_of(michael), vec![(jake, best_friends)]); - map_graph.remove_edge_between(michael, jake); + assert!(map_graph + .edge_between(michael, jake) + .remove_undirected(&mut map_graph) + .is_ok()); let strength_jake = map_graph.edge_between(jake, michael).get(&map_graph); assert!(strength_jake.is_none()); @@ -197,7 +207,10 @@ mod test { assert_eq!(map_graph.edges_of(jake), vec![(jennifer, oneway_crush)]); assert_eq!(map_graph.edges_of(jennifer), vec![]); - map_graph.remove_edge_between(jake, jennifer); + assert!(map_graph + .edge_between(jake, jennifer) + .remove_directed(&mut map_graph) + .is_ok()); let strength_jake = map_graph.edge_between(jake, jennifer).get(&map_graph); assert!(strength_jake.is_none()); From 73b59b02597bac1fc827c3c0b1d1c577f01c01cc Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 20:37:41 +0100 Subject: [PATCH 035/183] Fix benchmarks --- benches/benches/bevy_graph/map.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/benches/benches/bevy_graph/map.rs b/benches/benches/bevy_graph/map.rs index 7e3bce30d2e86..64f9d2ff70723 100644 --- a/benches/benches/bevy_graph/map.rs +++ b/benches/benches/bevy_graph/map.rs @@ -1,4 +1,8 @@ -use bevy_graph::{graphs::simple::SimpleMapGraph, EdgeIdx, Graph, NodeIdx, UndirectedGraph}; +use bevy_graph::graphs::{ + keys::{EdgeIdx, NodeIdx}, + simple::SimpleMapGraph, + Graph, UndirectedGraph, +}; use bevy_utils::Duration; use criterion::{black_box, criterion_group, criterion_main, Criterion}; @@ -41,7 +45,12 @@ fn nodes_10_000_undirected(c: &mut Criterion) { c.bench_function("nodes_10_000_remove_edge", |b| { b.iter(|| { for i in 1..10_000 { - black_box(map_graph.remove_edge_between(nodes[i - 1], nodes[i])); + black_box( + map_graph + .edge_between(nodes[i - 1], nodes[i]) + .remove_undirected(&mut map_graph) + .unwrap(), + ); } }) }); From e3e791d9cb092418e256e9e98d3c20f48826622a Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 10 Jan 2023 20:54:18 +0100 Subject: [PATCH 036/183] CI... --- crates/bevy_graph/src/graphs/simple/list.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index ef1f880e1b596..06eaf87baa04f 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -120,13 +120,6 @@ impl UndirectedGraph for SimpleListGraph { } } -// Util function TODO: move -#[inline] -fn find_edge(list: &Vec<(NodeIdx, EdgeIdx)>, node: NodeIdx) -> Option { - list.iter() - .position(|(node_idx, _edge_idx)| *node_idx == node) -} - impl DirectedGraph for SimpleListGraph { fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { @@ -162,6 +155,13 @@ impl Default for SimpleListGraph { } } +// Util function +#[inline] +fn find_edge(list: &[(NodeIdx, EdgeIdx)], node: NodeIdx) -> Option { + list.iter() + .position(|(node_idx, _edge_idx)| *node_idx == node) +} + #[cfg(test)] mod test { use crate::graphs::{DirectedGraph, Graph, UndirectedGraph}; From 4fad13e7ce5b8a11aab861617802b19036bb2370 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 11 Jan 2023 16:41:06 +0100 Subject: [PATCH 037/183] Restructed traits --- crates/bevy_graph/src/algos/bfs.rs | 2 +- crates/bevy_graph/src/graphs/keys.rs | 15 +-- crates/bevy_graph/src/graphs/mod.rs | 39 +++--- crates/bevy_graph/src/graphs/simple/list.rs | 125 ++++++++++++-------- crates/bevy_graph/src/graphs/simple/map.rs | 123 +++++++++++-------- 5 files changed, 175 insertions(+), 129 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index e5fb7c6ab7df3..22f57dfbac51e 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -51,7 +51,7 @@ impl BreadthFirstSearch { #[cfg(test)] mod test { - use crate::graphs::{simple::SimpleMapGraph, DirectedGraph, Graph}; + use crate::graphs::{simple::SimpleMapGraph, Graph, NewEdge, NewNode}; #[test] fn bfs() { diff --git a/crates/bevy_graph/src/graphs/keys.rs b/crates/bevy_graph/src/graphs/keys.rs index 3fd065c7e4f59..750b640a223cf 100644 --- a/crates/bevy_graph/src/graphs/keys.rs +++ b/crates/bevy_graph/src/graphs/keys.rs @@ -2,7 +2,7 @@ use slotmap::new_key_type; use crate::error::GraphResult; -use super::{DirectedGraph, Graph, UndirectedGraph}; +use super::{GetEdge, NewEdge}; new_key_type! { pub struct NodeIdx; @@ -11,24 +11,17 @@ new_key_type! { impl EdgeIdx { #[inline] - pub fn get(self, graph: &impl Graph) -> Option<&E> { + pub fn get(self, graph: &impl GetEdge) -> Option<&E> { graph.get_edge(self) } #[inline] - pub fn get_mut(self, graph: &mut impl Graph) -> Option<&mut E> { + pub fn get_mut(self, graph: &mut impl GetEdge) -> Option<&mut E> { graph.get_edge_mut(self) } #[inline] - // TODO: make them 1 function when reorganizing traits - pub fn remove_directed(self, graph: &mut impl DirectedGraph) -> GraphResult { - graph.remove_edge(self) - } - - #[inline] - // TODO: make them 1 function when reorganizing traits - pub fn remove_undirected(self, graph: &mut impl UndirectedGraph) -> GraphResult { + pub fn remove(self, graph: &mut impl NewEdge) -> GraphResult { graph.remove_edge(self) } } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 9831af377dd3c..b558ad23c2676 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -8,36 +8,37 @@ use crate::error::GraphResult; use self::keys::{EdgeIdx, NodeIdx}; +pub trait Graph: NewNode + GetNode + NewEdge + GetEdge + EdgeUtils { + #[inline] + fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { + BreadthFirstSearch::new(start, self.len()) + } +} + #[allow(clippy::len_without_is_empty)] -pub trait Graph { +pub trait NewNode { fn new_node(&mut self, node: N) -> NodeIdx; - fn node(&self, idx: NodeIdx) -> GraphResult<&N>; - fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; - fn len(&self) -> usize; +} - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; - - fn get_edge(&self, edge: EdgeIdx) -> Option<&E>; - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; - - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? - - #[inline] - fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { - BreadthFirstSearch::new(start, self.len()) - } +pub trait GetNode { + fn node(&self, idx: NodeIdx) -> GraphResult<&N>; + fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; } -pub trait UndirectedGraph { +pub trait NewEdge { fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; } -pub trait DirectedGraph { - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx; +pub trait GetEdge { + fn get_edge(&self, edge: EdgeIdx) -> Option<&E>; + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; +} - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; +pub trait EdgeUtils { + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 06eaf87baa04f..bfe2b77350eeb 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -5,7 +5,7 @@ use crate::{ graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, - DirectedGraph, Graph, UndirectedGraph, + EdgeUtils, GetEdge, GetNode, Graph, NewEdge, NewNode, }, }; @@ -26,13 +26,21 @@ impl SimpleListGraph { } } -impl Graph for SimpleListGraph { +impl NewNode for SimpleListGraph { + #[inline] fn new_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, Vec::new()); idx } + #[inline] + fn len(&self) -> usize { + self.nodes.len() + } +} + +impl GetNode for SimpleListGraph { #[inline] fn node(&self, idx: NodeIdx) -> GraphResult<&N> { if let Some(node) = self.nodes.get(idx) { @@ -50,43 +58,9 @@ impl Graph for SimpleListGraph Err(GraphError::NodeDoesntExist(idx)) } } - - #[inline] - fn len(&self) -> usize { - self.nodes.len() - } - - #[inline] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - if let Some(idx) = self - .adjacencies - .get(from) - .unwrap() - .iter() - .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) - { - idx - } else { - EdgeIdx::null() - } - } - - #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { - self.edges.get(edge).map(|e| &e.data) - } - - #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { - self.edges.get_mut(edge).map(|e| &mut e.data) - } - - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - self.adjacencies.get(node).unwrap().to_vec() - } } -impl UndirectedGraph for SimpleListGraph { +impl NewEdge for SimpleListGraph { fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { src: node, @@ -120,7 +94,7 @@ impl UndirectedGraph for SimpleListGraph { } } -impl DirectedGraph for SimpleListGraph { +impl NewEdge for SimpleListGraph { fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { src: from, @@ -148,6 +122,43 @@ impl DirectedGraph for SimpleListGraph { } } +impl GetEdge for SimpleListGraph { + #[inline] + fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { + self.edges.get(edge).map(|e| &e.data) + } + + #[inline] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + self.edges.get_mut(edge).map(|e| &mut e.data) + } +} + +impl EdgeUtils for SimpleListGraph { + #[inline] + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + if let Some(idx) = self + .adjacencies + .get(from) + .unwrap() + .iter() + .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) + { + idx + } else { + EdgeIdx::null() + } + } + + #[inline] + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + self.adjacencies.get(node).unwrap().to_vec() + } +} + +impl Graph for SimpleListGraph {} +impl Graph for SimpleListGraph {} + impl Default for SimpleListGraph { #[inline] fn default() -> Self { @@ -164,7 +175,7 @@ fn find_edge(list: &[(NodeIdx, EdgeIdx)], node: NodeIdx) -> Option { #[cfg(test)] mod test { - use crate::graphs::{DirectedGraph, Graph, UndirectedGraph}; + use crate::graphs::{EdgeUtils, NewEdge, NewNode}; use super::SimpleListGraph; @@ -184,11 +195,15 @@ mod test { let michael = list_graph.new_node(Person::Michael); let best_friends = list_graph.new_edge(jake, michael, STRENGTH); - let strength_jake = list_graph.edge_between(jake, michael).get(&list_graph); + let strength_jake = list_graph + .edge_between(jake, michael) + .get::(&list_graph); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_michael = list_graph.edge_between(michael, jake).get(&list_graph); + let strength_michael = list_graph + .edge_between(michael, jake) + .get::(&list_graph); assert!(strength_michael.is_some()); assert_eq!(strength_michael.unwrap(), &STRENGTH); @@ -197,13 +212,17 @@ mod test { assert!(list_graph .edge_between(michael, jake) - .remove_undirected(&mut list_graph) + .remove::(&mut list_graph) .is_ok()); - let strength_jake = list_graph.edge_between(jake, michael).get(&list_graph); + let strength_jake = list_graph + .edge_between(jake, michael) + .get::(&list_graph); assert!(strength_jake.is_none()); - let strength_michael = list_graph.edge_between(michael, jake).get(&list_graph); + let strength_michael = list_graph + .edge_between(michael, jake) + .get::(&list_graph); assert!(strength_michael.is_none()); } @@ -217,11 +236,15 @@ mod test { let jennifer = list_graph.new_node(Person::Jennifer); let oneway_crush = list_graph.new_edge(jake, jennifer, STRENGTH); - let strength_jake = list_graph.edge_between(jake, jennifer).get(&list_graph); + let strength_jake = list_graph + .edge_between(jake, jennifer) + .get::(&list_graph); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_jennifer = list_graph.edge_between(jennifer, jake).get(&list_graph); + let strength_jennifer = list_graph + .edge_between(jennifer, jake) + .get::(&list_graph); assert!(strength_jennifer.is_none()); assert_eq!(list_graph.edges_of(jake), vec![(jennifer, oneway_crush)]); @@ -229,13 +252,17 @@ mod test { assert!(list_graph .edge_between(jake, jennifer) - .remove_directed(&mut list_graph) + .remove::(&mut list_graph) .is_ok()); - let strength_jake = list_graph.edge_between(jake, jennifer).get(&list_graph); + let strength_jake = list_graph + .edge_between(jake, jennifer) + .get::(&list_graph); assert!(strength_jake.is_none()); - let strength_jennifer = list_graph.edge_between(jennifer, jake).get(&list_graph); + let strength_jennifer = list_graph + .edge_between(jennifer, jake) + .get::(&list_graph); assert!(strength_jennifer.is_none()); } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 9df52a76e6991..fd82a735ca88d 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -6,7 +6,7 @@ use crate::{ graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, - DirectedGraph, Graph, UndirectedGraph, + EdgeUtils, GetEdge, GetNode, Graph, NewEdge, NewNode, }, }; @@ -27,13 +27,20 @@ impl SimpleMapGraph { } } -impl Graph for SimpleMapGraph { +impl NewNode for SimpleMapGraph { fn new_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, HashMap::new()); idx } + #[inline] + fn len(&self) -> usize { + self.nodes.len() + } +} + +impl GetNode for SimpleMapGraph { #[inline] fn node(&self, idx: NodeIdx) -> GraphResult<&N> { if let Some(node) = self.nodes.get(idx) { @@ -51,43 +58,9 @@ impl Graph for SimpleMapGraph Err(GraphError::NodeDoesntExist(idx)) } } - - #[inline] - fn len(&self) -> usize { - self.nodes.len() - } - - #[inline] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - self.adjacencies - .get(from) - .unwrap() - .get(&to) - .cloned() - .unwrap_or_else(EdgeIdx::null) - } - - #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { - self.edges.get(edge).map(|e| &e.data) - } - - #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { - self.edges.get_mut(edge).map(|e| &mut e.data) - } - - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - self.adjacencies - .get(node) - .unwrap() - .iter() - .map(|(node, edge)| (*node, *edge)) - .collect() - } } -impl UndirectedGraph for SimpleMapGraph { +impl NewEdge for SimpleMapGraph { fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { src: node, @@ -111,7 +84,7 @@ impl UndirectedGraph for SimpleMapGraph { } } -impl DirectedGraph for SimpleMapGraph { +impl NewEdge for SimpleMapGraph { fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { src: from, @@ -133,6 +106,42 @@ impl DirectedGraph for SimpleMapGraph { } } +impl GetEdge for SimpleMapGraph { + #[inline] + fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { + self.edges.get(edge).map(|e| &e.data) + } + + #[inline] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + self.edges.get_mut(edge).map(|e| &mut e.data) + } +} + +impl EdgeUtils for SimpleMapGraph { + #[inline] + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + self.adjacencies + .get(from) + .unwrap() + .get(&to) + .cloned() + .unwrap_or_else(EdgeIdx::null) + } + + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + self.adjacencies + .get(node) + .unwrap() + .iter() + .map(|(node, edge)| (*node, *edge)) + .collect() + } +} + +impl Graph for SimpleMapGraph {} +impl Graph for SimpleMapGraph {} + impl Default for SimpleMapGraph { #[inline] fn default() -> Self { @@ -142,7 +151,7 @@ impl Default for SimpleMapGraph { #[cfg(test)] mod test { - use crate::graphs::{DirectedGraph, Graph, UndirectedGraph}; + use crate::graphs::{EdgeUtils, NewEdge, NewNode}; use super::SimpleMapGraph; @@ -163,11 +172,15 @@ mod test { let best_friends = map_graph.new_edge(jake, michael, STRENGTH); - let strength_jake = map_graph.edge_between(jake, michael).get(&map_graph); + let strength_jake = map_graph + .edge_between(jake, michael) + .get::(&map_graph); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_michael = map_graph.edge_between(michael, jake).get(&map_graph); + let strength_michael = map_graph + .edge_between(michael, jake) + .get::(&map_graph); assert!(strength_michael.is_some()); assert_eq!(strength_michael.unwrap(), &STRENGTH); @@ -176,13 +189,17 @@ mod test { assert!(map_graph .edge_between(michael, jake) - .remove_undirected(&mut map_graph) + .remove::(&mut map_graph) .is_ok()); - let strength_jake = map_graph.edge_between(jake, michael).get(&map_graph); + let strength_jake = map_graph + .edge_between(jake, michael) + .get::(&map_graph); assert!(strength_jake.is_none()); - let strength_michael = map_graph.edge_between(michael, jake).get(&map_graph); + let strength_michael = map_graph + .edge_between(michael, jake) + .get::(&map_graph); assert!(strength_michael.is_none()); } @@ -197,11 +214,15 @@ mod test { let oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); - let strength_jake = map_graph.edge_between(jake, jennifer).get(&map_graph); + let strength_jake = map_graph + .edge_between(jake, jennifer) + .get::(&map_graph); assert!(strength_jake.is_some()); assert_eq!(strength_jake.unwrap(), &STRENGTH); - let strength_jennifer = map_graph.edge_between(jennifer, jake).get(&map_graph); + let strength_jennifer = map_graph + .edge_between(jennifer, jake) + .get::(&map_graph); assert!(strength_jennifer.is_none()); assert_eq!(map_graph.edges_of(jake), vec![(jennifer, oneway_crush)]); @@ -209,13 +230,17 @@ mod test { assert!(map_graph .edge_between(jake, jennifer) - .remove_directed(&mut map_graph) + .remove::(&mut map_graph) .is_ok()); - let strength_jake = map_graph.edge_between(jake, jennifer).get(&map_graph); + let strength_jake = map_graph + .edge_between(jake, jennifer) + .get::(&map_graph); assert!(strength_jake.is_none()); - let strength_jennifer = map_graph.edge_between(jennifer, jake).get(&map_graph); + let strength_jennifer = map_graph + .edge_between(jennifer, jake) + .get::(&map_graph); assert!(strength_jennifer.is_none()); } } From 3db9d7ee209ae594b4b9e4fb82fa819697f3ddd4 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 11 Jan 2023 17:05:29 +0100 Subject: [PATCH 038/183] Another try of api --- crates/bevy_graph/src/algos/bfs.rs | 2 +- crates/bevy_graph/src/graphs/keys.rs | 8 +- crates/bevy_graph/src/graphs/mod.rs | 31 ++---- crates/bevy_graph/src/graphs/simple/list.rs | 105 ++++++++---------- crates/bevy_graph/src/graphs/simple/map.rs | 103 ++++++++--------- .../bevy_graph/src/graphs/trait_impl_util.rs | 56 ++++++++++ 6 files changed, 167 insertions(+), 138 deletions(-) create mode 100644 crates/bevy_graph/src/graphs/trait_impl_util.rs diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 22f57dfbac51e..4f3f28b334b14 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -51,7 +51,7 @@ impl BreadthFirstSearch { #[cfg(test)] mod test { - use crate::graphs::{simple::SimpleMapGraph, Graph, NewEdge, NewNode}; + use crate::graphs::{simple::SimpleMapGraph, Graph}; #[test] fn bfs() { diff --git a/crates/bevy_graph/src/graphs/keys.rs b/crates/bevy_graph/src/graphs/keys.rs index 750b640a223cf..a5cf8844eea61 100644 --- a/crates/bevy_graph/src/graphs/keys.rs +++ b/crates/bevy_graph/src/graphs/keys.rs @@ -2,7 +2,7 @@ use slotmap::new_key_type; use crate::error::GraphResult; -use super::{GetEdge, NewEdge}; +use super::Graph; new_key_type! { pub struct NodeIdx; @@ -11,17 +11,17 @@ new_key_type! { impl EdgeIdx { #[inline] - pub fn get(self, graph: &impl GetEdge) -> Option<&E> { + pub fn get(self, graph: &impl Graph) -> Option<&E> { graph.get_edge(self) } #[inline] - pub fn get_mut(self, graph: &mut impl GetEdge) -> Option<&mut E> { + pub fn get_mut(self, graph: &mut impl Graph) -> Option<&mut E> { graph.get_edge_mut(self) } #[inline] - pub fn remove(self, graph: &mut impl NewEdge) -> GraphResult { + pub fn remove(self, graph: &mut impl Graph) -> GraphResult { graph.remove_edge(self) } } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index b558ad23c2676..b48292ec92249 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -2,43 +2,34 @@ pub mod simple; pub mod edge; pub mod keys; +pub mod trait_impl_util; use crate::algos::bfs::BreadthFirstSearch; use crate::error::GraphResult; use self::keys::{EdgeIdx, NodeIdx}; -pub trait Graph: NewNode + GetNode + NewEdge + GetEdge + EdgeUtils { - #[inline] - fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { - BreadthFirstSearch::new(start, self.len()) - } -} - #[allow(clippy::len_without_is_empty)] -pub trait NewNode { - fn new_node(&mut self, node: N) -> NodeIdx; - +pub trait Graph { fn len(&self) -> usize; -} -pub trait GetNode { + fn new_node(&mut self, node: N) -> NodeIdx; + fn node(&self, idx: NodeIdx) -> GraphResult<&N>; fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; -} -pub trait NewEdge { fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; -} - -pub trait GetEdge { fn get_edge(&self, edge: EdgeIdx) -> Option<&E>; fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; -} -pub trait EdgeUtils { + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? + + #[inline] + fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { + BreadthFirstSearch::new(start, self.len()) + } } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index bfe2b77350eeb..1e4757ad74072 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -5,8 +5,9 @@ use crate::{ graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, - EdgeUtils, GetEdge, GetNode, Graph, NewEdge, NewNode, + Graph, }, + impl_graph, }; #[derive(Clone)] @@ -24,25 +25,21 @@ impl SimpleListGraph { adjacencies: SecondaryMap::new(), } } -} -impl NewNode for SimpleListGraph { #[inline] - fn new_node(&mut self, node: N) -> NodeIdx { + pub fn len(&self) -> usize { + self.nodes.len() + } + + #[inline] + pub fn new_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, Vec::new()); idx } #[inline] - fn len(&self) -> usize { - self.nodes.len() - } -} - -impl GetNode for SimpleListGraph { - #[inline] - fn node(&self, idx: NodeIdx) -> GraphResult<&N> { + pub fn node(&self, idx: NodeIdx) -> GraphResult<&N> { if let Some(node) = self.nodes.get(idx) { Ok(node) } else { @@ -51,17 +48,47 @@ impl GetNode for SimpleListGraph } #[inline] - fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + pub fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { if let Some(node) = self.nodes.get_mut(idx) { Ok(node) } else { Err(GraphError::NodeDoesntExist(idx)) } } + + #[inline] + pub fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { + self.edges.get(edge).map(|e| &e.data) + } + + #[inline] + pub fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + self.edges.get_mut(edge).map(|e| &mut e.data) + } + + #[inline] + pub fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + if let Some(idx) = self + .adjacencies + .get(from) + .unwrap() + .iter() + .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) + { + idx + } else { + EdgeIdx::null() + } + } + + #[inline] + pub fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + self.adjacencies.get(node).unwrap().to_vec() + } } -impl NewEdge for SimpleListGraph { - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { +impl SimpleListGraph { + pub fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { src: node, dst: other, @@ -72,7 +99,7 @@ impl NewEdge for SimpleListGraph { idx } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + pub fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { let list = self.adjacencies.get_mut(node).unwrap(); @@ -94,8 +121,8 @@ impl NewEdge for SimpleListGraph { } } -impl NewEdge for SimpleListGraph { - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { +impl SimpleListGraph { + pub fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { src: from, dst: to, @@ -105,7 +132,7 @@ impl NewEdge for SimpleListGraph { idx } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + pub fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { if let Some((from, to)) = self.edges.get(edge).map(|e| e.indices()) { let list = self.adjacencies.get_mut(from).unwrap(); @@ -122,42 +149,8 @@ impl NewEdge for SimpleListGraph { } } -impl GetEdge for SimpleListGraph { - #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { - self.edges.get(edge).map(|e| &e.data) - } - - #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { - self.edges.get_mut(edge).map(|e| &mut e.data) - } -} - -impl EdgeUtils for SimpleListGraph { - #[inline] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - if let Some(idx) = self - .adjacencies - .get(from) - .unwrap() - .iter() - .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) - { - idx - } else { - EdgeIdx::null() - } - } - - #[inline] - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - self.adjacencies.get(node).unwrap().to_vec() - } -} - -impl Graph for SimpleListGraph {} -impl Graph for SimpleListGraph {} +impl_graph!(SimpleListGraph, false); +impl_graph!(SimpleListGraph, true); impl Default for SimpleListGraph { #[inline] @@ -175,8 +168,6 @@ fn find_edge(list: &[(NodeIdx, EdgeIdx)], node: NodeIdx) -> Option { #[cfg(test)] mod test { - use crate::graphs::{EdgeUtils, NewEdge, NewNode}; - use super::SimpleListGraph; enum Person { diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index fd82a735ca88d..2393811556c71 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -6,8 +6,9 @@ use crate::{ graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, - EdgeUtils, GetEdge, GetNode, Graph, NewEdge, NewNode, + Graph, }, + impl_graph, }; #[derive(Clone)] @@ -25,24 +26,20 @@ impl SimpleMapGraph { adjacencies: SecondaryMap::new(), } } -} -impl NewNode for SimpleMapGraph { - fn new_node(&mut self, node: N) -> NodeIdx { + #[inline] + pub fn len(&self) -> usize { + self.nodes.len() + } + + pub fn new_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, HashMap::new()); idx } #[inline] - fn len(&self) -> usize { - self.nodes.len() - } -} - -impl GetNode for SimpleMapGraph { - #[inline] - fn node(&self, idx: NodeIdx) -> GraphResult<&N> { + pub fn node(&self, idx: NodeIdx) -> GraphResult<&N> { if let Some(node) = self.nodes.get(idx) { Ok(node) } else { @@ -51,17 +48,46 @@ impl GetNode for SimpleMapGraph { } #[inline] - fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + pub fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { if let Some(node) = self.nodes.get_mut(idx) { Ok(node) } else { Err(GraphError::NodeDoesntExist(idx)) } } + + #[inline] + pub fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { + self.edges.get(edge).map(|e| &e.data) + } + + #[inline] + pub fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + self.edges.get_mut(edge).map(|e| &mut e.data) + } + + #[inline] + pub fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + self.adjacencies + .get(from) + .unwrap() + .get(&to) + .cloned() + .unwrap_or_else(EdgeIdx::null) + } + + pub fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + self.adjacencies + .get(node) + .unwrap() + .iter() + .map(|(node, edge)| (*node, *edge)) + .collect() + } } -impl NewEdge for SimpleMapGraph { - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { +impl SimpleMapGraph { + pub fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { src: node, dst: other, @@ -72,7 +98,7 @@ impl NewEdge for SimpleMapGraph { idx } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + pub fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { self.adjacencies.get_mut(node).unwrap().remove(&other); self.adjacencies.get_mut(other).unwrap().remove(&node); @@ -84,8 +110,8 @@ impl NewEdge for SimpleMapGraph { } } -impl NewEdge for SimpleMapGraph { - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { +impl SimpleMapGraph { + pub fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { src: from, dst: to, @@ -95,7 +121,7 @@ impl NewEdge for SimpleMapGraph { idx } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + pub fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { if let Some((from, to)) = self.edges.get(edge).map(|e| e.indices()) { self.adjacencies.get_mut(from).unwrap().remove(&to); @@ -106,41 +132,8 @@ impl NewEdge for SimpleMapGraph { } } -impl GetEdge for SimpleMapGraph { - #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { - self.edges.get(edge).map(|e| &e.data) - } - - #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { - self.edges.get_mut(edge).map(|e| &mut e.data) - } -} - -impl EdgeUtils for SimpleMapGraph { - #[inline] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - self.adjacencies - .get(from) - .unwrap() - .get(&to) - .cloned() - .unwrap_or_else(EdgeIdx::null) - } - - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - self.adjacencies - .get(node) - .unwrap() - .iter() - .map(|(node, edge)| (*node, *edge)) - .collect() - } -} - -impl Graph for SimpleMapGraph {} -impl Graph for SimpleMapGraph {} +impl_graph!(SimpleMapGraph, false); +impl_graph!(SimpleMapGraph, true); impl Default for SimpleMapGraph { #[inline] @@ -151,8 +144,6 @@ impl Default for SimpleMapGraph { #[cfg(test)] mod test { - use crate::graphs::{EdgeUtils, NewEdge, NewNode}; - use super::SimpleMapGraph; enum Person { diff --git a/crates/bevy_graph/src/graphs/trait_impl_util.rs b/crates/bevy_graph/src/graphs/trait_impl_util.rs new file mode 100644 index 0000000000000..60d29b6d6a1e6 --- /dev/null +++ b/crates/bevy_graph/src/graphs/trait_impl_util.rs @@ -0,0 +1,56 @@ +#[macro_export] +macro_rules! impl_graph { + ($target:ident, $directed:tt) => { + impl Graph for $target { + #[inline(always)] + fn len(&self) -> usize { + $target::::len(self) + } + + #[inline(always)] + fn new_node(&mut self, node: N) -> NodeIdx { + $target::::new_node(self, node) + } + + #[inline(always)] + fn node(&self, idx: NodeIdx) -> GraphResult<&N> { + $target::::node(self, idx) + } + + #[inline(always)] + fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + $target::::node_mut(self, idx) + } + + #[inline(always)] + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + $target::::new_edge(self, from, to, edge) + } + + #[inline(always)] + fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { + $target::::get_edge(self, edge) + } + + #[inline(always)] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + $target::::get_edge_mut(self, edge) + } + + #[inline(always)] + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + $target::::remove_edge(self, edge) + } + + #[inline(always)] + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + $target::::edge_between(self, from, to) + } + + #[inline(always)] + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + $target::::edges_of(self, node) + } + } + }; +} From 70f1700e8b36f4c35df420cf14ec82b5af8ec9a0 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Thu, 12 Jan 2023 15:49:43 +0100 Subject: [PATCH 039/183] =?UTF-8?q?impl=5Fgraph=20macro=20is=20now=20a=20S?= =?UTF-8?q?igma=20=F0=9F=97=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/bevy_graph/src/algos/bfs.rs | 4 +- crates/bevy_graph/src/graphs/impl_graph.rs | 28 +++ crates/bevy_graph/src/graphs/mod.rs | 7 +- crates/bevy_graph/src/graphs/simple/list.rs | 194 +++++++++--------- crates/bevy_graph/src/graphs/simple/map.rs | 176 ++++++++-------- .../bevy_graph/src/graphs/trait_impl_util.rs | 56 ----- 6 files changed, 220 insertions(+), 245 deletions(-) create mode 100644 crates/bevy_graph/src/graphs/impl_graph.rs delete mode 100644 crates/bevy_graph/src/graphs/trait_impl_util.rs diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 4f3f28b334b14..4dc601bfa0fbc 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -10,9 +10,9 @@ pub struct BreadthFirstSearch { } impl BreadthFirstSearch { - pub fn new(start: NodeIdx, len: usize) -> Self { + pub fn new(start: NodeIdx, count: usize) -> Self { let mut queue = VecDeque::new(); - let mut visited = HashSet::with_capacity(len); + let mut visited = HashSet::with_capacity(count); visited.insert(start); queue.push_back(start); diff --git a/crates/bevy_graph/src/graphs/impl_graph.rs b/crates/bevy_graph/src/graphs/impl_graph.rs new file mode 100644 index 0000000000000..5eaac3508e3de --- /dev/null +++ b/crates/bevy_graph/src/graphs/impl_graph.rs @@ -0,0 +1,28 @@ +#[macro_export] +macro_rules! impl_graph { + (impl common for $name:ident { + $($common_code:tt)* + } + + impl undirected { + $($undirected_code:tt)* + } + + impl directed { + $($directed_code:tt)* + }) => { + impl crate::graphs::Graph for $name { + $($common_code)* + + $($undirected_code)* + } + + impl crate::graphs::Graph for $name { + $($common_code)* + + $($directed_code)* + } + } +} + +// TODO: replace `crate::graphs::` with one of bevy's macro util helpers diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index b48292ec92249..b91391956edfb 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -1,17 +1,16 @@ pub mod simple; pub mod edge; +pub mod impl_graph; pub mod keys; -pub mod trait_impl_util; use crate::algos::bfs::BreadthFirstSearch; use crate::error::GraphResult; use self::keys::{EdgeIdx, NodeIdx}; -#[allow(clippy::len_without_is_empty)] pub trait Graph { - fn len(&self) -> usize; + fn count(&self) -> usize; fn new_node(&mut self, node: N) -> NodeIdx; @@ -30,6 +29,6 @@ pub trait Graph { #[inline] fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { - BreadthFirstSearch::new(start, self.len()) + BreadthFirstSearch::new(start, self.count()) } } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 1e4757ad74072..10c978e38f604 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -5,7 +5,6 @@ use crate::{ graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, - Graph, }, impl_graph, }; @@ -18,140 +17,141 @@ pub struct SimpleListGraph { } impl SimpleListGraph { - pub fn new() -> Self { + fn new() -> Self { Self { nodes: HopSlotMap::with_key(), edges: HopSlotMap::with_key(), adjacencies: SecondaryMap::new(), } } +} - #[inline] - pub fn len(&self) -> usize { - self.nodes.len() - } - - #[inline] - pub fn new_node(&mut self, node: N) -> NodeIdx { - let idx = self.nodes.insert(node); - self.adjacencies.insert(idx, Vec::new()); - idx - } +impl_graph! { + impl common for SimpleListGraph { + #[inline] + fn count(&self) -> usize { + self.nodes.len() + } - #[inline] - pub fn node(&self, idx: NodeIdx) -> GraphResult<&N> { - if let Some(node) = self.nodes.get(idx) { - Ok(node) - } else { - Err(GraphError::NodeDoesntExist(idx)) + #[inline] + fn new_node(&mut self, node: N) -> NodeIdx { + let idx = self.nodes.insert(node); + self.adjacencies.insert(idx, Vec::new()); + idx } - } - #[inline] - pub fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { - if let Some(node) = self.nodes.get_mut(idx) { - Ok(node) - } else { - Err(GraphError::NodeDoesntExist(idx)) + #[inline] + fn node(&self, idx: NodeIdx) -> GraphResult<&N> { + if let Some(node) = self.nodes.get(idx) { + Ok(node) + } else { + Err(GraphError::NodeDoesntExist(idx)) + } } - } - #[inline] - pub fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { - self.edges.get(edge).map(|e| &e.data) - } + #[inline] + fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + if let Some(node) = self.nodes.get_mut(idx) { + Ok(node) + } else { + Err(GraphError::NodeDoesntExist(idx)) + } + } - #[inline] - pub fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { - self.edges.get_mut(edge).map(|e| &mut e.data) - } + #[inline] + fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { + self.edges.get(edge).map(|e| &e.data) + } - #[inline] - pub fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - if let Some(idx) = self - .adjacencies - .get(from) - .unwrap() - .iter() - .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) - { - idx - } else { - EdgeIdx::null() + #[inline] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + self.edges.get_mut(edge).map(|e| &mut e.data) } - } - #[inline] - pub fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - self.adjacencies.get(node).unwrap().to_vec() - } -} + #[inline] + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + if let Some(idx) = self + .adjacencies + .get(from) + .unwrap() + .iter() + .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) + { + idx + } else { + EdgeIdx::null() + } + } -impl SimpleListGraph { - pub fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: node, - dst: other, - data: edge, - }); - self.adjacencies.get_mut(node).unwrap().push((other, idx)); - self.adjacencies.get_mut(other).unwrap().push((node, idx)); - idx + #[inline] + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + self.adjacencies.get(node).unwrap().to_vec() + } } - pub fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { - let list = self.adjacencies.get_mut(node).unwrap(); + impl undirected { + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: node, + dst: other, + data: edge, + }); + self.adjacencies.get_mut(node).unwrap().push((other, idx)); + self.adjacencies.get_mut(other).unwrap().push((node, idx)); + idx + } - if let Some(index) = find_edge(list, other) { - list.swap_remove(index); // TODO: remove or swap_remove ? + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { + let list = self.adjacencies.get_mut(node).unwrap(); - let list = self.adjacencies.get_mut(other).unwrap(); - if let Some(index) = find_edge(list, node) { + if let Some(index) = find_edge(list, other) { list.swap_remove(index); // TODO: remove or swap_remove ? - } - Ok(self.edges.remove(edge).unwrap().data) + let list = self.adjacencies.get_mut(other).unwrap(); + if let Some(index) = find_edge(list, node) { + list.swap_remove(index); // TODO: remove or swap_remove ? + } + + Ok(self.edges.remove(edge).unwrap().data) + } else { + Err(GraphError::EdgeDoesntExist(edge)) + } } else { Err(GraphError::EdgeDoesntExist(edge)) } - } else { - Err(GraphError::EdgeDoesntExist(edge)) } } -} -impl SimpleListGraph { - pub fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); - self.adjacencies.get_mut(from).unwrap().push((to, idx)); - idx - } + impl directed { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); + self.adjacencies.get_mut(from).unwrap().push((to, idx)); + idx + } - pub fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if let Some((from, to)) = self.edges.get(edge).map(|e| e.indices()) { - let list = self.adjacencies.get_mut(from).unwrap(); + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if let Some((from, to)) = self.edges.get(edge).map(|e| e.indices()) { + let list = self.adjacencies.get_mut(from).unwrap(); - if let Some(index) = find_edge(list, to) { - list.swap_remove(index); // TODO: remove or swap_remove ? + if let Some(index) = find_edge(list, to) { + list.swap_remove(index); // TODO: remove or swap_remove ? - Ok(self.edges.remove(edge).unwrap().data) + Ok(self.edges.remove(edge).unwrap().data) + } else { + Err(GraphError::EdgeDoesntExist(edge)) + } } else { Err(GraphError::EdgeDoesntExist(edge)) } - } else { - Err(GraphError::EdgeDoesntExist(edge)) } } } -impl_graph!(SimpleListGraph, false); -impl_graph!(SimpleListGraph, true); - impl Default for SimpleListGraph { #[inline] fn default() -> Self { @@ -168,6 +168,8 @@ fn find_edge(list: &[(NodeIdx, EdgeIdx)], node: NodeIdx) -> Option { #[cfg(test)] mod test { + use crate::graphs::Graph; + use super::SimpleListGraph; enum Person { diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 2393811556c71..47a0fd6715804 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -6,7 +6,6 @@ use crate::{ graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, - Graph, }, impl_graph, }; @@ -26,115 +25,116 @@ impl SimpleMapGraph { adjacencies: SecondaryMap::new(), } } +} - #[inline] - pub fn len(&self) -> usize { - self.nodes.len() - } +impl_graph! { + impl common for SimpleMapGraph { + #[inline] + fn count(&self) -> usize { + self.nodes.len() + } - pub fn new_node(&mut self, node: N) -> NodeIdx { - let idx = self.nodes.insert(node); - self.adjacencies.insert(idx, HashMap::new()); - idx - } + fn new_node(&mut self, node: N) -> NodeIdx { + let idx = self.nodes.insert(node); + self.adjacencies.insert(idx, HashMap::new()); + idx + } - #[inline] - pub fn node(&self, idx: NodeIdx) -> GraphResult<&N> { - if let Some(node) = self.nodes.get(idx) { - Ok(node) - } else { - Err(GraphError::NodeDoesntExist(idx)) + #[inline] + fn node(&self, idx: NodeIdx) -> GraphResult<&N> { + if let Some(node) = self.nodes.get(idx) { + Ok(node) + } else { + Err(GraphError::NodeDoesntExist(idx)) + } } - } - #[inline] - pub fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { - if let Some(node) = self.nodes.get_mut(idx) { - Ok(node) - } else { - Err(GraphError::NodeDoesntExist(idx)) + #[inline] + fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + if let Some(node) = self.nodes.get_mut(idx) { + Ok(node) + } else { + Err(GraphError::NodeDoesntExist(idx)) + } } - } - #[inline] - pub fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { - self.edges.get(edge).map(|e| &e.data) - } + #[inline] + fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { + self.edges.get(edge).map(|e| &e.data) + } - #[inline] - pub fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { - self.edges.get_mut(edge).map(|e| &mut e.data) - } + #[inline] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { + self.edges.get_mut(edge).map(|e| &mut e.data) + } - #[inline] - pub fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - self.adjacencies - .get(from) - .unwrap() - .get(&to) - .cloned() - .unwrap_or_else(EdgeIdx::null) - } + #[inline] + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + self.adjacencies + .get(from) + .unwrap() + .get(&to) + .cloned() + .unwrap_or_else(EdgeIdx::null) + } - pub fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - self.adjacencies - .get(node) - .unwrap() - .iter() - .map(|(node, edge)| (*node, *edge)) - .collect() + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + self.adjacencies + .get(node) + .unwrap() + .iter() + .map(|(node, edge)| (*node, *edge)) + .collect() + } } -} -impl SimpleMapGraph { - pub fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: node, - dst: other, - data: edge, - }); - self.adjacencies.get_mut(node).unwrap().insert(other, idx); - self.adjacencies.get_mut(other).unwrap().insert(node, idx); - idx - } + impl undirected { + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: node, + dst: other, + data: edge, + }); + self.adjacencies.get_mut(node).unwrap().insert(other, idx); + self.adjacencies.get_mut(other).unwrap().insert(node, idx); + idx + } - pub fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { - self.adjacencies.get_mut(node).unwrap().remove(&other); - self.adjacencies.get_mut(other).unwrap().remove(&node); + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { + self.adjacencies.get_mut(node).unwrap().remove(&other); + self.adjacencies.get_mut(other).unwrap().remove(&node); - Ok(self.edges.remove(edge).unwrap().data) - } else { - Err(GraphError::EdgeDoesntExist(edge)) + Ok(self.edges.remove(edge).unwrap().data) + } else { + Err(GraphError::EdgeDoesntExist(edge)) + } } } -} -impl SimpleMapGraph { - pub fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); - self.adjacencies.get_mut(from).unwrap().insert(to, idx); - idx - } + impl directed { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); + self.adjacencies.get_mut(from).unwrap().insert(to, idx); + idx + } - pub fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if let Some((from, to)) = self.edges.get(edge).map(|e| e.indices()) { - self.adjacencies.get_mut(from).unwrap().remove(&to); + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if let Some((from, to)) = self.edges.get(edge).map(|e| e.indices()) { + self.adjacencies.get_mut(from).unwrap().remove(&to); - Ok(self.edges.remove(edge).unwrap().data) - } else { - Err(GraphError::EdgeDoesntExist(edge)) + Ok(self.edges.remove(edge).unwrap().data) + } else { + Err(GraphError::EdgeDoesntExist(edge)) + } } } } -impl_graph!(SimpleMapGraph, false); -impl_graph!(SimpleMapGraph, true); - impl Default for SimpleMapGraph { #[inline] fn default() -> Self { @@ -144,6 +144,8 @@ impl Default for SimpleMapGraph { #[cfg(test)] mod test { + use crate::graphs::Graph; + use super::SimpleMapGraph; enum Person { diff --git a/crates/bevy_graph/src/graphs/trait_impl_util.rs b/crates/bevy_graph/src/graphs/trait_impl_util.rs deleted file mode 100644 index 60d29b6d6a1e6..0000000000000 --- a/crates/bevy_graph/src/graphs/trait_impl_util.rs +++ /dev/null @@ -1,56 +0,0 @@ -#[macro_export] -macro_rules! impl_graph { - ($target:ident, $directed:tt) => { - impl Graph for $target { - #[inline(always)] - fn len(&self) -> usize { - $target::::len(self) - } - - #[inline(always)] - fn new_node(&mut self, node: N) -> NodeIdx { - $target::::new_node(self, node) - } - - #[inline(always)] - fn node(&self, idx: NodeIdx) -> GraphResult<&N> { - $target::::node(self, idx) - } - - #[inline(always)] - fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { - $target::::node_mut(self, idx) - } - - #[inline(always)] - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - $target::::new_edge(self, from, to, edge) - } - - #[inline(always)] - fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { - $target::::get_edge(self, edge) - } - - #[inline(always)] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { - $target::::get_edge_mut(self, edge) - } - - #[inline(always)] - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - $target::::remove_edge(self, edge) - } - - #[inline(always)] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - $target::::edge_between(self, from, to) - } - - #[inline(always)] - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - $target::::edges_of(self, node) - } - } - }; -} From 5c51e8418be77e4c97bdcb3d680c90eeb5fc9891 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Thu, 12 Jan 2023 16:03:06 +0100 Subject: [PATCH 040/183] Update Bench --- benches/benches/bevy_graph/map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benches/benches/bevy_graph/map.rs b/benches/benches/bevy_graph/map.rs index 64f9d2ff70723..003c4b6918515 100644 --- a/benches/benches/bevy_graph/map.rs +++ b/benches/benches/bevy_graph/map.rs @@ -1,7 +1,7 @@ use bevy_graph::graphs::{ keys::{EdgeIdx, NodeIdx}, simple::SimpleMapGraph, - Graph, UndirectedGraph, + Graph, }; use bevy_utils::Duration; use criterion::{black_box, criterion_group, criterion_main, Criterion}; @@ -48,7 +48,7 @@ fn nodes_10_000_undirected(c: &mut Criterion) { black_box( map_graph .edge_between(nodes[i - 1], nodes[i]) - .remove_undirected(&mut map_graph) + .remove(&mut map_graph) .unwrap(), ); } From be83c21ad018b451a27f207108142b8f63d76634 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Thu, 12 Jan 2023 16:14:30 +0100 Subject: [PATCH 041/183] Now i understand what $crate does :D --- crates/bevy_graph/src/graphs/impl_graph.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/bevy_graph/src/graphs/impl_graph.rs b/crates/bevy_graph/src/graphs/impl_graph.rs index 5eaac3508e3de..b625bf1d73051 100644 --- a/crates/bevy_graph/src/graphs/impl_graph.rs +++ b/crates/bevy_graph/src/graphs/impl_graph.rs @@ -11,18 +11,16 @@ macro_rules! impl_graph { impl directed { $($directed_code:tt)* }) => { - impl crate::graphs::Graph for $name { + impl $crate::graphs::Graph for $name { $($common_code)* $($undirected_code)* } - impl crate::graphs::Graph for $name { + impl $crate::graphs::Graph for $name { $($common_code)* $($directed_code)* } } } - -// TODO: replace `crate::graphs::` with one of bevy's macro util helpers From 46fcd868c844c2cd82ad1f9a5029ac09182f095e Mon Sep 17 00:00:00 2001 From: DasLixou Date: Thu, 12 Jan 2023 18:06:03 +0100 Subject: [PATCH 042/183] Add support to remove nodes --- crates/bevy_graph/src/graphs/mod.rs | 5 ++ crates/bevy_graph/src/graphs/simple/list.rs | 63 ++++++++++++++++++++ crates/bevy_graph/src/graphs/simple/map.rs | 64 +++++++++++++++++++++ 3 files changed, 132 insertions(+) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index b91391956edfb..632fc634caf59 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -12,11 +12,15 @@ use self::keys::{EdgeIdx, NodeIdx}; pub trait Graph { fn count(&self) -> usize; + // Nodes fn new_node(&mut self, node: N) -> NodeIdx; fn node(&self, idx: NodeIdx) -> GraphResult<&N>; fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; + fn remove_node(&mut self, node: NodeIdx) -> GraphResult; + + // Edges fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; fn get_edge(&self, edge: EdgeIdx) -> Option<&E>; @@ -27,6 +31,7 @@ pub trait Graph { fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? + // Algos #[inline] fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { BreadthFirstSearch::new(start, self.count()) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 10c978e38f604..c9f6ccc1db630 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -90,6 +90,16 @@ impl_graph! { } impl undirected { + fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + for (_, edge) in self.edges_of(node) { + self.remove_edge(edge).unwrap(); + } + match self.nodes.remove(node) { + Some(n) => Ok(n), + None => Err(GraphError::NodeDoesntExist(node)) + } + } + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { src: node, @@ -124,6 +134,23 @@ impl_graph! { } impl directed { + fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + let mut edges = vec![]; + for (edge, data) in &self.edges { + let (src, dst) = data.indices(); + if dst == node || src == node { + edges.push(edge); + } + } + for edge in edges { + self.remove_edge(edge).unwrap(); + } + match self.nodes.remove(node) { + Some(n) => Ok(n), + None => Err(GraphError::NodeDoesntExist(node)) + } + } + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { src: from, @@ -168,6 +195,8 @@ fn find_edge(list: &[(NodeIdx, EdgeIdx)], node: NodeIdx) -> Option { #[cfg(test)] mod test { + use slotmap::Key; + use crate::graphs::Graph; use super::SimpleListGraph; @@ -258,4 +287,38 @@ mod test { .get::(&list_graph); assert!(strength_jennifer.is_none()); } + + #[test] + fn remove_undirected_node() { + const STRENGTH: i32 = 100; + + let mut map_graph = SimpleListGraph::::new(); + + let jake = map_graph.new_node(Person::Jake); + let michael = map_graph.new_node(Person::Michael); + + let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); + + assert!(map_graph.remove_node(michael).is_ok()); + + assert!(map_graph.node(michael).is_err()); + assert!(map_graph.edge_between(jake, michael).is_null()); + } + + #[test] + fn remove_directed_node() { + const STRENGTH: i32 = 9999; + + let mut map_graph = SimpleListGraph::::new(); + + let jake = map_graph.new_node(Person::Jake); + let jennifer = map_graph.new_node(Person::Jennifer); + + let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); + + assert!(map_graph.remove_node(jake).is_ok()); + + assert!(map_graph.node(jake).is_err()); + assert!(map_graph.edge_between(jake, jennifer).is_null()); + } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 47a0fd6715804..658a4c5a4a822 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -78,6 +78,7 @@ impl_graph! { .unwrap_or_else(EdgeIdx::null) } + #[inline] fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { self.adjacencies .get(node) @@ -89,6 +90,16 @@ impl_graph! { } impl undirected { + fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + for (_, edge) in self.edges_of(node) { + self.remove_edge(edge).unwrap(); + } + match self.nodes.remove(node) { + Some(n) => Ok(n), + None => Err(GraphError::NodeDoesntExist(node)) + } + } + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { src: node, @@ -113,6 +124,23 @@ impl_graph! { } impl directed { + fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + let mut edges = vec![]; + for (edge, data) in &self.edges { + let (src, dst) = data.indices(); + if dst == node || src == node { + edges.push(edge); + } + } + for edge in edges { + self.remove_edge(edge).unwrap(); + } + match self.nodes.remove(node) { + Some(n) => Ok(n), + None => Err(GraphError::NodeDoesntExist(node)) + } + } + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { let idx = self.edges.insert(Edge { src: from, @@ -144,6 +172,8 @@ impl Default for SimpleMapGraph { #[cfg(test)] mod test { + use slotmap::Key; + use crate::graphs::Graph; use super::SimpleMapGraph; @@ -236,4 +266,38 @@ mod test { .get::(&map_graph); assert!(strength_jennifer.is_none()); } + + #[test] + fn remove_undirected_node() { + const STRENGTH: i32 = 100; + + let mut map_graph = SimpleMapGraph::::new(); + + let jake = map_graph.new_node(Person::Jake); + let michael = map_graph.new_node(Person::Michael); + + let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); + + assert!(map_graph.remove_node(michael).is_ok()); + + assert!(map_graph.node(michael).is_err()); + assert!(map_graph.edge_between(jake, michael).is_null()); + } + + #[test] + fn remove_directed_node() { + const STRENGTH: i32 = 9999; + + let mut map_graph = SimpleMapGraph::::new(); + + let jake = map_graph.new_node(Person::Jake); + let jennifer = map_graph.new_node(Person::Jennifer); + + let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); + + assert!(map_graph.remove_node(jake).is_ok()); + + assert!(map_graph.node(jake).is_err()); + assert!(map_graph.edge_between(jake, jennifer).is_null()); + } } From a7442e75a0f883ff3a6646d4b11de31e4493476d Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 13 Jan 2023 15:56:17 +0100 Subject: [PATCH 043/183] Move Tests for Graph in one file --- crates/bevy_graph/src/graphs/simple/list.rs | 126 ++----------- crates/bevy_graph/src/graphs/simple/map.rs | 128 ++------------ crates/bevy_graph/src/graphs/simple/mod.rs | 186 ++++++++++++++++++++ 3 files changed, 210 insertions(+), 230 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index c9f6ccc1db630..cc43e2ab1cc97 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -195,130 +195,28 @@ fn find_edge(list: &[(NodeIdx, EdgeIdx)], node: NodeIdx) -> Option { #[cfg(test)] mod test { - use slotmap::Key; - - use crate::graphs::Graph; + use crate::graphs::simple::test::{self, Person}; use super::SimpleListGraph; - enum Person { - Jake, - Michael, - Jennifer, + #[test] + fn nodes() { + test::nodes(SimpleListGraph::::new()) } - #[test] - fn undirected_edge() { - const STRENGTH: i32 = 100; - - let mut list_graph = SimpleListGraph::::new(); - - let jake = list_graph.new_node(Person::Jake); - let michael = list_graph.new_node(Person::Michael); - let best_friends = list_graph.new_edge(jake, michael, STRENGTH); - - let strength_jake = list_graph - .edge_between(jake, michael) - .get::(&list_graph); - assert!(strength_jake.is_some()); - assert_eq!(strength_jake.unwrap(), &STRENGTH); - - let strength_michael = list_graph - .edge_between(michael, jake) - .get::(&list_graph); - assert!(strength_michael.is_some()); - assert_eq!(strength_michael.unwrap(), &STRENGTH); - - assert_eq!(list_graph.edges_of(jake), vec![(michael, best_friends)]); - assert_eq!(list_graph.edges_of(michael), vec![(jake, best_friends)]); - - assert!(list_graph - .edge_between(michael, jake) - .remove::(&mut list_graph) - .is_ok()); - - let strength_jake = list_graph - .edge_between(jake, michael) - .get::(&list_graph); - assert!(strength_jake.is_none()); - - let strength_michael = list_graph - .edge_between(michael, jake) - .get::(&list_graph); - assert!(strength_michael.is_none()); + fn undirected_edges() { + test::undirected_edges(SimpleListGraph::::new()) } - #[test] - fn directed_edge() { - const STRENGTH: i32 = 9999; - - let mut list_graph = SimpleListGraph::::new(); - - let jake = list_graph.new_node(Person::Jake); - let jennifer = list_graph.new_node(Person::Jennifer); - let oneway_crush = list_graph.new_edge(jake, jennifer, STRENGTH); - - let strength_jake = list_graph - .edge_between(jake, jennifer) - .get::(&list_graph); - assert!(strength_jake.is_some()); - assert_eq!(strength_jake.unwrap(), &STRENGTH); - - let strength_jennifer = list_graph - .edge_between(jennifer, jake) - .get::(&list_graph); - assert!(strength_jennifer.is_none()); - - assert_eq!(list_graph.edges_of(jake), vec![(jennifer, oneway_crush)]); - assert_eq!(list_graph.edges_of(jennifer), vec![]); - - assert!(list_graph - .edge_between(jake, jennifer) - .remove::(&mut list_graph) - .is_ok()); - - let strength_jake = list_graph - .edge_between(jake, jennifer) - .get::(&list_graph); - assert!(strength_jake.is_none()); - - let strength_jennifer = list_graph - .edge_between(jennifer, jake) - .get::(&list_graph); - assert!(strength_jennifer.is_none()); + fn directed_edges() { + test::directed_edges(SimpleListGraph::::new()) } - #[test] - fn remove_undirected_node() { - const STRENGTH: i32 = 100; - - let mut map_graph = SimpleListGraph::::new(); - - let jake = map_graph.new_node(Person::Jake); - let michael = map_graph.new_node(Person::Michael); - - let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); - - assert!(map_graph.remove_node(michael).is_ok()); - - assert!(map_graph.node(michael).is_err()); - assert!(map_graph.edge_between(jake, michael).is_null()); + fn remove_node_undirected() { + test::remove_node_undirected(SimpleListGraph::::new()) } - #[test] - fn remove_directed_node() { - const STRENGTH: i32 = 9999; - - let mut map_graph = SimpleListGraph::::new(); - - let jake = map_graph.new_node(Person::Jake); - let jennifer = map_graph.new_node(Person::Jennifer); - - let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); - - assert!(map_graph.remove_node(jake).is_ok()); - - assert!(map_graph.node(jake).is_err()); - assert!(map_graph.edge_between(jake, jennifer).is_null()); + fn remove_node_directed() { + test::remove_node_directed(SimpleListGraph::::new()) } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 658a4c5a4a822..640a4852aa372 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -172,132 +172,28 @@ impl Default for SimpleMapGraph { #[cfg(test)] mod test { - use slotmap::Key; - - use crate::graphs::Graph; + use crate::graphs::simple::test::{self, Person}; use super::SimpleMapGraph; - enum Person { - Jake, - Michael, - Jennifer, + #[test] + fn nodes() { + test::nodes(SimpleMapGraph::::new()) } - #[test] - fn undirected_edge() { - const STRENGTH: i32 = 100; - - let mut map_graph = SimpleMapGraph::::new(); - - let jake = map_graph.new_node(Person::Jake); - let michael = map_graph.new_node(Person::Michael); - - let best_friends = map_graph.new_edge(jake, michael, STRENGTH); - - let strength_jake = map_graph - .edge_between(jake, michael) - .get::(&map_graph); - assert!(strength_jake.is_some()); - assert_eq!(strength_jake.unwrap(), &STRENGTH); - - let strength_michael = map_graph - .edge_between(michael, jake) - .get::(&map_graph); - assert!(strength_michael.is_some()); - assert_eq!(strength_michael.unwrap(), &STRENGTH); - - assert_eq!(map_graph.edges_of(jake), vec![(michael, best_friends)]); - assert_eq!(map_graph.edges_of(michael), vec![(jake, best_friends)]); - - assert!(map_graph - .edge_between(michael, jake) - .remove::(&mut map_graph) - .is_ok()); - - let strength_jake = map_graph - .edge_between(jake, michael) - .get::(&map_graph); - assert!(strength_jake.is_none()); - - let strength_michael = map_graph - .edge_between(michael, jake) - .get::(&map_graph); - assert!(strength_michael.is_none()); + fn undirected_edges() { + test::undirected_edges(SimpleMapGraph::::new()) } - #[test] - fn directed_edge() { - const STRENGTH: i32 = 9999; - - let mut map_graph = SimpleMapGraph::::new(); - - let jake = map_graph.new_node(Person::Jake); - let jennifer = map_graph.new_node(Person::Jennifer); - - let oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); - - let strength_jake = map_graph - .edge_between(jake, jennifer) - .get::(&map_graph); - assert!(strength_jake.is_some()); - assert_eq!(strength_jake.unwrap(), &STRENGTH); - - let strength_jennifer = map_graph - .edge_between(jennifer, jake) - .get::(&map_graph); - assert!(strength_jennifer.is_none()); - - assert_eq!(map_graph.edges_of(jake), vec![(jennifer, oneway_crush)]); - assert_eq!(map_graph.edges_of(jennifer), vec![]); - - assert!(map_graph - .edge_between(jake, jennifer) - .remove::(&mut map_graph) - .is_ok()); - - let strength_jake = map_graph - .edge_between(jake, jennifer) - .get::(&map_graph); - assert!(strength_jake.is_none()); - - let strength_jennifer = map_graph - .edge_between(jennifer, jake) - .get::(&map_graph); - assert!(strength_jennifer.is_none()); + fn directed_edges() { + test::directed_edges(SimpleMapGraph::::new()) } - #[test] - fn remove_undirected_node() { - const STRENGTH: i32 = 100; - - let mut map_graph = SimpleMapGraph::::new(); - - let jake = map_graph.new_node(Person::Jake); - let michael = map_graph.new_node(Person::Michael); - - let _best_friends = map_graph.new_edge(jake, michael, STRENGTH); - - assert!(map_graph.remove_node(michael).is_ok()); - - assert!(map_graph.node(michael).is_err()); - assert!(map_graph.edge_between(jake, michael).is_null()); + fn remove_node_undirected() { + test::remove_node_undirected(SimpleMapGraph::::new()) } - #[test] - fn remove_directed_node() { - const STRENGTH: i32 = 9999; - - let mut map_graph = SimpleMapGraph::::new(); - - let jake = map_graph.new_node(Person::Jake); - let jennifer = map_graph.new_node(Person::Jennifer); - - let _oneway_crush = map_graph.new_edge(jake, jennifer, STRENGTH); - - assert!(map_graph.remove_node(jake).is_ok()); - - assert!(map_graph.node(jake).is_err()); - assert!(map_graph.edge_between(jake, jennifer).is_null()); + fn remove_node_directed() { + test::remove_node_directed(SimpleMapGraph::::new()) } } diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index 4efa46e6469cb..d2176a4cad724 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -3,3 +3,189 @@ pub use map::*; mod list; pub use list::*; + +#[cfg(test)] +mod test { + use hashbrown::HashSet; + use slotmap::Key; + use std::hash::Hash; + + use crate::graphs::Graph; + + #[derive(PartialEq, Debug)] + pub enum Person { + Jake, + Michael, + Jennifer, + } + + pub fn nodes(mut graph: impl Graph) { + let jake = graph.new_node(Person::Jake); + let michael = graph.new_node(Person::Michael); + let jennifer = graph.new_node(Person::Jennifer); + let other_jake = graph.new_node(Person::Jake); + + assert_eq!(graph.node(jake).unwrap(), &Person::Jake); + assert_eq!(graph.node(michael).unwrap(), &Person::Michael); + assert_eq!(graph.node(jennifer).unwrap(), &Person::Jennifer); + assert_eq!(graph.node(other_jake).unwrap(), &Person::Jake); + + graph + .node_mut(jake) + .map(|node| *node = Person::Michael) + .unwrap(); + + assert_eq!(graph.node(jake).unwrap(), &Person::Michael); + assert_eq!(graph.node(michael).unwrap(), &Person::Michael); + assert_eq!(graph.node(jennifer).unwrap(), &Person::Jennifer); + assert_eq!(graph.node(other_jake).unwrap(), &Person::Jake); + + assert!(graph.remove_node(jake).is_ok()); + assert!(graph.remove_node(michael).is_ok()); + assert!(graph.remove_node(jennifer).is_ok()); + assert!(graph.remove_node(other_jake).is_ok()); + + assert!(graph.node(jake).is_err()); + assert!(graph.node(michael).is_err()); + assert!(graph.node(jennifer).is_err()); + assert!(graph.node(other_jake).is_err()); + } + + pub fn undirected_edges(mut graph: impl Graph) { + let jake = graph.new_node(Person::Jake); + let michael = graph.new_node(Person::Michael); + let jennifer = graph.new_node(Person::Jennifer); + let other_jake = graph.new_node(Person::Jake); + + let jm = graph.new_edge(jake, michael, 2); + let jj = graph.new_edge(jennifer, jake, 7); + let jo = graph.new_edge(jake, other_jake, 5); + let mo = graph.new_edge(michael, other_jake, 1); + + assert!(unordered_eq( + &graph.edges_of(jake), + &[(michael, jm), (jennifer, jj), (other_jake, jo)] + )); + + assert_eq!(graph.get_edge(jm).unwrap(), &2); + assert_eq!(graph.get_edge(jj).unwrap(), &7); + assert_eq!(graph.get_edge(jo).unwrap(), &5); + assert_eq!(graph.get_edge(mo).unwrap(), &1); + + assert_eq!( + graph.edge_between(jennifer, jake), + graph.edge_between(jake, jennifer) + ); + + graph.get_edge_mut(mo).map(|edge| *edge = 10); + + assert_eq!(graph.get_edge(jm).unwrap(), &2); + assert_eq!(graph.get_edge(jj).unwrap(), &7); + assert_eq!(graph.get_edge(jo).unwrap(), &5); + assert_eq!(graph.get_edge(mo).unwrap(), &10); + + assert!(graph.remove_edge(jm).is_ok()); + assert!(graph.remove_edge(jj).is_ok()); + assert!(graph.remove_edge(jo).is_ok()); + assert!(graph.remove_edge(mo).is_ok()); + + assert!(graph.get_edge(jm).is_none()); + assert!(graph.get_edge(jj).is_none()); + assert!(graph.get_edge(jo).is_none()); + assert!(graph.get_edge(mo).is_none()); + } + + pub fn directed_edges(mut graph: impl Graph) { + let jake = graph.new_node(Person::Jake); + let michael = graph.new_node(Person::Michael); + let jennifer = graph.new_node(Person::Jennifer); + let other_jake = graph.new_node(Person::Jake); + + let jm = graph.new_edge(jake, michael, 2); + let jj = graph.new_edge(jennifer, jake, 7); + let jo = graph.new_edge(jake, other_jake, 5); + let mo = graph.new_edge(michael, other_jake, 1); + + assert!(unordered_eq( + &graph.edges_of(jake), + &[(michael, jm), (other_jake, jo)] + )); + + assert_eq!(graph.get_edge(jm).unwrap(), &2); + assert_eq!(graph.get_edge(jj).unwrap(), &7); + assert_eq!(graph.get_edge(jo).unwrap(), &5); + assert_eq!(graph.get_edge(mo).unwrap(), &1); + + assert!(!graph.edge_between(jennifer, jake).is_null()); + assert!(graph.edge_between(jake, jennifer).is_null()); + + graph.get_edge_mut(mo).map(|edge| *edge = 10); + + assert_eq!(graph.get_edge(jm).unwrap(), &2); + assert_eq!(graph.get_edge(jj).unwrap(), &7); + assert_eq!(graph.get_edge(jo).unwrap(), &5); + assert_eq!(graph.get_edge(mo).unwrap(), &10); + + assert!(graph.remove_edge(jm).is_ok()); + assert!(graph.remove_edge(jj).is_ok()); + assert!(graph.remove_edge(jo).is_ok()); + assert!(graph.remove_edge(mo).is_ok()); + + assert!(graph.get_edge(jm).is_none()); + assert!(graph.get_edge(jj).is_none()); + assert!(graph.get_edge(jo).is_none()); + assert!(graph.get_edge(mo).is_none()); + } + + pub fn remove_node_undirected(mut graph: impl Graph) { + let jake = graph.new_node(Person::Jake); + let michael = graph.new_node(Person::Michael); + + let edge = graph.new_edge(jake, michael, 20); + + assert!(graph.node(jake).is_ok()); + assert!(graph.node(michael).is_ok()); + assert_eq!(graph.get_edge(edge).unwrap(), &20); + assert_eq!(graph.edge_between(jake, michael).get(&graph).unwrap(), &20); + assert_eq!(graph.edge_between(michael, jake).get(&graph).unwrap(), &20); + + assert!(graph.remove_node(michael).is_ok()); + + assert!(graph.node(jake).is_ok()); + assert!(graph.node(michael).is_err()); + assert!(graph.get_edge(edge).is_none()); + assert!(graph.edge_between(jake, michael).get(&graph).is_none()); + assert!(graph.edge_between(michael, jake).get(&graph).is_none()); + } + + pub fn remove_node_directed(mut graph: impl Graph) { + let jake = graph.new_node(Person::Jake); + let michael = graph.new_node(Person::Michael); + + let edge = graph.new_edge(jake, michael, 20); + + assert!(graph.node(jake).is_ok()); + assert!(graph.node(michael).is_ok()); + assert_eq!(graph.get_edge(edge).unwrap(), &20); + assert_eq!(graph.edge_between(jake, michael).get(&graph).unwrap(), &20); + assert!(graph.edge_between(michael, jake).get(&graph).is_none()); + + assert!(graph.remove_node(michael).is_ok()); + + assert!(graph.node(jake).is_ok()); + assert!(graph.node(michael).is_err()); + assert!(graph.get_edge(edge).is_none()); + assert!(graph.edge_between(jake, michael).get(&graph).is_none()); + assert!(graph.edge_between(michael, jake).get(&graph).is_none()); + } + + fn unordered_eq(a: &[T], b: &[T]) -> bool + where + T: Eq + Hash, + { + let a: HashSet<_> = a.iter().collect(); + let b: HashSet<_> = b.iter().collect(); + + a == b + } +} From 5aa9c14595083d8bfac115415e34aa33edd70a87 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 13 Jan 2023 16:21:45 +0100 Subject: [PATCH 044/183] graph_tests macro :o --- crates/bevy_graph/src/graphs/simple/list.rs | 25 ++---------------- crates/bevy_graph/src/graphs/simple/map.rs | 25 ++---------------- crates/bevy_graph/src/graphs/simple/mod.rs | 28 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 46 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index cc43e2ab1cc97..8ef7241d2533d 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -195,28 +195,7 @@ fn find_edge(list: &[(NodeIdx, EdgeIdx)], node: NodeIdx) -> Option { #[cfg(test)] mod test { - use crate::graphs::simple::test::{self, Person}; + use crate::graph_tests; - use super::SimpleListGraph; - - #[test] - fn nodes() { - test::nodes(SimpleListGraph::::new()) - } - #[test] - fn undirected_edges() { - test::undirected_edges(SimpleListGraph::::new()) - } - #[test] - fn directed_edges() { - test::directed_edges(SimpleListGraph::::new()) - } - #[test] - fn remove_node_undirected() { - test::remove_node_undirected(SimpleListGraph::::new()) - } - #[test] - fn remove_node_directed() { - test::remove_node_directed(SimpleListGraph::::new()) - } + graph_tests!(super::SimpleListGraph); } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 640a4852aa372..d76b93b9255d1 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -172,28 +172,7 @@ impl Default for SimpleMapGraph { #[cfg(test)] mod test { - use crate::graphs::simple::test::{self, Person}; + use crate::graph_tests; - use super::SimpleMapGraph; - - #[test] - fn nodes() { - test::nodes(SimpleMapGraph::::new()) - } - #[test] - fn undirected_edges() { - test::undirected_edges(SimpleMapGraph::::new()) - } - #[test] - fn directed_edges() { - test::directed_edges(SimpleMapGraph::::new()) - } - #[test] - fn remove_node_undirected() { - test::remove_node_undirected(SimpleMapGraph::::new()) - } - #[test] - fn remove_node_directed() { - test::remove_node_directed(SimpleMapGraph::::new()) - } + graph_tests!(super::SimpleMapGraph); } diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index d2176a4cad724..26304be8e1082 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -19,6 +19,34 @@ mod test { Jennifer, } + #[macro_export] + macro_rules! graph_tests { + ($($graph:ident )::+) => { + use $crate::graphs::simple::test::{self, Person}; + + #[test] + fn nodes() { + test::nodes(<$($graph)::+ >::new()) + } + #[test] + fn undirected_edges() { + test::undirected_edges(<$($graph)::+ >::new()) + } + #[test] + fn directed_edges() { + test::directed_edges(<$($graph)::+ >::new()) + } + #[test] + fn remove_node_undirected() { + test::remove_node_undirected(<$($graph)::+ >::new()) + } + #[test] + fn remove_node_directed() { + test::remove_node_directed(<$($graph)::+ >::new()) + } + }; + } + pub fn nodes(mut graph: impl Graph) { let jake = graph.new_node(Person::Jake); let michael = graph.new_node(Person::Michael); From 0710a1dd8bd08eff6c355adb2721c04a28c60fc3 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 13 Jan 2023 16:27:31 +0100 Subject: [PATCH 045/183] Cleanup --- crates/bevy_graph/src/graphs/simple/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index 26304be8e1082..9e1cd3cdf77d4 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -105,7 +105,7 @@ mod test { graph.edge_between(jake, jennifer) ); - graph.get_edge_mut(mo).map(|edge| *edge = 10); + *graph.get_edge_mut(mo).unwrap() = 10; assert_eq!(graph.get_edge(jm).unwrap(), &2); assert_eq!(graph.get_edge(jj).unwrap(), &7); @@ -147,7 +147,7 @@ mod test { assert!(!graph.edge_between(jennifer, jake).is_null()); assert!(graph.edge_between(jake, jennifer).is_null()); - graph.get_edge_mut(mo).map(|edge| *edge = 10); + *graph.get_edge_mut(mo).unwrap() = 10; assert_eq!(graph.get_edge(jm).unwrap(), &2); assert_eq!(graph.get_edge(jj).unwrap(), &7); From cf661e1dd5268a98bed34a01421cd084f0cf982e Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 13 Jan 2023 18:16:02 +0100 Subject: [PATCH 046/183] =?UTF-8?q?Refactor=20`new=5Fedge`=20with=20safety?= =?UTF-8?q?=20=E2=9A=A0=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/bevy_graph/src/algos/bfs.rs | 14 ++-- crates/bevy_graph/src/error.rs | 1 + crates/bevy_graph/src/graphs/keys.rs | 4 +- crates/bevy_graph/src/graphs/mod.rs | 12 +-- crates/bevy_graph/src/graphs/simple/list.rs | 89 ++++++++++++++------ crates/bevy_graph/src/graphs/simple/map.rs | 89 ++++++++++++++------ crates/bevy_graph/src/graphs/simple/mod.rs | 92 ++++++++++----------- 7 files changed, 195 insertions(+), 106 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 4dc601bfa0fbc..88e31617d0b97 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -28,7 +28,7 @@ impl BreadthFirstSearch { self.queue.push_back(idx); } } - Some(graph.node(node).unwrap()) + Some(graph.get_node(node).unwrap()) } else { None } @@ -42,7 +42,7 @@ impl BreadthFirstSearch { self.queue.push_back(idx); } } - Some(graph.node_mut(node).unwrap()) + Some(graph.get_node_mut(node).unwrap()) } else { None } @@ -64,11 +64,11 @@ mod test { let sum = 6; // 0 + 1 + 2 + 3 - map.new_edge(zero, one, ()); - map.new_edge(zero, two, ()); - map.new_edge(one, two, ()); - map.new_edge(two, zero, ()); - map.new_edge(two, three, ()); + map.new_edge(zero, one, ()).unwrap(); + map.new_edge(zero, two, ()).unwrap(); + map.new_edge(one, two, ()).unwrap(); + map.new_edge(two, zero, ()).unwrap(); + map.new_edge(two, three, ()).unwrap(); let mut counter = 0; diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs index e17c8404ac2cf..b79cadefb3e9c 100644 --- a/crates/bevy_graph/src/error.rs +++ b/crates/bevy_graph/src/error.rs @@ -4,6 +4,7 @@ use crate::graphs::keys::{EdgeIdx, NodeIdx}; pub enum GraphError { NodeDoesntExist(NodeIdx), EdgeDoesntExist(EdgeIdx), + EdgeAlreadyExists(NodeIdx, NodeIdx), } pub type GraphResult = Result; diff --git a/crates/bevy_graph/src/graphs/keys.rs b/crates/bevy_graph/src/graphs/keys.rs index a5cf8844eea61..7432849b04742 100644 --- a/crates/bevy_graph/src/graphs/keys.rs +++ b/crates/bevy_graph/src/graphs/keys.rs @@ -11,12 +11,12 @@ new_key_type! { impl EdgeIdx { #[inline] - pub fn get(self, graph: &impl Graph) -> Option<&E> { + pub fn get(self, graph: &impl Graph) -> GraphResult<&E> { graph.get_edge(self) } #[inline] - pub fn get_mut(self, graph: &mut impl Graph) -> Option<&mut E> { + pub fn get_mut(self, graph: &mut impl Graph) -> GraphResult<&mut E> { graph.get_edge_mut(self) } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 632fc634caf59..96f92f7a34084 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -15,16 +15,18 @@ pub trait Graph { // Nodes fn new_node(&mut self, node: N) -> NodeIdx; - fn node(&self, idx: NodeIdx) -> GraphResult<&N>; - fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; + fn get_node(&self, idx: NodeIdx) -> GraphResult<&N>; + fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; fn remove_node(&mut self, node: NodeIdx) -> GraphResult; + fn has_node(&self, node: NodeIdx) -> bool; + // Edges - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult; - fn get_edge(&self, edge: EdgeIdx) -> Option<&E>; - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E>; + fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E>; + fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E>; fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 8ef7241d2533d..4213f6f3f10b4 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -41,7 +41,7 @@ impl_graph! { } #[inline] - fn node(&self, idx: NodeIdx) -> GraphResult<&N> { + fn get_node(&self, idx: NodeIdx) -> GraphResult<&N> { if let Some(node) = self.nodes.get(idx) { Ok(node) } else { @@ -50,7 +50,7 @@ impl_graph! { } #[inline] - fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { if let Some(node) = self.nodes.get_mut(idx) { Ok(node) } else { @@ -59,13 +59,24 @@ impl_graph! { } #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { - self.edges.get(edge).map(|e| &e.data) + fn has_node(&self, node: NodeIdx) -> bool { + self.nodes.contains_key(node) } #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { - self.edges.get_mut(edge).map(|e| &mut e.data) + fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E> { + match self.edges.get(edge) { + Some(e) => Ok(&e.data), + None => Err(GraphError::EdgeDoesntExist(edge)) + } + } + + #[inline] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E> { + match self.edges.get_mut(edge) { + Some(e) => Ok(&mut e.data), + None => Err(GraphError::EdgeDoesntExist(edge)) + } } #[inline] @@ -100,15 +111,33 @@ impl_graph! { } } - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: node, - dst: other, - data: edge, - }); - self.adjacencies.get_mut(node).unwrap().push((other, idx)); - self.adjacencies.get_mut(other).unwrap().push((node, idx)); - idx + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { + if let Some(node_edges) = self.adjacencies.get(node) { + if node_edges.iter().any(|(n, _)| *n == other) { + Err(GraphError::EdgeAlreadyExists(node, other)) + } else { + if let Some(other_edges) = self.adjacencies.get(other) { + if other_edges.iter().any(|(n, _)| *n == node) { + Err(GraphError::EdgeAlreadyExists(other, node)) + } else { + let idx = self.edges.insert(Edge { + src: node, + dst: other, + data: edge, + }); + unsafe { + self.adjacencies.get_unchecked_mut(node).push((other, idx)); + self.adjacencies.get_unchecked_mut(other).push((node, idx)); + } + Ok(idx) + } + } else { + Err(GraphError::NodeDoesntExist(other)) + } + } + } else { + Err(GraphError::NodeDoesntExist(node)) + } } fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { @@ -151,14 +180,28 @@ impl_graph! { } } - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); - self.adjacencies.get_mut(from).unwrap().push((to, idx)); - idx + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { + if let Some(from_edges) = self.adjacencies.get(from) { + if from_edges.iter().any(|(n, _)| *n == to) { + Err(GraphError::EdgeAlreadyExists(from, to)) + } else { + if self.has_node(to) { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); + unsafe { + self.adjacencies.get_unchecked_mut(from).push((to, idx)); + } + Ok(idx) + } else { + Err(GraphError::NodeDoesntExist(to)) + } + } + } else { + Err(GraphError::NodeDoesntExist(from)) + } } fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index d76b93b9255d1..49f4218aca034 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -41,7 +41,7 @@ impl_graph! { } #[inline] - fn node(&self, idx: NodeIdx) -> GraphResult<&N> { + fn get_node(&self, idx: NodeIdx) -> GraphResult<&N> { if let Some(node) = self.nodes.get(idx) { Ok(node) } else { @@ -50,7 +50,7 @@ impl_graph! { } #[inline] - fn node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { if let Some(node) = self.nodes.get_mut(idx) { Ok(node) } else { @@ -59,13 +59,24 @@ impl_graph! { } #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Option<&E> { - self.edges.get(edge).map(|e| &e.data) + fn has_node(&self, node: NodeIdx) -> bool { + self.nodes.contains_key(node) } #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Option<&mut E> { - self.edges.get_mut(edge).map(|e| &mut e.data) + fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E> { + match self.edges.get(edge) { + Some(e) => Ok(&e.data), + None => Err(GraphError::EdgeDoesntExist(edge)) + } + } + + #[inline] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E> { + match self.edges.get_mut(edge) { + Some(e) => Ok(&mut e.data), + None => Err(GraphError::EdgeDoesntExist(edge)) + } } #[inline] @@ -100,15 +111,33 @@ impl_graph! { } } - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: node, - dst: other, - data: edge, - }); - self.adjacencies.get_mut(node).unwrap().insert(other, idx); - self.adjacencies.get_mut(other).unwrap().insert(node, idx); - idx + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { + if let Some(node_edges) = self.adjacencies.get(node) { + if node_edges.contains_key(&other) { + Err(GraphError::EdgeAlreadyExists(node, other)) + } else { + if let Some(other_edges) = self.adjacencies.get(other) { + if other_edges.contains_key(&node) { + Err(GraphError::EdgeAlreadyExists(node, other)) + } else { + let idx = self.edges.insert(Edge { + src: node, + dst: other, + data: edge, + }); + unsafe { + self.adjacencies.get_unchecked_mut(node).insert_unique_unchecked(other, idx); + self.adjacencies.get_unchecked_mut(other).insert_unique_unchecked(node, idx); + } + Ok(idx) + } + } else { + Err(GraphError::NodeDoesntExist(other)) + } + } + } else { + Err(GraphError::NodeDoesntExist(node)) + } } fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { @@ -141,14 +170,28 @@ impl_graph! { } } - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); - self.adjacencies.get_mut(from).unwrap().insert(to, idx); - idx + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { + if let Some(from_edges) = self.adjacencies.get(from) { + if from_edges.contains_key(&to) { + Err(GraphError::EdgeAlreadyExists(from, to)) + } else { + if self.has_node(to) { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); + unsafe { + self.adjacencies.get_unchecked_mut(from).insert_unique_unchecked(to, idx); + } + Ok(idx) + } else { + Err(GraphError::NodeDoesntExist(to)) + } + } + } else { + Err(GraphError::NodeDoesntExist(from)) + } } fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index 9e1cd3cdf77d4..ad38d4138ed64 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -53,30 +53,30 @@ mod test { let jennifer = graph.new_node(Person::Jennifer); let other_jake = graph.new_node(Person::Jake); - assert_eq!(graph.node(jake).unwrap(), &Person::Jake); - assert_eq!(graph.node(michael).unwrap(), &Person::Michael); - assert_eq!(graph.node(jennifer).unwrap(), &Person::Jennifer); - assert_eq!(graph.node(other_jake).unwrap(), &Person::Jake); + assert_eq!(graph.get_node(jake).unwrap(), &Person::Jake); + assert_eq!(graph.get_node(michael).unwrap(), &Person::Michael); + assert_eq!(graph.get_node(jennifer).unwrap(), &Person::Jennifer); + assert_eq!(graph.get_node(other_jake).unwrap(), &Person::Jake); graph - .node_mut(jake) + .get_node_mut(jake) .map(|node| *node = Person::Michael) .unwrap(); - assert_eq!(graph.node(jake).unwrap(), &Person::Michael); - assert_eq!(graph.node(michael).unwrap(), &Person::Michael); - assert_eq!(graph.node(jennifer).unwrap(), &Person::Jennifer); - assert_eq!(graph.node(other_jake).unwrap(), &Person::Jake); + assert_eq!(graph.get_node(jake).unwrap(), &Person::Michael); + assert_eq!(graph.get_node(michael).unwrap(), &Person::Michael); + assert_eq!(graph.get_node(jennifer).unwrap(), &Person::Jennifer); + assert_eq!(graph.get_node(other_jake).unwrap(), &Person::Jake); assert!(graph.remove_node(jake).is_ok()); assert!(graph.remove_node(michael).is_ok()); assert!(graph.remove_node(jennifer).is_ok()); assert!(graph.remove_node(other_jake).is_ok()); - assert!(graph.node(jake).is_err()); - assert!(graph.node(michael).is_err()); - assert!(graph.node(jennifer).is_err()); - assert!(graph.node(other_jake).is_err()); + assert!(graph.get_node(jake).is_err()); + assert!(graph.get_node(michael).is_err()); + assert!(graph.get_node(jennifer).is_err()); + assert!(graph.get_node(other_jake).is_err()); } pub fn undirected_edges(mut graph: impl Graph) { @@ -85,10 +85,10 @@ mod test { let jennifer = graph.new_node(Person::Jennifer); let other_jake = graph.new_node(Person::Jake); - let jm = graph.new_edge(jake, michael, 2); - let jj = graph.new_edge(jennifer, jake, 7); - let jo = graph.new_edge(jake, other_jake, 5); - let mo = graph.new_edge(michael, other_jake, 1); + let jm = graph.new_edge(jake, michael, 2).unwrap(); + let jj = graph.new_edge(jennifer, jake, 7).unwrap(); + let jo = graph.new_edge(jake, other_jake, 5).unwrap(); + let mo = graph.new_edge(michael, other_jake, 1).unwrap(); assert!(unordered_eq( &graph.edges_of(jake), @@ -117,10 +117,10 @@ mod test { assert!(graph.remove_edge(jo).is_ok()); assert!(graph.remove_edge(mo).is_ok()); - assert!(graph.get_edge(jm).is_none()); - assert!(graph.get_edge(jj).is_none()); - assert!(graph.get_edge(jo).is_none()); - assert!(graph.get_edge(mo).is_none()); + assert!(graph.get_edge(jm).is_err()); + assert!(graph.get_edge(jj).is_err()); + assert!(graph.get_edge(jo).is_err()); + assert!(graph.get_edge(mo).is_err()); } pub fn directed_edges(mut graph: impl Graph) { @@ -129,10 +129,10 @@ mod test { let jennifer = graph.new_node(Person::Jennifer); let other_jake = graph.new_node(Person::Jake); - let jm = graph.new_edge(jake, michael, 2); - let jj = graph.new_edge(jennifer, jake, 7); - let jo = graph.new_edge(jake, other_jake, 5); - let mo = graph.new_edge(michael, other_jake, 1); + let jm = graph.new_edge(jake, michael, 2).unwrap(); + let jj = graph.new_edge(jennifer, jake, 7).unwrap(); + let jo = graph.new_edge(jake, other_jake, 5).unwrap(); + let mo = graph.new_edge(michael, other_jake, 1).unwrap(); assert!(unordered_eq( &graph.edges_of(jake), @@ -159,52 +159,52 @@ mod test { assert!(graph.remove_edge(jo).is_ok()); assert!(graph.remove_edge(mo).is_ok()); - assert!(graph.get_edge(jm).is_none()); - assert!(graph.get_edge(jj).is_none()); - assert!(graph.get_edge(jo).is_none()); - assert!(graph.get_edge(mo).is_none()); + assert!(graph.get_edge(jm).is_err()); + assert!(graph.get_edge(jj).is_err()); + assert!(graph.get_edge(jo).is_err()); + assert!(graph.get_edge(mo).is_err()); } pub fn remove_node_undirected(mut graph: impl Graph) { let jake = graph.new_node(Person::Jake); let michael = graph.new_node(Person::Michael); - let edge = graph.new_edge(jake, michael, 20); + let edge = graph.new_edge(jake, michael, 20).unwrap(); - assert!(graph.node(jake).is_ok()); - assert!(graph.node(michael).is_ok()); + assert!(graph.get_node(jake).is_ok()); + assert!(graph.get_node(michael).is_ok()); assert_eq!(graph.get_edge(edge).unwrap(), &20); assert_eq!(graph.edge_between(jake, michael).get(&graph).unwrap(), &20); assert_eq!(graph.edge_between(michael, jake).get(&graph).unwrap(), &20); assert!(graph.remove_node(michael).is_ok()); - assert!(graph.node(jake).is_ok()); - assert!(graph.node(michael).is_err()); - assert!(graph.get_edge(edge).is_none()); - assert!(graph.edge_between(jake, michael).get(&graph).is_none()); - assert!(graph.edge_between(michael, jake).get(&graph).is_none()); + assert!(graph.get_node(jake).is_ok()); + assert!(graph.get_node(michael).is_err()); + assert!(graph.get_edge(edge).is_err()); + assert!(graph.edge_between(jake, michael).get(&graph).is_err()); + assert!(graph.edge_between(michael, jake).get(&graph).is_err()); } pub fn remove_node_directed(mut graph: impl Graph) { let jake = graph.new_node(Person::Jake); let michael = graph.new_node(Person::Michael); - let edge = graph.new_edge(jake, michael, 20); + let edge = graph.new_edge(jake, michael, 20).unwrap(); - assert!(graph.node(jake).is_ok()); - assert!(graph.node(michael).is_ok()); + assert!(graph.get_node(jake).is_ok()); + assert!(graph.get_node(michael).is_ok()); assert_eq!(graph.get_edge(edge).unwrap(), &20); assert_eq!(graph.edge_between(jake, michael).get(&graph).unwrap(), &20); - assert!(graph.edge_between(michael, jake).get(&graph).is_none()); + assert!(graph.edge_between(michael, jake).get(&graph).is_err()); assert!(graph.remove_node(michael).is_ok()); - assert!(graph.node(jake).is_ok()); - assert!(graph.node(michael).is_err()); - assert!(graph.get_edge(edge).is_none()); - assert!(graph.edge_between(jake, michael).get(&graph).is_none()); - assert!(graph.edge_between(michael, jake).get(&graph).is_none()); + assert!(graph.get_node(jake).is_ok()); + assert!(graph.get_node(michael).is_err()); + assert!(graph.get_edge(edge).is_err()); + assert!(graph.edge_between(jake, michael).get(&graph).is_err()); + assert!(graph.edge_between(michael, jake).get(&graph).is_err()); } fn unordered_eq(a: &[T], b: &[T]) -> bool From 7e1571d0f8864ab00bbfbf9febcf1a250beb693c Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 13 Jan 2023 18:22:49 +0100 Subject: [PATCH 047/183] =?UTF-8?q?outscore=20in=20unsafe=20functions=20?= =?UTF-8?q?=F0=9F=A5=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/bevy_graph/src/graphs/mod.rs | 1 + crates/bevy_graph/src/graphs/simple/list.rs | 38 +++++++++++++-------- crates/bevy_graph/src/graphs/simple/map.rs | 38 +++++++++++++-------- 3 files changed, 47 insertions(+), 30 deletions(-) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 96f92f7a34084..d0ae3558b00f0 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -24,6 +24,7 @@ pub trait Graph { // Edges fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult; + unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E>; fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E>; diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 4213f6f3f10b4..25e232b6cbaa0 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -120,16 +120,9 @@ impl_graph! { if other_edges.iter().any(|(n, _)| *n == node) { Err(GraphError::EdgeAlreadyExists(other, node)) } else { - let idx = self.edges.insert(Edge { - src: node, - dst: other, - data: edge, - }); unsafe { - self.adjacencies.get_unchecked_mut(node).push((other, idx)); - self.adjacencies.get_unchecked_mut(other).push((node, idx)); + Ok(self.new_edge_unchecked(node, other, edge)) } - Ok(idx) } } else { Err(GraphError::NodeDoesntExist(other)) @@ -140,6 +133,17 @@ impl_graph! { } } + unsafe fn new_edge_unchecked(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: node, + dst: other, + data: edge, + }); + self.adjacencies.get_unchecked_mut(node).push((other, idx)); + self.adjacencies.get_unchecked_mut(other).push((node, idx)); + idx + } + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { let list = self.adjacencies.get_mut(node).unwrap(); @@ -186,15 +190,9 @@ impl_graph! { Err(GraphError::EdgeAlreadyExists(from, to)) } else { if self.has_node(to) { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); unsafe { - self.adjacencies.get_unchecked_mut(from).push((to, idx)); + Ok(self.new_edge_unchecked(from, to, edge)) } - Ok(idx) } else { Err(GraphError::NodeDoesntExist(to)) } @@ -204,6 +202,16 @@ impl_graph! { } } + unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); + self.adjacencies.get_unchecked_mut(from).push((to, idx)); + idx + } + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { if let Some((from, to)) = self.edges.get(edge).map(|e| e.indices()) { let list = self.adjacencies.get_mut(from).unwrap(); diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 49f4218aca034..54a55a92b1af6 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -120,16 +120,9 @@ impl_graph! { if other_edges.contains_key(&node) { Err(GraphError::EdgeAlreadyExists(node, other)) } else { - let idx = self.edges.insert(Edge { - src: node, - dst: other, - data: edge, - }); unsafe { - self.adjacencies.get_unchecked_mut(node).insert_unique_unchecked(other, idx); - self.adjacencies.get_unchecked_mut(other).insert_unique_unchecked(node, idx); + Ok(self.new_edge_unchecked(node, other, edge)) } - Ok(idx) } } else { Err(GraphError::NodeDoesntExist(other)) @@ -140,6 +133,17 @@ impl_graph! { } } + unsafe fn new_edge_unchecked(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: node, + dst: other, + data: edge, + }); + self.adjacencies.get_unchecked_mut(node).insert_unique_unchecked(other, idx); + self.adjacencies.get_unchecked_mut(other).insert_unique_unchecked(node, idx); + idx + } + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { self.adjacencies.get_mut(node).unwrap().remove(&other); @@ -176,15 +180,9 @@ impl_graph! { Err(GraphError::EdgeAlreadyExists(from, to)) } else { if self.has_node(to) { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); unsafe { - self.adjacencies.get_unchecked_mut(from).insert_unique_unchecked(to, idx); + Ok(self.new_edge_unchecked(from, to, edge)) } - Ok(idx) } else { Err(GraphError::NodeDoesntExist(to)) } @@ -194,6 +192,16 @@ impl_graph! { } } + unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); + self.adjacencies.get_unchecked_mut(from).insert_unique_unchecked(to, idx); + idx + } + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { if let Some((from, to)) = self.edges.get(edge).map(|e| e.indices()) { self.adjacencies.get_mut(from).unwrap().remove(&to); From 033c20099b5f8f3c101e5c2437187bc4fc6827b7 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 13 Jan 2023 18:28:37 +0100 Subject: [PATCH 048/183] =?UTF-8?q?Make=20clippy=20happy=20=F0=9F=98=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/bevy_graph/src/graphs/mod.rs | 9 +++++++ crates/bevy_graph/src/graphs/simple/list.rs | 30 +++++++++------------ crates/bevy_graph/src/graphs/simple/map.rs | 30 +++++++++------------ 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index d0ae3558b00f0..6c1d8ee108743 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -12,7 +12,9 @@ use self::keys::{EdgeIdx, NodeIdx}; pub trait Graph { fn count(&self) -> usize; + //////////////////////////// // Nodes + //////////////////////////// fn new_node(&mut self, node: N) -> NodeIdx; fn get_node(&self, idx: NodeIdx) -> GraphResult<&N>; @@ -22,8 +24,13 @@ pub trait Graph { fn has_node(&self, node: NodeIdx) -> bool; + //////////////////////////// // Edges + //////////////////////////// fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult; + /// # Safety + /// + /// This function should only be called when the nodes exist and there is no equal edge. unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E>; @@ -34,7 +41,9 @@ pub trait Graph { fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? + //////////////////////////// // Algos + //////////////////////////// #[inline] fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { BreadthFirstSearch::new(start, self.count()) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 25e232b6cbaa0..02649aba68127 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -115,18 +115,16 @@ impl_graph! { if let Some(node_edges) = self.adjacencies.get(node) { if node_edges.iter().any(|(n, _)| *n == other) { Err(GraphError::EdgeAlreadyExists(node, other)) - } else { - if let Some(other_edges) = self.adjacencies.get(other) { - if other_edges.iter().any(|(n, _)| *n == node) { - Err(GraphError::EdgeAlreadyExists(other, node)) - } else { - unsafe { - Ok(self.new_edge_unchecked(node, other, edge)) - } - } + } else if let Some(other_edges) = self.adjacencies.get(other) { + if other_edges.iter().any(|(n, _)| *n == node) { + Err(GraphError::EdgeAlreadyExists(other, node)) } else { - Err(GraphError::NodeDoesntExist(other)) + unsafe { + Ok(self.new_edge_unchecked(node, other, edge)) + } } + } else { + Err(GraphError::NodeDoesntExist(other)) } } else { Err(GraphError::NodeDoesntExist(node)) @@ -188,14 +186,12 @@ impl_graph! { if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.iter().any(|(n, _)| *n == to) { Err(GraphError::EdgeAlreadyExists(from, to)) - } else { - if self.has_node(to) { - unsafe { - Ok(self.new_edge_unchecked(from, to, edge)) - } - } else { - Err(GraphError::NodeDoesntExist(to)) + } else if self.has_node(to) { + unsafe { + Ok(self.new_edge_unchecked(from, to, edge)) } + } else { + Err(GraphError::NodeDoesntExist(to)) } } else { Err(GraphError::NodeDoesntExist(from)) diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 54a55a92b1af6..3f00af82c0f16 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -115,18 +115,16 @@ impl_graph! { if let Some(node_edges) = self.adjacencies.get(node) { if node_edges.contains_key(&other) { Err(GraphError::EdgeAlreadyExists(node, other)) - } else { - if let Some(other_edges) = self.adjacencies.get(other) { - if other_edges.contains_key(&node) { - Err(GraphError::EdgeAlreadyExists(node, other)) - } else { - unsafe { - Ok(self.new_edge_unchecked(node, other, edge)) - } - } + } else if let Some(other_edges) = self.adjacencies.get(other) { + if other_edges.contains_key(&node) { + Err(GraphError::EdgeAlreadyExists(node, other)) } else { - Err(GraphError::NodeDoesntExist(other)) + unsafe { + Ok(self.new_edge_unchecked(node, other, edge)) + } } + } else { + Err(GraphError::NodeDoesntExist(other)) } } else { Err(GraphError::NodeDoesntExist(node)) @@ -178,14 +176,12 @@ impl_graph! { if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.contains_key(&to) { Err(GraphError::EdgeAlreadyExists(from, to)) - } else { - if self.has_node(to) { - unsafe { - Ok(self.new_edge_unchecked(from, to, edge)) - } - } else { - Err(GraphError::NodeDoesntExist(to)) + } else if self.has_node(to) { + unsafe { + Ok(self.new_edge_unchecked(from, to, edge)) } + } else { + Err(GraphError::NodeDoesntExist(to)) } } else { Err(GraphError::NodeDoesntExist(from)) From 18a42327ab24ce0d41743ea45c36f1515d7bdfe0 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 13 Jan 2023 18:58:03 +0100 Subject: [PATCH 049/183] benchmarks fast fix --- benches/benches/bevy_graph/map.rs | 36 ++++++++++++------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/benches/benches/bevy_graph/map.rs b/benches/benches/bevy_graph/map.rs index 003c4b6918515..1e7f03a73a570 100644 --- a/benches/benches/bevy_graph/map.rs +++ b/benches/benches/bevy_graph/map.rs @@ -16,39 +16,31 @@ criterion_group! { targets = nodes_10_000_undirected } +// TODO: find a better way for fix with multiple iterations over same graph fn nodes_10_000_undirected(c: &mut Criterion) { - let mut map_graph = SimpleMapGraph::::new(); - - let mut nodes: Vec = Vec::with_capacity(10_000); - c.bench_function("nodes_10_000_new_node", |b| { + c.bench_function("nodes_10_000", |b| { b.iter(|| { + let mut graph = SimpleMapGraph::::new(); + + let mut nodes: Vec = Vec::with_capacity(10_000); for i in 1..=10_000 { - nodes.push(map_graph.new_node(i)); + nodes.push(graph.new_node(i)); } - }) - }); - let mut edges: Vec = Vec::with_capacity(10_000 - 1); - c.bench_function("nodes_10_000_new_edge", |b| { - b.iter(|| { + + let mut edges: Vec = Vec::with_capacity(10_000 - 1); for i in 1..10_000 { - edges.push(map_graph.new_edge(nodes[i - 1], nodes[i], ())); + edges.push(graph.new_edge(nodes[i - 1], nodes[i], ()).unwrap()); } - }) - }); - c.bench_function("nodes_10_000_get_edge", |b| { - b.iter(|| { + for edge in &edges { - black_box(edge.get(&map_graph)); + black_box(edge.get(&graph)); } - }) - }); - c.bench_function("nodes_10_000_remove_edge", |b| { - b.iter(|| { + for i in 1..10_000 { black_box( - map_graph + graph .edge_between(nodes[i - 1], nodes[i]) - .remove(&mut map_graph) + .remove(&mut graph) .unwrap(), ); } From e3be206be15dc5a7d6bc25645585d5562188ce76 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 13 Jan 2023 19:43:28 +0100 Subject: [PATCH 050/183] make indices const :D --- crates/bevy_graph/src/graphs/edge.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs index 5c2dff9a26f7a..81d8deb11ac2b 100644 --- a/crates/bevy_graph/src/graphs/edge.rs +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -9,7 +9,7 @@ pub struct Edge { impl Edge { #[inline] - pub fn indices(&self) -> (NodeIdx, NodeIdx) { + pub const fn indices(&self) -> (NodeIdx, NodeIdx) { (self.src, self.dst) } } From 450ff002408e154f7a3344fe535b2299d1b422c1 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 13 Jan 2023 19:54:19 +0100 Subject: [PATCH 051/183] Preparation for Multi Graphs :O --- crates/bevy_graph/src/graphs/mod.rs | 1 + crates/bevy_graph/src/graphs/multi/map.rs | 129 +++++++++++++++++++++ crates/bevy_graph/src/graphs/multi/mod.rs | 2 + crates/bevy_graph/src/graphs/simple/map.rs | 1 + 4 files changed, 133 insertions(+) create mode 100644 crates/bevy_graph/src/graphs/multi/map.rs create mode 100644 crates/bevy_graph/src/graphs/multi/mod.rs diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 6c1d8ee108743..a4f7f53a066b5 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -1,3 +1,4 @@ +pub mod multi; pub mod simple; pub mod edge; diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs new file mode 100644 index 0000000000000..21ca179c10f28 --- /dev/null +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -0,0 +1,129 @@ +use hashbrown::HashMap; +use slotmap::{HopSlotMap, SecondaryMap}; + +use crate::{ + error::{GraphError, GraphResult}, + graphs::{ + edge::Edge, + keys::{EdgeIdx, NodeIdx}, + }, + impl_graph, +}; + +#[derive(Clone)] +pub struct MultiMapGraph { + nodes: HopSlotMap, + edges: HopSlotMap>, + adjacencies: SecondaryMap>>, +} + +impl MultiMapGraph { + pub fn new() -> Self { + Self { + nodes: HopSlotMap::with_key(), + edges: HopSlotMap::with_key(), + adjacencies: SecondaryMap::new(), + } + } +} + +impl_graph! { + impl common for MultiMapGraph { + #[inline] + fn count(&self) -> usize { + self.nodes.len() + } + + #[inline] + fn new_node(&mut self, node: N) -> NodeIdx { + let idx = self.nodes.insert(node); + self.adjacencies.insert(idx, HashMap::new()); + idx + } + + #[inline] + fn get_node(&self, idx: NodeIdx) -> GraphResult<&N> { + if let Some(node) = self.nodes.get(idx) { + Ok(node) + } else { + Err(GraphError::NodeDoesntExist(idx)) + } + } + + #[inline] + fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + if let Some(node) = self.nodes.get_mut(idx) { + Ok(node) + } else { + Err(GraphError::NodeDoesntExist(idx)) + } + } + + #[inline] + fn has_node(&self, node: NodeIdx) -> bool { + self.nodes.contains_key(node) + } + + #[inline] + fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E> { + match self.edges.get(edge) { + Some(e) => Ok(&e.data), + None => Err(GraphError::EdgeDoesntExist(edge)) + } + } + + #[inline] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E> { + match self.edges.get_mut(edge) { + Some(e) => Ok(&mut e.data), + None => Err(GraphError::EdgeDoesntExist(edge)) + } + } + + #[inline] + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + todo!() + } + + #[inline] + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + todo!() + } + } + + impl undirected { + fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + todo!() + } + + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { + todo!() + } + + unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + todo!() + } + + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + todo!() + } + } + + impl directed { + fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + todo!() + } + + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { + todo!() + } + + unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + todo!() + } + + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + todo!() + } + } +} diff --git a/crates/bevy_graph/src/graphs/multi/mod.rs b/crates/bevy_graph/src/graphs/multi/mod.rs new file mode 100644 index 0000000000000..aa2efd93933f6 --- /dev/null +++ b/crates/bevy_graph/src/graphs/multi/mod.rs @@ -0,0 +1,2 @@ +mod map; +pub use map::*; diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 3f00af82c0f16..313d1ca8782cf 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -34,6 +34,7 @@ impl_graph! { self.nodes.len() } + #[inline] fn new_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, HashMap::new()); From c2c0ddc53af307bcfe5534529f79704f5d507467 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 13 Jan 2023 20:16:01 +0100 Subject: [PATCH 052/183] `edge_between` now returns GraphResult --- crates/bevy_graph/src/error.rs | 7 ++- crates/bevy_graph/src/graphs/mod.rs | 6 +- crates/bevy_graph/src/graphs/multi/map.rs | 39 +++++++----- crates/bevy_graph/src/graphs/simple/list.rs | 57 +++++++++++------- crates/bevy_graph/src/graphs/simple/map.rs | 55 ++++++++++------- crates/bevy_graph/src/graphs/simple/mod.rs | 66 +++++++++++++++++---- 6 files changed, 153 insertions(+), 77 deletions(-) diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs index b79cadefb3e9c..fa8d4688cb4b0 100644 --- a/crates/bevy_graph/src/error.rs +++ b/crates/bevy_graph/src/error.rs @@ -2,9 +2,10 @@ use crate::graphs::keys::{EdgeIdx, NodeIdx}; #[derive(Debug)] pub enum GraphError { - NodeDoesntExist(NodeIdx), - EdgeDoesntExist(EdgeIdx), - EdgeAlreadyExists(NodeIdx, NodeIdx), + NodeIdxDoesntExist(NodeIdx), + EdgeIdxDoesntExist(EdgeIdx), + EdgeBetweenDoesntExist(NodeIdx, NodeIdx), + EdgeBetweenAlreadyExists(NodeIdx, NodeIdx), } pub type GraphResult = Result; diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index a4f7f53a066b5..4a1bcd1ef0ae6 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -39,7 +39,11 @@ pub trait Graph { fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult; + /// # Safety + /// + /// This function should only be called when the nodes and the edge between exists. + unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? //////////////////////////// diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 21ca179c10f28..3dbf150ffc44c 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -46,7 +46,7 @@ impl_graph! { if let Some(node) = self.nodes.get(idx) { Ok(node) } else { - Err(GraphError::NodeDoesntExist(idx)) + Err(GraphError::NodeIdxDoesntExist(idx)) } } @@ -55,7 +55,7 @@ impl_graph! { if let Some(node) = self.nodes.get_mut(idx) { Ok(node) } else { - Err(GraphError::NodeDoesntExist(idx)) + Err(GraphError::NodeIdxDoesntExist(idx)) } } @@ -68,7 +68,7 @@ impl_graph! { fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E> { match self.edges.get(edge) { Some(e) => Ok(&e.data), - None => Err(GraphError::EdgeDoesntExist(edge)) + None => Err(GraphError::EdgeIdxDoesntExist(edge)) } } @@ -76,54 +76,65 @@ impl_graph! { fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E> { match self.edges.get_mut(edge) { Some(e) => Ok(&mut e.data), - None => Err(GraphError::EdgeDoesntExist(edge)) + None => Err(GraphError::EdgeIdxDoesntExist(edge)) } } #[inline] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + fn edge_between(&self, _from: NodeIdx, _to: NodeIdx) -> GraphResult { + todo!() + } + + unsafe fn edge_between_unchecked(&self, _from: NodeIdx, _to: NodeIdx) -> EdgeIdx { todo!() } #[inline] - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + fn edges_of(&self, _node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { todo!() } } impl undirected { - fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + fn remove_node(&mut self, _node: NodeIdx) -> GraphResult { todo!() } - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { + fn new_edge(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> GraphResult { todo!() } - unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + unsafe fn new_edge_unchecked(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> EdgeIdx { todo!() } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + fn remove_edge(&mut self, _edge: EdgeIdx) -> GraphResult { todo!() } } impl directed { - fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + fn remove_node(&mut self, _node: NodeIdx) -> GraphResult { todo!() } - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { + fn new_edge(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> GraphResult { todo!() } - unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + unsafe fn new_edge_unchecked(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> EdgeIdx { todo!() } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + fn remove_edge(&mut self, _edge: EdgeIdx) -> GraphResult { todo!() } } } + +impl Default for MultiMapGraph { + #[inline] + fn default() -> Self { + Self::new() + } +} diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 02649aba68127..8a75cdf38a091 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -45,7 +45,7 @@ impl_graph! { if let Some(node) = self.nodes.get(idx) { Ok(node) } else { - Err(GraphError::NodeDoesntExist(idx)) + Err(GraphError::NodeIdxDoesntExist(idx)) } } @@ -54,7 +54,7 @@ impl_graph! { if let Some(node) = self.nodes.get_mut(idx) { Ok(node) } else { - Err(GraphError::NodeDoesntExist(idx)) + Err(GraphError::NodeIdxDoesntExist(idx)) } } @@ -67,7 +67,7 @@ impl_graph! { fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E> { match self.edges.get(edge) { Some(e) => Ok(&e.data), - None => Err(GraphError::EdgeDoesntExist(edge)) + None => Err(GraphError::EdgeIdxDoesntExist(edge)) } } @@ -75,17 +75,28 @@ impl_graph! { fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E> { match self.edges.get_mut(edge) { Some(e) => Ok(&mut e.data), - None => Err(GraphError::EdgeDoesntExist(edge)) + None => Err(GraphError::EdgeIdxDoesntExist(edge)) } } #[inline] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - if let Some(idx) = self - .adjacencies - .get(from) - .unwrap() - .iter() + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult { + if self.adjacencies.contains_key(from) { + unsafe { + let idx = self.edge_between_unchecked(from, to); + if idx.is_null() { + Err(GraphError::EdgeBetweenDoesntExist(from, to)) + } else { + Ok(idx) + } + } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) + } + } + + unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + if let Some(idx) = self.adjacencies.get_unchecked(from).iter() .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) { idx @@ -107,27 +118,27 @@ impl_graph! { } match self.nodes.remove(node) { Some(n) => Ok(n), - None => Err(GraphError::NodeDoesntExist(node)) + None => Err(GraphError::NodeIdxDoesntExist(node)) } } fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { if let Some(node_edges) = self.adjacencies.get(node) { if node_edges.iter().any(|(n, _)| *n == other) { - Err(GraphError::EdgeAlreadyExists(node, other)) + Err(GraphError::EdgeBetweenAlreadyExists(node, other)) } else if let Some(other_edges) = self.adjacencies.get(other) { if other_edges.iter().any(|(n, _)| *n == node) { - Err(GraphError::EdgeAlreadyExists(other, node)) + Err(GraphError::EdgeBetweenAlreadyExists(other, node)) } else { unsafe { Ok(self.new_edge_unchecked(node, other, edge)) } } } else { - Err(GraphError::NodeDoesntExist(other)) + Err(GraphError::NodeIdxDoesntExist(other)) } } else { - Err(GraphError::NodeDoesntExist(node)) + Err(GraphError::NodeIdxDoesntExist(node)) } } @@ -156,10 +167,10 @@ impl_graph! { Ok(self.edges.remove(edge).unwrap().data) } else { - Err(GraphError::EdgeDoesntExist(edge)) + Err(GraphError::EdgeIdxDoesntExist(edge)) } } else { - Err(GraphError::EdgeDoesntExist(edge)) + Err(GraphError::EdgeIdxDoesntExist(edge)) } } } @@ -178,23 +189,23 @@ impl_graph! { } match self.nodes.remove(node) { Some(n) => Ok(n), - None => Err(GraphError::NodeDoesntExist(node)) + None => Err(GraphError::NodeIdxDoesntExist(node)) } } fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.iter().any(|(n, _)| *n == to) { - Err(GraphError::EdgeAlreadyExists(from, to)) + Err(GraphError::EdgeBetweenAlreadyExists(from, to)) } else if self.has_node(to) { unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } } else { - Err(GraphError::NodeDoesntExist(to)) + Err(GraphError::NodeIdxDoesntExist(to)) } } else { - Err(GraphError::NodeDoesntExist(from)) + Err(GraphError::NodeIdxDoesntExist(from)) } } @@ -217,10 +228,10 @@ impl_graph! { Ok(self.edges.remove(edge).unwrap().data) } else { - Err(GraphError::EdgeDoesntExist(edge)) + Err(GraphError::EdgeIdxDoesntExist(edge)) } } else { - Err(GraphError::EdgeDoesntExist(edge)) + Err(GraphError::EdgeIdxDoesntExist(edge)) } } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 313d1ca8782cf..e2c5c5fed45a0 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -1,5 +1,5 @@ use hashbrown::HashMap; -use slotmap::{HopSlotMap, Key, SecondaryMap}; +use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ error::{GraphError, GraphResult}, @@ -46,7 +46,7 @@ impl_graph! { if let Some(node) = self.nodes.get(idx) { Ok(node) } else { - Err(GraphError::NodeDoesntExist(idx)) + Err(GraphError::NodeIdxDoesntExist(idx)) } } @@ -55,7 +55,7 @@ impl_graph! { if let Some(node) = self.nodes.get_mut(idx) { Ok(node) } else { - Err(GraphError::NodeDoesntExist(idx)) + Err(GraphError::NodeIdxDoesntExist(idx)) } } @@ -68,7 +68,7 @@ impl_graph! { fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E> { match self.edges.get(edge) { Some(e) => Ok(&e.data), - None => Err(GraphError::EdgeDoesntExist(edge)) + None => Err(GraphError::EdgeIdxDoesntExist(edge)) } } @@ -76,18 +76,27 @@ impl_graph! { fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E> { match self.edges.get_mut(edge) { Some(e) => Ok(&mut e.data), - None => Err(GraphError::EdgeDoesntExist(edge)) + None => Err(GraphError::EdgeIdxDoesntExist(edge)) } } #[inline] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - self.adjacencies - .get(from) - .unwrap() - .get(&to) - .cloned() - .unwrap_or_else(EdgeIdx::null) + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult { + if let Some(from_edges) = self.adjacencies.get(from) { + if from_edges.contains_key(&to) { + unsafe { + Ok(self.edge_between_unchecked(from, to)) + } + } else { + Err(GraphError::EdgeBetweenDoesntExist(from, to)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) + } + } + + unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + self.adjacencies.get_unchecked(from).get(&to).cloned().unwrap() } #[inline] @@ -108,27 +117,27 @@ impl_graph! { } match self.nodes.remove(node) { Some(n) => Ok(n), - None => Err(GraphError::NodeDoesntExist(node)) + None => Err(GraphError::NodeIdxDoesntExist(node)) } } fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { if let Some(node_edges) = self.adjacencies.get(node) { if node_edges.contains_key(&other) { - Err(GraphError::EdgeAlreadyExists(node, other)) + Err(GraphError::EdgeBetweenAlreadyExists(node, other)) } else if let Some(other_edges) = self.adjacencies.get(other) { if other_edges.contains_key(&node) { - Err(GraphError::EdgeAlreadyExists(node, other)) + Err(GraphError::EdgeBetweenAlreadyExists(node, other)) } else { unsafe { Ok(self.new_edge_unchecked(node, other, edge)) } } } else { - Err(GraphError::NodeDoesntExist(other)) + Err(GraphError::NodeIdxDoesntExist(other)) } } else { - Err(GraphError::NodeDoesntExist(node)) + Err(GraphError::NodeIdxDoesntExist(node)) } } @@ -150,7 +159,7 @@ impl_graph! { Ok(self.edges.remove(edge).unwrap().data) } else { - Err(GraphError::EdgeDoesntExist(edge)) + Err(GraphError::EdgeIdxDoesntExist(edge)) } } } @@ -169,23 +178,23 @@ impl_graph! { } match self.nodes.remove(node) { Some(n) => Ok(n), - None => Err(GraphError::NodeDoesntExist(node)) + None => Err(GraphError::NodeIdxDoesntExist(node)) } } fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.contains_key(&to) { - Err(GraphError::EdgeAlreadyExists(from, to)) + Err(GraphError::EdgeBetweenAlreadyExists(from, to)) } else if self.has_node(to) { unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } } else { - Err(GraphError::NodeDoesntExist(to)) + Err(GraphError::NodeIdxDoesntExist(to)) } } else { - Err(GraphError::NodeDoesntExist(from)) + Err(GraphError::NodeIdxDoesntExist(from)) } } @@ -205,7 +214,7 @@ impl_graph! { Ok(self.edges.remove(edge).unwrap().data) } else { - Err(GraphError::EdgeDoesntExist(edge)) + Err(GraphError::EdgeIdxDoesntExist(edge)) } } } diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index ad38d4138ed64..fda15c98fc04f 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -7,7 +7,6 @@ pub use list::*; #[cfg(test)] mod test { use hashbrown::HashSet; - use slotmap::Key; use std::hash::Hash; use crate::graphs::Graph; @@ -101,8 +100,8 @@ mod test { assert_eq!(graph.get_edge(mo).unwrap(), &1); assert_eq!( - graph.edge_between(jennifer, jake), - graph.edge_between(jake, jennifer) + graph.edge_between(jennifer, jake).unwrap(), + graph.edge_between(jake, jennifer).unwrap() ); *graph.get_edge_mut(mo).unwrap() = 10; @@ -144,8 +143,8 @@ mod test { assert_eq!(graph.get_edge(jo).unwrap(), &5); assert_eq!(graph.get_edge(mo).unwrap(), &1); - assert!(!graph.edge_between(jennifer, jake).is_null()); - assert!(graph.edge_between(jake, jennifer).is_null()); + assert!(!graph.edge_between(jennifer, jake).is_err()); + assert!(graph.edge_between(jake, jennifer).is_err()); *graph.get_edge_mut(mo).unwrap() = 10; @@ -174,16 +173,38 @@ mod test { assert!(graph.get_node(jake).is_ok()); assert!(graph.get_node(michael).is_ok()); assert_eq!(graph.get_edge(edge).unwrap(), &20); - assert_eq!(graph.edge_between(jake, michael).get(&graph).unwrap(), &20); - assert_eq!(graph.edge_between(michael, jake).get(&graph).unwrap(), &20); + assert_eq!( + graph + .edge_between(jake, michael) + .unwrap() + .get(&graph) + .unwrap(), + &20 + ); + assert_eq!( + graph + .edge_between(michael, jake) + .unwrap() + .get(&graph) + .unwrap(), + &20 + ); assert!(graph.remove_node(michael).is_ok()); assert!(graph.get_node(jake).is_ok()); assert!(graph.get_node(michael).is_err()); assert!(graph.get_edge(edge).is_err()); - assert!(graph.edge_between(jake, michael).get(&graph).is_err()); - assert!(graph.edge_between(michael, jake).get(&graph).is_err()); + assert!(graph + .edge_between(jake, michael) + .unwrap() + .get(&graph) + .is_err()); + assert!(graph + .edge_between(michael, jake) + .unwrap() + .get(&graph) + .is_err()); } pub fn remove_node_directed(mut graph: impl Graph) { @@ -195,16 +216,35 @@ mod test { assert!(graph.get_node(jake).is_ok()); assert!(graph.get_node(michael).is_ok()); assert_eq!(graph.get_edge(edge).unwrap(), &20); - assert_eq!(graph.edge_between(jake, michael).get(&graph).unwrap(), &20); - assert!(graph.edge_between(michael, jake).get(&graph).is_err()); + assert_eq!( + graph + .edge_between(jake, michael) + .unwrap() + .get(&graph) + .unwrap(), + &20 + ); + assert!(graph + .edge_between(michael, jake) + .unwrap() + .get(&graph) + .is_err()); assert!(graph.remove_node(michael).is_ok()); assert!(graph.get_node(jake).is_ok()); assert!(graph.get_node(michael).is_err()); assert!(graph.get_edge(edge).is_err()); - assert!(graph.edge_between(jake, michael).get(&graph).is_err()); - assert!(graph.edge_between(michael, jake).get(&graph).is_err()); + assert!(graph + .edge_between(jake, michael) + .unwrap() + .get(&graph) + .is_err()); + assert!(graph + .edge_between(michael, jake) + .unwrap() + .get(&graph) + .is_err()); } fn unordered_eq(a: &[T], b: &[T]) -> bool From 7753257b8ddecf0c2485b92d404264b1df07a931 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 13 Jan 2023 20:17:50 +0100 Subject: [PATCH 053/183] Fix tests --- crates/bevy_graph/src/graphs/simple/mod.rs | 30 ++++------------------ 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index fda15c98fc04f..6246a48ce01a5 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -195,16 +195,8 @@ mod test { assert!(graph.get_node(jake).is_ok()); assert!(graph.get_node(michael).is_err()); assert!(graph.get_edge(edge).is_err()); - assert!(graph - .edge_between(jake, michael) - .unwrap() - .get(&graph) - .is_err()); - assert!(graph - .edge_between(michael, jake) - .unwrap() - .get(&graph) - .is_err()); + assert!(graph.edge_between(jake, michael).is_err()); + assert!(graph.edge_between(michael, jake).is_err()); } pub fn remove_node_directed(mut graph: impl Graph) { @@ -224,27 +216,15 @@ mod test { .unwrap(), &20 ); - assert!(graph - .edge_between(michael, jake) - .unwrap() - .get(&graph) - .is_err()); + assert!(graph.edge_between(michael, jake).is_err()); assert!(graph.remove_node(michael).is_ok()); assert!(graph.get_node(jake).is_ok()); assert!(graph.get_node(michael).is_err()); assert!(graph.get_edge(edge).is_err()); - assert!(graph - .edge_between(jake, michael) - .unwrap() - .get(&graph) - .is_err()); - assert!(graph - .edge_between(michael, jake) - .unwrap() - .get(&graph) - .is_err()); + assert!(graph.edge_between(jake, michael).is_err()); + assert!(graph.edge_between(michael, jake).is_err()); } fn unordered_eq(a: &[T], b: &[T]) -> bool From d25ec0a2486535adf280b57c45be8c1ef70ffda2 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 13 Jan 2023 20:30:07 +0100 Subject: [PATCH 054/183] Clippy. --- crates/bevy_graph/src/graphs/simple/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index 6246a48ce01a5..ab6969bbad7af 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -143,7 +143,7 @@ mod test { assert_eq!(graph.get_edge(jo).unwrap(), &5); assert_eq!(graph.get_edge(mo).unwrap(), &1); - assert!(!graph.edge_between(jennifer, jake).is_err()); + assert!(graph.edge_between(jennifer, jake).is_ok()); assert!(graph.edge_between(jake, jennifer).is_err()); *graph.get_edge_mut(mo).unwrap() = 10; From 06d5709d5d34d5b61204a7421fd075912b824492 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 14 Jan 2023 14:31:08 +0100 Subject: [PATCH 055/183] Fix benchmarks --- benches/benches/bevy_graph/map.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/benches/benches/bevy_graph/map.rs b/benches/benches/bevy_graph/map.rs index 1e7f03a73a570..d6d69b5a40de2 100644 --- a/benches/benches/bevy_graph/map.rs +++ b/benches/benches/bevy_graph/map.rs @@ -40,6 +40,7 @@ fn nodes_10_000_undirected(c: &mut Criterion) { black_box( graph .edge_between(nodes[i - 1], nodes[i]) + .unwrap() .remove(&mut graph) .unwrap(), ); From 83467a24aea1ebe77d5660b19a4e9b6082982642 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 14 Jan 2023 14:48:11 +0100 Subject: [PATCH 056/183] Add iterative DepthFirstSearch algo --- crates/bevy_graph/src/algos/bfs.rs | 10 ++-- crates/bevy_graph/src/algos/dfs.rs | 80 +++++++++++++++++++++++++++++ crates/bevy_graph/src/algos/mod.rs | 1 + crates/bevy_graph/src/graphs/mod.rs | 6 ++- 4 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 crates/bevy_graph/src/algos/dfs.rs diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 88e31617d0b97..119210bc200cc 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -62,21 +62,21 @@ mod test { let two = map.new_node(2); let three = map.new_node(3); - let sum = 6; // 0 + 1 + 2 + 3 - map.new_edge(zero, one, ()).unwrap(); map.new_edge(zero, two, ()).unwrap(); map.new_edge(one, two, ()).unwrap(); map.new_edge(two, zero, ()).unwrap(); map.new_edge(two, three, ()).unwrap(); - let mut counter = 0; + let elements = vec![0, 2, 1, 3]; + + let mut counted_elements = Vec::with_capacity(4); let mut bfs = map.algo_bfs(zero); while let Some(node) = bfs.next(&map) { - counter += node; + counted_elements.push(*node) } - assert_eq!(sum, counter); + assert_eq!(elements, counted_elements); } } diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs new file mode 100644 index 0000000000000..6c5137c3cc344 --- /dev/null +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -0,0 +1,80 @@ +use hashbrown::HashSet; + +use crate::graphs::{keys::NodeIdx, Graph}; + +pub struct DepthFirstSearch { + stack: Vec, + visited: HashSet, +} + +impl DepthFirstSearch { + pub fn new(start: NodeIdx, count: usize) -> Self { + let mut stack = Vec::new(); + let mut visited = HashSet::with_capacity(count); + + visited.insert(start); + stack.push(start); + + Self { stack, visited } + } + + pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { + if let Some(node) = self.stack.pop() { + for (idx, _) in graph.edges_of(node) { + if !self.visited.contains(&idx) { + self.visited.insert(idx); + self.stack.push(idx); + } + } + Some(graph.get_node(node).unwrap()) + } else { + None + } + } + + pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { + if let Some(node) = self.stack.pop() { + for (idx, _) in graph.edges_of(node) { + if !self.visited.contains(&idx) { + self.visited.insert(idx); + self.stack.push(idx); + } + } + Some(graph.get_node_mut(node).unwrap()) + } else { + None + } + } +} + +#[cfg(test)] +mod test { + use crate::graphs::{simple::SimpleMapGraph, Graph}; + + #[test] + fn dfs() { + let mut map = SimpleMapGraph::::new(); + + let zero = map.new_node(0); + let one = map.new_node(1); + let two = map.new_node(2); + let three = map.new_node(3); + + map.new_edge(zero, one, ()).unwrap(); + map.new_edge(zero, two, ()).unwrap(); + map.new_edge(one, two, ()).unwrap(); + map.new_edge(two, zero, ()).unwrap(); + map.new_edge(two, three, ()).unwrap(); + + let elements = vec![0, 1, 2, 3]; + + let mut counted_elements = Vec::with_capacity(4); + + let mut dfs = map.algo_dfs(zero); + while let Some(node) = dfs.next(&map) { + counted_elements.push(*node) + } + + assert_eq!(elements, counted_elements); + } +} diff --git a/crates/bevy_graph/src/algos/mod.rs b/crates/bevy_graph/src/algos/mod.rs index 02523080fe46f..ae6cb413c3dcc 100644 --- a/crates/bevy_graph/src/algos/mod.rs +++ b/crates/bevy_graph/src/algos/mod.rs @@ -1 +1,2 @@ pub mod bfs; +pub mod dfs; diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 4a1bcd1ef0ae6..0c0d268fcd8e1 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -5,7 +5,7 @@ pub mod edge; pub mod impl_graph; pub mod keys; -use crate::algos::bfs::BreadthFirstSearch; +use crate::algos::{bfs::BreadthFirstSearch, dfs::DepthFirstSearch}; use crate::error::GraphResult; use self::keys::{EdgeIdx, NodeIdx}; @@ -53,4 +53,8 @@ pub trait Graph { fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { BreadthFirstSearch::new(start, self.count()) } + #[inline] + fn algo_dfs(&self, start: NodeIdx) -> DepthFirstSearch { + DepthFirstSearch::new(start, self.count()) + } } From 86cbf7ed7766c3639f119a764020d5957fb5a030 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 14 Jan 2023 15:01:34 +0100 Subject: [PATCH 057/183] Implement unsafe `get_node` for graphs --- crates/bevy_graph/src/graphs/mod.rs | 8 ++++++++ crates/bevy_graph/src/graphs/multi/map.rs | 22 +++++++++++++++++---- crates/bevy_graph/src/graphs/simple/list.rs | 22 +++++++++++++++++---- crates/bevy_graph/src/graphs/simple/map.rs | 22 +++++++++++++++++---- 4 files changed, 62 insertions(+), 12 deletions(-) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 0c0d268fcd8e1..b54ab7c8dbf8c 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -19,7 +19,15 @@ pub trait Graph { fn new_node(&mut self, node: N) -> NodeIdx; fn get_node(&self, idx: NodeIdx) -> GraphResult<&N>; + /// # Safety + /// + /// This function should only be called when the Node for the NodeIdx exists. + unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N; fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; + /// # Safety + /// + /// This function should only be called when the Node for the NodeIdx exists. + unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N; fn remove_node(&mut self, node: NodeIdx) -> GraphResult; diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 3dbf150ffc44c..777ec69848108 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -43,22 +43,36 @@ impl_graph! { #[inline] fn get_node(&self, idx: NodeIdx) -> GraphResult<&N> { - if let Some(node) = self.nodes.get(idx) { - Ok(node) + if self.nodes.contains_key(idx) { + unsafe { + Ok(self.get_node_unchecked(idx)) + } } else { Err(GraphError::NodeIdxDoesntExist(idx)) } } + #[inline] + unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { + self.nodes.get_unchecked(idx) + } + #[inline] fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { - if let Some(node) = self.nodes.get_mut(idx) { - Ok(node) + if self.nodes.contains_key(idx) { + unsafe { + Ok(self.get_node_unchecked_mut(idx)) + } } else { Err(GraphError::NodeIdxDoesntExist(idx)) } } + #[inline] + unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { + self.nodes.get_unchecked_mut(idx) + } + #[inline] fn has_node(&self, node: NodeIdx) -> bool { self.nodes.contains_key(node) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 8a75cdf38a091..e9e8a7ba0cef7 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -42,22 +42,36 @@ impl_graph! { #[inline] fn get_node(&self, idx: NodeIdx) -> GraphResult<&N> { - if let Some(node) = self.nodes.get(idx) { - Ok(node) + if self.nodes.contains_key(idx) { + unsafe { + Ok(self.get_node_unchecked(idx)) + } } else { Err(GraphError::NodeIdxDoesntExist(idx)) } } + #[inline] + unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { + self.nodes.get_unchecked(idx) + } + #[inline] fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { - if let Some(node) = self.nodes.get_mut(idx) { - Ok(node) + if self.nodes.contains_key(idx) { + unsafe { + Ok(self.get_node_unchecked_mut(idx)) + } } else { Err(GraphError::NodeIdxDoesntExist(idx)) } } + #[inline] + unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { + self.nodes.get_unchecked_mut(idx) + } + #[inline] fn has_node(&self, node: NodeIdx) -> bool { self.nodes.contains_key(node) diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index e2c5c5fed45a0..cf827372b2db8 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -43,22 +43,36 @@ impl_graph! { #[inline] fn get_node(&self, idx: NodeIdx) -> GraphResult<&N> { - if let Some(node) = self.nodes.get(idx) { - Ok(node) + if self.nodes.contains_key(idx) { + unsafe { + Ok(self.get_node_unchecked(idx)) + } } else { Err(GraphError::NodeIdxDoesntExist(idx)) } } + #[inline] + unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { + self.nodes.get_unchecked(idx) + } + #[inline] fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { - if let Some(node) = self.nodes.get_mut(idx) { - Ok(node) + if self.nodes.contains_key(idx) { + unsafe { + Ok(self.get_node_unchecked_mut(idx)) + } } else { Err(GraphError::NodeIdxDoesntExist(idx)) } } + #[inline] + unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { + self.nodes.get_unchecked_mut(idx) + } + #[inline] fn has_node(&self, node: NodeIdx) -> bool { self.nodes.contains_key(node) From 78f510ce47fb78a4c24783dfd336cbe39d843ce0 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 14 Jan 2023 15:05:56 +0100 Subject: [PATCH 058/183] Add `next_unchecked` functions for BFS and DFS --- crates/bevy_graph/src/algos/bfs.rs | 42 ++++++++++++++++++++++++++++++ crates/bevy_graph/src/algos/dfs.rs | 42 ++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 119210bc200cc..c5e026d1a5026 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -34,6 +34,27 @@ impl BreadthFirstSearch { } } + /// # Safety + /// + /// This function should only be called when the node from the edge exists. + /// This can happen when a node or edge gets removed but its index is still present in the BFS. + pub unsafe fn next_unchecked<'g, N, E>( + &mut self, + graph: &'g impl Graph, + ) -> Option<&'g N> { + if let Some(node) = self.queue.pop_front() { + for (idx, _) in graph.edges_of(node) { + if !self.visited.contains(&idx) { + self.visited.insert(idx); + self.queue.push_back(idx); + } + } + Some(graph.get_node_unchecked(node)) + } else { + None + } + } + pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.queue.pop_front() { for (idx, _) in graph.edges_of(node) { @@ -47,6 +68,27 @@ impl BreadthFirstSearch { None } } + + /// # Safety + /// + /// This function should only be called when the node from the edge exists. + /// This can happen when a node or edge gets removed but its index is still present in the BFS. + pub unsafe fn next_unchecked_mut<'g, N, E>( + &mut self, + graph: &'g mut impl Graph, + ) -> Option<&'g mut N> { + if let Some(node) = self.queue.pop_front() { + for (idx, _) in graph.edges_of(node) { + if !self.visited.contains(&idx) { + self.visited.insert(idx); + self.queue.push_back(idx); + } + } + Some(graph.get_node_unchecked_mut(node)) + } else { + None + } + } } #[cfg(test)] diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 6c5137c3cc344..a86fac4bd6c6b 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -32,6 +32,27 @@ impl DepthFirstSearch { } } + /// # Safety + /// + /// This function should only be called when the node from the edge exists. + /// This can happen when a node or edge gets removed but its index is still present in the DFS. + pub unsafe fn next_unchecked<'g, N, E>( + &mut self, + graph: &'g impl Graph, + ) -> Option<&'g N> { + if let Some(node) = self.stack.pop() { + for (idx, _) in graph.edges_of(node) { + if !self.visited.contains(&idx) { + self.visited.insert(idx); + self.stack.push(idx); + } + } + Some(graph.get_node_unchecked(node)) + } else { + None + } + } + pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.stack.pop() { for (idx, _) in graph.edges_of(node) { @@ -45,6 +66,27 @@ impl DepthFirstSearch { None } } + + /// # Safety + /// + /// This function should only be called when the node from the edge exists. + /// This can happen when a node or edge gets removed but its index is still present in the DFS. + pub unsafe fn next_unchecked_mut<'g, N, E>( + &mut self, + graph: &'g mut impl Graph, + ) -> Option<&'g mut N> { + if let Some(node) = self.stack.pop() { + for (idx, _) in graph.edges_of(node) { + if !self.visited.contains(&idx) { + self.visited.insert(idx); + self.stack.push(idx); + } + } + Some(graph.get_node_unchecked_mut(node)) + } else { + None + } + } } #[cfg(test)] From d59e6bace7580ed10ee621042d5d9bd0d5f3d092 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 14 Jan 2023 19:24:26 +0100 Subject: [PATCH 059/183] =?UTF-8?q?Clippy=20=F0=9F=93=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/bevy_graph/src/algos/bfs.rs | 2 +- crates/bevy_graph/src/algos/dfs.rs | 2 +- crates/bevy_graph/src/graphs/mod.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index c5e026d1a5026..8000e0c324557 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -116,7 +116,7 @@ mod test { let mut bfs = map.algo_bfs(zero); while let Some(node) = bfs.next(&map) { - counted_elements.push(*node) + counted_elements.push(*node); } assert_eq!(elements, counted_elements); diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index a86fac4bd6c6b..e6e7929a860f0 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -114,7 +114,7 @@ mod test { let mut dfs = map.algo_dfs(zero); while let Some(node) = dfs.next(&map) { - counted_elements.push(*node) + counted_elements.push(*node); } assert_eq!(elements, counted_elements); diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index b54ab7c8dbf8c..7d174d4cc4f56 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -21,12 +21,12 @@ pub trait Graph { fn get_node(&self, idx: NodeIdx) -> GraphResult<&N>; /// # Safety /// - /// This function should only be called when the Node for the NodeIdx exists. + /// This function should only be called when the Node for the `NodeIdx` exists. unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N; fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; /// # Safety /// - /// This function should only be called when the Node for the NodeIdx exists. + /// This function should only be called when the Node for the `NodeIdx` exists. unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N; fn remove_node(&mut self, node: NodeIdx) -> GraphResult; From 9788bae18e02f294d09efac5b442a2df77f583ca Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 14 Jan 2023 19:40:56 +0100 Subject: [PATCH 060/183] Simple Graph `new_edge` should not have same node --- crates/bevy_graph/src/error.rs | 1 + crates/bevy_graph/src/graphs/simple/list.rs | 8 ++++++-- crates/bevy_graph/src/graphs/simple/map.rs | 8 ++++++-- crates/bevy_graph/src/graphs/simple/mod.rs | 19 ++++++++++++++++++- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs index fa8d4688cb4b0..2d7f7c539775c 100644 --- a/crates/bevy_graph/src/error.rs +++ b/crates/bevy_graph/src/error.rs @@ -6,6 +6,7 @@ pub enum GraphError { EdgeIdxDoesntExist(EdgeIdx), EdgeBetweenDoesntExist(NodeIdx, NodeIdx), EdgeBetweenAlreadyExists(NodeIdx, NodeIdx), + EdgeBetweenSameNode(NodeIdx), } pub type GraphResult = Result; diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index e9e8a7ba0cef7..6f03cb8a24c2b 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -137,7 +137,9 @@ impl_graph! { } fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { - if let Some(node_edges) = self.adjacencies.get(node) { + if node == other { + Err(GraphError::EdgeBetweenSameNode(node)) + } else if let Some(node_edges) = self.adjacencies.get(node) { if node_edges.iter().any(|(n, _)| *n == other) { Err(GraphError::EdgeBetweenAlreadyExists(node, other)) } else if let Some(other_edges) = self.adjacencies.get(other) { @@ -208,7 +210,9 @@ impl_graph! { } fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { - if let Some(from_edges) = self.adjacencies.get(from) { + if from == to { + Err(GraphError::EdgeBetweenSameNode(from)) + } else if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.iter().any(|(n, _)| *n == to) { Err(GraphError::EdgeBetweenAlreadyExists(from, to)) } else if self.has_node(to) { diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index cf827372b2db8..2e8e32bfa95b4 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -136,7 +136,9 @@ impl_graph! { } fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { - if let Some(node_edges) = self.adjacencies.get(node) { + if node == other { + Err(GraphError::EdgeBetweenSameNode(node)) + } else if let Some(node_edges) = self.adjacencies.get(node) { if node_edges.contains_key(&other) { Err(GraphError::EdgeBetweenAlreadyExists(node, other)) } else if let Some(other_edges) = self.adjacencies.get(other) { @@ -197,7 +199,9 @@ impl_graph! { } fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { - if let Some(from_edges) = self.adjacencies.get(from) { + if from == to { + Err(GraphError::EdgeBetweenSameNode(from)) + } else if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.contains_key(&to) { Err(GraphError::EdgeBetweenAlreadyExists(from, to)) } else if self.has_node(to) { diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index ab6969bbad7af..a3467bd45789b 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -9,7 +9,7 @@ mod test { use hashbrown::HashSet; use std::hash::Hash; - use crate::graphs::Graph; + use crate::{error::GraphError, graphs::Graph}; #[derive(PartialEq, Debug)] pub enum Person { @@ -43,6 +43,14 @@ mod test { fn remove_node_directed() { test::remove_node_directed(<$($graph)::+ >::new()) } + #[test] + fn edge_between_same_node_undirected() { + test::edge_between_same_node(<$($graph)::+ >::new()) + } + #[test] + fn edge_between_same_node_directed() { + test::edge_between_same_node(<$($graph)::+ >::new()) + } }; } @@ -227,6 +235,15 @@ mod test { assert!(graph.edge_between(michael, jake).is_err()); } + pub fn edge_between_same_node(mut graph: impl Graph) { + let jake = graph.new_node(Person::Jake); + + assert!(matches!( + graph.new_edge(jake, jake, 20), + Err(GraphError::EdgeBetweenSameNode(node)) if node == jake + )); + } + fn unordered_eq(a: &[T], b: &[T]) -> bool where T: Eq + Hash, From 5c0fe702b16044c8b493f6cce7ed03d614d9ab31 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 14 Jan 2023 21:08:53 +0100 Subject: [PATCH 061/183] `edge(s)_between` chaos for multi graph --- crates/bevy_graph/src/error.rs | 1 + crates/bevy_graph/src/graphs/mod.rs | 5 +++-- crates/bevy_graph/src/graphs/multi/map.rs | 10 +++++++-- crates/bevy_graph/src/graphs/simple/list.rs | 25 ++++++++++++++------- crates/bevy_graph/src/graphs/simple/map.rs | 16 +++++++++---- 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs index 2d7f7c539775c..e4819b8f45389 100644 --- a/crates/bevy_graph/src/error.rs +++ b/crates/bevy_graph/src/error.rs @@ -7,6 +7,7 @@ pub enum GraphError { EdgeBetweenDoesntExist(NodeIdx, NodeIdx), EdgeBetweenAlreadyExists(NodeIdx, NodeIdx), EdgeBetweenSameNode(NodeIdx), + CanHaveMultipleEdges, } pub type GraphResult = Result; diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 7d174d4cc4f56..815eadafa21c2 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -47,11 +47,12 @@ pub trait Graph { fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult>; fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult; /// # Safety /// - /// This function should only be called when the nodes and the edge between exists. - unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; + /// This function should only be called when the nodes and the edges between exists. + unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec; fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? //////////////////////////// diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 777ec69848108..f68dbffd927ea 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -95,11 +95,17 @@ impl_graph! { } #[inline] - fn edge_between(&self, _from: NodeIdx, _to: NodeIdx) -> GraphResult { + fn edges_between(&self, _from: NodeIdx, _to: NodeIdx) -> GraphResult> { todo!() } - unsafe fn edge_between_unchecked(&self, _from: NodeIdx, _to: NodeIdx) -> EdgeIdx { + #[inline] + fn edge_between(&self, _from: NodeIdx, _to: NodeIdx) -> GraphResult { + Err(GraphError::CanHaveMultipleEdges) + } + + #[inline] + unsafe fn edges_between_unchecked(&self, _from: NodeIdx, _to: NodeIdx) -> Vec { todo!() } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 6f03cb8a24c2b..e7dc02ca45194 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -1,4 +1,4 @@ -use slotmap::{HopSlotMap, Key, SecondaryMap}; +use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ error::{GraphError, GraphResult}, @@ -94,11 +94,11 @@ impl_graph! { } #[inline] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult { + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { if self.adjacencies.contains_key(from) { unsafe { - let idx = self.edge_between_unchecked(from, to); - if idx.is_null() { + let idx = self.edges_between_unchecked(from, to); + if idx.is_empty() { Err(GraphError::EdgeBetweenDoesntExist(from, to)) } else { Ok(idx) @@ -109,13 +109,22 @@ impl_graph! { } } - unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + #[inline] + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult { + match self.edges_between(from, to) { + Ok(edges) => Ok(edges[0]), + Err(err) => Err(err) + } + } + + #[inline] + unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { if let Some(idx) = self.adjacencies.get_unchecked(from).iter() - .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) + .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) // we know it simple graph can only have 1 edge so `find_map` is enough { - idx + vec![idx] } else { - EdgeIdx::null() + vec![] } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 2e8e32bfa95b4..549db55692586 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -95,11 +95,11 @@ impl_graph! { } #[inline] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult { + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.contains_key(&to) { unsafe { - Ok(self.edge_between_unchecked(from, to)) + Ok(self.edges_between_unchecked(from, to)) } } else { Err(GraphError::EdgeBetweenDoesntExist(from, to)) @@ -109,8 +109,16 @@ impl_graph! { } } - unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - self.adjacencies.get_unchecked(from).get(&to).cloned().unwrap() + #[inline] + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult { + match self.edges_between(from, to) { + Ok(edges) => Ok(edges[0]), + Err(err) => Err(err) + } + } + + unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { + vec![self.adjacencies.get_unchecked(from).get(&to).cloned().unwrap()] } #[inline] From ca9d139cc4aabfd00e91a25f8d4a652283ad6d7e Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 10:41:50 +0100 Subject: [PATCH 062/183] [DIRTY] refactor `impl_graph!` macro and traits --- crates/bevy_graph/src/error.rs | 1 - crates/bevy_graph/src/graphs/impl_graph.rs | 46 +++++++++++++++++---- crates/bevy_graph/src/graphs/mod.rs | 13 +++++- crates/bevy_graph/src/graphs/multi/map.rs | 11 ++--- crates/bevy_graph/src/graphs/simple/list.rs | 14 ++----- crates/bevy_graph/src/graphs/simple/map.rs | 14 ++----- 6 files changed, 58 insertions(+), 41 deletions(-) diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs index e4819b8f45389..2d7f7c539775c 100644 --- a/crates/bevy_graph/src/error.rs +++ b/crates/bevy_graph/src/error.rs @@ -7,7 +7,6 @@ pub enum GraphError { EdgeBetweenDoesntExist(NodeIdx, NodeIdx), EdgeBetweenAlreadyExists(NodeIdx, NodeIdx), EdgeBetweenSameNode(NodeIdx), - CanHaveMultipleEdges, } pub type GraphResult = Result; diff --git a/crates/bevy_graph/src/graphs/impl_graph.rs b/crates/bevy_graph/src/graphs/impl_graph.rs index b625bf1d73051..163e1bdb889c7 100644 --- a/crates/bevy_graph/src/graphs/impl_graph.rs +++ b/crates/bevy_graph/src/graphs/impl_graph.rs @@ -1,26 +1,54 @@ #[macro_export] macro_rules! impl_graph { - (impl common for $name:ident { + (impl COMMON for $name:ident { $($common_code:tt)* } - impl undirected { - $($undirected_code:tt)* - } + $(impl COMMON?undirected { + $($common_undirected_code:tt)* + })? + + $(impl COMMON?directed { + $($common_directed_code:tt)* + })? + + $( + impl SIMPLE { + $($simple_code:tt)* + } + + $(impl SIMPLE?undirected { + $($simple_undirected_code:tt)* + })? - impl directed { - $($directed_code:tt)* - }) => { + $(impl SIMPLE?directed { + $($simple_directed_code:tt)* + })? + )?) => { impl $crate::graphs::Graph for $name { $($common_code)* - $($undirected_code)* + $($($common_undirected_code)*)? } impl $crate::graphs::Graph for $name { $($common_code)* - $($directed_code)* + $($($common_directed_code)*)? } + + $( + impl $crate::graphs::SimpleGraph for $name { + $($simple_code)* + + $($($simple_undirected_code)*)? + } + + impl $crate::graphs::SimpleGraph for $name { + $($simple_code)* + + $($($simple_directed_code)*)? + } + )? } } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 815eadafa21c2..766e3b0d8ce65 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -10,6 +10,10 @@ use crate::error::GraphResult; use self::keys::{EdgeIdx, NodeIdx}; +// NOTE: There should always be a general API function and a more precise API function for one problem with multiple signatures needed. +// Example: `edges_between` is `trait Graph` general and has support for Simple- and Multigraphs. +// `edge_between` is only available for `SimpleGraph` but is also called from `edges_between`. + pub trait Graph { fn count(&self) -> usize; @@ -48,7 +52,6 @@ pub trait Graph { fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult>; - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult; /// # Safety /// /// This function should only be called when the nodes and the edges between exists. @@ -67,3 +70,11 @@ pub trait Graph { DepthFirstSearch::new(start, self.count()) } } + +pub trait SimpleGraph: Graph { + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult; + /// # Safety + /// + /// This function should only be called when the nodes and the edge between exists. + unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; +} diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index f68dbffd927ea..4c16899f45ffe 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -28,7 +28,7 @@ impl MultiMapGraph { } impl_graph! { - impl common for MultiMapGraph { + impl COMMON for MultiMapGraph { #[inline] fn count(&self) -> usize { self.nodes.len() @@ -99,11 +99,6 @@ impl_graph! { todo!() } - #[inline] - fn edge_between(&self, _from: NodeIdx, _to: NodeIdx) -> GraphResult { - Err(GraphError::CanHaveMultipleEdges) - } - #[inline] unsafe fn edges_between_unchecked(&self, _from: NodeIdx, _to: NodeIdx) -> Vec { todo!() @@ -115,7 +110,7 @@ impl_graph! { } } - impl undirected { + impl COMMON?undirected { fn remove_node(&mut self, _node: NodeIdx) -> GraphResult { todo!() } @@ -133,7 +128,7 @@ impl_graph! { } } - impl directed { + impl COMMON?directed { fn remove_node(&mut self, _node: NodeIdx) -> GraphResult { todo!() } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index e7dc02ca45194..c06bed704db44 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -27,7 +27,7 @@ impl SimpleListGraph { } impl_graph! { - impl common for SimpleListGraph { + impl COMMON for SimpleListGraph { #[inline] fn count(&self) -> usize { self.nodes.len() @@ -109,14 +109,6 @@ impl_graph! { } } - #[inline] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult { - match self.edges_between(from, to) { - Ok(edges) => Ok(edges[0]), - Err(err) => Err(err) - } - } - #[inline] unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { if let Some(idx) = self.adjacencies.get_unchecked(from).iter() @@ -134,7 +126,7 @@ impl_graph! { } } - impl undirected { + impl COMMON?undirected { fn remove_node(&mut self, node: NodeIdx) -> GraphResult { for (_, edge) in self.edges_of(node) { self.remove_edge(edge).unwrap(); @@ -200,7 +192,7 @@ impl_graph! { } } - impl directed { + impl COMMON?directed { fn remove_node(&mut self, node: NodeIdx) -> GraphResult { let mut edges = vec![]; for (edge, data) in &self.edges { diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 549db55692586..16bd496014a29 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -28,7 +28,7 @@ impl SimpleMapGraph { } impl_graph! { - impl common for SimpleMapGraph { + impl COMMON for SimpleMapGraph { #[inline] fn count(&self) -> usize { self.nodes.len() @@ -109,14 +109,6 @@ impl_graph! { } } - #[inline] - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult { - match self.edges_between(from, to) { - Ok(edges) => Ok(edges[0]), - Err(err) => Err(err) - } - } - unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { vec![self.adjacencies.get_unchecked(from).get(&to).cloned().unwrap()] } @@ -132,7 +124,7 @@ impl_graph! { } } - impl undirected { + impl COMMON?undirected { fn remove_node(&mut self, node: NodeIdx) -> GraphResult { for (_, edge) in self.edges_of(node) { self.remove_edge(edge).unwrap(); @@ -188,7 +180,7 @@ impl_graph! { } } - impl directed { + impl COMMON?directed { fn remove_node(&mut self, node: NodeIdx) -> GraphResult { let mut edges = vec![]; for (edge, data) in &self.edges { From 2410df439345c9a4fd0858198bcfb038f4ab63fe Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 10:52:55 +0100 Subject: [PATCH 063/183] Use new `impl_graph` for cleaner `edge_between` --- crates/bevy_graph/src/graphs/simple/list.rs | 56 +++++++++++++-------- crates/bevy_graph/src/graphs/simple/map.rs | 41 ++++++++++----- crates/bevy_graph/src/graphs/simple/mod.rs | 16 +++--- 3 files changed, 71 insertions(+), 42 deletions(-) diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index c06bed704db44..a77a18901c9fe 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -1,10 +1,11 @@ -use slotmap::{HopSlotMap, SecondaryMap}; +use slotmap::{HopSlotMap, Key, SecondaryMap}; use crate::{ error::{GraphError, GraphResult}, graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, + SimpleGraph, }, impl_graph, }; @@ -95,29 +96,15 @@ impl_graph! { #[inline] fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { - if self.adjacencies.contains_key(from) { - unsafe { - let idx = self.edges_between_unchecked(from, to); - if idx.is_empty() { - Err(GraphError::EdgeBetweenDoesntExist(from, to)) - } else { - Ok(idx) - } - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) + match self.edge_between(from, to) { + Ok(idx) => Ok(vec![idx]), + Err(e) => Err(e), } } #[inline] unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { - if let Some(idx) = self.adjacencies.get_unchecked(from).iter() - .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) // we know it simple graph can only have 1 edge so `find_map` is enough - { - vec![idx] - } else { - vec![] - } + vec![self.edge_between_unchecked(from, to)] } #[inline] @@ -254,6 +241,33 @@ impl_graph! { } } } + + impl SIMPLE { + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult { + if self.adjacencies.contains_key(from) { + unsafe { + let idx = self.edge_between_unchecked(from, to); + if idx.is_null() { + Err(GraphError::EdgeBetweenDoesntExist(from, to)) + } else { + Ok(idx) + } + } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) + } + } + + unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + if let Some(idx) = self.adjacencies.get_unchecked(from).iter() + .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) // we know it simple graph can only have 1 edge so `find_map` is enough + { + idx + } else { + EdgeIdx::null() + } + } + } } impl Default for SimpleListGraph { @@ -272,7 +286,7 @@ fn find_edge(list: &[(NodeIdx, EdgeIdx)], node: NodeIdx) -> Option { #[cfg(test)] mod test { - use crate::graph_tests; + use crate::simple_graph_tests; - graph_tests!(super::SimpleListGraph); + simple_graph_tests!(super::SimpleListGraph); } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 16bd496014a29..fcf79d4bd680e 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -6,6 +6,7 @@ use crate::{ graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, + SimpleGraph, }, impl_graph, }; @@ -96,21 +97,15 @@ impl_graph! { #[inline] fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { - if let Some(from_edges) = self.adjacencies.get(from) { - if from_edges.contains_key(&to) { - unsafe { - Ok(self.edges_between_unchecked(from, to)) - } - } else { - Err(GraphError::EdgeBetweenDoesntExist(from, to)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) + match self.edge_between(from, to) { + Ok(idx) => Ok(vec![idx]), + Err(e) => Err(e) } } + #[inline] unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { - vec![self.adjacencies.get_unchecked(from).get(&to).cloned().unwrap()] + vec![self.edge_between_unchecked(from, to)] } #[inline] @@ -236,6 +231,26 @@ impl_graph! { } } } + + impl SIMPLE { + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult { + if let Some(from_edges) = self.adjacencies.get(from) { + if from_edges.contains_key(&to) { + unsafe { + Ok(self.edge_between_unchecked(from, to)) + } + } else { + Err(GraphError::EdgeBetweenDoesntExist(from, to)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) + } + } + + unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + self.adjacencies.get_unchecked(from).get(&to).cloned().unwrap() + } + } } impl Default for SimpleMapGraph { @@ -247,7 +262,7 @@ impl Default for SimpleMapGraph { #[cfg(test)] mod test { - use crate::graph_tests; + use crate::simple_graph_tests; - graph_tests!(super::SimpleMapGraph); + simple_graph_tests!(super::SimpleMapGraph); } diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index a3467bd45789b..793c1f6b4783b 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -9,7 +9,7 @@ mod test { use hashbrown::HashSet; use std::hash::Hash; - use crate::{error::GraphError, graphs::Graph}; + use crate::{error::GraphError, graphs::SimpleGraph}; #[derive(PartialEq, Debug)] pub enum Person { @@ -19,7 +19,7 @@ mod test { } #[macro_export] - macro_rules! graph_tests { + macro_rules! simple_graph_tests { ($($graph:ident )::+) => { use $crate::graphs::simple::test::{self, Person}; @@ -54,7 +54,7 @@ mod test { }; } - pub fn nodes(mut graph: impl Graph) { + pub fn nodes(mut graph: impl SimpleGraph) { let jake = graph.new_node(Person::Jake); let michael = graph.new_node(Person::Michael); let jennifer = graph.new_node(Person::Jennifer); @@ -86,7 +86,7 @@ mod test { assert!(graph.get_node(other_jake).is_err()); } - pub fn undirected_edges(mut graph: impl Graph) { + pub fn undirected_edges(mut graph: impl SimpleGraph) { let jake = graph.new_node(Person::Jake); let michael = graph.new_node(Person::Michael); let jennifer = graph.new_node(Person::Jennifer); @@ -130,7 +130,7 @@ mod test { assert!(graph.get_edge(mo).is_err()); } - pub fn directed_edges(mut graph: impl Graph) { + pub fn directed_edges(mut graph: impl SimpleGraph) { let jake = graph.new_node(Person::Jake); let michael = graph.new_node(Person::Michael); let jennifer = graph.new_node(Person::Jennifer); @@ -172,7 +172,7 @@ mod test { assert!(graph.get_edge(mo).is_err()); } - pub fn remove_node_undirected(mut graph: impl Graph) { + pub fn remove_node_undirected(mut graph: impl SimpleGraph) { let jake = graph.new_node(Person::Jake); let michael = graph.new_node(Person::Michael); @@ -207,7 +207,7 @@ mod test { assert!(graph.edge_between(michael, jake).is_err()); } - pub fn remove_node_directed(mut graph: impl Graph) { + pub fn remove_node_directed(mut graph: impl SimpleGraph) { let jake = graph.new_node(Person::Jake); let michael = graph.new_node(Person::Michael); @@ -235,7 +235,7 @@ mod test { assert!(graph.edge_between(michael, jake).is_err()); } - pub fn edge_between_same_node(mut graph: impl Graph) { + pub fn edge_between_same_node(mut graph: impl SimpleGraph) { let jake = graph.new_node(Person::Jake); assert!(matches!( From 7908c1fca17d3469014137e06a25c196103ad69a Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 10:59:27 +0100 Subject: [PATCH 064/183] benchi benchi --- benches/benches/bevy_graph/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/benches/bevy_graph/map.rs b/benches/benches/bevy_graph/map.rs index d6d69b5a40de2..332940446991e 100644 --- a/benches/benches/bevy_graph/map.rs +++ b/benches/benches/bevy_graph/map.rs @@ -1,7 +1,7 @@ use bevy_graph::graphs::{ keys::{EdgeIdx, NodeIdx}, simple::SimpleMapGraph, - Graph, + Graph, SimpleGraph, }; use bevy_utils::Duration; use criterion::{black_box, criterion_group, criterion_main, Criterion}; From d011cd9b48dfb71f6e315b4d8e4632dd48397b7f Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 13:35:14 +0100 Subject: [PATCH 065/183] Add benchmarks for `bfs` and `dfs` algo --- benches/Cargo.toml | 5 +++ benches/benches/bevy_graph/bfs_and_dfs.rs | 54 +++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 benches/benches/bevy_graph/bfs_and_dfs.rs diff --git a/benches/Cargo.toml b/benches/Cargo.toml index 93d1ff4468327..3aa830d33bc40 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -32,6 +32,11 @@ name = "ecs" path = "benches/bevy_ecs/benches.rs" harness = false +[[bench]] +name = "bfs_and_dfs_graph" +path = "benches/bevy_graph/bfs_and_dfs.rs" +harness = false + [[bench]] name = "map_graph" path = "benches/bevy_graph/map.rs" diff --git a/benches/benches/bevy_graph/bfs_and_dfs.rs b/benches/benches/bevy_graph/bfs_and_dfs.rs new file mode 100644 index 0000000000000..4a3c4633037c0 --- /dev/null +++ b/benches/benches/bevy_graph/bfs_and_dfs.rs @@ -0,0 +1,54 @@ +use bevy_graph::graphs::{keys::NodeIdx, simple::SimpleMapGraph, Graph}; +use bevy_utils::Duration; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use rand::seq::SliceRandom; + +criterion_main!(benches); + +const WARM_UP_TIME: Duration = Duration::from_millis(500); + +criterion_group! { + name = benches; + config = Criterion::default().warm_up_time(WARM_UP_TIME); + targets = algo_10_000 +} + +// TODO: find a better way for fix with multiple iterations over same graph +fn algo_10_000(c: &mut Criterion) { + let mut graph = SimpleMapGraph::::new(); + let mut nodes = Vec::with_capacity(10_000); + let first = graph.new_node(0); + for i in 1..10_000 { + nodes.push(graph.new_node(i)); + } + let mut shuffled = nodes.clone(); + shuffled.shuffle(&mut rand::thread_rng()); + for (i, node) in shuffled + .iter() + .cloned() + .collect::>() + .windows(2) + .enumerate() + { + let _ = graph.new_edge(node[0], node[1], ()).unwrap(); + let _ = black_box(graph.new_edge(node[0], nodes[i], ())); + } + + c.bench_function("bfs_10_000", |b| { + b.iter(|| { + let mut bfs = graph.algo_bfs(first); + while let Some(node) = bfs.next(&graph) { + let _ = black_box(node); + } + }) + }); + + c.bench_function("dfs_10_000", |b| { + b.iter(|| { + let mut dfs = graph.algo_dfs(first); + while let Some(node) = dfs.next(&graph) { + let _ = black_box(node); + } + }) + }); +} From f94dd2255b412d52316a1db97dc7b61d9e9e2fe3 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 15:07:14 +0100 Subject: [PATCH 066/183] Move `new` into Graph trait --- crates/bevy_graph/src/graphs/impl_graph.rs | 14 ++++++++++++ crates/bevy_graph/src/graphs/mod.rs | 4 ++++ crates/bevy_graph/src/graphs/multi/map.rs | 25 +++++++-------------- crates/bevy_graph/src/graphs/simple/list.rs | 25 +++++++-------------- crates/bevy_graph/src/graphs/simple/map.rs | 25 ++++++++------------- crates/bevy_graph/src/graphs/simple/mod.rs | 2 +- 6 files changed, 44 insertions(+), 51 deletions(-) diff --git a/crates/bevy_graph/src/graphs/impl_graph.rs b/crates/bevy_graph/src/graphs/impl_graph.rs index 163e1bdb889c7..0662b1a86eedb 100644 --- a/crates/bevy_graph/src/graphs/impl_graph.rs +++ b/crates/bevy_graph/src/graphs/impl_graph.rs @@ -50,5 +50,19 @@ macro_rules! impl_graph { $($($simple_directed_code)*)? } )? + + impl Default for $name { + #[inline] + fn default() -> Self { + $crate::graphs::Graph::new() + } + } + + impl Default for $name { + #[inline] + fn default() -> Self { + $crate::graphs::Graph::new() + } + } } } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 766e3b0d8ce65..888f7f544f7ce 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -15,6 +15,10 @@ use self::keys::{EdgeIdx, NodeIdx}; // `edge_between` is only available for `SimpleGraph` but is also called from `edges_between`. pub trait Graph { + fn new() -> Self + where + Self: Sized; + fn count(&self) -> usize; //////////////////////////// diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 4c16899f45ffe..e0e53903d120c 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -17,18 +17,16 @@ pub struct MultiMapGraph { adjacencies: SecondaryMap>>, } -impl MultiMapGraph { - pub fn new() -> Self { - Self { - nodes: HopSlotMap::with_key(), - edges: HopSlotMap::with_key(), - adjacencies: SecondaryMap::new(), - } - } -} - impl_graph! { impl COMMON for MultiMapGraph { + fn new() -> Self { + Self { + nodes: HopSlotMap::with_key(), + edges: HopSlotMap::with_key(), + adjacencies: SecondaryMap::new(), + } + } + #[inline] fn count(&self) -> usize { self.nodes.len() @@ -146,10 +144,3 @@ impl_graph! { } } } - -impl Default for MultiMapGraph { - #[inline] - fn default() -> Self { - Self::new() - } -} diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index a77a18901c9fe..c7924e4efc47f 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -17,18 +17,16 @@ pub struct SimpleListGraph { adjacencies: SecondaryMap>, } -impl SimpleListGraph { - fn new() -> Self { - Self { - nodes: HopSlotMap::with_key(), - edges: HopSlotMap::with_key(), - adjacencies: SecondaryMap::new(), - } - } -} - impl_graph! { impl COMMON for SimpleListGraph { + fn new() -> Self { + Self { + nodes: HopSlotMap::with_key(), + edges: HopSlotMap::with_key(), + adjacencies: SecondaryMap::new(), + } + } + #[inline] fn count(&self) -> usize { self.nodes.len() @@ -270,13 +268,6 @@ impl_graph! { } } -impl Default for SimpleListGraph { - #[inline] - fn default() -> Self { - Self::new() - } -} - // Util function #[inline] fn find_edge(list: &[(NodeIdx, EdgeIdx)], node: NodeIdx) -> Option { diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index fcf79d4bd680e..797e1677f4b25 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -18,18 +18,18 @@ pub struct SimpleMapGraph { adjacencies: SecondaryMap>, } -impl SimpleMapGraph { - pub fn new() -> Self { - Self { - nodes: HopSlotMap::with_key(), - edges: HopSlotMap::with_key(), - adjacencies: SecondaryMap::new(), - } - } -} +impl SimpleMapGraph {} impl_graph! { impl COMMON for SimpleMapGraph { + fn new() -> Self { + Self { + nodes: HopSlotMap::with_key(), + edges: HopSlotMap::with_key(), + adjacencies: SecondaryMap::new(), + } + } + #[inline] fn count(&self) -> usize { self.nodes.len() @@ -253,13 +253,6 @@ impl_graph! { } } -impl Default for SimpleMapGraph { - #[inline] - fn default() -> Self { - Self::new() - } -} - #[cfg(test)] mod test { use crate::simple_graph_tests; diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index 793c1f6b4783b..f70126747e127 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -21,7 +21,7 @@ mod test { #[macro_export] macro_rules! simple_graph_tests { ($($graph:ident )::+) => { - use $crate::graphs::simple::test::{self, Person}; + use $crate::graphs::{Graph, simple::test::{self, Person}}; #[test] fn nodes() { From 5518c6bf79b7c4197eac47f5e5599b6a93f086c3 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 15:37:48 +0100 Subject: [PATCH 067/183] Impl `new_edge` for `MultiMapGraph` --- crates/bevy_graph/src/graphs/multi/map.rs | 49 +++++++++++++++++++---- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index e0e53903d120c..aa24b95914aab 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -113,12 +113,29 @@ impl_graph! { todo!() } - fn new_edge(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> GraphResult { - todo!() + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { + if self.has_node(node) { + if self.has_node(other) { + unsafe { + Ok(self.new_edge_unchecked(node, other, edge)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(other)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(node)) + } } - unsafe fn new_edge_unchecked(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> EdgeIdx { - todo!() + unsafe fn new_edge_unchecked(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: node, + dst: other, + data: edge, + }); + self.adjacencies.get_unchecked_mut(node).entry(other).or_default().push(idx); + self.adjacencies.get_unchecked_mut(other).entry(node).or_default().push(idx); + idx } fn remove_edge(&mut self, _edge: EdgeIdx) -> GraphResult { @@ -131,12 +148,28 @@ impl_graph! { todo!() } - fn new_edge(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> GraphResult { - todo!() + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { + if self.has_node(from) { + if self.has_node(to) { + unsafe { + Ok(self.new_edge_unchecked(from, to, edge)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(to)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) + } } - unsafe fn new_edge_unchecked(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> EdgeIdx { - todo!() + unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); + self.adjacencies.get_unchecked_mut(from).entry(to).or_default().push(idx); + idx } fn remove_edge(&mut self, _edge: EdgeIdx) -> GraphResult { From 088cfe167635bddcd8801a60501c07fb308d33db Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 16:07:58 +0100 Subject: [PATCH 068/183] add `remove_edge` for `MultiMapGraph` --- crates/bevy_graph/src/graphs/multi/map.rs | 30 ++++++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index aa24b95914aab..3231dcdd6fca3 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -138,8 +138,21 @@ impl_graph! { idx } - fn remove_edge(&mut self, _edge: EdgeIdx) -> GraphResult { - todo!() + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { + let adjas = self.adjacencies.get_mut(node).unwrap().get_mut(&other).unwrap(); + if let Some(pos) = adjas.iter().position(|e| *e == edge) { + adjas.swap_remove(pos); + } + let adjas = self.adjacencies.get_mut(other).unwrap().get_mut(&node).unwrap(); + if let Some(pos) = adjas.iter().position(|e| *e == edge) { + adjas.swap_remove(pos); + } + + Ok(self.edges.remove(edge).unwrap().data) + } else { + Err(GraphError::EdgeIdxDoesntExist(edge)) + } } } @@ -172,8 +185,17 @@ impl_graph! { idx } - fn remove_edge(&mut self, _edge: EdgeIdx) -> GraphResult { - todo!() + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { + let adjas = self.adjacencies.get_mut(node).unwrap().get_mut(&other).unwrap(); + if let Some(pos) = adjas.iter().position(|e| *e == edge) { + adjas.swap_remove(pos); + } + + Ok(self.edges.remove(edge).unwrap().data) + } else { + Err(GraphError::EdgeIdxDoesntExist(edge)) + } } } } From 159e70fa56ec7d7a52122b2a96ff9aafb010bc52 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 16:20:23 +0100 Subject: [PATCH 069/183] Add unsafe `remove_edge_unchecked` --- crates/bevy_graph/src/graphs/mod.rs | 4 ++ crates/bevy_graph/src/graphs/multi/map.rs | 38 +++++++++-------- crates/bevy_graph/src/graphs/simple/list.rs | 45 ++++++++++----------- crates/bevy_graph/src/graphs/simple/map.rs | 30 +++++++++----- 4 files changed, 69 insertions(+), 48 deletions(-) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 888f7f544f7ce..61544a909daa4 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -54,6 +54,10 @@ pub trait Graph { fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E>; fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; + /// # Safety + /// + /// This function should only be called when the edge exists. + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E; fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult>; /// # Safety diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 3231dcdd6fca3..1cb752be88212 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -139,21 +139,23 @@ impl_graph! { } fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { - let adjas = self.adjacencies.get_mut(node).unwrap().get_mut(&other).unwrap(); - if let Some(pos) = adjas.iter().position(|e| *e == edge) { - adjas.swap_remove(pos); - } - let adjas = self.adjacencies.get_mut(other).unwrap().get_mut(&node).unwrap(); - if let Some(pos) = adjas.iter().position(|e| *e == edge) { - adjas.swap_remove(pos); + if self.edges.contains_key(edge) { + unsafe { + Ok(self.remove_edge_unchecked(edge)) } - - Ok(self.edges.remove(edge).unwrap().data) } else { Err(GraphError::EdgeIdxDoesntExist(edge)) } } + + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + let (node, other) = self.edges.get_unchecked(edge).indices(); + let adjas = self.adjacencies.get_unchecked_mut(node).get_mut(&other).unwrap(); + adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? + let adjas = self.adjacencies.get_unchecked_mut(other).get_mut(&node).unwrap(); + adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? + self.edges.remove(edge).unwrap().data + } } impl COMMON?directed { @@ -186,16 +188,20 @@ impl_graph! { } fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { - let adjas = self.adjacencies.get_mut(node).unwrap().get_mut(&other).unwrap(); - if let Some(pos) = adjas.iter().position(|e| *e == edge) { - adjas.swap_remove(pos); + if self.edges.contains_key(edge) { + unsafe { + Ok(self.remove_edge_unchecked(edge)) } - - Ok(self.edges.remove(edge).unwrap().data) } else { Err(GraphError::EdgeIdxDoesntExist(edge)) } } + + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + let (from, to) = self.edges.get_unchecked(edge).indices(); + let adjas = self.adjacencies.get_unchecked_mut(from).get_mut(&to).unwrap(); + adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? + self.edges.remove(edge).unwrap().data + } } } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index c7924e4efc47f..6d0003a7ee1ac 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -156,25 +156,23 @@ impl_graph! { } fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { - let list = self.adjacencies.get_mut(node).unwrap(); - - if let Some(index) = find_edge(list, other) { - list.swap_remove(index); // TODO: remove or swap_remove ? - - let list = self.adjacencies.get_mut(other).unwrap(); - if let Some(index) = find_edge(list, node) { - list.swap_remove(index); // TODO: remove or swap_remove ? - } - - Ok(self.edges.remove(edge).unwrap().data) - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) + if self.edges.contains_key(edge) { + unsafe { + Ok(self.remove_edge_unchecked(edge)) } } else { Err(GraphError::EdgeIdxDoesntExist(edge)) } } + + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + let (node, other) = self.edges.get_unchecked(edge).indices(); + let list = self.adjacencies.get_unchecked_mut(node); + list.swap_remove(find_edge(list, other).unwrap()); // TODO: remove or swap_remove ? + let list = self.adjacencies.get_unchecked_mut(other); + list.swap_remove(find_edge(list, node).unwrap()); // TODO: remove or swap_remove ? + self.edges.remove(edge).unwrap().data + } } impl COMMON?directed { @@ -224,20 +222,21 @@ impl_graph! { } fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if let Some((from, to)) = self.edges.get(edge).map(|e| e.indices()) { - let list = self.adjacencies.get_mut(from).unwrap(); - - if let Some(index) = find_edge(list, to) { - list.swap_remove(index); // TODO: remove or swap_remove ? - - Ok(self.edges.remove(edge).unwrap().data) - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) + if self.edges.contains_key(edge) { + unsafe { + Ok(self.remove_edge_unchecked(edge)) } } else { Err(GraphError::EdgeIdxDoesntExist(edge)) } } + + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + let (from, to) = self.edges.get_unchecked(edge).indices(); + let list = self.adjacencies.get_unchecked_mut(from); + list.swap_remove(find_edge(list, to).unwrap()); // TODO: remove or swap_remove ? + self.edges.remove(edge).unwrap().data + } } impl SIMPLE { diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 797e1677f4b25..6cb52e7b2a8af 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -164,15 +164,21 @@ impl_graph! { } fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if let Some((node, other)) = self.edges.get(edge).map(|e| e.indices()) { - self.adjacencies.get_mut(node).unwrap().remove(&other); - self.adjacencies.get_mut(other).unwrap().remove(&node); - - Ok(self.edges.remove(edge).unwrap().data) + if self.edges.contains_key(edge) { + unsafe { + Ok(self.remove_edge_unchecked(edge)) + } } else { Err(GraphError::EdgeIdxDoesntExist(edge)) } } + + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + let (node, other) = self.edges.get_unchecked(edge).indices(); + self.adjacencies.get_unchecked_mut(node).remove(&other); + self.adjacencies.get_unchecked_mut(other).remove(&node); + self.edges.remove(edge).unwrap().data + } } impl COMMON?directed { @@ -222,14 +228,20 @@ impl_graph! { } fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if let Some((from, to)) = self.edges.get(edge).map(|e| e.indices()) { - self.adjacencies.get_mut(from).unwrap().remove(&to); - - Ok(self.edges.remove(edge).unwrap().data) + if self.edges.contains_key(edge) { + unsafe { + Ok(self.remove_edge_unchecked(edge)) + } } else { Err(GraphError::EdgeIdxDoesntExist(edge)) } } + + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + let (from, to) = self.edges.get_unchecked(edge).indices(); + self.adjacencies.get_unchecked_mut(from).remove(&to); + self.edges.remove(edge).unwrap().data + } } impl SIMPLE { From bb1333c7de09bcc3ac9f5b82082cad9f2dec553c Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 16:21:58 +0100 Subject: [PATCH 070/183] =?UTF-8?q?Cleanup=20duplicates=20ah=20i=20love=20?= =?UTF-8?q?my=20macro=20=F0=9F=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/bevy_graph/src/graphs/multi/map.rs | 30 +++++++-------------- crates/bevy_graph/src/graphs/simple/list.rs | 30 +++++++-------------- crates/bevy_graph/src/graphs/simple/map.rs | 30 +++++++-------------- 3 files changed, 30 insertions(+), 60 deletions(-) diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 1cb752be88212..9b568674472c9 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -92,6 +92,16 @@ impl_graph! { } } + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if self.edges.contains_key(edge) { + unsafe { + Ok(self.remove_edge_unchecked(edge)) + } + } else { + Err(GraphError::EdgeIdxDoesntExist(edge)) + } + } + #[inline] fn edges_between(&self, _from: NodeIdx, _to: NodeIdx) -> GraphResult> { todo!() @@ -138,16 +148,6 @@ impl_graph! { idx } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if self.edges.contains_key(edge) { - unsafe { - Ok(self.remove_edge_unchecked(edge)) - } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } - } - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { let (node, other) = self.edges.get_unchecked(edge).indices(); let adjas = self.adjacencies.get_unchecked_mut(node).get_mut(&other).unwrap(); @@ -187,16 +187,6 @@ impl_graph! { idx } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if self.edges.contains_key(edge) { - unsafe { - Ok(self.remove_edge_unchecked(edge)) - } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } - } - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { let (from, to) = self.edges.get_unchecked(edge).indices(); let adjas = self.adjacencies.get_unchecked_mut(from).get_mut(&to).unwrap(); diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 6d0003a7ee1ac..1e24325210d98 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -92,6 +92,16 @@ impl_graph! { } } + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if self.edges.contains_key(edge) { + unsafe { + Ok(self.remove_edge_unchecked(edge)) + } + } else { + Err(GraphError::EdgeIdxDoesntExist(edge)) + } + } + #[inline] fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { match self.edge_between(from, to) { @@ -155,16 +165,6 @@ impl_graph! { idx } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if self.edges.contains_key(edge) { - unsafe { - Ok(self.remove_edge_unchecked(edge)) - } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } - } - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { let (node, other) = self.edges.get_unchecked(edge).indices(); let list = self.adjacencies.get_unchecked_mut(node); @@ -221,16 +221,6 @@ impl_graph! { idx } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if self.edges.contains_key(edge) { - unsafe { - Ok(self.remove_edge_unchecked(edge)) - } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } - } - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { let (from, to) = self.edges.get_unchecked(edge).indices(); let list = self.adjacencies.get_unchecked_mut(from); diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 6cb52e7b2a8af..ff628d5889a57 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -95,6 +95,16 @@ impl_graph! { } } + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if self.edges.contains_key(edge) { + unsafe { + Ok(self.remove_edge_unchecked(edge)) + } + } else { + Err(GraphError::EdgeIdxDoesntExist(edge)) + } + } + #[inline] fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { match self.edge_between(from, to) { @@ -163,16 +173,6 @@ impl_graph! { idx } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if self.edges.contains_key(edge) { - unsafe { - Ok(self.remove_edge_unchecked(edge)) - } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } - } - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { let (node, other) = self.edges.get_unchecked(edge).indices(); self.adjacencies.get_unchecked_mut(node).remove(&other); @@ -227,16 +227,6 @@ impl_graph! { idx } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { - if self.edges.contains_key(edge) { - unsafe { - Ok(self.remove_edge_unchecked(edge)) - } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } - } - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { let (from, to) = self.edges.get_unchecked(edge).indices(); self.adjacencies.get_unchecked_mut(from).remove(&to); From dcc8df767bd93cb6b27a96e284142709fa78940f Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 16:40:18 +0100 Subject: [PATCH 071/183] Add `remove_node` for `MultiMapGraph` --- crates/bevy_graph/src/graphs/multi/map.rs | 33 ++++++++++++++++++--- crates/bevy_graph/src/graphs/simple/list.rs | 10 +++++-- crates/bevy_graph/src/graphs/simple/map.rs | 10 +++++-- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 9b568674472c9..55006e8b2e042 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -119,8 +119,17 @@ impl_graph! { } impl COMMON?undirected { - fn remove_node(&mut self, _node: NodeIdx) -> GraphResult { - todo!() + fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + for (_, edge) in self.edges_of(node) { + unsafe { + // SAFETY: we know it must exist + self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? + } + } + match self.nodes.remove(node) { + Some(n) => Ok(n), + None => Err(GraphError::NodeIdxDoesntExist(node)) + } } fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { @@ -159,8 +168,24 @@ impl_graph! { } impl COMMON?directed { - fn remove_node(&mut self, _node: NodeIdx) -> GraphResult { - todo!() + fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + let mut edges = vec![]; + for (edge, data) in &self.edges { + let (src, dst) = data.indices(); + if dst == node || src == node { + edges.push(edge); + } + } + for edge in edges { + unsafe { + // SAFETY: we know it must exist + self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? + } + } + match self.nodes.remove(node) { + Some(n) => Ok(n), + None => Err(GraphError::NodeIdxDoesntExist(node)) + } } fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 1e24325210d98..6efa3264031fa 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -124,7 +124,10 @@ impl_graph! { impl COMMON?undirected { fn remove_node(&mut self, node: NodeIdx) -> GraphResult { for (_, edge) in self.edges_of(node) { - self.remove_edge(edge).unwrap(); + unsafe { + // SAFETY: we know it must exist + self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? + } } match self.nodes.remove(node) { Some(n) => Ok(n), @@ -185,7 +188,10 @@ impl_graph! { } } for edge in edges { - self.remove_edge(edge).unwrap(); + unsafe { + // SAFETY: we know it must exist + self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? + } } match self.nodes.remove(node) { Some(n) => Ok(n), diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index ff628d5889a57..2f5d1d7e4a628 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -132,7 +132,10 @@ impl_graph! { impl COMMON?undirected { fn remove_node(&mut self, node: NodeIdx) -> GraphResult { for (_, edge) in self.edges_of(node) { - self.remove_edge(edge).unwrap(); + unsafe { + // SAFETY: we know it must exist + self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? + } } match self.nodes.remove(node) { Some(n) => Ok(n), @@ -191,7 +194,10 @@ impl_graph! { } } for edge in edges { - self.remove_edge(edge).unwrap(); + unsafe { + // SAFETY: we know it must exist + self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? + } } match self.nodes.remove(node) { Some(n) => Ok(n), From a007ee5015f51fcb008828c7cc520bb58fefd950 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 16:48:27 +0100 Subject: [PATCH 072/183] Add `edges_of` for `MultiMapGraph` --- crates/bevy_graph/src/graphs/multi/map.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 55006e8b2e042..ba834b13a1508 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -113,8 +113,19 @@ impl_graph! { } #[inline] - fn edges_of(&self, _node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - todo!() + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + if let Some(map) = self.adjacencies.get(node) { + // TODO: can this be done with iterators? + let mut result = Vec::new(); + for (target, edges) in map { + for edge in edges { + result.push((*target, *edge)); + } + } + result + } else { + Vec::new() + } } } From 2dac00bd5f316be629c740307ff2e45478773af9 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 16:53:13 +0100 Subject: [PATCH 073/183] Make `SimpleGraph`'s `edge_between` an Option --- crates/bevy_graph/src/graphs/mod.rs | 2 +- crates/bevy_graph/src/graphs/simple/list.rs | 9 +++++---- crates/bevy_graph/src/graphs/simple/map.rs | 9 +++++---- crates/bevy_graph/src/graphs/simple/mod.rs | 17 ++++++++++------- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 61544a909daa4..a2df9027acf76 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -80,7 +80,7 @@ pub trait Graph { } pub trait SimpleGraph: Graph { - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult; + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult>; /// # Safety /// /// This function should only be called when the nodes and the edge between exists. diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 6efa3264031fa..dee3760c7e6ea 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -105,7 +105,8 @@ impl_graph! { #[inline] fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { match self.edge_between(from, to) { - Ok(idx) => Ok(vec![idx]), + Ok(Some(idx)) => Ok(vec![idx]), + Ok(None) => Ok(vec![]), Err(e) => Err(e), } } @@ -236,14 +237,14 @@ impl_graph! { } impl SIMPLE { - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult { + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { if self.adjacencies.contains_key(from) { unsafe { let idx = self.edge_between_unchecked(from, to); if idx.is_null() { - Err(GraphError::EdgeBetweenDoesntExist(from, to)) + Ok(None) } else { - Ok(idx) + Ok(Some(idx)) } } } else { diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 2f5d1d7e4a628..1588c1df48f6c 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -108,7 +108,8 @@ impl_graph! { #[inline] fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { match self.edge_between(from, to) { - Ok(idx) => Ok(vec![idx]), + Ok(Some(idx)) => Ok(vec![idx]), + Ok(None) => Ok(vec![]), Err(e) => Err(e) } } @@ -241,14 +242,14 @@ impl_graph! { } impl SIMPLE { - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult { + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.contains_key(&to) { unsafe { - Ok(self.edge_between_unchecked(from, to)) + Ok(Some(self.edge_between_unchecked(from, to))) } } else { - Err(GraphError::EdgeBetweenDoesntExist(from, to)) + Ok(None) } } else { Err(GraphError::NodeIdxDoesntExist(from)) diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index f70126747e127..bdc2c356055a4 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -151,8 +151,8 @@ mod test { assert_eq!(graph.get_edge(jo).unwrap(), &5); assert_eq!(graph.get_edge(mo).unwrap(), &1); - assert!(graph.edge_between(jennifer, jake).is_ok()); - assert!(graph.edge_between(jake, jennifer).is_err()); + assert!(graph.edge_between(jennifer, jake).unwrap().is_some()); + assert!(graph.edge_between(jake, jennifer).unwrap().is_none()); *graph.get_edge_mut(mo).unwrap() = 10; @@ -185,6 +185,7 @@ mod test { graph .edge_between(jake, michael) .unwrap() + .unwrap() .get(&graph) .unwrap(), &20 @@ -193,6 +194,7 @@ mod test { graph .edge_between(michael, jake) .unwrap() + .unwrap() .get(&graph) .unwrap(), &20 @@ -203,8 +205,8 @@ mod test { assert!(graph.get_node(jake).is_ok()); assert!(graph.get_node(michael).is_err()); assert!(graph.get_edge(edge).is_err()); - assert!(graph.edge_between(jake, michael).is_err()); - assert!(graph.edge_between(michael, jake).is_err()); + assert!(graph.edge_between(jake, michael).unwrap().is_none()); + assert!(graph.edge_between(michael, jake).unwrap().is_none()); } pub fn remove_node_directed(mut graph: impl SimpleGraph) { @@ -220,19 +222,20 @@ mod test { graph .edge_between(jake, michael) .unwrap() + .unwrap() .get(&graph) .unwrap(), &20 ); - assert!(graph.edge_between(michael, jake).is_err()); + assert!(graph.edge_between(michael, jake).unwrap().is_none()); assert!(graph.remove_node(michael).is_ok()); assert!(graph.get_node(jake).is_ok()); assert!(graph.get_node(michael).is_err()); assert!(graph.get_edge(edge).is_err()); - assert!(graph.edge_between(jake, michael).is_err()); - assert!(graph.edge_between(michael, jake).is_err()); + assert!(graph.edge_between(jake, michael).unwrap().is_none()); + assert!(graph.edge_between(michael, jake).unwrap().is_none()); } pub fn edge_between_same_node(mut graph: impl SimpleGraph) { From 7ab4f666b6778c5f55dcd4bd9f260ec89e82cef3 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 16:58:35 +0100 Subject: [PATCH 074/183] Implement last methods for `MultiMapGraph` :D --- crates/bevy_graph/src/graphs/multi/map.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index ba834b13a1508..a376b0347ea74 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -103,13 +103,23 @@ impl_graph! { } #[inline] - fn edges_between(&self, _from: NodeIdx, _to: NodeIdx) -> GraphResult> { - todo!() + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { + if let Some(from_edges) = self.adjacencies.get(from) { + if from_edges.contains_key(&to) { + unsafe { + Ok(self.edges_between_unchecked(from, to)) + } + } else { + Ok(vec![]) + } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) + } } #[inline] - unsafe fn edges_between_unchecked(&self, _from: NodeIdx, _to: NodeIdx) -> Vec { - todo!() + unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { + self.adjacencies.get_unchecked(from).get(&to).cloned().unwrap() } #[inline] From b8dea3a89e576038c2e28c3469b6ecd5eff89681 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 17:10:16 +0100 Subject: [PATCH 075/183] Add tests for MultiGraphs --- crates/bevy_graph/src/graphs/multi/map.rs | 7 + crates/bevy_graph/src/graphs/multi/mod.rs | 265 ++++++++++++++++++++++ 2 files changed, 272 insertions(+) diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index a376b0347ea74..bf38911b5a2a1 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -241,3 +241,10 @@ impl_graph! { } } } + +#[cfg(test)] +mod test { + use crate::multi_graph_tests; + + multi_graph_tests!(super::MultiMapGraph); +} diff --git a/crates/bevy_graph/src/graphs/multi/mod.rs b/crates/bevy_graph/src/graphs/multi/mod.rs index aa2efd93933f6..204f060775236 100644 --- a/crates/bevy_graph/src/graphs/multi/mod.rs +++ b/crates/bevy_graph/src/graphs/multi/mod.rs @@ -1,2 +1,267 @@ mod map; pub use map::*; + +#[cfg(test)] +mod test { + use hashbrown::HashSet; + use std::hash::Hash; + + use crate::graphs::Graph; + + #[derive(PartialEq, Debug)] + pub enum Person { + Jake, + Michael, + Jennifer, + } + + #[macro_export] + macro_rules! multi_graph_tests { + ($($graph:ident )::+) => { + use $crate::graphs::{Graph, multi::test::{self, Person}}; + + #[test] + fn nodes() { + test::nodes(<$($graph)::+ >::new()) + } + #[test] + fn undirected_edges() { + test::undirected_edges(<$($graph)::+ >::new()) + } + #[test] + fn directed_edges() { + test::directed_edges(<$($graph)::+ >::new()) + } + #[test] + fn remove_node_undirected() { + test::remove_node_undirected(<$($graph)::+ >::new()) + } + #[test] + fn remove_node_directed() { + test::remove_node_directed(<$($graph)::+ >::new()) + } + #[test] + fn edge_between_same_node_undirected() { + test::edge_between_same_node(<$($graph)::+ >::new()) + } + #[test] + fn edge_between_same_node_directed() { + test::edge_between_same_node(<$($graph)::+ >::new()) + } + }; + } + + pub fn nodes(mut graph: impl Graph) { + let jake = graph.new_node(Person::Jake); + let michael = graph.new_node(Person::Michael); + let jennifer = graph.new_node(Person::Jennifer); + let other_jake = graph.new_node(Person::Jake); + + assert_eq!(graph.get_node(jake).unwrap(), &Person::Jake); + assert_eq!(graph.get_node(michael).unwrap(), &Person::Michael); + assert_eq!(graph.get_node(jennifer).unwrap(), &Person::Jennifer); + assert_eq!(graph.get_node(other_jake).unwrap(), &Person::Jake); + + graph + .get_node_mut(jake) + .map(|node| *node = Person::Michael) + .unwrap(); + + assert_eq!(graph.get_node(jake).unwrap(), &Person::Michael); + assert_eq!(graph.get_node(michael).unwrap(), &Person::Michael); + assert_eq!(graph.get_node(jennifer).unwrap(), &Person::Jennifer); + assert_eq!(graph.get_node(other_jake).unwrap(), &Person::Jake); + + assert!(graph.remove_node(jake).is_ok()); + assert!(graph.remove_node(michael).is_ok()); + assert!(graph.remove_node(jennifer).is_ok()); + assert!(graph.remove_node(other_jake).is_ok()); + + assert!(graph.get_node(jake).is_err()); + assert!(graph.get_node(michael).is_err()); + assert!(graph.get_node(jennifer).is_err()); + assert!(graph.get_node(other_jake).is_err()); + } + + pub fn undirected_edges(mut graph: impl Graph) { + let jake = graph.new_node(Person::Jake); + let michael = graph.new_node(Person::Michael); + let jennifer = graph.new_node(Person::Jennifer); + let other_jake = graph.new_node(Person::Jake); + + let jm = graph.new_edge(jake, michael, 2).unwrap(); + let jm2 = graph.new_edge(jake, michael, 20).unwrap(); + let jj = graph.new_edge(jennifer, jake, 7).unwrap(); + let jo = graph.new_edge(jake, other_jake, 5).unwrap(); + let mo = graph.new_edge(michael, other_jake, 1).unwrap(); + let j_itself = graph.new_edge(jennifer, jennifer, 8).unwrap(); + + assert!(unordered_eq( + &graph.edges_of(jake), + &[ + (michael, jm), + (michael, jm2), + (jennifer, jj), + (other_jake, jo) + ] + )); + + assert_eq!(graph.get_edge(jm).unwrap(), &2); + assert_eq!(graph.get_edge(jj).unwrap(), &7); + assert_eq!(graph.get_edge(jo).unwrap(), &5); + assert_eq!(graph.get_edge(mo).unwrap(), &1); + + assert_eq!( + graph.edges_between(jennifer, jake).unwrap(), + graph.edges_between(jake, jennifer).unwrap() + ); + + assert!(graph.edges_of(jennifer).contains(&(jennifer, j_itself))); + + assert!(unordered_eq( + &graph.edges_between(jake, michael).unwrap(), + &[jm, jm2] + )); + + *graph.get_edge_mut(mo).unwrap() = 10; + + assert_eq!(graph.get_edge(jm).unwrap(), &2); + assert_eq!(graph.get_edge(jj).unwrap(), &7); + assert_eq!(graph.get_edge(jo).unwrap(), &5); + assert_eq!(graph.get_edge(mo).unwrap(), &10); + + assert!(graph.remove_edge(jm).is_ok()); + assert!(graph.remove_edge(jj).is_ok()); + assert!(graph.remove_edge(jo).is_ok()); + assert!(graph.remove_edge(mo).is_ok()); + + assert!(graph.get_edge(jm).is_err()); + assert!(graph.get_edge(jj).is_err()); + assert!(graph.get_edge(jo).is_err()); + assert!(graph.get_edge(mo).is_err()); + } + + pub fn directed_edges(mut graph: impl Graph) { + let jake = graph.new_node(Person::Jake); + let michael = graph.new_node(Person::Michael); + let jennifer = graph.new_node(Person::Jennifer); + let other_jake = graph.new_node(Person::Jake); + + let jm = graph.new_edge(jake, michael, 2).unwrap(); + let jm2 = graph.new_edge(jake, michael, 20).unwrap(); + let jj = graph.new_edge(jennifer, jake, 7).unwrap(); + let jo = graph.new_edge(jake, other_jake, 5).unwrap(); + let mo = graph.new_edge(michael, other_jake, 1).unwrap(); + let j_itself = graph.new_edge(jennifer, jennifer, 8).unwrap(); + + assert!(unordered_eq( + &graph.edges_of(jake), + &[(michael, jm), (michael, jm2), (other_jake, jo)] + )); + + assert_eq!(graph.get_edge(jm).unwrap(), &2); + assert_eq!(graph.get_edge(jj).unwrap(), &7); + assert_eq!(graph.get_edge(jo).unwrap(), &5); + assert_eq!(graph.get_edge(mo).unwrap(), &1); + + assert!(!graph.edges_between(jennifer, jake).unwrap().is_empty()); + assert!(graph.edges_between(jake, jennifer).unwrap().is_empty()); + + assert!(graph.edges_of(jennifer).contains(&(jennifer, j_itself))); + + assert!(unordered_eq( + &graph.edges_between(jake, michael).unwrap(), + &[jm, jm2] + )); + + *graph.get_edge_mut(mo).unwrap() = 10; + + assert_eq!(graph.get_edge(jm).unwrap(), &2); + assert_eq!(graph.get_edge(jj).unwrap(), &7); + assert_eq!(graph.get_edge(jo).unwrap(), &5); + assert_eq!(graph.get_edge(mo).unwrap(), &10); + + assert!(graph.remove_edge(jm).is_ok()); + assert!(graph.remove_edge(jj).is_ok()); + assert!(graph.remove_edge(jo).is_ok()); + assert!(graph.remove_edge(mo).is_ok()); + + assert!(graph.get_edge(jm).is_err()); + assert!(graph.get_edge(jj).is_err()); + assert!(graph.get_edge(jo).is_err()); + assert!(graph.get_edge(mo).is_err()); + } + + pub fn remove_node_undirected(mut graph: impl Graph) { + let jake = graph.new_node(Person::Jake); + let michael = graph.new_node(Person::Michael); + + let edge = graph.new_edge(jake, michael, 20).unwrap(); + + assert!(graph.get_node(jake).is_ok()); + assert!(graph.get_node(michael).is_ok()); + assert_eq!(graph.get_edge(edge).unwrap(), &20); + assert_eq!( + graph.edges_between(jake, michael).unwrap()[0] + .get(&graph) + .unwrap(), + &20 + ); + assert_eq!( + graph.edges_between(michael, jake).unwrap()[0] + .get(&graph) + .unwrap(), + &20 + ); + + assert!(graph.remove_node(michael).is_ok()); + + assert!(graph.get_node(jake).is_ok()); + assert!(graph.get_node(michael).is_err()); + assert!(graph.get_edge(edge).is_err()); + assert!(graph.edges_between(jake, michael).unwrap().is_empty()); + assert!(graph.edges_between(michael, jake).unwrap().is_empty()); + } + + pub fn remove_node_directed(mut graph: impl Graph) { + let jake = graph.new_node(Person::Jake); + let michael = graph.new_node(Person::Michael); + + let edge = graph.new_edge(jake, michael, 20).unwrap(); + + assert!(graph.get_node(jake).is_ok()); + assert!(graph.get_node(michael).is_ok()); + assert_eq!(graph.get_edge(edge).unwrap(), &20); + assert_eq!( + graph.edges_between(jake, michael).unwrap()[0] + .get(&graph) + .unwrap(), + &20 + ); + assert!(graph.edges_between(michael, jake).unwrap().is_empty()); + + assert!(graph.remove_node(michael).is_ok()); + + assert!(graph.get_node(jake).is_ok()); + assert!(graph.get_node(michael).is_err()); + assert!(graph.get_edge(edge).is_err()); + assert!(graph.edges_between(jake, michael).unwrap().is_empty()); + assert!(graph.edges_between(michael, jake).unwrap().is_empty()); + } + + pub fn edge_between_same_node(mut graph: impl Graph) { + let jake = graph.new_node(Person::Jake); + + assert!(graph.new_edge(jake, jake, 20).is_ok()); + } + + fn unordered_eq(a: &[T], b: &[T]) -> bool + where + T: Eq + Hash, + { + let a: HashSet<_> = a.iter().collect(); + let b: HashSet<_> = b.iter().collect(); + + a == b + } +} From c957fc59d40c2bfb24a683670a532fe66cbfb730 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 17:11:17 +0100 Subject: [PATCH 076/183] Fix benches --- benches/benches/bevy_graph/map.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/benches/benches/bevy_graph/map.rs b/benches/benches/bevy_graph/map.rs index 332940446991e..ee5f09172c4a9 100644 --- a/benches/benches/bevy_graph/map.rs +++ b/benches/benches/bevy_graph/map.rs @@ -41,6 +41,7 @@ fn nodes_10_000_undirected(c: &mut Criterion) { graph .edge_between(nodes[i - 1], nodes[i]) .unwrap() + .unwrap() .remove(&mut graph) .unwrap(), ); From dc008276dc470f417459c84f454969ce6d33093b Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 17:19:27 +0100 Subject: [PATCH 077/183] Add skeleton for `MultiListGraph` --- crates/bevy_graph/src/graphs/multi/list.rs | 152 +++++++++++++++++++++ crates/bevy_graph/src/graphs/multi/mod.rs | 3 + 2 files changed, 155 insertions(+) create mode 100644 crates/bevy_graph/src/graphs/multi/list.rs diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs new file mode 100644 index 0000000000000..22217b851f514 --- /dev/null +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -0,0 +1,152 @@ +use slotmap::{HopSlotMap, SecondaryMap}; + +use crate::{ + error::{GraphError, GraphResult}, + graphs::{ + edge::Edge, + keys::{EdgeIdx, NodeIdx}, + }, + impl_graph, +}; + +#[derive(Clone)] +pub struct MultiListGraph { + nodes: HopSlotMap, + edges: HopSlotMap>, + adjacencies: SecondaryMap)>>, +} + +impl_graph! { + impl COMMON for MultiListGraph { + fn new() -> Self { + Self { + nodes: HopSlotMap::with_key(), + edges: HopSlotMap::with_key(), + adjacencies: SecondaryMap::new(), + } + } + + #[inline] + fn count(&self) -> usize { + self.nodes.len() + } + + #[inline] + fn new_node(&mut self, node: N) -> NodeIdx { + let idx = self.nodes.insert(node); + self.adjacencies.insert(idx, Vec::new()); + idx + } + + #[inline] + fn get_node(&self, idx: NodeIdx) -> GraphResult<&N> { + if self.nodes.contains_key(idx) { + unsafe { + Ok(self.get_node_unchecked(idx)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(idx)) + } + } + + #[inline] + unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { + self.nodes.get_unchecked(idx) + } + + #[inline] + fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + if self.nodes.contains_key(idx) { + unsafe { + Ok(self.get_node_unchecked_mut(idx)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(idx)) + } + } + + #[inline] + unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { + self.nodes.get_unchecked_mut(idx) + } + + #[inline] + fn has_node(&self, node: NodeIdx) -> bool { + self.nodes.contains_key(node) + } + + #[inline] + fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E> { + match self.edges.get(edge) { + Some(e) => Ok(&e.data), + None => Err(GraphError::EdgeIdxDoesntExist(edge)) + } + } + + #[inline] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E> { + match self.edges.get_mut(edge) { + Some(e) => Ok(&mut e.data), + None => Err(GraphError::EdgeIdxDoesntExist(edge)) + } + } + + fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + if self.edges.contains_key(edge) { + unsafe { + Ok(self.remove_edge_unchecked(edge)) + } + } else { + Err(GraphError::EdgeIdxDoesntExist(edge)) + } + } + + fn edges_between(&self, _from: NodeIdx, _to: NodeIdx) -> GraphResult> { + todo!() + } + + unsafe fn edges_between_unchecked(&self, _from: NodeIdx, _to: NodeIdx) -> Vec { + todo!() + } + + fn edges_of(&self, _node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + todo!() + } + } + + impl COMMON?undirected { + fn remove_node(&mut self, _node: NodeIdx) -> GraphResult { + todo!() + } + + fn new_edge(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> GraphResult { + todo!() + } + + unsafe fn new_edge_unchecked(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> EdgeIdx { + todo!() + } + + unsafe fn remove_edge_unchecked(&mut self, _edge: EdgeIdx) -> E { + todo!() + } + } + + impl COMMON?directed { + fn remove_node(&mut self, _node: NodeIdx) -> GraphResult { + todo!() + } + + fn new_edge(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> GraphResult { + todo!() + } + + unsafe fn new_edge_unchecked(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> EdgeIdx { + todo!() + } + + unsafe fn remove_edge_unchecked(&mut self, _edge: EdgeIdx) -> E { + todo!() + } + } +} diff --git a/crates/bevy_graph/src/graphs/multi/mod.rs b/crates/bevy_graph/src/graphs/multi/mod.rs index 204f060775236..9ea849f7016d1 100644 --- a/crates/bevy_graph/src/graphs/multi/mod.rs +++ b/crates/bevy_graph/src/graphs/multi/mod.rs @@ -1,6 +1,9 @@ mod map; pub use map::*; +mod list; +pub use list::*; + #[cfg(test)] mod test { use hashbrown::HashSet; From 09eee1e5611e1027140b2747a3fcdeb845ff8143 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 15 Jan 2023 18:21:06 +0100 Subject: [PATCH 078/183] Finish `MultiListGraph` and fix misconception in tests lol --- crates/bevy_graph/src/graphs/multi/list.rs | 190 +++++++++++++++++--- crates/bevy_graph/src/graphs/multi/map.rs | 16 +- crates/bevy_graph/src/graphs/multi/mod.rs | 4 +- crates/bevy_graph/src/graphs/simple/list.rs | 16 +- crates/bevy_graph/src/graphs/simple/map.rs | 16 +- crates/bevy_graph/src/graphs/simple/mod.rs | 4 +- 6 files changed, 214 insertions(+), 32 deletions(-) diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 22217b851f514..a21a5aff2944b 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -101,52 +101,198 @@ impl_graph! { } } - fn edges_between(&self, _from: NodeIdx, _to: NodeIdx) -> GraphResult> { - todo!() + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { + if self.has_node(from) { + unsafe { + Ok(self.edges_between_unchecked(from, to)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) + } } - unsafe fn edges_between_unchecked(&self, _from: NodeIdx, _to: NodeIdx) -> Vec { - todo!() + unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { + find_edge_list(self.adjacencies.get_unchecked(from), to).cloned().unwrap_or_default() } - fn edges_of(&self, _node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - todo!() + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + if let Some(list) = self.adjacencies.get(node) { + // TODO: can this be done with iterators? + let mut result = Vec::new(); + for (target, edges) in list { + for edge in edges { + result.push((*target, *edge)); + } + } + result + } else { + Vec::new() + } } } impl COMMON?undirected { - fn remove_node(&mut self, _node: NodeIdx) -> GraphResult { - todo!() + fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + for (_, edge) in self.edges_of(node) { + unsafe { + // SAFETY: we know it must exist + self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? + } + } + match self.nodes.remove(node) { + Some(n) => { + unsafe { + // SAFETY: it will exist. + self.adjacencies.remove(node).unwrap_unchecked(); + } + Ok(n) + }, + None => Err(GraphError::NodeIdxDoesntExist(node)) + } } - fn new_edge(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> GraphResult { - todo!() + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { + if self.has_node(node) { + if self.has_node(other) { + unsafe { + Ok(self.new_edge_unchecked(node, other, edge)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(other)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(node)) + } } - unsafe fn new_edge_unchecked(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> EdgeIdx { - todo!() + unsafe fn new_edge_unchecked(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: node, + dst: other, + data: edge, + }); + let adjs = self.adjacencies.get_unchecked_mut(node); + if let Some(list) = find_edge_list_mut(adjs, other) { + list.push(idx); + } else { + adjs.push((other, vec![idx])); + } + let adjs = self.adjacencies.get_unchecked_mut(other); + if let Some(list) = find_edge_list_mut(adjs, node) { + list.push(idx); + } else { + adjs.push((node, vec![idx])); + } + idx } - unsafe fn remove_edge_unchecked(&mut self, _edge: EdgeIdx) -> E { - todo!() + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + let (from, to) = self.edges.get_unchecked(edge).indices(); + + let list = self.adjacencies.get_unchecked_mut(from); + let list = find_edge_list_mut(list, to).unwrap(); + list.swap_remove(find_edge(&list, edge).unwrap()); // TODO: remove or swap_remove ? + + let list = self.adjacencies.get_unchecked_mut(to); + let list = find_edge_list_mut(list, from).unwrap(); + list.swap_remove(find_edge(&list, edge).unwrap()); // TODO: remove or swap_remove ? + + self.edges.remove(edge).unwrap().data } } impl COMMON?directed { - fn remove_node(&mut self, _node: NodeIdx) -> GraphResult { - todo!() + fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + let mut edges = vec![]; + for (edge, data) in &self.edges { + let (src, dst) = data.indices(); + if dst == node || src == node { + edges.push(edge); + } + } + for edge in edges { + unsafe { + // SAFETY: we know it must exist + self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? + } + } + match self.nodes.remove(node) { + Some(n) => { + unsafe { + // SAFETY: it will exist. + self.adjacencies.remove(node).unwrap_unchecked(); + } + Ok(n) + }, + None => Err(GraphError::NodeIdxDoesntExist(node)) + } } - fn new_edge(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> GraphResult { - todo!() + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { + if self.has_node(from) { + if self.has_node(to) { + unsafe { + Ok(self.new_edge_unchecked(from, to, edge)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(to)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) + } } - unsafe fn new_edge_unchecked(&mut self, _from: NodeIdx, _to: NodeIdx, _edge: E) -> EdgeIdx { - todo!() + unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); + let adjs = self.adjacencies.get_unchecked_mut(from); + if let Some(list) = find_edge_list_mut(adjs, to) { + list.push(idx); + } else { + adjs.push((to, vec![idx])); + } + idx } - unsafe fn remove_edge_unchecked(&mut self, _edge: EdgeIdx) -> E { - todo!() + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + let (from, to) = self.edges.get_unchecked(edge).indices(); + let list = self.adjacencies.get_unchecked_mut(from); + let list = find_edge_list_mut(list, to).unwrap(); + list.swap_remove(find_edge(&list, edge).unwrap()); // TODO: remove or swap_remove ? + self.edges.remove(edge).unwrap().data } } } + +// Util function +#[inline] +fn find_edge_list(list: &[(NodeIdx, Vec)], node: NodeIdx) -> Option<&Vec> { + match list.iter().find(|l| l.0 == node) { + Some((_, l)) => Some(l), + None => None, + } +} +#[inline] +fn find_edge_list_mut( + list: &mut [(NodeIdx, Vec)], + node: NodeIdx, +) -> Option<&mut Vec> { + match list.iter_mut().find(|l| l.0 == node) { + Some((_, l)) => Some(l), + None => None, + } +} +#[inline] +fn find_edge(list: &[EdgeIdx], edge: EdgeIdx) -> Option { + list.iter().position(|edge_idx| *edge_idx == edge) +} + +#[cfg(test)] +mod test { + use crate::multi_graph_tests; + + multi_graph_tests!(super::MultiListGraph); +} diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index bf38911b5a2a1..4ab237bceebba 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -148,7 +148,13 @@ impl_graph! { } } match self.nodes.remove(node) { - Some(n) => Ok(n), + Some(n) => { + unsafe { + // SAFETY: it will exist. + self.adjacencies.remove(node).unwrap_unchecked(); + } + Ok(n) + }, None => Err(GraphError::NodeIdxDoesntExist(node)) } } @@ -204,7 +210,13 @@ impl_graph! { } } match self.nodes.remove(node) { - Some(n) => Ok(n), + Some(n) => { + unsafe { + // SAFETY: it will exist. + self.adjacencies.remove(node).unwrap_unchecked(); + } + Ok(n) + }, None => Err(GraphError::NodeIdxDoesntExist(node)) } } diff --git a/crates/bevy_graph/src/graphs/multi/mod.rs b/crates/bevy_graph/src/graphs/multi/mod.rs index 9ea849f7016d1..1b193c2a6afb8 100644 --- a/crates/bevy_graph/src/graphs/multi/mod.rs +++ b/crates/bevy_graph/src/graphs/multi/mod.rs @@ -223,7 +223,7 @@ mod test { assert!(graph.get_node(michael).is_err()); assert!(graph.get_edge(edge).is_err()); assert!(graph.edges_between(jake, michael).unwrap().is_empty()); - assert!(graph.edges_between(michael, jake).unwrap().is_empty()); + assert!(graph.edges_between(michael, jake).is_err()); } pub fn remove_node_directed(mut graph: impl Graph) { @@ -249,7 +249,7 @@ mod test { assert!(graph.get_node(michael).is_err()); assert!(graph.get_edge(edge).is_err()); assert!(graph.edges_between(jake, michael).unwrap().is_empty()); - assert!(graph.edges_between(michael, jake).unwrap().is_empty()); + assert!(graph.edges_between(michael, jake).is_err()); } pub fn edge_between_same_node(mut graph: impl Graph) { diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index dee3760c7e6ea..29e1186d94006 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -131,7 +131,13 @@ impl_graph! { } } match self.nodes.remove(node) { - Some(n) => Ok(n), + Some(n) => { + unsafe { + // SAFETY: it will exist. + self.adjacencies.remove(node).unwrap_unchecked(); + } + Ok(n) + }, None => Err(GraphError::NodeIdxDoesntExist(node)) } } @@ -195,7 +201,13 @@ impl_graph! { } } match self.nodes.remove(node) { - Some(n) => Ok(n), + Some(n) => { + unsafe { + // SAFETY: it will exist. + self.adjacencies.remove(node).unwrap_unchecked(); + } + Ok(n) + }, None => Err(GraphError::NodeIdxDoesntExist(node)) } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 1588c1df48f6c..b164f2bbebc63 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -139,7 +139,13 @@ impl_graph! { } } match self.nodes.remove(node) { - Some(n) => Ok(n), + Some(n) => { + unsafe { + // SAFETY: it will exist. + self.adjacencies.remove(node).unwrap_unchecked(); + } + Ok(n) + }, None => Err(GraphError::NodeIdxDoesntExist(node)) } } @@ -201,7 +207,13 @@ impl_graph! { } } match self.nodes.remove(node) { - Some(n) => Ok(n), + Some(n) => { + unsafe { + // SAFETY: it will exist. + self.adjacencies.remove(node).unwrap_unchecked(); + } + Ok(n) + }, None => Err(GraphError::NodeIdxDoesntExist(node)) } } diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index bdc2c356055a4..eff59cf494f64 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -206,7 +206,7 @@ mod test { assert!(graph.get_node(michael).is_err()); assert!(graph.get_edge(edge).is_err()); assert!(graph.edge_between(jake, michael).unwrap().is_none()); - assert!(graph.edge_between(michael, jake).unwrap().is_none()); + assert!(graph.edge_between(michael, jake).is_err()); } pub fn remove_node_directed(mut graph: impl SimpleGraph) { @@ -235,7 +235,7 @@ mod test { assert!(graph.get_node(michael).is_err()); assert!(graph.get_edge(edge).is_err()); assert!(graph.edge_between(jake, michael).unwrap().is_none()); - assert!(graph.edge_between(michael, jake).unwrap().is_none()); + assert!(graph.edge_between(michael, jake).is_err()); } pub fn edge_between_same_node(mut graph: impl SimpleGraph) { From dcfcfeb50e0153b9a0a0ba23095e01b0986957bf Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Sun, 15 Jan 2023 19:34:27 +0100 Subject: [PATCH 079/183] Ci is happy = I am happy --- crates/bevy_graph/src/graphs/multi/list.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index a21a5aff2944b..8550b09064fe5 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -191,11 +191,11 @@ impl_graph! { let list = self.adjacencies.get_unchecked_mut(from); let list = find_edge_list_mut(list, to).unwrap(); - list.swap_remove(find_edge(&list, edge).unwrap()); // TODO: remove or swap_remove ? + list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? let list = self.adjacencies.get_unchecked_mut(to); let list = find_edge_list_mut(list, from).unwrap(); - list.swap_remove(find_edge(&list, edge).unwrap()); // TODO: remove or swap_remove ? + list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? self.edges.remove(edge).unwrap().data } @@ -261,7 +261,7 @@ impl_graph! { let (from, to) = self.edges.get_unchecked(edge).indices(); let list = self.adjacencies.get_unchecked_mut(from); let list = find_edge_list_mut(list, to).unwrap(); - list.swap_remove(find_edge(&list, edge).unwrap()); // TODO: remove or swap_remove ? + list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? self.edges.remove(edge).unwrap().data } } From 8d750dbee95b08ef4209f3ebfef3821cf222b2f5 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 14:28:15 +0100 Subject: [PATCH 080/183] Documenting Graph and SimpleGraph traits --- crates/bevy_graph/src/graphs/mod.rs | 96 +++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 4 deletions(-) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index a2df9027acf76..f2bac38262312 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -15,6 +15,7 @@ use self::keys::{EdgeIdx, NodeIdx}; // `edge_between` is only available for `SimpleGraph` but is also called from `edges_between`. pub trait Graph { + /// Creates a new graph fn new() -> Self where Self: Sized; @@ -24,55 +25,138 @@ pub trait Graph { //////////////////////////// // Nodes //////////////////////////// + + /// Creates a new node with the given value in the graph and returns its `NodeIdx` fn new_node(&mut self, node: N) -> NodeIdx; + /// Returns a reference to the value of a given node fn get_node(&self, idx: NodeIdx) -> GraphResult<&N>; + + /// Returns a reference to the value of a given node + /// /// # Safety /// - /// This function should only be called when the Node for the `NodeIdx` exists. + /// This function should only be called when the Node for the `NodeIdx` exists unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N; + + /// Returns a mutable reference to the value of a given node fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; + + /// Returns a mutable reference to the value of a given node + /// /// # Safety /// - /// This function should only be called when the Node for the `NodeIdx` exists. + /// This function should only be called when the Node for the `NodeIdx` exists unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N; + /// Removes a node from the graph by its `NodeIdx` fn remove_node(&mut self, node: NodeIdx) -> GraphResult; + /// Returns true as long as the node from the given `NodeIdx` is preset fn has_node(&self, node: NodeIdx) -> bool; //////////////////////////// // Edges //////////////////////////// + + /// Creates a new edge between the two nodes and with the given value in the graph and returns its `EdgeIdx` fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult; + + /// Creates a new edge between the two nodes and with the given value in the graph and returns its `EdgeIdx` + /// /// # Safety /// /// This function should only be called when the nodes exist and there is no equal edge. unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; + /// Returns a reference to the value of a given edge + /// + /// ## Inline helper + /// + /// This function can also be directly called by the `EdgeIdx`: + /// ``` + /// # use bevy_graph::graphs::{Graph, simple::SimpleMapGraph}; + /// # let graph = SimpleMapGraph::new(); + /// let from = graph.new_node(); + /// let to = graph.new_node(); + /// let edge = graph.new_edge(from, to, 12).unwrap(); + /// assert_eq!(edge.get(&graph), &12); + /// ``` fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E>; + + /// Returns a mutable reference to the value of a given edge + /// + /// ## Inline helper + /// + /// This function can also be directly called by the `EdgeIdx`: + /// ``` + /// # use bevy_graph::graphs::{Graph, simple::SimpleMapGraph}; + /// # let graph = SimpleMapGraph::new(); + /// let from = graph.new_node(); + /// let to = graph.new_node(); + /// let edge = graph.new_edge(from, to, 12).unwrap(); + /// assert_eq!(edge.get_mut(&graph), &12); + /// ``` fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E>; + /// Remove an edge by its `EdgeIdx` and returns the edge data + /// + /// ## Inline helper + /// + /// This function can also be directly called by the `EdgeIdx`: + /// ``` + /// # use bevy_graph::graphs::{Graph, simple::SimpleMapGraph}; + /// # let graph = SimpleMapGraph::new(); + /// let from = graph.new_node(); + /// let to = graph.new_node(); + /// let edge = graph.new_edge(from, to, 12).unwrap(); + /// assert_eq!(edge.remove(&graph).unwrap(), 12); + /// ``` fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; + + /// Remove an edge by its `EdgeIdx` and returns the edge data + /// + /// ## Inline helper + /// + /// This function can also be directly called by the `EdgeIdx`: + /// ``` + /// # use bevy_graph::graphs::{Graph, simple::SimpleMapGraph}; + /// # let graph = SimpleMapGraph::new(); + /// let from = graph.new_node(); + /// let to = graph.new_node(); + /// let edge = graph.new_edge(from, to, 12).unwrap(); + /// assert_eq!(edge.remove(&graph).unwrap(), 12); + /// ``` + /// /// # Safety /// - /// This function should only be called when the edge exists. + /// This function should only be called when the edge exists unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E; + /// Returns a `Vec` of all edges between two nodes as `EdgeIdx` fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult>; + + /// Returns a `Vec` of all edges between two nodes as `EdgeIdx` + /// /// # Safety /// - /// This function should only be called when the nodes and the edges between exists. + /// This function should only be called when the nodes and the edges between exists unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec; + + /// Returns a `Vec` of all edges the node is outgoing from. fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? //////////////////////////// // Algos //////////////////////////// + + /// Makes a `BreadthFirstSearch` over this graph #[inline] fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { BreadthFirstSearch::new(start, self.count()) } + + /// Makes a `DepthFirstSearch` over this graph #[inline] fn algo_dfs(&self, start: NodeIdx) -> DepthFirstSearch { DepthFirstSearch::new(start, self.count()) @@ -80,7 +164,11 @@ pub trait Graph { } pub trait SimpleGraph: Graph { + /// Returns an edge between two nodes as `EdgeIdx` fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult>; + + /// Returns an edge between two nodes as `EdgeIdx` + /// /// # Safety /// /// This function should only be called when the nodes and the edge between exists. From 1523a3822b7bd7b3870c62e98414405b0bdd734c Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 14:36:44 +0100 Subject: [PATCH 081/183] More documentation --- crates/bevy_graph/src/algos/bfs.rs | 11 +++++++++++ crates/bevy_graph/src/algos/dfs.rs | 10 ++++++++++ crates/bevy_graph/src/graphs/multi/list.rs | 3 +++ crates/bevy_graph/src/graphs/multi/map.rs | 3 +++ crates/bevy_graph/src/graphs/simple/list.rs | 3 +++ crates/bevy_graph/src/graphs/simple/map.rs | 5 +++-- 6 files changed, 33 insertions(+), 2 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 8000e0c324557..81a31efd2d39a 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -4,12 +4,17 @@ use hashbrown::HashSet; use crate::graphs::{keys::NodeIdx, Graph}; +/// Implementation of the `BFS` algorythm +/// +/// when `d` is the distance between a node and the startnode, +/// it will evaluate every node with `d=1`, then continue with `d=2` and so on. pub struct BreadthFirstSearch { queue: VecDeque, visited: HashSet, } impl BreadthFirstSearch { + /// Creates a new `DepthFirstSearch` with a start node and the count of nodes pub fn new(start: NodeIdx, count: usize) -> Self { let mut queue = VecDeque::new(); let mut visited = HashSet::with_capacity(count); @@ -20,6 +25,7 @@ impl BreadthFirstSearch { Self { queue, visited } } + /// Gets a reference to the value of the next node from the algorythm pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { if let Some(node) = self.queue.pop_front() { for (idx, _) in graph.edges_of(node) { @@ -34,6 +40,8 @@ impl BreadthFirstSearch { } } + /// Gets a reference to the value of the next node from the algorythm + /// /// # Safety /// /// This function should only be called when the node from the edge exists. @@ -55,6 +63,7 @@ impl BreadthFirstSearch { } } + /// Gets a mutable reference to the value of the next node from the algorythm pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.queue.pop_front() { for (idx, _) in graph.edges_of(node) { @@ -69,6 +78,8 @@ impl BreadthFirstSearch { } } + /// Gets a mutable reference to the value of the next node from the algorythm + /// /// # Safety /// /// This function should only be called when the node from the edge exists. diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index e6e7929a860f0..cec64a1a15082 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -2,12 +2,16 @@ use hashbrown::HashSet; use crate::graphs::{keys::NodeIdx, Graph}; +/// Implementation of the `DFS` algorythm +/// +/// it will evaluate every node from the start as deep as it can and then up till the next node. pub struct DepthFirstSearch { stack: Vec, visited: HashSet, } impl DepthFirstSearch { + /// Creates a new `DepthFirstSearch` with a start node and the count of nodes pub fn new(start: NodeIdx, count: usize) -> Self { let mut stack = Vec::new(); let mut visited = HashSet::with_capacity(count); @@ -18,6 +22,7 @@ impl DepthFirstSearch { Self { stack, visited } } + /// Gets a reference to the value of the next node from the algorythm pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { if let Some(node) = self.stack.pop() { for (idx, _) in graph.edges_of(node) { @@ -32,6 +37,8 @@ impl DepthFirstSearch { } } + /// Gets a reference to the value of the next node from the algorythm + /// /// # Safety /// /// This function should only be called when the node from the edge exists. @@ -53,6 +60,7 @@ impl DepthFirstSearch { } } + /// Gets a mutable reference to the value of the next node from the algorythm pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.stack.pop() { for (idx, _) in graph.edges_of(node) { @@ -67,6 +75,8 @@ impl DepthFirstSearch { } } + /// Gets a mutable reference to the value of the next node from the algorythm + /// /// # Safety /// /// This function should only be called when the node from the edge exists. diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 8550b09064fe5..e85293fe2f87a 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -9,6 +9,9 @@ use crate::{ impl_graph, }; +/// Implementation of a MultiGraph which uses `Vec<(NodeIdx, Vec)>` for adjacencies +/// +/// MultiGraphs can hold multiple edges between two nodes and edges between the same node #[derive(Clone)] pub struct MultiListGraph { nodes: HopSlotMap, diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 4ab237bceebba..44c2896253884 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -10,6 +10,9 @@ use crate::{ impl_graph, }; +/// Implementation of a MultiGraph which uses `HashMap>` for adjacencies +/// +/// MultiGraphs can hold multiple edges between two nodes and edges between the same node #[derive(Clone)] pub struct MultiMapGraph { nodes: HopSlotMap, diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 29e1186d94006..21b7774e59c5e 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -10,6 +10,9 @@ use crate::{ impl_graph, }; +/// Implementation of a SimpleGraph which uses `Vec<(NodeIdx, EdgeIdx)>` for adjacencies +/// +/// SimpleGraphs can only hold one edge between two nodes and can't have edges between the same node #[derive(Clone)] pub struct SimpleListGraph { nodes: HopSlotMap, diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index b164f2bbebc63..851aab4d5615c 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -11,6 +11,9 @@ use crate::{ impl_graph, }; +/// Implementation of a SimpleGraph which uses `HashMap` for adjacencies +/// +/// SimpleGraphs can only hold one edge between two nodes and can't have edges between the same node #[derive(Clone)] pub struct SimpleMapGraph { nodes: HopSlotMap, @@ -18,8 +21,6 @@ pub struct SimpleMapGraph { adjacencies: SecondaryMap>, } -impl SimpleMapGraph {} - impl_graph! { impl COMMON for SimpleMapGraph { fn new() -> Self { From 3aec9915a478ae620420f6e2ec19ac26947dbf17 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 14:51:02 +0100 Subject: [PATCH 082/183] backticks... --- crates/bevy_graph/src/graphs/multi/list.rs | 4 ++-- crates/bevy_graph/src/graphs/multi/map.rs | 4 ++-- crates/bevy_graph/src/graphs/simple/list.rs | 4 ++-- crates/bevy_graph/src/graphs/simple/map.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index e85293fe2f87a..022b1d6d32db1 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -9,9 +9,9 @@ use crate::{ impl_graph, }; -/// Implementation of a MultiGraph which uses `Vec<(NodeIdx, Vec)>` for adjacencies +/// Implementation of a `MultiGraph` which uses `Vec<(NodeIdx, Vec)>` for adjacencies /// -/// MultiGraphs can hold multiple edges between two nodes and edges between the same node +/// `MultiGraph`s can hold multiple edges between two nodes and edges between the same node #[derive(Clone)] pub struct MultiListGraph { nodes: HopSlotMap, diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 44c2896253884..ad0e79f98c2b0 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -10,9 +10,9 @@ use crate::{ impl_graph, }; -/// Implementation of a MultiGraph which uses `HashMap>` for adjacencies +/// Implementation of a `MultiGraph` which uses `HashMap>` for adjacencies /// -/// MultiGraphs can hold multiple edges between two nodes and edges between the same node +/// `MultiGraph`s can hold multiple edges between two nodes and edges between the same node #[derive(Clone)] pub struct MultiMapGraph { nodes: HopSlotMap, diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 21b7774e59c5e..9f5b02c92bd2d 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -10,9 +10,9 @@ use crate::{ impl_graph, }; -/// Implementation of a SimpleGraph which uses `Vec<(NodeIdx, EdgeIdx)>` for adjacencies +/// Implementation of a `SimpleGraph` which uses `Vec<(NodeIdx, EdgeIdx)>` for adjacencies /// -/// SimpleGraphs can only hold one edge between two nodes and can't have edges between the same node +/// `SimpleGraph`s can only hold one edge between two nodes and can't have edges between the same node #[derive(Clone)] pub struct SimpleListGraph { nodes: HopSlotMap, diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 851aab4d5615c..bb309d45a42fd 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -11,9 +11,9 @@ use crate::{ impl_graph, }; -/// Implementation of a SimpleGraph which uses `HashMap` for adjacencies +/// Implementation of a `SimpleGraph` which uses `HashMap` for adjacencies /// -/// SimpleGraphs can only hold one edge between two nodes and can't have edges between the same node +/// `SimpleGraph`s can only hold one edge between two nodes and can't have edges between the same node #[derive(Clone)] pub struct SimpleMapGraph { nodes: HopSlotMap, From c63597aafa2d37b0c95089bcf5030665f599a39b Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 14:59:10 +0100 Subject: [PATCH 083/183] Apparently don't know my own API - well thats cool --- crates/bevy_graph/src/graphs/mod.rs | 36 ++++++++++------------------- 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index f2bac38262312..d87dea33b63d6 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -76,11 +76,11 @@ pub trait Graph { /// This function can also be directly called by the `EdgeIdx`: /// ``` /// # use bevy_graph::graphs::{Graph, simple::SimpleMapGraph}; - /// # let graph = SimpleMapGraph::new(); - /// let from = graph.new_node(); - /// let to = graph.new_node(); + /// # let mut graph = SimpleMapGraph::<(), i32, true>::new(); + /// let from = graph.new_node(()); + /// let to = graph.new_node(()); /// let edge = graph.new_edge(from, to, 12).unwrap(); - /// assert_eq!(edge.get(&graph), &12); + /// assert_eq!(edge.get(&graph).unwrap(), &12); /// ``` fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E>; @@ -91,11 +91,11 @@ pub trait Graph { /// This function can also be directly called by the `EdgeIdx`: /// ``` /// # use bevy_graph::graphs::{Graph, simple::SimpleMapGraph}; - /// # let graph = SimpleMapGraph::new(); - /// let from = graph.new_node(); - /// let to = graph.new_node(); + /// # let mut graph = SimpleMapGraph::<(), i32, true>::new(); + /// let from = graph.new_node(()); + /// let to = graph.new_node(()); /// let edge = graph.new_edge(from, to, 12).unwrap(); - /// assert_eq!(edge.get_mut(&graph), &12); + /// assert_eq!(edge.get_mut(&mut graph).unwrap(), &12); /// ``` fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E>; @@ -106,28 +106,16 @@ pub trait Graph { /// This function can also be directly called by the `EdgeIdx`: /// ``` /// # use bevy_graph::graphs::{Graph, simple::SimpleMapGraph}; - /// # let graph = SimpleMapGraph::new(); - /// let from = graph.new_node(); - /// let to = graph.new_node(); + /// # let mut graph = SimpleMapGraph::<(), i32, true>::new(); + /// let from = graph.new_node(()); + /// let to = graph.new_node(()); /// let edge = graph.new_edge(from, to, 12).unwrap(); - /// assert_eq!(edge.remove(&graph).unwrap(), 12); + /// assert_eq!(edge.remove(&mut graph).unwrap(), 12); /// ``` fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; /// Remove an edge by its `EdgeIdx` and returns the edge data /// - /// ## Inline helper - /// - /// This function can also be directly called by the `EdgeIdx`: - /// ``` - /// # use bevy_graph::graphs::{Graph, simple::SimpleMapGraph}; - /// # let graph = SimpleMapGraph::new(); - /// let from = graph.new_node(); - /// let to = graph.new_node(); - /// let edge = graph.new_edge(from, to, 12).unwrap(); - /// assert_eq!(edge.remove(&graph).unwrap(), 12); - /// ``` - /// /// # Safety /// /// This function should only be called when the edge exists From 38673117c516bb27decacecff1b3a7987c817dc3 Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:14:43 +0100 Subject: [PATCH 084/183] Update description in Cargo.toml Co-authored-by: Alice Cecile --- crates/bevy_graph/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/Cargo.toml b/crates/bevy_graph/Cargo.toml index a1337c7bcb97e..5e042f4ec34f8 100644 --- a/crates/bevy_graph/Cargo.toml +++ b/crates/bevy_graph/Cargo.toml @@ -2,7 +2,7 @@ name = "bevy_graph" version = "0.9.0" edition = "2021" -description = "Bevy Engine Graph Structure" +description = "Graph data structures, as used by the Bevy game engine" homepage = "https://bevyengine.org" repository = "https://github.com/bevyengine/bevy" license = "MIT OR Apache-2.0" From 51faf5f8491384886fe6ee505c4aab051c7089e4 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 15:17:50 +0100 Subject: [PATCH 085/183] Link algorythms --- crates/bevy_graph/src/algos/bfs.rs | 2 +- crates/bevy_graph/src/algos/dfs.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 81a31efd2d39a..eb87029241e0d 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -4,7 +4,7 @@ use hashbrown::HashSet; use crate::graphs::{keys::NodeIdx, Graph}; -/// Implementation of the `BFS` algorythm +/// Implementation of the [`BFS` algorythm](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/) /// /// when `d` is the distance between a node and the startnode, /// it will evaluate every node with `d=1`, then continue with `d=2` and so on. diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index cec64a1a15082..7f9084fcd67e8 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -2,7 +2,7 @@ use hashbrown::HashSet; use crate::graphs::{keys::NodeIdx, Graph}; -/// Implementation of the `DFS` algorythm +/// Implementation of the [`DFS` algorythm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) /// /// it will evaluate every node from the start as deep as it can and then up till the next node. pub struct DepthFirstSearch { From c4150cab4aaea9db384ff334483d8f18653761bc Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 15:20:37 +0100 Subject: [PATCH 086/183] algos with `with_capacity` --- crates/bevy_graph/src/algos/bfs.rs | 15 +++++++++++++-- crates/bevy_graph/src/algos/dfs.rs | 15 +++++++++++++-- crates/bevy_graph/src/graphs/mod.rs | 4 ++-- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index eb87029241e0d..a72226ed17e75 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -14,9 +14,20 @@ pub struct BreadthFirstSearch { } impl BreadthFirstSearch { - /// Creates a new `DepthFirstSearch` with a start node and the count of nodes - pub fn new(start: NodeIdx, count: usize) -> Self { + /// Creates a new `BreadthFirstSearch` with a start node + pub fn new(start: NodeIdx) -> Self { let mut queue = VecDeque::new(); + let mut visited = HashSet::new(); + + visited.insert(start); + queue.push_back(start); + + Self { queue, visited } + } + + /// Creates a new `BreadthFirstSearch` with a start node and the count of nodes for capacity reserving + pub fn with_capacity(start: NodeIdx, count: usize) -> Self { + let mut queue = VecDeque::with_capacity(count); let mut visited = HashSet::with_capacity(count); visited.insert(start); diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 7f9084fcd67e8..a5fe27376cc8b 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -11,9 +11,20 @@ pub struct DepthFirstSearch { } impl DepthFirstSearch { - /// Creates a new `DepthFirstSearch` with a start node and the count of nodes - pub fn new(start: NodeIdx, count: usize) -> Self { + /// Creates a new `DepthFirstSearch` with a start node + pub fn new(start: NodeIdx) -> Self { let mut stack = Vec::new(); + let mut visited = HashSet::new(); + + visited.insert(start); + stack.push(start); + + Self { stack, visited } + } + + /// Creates a new `DepthFirstSearch` with a start node and the count of nodes for capacity reserving + pub fn with_capacity(start: NodeIdx, count: usize) -> Self { + let mut stack = Vec::with_capacity(count); let mut visited = HashSet::with_capacity(count); visited.insert(start); diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index d87dea33b63d6..80e2d75212e63 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -141,13 +141,13 @@ pub trait Graph { /// Makes a `BreadthFirstSearch` over this graph #[inline] fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { - BreadthFirstSearch::new(start, self.count()) + BreadthFirstSearch::with_capacity(start, self.count()) } /// Makes a `DepthFirstSearch` over this graph #[inline] fn algo_dfs(&self, start: NodeIdx) -> DepthFirstSearch { - DepthFirstSearch::new(start, self.count()) + DepthFirstSearch::with_capacity(start, self.count()) } } From a13b35b621d31d4589308548fd60165d8cfa737a Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:22:02 +0100 Subject: [PATCH 087/183] docs Co-authored-by: Alice Cecile --- crates/bevy_graph/src/algos/bfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index a72226ed17e75..4612d2602902e 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -51,7 +51,7 @@ impl BreadthFirstSearch { } } - /// Gets a reference to the value of the next node from the algorythm + /// Gets an immutable reference to the value of the next node from the algorithm /// /// # Safety /// From e0c24ae2451046a524dbe81eddeb7d7b9ddb9d8c Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:22:27 +0100 Subject: [PATCH 088/183] docs Co-authored-by: Alice Cecile --- crates/bevy_graph/src/algos/bfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 4612d2602902e..f391106d10ebc 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -36,7 +36,7 @@ impl BreadthFirstSearch { Self { queue, visited } } - /// Gets a reference to the value of the next node from the algorythm + /// Gets an immutable reference to the value of the next node from the algorithm pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { if let Some(node) = self.queue.pop_front() { for (idx, _) in graph.edges_of(node) { From 25529325131b8c2cfed49cfad20359d56e3a87bb Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:23:31 +0100 Subject: [PATCH 089/183] docs Co-authored-by: Alice Cecile --- crates/bevy_graph/src/algos/bfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index f391106d10ebc..3d60ab36b0535 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -74,7 +74,7 @@ impl BreadthFirstSearch { } } - /// Gets a mutable reference to the value of the next node from the algorythm + /// Gets a mutable reference to the value of the next node from the algorithm. pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.queue.pop_front() { for (idx, _) in graph.edges_of(node) { From 6389a6a16dfced41bc7a8443fe402e2e693f7b47 Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:23:52 +0100 Subject: [PATCH 090/183] docs Co-authored-by: Alice Cecile --- crates/bevy_graph/src/algos/bfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 3d60ab36b0535..fa3b332c85a04 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -89,7 +89,7 @@ impl BreadthFirstSearch { } } - /// Gets a mutable reference to the value of the next node from the algorythm + /// Gets a mutable reference to the value of the next node from the algorithm. /// /// # Safety /// From c387337795bdd65886e541f9d0b0e6ceff9dafcd Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:24:48 +0100 Subject: [PATCH 091/183] the wording i saw infront of me Co-authored-by: Alice Cecile --- crates/bevy_graph/src/algos/dfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index a5fe27376cc8b..2574f96eb5c30 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -4,7 +4,7 @@ use crate::graphs::{keys::NodeIdx, Graph}; /// Implementation of the [`DFS` algorythm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) /// -/// it will evaluate every node from the start as deep as it can and then up till the next node. +/// it will evaluate every node from the start as deep as it can and then continue at the next sibling node from the top. pub struct DepthFirstSearch { stack: Vec, visited: HashSet, From 8cf48b30a0a4a4f6b137e3c145728285fad674d6 Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:25:30 +0100 Subject: [PATCH 092/183] docs Co-authored-by: Alice Cecile --- crates/bevy_graph/src/algos/dfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 2574f96eb5c30..5af311691487c 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -33,7 +33,7 @@ impl DepthFirstSearch { Self { stack, visited } } - /// Gets a reference to the value of the next node from the algorythm + /// Gets a reference to the value of the next node from the algorithm. pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { if let Some(node) = self.stack.pop() { for (idx, _) in graph.edges_of(node) { From 0ced1beda5c86ffaad6ca943b3e5d855db61d1f1 Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:25:59 +0100 Subject: [PATCH 093/183] docs Co-authored-by: Alice Cecile --- crates/bevy_graph/src/algos/dfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 5af311691487c..a7e5ef4f09514 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -48,7 +48,7 @@ impl DepthFirstSearch { } } - /// Gets a reference to the value of the next node from the algorythm + /// Gets a reference to the value of the next node from the algorithm. /// /// # Safety /// From 5304cc27e623d3d302b0a601f1bb941c4e44d9bf Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:26:18 +0100 Subject: [PATCH 094/183] docs Co-authored-by: Alice Cecile --- crates/bevy_graph/src/algos/dfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index a7e5ef4f09514..6ebbf602e667e 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -71,7 +71,7 @@ impl DepthFirstSearch { } } - /// Gets a mutable reference to the value of the next node from the algorythm + /// Gets a mutable reference to the value of the next node from the algorithm. pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.stack.pop() { for (idx, _) in graph.edges_of(node) { From b08215155c835bb98e686a640ed0d593005cd05c Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:28:01 +0100 Subject: [PATCH 095/183] `GraphError` docs Co-authored-by: Alice Cecile --- crates/bevy_graph/src/error.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs index 2d7f7c539775c..c9942460cc654 100644 --- a/crates/bevy_graph/src/error.rs +++ b/crates/bevy_graph/src/error.rs @@ -1,6 +1,7 @@ use crate::graphs::keys::{EdgeIdx, NodeIdx}; #[derive(Debug)] +/// An error that can occur when traversing or manipulating a graph data structure pub enum GraphError { NodeIdxDoesntExist(NodeIdx), EdgeIdxDoesntExist(EdgeIdx), From 849e9e9e4608ae1449638250f9ad7479a806f871 Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:29:46 +0100 Subject: [PATCH 096/183] `Edge` docs Co-authored-by: Alice Cecile --- crates/bevy_graph/src/graphs/edge.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs index 81d8deb11ac2b..609f7f9decda6 100644 --- a/crates/bevy_graph/src/graphs/edge.rs +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -1,6 +1,7 @@ use super::keys::NodeIdx; #[derive(Clone)] +/// An edge between nodes that store data of type `E`. pub struct Edge { pub src: NodeIdx, pub dst: NodeIdx, From 5df0f0432404f3b5a904034fd35aec0dc902f5e1 Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:31:58 +0100 Subject: [PATCH 097/183] missing_docs warn Co-authored-by: Alice Cecile --- crates/bevy_graph/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index fb18c8af9443d..9358d20ddfc11 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -1,3 +1,5 @@ +#![warn(missing_docs)] + pub mod algos; pub mod error; pub mod graphs; From 6c9e16896981c257430acba1a351674db2a03a40 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 15:43:21 +0100 Subject: [PATCH 098/183] thiserror and document Idx types --- crates/bevy_graph/Cargo.toml | 1 + crates/bevy_graph/src/error.rs | 9 ++++++++- crates/bevy_graph/src/graphs/keys.rs | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/bevy_graph/Cargo.toml b/crates/bevy_graph/Cargo.toml index 5e042f4ec34f8..227ebdbb5147a 100644 --- a/crates/bevy_graph/Cargo.toml +++ b/crates/bevy_graph/Cargo.toml @@ -11,3 +11,4 @@ keywords = ["bevy"] [dependencies] hashbrown = "0.13.1" slotmap = "1.0.6" +thiserror = "1.0.38" diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs index 2d7f7c539775c..b49fcfc2c1bd6 100644 --- a/crates/bevy_graph/src/error.rs +++ b/crates/bevy_graph/src/error.rs @@ -1,11 +1,18 @@ +use thiserror::Error; + use crate::graphs::keys::{EdgeIdx, NodeIdx}; -#[derive(Debug)] +#[derive(Debug, Error)] pub enum GraphError { + #[error("node by given NodeIdx `{0:?}` doesn't exist in this graph")] NodeIdxDoesntExist(NodeIdx), + #[error("edge by given EdgeIdx `{0:?}` doesn't exist in this graph")] EdgeIdxDoesntExist(EdgeIdx), + #[error("edge between nodes `{0:?}` and `{1:?}` doesn't exist in this graph")] EdgeBetweenDoesntExist(NodeIdx, NodeIdx), + #[error("edge between nodes `{0:?}` and `{1:?}` is already preset in this graph")] EdgeBetweenAlreadyExists(NodeIdx, NodeIdx), + #[error("cannot create an edge between node `{0:?}` and itself in a SimpleGraph. use MultiGraph instead")] EdgeBetweenSameNode(NodeIdx), } diff --git a/crates/bevy_graph/src/graphs/keys.rs b/crates/bevy_graph/src/graphs/keys.rs index 7432849b04742..42e2620857b56 100644 --- a/crates/bevy_graph/src/graphs/keys.rs +++ b/crates/bevy_graph/src/graphs/keys.rs @@ -5,7 +5,9 @@ use crate::error::GraphResult; use super::Graph; new_key_type! { + /// a key that holds an index to a node in a graph pub struct NodeIdx; + /// a key that holds an index to an edge in a graph pub struct EdgeIdx; } From 91e4c79b3193128431423966734a463b0dfdcf49 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 16:02:09 +0100 Subject: [PATCH 099/183] big doc and result change --- crates/bevy_graph/src/algos/mod.rs | 2 ++ crates/bevy_graph/src/error.rs | 9 ++++--- crates/bevy_graph/src/graphs/edge.rs | 6 ++++- crates/bevy_graph/src/graphs/impl_graph.rs | 1 + crates/bevy_graph/src/graphs/keys.rs | 11 +++++--- crates/bevy_graph/src/graphs/mod.rs | 30 +++++++++++++-------- crates/bevy_graph/src/graphs/multi/list.rs | 22 +++++++-------- crates/bevy_graph/src/graphs/multi/map.rs | 22 +++++++-------- crates/bevy_graph/src/graphs/simple/list.rs | 24 ++++++++--------- crates/bevy_graph/src/graphs/simple/map.rs | 24 ++++++++--------- crates/bevy_graph/src/lib.rs | 4 +++ 11 files changed, 90 insertions(+), 65 deletions(-) diff --git a/crates/bevy_graph/src/algos/mod.rs b/crates/bevy_graph/src/algos/mod.rs index ae6cb413c3dcc..cde0fa3130c06 100644 --- a/crates/bevy_graph/src/algos/mod.rs +++ b/crates/bevy_graph/src/algos/mod.rs @@ -1,2 +1,4 @@ +/// Implementation of the [`BFS` algorythm](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/) pub mod bfs; +/// Implementation of the [`DFS` algorythm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) pub mod dfs; diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs index 3f50adb610c44..e5af83a58a45d 100644 --- a/crates/bevy_graph/src/error.rs +++ b/crates/bevy_graph/src/error.rs @@ -5,16 +5,19 @@ use crate::graphs::keys::{EdgeIdx, NodeIdx}; /// An error that can occur when traversing or manipulating a graph data structure #[derive(Debug, Error)] pub enum GraphError { + /// the given `NodeIdx` is not preset in the graph #[error("node by given NodeIdx `{0:?}` doesn't exist in this graph")] NodeIdxDoesntExist(NodeIdx), + /// the given `EdgeIdx` is not preset in the graph #[error("edge by given EdgeIdx `{0:?}` doesn't exist in this graph")] EdgeIdxDoesntExist(EdgeIdx), + /// there is no edge between the two nodes in the graph #[error("edge between nodes `{0:?}` and `{1:?}` doesn't exist in this graph")] EdgeBetweenDoesntExist(NodeIdx, NodeIdx), - #[error("edge between nodes `{0:?}` and `{1:?}` is already preset in this graph")] + /// there is already an edge between those two nodes + #[error("edge between nodes `{0:?}` and `{1:?}` is already preset in this graph. would you like to use MultiGraph instead?")] EdgeBetweenAlreadyExists(NodeIdx, NodeIdx), + /// `SimpleGraph`s can't hold an edge between the same node #[error("cannot create an edge between node `{0:?}` and itself in a SimpleGraph. use MultiGraph instead")] EdgeBetweenSameNode(NodeIdx), } - -pub type GraphResult = Result; diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs index 609f7f9decda6..2efc1ecafe1b1 100644 --- a/crates/bevy_graph/src/graphs/edge.rs +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -1,14 +1,18 @@ use super::keys::NodeIdx; -#[derive(Clone)] /// An edge between nodes that store data of type `E`. +#[derive(Clone)] pub struct Edge { + /// the `NodeIdx` of the source node pub src: NodeIdx, + /// the `NodeIdx` of the destination node pub dst: NodeIdx, + /// the edge data pub data: E, } impl Edge { + /// Returns the `src` and `dst` of the edge as a tuple #[inline] pub const fn indices(&self) -> (NodeIdx, NodeIdx) { (self.src, self.dst) diff --git a/crates/bevy_graph/src/graphs/impl_graph.rs b/crates/bevy_graph/src/graphs/impl_graph.rs index 0662b1a86eedb..79f3c17aef50c 100644 --- a/crates/bevy_graph/src/graphs/impl_graph.rs +++ b/crates/bevy_graph/src/graphs/impl_graph.rs @@ -1,3 +1,4 @@ +/// An util macro for implementing `Graph` and neighbour traits #[macro_export] macro_rules! impl_graph { (impl COMMON for $name:ident { diff --git a/crates/bevy_graph/src/graphs/keys.rs b/crates/bevy_graph/src/graphs/keys.rs index 42e2620857b56..b30e3a6d4cf6e 100644 --- a/crates/bevy_graph/src/graphs/keys.rs +++ b/crates/bevy_graph/src/graphs/keys.rs @@ -1,6 +1,6 @@ use slotmap::new_key_type; -use crate::error::GraphResult; +use crate::error::GraphError; use super::Graph; @@ -12,18 +12,21 @@ new_key_type! { } impl EdgeIdx { + /// shorthand for getting an immutable reference to the edge data #[inline] - pub fn get(self, graph: &impl Graph) -> GraphResult<&E> { + pub fn get(self, graph: &impl Graph) -> Result<&E, GraphError> { graph.get_edge(self) } + /// shorthand for getting a mutable reference to the edge data #[inline] - pub fn get_mut(self, graph: &mut impl Graph) -> GraphResult<&mut E> { + pub fn get_mut(self, graph: &mut impl Graph) -> Result<&mut E, GraphError> { graph.get_edge_mut(self) } + /// shorthand for removing this edge #[inline] - pub fn remove(self, graph: &mut impl Graph) -> GraphResult { + pub fn remove(self, graph: &mut impl Graph) -> Result { graph.remove_edge(self) } } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 80e2d75212e63..aa78132f74f58 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -1,12 +1,19 @@ +/// All graph types implementing a `MultiGraph` pub mod multi; +/// All graph types implementing a `SimpleGraph` pub mod simple; +/// An edge between nodes that store data of type `E`. pub mod edge; +/// An util macro for implementing `Graph` and neighbour traits pub mod impl_graph; +/// The `NodeIdx` and `EdgeIdx` structs pub mod keys; -use crate::algos::{bfs::BreadthFirstSearch, dfs::DepthFirstSearch}; -use crate::error::GraphResult; +use crate::{ + algos::{bfs::BreadthFirstSearch, dfs::DepthFirstSearch}, + error::GraphError, +}; use self::keys::{EdgeIdx, NodeIdx}; @@ -20,6 +27,7 @@ pub trait Graph { where Self: Sized; + /// Returns the count of nodes in this graph fn count(&self) -> usize; //////////////////////////// @@ -30,7 +38,7 @@ pub trait Graph { fn new_node(&mut self, node: N) -> NodeIdx; /// Returns a reference to the value of a given node - fn get_node(&self, idx: NodeIdx) -> GraphResult<&N>; + fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError>; /// Returns a reference to the value of a given node /// @@ -40,7 +48,7 @@ pub trait Graph { unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N; /// Returns a mutable reference to the value of a given node - fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N>; + fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError>; /// Returns a mutable reference to the value of a given node /// @@ -50,7 +58,7 @@ pub trait Graph { unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N; /// Removes a node from the graph by its `NodeIdx` - fn remove_node(&mut self, node: NodeIdx) -> GraphResult; + fn remove_node(&mut self, node: NodeIdx) -> Result; /// Returns true as long as the node from the given `NodeIdx` is preset fn has_node(&self, node: NodeIdx) -> bool; @@ -60,7 +68,7 @@ pub trait Graph { //////////////////////////// /// Creates a new edge between the two nodes and with the given value in the graph and returns its `EdgeIdx` - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult; + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result; /// Creates a new edge between the two nodes and with the given value in the graph and returns its `EdgeIdx` /// @@ -82,7 +90,7 @@ pub trait Graph { /// let edge = graph.new_edge(from, to, 12).unwrap(); /// assert_eq!(edge.get(&graph).unwrap(), &12); /// ``` - fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E>; + fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError>; /// Returns a mutable reference to the value of a given edge /// @@ -97,7 +105,7 @@ pub trait Graph { /// let edge = graph.new_edge(from, to, 12).unwrap(); /// assert_eq!(edge.get_mut(&mut graph).unwrap(), &12); /// ``` - fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E>; + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError>; /// Remove an edge by its `EdgeIdx` and returns the edge data /// @@ -112,7 +120,7 @@ pub trait Graph { /// let edge = graph.new_edge(from, to, 12).unwrap(); /// assert_eq!(edge.remove(&mut graph).unwrap(), 12); /// ``` - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult; + fn remove_edge(&mut self, edge: EdgeIdx) -> Result; /// Remove an edge by its `EdgeIdx` and returns the edge data /// @@ -122,7 +130,7 @@ pub trait Graph { unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E; /// Returns a `Vec` of all edges between two nodes as `EdgeIdx` - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult>; + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError>; /// Returns a `Vec` of all edges between two nodes as `EdgeIdx` /// @@ -153,7 +161,7 @@ pub trait Graph { pub trait SimpleGraph: Graph { /// Returns an edge between two nodes as `EdgeIdx` - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult>; + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError>; /// Returns an edge between two nodes as `EdgeIdx` /// diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 022b1d6d32db1..02aadd937925f 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -1,7 +1,7 @@ use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ - error::{GraphError, GraphResult}, + error::GraphError, graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, @@ -42,7 +42,7 @@ impl_graph! { } #[inline] - fn get_node(&self, idx: NodeIdx) -> GraphResult<&N> { + fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { if self.nodes.contains_key(idx) { unsafe { Ok(self.get_node_unchecked(idx)) @@ -58,7 +58,7 @@ impl_graph! { } #[inline] - fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { if self.nodes.contains_key(idx) { unsafe { Ok(self.get_node_unchecked_mut(idx)) @@ -79,7 +79,7 @@ impl_graph! { } #[inline] - fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E> { + fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { match self.edges.get(edge) { Some(e) => Ok(&e.data), None => Err(GraphError::EdgeIdxDoesntExist(edge)) @@ -87,14 +87,14 @@ impl_graph! { } #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E> { + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { match self.edges.get_mut(edge) { Some(e) => Ok(&mut e.data), None => Err(GraphError::EdgeIdxDoesntExist(edge)) } } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + fn remove_edge(&mut self, edge: EdgeIdx) -> Result { if self.edges.contains_key(edge) { unsafe { Ok(self.remove_edge_unchecked(edge)) @@ -104,7 +104,7 @@ impl_graph! { } } - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { if self.has_node(from) { unsafe { Ok(self.edges_between_unchecked(from, to)) @@ -135,7 +135,7 @@ impl_graph! { } impl COMMON?undirected { - fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + fn remove_node(&mut self, node: NodeIdx) -> Result { for (_, edge) in self.edges_of(node) { unsafe { // SAFETY: we know it must exist @@ -154,7 +154,7 @@ impl_graph! { } } - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> Result { if self.has_node(node) { if self.has_node(other) { unsafe { @@ -205,7 +205,7 @@ impl_graph! { } impl COMMON?directed { - fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + fn remove_node(&mut self, node: NodeIdx) -> Result { let mut edges = vec![]; for (edge, data) in &self.edges { let (src, dst) = data.indices(); @@ -231,7 +231,7 @@ impl_graph! { } } - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { if self.has_node(from) { if self.has_node(to) { unsafe { diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index ad0e79f98c2b0..afb9ab5135e08 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -2,7 +2,7 @@ use hashbrown::HashMap; use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ - error::{GraphError, GraphResult}, + error::GraphError, graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, @@ -43,7 +43,7 @@ impl_graph! { } #[inline] - fn get_node(&self, idx: NodeIdx) -> GraphResult<&N> { + fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { if self.nodes.contains_key(idx) { unsafe { Ok(self.get_node_unchecked(idx)) @@ -59,7 +59,7 @@ impl_graph! { } #[inline] - fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { if self.nodes.contains_key(idx) { unsafe { Ok(self.get_node_unchecked_mut(idx)) @@ -80,7 +80,7 @@ impl_graph! { } #[inline] - fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E> { + fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { match self.edges.get(edge) { Some(e) => Ok(&e.data), None => Err(GraphError::EdgeIdxDoesntExist(edge)) @@ -88,14 +88,14 @@ impl_graph! { } #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E> { + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { match self.edges.get_mut(edge) { Some(e) => Ok(&mut e.data), None => Err(GraphError::EdgeIdxDoesntExist(edge)) } } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + fn remove_edge(&mut self, edge: EdgeIdx) -> Result { if self.edges.contains_key(edge) { unsafe { Ok(self.remove_edge_unchecked(edge)) @@ -106,7 +106,7 @@ impl_graph! { } #[inline] - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.contains_key(&to) { unsafe { @@ -143,7 +143,7 @@ impl_graph! { } impl COMMON?undirected { - fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + fn remove_node(&mut self, node: NodeIdx) -> Result { for (_, edge) in self.edges_of(node) { unsafe { // SAFETY: we know it must exist @@ -162,7 +162,7 @@ impl_graph! { } } - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> Result { if self.has_node(node) { if self.has_node(other) { unsafe { @@ -198,7 +198,7 @@ impl_graph! { } impl COMMON?directed { - fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + fn remove_node(&mut self, node: NodeIdx) -> Result { let mut edges = vec![]; for (edge, data) in &self.edges { let (src, dst) = data.indices(); @@ -224,7 +224,7 @@ impl_graph! { } } - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { if self.has_node(from) { if self.has_node(to) { unsafe { diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 9f5b02c92bd2d..1ac262b94edf9 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -1,7 +1,7 @@ use slotmap::{HopSlotMap, Key, SecondaryMap}; use crate::{ - error::{GraphError, GraphResult}, + error::GraphError, graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, @@ -43,7 +43,7 @@ impl_graph! { } #[inline] - fn get_node(&self, idx: NodeIdx) -> GraphResult<&N> { + fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { if self.nodes.contains_key(idx) { unsafe { Ok(self.get_node_unchecked(idx)) @@ -59,7 +59,7 @@ impl_graph! { } #[inline] - fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { if self.nodes.contains_key(idx) { unsafe { Ok(self.get_node_unchecked_mut(idx)) @@ -80,7 +80,7 @@ impl_graph! { } #[inline] - fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E> { + fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { match self.edges.get(edge) { Some(e) => Ok(&e.data), None => Err(GraphError::EdgeIdxDoesntExist(edge)) @@ -88,14 +88,14 @@ impl_graph! { } #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E> { + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { match self.edges.get_mut(edge) { Some(e) => Ok(&mut e.data), None => Err(GraphError::EdgeIdxDoesntExist(edge)) } } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + fn remove_edge(&mut self, edge: EdgeIdx) -> Result { if self.edges.contains_key(edge) { unsafe { Ok(self.remove_edge_unchecked(edge)) @@ -106,7 +106,7 @@ impl_graph! { } #[inline] - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { match self.edge_between(from, to) { Ok(Some(idx)) => Ok(vec![idx]), Ok(None) => Ok(vec![]), @@ -126,7 +126,7 @@ impl_graph! { } impl COMMON?undirected { - fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + fn remove_node(&mut self, node: NodeIdx) -> Result { for (_, edge) in self.edges_of(node) { unsafe { // SAFETY: we know it must exist @@ -145,7 +145,7 @@ impl_graph! { } } - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> Result { if node == other { Err(GraphError::EdgeBetweenSameNode(node)) } else if let Some(node_edges) = self.adjacencies.get(node) { @@ -189,7 +189,7 @@ impl_graph! { } impl COMMON?directed { - fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + fn remove_node(&mut self, node: NodeIdx) -> Result { let mut edges = vec![]; for (edge, data) in &self.edges { let (src, dst) = data.indices(); @@ -215,7 +215,7 @@ impl_graph! { } } - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { if from == to { Err(GraphError::EdgeBetweenSameNode(from)) } else if let Some(from_edges) = self.adjacencies.get(from) { @@ -252,7 +252,7 @@ impl_graph! { } impl SIMPLE { - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { if self.adjacencies.contains_key(from) { unsafe { let idx = self.edge_between_unchecked(from, to); diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index bb309d45a42fd..f0fde3078f554 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -2,7 +2,7 @@ use hashbrown::HashMap; use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ - error::{GraphError, GraphResult}, + error::GraphError, graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, @@ -44,7 +44,7 @@ impl_graph! { } #[inline] - fn get_node(&self, idx: NodeIdx) -> GraphResult<&N> { + fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { if self.nodes.contains_key(idx) { unsafe { Ok(self.get_node_unchecked(idx)) @@ -60,7 +60,7 @@ impl_graph! { } #[inline] - fn get_node_mut(&mut self, idx: NodeIdx) -> GraphResult<&mut N> { + fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { if self.nodes.contains_key(idx) { unsafe { Ok(self.get_node_unchecked_mut(idx)) @@ -81,7 +81,7 @@ impl_graph! { } #[inline] - fn get_edge(&self, edge: EdgeIdx) -> GraphResult<&E> { + fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { match self.edges.get(edge) { Some(e) => Ok(&e.data), None => Err(GraphError::EdgeIdxDoesntExist(edge)) @@ -89,14 +89,14 @@ impl_graph! { } #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> GraphResult<&mut E> { + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { match self.edges.get_mut(edge) { Some(e) => Ok(&mut e.data), None => Err(GraphError::EdgeIdxDoesntExist(edge)) } } - fn remove_edge(&mut self, edge: EdgeIdx) -> GraphResult { + fn remove_edge(&mut self, edge: EdgeIdx) -> Result { if self.edges.contains_key(edge) { unsafe { Ok(self.remove_edge_unchecked(edge)) @@ -107,7 +107,7 @@ impl_graph! { } #[inline] - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { match self.edge_between(from, to) { Ok(Some(idx)) => Ok(vec![idx]), Ok(None) => Ok(vec![]), @@ -132,7 +132,7 @@ impl_graph! { } impl COMMON?undirected { - fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + fn remove_node(&mut self, node: NodeIdx) -> Result { for (_, edge) in self.edges_of(node) { unsafe { // SAFETY: we know it must exist @@ -151,7 +151,7 @@ impl_graph! { } } - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> GraphResult { + fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> Result { if node == other { Err(GraphError::EdgeBetweenSameNode(node)) } else if let Some(node_edges) = self.adjacencies.get(node) { @@ -193,7 +193,7 @@ impl_graph! { } impl COMMON?directed { - fn remove_node(&mut self, node: NodeIdx) -> GraphResult { + fn remove_node(&mut self, node: NodeIdx) -> Result { let mut edges = vec![]; for (edge, data) in &self.edges { let (src, dst) = data.indices(); @@ -219,7 +219,7 @@ impl_graph! { } } - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> GraphResult { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { if from == to { Err(GraphError::EdgeBetweenSameNode(from)) } else if let Some(from_edges) = self.adjacencies.get(from) { @@ -255,7 +255,7 @@ impl_graph! { } impl SIMPLE { - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> GraphResult> { + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.contains_key(&to) { unsafe { diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index 9358d20ddfc11..6cd4a7ef2836a 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -1,5 +1,9 @@ #![warn(missing_docs)] +//! Graph data structures, as used by the Bevy game engine +/// All implemented algorithms for graphs pub mod algos; +/// All errors that can occur when executing a graph operation pub mod error; +/// The `Graph` trait and all graph implementations pub mod graphs; From d23424c05cfe0dcf68337d0619e8660b2da07fb8 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 16:03:38 +0100 Subject: [PATCH 100/183] renaming `algo_*` methods for graph --- crates/bevy_graph/src/graphs/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index aa78132f74f58..9569dbdcf1418 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -148,13 +148,13 @@ pub trait Graph { /// Makes a `BreadthFirstSearch` over this graph #[inline] - fn algo_bfs(&self, start: NodeIdx) -> BreadthFirstSearch { + fn breadth_first_search(&self, start: NodeIdx) -> BreadthFirstSearch { BreadthFirstSearch::with_capacity(start, self.count()) } /// Makes a `DepthFirstSearch` over this graph #[inline] - fn algo_dfs(&self, start: NodeIdx) -> DepthFirstSearch { + fn depth_first_search(&self, start: NodeIdx) -> DepthFirstSearch { DepthFirstSearch::with_capacity(start, self.count()) } } From 624d8716e5fa541641c582f41e86302c82c70af1 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 16:07:00 +0100 Subject: [PATCH 101/183] working on algos --- crates/bevy_graph/src/algos/bfs.rs | 14 ++++++++++---- crates/bevy_graph/src/algos/dfs.rs | 14 ++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index fa3b332c85a04..9d0f1a1d39b01 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -68,7 +68,10 @@ impl BreadthFirstSearch { self.queue.push_back(idx); } } - Some(graph.get_node_unchecked(node)) + unsafe { + // SAFETY: the caller says its fine + Some(graph.get_node_unchecked(node)) + } } else { None } @@ -106,7 +109,10 @@ impl BreadthFirstSearch { self.queue.push_back(idx); } } - Some(graph.get_node_unchecked_mut(node)) + unsafe { + // SAFETY: the caller says its fine + Some(graph.get_node_unchecked_mut(node)) + } } else { None } @@ -118,7 +124,7 @@ mod test { use crate::graphs::{simple::SimpleMapGraph, Graph}; #[test] - fn bfs() { + fn basic_imperative_bfs() { let mut map = SimpleMapGraph::::new(); let zero = map.new_node(0); @@ -136,7 +142,7 @@ mod test { let mut counted_elements = Vec::with_capacity(4); - let mut bfs = map.algo_bfs(zero); + let mut bfs = map.breadth_first_search(zero); while let Some(node) = bfs.next(&map) { counted_elements.push(*node); } diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 6ebbf602e667e..ff310f97c4e06 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -65,7 +65,10 @@ impl DepthFirstSearch { self.stack.push(idx); } } - Some(graph.get_node_unchecked(node)) + unsafe { + // SAFETY: the caller says its fine + Some(graph.get_node_unchecked(node)) + } } else { None } @@ -103,7 +106,10 @@ impl DepthFirstSearch { self.stack.push(idx); } } - Some(graph.get_node_unchecked_mut(node)) + unsafe { + // SAFETY: the caller says its fine + Some(graph.get_node_unchecked_mut(node)) + } } else { None } @@ -115,7 +121,7 @@ mod test { use crate::graphs::{simple::SimpleMapGraph, Graph}; #[test] - fn dfs() { + fn basic_imperative_dfs() { let mut map = SimpleMapGraph::::new(); let zero = map.new_node(0); @@ -133,7 +139,7 @@ mod test { let mut counted_elements = Vec::with_capacity(4); - let mut dfs = map.algo_dfs(zero); + let mut dfs = map.depth_first_search(zero); while let Some(node) = dfs.next(&map) { counted_elements.push(*node); } From 8fb962c81bd65aa4190f1335eb89321ed9c3c7df Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 16:10:56 +0100 Subject: [PATCH 102/183] docs for Graph traits --- crates/bevy_graph/src/graphs/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 9569dbdcf1418..6f6daa5ede6db 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -17,10 +17,11 @@ use crate::{ use self::keys::{EdgeIdx, NodeIdx}; -// NOTE: There should always be a general API function and a more precise API function for one problem with multiple signatures needed. +// NOTE: There should always be a common function and if needed a more precise function which the common function wraps. // Example: `edges_between` is `trait Graph` general and has support for Simple- and Multigraphs. // `edge_between` is only available for `SimpleGraph` but is also called from `edges_between`. +/// A trait with all the common functions for a graph pub trait Graph { /// Creates a new graph fn new() -> Self @@ -159,6 +160,7 @@ pub trait Graph { } } +/// A more precise trait with functions special for a simple graph pub trait SimpleGraph: Graph { /// Returns an edge between two nodes as `EdgeIdx` fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError>; From f864a314885ae064ff2e7c086983d6156a03a5d4 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 16:22:38 +0100 Subject: [PATCH 103/183] benchies --- benches/benches/bevy_graph/bfs_and_dfs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benches/benches/bevy_graph/bfs_and_dfs.rs b/benches/benches/bevy_graph/bfs_and_dfs.rs index 4a3c4633037c0..965180d50753b 100644 --- a/benches/benches/bevy_graph/bfs_and_dfs.rs +++ b/benches/benches/bevy_graph/bfs_and_dfs.rs @@ -36,7 +36,7 @@ fn algo_10_000(c: &mut Criterion) { c.bench_function("bfs_10_000", |b| { b.iter(|| { - let mut bfs = graph.algo_bfs(first); + let mut bfs = graph.breadth_first_search(first); while let Some(node) = bfs.next(&graph) { let _ = black_box(node); } @@ -45,7 +45,7 @@ fn algo_10_000(c: &mut Criterion) { c.bench_function("dfs_10_000", |b| { b.iter(|| { - let mut dfs = graph.algo_dfs(first); + let mut dfs = graph.depth_first_search(first); while let Some(node) = dfs.next(&graph) { let _ = black_box(node); } From 03b95dbf2b355f3a90beca44db69d62302d3c7f9 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 19:44:02 +0100 Subject: [PATCH 104/183] remove algo functions from `Graph` trait --- benches/benches/bevy_graph/bfs_and_dfs.rs | 9 ++++--- crates/bevy_graph/src/algos/bfs.rs | 29 +++++++++++++---------- crates/bevy_graph/src/algos/dfs.rs | 29 +++++++++++++---------- crates/bevy_graph/src/graphs/mod.rs | 21 +--------------- 4 files changed, 39 insertions(+), 49 deletions(-) diff --git a/benches/benches/bevy_graph/bfs_and_dfs.rs b/benches/benches/bevy_graph/bfs_and_dfs.rs index 965180d50753b..701a7d56b3a88 100644 --- a/benches/benches/bevy_graph/bfs_and_dfs.rs +++ b/benches/benches/bevy_graph/bfs_and_dfs.rs @@ -1,4 +1,7 @@ -use bevy_graph::graphs::{keys::NodeIdx, simple::SimpleMapGraph, Graph}; +use bevy_graph::{ + algos::{bfs::BreadthFirstSearch, dfs::DepthFirstSearch}, + graphs::{keys::NodeIdx, simple::SimpleMapGraph, Graph}, +}; use bevy_utils::Duration; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use rand::seq::SliceRandom; @@ -36,7 +39,7 @@ fn algo_10_000(c: &mut Criterion) { c.bench_function("bfs_10_000", |b| { b.iter(|| { - let mut bfs = graph.breadth_first_search(first); + let mut bfs = BreadthFirstSearch::with_capacity(first, graph.count()); while let Some(node) = bfs.next(&graph) { let _ = black_box(node); } @@ -45,7 +48,7 @@ fn algo_10_000(c: &mut Criterion) { c.bench_function("dfs_10_000", |b| { b.iter(|| { - let mut dfs = graph.depth_first_search(first); + let mut dfs = DepthFirstSearch::with_capacity(first, graph.count()); while let Some(node) = dfs.next(&graph) { let _ = black_box(node); } diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 9d0f1a1d39b01..5a8ee7bc23084 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -121,29 +121,32 @@ impl BreadthFirstSearch { #[cfg(test)] mod test { - use crate::graphs::{simple::SimpleMapGraph, Graph}; + use crate::{ + algos::bfs::BreadthFirstSearch, + graphs::{simple::SimpleMapGraph, Graph}, + }; #[test] fn basic_imperative_bfs() { - let mut map = SimpleMapGraph::::new(); + let mut graph = SimpleMapGraph::::new(); - let zero = map.new_node(0); - let one = map.new_node(1); - let two = map.new_node(2); - let three = map.new_node(3); + let zero = graph.new_node(0); + let one = graph.new_node(1); + let two = graph.new_node(2); + let three = graph.new_node(3); - map.new_edge(zero, one, ()).unwrap(); - map.new_edge(zero, two, ()).unwrap(); - map.new_edge(one, two, ()).unwrap(); - map.new_edge(two, zero, ()).unwrap(); - map.new_edge(two, three, ()).unwrap(); + graph.new_edge(zero, one, ()).unwrap(); + graph.new_edge(zero, two, ()).unwrap(); + graph.new_edge(one, two, ()).unwrap(); + graph.new_edge(two, zero, ()).unwrap(); + graph.new_edge(two, three, ()).unwrap(); let elements = vec![0, 2, 1, 3]; let mut counted_elements = Vec::with_capacity(4); - let mut bfs = map.breadth_first_search(zero); - while let Some(node) = bfs.next(&map) { + let mut bfs = BreadthFirstSearch::with_capacity(zero, graph.count()); + while let Some(node) = bfs.next(&graph) { counted_elements.push(*node); } diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index ff310f97c4e06..f5b82cf93719c 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -118,29 +118,32 @@ impl DepthFirstSearch { #[cfg(test)] mod test { - use crate::graphs::{simple::SimpleMapGraph, Graph}; + use crate::{ + algos::dfs::DepthFirstSearch, + graphs::{simple::SimpleMapGraph, Graph}, + }; #[test] fn basic_imperative_dfs() { - let mut map = SimpleMapGraph::::new(); + let mut graph = SimpleMapGraph::::new(); - let zero = map.new_node(0); - let one = map.new_node(1); - let two = map.new_node(2); - let three = map.new_node(3); + let zero = graph.new_node(0); + let one = graph.new_node(1); + let two = graph.new_node(2); + let three = graph.new_node(3); - map.new_edge(zero, one, ()).unwrap(); - map.new_edge(zero, two, ()).unwrap(); - map.new_edge(one, two, ()).unwrap(); - map.new_edge(two, zero, ()).unwrap(); - map.new_edge(two, three, ()).unwrap(); + graph.new_edge(zero, one, ()).unwrap(); + graph.new_edge(zero, two, ()).unwrap(); + graph.new_edge(one, two, ()).unwrap(); + graph.new_edge(two, zero, ()).unwrap(); + graph.new_edge(two, three, ()).unwrap(); let elements = vec![0, 1, 2, 3]; let mut counted_elements = Vec::with_capacity(4); - let mut dfs = map.depth_first_search(zero); - while let Some(node) = dfs.next(&map) { + let mut dfs = DepthFirstSearch::with_capacity(zero, graph.count()); + while let Some(node) = dfs.next(&graph) { counted_elements.push(*node); } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 6f6daa5ede6db..9c5cdcb6aa66f 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -10,10 +10,7 @@ pub mod impl_graph; /// The `NodeIdx` and `EdgeIdx` structs pub mod keys; -use crate::{ - algos::{bfs::BreadthFirstSearch, dfs::DepthFirstSearch}, - error::GraphError, -}; +use crate::error::GraphError; use self::keys::{EdgeIdx, NodeIdx}; @@ -142,22 +139,6 @@ pub trait Graph { /// Returns a `Vec` of all edges the node is outgoing from. fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? - - //////////////////////////// - // Algos - //////////////////////////// - - /// Makes a `BreadthFirstSearch` over this graph - #[inline] - fn breadth_first_search(&self, start: NodeIdx) -> BreadthFirstSearch { - BreadthFirstSearch::with_capacity(start, self.count()) - } - - /// Makes a `DepthFirstSearch` over this graph - #[inline] - fn depth_first_search(&self, start: NodeIdx) -> DepthFirstSearch { - DepthFirstSearch::with_capacity(start, self.count()) - } } /// A more precise trait with functions special for a simple graph From 1249298d28f4ec4229f26637aaaa5f29c76c3012 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 20:04:26 +0100 Subject: [PATCH 105/183] remove `impl_graph` macro --- crates/bevy_graph/src/graphs/impl_graph.rs | 69 ---- crates/bevy_graph/src/graphs/mod.rs | 2 - crates/bevy_graph/src/graphs/multi/list.rs | 314 +++++++++---------- crates/bevy_graph/src/graphs/multi/map.rs | 324 +++++++++---------- crates/bevy_graph/src/graphs/simple/list.rs | 329 ++++++++++---------- crates/bevy_graph/src/graphs/simple/map.rs | 329 ++++++++++---------- 6 files changed, 634 insertions(+), 733 deletions(-) delete mode 100644 crates/bevy_graph/src/graphs/impl_graph.rs diff --git a/crates/bevy_graph/src/graphs/impl_graph.rs b/crates/bevy_graph/src/graphs/impl_graph.rs deleted file mode 100644 index 79f3c17aef50c..0000000000000 --- a/crates/bevy_graph/src/graphs/impl_graph.rs +++ /dev/null @@ -1,69 +0,0 @@ -/// An util macro for implementing `Graph` and neighbour traits -#[macro_export] -macro_rules! impl_graph { - (impl COMMON for $name:ident { - $($common_code:tt)* - } - - $(impl COMMON?undirected { - $($common_undirected_code:tt)* - })? - - $(impl COMMON?directed { - $($common_directed_code:tt)* - })? - - $( - impl SIMPLE { - $($simple_code:tt)* - } - - $(impl SIMPLE?undirected { - $($simple_undirected_code:tt)* - })? - - $(impl SIMPLE?directed { - $($simple_directed_code:tt)* - })? - )?) => { - impl $crate::graphs::Graph for $name { - $($common_code)* - - $($($common_undirected_code)*)? - } - - impl $crate::graphs::Graph for $name { - $($common_code)* - - $($($common_directed_code)*)? - } - - $( - impl $crate::graphs::SimpleGraph for $name { - $($simple_code)* - - $($($simple_undirected_code)*)? - } - - impl $crate::graphs::SimpleGraph for $name { - $($simple_code)* - - $($($simple_directed_code)*)? - } - )? - - impl Default for $name { - #[inline] - fn default() -> Self { - $crate::graphs::Graph::new() - } - } - - impl Default for $name { - #[inline] - fn default() -> Self { - $crate::graphs::Graph::new() - } - } - } -} diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 9c5cdcb6aa66f..3c104db11f273 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -5,8 +5,6 @@ pub mod simple; /// An edge between nodes that store data of type `E`. pub mod edge; -/// An util macro for implementing `Graph` and neighbour traits -pub mod impl_graph; /// The `NodeIdx` and `EdgeIdx` structs pub mod keys; diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 02aadd937925f..57f83d0426abb 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -5,8 +5,8 @@ use crate::{ graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, + Graph, }, - impl_graph, }; /// Implementation of a `MultiGraph` which uses `Vec<(NodeIdx, Vec)>` for adjacencies @@ -19,124 +19,123 @@ pub struct MultiListGraph { adjacencies: SecondaryMap)>>, } -impl_graph! { - impl COMMON for MultiListGraph { - fn new() -> Self { - Self { - nodes: HopSlotMap::with_key(), - edges: HopSlotMap::with_key(), - adjacencies: SecondaryMap::new(), - } +impl Graph for MultiListGraph { + fn new() -> Self { + Self { + nodes: HopSlotMap::with_key(), + edges: HopSlotMap::with_key(), + adjacencies: SecondaryMap::new(), } + } - #[inline] - fn count(&self) -> usize { - self.nodes.len() - } + #[inline] + fn count(&self) -> usize { + self.nodes.len() + } - #[inline] - fn new_node(&mut self, node: N) -> NodeIdx { - let idx = self.nodes.insert(node); - self.adjacencies.insert(idx, Vec::new()); - idx - } + #[inline] + fn new_node(&mut self, node: N) -> NodeIdx { + let idx = self.nodes.insert(node); + self.adjacencies.insert(idx, Vec::new()); + idx + } - #[inline] - fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { - Ok(self.get_node_unchecked(idx)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) - } + #[inline] + fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { + if self.nodes.contains_key(idx) { + unsafe { Ok(self.get_node_unchecked(idx)) } + } else { + Err(GraphError::NodeIdxDoesntExist(idx)) } + } - #[inline] - unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { - self.nodes.get_unchecked(idx) - } + #[inline] + unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { + self.nodes.get_unchecked(idx) + } - #[inline] - fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { - Ok(self.get_node_unchecked_mut(idx)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) - } + #[inline] + fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { + if self.nodes.contains_key(idx) { + unsafe { Ok(self.get_node_unchecked_mut(idx)) } + } else { + Err(GraphError::NodeIdxDoesntExist(idx)) } + } - #[inline] - unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { - self.nodes.get_unchecked_mut(idx) - } + #[inline] + unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { + self.nodes.get_unchecked_mut(idx) + } - #[inline] - fn has_node(&self, node: NodeIdx) -> bool { - self.nodes.contains_key(node) - } + #[inline] + fn has_node(&self, node: NodeIdx) -> bool { + self.nodes.contains_key(node) + } - #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { - match self.edges.get(edge) { - Some(e) => Ok(&e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)) - } + #[inline] + fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { + match self.edges.get(edge) { + Some(e) => Ok(&e.data), + None => Err(GraphError::EdgeIdxDoesntExist(edge)), } + } - #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { - match self.edges.get_mut(edge) { - Some(e) => Ok(&mut e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)) - } + #[inline] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { + match self.edges.get_mut(edge) { + Some(e) => Ok(&mut e.data), + None => Err(GraphError::EdgeIdxDoesntExist(edge)), } + } - fn remove_edge(&mut self, edge: EdgeIdx) -> Result { - if self.edges.contains_key(edge) { - unsafe { - Ok(self.remove_edge_unchecked(edge)) - } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } + fn remove_edge(&mut self, edge: EdgeIdx) -> Result { + if self.edges.contains_key(edge) { + unsafe { Ok(self.remove_edge_unchecked(edge)) } + } else { + Err(GraphError::EdgeIdxDoesntExist(edge)) } + } - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { - if self.has_node(from) { - unsafe { - Ok(self.edges_between_unchecked(from, to)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) - } + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { + if self.has_node(from) { + unsafe { Ok(self.edges_between_unchecked(from, to)) } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) } + } - unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { - find_edge_list(self.adjacencies.get_unchecked(from), to).cloned().unwrap_or_default() - } + unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { + find_edge_list(self.adjacencies.get_unchecked(from), to) + .cloned() + .unwrap_or_default() + } - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - if let Some(list) = self.adjacencies.get(node) { - // TODO: can this be done with iterators? - let mut result = Vec::new(); - for (target, edges) in list { - for edge in edges { - result.push((*target, *edge)); - } + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + if let Some(list) = self.adjacencies.get(node) { + // TODO: can this be done with iterators? + let mut result = Vec::new(); + for (target, edges) in list { + for edge in edges { + result.push((*target, *edge)); } - result - } else { - Vec::new() } + result + } else { + Vec::new() } } - impl COMMON?undirected { - fn remove_node(&mut self, node: NodeIdx) -> Result { - for (_, edge) in self.edges_of(node) { + fn remove_node(&mut self, node: NodeIdx) -> Result { + if DIRECTED { + let mut edges = vec![]; + for (edge, data) in &self.edges { + let (src, dst) = data.indices(); + if dst == node || src == node { + edges.push(edge); + } + } + for edge in edges { unsafe { // SAFETY: we know it must exist self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? @@ -149,71 +148,11 @@ impl_graph! { self.adjacencies.remove(node).unwrap_unchecked(); } Ok(n) - }, - None => Err(GraphError::NodeIdxDoesntExist(node)) - } - } - - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> Result { - if self.has_node(node) { - if self.has_node(other) { - unsafe { - Ok(self.new_edge_unchecked(node, other, edge)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(other)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(node)) - } - } - - unsafe fn new_edge_unchecked(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: node, - dst: other, - data: edge, - }); - let adjs = self.adjacencies.get_unchecked_mut(node); - if let Some(list) = find_edge_list_mut(adjs, other) { - list.push(idx); - } else { - adjs.push((other, vec![idx])); - } - let adjs = self.adjacencies.get_unchecked_mut(other); - if let Some(list) = find_edge_list_mut(adjs, node) { - list.push(idx); - } else { - adjs.push((node, vec![idx])); - } - idx - } - - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { - let (from, to) = self.edges.get_unchecked(edge).indices(); - - let list = self.adjacencies.get_unchecked_mut(from); - let list = find_edge_list_mut(list, to).unwrap(); - list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? - - let list = self.adjacencies.get_unchecked_mut(to); - let list = find_edge_list_mut(list, from).unwrap(); - list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? - - self.edges.remove(edge).unwrap().data - } - } - - impl COMMON?directed { - fn remove_node(&mut self, node: NodeIdx) -> Result { - let mut edges = vec![]; - for (edge, data) in &self.edges { - let (src, dst) = data.indices(); - if dst == node || src == node { - edges.push(edge); } + None => Err(GraphError::NodeIdxDoesntExist(node)), } - for edge in edges { + } else { + for (_, edge) in self.edges_of(node) { unsafe { // SAFETY: we know it must exist self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? @@ -226,17 +165,27 @@ impl_graph! { self.adjacencies.remove(node).unwrap_unchecked(); } Ok(n) - }, - None => Err(GraphError::NodeIdxDoesntExist(node)) + } + None => Err(GraphError::NodeIdxDoesntExist(node)), } } + } - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { + if DIRECTED { if self.has_node(from) { if self.has_node(to) { - unsafe { - Ok(self.new_edge_unchecked(from, to, edge)) - } + unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } + } else { + Err(GraphError::NodeIdxDoesntExist(to)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) + } + } else { + if self.has_node(from) { + if self.has_node(to) { + unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } } else { Err(GraphError::NodeIdxDoesntExist(to)) } @@ -244,8 +193,23 @@ impl_graph! { Err(GraphError::NodeIdxDoesntExist(from)) } } + } - unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + if DIRECTED { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); + let adjs = self.adjacencies.get_unchecked_mut(from); + if let Some(list) = find_edge_list_mut(adjs, to) { + list.push(idx); + } else { + adjs.push((to, vec![idx])); + } + idx + } else { let idx = self.edges.insert(Edge { src: from, dst: to, @@ -257,14 +221,34 @@ impl_graph! { } else { adjs.push((to, vec![idx])); } + let adjs = self.adjacencies.get_unchecked_mut(to); + if let Some(list) = find_edge_list_mut(adjs, from) { + list.push(idx); + } else { + adjs.push((from, vec![idx])); + } idx } + } - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + if DIRECTED { let (from, to) = self.edges.get_unchecked(edge).indices(); let list = self.adjacencies.get_unchecked_mut(from); let list = find_edge_list_mut(list, to).unwrap(); list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? + self.edges.remove(edge).unwrap().data + } else { + let (from, to) = self.edges.get_unchecked(edge).indices(); + + let list = self.adjacencies.get_unchecked_mut(from); + let list = find_edge_list_mut(list, to).unwrap(); + list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? + + let list = self.adjacencies.get_unchecked_mut(to); + let list = find_edge_list_mut(list, from).unwrap(); + list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? + self.edges.remove(edge).unwrap().data } } diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index afb9ab5135e08..f4c485f7c720d 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -6,8 +6,8 @@ use crate::{ graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, + Graph, }, - impl_graph, }; /// Implementation of a `MultiGraph` which uses `HashMap>` for adjacencies @@ -20,131 +20,132 @@ pub struct MultiMapGraph { adjacencies: SecondaryMap>>, } -impl_graph! { - impl COMMON for MultiMapGraph { - fn new() -> Self { - Self { - nodes: HopSlotMap::with_key(), - edges: HopSlotMap::with_key(), - adjacencies: SecondaryMap::new(), - } +impl Graph for MultiMapGraph { + fn new() -> Self { + Self { + nodes: HopSlotMap::with_key(), + edges: HopSlotMap::with_key(), + adjacencies: SecondaryMap::new(), } + } - #[inline] - fn count(&self) -> usize { - self.nodes.len() - } + #[inline] + fn count(&self) -> usize { + self.nodes.len() + } - #[inline] - fn new_node(&mut self, node: N) -> NodeIdx { - let idx = self.nodes.insert(node); - self.adjacencies.insert(idx, HashMap::new()); - idx - } + #[inline] + fn new_node(&mut self, node: N) -> NodeIdx { + let idx = self.nodes.insert(node); + self.adjacencies.insert(idx, HashMap::new()); + idx + } - #[inline] - fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { - Ok(self.get_node_unchecked(idx)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) - } + #[inline] + fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { + if self.nodes.contains_key(idx) { + unsafe { Ok(self.get_node_unchecked(idx)) } + } else { + Err(GraphError::NodeIdxDoesntExist(idx)) } + } - #[inline] - unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { - self.nodes.get_unchecked(idx) - } + #[inline] + unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { + self.nodes.get_unchecked(idx) + } - #[inline] - fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { - Ok(self.get_node_unchecked_mut(idx)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) - } + #[inline] + fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { + if self.nodes.contains_key(idx) { + unsafe { Ok(self.get_node_unchecked_mut(idx)) } + } else { + Err(GraphError::NodeIdxDoesntExist(idx)) } + } - #[inline] - unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { - self.nodes.get_unchecked_mut(idx) - } + #[inline] + unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { + self.nodes.get_unchecked_mut(idx) + } - #[inline] - fn has_node(&self, node: NodeIdx) -> bool { - self.nodes.contains_key(node) - } + #[inline] + fn has_node(&self, node: NodeIdx) -> bool { + self.nodes.contains_key(node) + } - #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { - match self.edges.get(edge) { - Some(e) => Ok(&e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)) - } + #[inline] + fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { + match self.edges.get(edge) { + Some(e) => Ok(&e.data), + None => Err(GraphError::EdgeIdxDoesntExist(edge)), } + } - #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { - match self.edges.get_mut(edge) { - Some(e) => Ok(&mut e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)) - } + #[inline] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { + match self.edges.get_mut(edge) { + Some(e) => Ok(&mut e.data), + None => Err(GraphError::EdgeIdxDoesntExist(edge)), } + } - fn remove_edge(&mut self, edge: EdgeIdx) -> Result { - if self.edges.contains_key(edge) { - unsafe { - Ok(self.remove_edge_unchecked(edge)) - } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } + fn remove_edge(&mut self, edge: EdgeIdx) -> Result { + if self.edges.contains_key(edge) { + unsafe { Ok(self.remove_edge_unchecked(edge)) } + } else { + Err(GraphError::EdgeIdxDoesntExist(edge)) } + } - #[inline] - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { - if let Some(from_edges) = self.adjacencies.get(from) { - if from_edges.contains_key(&to) { - unsafe { - Ok(self.edges_between_unchecked(from, to)) - } - } else { - Ok(vec![]) - } + #[inline] + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { + if let Some(from_edges) = self.adjacencies.get(from) { + if from_edges.contains_key(&to) { + unsafe { Ok(self.edges_between_unchecked(from, to)) } } else { - Err(GraphError::NodeIdxDoesntExist(from)) + Ok(vec![]) } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) } + } - #[inline] - unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { - self.adjacencies.get_unchecked(from).get(&to).cloned().unwrap() - } + #[inline] + unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { + self.adjacencies + .get_unchecked(from) + .get(&to) + .cloned() + .unwrap() + } - #[inline] - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - if let Some(map) = self.adjacencies.get(node) { - // TODO: can this be done with iterators? - let mut result = Vec::new(); - for (target, edges) in map { - for edge in edges { - result.push((*target, *edge)); - } + #[inline] + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + if let Some(map) = self.adjacencies.get(node) { + // TODO: can this be done with iterators? + let mut result = Vec::new(); + for (target, edges) in map { + for edge in edges { + result.push((*target, *edge)); } - result - } else { - Vec::new() } + result + } else { + Vec::new() } } - impl COMMON?undirected { - fn remove_node(&mut self, node: NodeIdx) -> Result { - for (_, edge) in self.edges_of(node) { + fn remove_node(&mut self, node: NodeIdx) -> Result { + if DIRECTED { + let mut edges = vec![]; + for (edge, data) in &self.edges { + let (src, dst) = data.indices(); + if dst == node || src == node { + edges.push(edge); + } + } + for edge in edges { unsafe { // SAFETY: we know it must exist self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? @@ -157,56 +158,11 @@ impl_graph! { self.adjacencies.remove(node).unwrap_unchecked(); } Ok(n) - }, - None => Err(GraphError::NodeIdxDoesntExist(node)) - } - } - - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> Result { - if self.has_node(node) { - if self.has_node(other) { - unsafe { - Ok(self.new_edge_unchecked(node, other, edge)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(other)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(node)) - } - } - - unsafe fn new_edge_unchecked(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: node, - dst: other, - data: edge, - }); - self.adjacencies.get_unchecked_mut(node).entry(other).or_default().push(idx); - self.adjacencies.get_unchecked_mut(other).entry(node).or_default().push(idx); - idx - } - - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { - let (node, other) = self.edges.get_unchecked(edge).indices(); - let adjas = self.adjacencies.get_unchecked_mut(node).get_mut(&other).unwrap(); - adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? - let adjas = self.adjacencies.get_unchecked_mut(other).get_mut(&node).unwrap(); - adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? - self.edges.remove(edge).unwrap().data - } - } - - impl COMMON?directed { - fn remove_node(&mut self, node: NodeIdx) -> Result { - let mut edges = vec![]; - for (edge, data) in &self.edges { - let (src, dst) = data.indices(); - if dst == node || src == node { - edges.push(edge); } + None => Err(GraphError::NodeIdxDoesntExist(node)), } - for edge in edges { + } else { + for (_, edge) in self.edges_of(node) { unsafe { // SAFETY: we know it must exist self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? @@ -219,17 +175,27 @@ impl_graph! { self.adjacencies.remove(node).unwrap_unchecked(); } Ok(n) - }, - None => Err(GraphError::NodeIdxDoesntExist(node)) + } + None => Err(GraphError::NodeIdxDoesntExist(node)), } } + } - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { + if DIRECTED { if self.has_node(from) { if self.has_node(to) { - unsafe { - Ok(self.new_edge_unchecked(from, to, edge)) - } + unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } + } else { + Err(GraphError::NodeIdxDoesntExist(to)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) + } + } else { + if self.has_node(from) { + if self.has_node(to) { + unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } } else { Err(GraphError::NodeIdxDoesntExist(to)) } @@ -237,20 +203,64 @@ impl_graph! { Err(GraphError::NodeIdxDoesntExist(from)) } } + } - unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + if DIRECTED { let idx = self.edges.insert(Edge { src: from, dst: to, data: edge, }); - self.adjacencies.get_unchecked_mut(from).entry(to).or_default().push(idx); + self.adjacencies + .get_unchecked_mut(from) + .entry(to) + .or_default() + .push(idx); + idx + } else { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); + self.adjacencies + .get_unchecked_mut(from) + .entry(to) + .or_default() + .push(idx); + self.adjacencies + .get_unchecked_mut(to) + .entry(from) + .or_default() + .push(idx); idx } + } - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + if DIRECTED { let (from, to) = self.edges.get_unchecked(edge).indices(); - let adjas = self.adjacencies.get_unchecked_mut(from).get_mut(&to).unwrap(); + let adjas = self + .adjacencies + .get_unchecked_mut(from) + .get_mut(&to) + .unwrap(); + adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? + self.edges.remove(edge).unwrap().data + } else { + let (node, other) = self.edges.get_unchecked(edge).indices(); + let adjas = self + .adjacencies + .get_unchecked_mut(node) + .get_mut(&other) + .unwrap(); + adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? + let adjas = self + .adjacencies + .get_unchecked_mut(other) + .get_mut(&node) + .unwrap(); adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? self.edges.remove(edge).unwrap().data } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 1ac262b94edf9..ea679cd64c112 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -5,9 +5,8 @@ use crate::{ graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, - SimpleGraph, + Graph, SimpleGraph, }, - impl_graph, }; /// Implementation of a `SimpleGraph` which uses `Vec<(NodeIdx, EdgeIdx)>` for adjacencies @@ -20,114 +19,113 @@ pub struct SimpleListGraph { adjacencies: SecondaryMap>, } -impl_graph! { - impl COMMON for SimpleListGraph { - fn new() -> Self { - Self { - nodes: HopSlotMap::with_key(), - edges: HopSlotMap::with_key(), - adjacencies: SecondaryMap::new(), - } +impl Graph for SimpleListGraph { + fn new() -> Self { + Self { + nodes: HopSlotMap::with_key(), + edges: HopSlotMap::with_key(), + adjacencies: SecondaryMap::new(), } + } - #[inline] - fn count(&self) -> usize { - self.nodes.len() - } + #[inline] + fn count(&self) -> usize { + self.nodes.len() + } - #[inline] - fn new_node(&mut self, node: N) -> NodeIdx { - let idx = self.nodes.insert(node); - self.adjacencies.insert(idx, Vec::new()); - idx - } + #[inline] + fn new_node(&mut self, node: N) -> NodeIdx { + let idx = self.nodes.insert(node); + self.adjacencies.insert(idx, Vec::new()); + idx + } - #[inline] - fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { - Ok(self.get_node_unchecked(idx)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) - } + #[inline] + fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { + if self.nodes.contains_key(idx) { + unsafe { Ok(self.get_node_unchecked(idx)) } + } else { + Err(GraphError::NodeIdxDoesntExist(idx)) } + } - #[inline] - unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { - self.nodes.get_unchecked(idx) - } + #[inline] + unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { + self.nodes.get_unchecked(idx) + } - #[inline] - fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { - Ok(self.get_node_unchecked_mut(idx)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) - } + #[inline] + fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { + if self.nodes.contains_key(idx) { + unsafe { Ok(self.get_node_unchecked_mut(idx)) } + } else { + Err(GraphError::NodeIdxDoesntExist(idx)) } + } - #[inline] - unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { - self.nodes.get_unchecked_mut(idx) - } + #[inline] + unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { + self.nodes.get_unchecked_mut(idx) + } - #[inline] - fn has_node(&self, node: NodeIdx) -> bool { - self.nodes.contains_key(node) - } + #[inline] + fn has_node(&self, node: NodeIdx) -> bool { + self.nodes.contains_key(node) + } - #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { - match self.edges.get(edge) { - Some(e) => Ok(&e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)) - } + #[inline] + fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { + match self.edges.get(edge) { + Some(e) => Ok(&e.data), + None => Err(GraphError::EdgeIdxDoesntExist(edge)), } + } - #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { - match self.edges.get_mut(edge) { - Some(e) => Ok(&mut e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)) - } + #[inline] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { + match self.edges.get_mut(edge) { + Some(e) => Ok(&mut e.data), + None => Err(GraphError::EdgeIdxDoesntExist(edge)), } + } - fn remove_edge(&mut self, edge: EdgeIdx) -> Result { - if self.edges.contains_key(edge) { - unsafe { - Ok(self.remove_edge_unchecked(edge)) - } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } + fn remove_edge(&mut self, edge: EdgeIdx) -> Result { + if self.edges.contains_key(edge) { + unsafe { Ok(self.remove_edge_unchecked(edge)) } + } else { + Err(GraphError::EdgeIdxDoesntExist(edge)) } + } - #[inline] - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { - match self.edge_between(from, to) { - Ok(Some(idx)) => Ok(vec![idx]), - Ok(None) => Ok(vec![]), - Err(e) => Err(e), - } + #[inline] + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { + match self.edge_between(from, to) { + Ok(Some(idx)) => Ok(vec![idx]), + Ok(None) => Ok(vec![]), + Err(e) => Err(e), } + } - #[inline] - unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { - vec![self.edge_between_unchecked(from, to)] - } + #[inline] + unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { + vec![self.edge_between_unchecked(from, to)] + } - #[inline] - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - self.adjacencies.get(node).unwrap().to_vec() - } + #[inline] + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + self.adjacencies.get(node).unwrap().to_vec() } - impl COMMON?undirected { - fn remove_node(&mut self, node: NodeIdx) -> Result { - for (_, edge) in self.edges_of(node) { + fn remove_node(&mut self, node: NodeIdx) -> Result { + if DIRECTED { + let mut edges = vec![]; + for (edge, data) in &self.edges { + let (src, dst) = data.indices(); + if dst == node || src == node { + edges.push(edge); + } + } + for edge in edges { unsafe { // SAFETY: we know it must exist self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? @@ -140,64 +138,11 @@ impl_graph! { self.adjacencies.remove(node).unwrap_unchecked(); } Ok(n) - }, - None => Err(GraphError::NodeIdxDoesntExist(node)) - } - } - - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> Result { - if node == other { - Err(GraphError::EdgeBetweenSameNode(node)) - } else if let Some(node_edges) = self.adjacencies.get(node) { - if node_edges.iter().any(|(n, _)| *n == other) { - Err(GraphError::EdgeBetweenAlreadyExists(node, other)) - } else if let Some(other_edges) = self.adjacencies.get(other) { - if other_edges.iter().any(|(n, _)| *n == node) { - Err(GraphError::EdgeBetweenAlreadyExists(other, node)) - } else { - unsafe { - Ok(self.new_edge_unchecked(node, other, edge)) - } - } - } else { - Err(GraphError::NodeIdxDoesntExist(other)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(node)) - } - } - - unsafe fn new_edge_unchecked(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: node, - dst: other, - data: edge, - }); - self.adjacencies.get_unchecked_mut(node).push((other, idx)); - self.adjacencies.get_unchecked_mut(other).push((node, idx)); - idx - } - - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { - let (node, other) = self.edges.get_unchecked(edge).indices(); - let list = self.adjacencies.get_unchecked_mut(node); - list.swap_remove(find_edge(list, other).unwrap()); // TODO: remove or swap_remove ? - let list = self.adjacencies.get_unchecked_mut(other); - list.swap_remove(find_edge(list, node).unwrap()); // TODO: remove or swap_remove ? - self.edges.remove(edge).unwrap().data - } - } - - impl COMMON?directed { - fn remove_node(&mut self, node: NodeIdx) -> Result { - let mut edges = vec![]; - for (edge, data) in &self.edges { - let (src, dst) = data.indices(); - if dst == node || src == node { - edges.push(edge); } + None => Err(GraphError::NodeIdxDoesntExist(node)), } - for edge in edges { + } else { + for (_, edge) in self.edges_of(node) { unsafe { // SAFETY: we know it must exist self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? @@ -210,20 +155,38 @@ impl_graph! { self.adjacencies.remove(node).unwrap_unchecked(); } Ok(n) - }, - None => Err(GraphError::NodeIdxDoesntExist(node)) + } + None => Err(GraphError::NodeIdxDoesntExist(node)), } } + } - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { + if DIRECTED { if from == to { Err(GraphError::EdgeBetweenSameNode(from)) } else if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.iter().any(|(n, _)| *n == to) { Err(GraphError::EdgeBetweenAlreadyExists(from, to)) } else if self.has_node(to) { - unsafe { - Ok(self.new_edge_unchecked(from, to, edge)) + unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } + } else { + Err(GraphError::NodeIdxDoesntExist(to)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) + } + } else { + if from == to { + Err(GraphError::EdgeBetweenSameNode(from)) + } else if let Some(node_edges) = self.adjacencies.get(from) { + if node_edges.iter().any(|(n, _)| *n == to) { + Err(GraphError::EdgeBetweenAlreadyExists(from, to)) + } else if let Some(other_edges) = self.adjacencies.get(to) { + if other_edges.iter().any(|(n, _)| *n == from) { + Err(GraphError::EdgeBetweenAlreadyExists(to, from)) + } else { + unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } } } else { Err(GraphError::NodeIdxDoesntExist(to)) @@ -232,8 +195,10 @@ impl_graph! { Err(GraphError::NodeIdxDoesntExist(from)) } } + } - unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + if DIRECTED { let idx = self.edges.insert(Edge { src: from, dst: to, @@ -241,40 +206,62 @@ impl_graph! { }); self.adjacencies.get_unchecked_mut(from).push((to, idx)); idx + } else { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); + self.adjacencies.get_unchecked_mut(from).push((to, idx)); + self.adjacencies.get_unchecked_mut(to).push((from, idx)); + idx } + } - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + if DIRECTED { let (from, to) = self.edges.get_unchecked(edge).indices(); let list = self.adjacencies.get_unchecked_mut(from); list.swap_remove(find_edge(list, to).unwrap()); // TODO: remove or swap_remove ? self.edges.remove(edge).unwrap().data + } else { + let (node, other) = self.edges.get_unchecked(edge).indices(); + let list = self.adjacencies.get_unchecked_mut(node); + list.swap_remove(find_edge(list, other).unwrap()); // TODO: remove or swap_remove ? + let list = self.adjacencies.get_unchecked_mut(other); + list.swap_remove(find_edge(list, node).unwrap()); // TODO: remove or swap_remove ? + self.edges.remove(edge).unwrap().data } } +} - impl SIMPLE { - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { - if self.adjacencies.contains_key(from) { - unsafe { - let idx = self.edge_between_unchecked(from, to); - if idx.is_null() { - Ok(None) - } else { - Ok(Some(idx)) - } +impl SimpleGraph for SimpleListGraph { + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { + if self.adjacencies.contains_key(from) { + unsafe { + let idx = self.edge_between_unchecked(from, to); + if idx.is_null() { + Ok(None) + } else { + Ok(Some(idx)) } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) } + } - unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - if let Some(idx) = self.adjacencies.get_unchecked(from).iter() - .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) // we know it simple graph can only have 1 edge so `find_map` is enough - { - idx - } else { - EdgeIdx::null() - } + unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + if let Some(idx) = self + .adjacencies + .get_unchecked(from) + .iter() + .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) + // we know it simple graph can only have 1 edge so `find_map` is enough + { + idx + } else { + EdgeIdx::null() } } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index f0fde3078f554..22f7f49099c3b 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -6,9 +6,8 @@ use crate::{ graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, - SimpleGraph, + Graph, SimpleGraph, }, - impl_graph, }; /// Implementation of a `SimpleGraph` which uses `HashMap` for adjacencies @@ -21,119 +20,118 @@ pub struct SimpleMapGraph { adjacencies: SecondaryMap>, } -impl_graph! { - impl COMMON for SimpleMapGraph { - fn new() -> Self { - Self { - nodes: HopSlotMap::with_key(), - edges: HopSlotMap::with_key(), - adjacencies: SecondaryMap::new(), - } +impl Graph for SimpleMapGraph { + fn new() -> Self { + Self { + nodes: HopSlotMap::with_key(), + edges: HopSlotMap::with_key(), + adjacencies: SecondaryMap::new(), } + } - #[inline] - fn count(&self) -> usize { - self.nodes.len() - } + #[inline] + fn count(&self) -> usize { + self.nodes.len() + } - #[inline] - fn new_node(&mut self, node: N) -> NodeIdx { - let idx = self.nodes.insert(node); - self.adjacencies.insert(idx, HashMap::new()); - idx - } + #[inline] + fn new_node(&mut self, node: N) -> NodeIdx { + let idx = self.nodes.insert(node); + self.adjacencies.insert(idx, HashMap::new()); + idx + } - #[inline] - fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { - Ok(self.get_node_unchecked(idx)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) - } + #[inline] + fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { + if self.nodes.contains_key(idx) { + unsafe { Ok(self.get_node_unchecked(idx)) } + } else { + Err(GraphError::NodeIdxDoesntExist(idx)) } + } - #[inline] - unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { - self.nodes.get_unchecked(idx) - } + #[inline] + unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { + self.nodes.get_unchecked(idx) + } - #[inline] - fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { - Ok(self.get_node_unchecked_mut(idx)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) - } + #[inline] + fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { + if self.nodes.contains_key(idx) { + unsafe { Ok(self.get_node_unchecked_mut(idx)) } + } else { + Err(GraphError::NodeIdxDoesntExist(idx)) } + } - #[inline] - unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { - self.nodes.get_unchecked_mut(idx) - } + #[inline] + unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { + self.nodes.get_unchecked_mut(idx) + } - #[inline] - fn has_node(&self, node: NodeIdx) -> bool { - self.nodes.contains_key(node) - } + #[inline] + fn has_node(&self, node: NodeIdx) -> bool { + self.nodes.contains_key(node) + } - #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { - match self.edges.get(edge) { - Some(e) => Ok(&e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)) - } + #[inline] + fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { + match self.edges.get(edge) { + Some(e) => Ok(&e.data), + None => Err(GraphError::EdgeIdxDoesntExist(edge)), } + } - #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { - match self.edges.get_mut(edge) { - Some(e) => Ok(&mut e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)) - } + #[inline] + fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { + match self.edges.get_mut(edge) { + Some(e) => Ok(&mut e.data), + None => Err(GraphError::EdgeIdxDoesntExist(edge)), } + } - fn remove_edge(&mut self, edge: EdgeIdx) -> Result { - if self.edges.contains_key(edge) { - unsafe { - Ok(self.remove_edge_unchecked(edge)) - } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } + fn remove_edge(&mut self, edge: EdgeIdx) -> Result { + if self.edges.contains_key(edge) { + unsafe { Ok(self.remove_edge_unchecked(edge)) } + } else { + Err(GraphError::EdgeIdxDoesntExist(edge)) } + } - #[inline] - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { - match self.edge_between(from, to) { - Ok(Some(idx)) => Ok(vec![idx]), - Ok(None) => Ok(vec![]), - Err(e) => Err(e) - } + #[inline] + fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { + match self.edge_between(from, to) { + Ok(Some(idx)) => Ok(vec![idx]), + Ok(None) => Ok(vec![]), + Err(e) => Err(e), } + } - #[inline] - unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { - vec![self.edge_between_unchecked(from, to)] - } + #[inline] + unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { + vec![self.edge_between_unchecked(from, to)] + } - #[inline] - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - self.adjacencies - .get(node) - .unwrap() - .iter() - .map(|(node, edge)| (*node, *edge)) - .collect() - } + #[inline] + fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { + self.adjacencies + .get(node) + .unwrap() + .iter() + .map(|(node, edge)| (*node, *edge)) + .collect() } - impl COMMON?undirected { - fn remove_node(&mut self, node: NodeIdx) -> Result { - for (_, edge) in self.edges_of(node) { + fn remove_node(&mut self, node: NodeIdx) -> Result { + if DIRECTED { + let mut edges = vec![]; + for (edge, data) in &self.edges { + let (src, dst) = data.indices(); + if dst == node || src == node { + edges.push(edge); + } + } + for edge in edges { unsafe { // SAFETY: we know it must exist self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? @@ -146,62 +144,11 @@ impl_graph! { self.adjacencies.remove(node).unwrap_unchecked(); } Ok(n) - }, - None => Err(GraphError::NodeIdxDoesntExist(node)) - } - } - - fn new_edge(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> Result { - if node == other { - Err(GraphError::EdgeBetweenSameNode(node)) - } else if let Some(node_edges) = self.adjacencies.get(node) { - if node_edges.contains_key(&other) { - Err(GraphError::EdgeBetweenAlreadyExists(node, other)) - } else if let Some(other_edges) = self.adjacencies.get(other) { - if other_edges.contains_key(&node) { - Err(GraphError::EdgeBetweenAlreadyExists(node, other)) - } else { - unsafe { - Ok(self.new_edge_unchecked(node, other, edge)) - } - } - } else { - Err(GraphError::NodeIdxDoesntExist(other)) } - } else { - Err(GraphError::NodeIdxDoesntExist(node)) + None => Err(GraphError::NodeIdxDoesntExist(node)), } - } - - unsafe fn new_edge_unchecked(&mut self, node: NodeIdx, other: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: node, - dst: other, - data: edge, - }); - self.adjacencies.get_unchecked_mut(node).insert_unique_unchecked(other, idx); - self.adjacencies.get_unchecked_mut(other).insert_unique_unchecked(node, idx); - idx - } - - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { - let (node, other) = self.edges.get_unchecked(edge).indices(); - self.adjacencies.get_unchecked_mut(node).remove(&other); - self.adjacencies.get_unchecked_mut(other).remove(&node); - self.edges.remove(edge).unwrap().data - } - } - - impl COMMON?directed { - fn remove_node(&mut self, node: NodeIdx) -> Result { - let mut edges = vec![]; - for (edge, data) in &self.edges { - let (src, dst) = data.indices(); - if dst == node || src == node { - edges.push(edge); - } - } - for edge in edges { + } else { + for (_, edge) in self.edges_of(node) { unsafe { // SAFETY: we know it must exist self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? @@ -214,20 +161,38 @@ impl_graph! { self.adjacencies.remove(node).unwrap_unchecked(); } Ok(n) - }, - None => Err(GraphError::NodeIdxDoesntExist(node)) + } + None => Err(GraphError::NodeIdxDoesntExist(node)), } } + } - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { + fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { + if DIRECTED { if from == to { Err(GraphError::EdgeBetweenSameNode(from)) } else if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.contains_key(&to) { Err(GraphError::EdgeBetweenAlreadyExists(from, to)) } else if self.has_node(to) { - unsafe { - Ok(self.new_edge_unchecked(from, to, edge)) + unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } + } else { + Err(GraphError::NodeIdxDoesntExist(to)) + } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) + } + } else { + if from == to { + Err(GraphError::EdgeBetweenSameNode(from)) + } else if let Some(node_edges) = self.adjacencies.get(from) { + if node_edges.contains_key(&to) { + Err(GraphError::EdgeBetweenAlreadyExists(from, to)) + } else if let Some(other_edges) = self.adjacencies.get(to) { + if other_edges.contains_key(&from) { + Err(GraphError::EdgeBetweenAlreadyExists(from, to)) + } else { + unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } } } else { Err(GraphError::NodeIdxDoesntExist(to)) @@ -236,42 +201,68 @@ impl_graph! { Err(GraphError::NodeIdxDoesntExist(from)) } } + } - unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + if DIRECTED { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); + self.adjacencies + .get_unchecked_mut(from) + .insert_unique_unchecked(to, idx); + idx + } else { let idx = self.edges.insert(Edge { src: from, dst: to, data: edge, }); - self.adjacencies.get_unchecked_mut(from).insert_unique_unchecked(to, idx); + self.adjacencies + .get_unchecked_mut(from) + .insert_unique_unchecked(to, idx); + self.adjacencies + .get_unchecked_mut(to) + .insert_unique_unchecked(from, idx); idx } + } - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { + if DIRECTED { let (from, to) = self.edges.get_unchecked(edge).indices(); self.adjacencies.get_unchecked_mut(from).remove(&to); self.edges.remove(edge).unwrap().data + } else { + let (node, other) = self.edges.get_unchecked(edge).indices(); + self.adjacencies.get_unchecked_mut(node).remove(&other); + self.adjacencies.get_unchecked_mut(other).remove(&node); + self.edges.remove(edge).unwrap().data } } +} - impl SIMPLE { - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { - if let Some(from_edges) = self.adjacencies.get(from) { - if from_edges.contains_key(&to) { - unsafe { - Ok(Some(self.edge_between_unchecked(from, to))) - } - } else { - Ok(None) - } +impl SimpleGraph for SimpleMapGraph { + fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { + if let Some(from_edges) = self.adjacencies.get(from) { + if from_edges.contains_key(&to) { + unsafe { Ok(Some(self.edge_between_unchecked(from, to))) } } else { - Err(GraphError::NodeIdxDoesntExist(from)) + Ok(None) } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) } + } - unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - self.adjacencies.get_unchecked(from).get(&to).cloned().unwrap() - } + unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { + self.adjacencies + .get_unchecked(from) + .get(&to) + .cloned() + .unwrap() } } From dd78eccfdd0dc4a620de41640331ce50a85ba7fe Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 20:06:13 +0100 Subject: [PATCH 106/183] clippy --- crates/bevy_graph/src/graphs/multi/list.rs | 22 ++++------------- crates/bevy_graph/src/graphs/multi/map.rs | 22 ++++------------- crates/bevy_graph/src/graphs/simple/list.rs | 26 ++++++++++----------- crates/bevy_graph/src/graphs/simple/map.rs | 24 +++++++++---------- 4 files changed, 33 insertions(+), 61 deletions(-) diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 57f83d0426abb..3206ae1c1d01f 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -172,26 +172,14 @@ impl Graph for MultiListGraph } fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { - if DIRECTED { - if self.has_node(from) { - if self.has_node(to) { - unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } - } else { - Err(GraphError::NodeIdxDoesntExist(to)) - } + if self.has_node(from) { + if self.has_node(to) { + unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } } else { - Err(GraphError::NodeIdxDoesntExist(from)) + Err(GraphError::NodeIdxDoesntExist(to)) } } else { - if self.has_node(from) { - if self.has_node(to) { - unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } - } else { - Err(GraphError::NodeIdxDoesntExist(to)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) - } + Err(GraphError::NodeIdxDoesntExist(from)) } } diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index f4c485f7c720d..16b91ee774b12 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -182,26 +182,14 @@ impl Graph for MultiMapGraph { } fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { - if DIRECTED { - if self.has_node(from) { - if self.has_node(to) { - unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } - } else { - Err(GraphError::NodeIdxDoesntExist(to)) - } + if self.has_node(from) { + if self.has_node(to) { + unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } } else { - Err(GraphError::NodeIdxDoesntExist(from)) + Err(GraphError::NodeIdxDoesntExist(to)) } } else { - if self.has_node(from) { - if self.has_node(to) { - unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } - } else { - Err(GraphError::NodeIdxDoesntExist(to)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) - } + Err(GraphError::NodeIdxDoesntExist(from)) } } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index ea679cd64c112..31f33557b5be7 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -176,24 +176,22 @@ impl Graph for SimpleListGraph } else { Err(GraphError::NodeIdxDoesntExist(from)) } - } else { - if from == to { - Err(GraphError::EdgeBetweenSameNode(from)) - } else if let Some(node_edges) = self.adjacencies.get(from) { - if node_edges.iter().any(|(n, _)| *n == to) { - Err(GraphError::EdgeBetweenAlreadyExists(from, to)) - } else if let Some(other_edges) = self.adjacencies.get(to) { - if other_edges.iter().any(|(n, _)| *n == from) { - Err(GraphError::EdgeBetweenAlreadyExists(to, from)) - } else { - unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } - } + } else if from == to { + Err(GraphError::EdgeBetweenSameNode(from)) + } else if let Some(node_edges) = self.adjacencies.get(from) { + if node_edges.iter().any(|(n, _)| *n == to) { + Err(GraphError::EdgeBetweenAlreadyExists(from, to)) + } else if let Some(other_edges) = self.adjacencies.get(to) { + if other_edges.iter().any(|(n, _)| *n == from) { + Err(GraphError::EdgeBetweenAlreadyExists(to, from)) } else { - Err(GraphError::NodeIdxDoesntExist(to)) + unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } } } else { - Err(GraphError::NodeIdxDoesntExist(from)) + Err(GraphError::NodeIdxDoesntExist(to)) } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 22f7f49099c3b..a5c64c364bd77 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -182,24 +182,22 @@ impl Graph for SimpleMapGraph } else { Err(GraphError::NodeIdxDoesntExist(from)) } - } else { - if from == to { - Err(GraphError::EdgeBetweenSameNode(from)) - } else if let Some(node_edges) = self.adjacencies.get(from) { - if node_edges.contains_key(&to) { + } else if from == to { + Err(GraphError::EdgeBetweenSameNode(from)) + } else if let Some(node_edges) = self.adjacencies.get(from) { + if node_edges.contains_key(&to) { + Err(GraphError::EdgeBetweenAlreadyExists(from, to)) + } else if let Some(other_edges) = self.adjacencies.get(to) { + if other_edges.contains_key(&from) { Err(GraphError::EdgeBetweenAlreadyExists(from, to)) - } else if let Some(other_edges) = self.adjacencies.get(to) { - if other_edges.contains_key(&from) { - Err(GraphError::EdgeBetweenAlreadyExists(from, to)) - } else { - unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } - } } else { - Err(GraphError::NodeIdxDoesntExist(to)) + unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } } } else { - Err(GraphError::NodeIdxDoesntExist(from)) + Err(GraphError::NodeIdxDoesntExist(to)) } + } else { + Err(GraphError::NodeIdxDoesntExist(from)) } } From 3d6fac57fe065ed6ba9bdd58468915402e3f437f Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 20:11:27 +0100 Subject: [PATCH 107/183] more cleanup --- crates/bevy_graph/src/graphs/multi/list.rs | 22 +++++---------- crates/bevy_graph/src/graphs/multi/map.rs | 21 +++++--------- crates/bevy_graph/src/graphs/simple/list.rs | 31 ++++++++------------- crates/bevy_graph/src/graphs/simple/map.rs | 31 ++++++++------------- 4 files changed, 36 insertions(+), 69 deletions(-) diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 3206ae1c1d01f..402406b7ae949 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -184,25 +184,19 @@ impl Graph for MultiListGraph } unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); if DIRECTED { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); let adjs = self.adjacencies.get_unchecked_mut(from); if let Some(list) = find_edge_list_mut(adjs, to) { list.push(idx); } else { adjs.push((to, vec![idx])); } - idx } else { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); let adjs = self.adjacencies.get_unchecked_mut(from); if let Some(list) = find_edge_list_mut(adjs, to) { list.push(idx); @@ -215,8 +209,8 @@ impl Graph for MultiListGraph } else { adjs.push((from, vec![idx])); } - idx } + idx } unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { @@ -225,7 +219,6 @@ impl Graph for MultiListGraph let list = self.adjacencies.get_unchecked_mut(from); let list = find_edge_list_mut(list, to).unwrap(); list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? - self.edges.remove(edge).unwrap().data } else { let (from, to) = self.edges.get_unchecked(edge).indices(); @@ -236,9 +229,8 @@ impl Graph for MultiListGraph let list = self.adjacencies.get_unchecked_mut(to); let list = find_edge_list_mut(list, from).unwrap(); list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? - - self.edges.remove(edge).unwrap().data } + self.edges.remove(edge).unwrap().data } } diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 16b91ee774b12..3a2167efbadff 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -194,24 +194,18 @@ impl Graph for MultiMapGraph { } unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); if DIRECTED { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); self.adjacencies .get_unchecked_mut(from) .entry(to) .or_default() .push(idx); - idx } else { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); self.adjacencies .get_unchecked_mut(from) .entry(to) @@ -222,8 +216,8 @@ impl Graph for MultiMapGraph { .entry(from) .or_default() .push(idx); - idx } + idx } unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { @@ -235,7 +229,6 @@ impl Graph for MultiMapGraph { .get_mut(&to) .unwrap(); adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? - self.edges.remove(edge).unwrap().data } else { let (node, other) = self.edges.get_unchecked(edge).indices(); let adjas = self @@ -250,8 +243,8 @@ impl Graph for MultiMapGraph { .get_mut(&node) .unwrap(); adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? - self.edges.remove(edge).unwrap().data } + self.edges.remove(edge).unwrap().data } } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 31f33557b5be7..6cefa180f998c 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -162,10 +162,10 @@ impl Graph for SimpleListGraph } fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { - if DIRECTED { - if from == to { - Err(GraphError::EdgeBetweenSameNode(from)) - } else if let Some(from_edges) = self.adjacencies.get(from) { + if from == to { + Err(GraphError::EdgeBetweenSameNode(from)) + } else if DIRECTED { + if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.iter().any(|(n, _)| *n == to) { Err(GraphError::EdgeBetweenAlreadyExists(from, to)) } else if self.has_node(to) { @@ -176,8 +176,6 @@ impl Graph for SimpleListGraph } else { Err(GraphError::NodeIdxDoesntExist(from)) } - } else if from == to { - Err(GraphError::EdgeBetweenSameNode(from)) } else if let Some(node_edges) = self.adjacencies.get(from) { if node_edges.iter().any(|(n, _)| *n == to) { Err(GraphError::EdgeBetweenAlreadyExists(from, to)) @@ -196,24 +194,18 @@ impl Graph for SimpleListGraph } unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); if DIRECTED { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); self.adjacencies.get_unchecked_mut(from).push((to, idx)); - idx } else { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); self.adjacencies.get_unchecked_mut(from).push((to, idx)); self.adjacencies.get_unchecked_mut(to).push((from, idx)); - idx } + idx } unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { @@ -221,15 +213,14 @@ impl Graph for SimpleListGraph let (from, to) = self.edges.get_unchecked(edge).indices(); let list = self.adjacencies.get_unchecked_mut(from); list.swap_remove(find_edge(list, to).unwrap()); // TODO: remove or swap_remove ? - self.edges.remove(edge).unwrap().data } else { let (node, other) = self.edges.get_unchecked(edge).indices(); let list = self.adjacencies.get_unchecked_mut(node); list.swap_remove(find_edge(list, other).unwrap()); // TODO: remove or swap_remove ? let list = self.adjacencies.get_unchecked_mut(other); list.swap_remove(find_edge(list, node).unwrap()); // TODO: remove or swap_remove ? - self.edges.remove(edge).unwrap().data } + self.edges.remove(edge).unwrap().data } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index a5c64c364bd77..ae6eaee2cd232 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -168,10 +168,10 @@ impl Graph for SimpleMapGraph } fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { - if DIRECTED { - if from == to { - Err(GraphError::EdgeBetweenSameNode(from)) - } else if let Some(from_edges) = self.adjacencies.get(from) { + if from == to { + Err(GraphError::EdgeBetweenSameNode(from)) + } else if DIRECTED { + if let Some(from_edges) = self.adjacencies.get(from) { if from_edges.contains_key(&to) { Err(GraphError::EdgeBetweenAlreadyExists(from, to)) } else if self.has_node(to) { @@ -182,8 +182,6 @@ impl Graph for SimpleMapGraph } else { Err(GraphError::NodeIdxDoesntExist(from)) } - } else if from == to { - Err(GraphError::EdgeBetweenSameNode(from)) } else if let Some(node_edges) = self.adjacencies.get(from) { if node_edges.contains_key(&to) { Err(GraphError::EdgeBetweenAlreadyExists(from, to)) @@ -202,43 +200,36 @@ impl Graph for SimpleMapGraph } unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { + src: from, + dst: to, + data: edge, + }); if DIRECTED { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); self.adjacencies .get_unchecked_mut(from) .insert_unique_unchecked(to, idx); - idx } else { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); self.adjacencies .get_unchecked_mut(from) .insert_unique_unchecked(to, idx); self.adjacencies .get_unchecked_mut(to) .insert_unique_unchecked(from, idx); - idx } + idx } unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { if DIRECTED { let (from, to) = self.edges.get_unchecked(edge).indices(); self.adjacencies.get_unchecked_mut(from).remove(&to); - self.edges.remove(edge).unwrap().data } else { let (node, other) = self.edges.get_unchecked(edge).indices(); self.adjacencies.get_unchecked_mut(node).remove(&other); self.adjacencies.get_unchecked_mut(other).remove(&node); - self.edges.remove(edge).unwrap().data } + self.edges.remove(edge).unwrap().data } } From 2c75cdf7f7febc058c17eefe9092e255364bbe8c Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 16 Jan 2023 20:14:54 +0100 Subject: [PATCH 108/183] add some more counting functions --- crates/bevy_graph/src/algos/bfs.rs | 2 +- crates/bevy_graph/src/algos/dfs.rs | 2 +- crates/bevy_graph/src/graphs/mod.rs | 17 +++++++++++++++-- crates/bevy_graph/src/graphs/multi/list.rs | 17 ++++++++++++++++- crates/bevy_graph/src/graphs/multi/map.rs | 17 ++++++++++++++++- crates/bevy_graph/src/graphs/simple/list.rs | 17 ++++++++++++++++- crates/bevy_graph/src/graphs/simple/map.rs | 17 ++++++++++++++++- 7 files changed, 81 insertions(+), 8 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 5a8ee7bc23084..129087700c11b 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -145,7 +145,7 @@ mod test { let mut counted_elements = Vec::with_capacity(4); - let mut bfs = BreadthFirstSearch::with_capacity(zero, graph.count()); + let mut bfs = BreadthFirstSearch::with_capacity(zero, graph.node_count()); while let Some(node) = bfs.next(&graph) { counted_elements.push(*node); } diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index f5b82cf93719c..4cf3c22903e8a 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -142,7 +142,7 @@ mod test { let mut counted_elements = Vec::with_capacity(4); - let mut dfs = DepthFirstSearch::with_capacity(zero, graph.count()); + let mut dfs = DepthFirstSearch::with_capacity(zero, graph.node_count()); while let Some(node) = dfs.next(&graph) { counted_elements.push(*node); } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 3c104db11f273..5ef90a0dc9054 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -23,9 +23,22 @@ pub trait Graph { where Self: Sized; - /// Returns the count of nodes in this graph - fn count(&self) -> usize; + /// Returns `true` if the edges in the graph are directed. + fn is_directed(&self) -> bool; + /// Returns `true` if the edges in the graph are undirected. + fn is_undirected(&self) -> bool; + + /// Returns the number of nodes in the graph. + fn node_count(&self) -> usize; + + /// Returns the number of edges in the graph. + fn edge_count(&self) -> usize; + + /// Returns `true` if the graph has no nodes. + fn is_empty(&self) -> bool { + self.node_count() == 0 + } //////////////////////////// // Nodes //////////////////////////// diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 402406b7ae949..b960489a253d3 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -29,10 +29,25 @@ impl Graph for MultiListGraph } #[inline] - fn count(&self) -> usize { + fn is_directed(&self) -> bool { + DIRECTED + } + + #[inline] + fn is_undirected(&self) -> bool { + !DIRECTED + } + + #[inline] + fn node_count(&self) -> usize { self.nodes.len() } + #[inline] + fn edge_count(&self) -> usize { + self.edges.len() + } + #[inline] fn new_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 3a2167efbadff..48fd12293272f 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -30,10 +30,25 @@ impl Graph for MultiMapGraph { } #[inline] - fn count(&self) -> usize { + fn is_directed(&self) -> bool { + DIRECTED + } + + #[inline] + fn is_undirected(&self) -> bool { + !DIRECTED + } + + #[inline] + fn node_count(&self) -> usize { self.nodes.len() } + #[inline] + fn edge_count(&self) -> usize { + self.edges.len() + } + #[inline] fn new_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 6cefa180f998c..7d717e03d81d6 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -29,10 +29,25 @@ impl Graph for SimpleListGraph } #[inline] - fn count(&self) -> usize { + fn is_directed(&self) -> bool { + DIRECTED + } + + #[inline] + fn is_undirected(&self) -> bool { + !DIRECTED + } + + #[inline] + fn node_count(&self) -> usize { self.nodes.len() } + #[inline] + fn edge_count(&self) -> usize { + self.edges.len() + } + #[inline] fn new_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index ae6eaee2cd232..6f71569e79757 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -30,10 +30,25 @@ impl Graph for SimpleMapGraph } #[inline] - fn count(&self) -> usize { + fn is_directed(&self) -> bool { + DIRECTED + } + + #[inline] + fn is_undirected(&self) -> bool { + !DIRECTED + } + + #[inline] + fn node_count(&self) -> usize { self.nodes.len() } + #[inline] + fn edge_count(&self) -> usize { + self.edges.len() + } + #[inline] fn new_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); From f57620bf345963ea7d9175191a2cfb56b7b8bbd8 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 17 Jan 2023 14:55:44 +0100 Subject: [PATCH 109/183] changes --- benches/benches/bevy_graph/bfs_and_dfs.rs | 4 ++-- crates/bevy_graph/src/algos/bfs.rs | 6 +++--- crates/bevy_graph/src/algos/dfs.rs | 6 +++--- crates/bevy_graph/src/graphs/mod.rs | 4 ++-- crates/bevy_graph/src/graphs/multi/list.rs | 5 ++--- crates/bevy_graph/src/graphs/multi/map.rs | 4 ++-- crates/bevy_graph/src/graphs/simple/list.rs | 4 ++-- crates/bevy_graph/src/graphs/simple/map.rs | 4 ++-- 8 files changed, 18 insertions(+), 19 deletions(-) diff --git a/benches/benches/bevy_graph/bfs_and_dfs.rs b/benches/benches/bevy_graph/bfs_and_dfs.rs index 701a7d56b3a88..1cfda0031d3c5 100644 --- a/benches/benches/bevy_graph/bfs_and_dfs.rs +++ b/benches/benches/bevy_graph/bfs_and_dfs.rs @@ -39,7 +39,7 @@ fn algo_10_000(c: &mut Criterion) { c.bench_function("bfs_10_000", |b| { b.iter(|| { - let mut bfs = BreadthFirstSearch::with_capacity(first, graph.count()); + let mut bfs = BreadthFirstSearch::with_capacity(first, graph.node_count()); while let Some(node) = bfs.next(&graph) { let _ = black_box(node); } @@ -48,7 +48,7 @@ fn algo_10_000(c: &mut Criterion) { c.bench_function("dfs_10_000", |b| { b.iter(|| { - let mut dfs = DepthFirstSearch::with_capacity(first, graph.count()); + let mut dfs = DepthFirstSearch::with_capacity(first, graph.node_count()); while let Some(node) = dfs.next(&graph) { let _ = black_box(node); } diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 129087700c11b..510e60d23bac7 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -26,9 +26,9 @@ impl BreadthFirstSearch { } /// Creates a new `BreadthFirstSearch` with a start node and the count of nodes for capacity reserving - pub fn with_capacity(start: NodeIdx, count: usize) -> Self { - let mut queue = VecDeque::with_capacity(count); - let mut visited = HashSet::with_capacity(count); + pub fn with_capacity(start: NodeIdx, node_count: usize) -> Self { + let mut queue = VecDeque::with_capacity(node_count); + let mut visited = HashSet::with_capacity(node_count); visited.insert(start); queue.push_back(start); diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 4cf3c22903e8a..15bd48676c3b3 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -23,9 +23,9 @@ impl DepthFirstSearch { } /// Creates a new `DepthFirstSearch` with a start node and the count of nodes for capacity reserving - pub fn with_capacity(start: NodeIdx, count: usize) -> Self { - let mut stack = Vec::with_capacity(count); - let mut visited = HashSet::with_capacity(count); + pub fn with_capacity(start: NodeIdx, node_count: usize) -> Self { + let mut stack = Vec::with_capacity(node_count); + let mut visited = HashSet::with_capacity(node_count); visited.insert(start); stack.push(start); diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 5ef90a0dc9054..03f54dd06e317 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -26,8 +26,8 @@ pub trait Graph { /// Returns `true` if the edges in the graph are directed. fn is_directed(&self) -> bool; - /// Returns `true` if the edges in the graph are undirected. - fn is_undirected(&self) -> bool; + /// Returns `true` if the graph allows for more than one edge between a pair of nodes. + fn is_multigraph(&self) -> bool; /// Returns the number of nodes in the graph. fn node_count(&self) -> usize; diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index b960489a253d3..bbc6d951b397c 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -34,10 +34,9 @@ impl Graph for MultiListGraph } #[inline] - fn is_undirected(&self) -> bool { - !DIRECTED + fn is_multigraph(&self) -> bool { + true } - #[inline] fn node_count(&self) -> usize { self.nodes.len() diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 48fd12293272f..2d9b9ffc5b91f 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -35,8 +35,8 @@ impl Graph for MultiMapGraph { } #[inline] - fn is_undirected(&self) -> bool { - !DIRECTED + fn is_multigraph(&self) -> bool { + true } #[inline] diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 7d717e03d81d6..a124c797af85f 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -34,8 +34,8 @@ impl Graph for SimpleListGraph } #[inline] - fn is_undirected(&self) -> bool { - !DIRECTED + fn is_multigraph(&self) -> bool { + false } #[inline] diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 6f71569e79757..9f9d92b97aa2d 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -35,8 +35,8 @@ impl Graph for SimpleMapGraph } #[inline] - fn is_undirected(&self) -> bool { - !DIRECTED + fn is_multigraph(&self) -> bool { + false } #[inline] From 8531841e0b13e58ce66311fb21d6430904146872 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 17 Jan 2023 15:02:30 +0100 Subject: [PATCH 110/183] `add_node` --- benches/benches/bevy_graph/bfs_and_dfs.rs | 4 +-- benches/benches/bevy_graph/map.rs | 2 +- crates/bevy_graph/src/algos/bfs.rs | 8 ++--- crates/bevy_graph/src/algos/dfs.rs | 8 ++--- crates/bevy_graph/src/graphs/mod.rs | 7 ++--- crates/bevy_graph/src/graphs/multi/list.rs | 2 +- crates/bevy_graph/src/graphs/multi/map.rs | 2 +- crates/bevy_graph/src/graphs/multi/mod.rs | 34 ++++++++++----------- crates/bevy_graph/src/graphs/simple/list.rs | 2 +- crates/bevy_graph/src/graphs/simple/map.rs | 2 +- crates/bevy_graph/src/graphs/simple/mod.rs | 34 ++++++++++----------- 11 files changed, 51 insertions(+), 54 deletions(-) diff --git a/benches/benches/bevy_graph/bfs_and_dfs.rs b/benches/benches/bevy_graph/bfs_and_dfs.rs index 1cfda0031d3c5..8d06e12cf3c33 100644 --- a/benches/benches/bevy_graph/bfs_and_dfs.rs +++ b/benches/benches/bevy_graph/bfs_and_dfs.rs @@ -20,9 +20,9 @@ criterion_group! { fn algo_10_000(c: &mut Criterion) { let mut graph = SimpleMapGraph::::new(); let mut nodes = Vec::with_capacity(10_000); - let first = graph.new_node(0); + let first = graph.add_node(0); for i in 1..10_000 { - nodes.push(graph.new_node(i)); + nodes.push(graph.add_node(i)); } let mut shuffled = nodes.clone(); shuffled.shuffle(&mut rand::thread_rng()); diff --git a/benches/benches/bevy_graph/map.rs b/benches/benches/bevy_graph/map.rs index ee5f09172c4a9..2bceadb9852f5 100644 --- a/benches/benches/bevy_graph/map.rs +++ b/benches/benches/bevy_graph/map.rs @@ -24,7 +24,7 @@ fn nodes_10_000_undirected(c: &mut Criterion) { let mut nodes: Vec = Vec::with_capacity(10_000); for i in 1..=10_000 { - nodes.push(graph.new_node(i)); + nodes.push(graph.add_node(i)); } let mut edges: Vec = Vec::with_capacity(10_000 - 1); diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 510e60d23bac7..91ae90ea30c8e 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -130,10 +130,10 @@ mod test { fn basic_imperative_bfs() { let mut graph = SimpleMapGraph::::new(); - let zero = graph.new_node(0); - let one = graph.new_node(1); - let two = graph.new_node(2); - let three = graph.new_node(3); + let zero = graph.add_node(0); + let one = graph.add_node(1); + let two = graph.add_node(2); + let three = graph.add_node(3); graph.new_edge(zero, one, ()).unwrap(); graph.new_edge(zero, two, ()).unwrap(); diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 15bd48676c3b3..127950c245704 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -127,10 +127,10 @@ mod test { fn basic_imperative_dfs() { let mut graph = SimpleMapGraph::::new(); - let zero = graph.new_node(0); - let one = graph.new_node(1); - let two = graph.new_node(2); - let three = graph.new_node(3); + let zero = graph.add_node(0); + let one = graph.add_node(1); + let two = graph.add_node(2); + let three = graph.add_node(3); graph.new_edge(zero, one, ()).unwrap(); graph.new_edge(zero, two, ()).unwrap(); diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 03f54dd06e317..61f15b04d2922 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -39,12 +39,9 @@ pub trait Graph { fn is_empty(&self) -> bool { self.node_count() == 0 } - //////////////////////////// - // Nodes - //////////////////////////// - /// Creates a new node with the given value in the graph and returns its `NodeIdx` - fn new_node(&mut self, node: N) -> NodeIdx; + /// Adds a node with the associated `value` and returns its [`NodeIdx`]. + fn add_node(&mut self, value: N) -> NodeIdx; /// Returns a reference to the value of a given node fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError>; diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index bbc6d951b397c..66deea8a8704f 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -48,7 +48,7 @@ impl Graph for MultiListGraph } #[inline] - fn new_node(&mut self, node: N) -> NodeIdx { + fn add_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, Vec::new()); idx diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 2d9b9ffc5b91f..fa2b181a3e4c5 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -50,7 +50,7 @@ impl Graph for MultiMapGraph { } #[inline] - fn new_node(&mut self, node: N) -> NodeIdx { + fn add_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, HashMap::new()); idx diff --git a/crates/bevy_graph/src/graphs/multi/mod.rs b/crates/bevy_graph/src/graphs/multi/mod.rs index 1b193c2a6afb8..43c3592b04f1f 100644 --- a/crates/bevy_graph/src/graphs/multi/mod.rs +++ b/crates/bevy_graph/src/graphs/multi/mod.rs @@ -55,10 +55,10 @@ mod test { } pub fn nodes(mut graph: impl Graph) { - let jake = graph.new_node(Person::Jake); - let michael = graph.new_node(Person::Michael); - let jennifer = graph.new_node(Person::Jennifer); - let other_jake = graph.new_node(Person::Jake); + let jake = graph.add_node(Person::Jake); + let michael = graph.add_node(Person::Michael); + let jennifer = graph.add_node(Person::Jennifer); + let other_jake = graph.add_node(Person::Jake); assert_eq!(graph.get_node(jake).unwrap(), &Person::Jake); assert_eq!(graph.get_node(michael).unwrap(), &Person::Michael); @@ -87,10 +87,10 @@ mod test { } pub fn undirected_edges(mut graph: impl Graph) { - let jake = graph.new_node(Person::Jake); - let michael = graph.new_node(Person::Michael); - let jennifer = graph.new_node(Person::Jennifer); - let other_jake = graph.new_node(Person::Jake); + let jake = graph.add_node(Person::Jake); + let michael = graph.add_node(Person::Michael); + let jennifer = graph.add_node(Person::Jennifer); + let other_jake = graph.add_node(Person::Jake); let jm = graph.new_edge(jake, michael, 2).unwrap(); let jm2 = graph.new_edge(jake, michael, 20).unwrap(); @@ -145,10 +145,10 @@ mod test { } pub fn directed_edges(mut graph: impl Graph) { - let jake = graph.new_node(Person::Jake); - let michael = graph.new_node(Person::Michael); - let jennifer = graph.new_node(Person::Jennifer); - let other_jake = graph.new_node(Person::Jake); + let jake = graph.add_node(Person::Jake); + let michael = graph.add_node(Person::Michael); + let jennifer = graph.add_node(Person::Jennifer); + let other_jake = graph.add_node(Person::Jake); let jm = graph.new_edge(jake, michael, 2).unwrap(); let jm2 = graph.new_edge(jake, michael, 20).unwrap(); @@ -196,8 +196,8 @@ mod test { } pub fn remove_node_undirected(mut graph: impl Graph) { - let jake = graph.new_node(Person::Jake); - let michael = graph.new_node(Person::Michael); + let jake = graph.add_node(Person::Jake); + let michael = graph.add_node(Person::Michael); let edge = graph.new_edge(jake, michael, 20).unwrap(); @@ -227,8 +227,8 @@ mod test { } pub fn remove_node_directed(mut graph: impl Graph) { - let jake = graph.new_node(Person::Jake); - let michael = graph.new_node(Person::Michael); + let jake = graph.add_node(Person::Jake); + let michael = graph.add_node(Person::Michael); let edge = graph.new_edge(jake, michael, 20).unwrap(); @@ -253,7 +253,7 @@ mod test { } pub fn edge_between_same_node(mut graph: impl Graph) { - let jake = graph.new_node(Person::Jake); + let jake = graph.add_node(Person::Jake); assert!(graph.new_edge(jake, jake, 20).is_ok()); } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index a124c797af85f..1c570a4c41997 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -49,7 +49,7 @@ impl Graph for SimpleListGraph } #[inline] - fn new_node(&mut self, node: N) -> NodeIdx { + fn add_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, Vec::new()); idx diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 9f9d92b97aa2d..84cd8f185a939 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -50,7 +50,7 @@ impl Graph for SimpleMapGraph } #[inline] - fn new_node(&mut self, node: N) -> NodeIdx { + fn add_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, HashMap::new()); idx diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index eff59cf494f64..d54d6784bdcda 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -55,10 +55,10 @@ mod test { } pub fn nodes(mut graph: impl SimpleGraph) { - let jake = graph.new_node(Person::Jake); - let michael = graph.new_node(Person::Michael); - let jennifer = graph.new_node(Person::Jennifer); - let other_jake = graph.new_node(Person::Jake); + let jake = graph.add_node(Person::Jake); + let michael = graph.add_node(Person::Michael); + let jennifer = graph.add_node(Person::Jennifer); + let other_jake = graph.add_node(Person::Jake); assert_eq!(graph.get_node(jake).unwrap(), &Person::Jake); assert_eq!(graph.get_node(michael).unwrap(), &Person::Michael); @@ -87,10 +87,10 @@ mod test { } pub fn undirected_edges(mut graph: impl SimpleGraph) { - let jake = graph.new_node(Person::Jake); - let michael = graph.new_node(Person::Michael); - let jennifer = graph.new_node(Person::Jennifer); - let other_jake = graph.new_node(Person::Jake); + let jake = graph.add_node(Person::Jake); + let michael = graph.add_node(Person::Michael); + let jennifer = graph.add_node(Person::Jennifer); + let other_jake = graph.add_node(Person::Jake); let jm = graph.new_edge(jake, michael, 2).unwrap(); let jj = graph.new_edge(jennifer, jake, 7).unwrap(); @@ -131,10 +131,10 @@ mod test { } pub fn directed_edges(mut graph: impl SimpleGraph) { - let jake = graph.new_node(Person::Jake); - let michael = graph.new_node(Person::Michael); - let jennifer = graph.new_node(Person::Jennifer); - let other_jake = graph.new_node(Person::Jake); + let jake = graph.add_node(Person::Jake); + let michael = graph.add_node(Person::Michael); + let jennifer = graph.add_node(Person::Jennifer); + let other_jake = graph.add_node(Person::Jake); let jm = graph.new_edge(jake, michael, 2).unwrap(); let jj = graph.new_edge(jennifer, jake, 7).unwrap(); @@ -173,8 +173,8 @@ mod test { } pub fn remove_node_undirected(mut graph: impl SimpleGraph) { - let jake = graph.new_node(Person::Jake); - let michael = graph.new_node(Person::Michael); + let jake = graph.add_node(Person::Jake); + let michael = graph.add_node(Person::Michael); let edge = graph.new_edge(jake, michael, 20).unwrap(); @@ -210,8 +210,8 @@ mod test { } pub fn remove_node_directed(mut graph: impl SimpleGraph) { - let jake = graph.new_node(Person::Jake); - let michael = graph.new_node(Person::Michael); + let jake = graph.add_node(Person::Jake); + let michael = graph.add_node(Person::Michael); let edge = graph.new_edge(jake, michael, 20).unwrap(); @@ -239,7 +239,7 @@ mod test { } pub fn edge_between_same_node(mut graph: impl SimpleGraph) { - let jake = graph.new_node(Person::Jake); + let jake = graph.add_node(Person::Jake); assert!(matches!( graph.new_edge(jake, jake, 20), From 498c0f61b9346bce627cae963ab16f5f718d3d5c Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 17 Jan 2023 16:14:38 +0100 Subject: [PATCH 111/183] Remove all old code and implement `new_edge` --- benches/Cargo.toml | 10 - benches/benches/bevy_graph/bfs_and_dfs.rs | 57 ----- benches/benches/bevy_graph/map.rs | 51 ---- crates/bevy_graph/src/algos/bfs.rs | 12 +- crates/bevy_graph/src/algos/dfs.rs | 12 +- crates/bevy_graph/src/error.rs | 24 +- crates/bevy_graph/src/graphs/edge.rs | 4 +- crates/bevy_graph/src/graphs/keys.rs | 24 -- crates/bevy_graph/src/graphs/mod.rs | 112 ++------- crates/bevy_graph/src/graphs/multi/list.rs | 231 ++--------------- crates/bevy_graph/src/graphs/multi/map.rs | 220 ++-------------- crates/bevy_graph/src/graphs/multi/mod.rs | 265 -------------------- crates/bevy_graph/src/graphs/simple/list.rs | 238 ++---------------- crates/bevy_graph/src/graphs/simple/map.rs | 227 ++--------------- crates/bevy_graph/src/graphs/simple/mod.rs | 254 ------------------- crates/bevy_graph/src/lib.rs | 2 + crates/bevy_graph/src/utils/mod.rs | 2 + crates/bevy_graph/src/utils/vecmap.rs | 87 +++++++ 18 files changed, 213 insertions(+), 1619 deletions(-) delete mode 100644 benches/benches/bevy_graph/bfs_and_dfs.rs delete mode 100644 benches/benches/bevy_graph/map.rs create mode 100644 crates/bevy_graph/src/utils/mod.rs create mode 100644 crates/bevy_graph/src/utils/vecmap.rs diff --git a/benches/Cargo.toml b/benches/Cargo.toml index 3aa830d33bc40..c6ac8b8d9a48c 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -32,16 +32,6 @@ name = "ecs" path = "benches/bevy_ecs/benches.rs" harness = false -[[bench]] -name = "bfs_and_dfs_graph" -path = "benches/bevy_graph/bfs_and_dfs.rs" -harness = false - -[[bench]] -name = "map_graph" -path = "benches/bevy_graph/map.rs" -harness = false - [[bench]] name = "reflect_list" path = "benches/bevy_reflect/list.rs" diff --git a/benches/benches/bevy_graph/bfs_and_dfs.rs b/benches/benches/bevy_graph/bfs_and_dfs.rs deleted file mode 100644 index 8d06e12cf3c33..0000000000000 --- a/benches/benches/bevy_graph/bfs_and_dfs.rs +++ /dev/null @@ -1,57 +0,0 @@ -use bevy_graph::{ - algos::{bfs::BreadthFirstSearch, dfs::DepthFirstSearch}, - graphs::{keys::NodeIdx, simple::SimpleMapGraph, Graph}, -}; -use bevy_utils::Duration; -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use rand::seq::SliceRandom; - -criterion_main!(benches); - -const WARM_UP_TIME: Duration = Duration::from_millis(500); - -criterion_group! { - name = benches; - config = Criterion::default().warm_up_time(WARM_UP_TIME); - targets = algo_10_000 -} - -// TODO: find a better way for fix with multiple iterations over same graph -fn algo_10_000(c: &mut Criterion) { - let mut graph = SimpleMapGraph::::new(); - let mut nodes = Vec::with_capacity(10_000); - let first = graph.add_node(0); - for i in 1..10_000 { - nodes.push(graph.add_node(i)); - } - let mut shuffled = nodes.clone(); - shuffled.shuffle(&mut rand::thread_rng()); - for (i, node) in shuffled - .iter() - .cloned() - .collect::>() - .windows(2) - .enumerate() - { - let _ = graph.new_edge(node[0], node[1], ()).unwrap(); - let _ = black_box(graph.new_edge(node[0], nodes[i], ())); - } - - c.bench_function("bfs_10_000", |b| { - b.iter(|| { - let mut bfs = BreadthFirstSearch::with_capacity(first, graph.node_count()); - while let Some(node) = bfs.next(&graph) { - let _ = black_box(node); - } - }) - }); - - c.bench_function("dfs_10_000", |b| { - b.iter(|| { - let mut dfs = DepthFirstSearch::with_capacity(first, graph.node_count()); - while let Some(node) = dfs.next(&graph) { - let _ = black_box(node); - } - }) - }); -} diff --git a/benches/benches/bevy_graph/map.rs b/benches/benches/bevy_graph/map.rs deleted file mode 100644 index 2bceadb9852f5..0000000000000 --- a/benches/benches/bevy_graph/map.rs +++ /dev/null @@ -1,51 +0,0 @@ -use bevy_graph::graphs::{ - keys::{EdgeIdx, NodeIdx}, - simple::SimpleMapGraph, - Graph, SimpleGraph, -}; -use bevy_utils::Duration; -use criterion::{black_box, criterion_group, criterion_main, Criterion}; - -criterion_main!(benches); - -const WARM_UP_TIME: Duration = Duration::from_millis(3000); - -criterion_group! { - name = benches; - config = Criterion::default().warm_up_time(WARM_UP_TIME); - targets = nodes_10_000_undirected -} - -// TODO: find a better way for fix with multiple iterations over same graph -fn nodes_10_000_undirected(c: &mut Criterion) { - c.bench_function("nodes_10_000", |b| { - b.iter(|| { - let mut graph = SimpleMapGraph::::new(); - - let mut nodes: Vec = Vec::with_capacity(10_000); - for i in 1..=10_000 { - nodes.push(graph.add_node(i)); - } - - let mut edges: Vec = Vec::with_capacity(10_000 - 1); - for i in 1..10_000 { - edges.push(graph.new_edge(nodes[i - 1], nodes[i], ()).unwrap()); - } - - for edge in &edges { - black_box(edge.get(&graph)); - } - - for i in 1..10_000 { - black_box( - graph - .edge_between(nodes[i - 1], nodes[i]) - .unwrap() - .unwrap() - .remove(&mut graph) - .unwrap(), - ); - } - }) - }); -} diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 91ae90ea30c8e..9d4d66e02ab37 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -135,11 +135,13 @@ mod test { let two = graph.add_node(2); let three = graph.add_node(3); - graph.new_edge(zero, one, ()).unwrap(); - graph.new_edge(zero, two, ()).unwrap(); - graph.new_edge(one, two, ()).unwrap(); - graph.new_edge(two, zero, ()).unwrap(); - graph.new_edge(two, three, ()).unwrap(); + unsafe { + graph.add_edge_unchecked(zero, one, ()); + graph.add_edge_unchecked(zero, two, ()); + graph.add_edge_unchecked(one, two, ()); + graph.add_edge_unchecked(two, zero, ()); + graph.add_edge_unchecked(two, three, ()); + } let elements = vec![0, 2, 1, 3]; diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 127950c245704..d37ccfd18d82d 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -132,11 +132,13 @@ mod test { let two = graph.add_node(2); let three = graph.add_node(3); - graph.new_edge(zero, one, ()).unwrap(); - graph.new_edge(zero, two, ()).unwrap(); - graph.new_edge(one, two, ()).unwrap(); - graph.new_edge(two, zero, ()).unwrap(); - graph.new_edge(two, three, ()).unwrap(); + unsafe { + graph.add_edge_unchecked(zero, one, ()); + graph.add_edge_unchecked(zero, two, ()); + graph.add_edge_unchecked(one, two, ()); + graph.add_edge_unchecked(two, zero, ()); + graph.add_edge_unchecked(two, three, ()); + } let elements = vec![0, 1, 2, 3]; diff --git a/crates/bevy_graph/src/error.rs b/crates/bevy_graph/src/error.rs index e5af83a58a45d..729b3c583accc 100644 --- a/crates/bevy_graph/src/error.rs +++ b/crates/bevy_graph/src/error.rs @@ -1,23 +1,17 @@ use thiserror::Error; -use crate::graphs::keys::{EdgeIdx, NodeIdx}; +use crate::graphs::keys::NodeIdx; /// An error that can occur when traversing or manipulating a graph data structure #[derive(Debug, Error)] pub enum GraphError { /// the given `NodeIdx` is not preset in the graph - #[error("node by given NodeIdx `{0:?}` doesn't exist in this graph")] - NodeIdxDoesntExist(NodeIdx), - /// the given `EdgeIdx` is not preset in the graph - #[error("edge by given EdgeIdx `{0:?}` doesn't exist in this graph")] - EdgeIdxDoesntExist(EdgeIdx), - /// there is no edge between the two nodes in the graph - #[error("edge between nodes `{0:?}` and `{1:?}` doesn't exist in this graph")] - EdgeBetweenDoesntExist(NodeIdx, NodeIdx), - /// there is already an edge between those two nodes - #[error("edge between nodes `{0:?}` and `{1:?}` is already preset in this graph. would you like to use MultiGraph instead?")] - EdgeBetweenAlreadyExists(NodeIdx, NodeIdx), - /// `SimpleGraph`s can't hold an edge between the same node - #[error("cannot create an edge between node `{0:?}` and itself in a SimpleGraph. use MultiGraph instead")] - EdgeBetweenSameNode(NodeIdx), + #[error("the given `{0:?}` isn't preset in the graph")] + NodeNotFound(NodeIdx), + /// there is already an edge between those nodes (not allowed in `SimpleGraph`) + #[error("there is already an edge between those nodes (not allowed in `SimpleGraph`)")] + Loop, + /// the `src` and `dst` nodes are equal, the edge would be a loop (not allowed in `SimpleGraph`) + #[error("the `src` and `dst` nodes are equal, the edge would be a loop (not allowed in `SimpleGraph`)")] + ContainsEdgeBetween, } diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs index 2efc1ecafe1b1..86179682a5806 100644 --- a/crates/bevy_graph/src/graphs/edge.rs +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -7,8 +7,8 @@ pub struct Edge { pub src: NodeIdx, /// the `NodeIdx` of the destination node pub dst: NodeIdx, - /// the edge data - pub data: E, + /// the edge value + pub value: E, } impl Edge { diff --git a/crates/bevy_graph/src/graphs/keys.rs b/crates/bevy_graph/src/graphs/keys.rs index b30e3a6d4cf6e..d769f4e806e68 100644 --- a/crates/bevy_graph/src/graphs/keys.rs +++ b/crates/bevy_graph/src/graphs/keys.rs @@ -1,32 +1,8 @@ use slotmap::new_key_type; -use crate::error::GraphError; - -use super::Graph; - new_key_type! { /// a key that holds an index to a node in a graph pub struct NodeIdx; /// a key that holds an index to an edge in a graph pub struct EdgeIdx; } - -impl EdgeIdx { - /// shorthand for getting an immutable reference to the edge data - #[inline] - pub fn get(self, graph: &impl Graph) -> Result<&E, GraphError> { - graph.get_edge(self) - } - - /// shorthand for getting a mutable reference to the edge data - #[inline] - pub fn get_mut(self, graph: &mut impl Graph) -> Result<&mut E, GraphError> { - graph.get_edge_mut(self) - } - - /// shorthand for removing this edge - #[inline] - pub fn remove(self, graph: &mut impl Graph) -> Result { - graph.remove_edge(self) - } -} diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 61f15b04d2922..29e2e80b23789 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -43,110 +43,28 @@ pub trait Graph { /// Adds a node with the associated `value` and returns its [`NodeIdx`]. fn add_node(&mut self, value: N) -> NodeIdx; - /// Returns a reference to the value of a given node - fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError>; - - /// Returns a reference to the value of a given node - /// - /// # Safety - /// - /// This function should only be called when the Node for the `NodeIdx` exists - unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N; - - /// Returns a mutable reference to the value of a given node - fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError>; - - /// Returns a mutable reference to the value of a given node - /// - /// # Safety + /// Adds an edge between the specified nodes with the associated `value`. /// - /// This function should only be called when the Node for the `NodeIdx` exists - unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N; + /// # Returns + /// * `Ok`: `EdgeIdx` of the new edge + /// * `Err`: + /// * `GraphError::NodeNotFound(NodeIdx)`: the given `src` or `dst` isn't preset in the graph + /// * `GraphError::ContainsEdgeBetween`: there is already an edge between those nodes (not allowed in `SimpleGraph`) + /// * `GraphError::Loop`: the `src` and `dst` nodes are equal, the edge would be a loop (not allowed in `SimpleGraph`) + fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> Result; - /// Removes a node from the graph by its `NodeIdx` - fn remove_node(&mut self, node: NodeIdx) -> Result; + /// Adds an edge between the specified nodes with the associated `value`. + unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx; - /// Returns true as long as the node from the given `NodeIdx` is preset + /// Returns `true` if the `node` is preset in the graph. fn has_node(&self, node: NodeIdx) -> bool; - //////////////////////////// - // Edges - //////////////////////////// - - /// Creates a new edge between the two nodes and with the given value in the graph and returns its `EdgeIdx` - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result; - - /// Creates a new edge between the two nodes and with the given value in the graph and returns its `EdgeIdx` - /// - /// # Safety - /// - /// This function should only be called when the nodes exist and there is no equal edge. - unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx; - - /// Returns a reference to the value of a given edge + /// Returns `true` if an edge between the specified nodes exists. /// - /// ## Inline helper + /// # Panics /// - /// This function can also be directly called by the `EdgeIdx`: - /// ``` - /// # use bevy_graph::graphs::{Graph, simple::SimpleMapGraph}; - /// # let mut graph = SimpleMapGraph::<(), i32, true>::new(); - /// let from = graph.new_node(()); - /// let to = graph.new_node(()); - /// let edge = graph.new_edge(from, to, 12).unwrap(); - /// assert_eq!(edge.get(&graph).unwrap(), &12); - /// ``` - fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError>; - - /// Returns a mutable reference to the value of a given edge - /// - /// ## Inline helper - /// - /// This function can also be directly called by the `EdgeIdx`: - /// ``` - /// # use bevy_graph::graphs::{Graph, simple::SimpleMapGraph}; - /// # let mut graph = SimpleMapGraph::<(), i32, true>::new(); - /// let from = graph.new_node(()); - /// let to = graph.new_node(()); - /// let edge = graph.new_edge(from, to, 12).unwrap(); - /// assert_eq!(edge.get_mut(&mut graph).unwrap(), &12); - /// ``` - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError>; - - /// Remove an edge by its `EdgeIdx` and returns the edge data - /// - /// ## Inline helper - /// - /// This function can also be directly called by the `EdgeIdx`: - /// ``` - /// # use bevy_graph::graphs::{Graph, simple::SimpleMapGraph}; - /// # let mut graph = SimpleMapGraph::<(), i32, true>::new(); - /// let from = graph.new_node(()); - /// let to = graph.new_node(()); - /// let edge = graph.new_edge(from, to, 12).unwrap(); - /// assert_eq!(edge.remove(&mut graph).unwrap(), 12); - /// ``` - fn remove_edge(&mut self, edge: EdgeIdx) -> Result; - - /// Remove an edge by its `EdgeIdx` and returns the edge data - /// - /// # Safety - /// - /// This function should only be called when the edge exists - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E; - - /// Returns a `Vec` of all edges between two nodes as `EdgeIdx` - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError>; - - /// Returns a `Vec` of all edges between two nodes as `EdgeIdx` - /// - /// # Safety - /// - /// This function should only be called when the nodes and the edges between exists - unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec; - - /// Returns a `Vec` of all edges the node is outgoing from. - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)>; // TODO: can we use other type than Vec? maybe directly iterator? + /// Panics if `src` or `dst` do not exist. + fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool; } /// A more precise trait with functions special for a simple graph diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 66deea8a8704f..40215d73eee84 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -7,6 +7,7 @@ use crate::{ keys::{EdgeIdx, NodeIdx}, Graph, }, + utils::vecmap::VecMap, }; /// Implementation of a `MultiGraph` which uses `Vec<(NodeIdx, Vec)>` for adjacencies @@ -47,39 +48,35 @@ impl Graph for MultiListGraph self.edges.len() } - #[inline] fn add_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, Vec::new()); idx } - #[inline] - fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { Ok(self.get_node_unchecked(idx)) } + fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> Result { + if !self.has_node(src) { + Err(GraphError::NodeNotFound(src)) + } else if !self.has_node(dst) { + Err(GraphError::NodeNotFound(dst)) } else { - Err(GraphError::NodeIdxDoesntExist(idx)) + unsafe { Ok(self.add_edge_unchecked(src, dst, value)) } } } - #[inline] - unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { - self.nodes.get_unchecked(idx) - } - - #[inline] - fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { Ok(self.get_node_unchecked_mut(idx)) } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) + unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { src, dst, value }); + self.adjacencies + .get_unchecked_mut(src) + .get_value_or_default_mut(dst) + .push(idx); + if !DIRECTED { + self.adjacencies + .get_unchecked_mut(dst) + .get_value_or_default_mut(src) + .push(idx); } - } - - #[inline] - unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { - self.nodes.get_unchecked_mut(idx) + idx } #[inline] @@ -87,193 +84,7 @@ impl Graph for MultiListGraph self.nodes.contains_key(node) } - #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { - match self.edges.get(edge) { - Some(e) => Ok(&e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)), - } - } - - #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { - match self.edges.get_mut(edge) { - Some(e) => Ok(&mut e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)), - } - } - - fn remove_edge(&mut self, edge: EdgeIdx) -> Result { - if self.edges.contains_key(edge) { - unsafe { Ok(self.remove_edge_unchecked(edge)) } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } + fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { + self.adjacencies.get(src).unwrap().contains_key(dst) } - - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { - if self.has_node(from) { - unsafe { Ok(self.edges_between_unchecked(from, to)) } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) - } - } - - unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { - find_edge_list(self.adjacencies.get_unchecked(from), to) - .cloned() - .unwrap_or_default() - } - - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - if let Some(list) = self.adjacencies.get(node) { - // TODO: can this be done with iterators? - let mut result = Vec::new(); - for (target, edges) in list { - for edge in edges { - result.push((*target, *edge)); - } - } - result - } else { - Vec::new() - } - } - - fn remove_node(&mut self, node: NodeIdx) -> Result { - if DIRECTED { - let mut edges = vec![]; - for (edge, data) in &self.edges { - let (src, dst) = data.indices(); - if dst == node || src == node { - edges.push(edge); - } - } - for edge in edges { - unsafe { - // SAFETY: we know it must exist - self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? - } - } - match self.nodes.remove(node) { - Some(n) => { - unsafe { - // SAFETY: it will exist. - self.adjacencies.remove(node).unwrap_unchecked(); - } - Ok(n) - } - None => Err(GraphError::NodeIdxDoesntExist(node)), - } - } else { - for (_, edge) in self.edges_of(node) { - unsafe { - // SAFETY: we know it must exist - self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? - } - } - match self.nodes.remove(node) { - Some(n) => { - unsafe { - // SAFETY: it will exist. - self.adjacencies.remove(node).unwrap_unchecked(); - } - Ok(n) - } - None => Err(GraphError::NodeIdxDoesntExist(node)), - } - } - } - - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { - if self.has_node(from) { - if self.has_node(to) { - unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } - } else { - Err(GraphError::NodeIdxDoesntExist(to)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) - } - } - - unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); - if DIRECTED { - let adjs = self.adjacencies.get_unchecked_mut(from); - if let Some(list) = find_edge_list_mut(adjs, to) { - list.push(idx); - } else { - adjs.push((to, vec![idx])); - } - } else { - let adjs = self.adjacencies.get_unchecked_mut(from); - if let Some(list) = find_edge_list_mut(adjs, to) { - list.push(idx); - } else { - adjs.push((to, vec![idx])); - } - let adjs = self.adjacencies.get_unchecked_mut(to); - if let Some(list) = find_edge_list_mut(adjs, from) { - list.push(idx); - } else { - adjs.push((from, vec![idx])); - } - } - idx - } - - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { - if DIRECTED { - let (from, to) = self.edges.get_unchecked(edge).indices(); - let list = self.adjacencies.get_unchecked_mut(from); - let list = find_edge_list_mut(list, to).unwrap(); - list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? - } else { - let (from, to) = self.edges.get_unchecked(edge).indices(); - - let list = self.adjacencies.get_unchecked_mut(from); - let list = find_edge_list_mut(list, to).unwrap(); - list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? - - let list = self.adjacencies.get_unchecked_mut(to); - let list = find_edge_list_mut(list, from).unwrap(); - list.swap_remove(find_edge(list, edge).unwrap()); // TODO: remove or swap_remove ? - } - self.edges.remove(edge).unwrap().data - } -} - -// Util function -#[inline] -fn find_edge_list(list: &[(NodeIdx, Vec)], node: NodeIdx) -> Option<&Vec> { - match list.iter().find(|l| l.0 == node) { - Some((_, l)) => Some(l), - None => None, - } -} -#[inline] -fn find_edge_list_mut( - list: &mut [(NodeIdx, Vec)], - node: NodeIdx, -) -> Option<&mut Vec> { - match list.iter_mut().find(|l| l.0 == node) { - Some((_, l)) => Some(l), - None => None, - } -} -#[inline] -fn find_edge(list: &[EdgeIdx], edge: EdgeIdx) -> Option { - list.iter().position(|edge_idx| *edge_idx == edge) -} - -#[cfg(test)] -mod test { - use crate::multi_graph_tests; - - multi_graph_tests!(super::MultiListGraph); } diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index fa2b181a3e4c5..f3eedfd980978 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -49,223 +49,45 @@ impl Graph for MultiMapGraph { self.edges.len() } - #[inline] fn add_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, HashMap::new()); idx } - #[inline] - fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { Ok(self.get_node_unchecked(idx)) } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) - } - } - - #[inline] - unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { - self.nodes.get_unchecked(idx) - } - - #[inline] - fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { Ok(self.get_node_unchecked_mut(idx)) } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) - } - } - - #[inline] - unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { - self.nodes.get_unchecked_mut(idx) - } - - #[inline] - fn has_node(&self, node: NodeIdx) -> bool { - self.nodes.contains_key(node) - } - - #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { - match self.edges.get(edge) { - Some(e) => Ok(&e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)), - } - } - - #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { - match self.edges.get_mut(edge) { - Some(e) => Ok(&mut e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)), - } - } - - fn remove_edge(&mut self, edge: EdgeIdx) -> Result { - if self.edges.contains_key(edge) { - unsafe { Ok(self.remove_edge_unchecked(edge)) } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } - } - - #[inline] - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { - if let Some(from_edges) = self.adjacencies.get(from) { - if from_edges.contains_key(&to) { - unsafe { Ok(self.edges_between_unchecked(from, to)) } - } else { - Ok(vec![]) - } + fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> Result { + if !self.has_node(src) { + Err(GraphError::NodeNotFound(src)) + } else if !self.has_node(dst) { + Err(GraphError::NodeNotFound(dst)) } else { - Err(GraphError::NodeIdxDoesntExist(from)) + unsafe { Ok(self.add_edge_unchecked(src, dst, value)) } } } - #[inline] - unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { + unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { src, dst, value }); self.adjacencies - .get_unchecked(from) - .get(&to) - .cloned() - .unwrap() - } - - #[inline] - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - if let Some(map) = self.adjacencies.get(node) { - // TODO: can this be done with iterators? - let mut result = Vec::new(); - for (target, edges) in map { - for edge in edges { - result.push((*target, *edge)); - } - } - result - } else { - Vec::new() - } - } - - fn remove_node(&mut self, node: NodeIdx) -> Result { - if DIRECTED { - let mut edges = vec![]; - for (edge, data) in &self.edges { - let (src, dst) = data.indices(); - if dst == node || src == node { - edges.push(edge); - } - } - for edge in edges { - unsafe { - // SAFETY: we know it must exist - self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? - } - } - match self.nodes.remove(node) { - Some(n) => { - unsafe { - // SAFETY: it will exist. - self.adjacencies.remove(node).unwrap_unchecked(); - } - Ok(n) - } - None => Err(GraphError::NodeIdxDoesntExist(node)), - } - } else { - for (_, edge) in self.edges_of(node) { - unsafe { - // SAFETY: we know it must exist - self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? - } - } - match self.nodes.remove(node) { - Some(n) => { - unsafe { - // SAFETY: it will exist. - self.adjacencies.remove(node).unwrap_unchecked(); - } - Ok(n) - } - None => Err(GraphError::NodeIdxDoesntExist(node)), - } - } - } - - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { - if self.has_node(from) { - if self.has_node(to) { - unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } - } else { - Err(GraphError::NodeIdxDoesntExist(to)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) - } - } - - unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); - if DIRECTED { - self.adjacencies - .get_unchecked_mut(from) - .entry(to) - .or_default() - .push(idx); - } else { - self.adjacencies - .get_unchecked_mut(from) - .entry(to) - .or_default() - .push(idx); + .get_unchecked_mut(src) + .entry(dst) + .or_default() + .push(idx); + if !DIRECTED { self.adjacencies - .get_unchecked_mut(to) - .entry(from) + .get_unchecked_mut(dst) + .entry(src) .or_default() .push(idx); } idx } - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { - if DIRECTED { - let (from, to) = self.edges.get_unchecked(edge).indices(); - let adjas = self - .adjacencies - .get_unchecked_mut(from) - .get_mut(&to) - .unwrap(); - adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? - } else { - let (node, other) = self.edges.get_unchecked(edge).indices(); - let adjas = self - .adjacencies - .get_unchecked_mut(node) - .get_mut(&other) - .unwrap(); - adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? - let adjas = self - .adjacencies - .get_unchecked_mut(other) - .get_mut(&node) - .unwrap(); - adjas.swap_remove(adjas.iter().position(|e| *e == edge).unwrap()); // TODO: remove or swap_remove ? - } - self.edges.remove(edge).unwrap().data + #[inline] + fn has_node(&self, node: NodeIdx) -> bool { + self.nodes.contains_key(node) } -} -#[cfg(test)] -mod test { - use crate::multi_graph_tests; - - multi_graph_tests!(super::MultiMapGraph); + fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { + self.adjacencies.get(src).unwrap().contains_key(&dst) + } } diff --git a/crates/bevy_graph/src/graphs/multi/mod.rs b/crates/bevy_graph/src/graphs/multi/mod.rs index 43c3592b04f1f..4efa46e6469cb 100644 --- a/crates/bevy_graph/src/graphs/multi/mod.rs +++ b/crates/bevy_graph/src/graphs/multi/mod.rs @@ -3,268 +3,3 @@ pub use map::*; mod list; pub use list::*; - -#[cfg(test)] -mod test { - use hashbrown::HashSet; - use std::hash::Hash; - - use crate::graphs::Graph; - - #[derive(PartialEq, Debug)] - pub enum Person { - Jake, - Michael, - Jennifer, - } - - #[macro_export] - macro_rules! multi_graph_tests { - ($($graph:ident )::+) => { - use $crate::graphs::{Graph, multi::test::{self, Person}}; - - #[test] - fn nodes() { - test::nodes(<$($graph)::+ >::new()) - } - #[test] - fn undirected_edges() { - test::undirected_edges(<$($graph)::+ >::new()) - } - #[test] - fn directed_edges() { - test::directed_edges(<$($graph)::+ >::new()) - } - #[test] - fn remove_node_undirected() { - test::remove_node_undirected(<$($graph)::+ >::new()) - } - #[test] - fn remove_node_directed() { - test::remove_node_directed(<$($graph)::+ >::new()) - } - #[test] - fn edge_between_same_node_undirected() { - test::edge_between_same_node(<$($graph)::+ >::new()) - } - #[test] - fn edge_between_same_node_directed() { - test::edge_between_same_node(<$($graph)::+ >::new()) - } - }; - } - - pub fn nodes(mut graph: impl Graph) { - let jake = graph.add_node(Person::Jake); - let michael = graph.add_node(Person::Michael); - let jennifer = graph.add_node(Person::Jennifer); - let other_jake = graph.add_node(Person::Jake); - - assert_eq!(graph.get_node(jake).unwrap(), &Person::Jake); - assert_eq!(graph.get_node(michael).unwrap(), &Person::Michael); - assert_eq!(graph.get_node(jennifer).unwrap(), &Person::Jennifer); - assert_eq!(graph.get_node(other_jake).unwrap(), &Person::Jake); - - graph - .get_node_mut(jake) - .map(|node| *node = Person::Michael) - .unwrap(); - - assert_eq!(graph.get_node(jake).unwrap(), &Person::Michael); - assert_eq!(graph.get_node(michael).unwrap(), &Person::Michael); - assert_eq!(graph.get_node(jennifer).unwrap(), &Person::Jennifer); - assert_eq!(graph.get_node(other_jake).unwrap(), &Person::Jake); - - assert!(graph.remove_node(jake).is_ok()); - assert!(graph.remove_node(michael).is_ok()); - assert!(graph.remove_node(jennifer).is_ok()); - assert!(graph.remove_node(other_jake).is_ok()); - - assert!(graph.get_node(jake).is_err()); - assert!(graph.get_node(michael).is_err()); - assert!(graph.get_node(jennifer).is_err()); - assert!(graph.get_node(other_jake).is_err()); - } - - pub fn undirected_edges(mut graph: impl Graph) { - let jake = graph.add_node(Person::Jake); - let michael = graph.add_node(Person::Michael); - let jennifer = graph.add_node(Person::Jennifer); - let other_jake = graph.add_node(Person::Jake); - - let jm = graph.new_edge(jake, michael, 2).unwrap(); - let jm2 = graph.new_edge(jake, michael, 20).unwrap(); - let jj = graph.new_edge(jennifer, jake, 7).unwrap(); - let jo = graph.new_edge(jake, other_jake, 5).unwrap(); - let mo = graph.new_edge(michael, other_jake, 1).unwrap(); - let j_itself = graph.new_edge(jennifer, jennifer, 8).unwrap(); - - assert!(unordered_eq( - &graph.edges_of(jake), - &[ - (michael, jm), - (michael, jm2), - (jennifer, jj), - (other_jake, jo) - ] - )); - - assert_eq!(graph.get_edge(jm).unwrap(), &2); - assert_eq!(graph.get_edge(jj).unwrap(), &7); - assert_eq!(graph.get_edge(jo).unwrap(), &5); - assert_eq!(graph.get_edge(mo).unwrap(), &1); - - assert_eq!( - graph.edges_between(jennifer, jake).unwrap(), - graph.edges_between(jake, jennifer).unwrap() - ); - - assert!(graph.edges_of(jennifer).contains(&(jennifer, j_itself))); - - assert!(unordered_eq( - &graph.edges_between(jake, michael).unwrap(), - &[jm, jm2] - )); - - *graph.get_edge_mut(mo).unwrap() = 10; - - assert_eq!(graph.get_edge(jm).unwrap(), &2); - assert_eq!(graph.get_edge(jj).unwrap(), &7); - assert_eq!(graph.get_edge(jo).unwrap(), &5); - assert_eq!(graph.get_edge(mo).unwrap(), &10); - - assert!(graph.remove_edge(jm).is_ok()); - assert!(graph.remove_edge(jj).is_ok()); - assert!(graph.remove_edge(jo).is_ok()); - assert!(graph.remove_edge(mo).is_ok()); - - assert!(graph.get_edge(jm).is_err()); - assert!(graph.get_edge(jj).is_err()); - assert!(graph.get_edge(jo).is_err()); - assert!(graph.get_edge(mo).is_err()); - } - - pub fn directed_edges(mut graph: impl Graph) { - let jake = graph.add_node(Person::Jake); - let michael = graph.add_node(Person::Michael); - let jennifer = graph.add_node(Person::Jennifer); - let other_jake = graph.add_node(Person::Jake); - - let jm = graph.new_edge(jake, michael, 2).unwrap(); - let jm2 = graph.new_edge(jake, michael, 20).unwrap(); - let jj = graph.new_edge(jennifer, jake, 7).unwrap(); - let jo = graph.new_edge(jake, other_jake, 5).unwrap(); - let mo = graph.new_edge(michael, other_jake, 1).unwrap(); - let j_itself = graph.new_edge(jennifer, jennifer, 8).unwrap(); - - assert!(unordered_eq( - &graph.edges_of(jake), - &[(michael, jm), (michael, jm2), (other_jake, jo)] - )); - - assert_eq!(graph.get_edge(jm).unwrap(), &2); - assert_eq!(graph.get_edge(jj).unwrap(), &7); - assert_eq!(graph.get_edge(jo).unwrap(), &5); - assert_eq!(graph.get_edge(mo).unwrap(), &1); - - assert!(!graph.edges_between(jennifer, jake).unwrap().is_empty()); - assert!(graph.edges_between(jake, jennifer).unwrap().is_empty()); - - assert!(graph.edges_of(jennifer).contains(&(jennifer, j_itself))); - - assert!(unordered_eq( - &graph.edges_between(jake, michael).unwrap(), - &[jm, jm2] - )); - - *graph.get_edge_mut(mo).unwrap() = 10; - - assert_eq!(graph.get_edge(jm).unwrap(), &2); - assert_eq!(graph.get_edge(jj).unwrap(), &7); - assert_eq!(graph.get_edge(jo).unwrap(), &5); - assert_eq!(graph.get_edge(mo).unwrap(), &10); - - assert!(graph.remove_edge(jm).is_ok()); - assert!(graph.remove_edge(jj).is_ok()); - assert!(graph.remove_edge(jo).is_ok()); - assert!(graph.remove_edge(mo).is_ok()); - - assert!(graph.get_edge(jm).is_err()); - assert!(graph.get_edge(jj).is_err()); - assert!(graph.get_edge(jo).is_err()); - assert!(graph.get_edge(mo).is_err()); - } - - pub fn remove_node_undirected(mut graph: impl Graph) { - let jake = graph.add_node(Person::Jake); - let michael = graph.add_node(Person::Michael); - - let edge = graph.new_edge(jake, michael, 20).unwrap(); - - assert!(graph.get_node(jake).is_ok()); - assert!(graph.get_node(michael).is_ok()); - assert_eq!(graph.get_edge(edge).unwrap(), &20); - assert_eq!( - graph.edges_between(jake, michael).unwrap()[0] - .get(&graph) - .unwrap(), - &20 - ); - assert_eq!( - graph.edges_between(michael, jake).unwrap()[0] - .get(&graph) - .unwrap(), - &20 - ); - - assert!(graph.remove_node(michael).is_ok()); - - assert!(graph.get_node(jake).is_ok()); - assert!(graph.get_node(michael).is_err()); - assert!(graph.get_edge(edge).is_err()); - assert!(graph.edges_between(jake, michael).unwrap().is_empty()); - assert!(graph.edges_between(michael, jake).is_err()); - } - - pub fn remove_node_directed(mut graph: impl Graph) { - let jake = graph.add_node(Person::Jake); - let michael = graph.add_node(Person::Michael); - - let edge = graph.new_edge(jake, michael, 20).unwrap(); - - assert!(graph.get_node(jake).is_ok()); - assert!(graph.get_node(michael).is_ok()); - assert_eq!(graph.get_edge(edge).unwrap(), &20); - assert_eq!( - graph.edges_between(jake, michael).unwrap()[0] - .get(&graph) - .unwrap(), - &20 - ); - assert!(graph.edges_between(michael, jake).unwrap().is_empty()); - - assert!(graph.remove_node(michael).is_ok()); - - assert!(graph.get_node(jake).is_ok()); - assert!(graph.get_node(michael).is_err()); - assert!(graph.get_edge(edge).is_err()); - assert!(graph.edges_between(jake, michael).unwrap().is_empty()); - assert!(graph.edges_between(michael, jake).is_err()); - } - - pub fn edge_between_same_node(mut graph: impl Graph) { - let jake = graph.add_node(Person::Jake); - - assert!(graph.new_edge(jake, jake, 20).is_ok()); - } - - fn unordered_eq(a: &[T], b: &[T]) -> bool - where - T: Eq + Hash, - { - let a: HashSet<_> = a.iter().collect(); - let b: HashSet<_> = b.iter().collect(); - - a == b - } -} diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 1c570a4c41997..7479f9f7c883a 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -1,12 +1,13 @@ -use slotmap::{HopSlotMap, Key, SecondaryMap}; +use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ error::GraphError, graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, - Graph, SimpleGraph, + Graph, }, + utils::vecmap::VecMap, }; /// Implementation of a `SimpleGraph` which uses `Vec<(NodeIdx, EdgeIdx)>` for adjacencies @@ -48,39 +49,33 @@ impl Graph for SimpleListGraph self.edges.len() } - #[inline] fn add_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, Vec::new()); idx } - #[inline] - fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { Ok(self.get_node_unchecked(idx)) } + fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> Result { + if !self.has_node(src) { + Err(GraphError::NodeNotFound(src)) + } else if !self.has_node(dst) { + Err(GraphError::NodeNotFound(dst)) + } else if self.contains_edge_between(src, dst) { + Err(GraphError::ContainsEdgeBetween) + } else if src == dst { + Err(GraphError::Loop) } else { - Err(GraphError::NodeIdxDoesntExist(idx)) + unsafe { Ok(self.add_edge_unchecked(src, dst, value)) } } } - #[inline] - unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { - self.nodes.get_unchecked(idx) - } - - #[inline] - fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { Ok(self.get_node_unchecked_mut(idx)) } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) + unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { src, dst, value }); + self.adjacencies.get_unchecked_mut(src).push((dst, idx)); + if !DIRECTED { + self.adjacencies.get_unchecked_mut(dst).push((src, idx)); } - } - - #[inline] - unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { - self.nodes.get_unchecked_mut(idx) + idx } #[inline] @@ -88,198 +83,7 @@ impl Graph for SimpleListGraph self.nodes.contains_key(node) } - #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { - match self.edges.get(edge) { - Some(e) => Ok(&e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)), - } - } - - #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { - match self.edges.get_mut(edge) { - Some(e) => Ok(&mut e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)), - } - } - - fn remove_edge(&mut self, edge: EdgeIdx) -> Result { - if self.edges.contains_key(edge) { - unsafe { Ok(self.remove_edge_unchecked(edge)) } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } - } - - #[inline] - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { - match self.edge_between(from, to) { - Ok(Some(idx)) => Ok(vec![idx]), - Ok(None) => Ok(vec![]), - Err(e) => Err(e), - } - } - - #[inline] - unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { - vec![self.edge_between_unchecked(from, to)] - } - - #[inline] - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - self.adjacencies.get(node).unwrap().to_vec() - } - - fn remove_node(&mut self, node: NodeIdx) -> Result { - if DIRECTED { - let mut edges = vec![]; - for (edge, data) in &self.edges { - let (src, dst) = data.indices(); - if dst == node || src == node { - edges.push(edge); - } - } - for edge in edges { - unsafe { - // SAFETY: we know it must exist - self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? - } - } - match self.nodes.remove(node) { - Some(n) => { - unsafe { - // SAFETY: it will exist. - self.adjacencies.remove(node).unwrap_unchecked(); - } - Ok(n) - } - None => Err(GraphError::NodeIdxDoesntExist(node)), - } - } else { - for (_, edge) in self.edges_of(node) { - unsafe { - // SAFETY: we know it must exist - self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? - } - } - match self.nodes.remove(node) { - Some(n) => { - unsafe { - // SAFETY: it will exist. - self.adjacencies.remove(node).unwrap_unchecked(); - } - Ok(n) - } - None => Err(GraphError::NodeIdxDoesntExist(node)), - } - } - } - - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { - if from == to { - Err(GraphError::EdgeBetweenSameNode(from)) - } else if DIRECTED { - if let Some(from_edges) = self.adjacencies.get(from) { - if from_edges.iter().any(|(n, _)| *n == to) { - Err(GraphError::EdgeBetweenAlreadyExists(from, to)) - } else if self.has_node(to) { - unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } - } else { - Err(GraphError::NodeIdxDoesntExist(to)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) - } - } else if let Some(node_edges) = self.adjacencies.get(from) { - if node_edges.iter().any(|(n, _)| *n == to) { - Err(GraphError::EdgeBetweenAlreadyExists(from, to)) - } else if let Some(other_edges) = self.adjacencies.get(to) { - if other_edges.iter().any(|(n, _)| *n == from) { - Err(GraphError::EdgeBetweenAlreadyExists(to, from)) - } else { - unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } - } - } else { - Err(GraphError::NodeIdxDoesntExist(to)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) - } - } - - unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); - if DIRECTED { - self.adjacencies.get_unchecked_mut(from).push((to, idx)); - } else { - self.adjacencies.get_unchecked_mut(from).push((to, idx)); - self.adjacencies.get_unchecked_mut(to).push((from, idx)); - } - idx + fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { + unsafe { self.adjacencies.get(src).unwrap().contains_key(dst) } } - - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { - if DIRECTED { - let (from, to) = self.edges.get_unchecked(edge).indices(); - let list = self.adjacencies.get_unchecked_mut(from); - list.swap_remove(find_edge(list, to).unwrap()); // TODO: remove or swap_remove ? - } else { - let (node, other) = self.edges.get_unchecked(edge).indices(); - let list = self.adjacencies.get_unchecked_mut(node); - list.swap_remove(find_edge(list, other).unwrap()); // TODO: remove or swap_remove ? - let list = self.adjacencies.get_unchecked_mut(other); - list.swap_remove(find_edge(list, node).unwrap()); // TODO: remove or swap_remove ? - } - self.edges.remove(edge).unwrap().data - } -} - -impl SimpleGraph for SimpleListGraph { - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { - if self.adjacencies.contains_key(from) { - unsafe { - let idx = self.edge_between_unchecked(from, to); - if idx.is_null() { - Ok(None) - } else { - Ok(Some(idx)) - } - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) - } - } - - unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - if let Some(idx) = self - .adjacencies - .get_unchecked(from) - .iter() - .find_map(|(other_node, idx)| if *other_node == to { Some(*idx) } else { None }) - // we know it simple graph can only have 1 edge so `find_map` is enough - { - idx - } else { - EdgeIdx::null() - } - } -} - -// Util function -#[inline] -fn find_edge(list: &[(NodeIdx, EdgeIdx)], node: NodeIdx) -> Option { - list.iter() - .position(|(node_idx, _edge_idx)| *node_idx == node) -} - -#[cfg(test)] -mod test { - use crate::simple_graph_tests; - - simple_graph_tests!(super::SimpleListGraph); } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 84cd8f185a939..ab20744c5a97f 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -6,7 +6,7 @@ use crate::{ graphs::{ edge::Edge, keys::{EdgeIdx, NodeIdx}, - Graph, SimpleGraph, + Graph, }, }; @@ -49,39 +49,33 @@ impl Graph for SimpleMapGraph self.edges.len() } - #[inline] fn add_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); self.adjacencies.insert(idx, HashMap::new()); idx } - #[inline] - fn get_node(&self, idx: NodeIdx) -> Result<&N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { Ok(self.get_node_unchecked(idx)) } + fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> Result { + if !self.has_node(src) { + Err(GraphError::NodeNotFound(src)) + } else if !self.has_node(dst) { + Err(GraphError::NodeNotFound(dst)) + } else if self.contains_edge_between(src, dst) { + Err(GraphError::ContainsEdgeBetween) + } else if src == dst { + Err(GraphError::Loop) } else { - Err(GraphError::NodeIdxDoesntExist(idx)) + unsafe { Ok(self.add_edge_unchecked(src, dst, value)) } } } - #[inline] - unsafe fn get_node_unchecked(&self, idx: NodeIdx) -> &N { - self.nodes.get_unchecked(idx) - } - - #[inline] - fn get_node_mut(&mut self, idx: NodeIdx) -> Result<&mut N, GraphError> { - if self.nodes.contains_key(idx) { - unsafe { Ok(self.get_node_unchecked_mut(idx)) } - } else { - Err(GraphError::NodeIdxDoesntExist(idx)) + unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { + let idx = self.edges.insert(Edge { src, dst, value }); + self.adjacencies.get_unchecked_mut(src).insert(dst, idx); + if !DIRECTED { + self.adjacencies.get_unchecked_mut(dst).insert(src, idx); } - } - - #[inline] - unsafe fn get_node_unchecked_mut(&mut self, idx: NodeIdx) -> &mut N { - self.nodes.get_unchecked_mut(idx) + idx } #[inline] @@ -89,190 +83,7 @@ impl Graph for SimpleMapGraph self.nodes.contains_key(node) } - #[inline] - fn get_edge(&self, edge: EdgeIdx) -> Result<&E, GraphError> { - match self.edges.get(edge) { - Some(e) => Ok(&e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)), - } - } - - #[inline] - fn get_edge_mut(&mut self, edge: EdgeIdx) -> Result<&mut E, GraphError> { - match self.edges.get_mut(edge) { - Some(e) => Ok(&mut e.data), - None => Err(GraphError::EdgeIdxDoesntExist(edge)), - } - } - - fn remove_edge(&mut self, edge: EdgeIdx) -> Result { - if self.edges.contains_key(edge) { - unsafe { Ok(self.remove_edge_unchecked(edge)) } - } else { - Err(GraphError::EdgeIdxDoesntExist(edge)) - } - } - - #[inline] - fn edges_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { - match self.edge_between(from, to) { - Ok(Some(idx)) => Ok(vec![idx]), - Ok(None) => Ok(vec![]), - Err(e) => Err(e), - } - } - - #[inline] - unsafe fn edges_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> Vec { - vec![self.edge_between_unchecked(from, to)] - } - - #[inline] - fn edges_of(&self, node: NodeIdx) -> Vec<(NodeIdx, EdgeIdx)> { - self.adjacencies - .get(node) - .unwrap() - .iter() - .map(|(node, edge)| (*node, *edge)) - .collect() - } - - fn remove_node(&mut self, node: NodeIdx) -> Result { - if DIRECTED { - let mut edges = vec![]; - for (edge, data) in &self.edges { - let (src, dst) = data.indices(); - if dst == node || src == node { - edges.push(edge); - } - } - for edge in edges { - unsafe { - // SAFETY: we know it must exist - self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? - } - } - match self.nodes.remove(node) { - Some(n) => { - unsafe { - // SAFETY: it will exist. - self.adjacencies.remove(node).unwrap_unchecked(); - } - Ok(n) - } - None => Err(GraphError::NodeIdxDoesntExist(node)), - } - } else { - for (_, edge) in self.edges_of(node) { - unsafe { - // SAFETY: we know it must exist - self.remove_edge_unchecked(edge); // TODO: can we have a `remove_edges` function? - } - } - match self.nodes.remove(node) { - Some(n) => { - unsafe { - // SAFETY: it will exist. - self.adjacencies.remove(node).unwrap_unchecked(); - } - Ok(n) - } - None => Err(GraphError::NodeIdxDoesntExist(node)), - } - } - } - - fn new_edge(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> Result { - if from == to { - Err(GraphError::EdgeBetweenSameNode(from)) - } else if DIRECTED { - if let Some(from_edges) = self.adjacencies.get(from) { - if from_edges.contains_key(&to) { - Err(GraphError::EdgeBetweenAlreadyExists(from, to)) - } else if self.has_node(to) { - unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } - } else { - Err(GraphError::NodeIdxDoesntExist(to)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) - } - } else if let Some(node_edges) = self.adjacencies.get(from) { - if node_edges.contains_key(&to) { - Err(GraphError::EdgeBetweenAlreadyExists(from, to)) - } else if let Some(other_edges) = self.adjacencies.get(to) { - if other_edges.contains_key(&from) { - Err(GraphError::EdgeBetweenAlreadyExists(from, to)) - } else { - unsafe { Ok(self.new_edge_unchecked(from, to, edge)) } - } - } else { - Err(GraphError::NodeIdxDoesntExist(to)) - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) - } - } - - unsafe fn new_edge_unchecked(&mut self, from: NodeIdx, to: NodeIdx, edge: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { - src: from, - dst: to, - data: edge, - }); - if DIRECTED { - self.adjacencies - .get_unchecked_mut(from) - .insert_unique_unchecked(to, idx); - } else { - self.adjacencies - .get_unchecked_mut(from) - .insert_unique_unchecked(to, idx); - self.adjacencies - .get_unchecked_mut(to) - .insert_unique_unchecked(from, idx); - } - idx + fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { + self.adjacencies.get(src).unwrap().contains_key(&dst) } - - unsafe fn remove_edge_unchecked(&mut self, edge: EdgeIdx) -> E { - if DIRECTED { - let (from, to) = self.edges.get_unchecked(edge).indices(); - self.adjacencies.get_unchecked_mut(from).remove(&to); - } else { - let (node, other) = self.edges.get_unchecked(edge).indices(); - self.adjacencies.get_unchecked_mut(node).remove(&other); - self.adjacencies.get_unchecked_mut(other).remove(&node); - } - self.edges.remove(edge).unwrap().data - } -} - -impl SimpleGraph for SimpleMapGraph { - fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError> { - if let Some(from_edges) = self.adjacencies.get(from) { - if from_edges.contains_key(&to) { - unsafe { Ok(Some(self.edge_between_unchecked(from, to))) } - } else { - Ok(None) - } - } else { - Err(GraphError::NodeIdxDoesntExist(from)) - } - } - - unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx { - self.adjacencies - .get_unchecked(from) - .get(&to) - .cloned() - .unwrap() - } -} - -#[cfg(test)] -mod test { - use crate::simple_graph_tests; - - simple_graph_tests!(super::SimpleMapGraph); } diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs index d54d6784bdcda..4efa46e6469cb 100644 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ b/crates/bevy_graph/src/graphs/simple/mod.rs @@ -3,257 +3,3 @@ pub use map::*; mod list; pub use list::*; - -#[cfg(test)] -mod test { - use hashbrown::HashSet; - use std::hash::Hash; - - use crate::{error::GraphError, graphs::SimpleGraph}; - - #[derive(PartialEq, Debug)] - pub enum Person { - Jake, - Michael, - Jennifer, - } - - #[macro_export] - macro_rules! simple_graph_tests { - ($($graph:ident )::+) => { - use $crate::graphs::{Graph, simple::test::{self, Person}}; - - #[test] - fn nodes() { - test::nodes(<$($graph)::+ >::new()) - } - #[test] - fn undirected_edges() { - test::undirected_edges(<$($graph)::+ >::new()) - } - #[test] - fn directed_edges() { - test::directed_edges(<$($graph)::+ >::new()) - } - #[test] - fn remove_node_undirected() { - test::remove_node_undirected(<$($graph)::+ >::new()) - } - #[test] - fn remove_node_directed() { - test::remove_node_directed(<$($graph)::+ >::new()) - } - #[test] - fn edge_between_same_node_undirected() { - test::edge_between_same_node(<$($graph)::+ >::new()) - } - #[test] - fn edge_between_same_node_directed() { - test::edge_between_same_node(<$($graph)::+ >::new()) - } - }; - } - - pub fn nodes(mut graph: impl SimpleGraph) { - let jake = graph.add_node(Person::Jake); - let michael = graph.add_node(Person::Michael); - let jennifer = graph.add_node(Person::Jennifer); - let other_jake = graph.add_node(Person::Jake); - - assert_eq!(graph.get_node(jake).unwrap(), &Person::Jake); - assert_eq!(graph.get_node(michael).unwrap(), &Person::Michael); - assert_eq!(graph.get_node(jennifer).unwrap(), &Person::Jennifer); - assert_eq!(graph.get_node(other_jake).unwrap(), &Person::Jake); - - graph - .get_node_mut(jake) - .map(|node| *node = Person::Michael) - .unwrap(); - - assert_eq!(graph.get_node(jake).unwrap(), &Person::Michael); - assert_eq!(graph.get_node(michael).unwrap(), &Person::Michael); - assert_eq!(graph.get_node(jennifer).unwrap(), &Person::Jennifer); - assert_eq!(graph.get_node(other_jake).unwrap(), &Person::Jake); - - assert!(graph.remove_node(jake).is_ok()); - assert!(graph.remove_node(michael).is_ok()); - assert!(graph.remove_node(jennifer).is_ok()); - assert!(graph.remove_node(other_jake).is_ok()); - - assert!(graph.get_node(jake).is_err()); - assert!(graph.get_node(michael).is_err()); - assert!(graph.get_node(jennifer).is_err()); - assert!(graph.get_node(other_jake).is_err()); - } - - pub fn undirected_edges(mut graph: impl SimpleGraph) { - let jake = graph.add_node(Person::Jake); - let michael = graph.add_node(Person::Michael); - let jennifer = graph.add_node(Person::Jennifer); - let other_jake = graph.add_node(Person::Jake); - - let jm = graph.new_edge(jake, michael, 2).unwrap(); - let jj = graph.new_edge(jennifer, jake, 7).unwrap(); - let jo = graph.new_edge(jake, other_jake, 5).unwrap(); - let mo = graph.new_edge(michael, other_jake, 1).unwrap(); - - assert!(unordered_eq( - &graph.edges_of(jake), - &[(michael, jm), (jennifer, jj), (other_jake, jo)] - )); - - assert_eq!(graph.get_edge(jm).unwrap(), &2); - assert_eq!(graph.get_edge(jj).unwrap(), &7); - assert_eq!(graph.get_edge(jo).unwrap(), &5); - assert_eq!(graph.get_edge(mo).unwrap(), &1); - - assert_eq!( - graph.edge_between(jennifer, jake).unwrap(), - graph.edge_between(jake, jennifer).unwrap() - ); - - *graph.get_edge_mut(mo).unwrap() = 10; - - assert_eq!(graph.get_edge(jm).unwrap(), &2); - assert_eq!(graph.get_edge(jj).unwrap(), &7); - assert_eq!(graph.get_edge(jo).unwrap(), &5); - assert_eq!(graph.get_edge(mo).unwrap(), &10); - - assert!(graph.remove_edge(jm).is_ok()); - assert!(graph.remove_edge(jj).is_ok()); - assert!(graph.remove_edge(jo).is_ok()); - assert!(graph.remove_edge(mo).is_ok()); - - assert!(graph.get_edge(jm).is_err()); - assert!(graph.get_edge(jj).is_err()); - assert!(graph.get_edge(jo).is_err()); - assert!(graph.get_edge(mo).is_err()); - } - - pub fn directed_edges(mut graph: impl SimpleGraph) { - let jake = graph.add_node(Person::Jake); - let michael = graph.add_node(Person::Michael); - let jennifer = graph.add_node(Person::Jennifer); - let other_jake = graph.add_node(Person::Jake); - - let jm = graph.new_edge(jake, michael, 2).unwrap(); - let jj = graph.new_edge(jennifer, jake, 7).unwrap(); - let jo = graph.new_edge(jake, other_jake, 5).unwrap(); - let mo = graph.new_edge(michael, other_jake, 1).unwrap(); - - assert!(unordered_eq( - &graph.edges_of(jake), - &[(michael, jm), (other_jake, jo)] - )); - - assert_eq!(graph.get_edge(jm).unwrap(), &2); - assert_eq!(graph.get_edge(jj).unwrap(), &7); - assert_eq!(graph.get_edge(jo).unwrap(), &5); - assert_eq!(graph.get_edge(mo).unwrap(), &1); - - assert!(graph.edge_between(jennifer, jake).unwrap().is_some()); - assert!(graph.edge_between(jake, jennifer).unwrap().is_none()); - - *graph.get_edge_mut(mo).unwrap() = 10; - - assert_eq!(graph.get_edge(jm).unwrap(), &2); - assert_eq!(graph.get_edge(jj).unwrap(), &7); - assert_eq!(graph.get_edge(jo).unwrap(), &5); - assert_eq!(graph.get_edge(mo).unwrap(), &10); - - assert!(graph.remove_edge(jm).is_ok()); - assert!(graph.remove_edge(jj).is_ok()); - assert!(graph.remove_edge(jo).is_ok()); - assert!(graph.remove_edge(mo).is_ok()); - - assert!(graph.get_edge(jm).is_err()); - assert!(graph.get_edge(jj).is_err()); - assert!(graph.get_edge(jo).is_err()); - assert!(graph.get_edge(mo).is_err()); - } - - pub fn remove_node_undirected(mut graph: impl SimpleGraph) { - let jake = graph.add_node(Person::Jake); - let michael = graph.add_node(Person::Michael); - - let edge = graph.new_edge(jake, michael, 20).unwrap(); - - assert!(graph.get_node(jake).is_ok()); - assert!(graph.get_node(michael).is_ok()); - assert_eq!(graph.get_edge(edge).unwrap(), &20); - assert_eq!( - graph - .edge_between(jake, michael) - .unwrap() - .unwrap() - .get(&graph) - .unwrap(), - &20 - ); - assert_eq!( - graph - .edge_between(michael, jake) - .unwrap() - .unwrap() - .get(&graph) - .unwrap(), - &20 - ); - - assert!(graph.remove_node(michael).is_ok()); - - assert!(graph.get_node(jake).is_ok()); - assert!(graph.get_node(michael).is_err()); - assert!(graph.get_edge(edge).is_err()); - assert!(graph.edge_between(jake, michael).unwrap().is_none()); - assert!(graph.edge_between(michael, jake).is_err()); - } - - pub fn remove_node_directed(mut graph: impl SimpleGraph) { - let jake = graph.add_node(Person::Jake); - let michael = graph.add_node(Person::Michael); - - let edge = graph.new_edge(jake, michael, 20).unwrap(); - - assert!(graph.get_node(jake).is_ok()); - assert!(graph.get_node(michael).is_ok()); - assert_eq!(graph.get_edge(edge).unwrap(), &20); - assert_eq!( - graph - .edge_between(jake, michael) - .unwrap() - .unwrap() - .get(&graph) - .unwrap(), - &20 - ); - assert!(graph.edge_between(michael, jake).unwrap().is_none()); - - assert!(graph.remove_node(michael).is_ok()); - - assert!(graph.get_node(jake).is_ok()); - assert!(graph.get_node(michael).is_err()); - assert!(graph.get_edge(edge).is_err()); - assert!(graph.edge_between(jake, michael).unwrap().is_none()); - assert!(graph.edge_between(michael, jake).is_err()); - } - - pub fn edge_between_same_node(mut graph: impl SimpleGraph) { - let jake = graph.add_node(Person::Jake); - - assert!(matches!( - graph.new_edge(jake, jake, 20), - Err(GraphError::EdgeBetweenSameNode(node)) if node == jake - )); - } - - fn unordered_eq(a: &[T], b: &[T]) -> bool - where - T: Eq + Hash, - { - let a: HashSet<_> = a.iter().collect(); - let b: HashSet<_> = b.iter().collect(); - - a == b - } -} diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index 6cd4a7ef2836a..e4b401ae6a0ea 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -7,3 +7,5 @@ pub mod algos; pub mod error; /// The `Graph` trait and all graph implementations pub mod graphs; +/// Utils used by graphs +pub mod utils; diff --git a/crates/bevy_graph/src/utils/mod.rs b/crates/bevy_graph/src/utils/mod.rs new file mode 100644 index 0000000000000..6e0306eb91cf2 --- /dev/null +++ b/crates/bevy_graph/src/utils/mod.rs @@ -0,0 +1,2 @@ +/// Map-like methods for `Vec<(K, V)>` +pub mod vecmap; diff --git a/crates/bevy_graph/src/utils/vecmap.rs b/crates/bevy_graph/src/utils/vecmap.rs new file mode 100644 index 0000000000000..0e4508b24b229 --- /dev/null +++ b/crates/bevy_graph/src/utils/vecmap.rs @@ -0,0 +1,87 @@ +/// Map-like methods for `Vec<(K, V)>` +pub trait VecMap { + /// Gets an immutable reference to value by key + fn get_value(&self, key: K) -> Option<&V>; + + /// Gets a mutable reference to value by key + fn get_value_mut(&mut self, key: K) -> Option<&mut V>; + + /// Gets an immutable reference to value by key + unsafe fn get_value_unchecked(&self, key: K) -> &V; + + /// Gets a mutable reference to value by key + unsafe fn get_value_unchecked_mut(&mut self, key: K) -> &mut V; + + /// Gets an immutable reference to value by key and inserts by closure when it's not preset + fn get_value_or(&mut self, key: K, or: fn() -> V) -> &V; + + /// Gets an immutable reference to value by key and inserts by closure when it's not preset + fn get_value_or_mut(&mut self, key: K, or: fn() -> V) -> &mut V; + + /// Gets an immutable reference to value by key and inserts the default when it's not preset + fn get_value_or_default(&mut self, key: K) -> &V + where + V: Default, + { + self.get_value_or(key, Default::default) + } + + /// Gets a mutable reference to value by key and inserts the default when it's not preset + fn get_value_or_default_mut(&mut self, key: K) -> &mut V + where + V: Default, + { + self.get_value_or_mut(key, Default::default) + } + + /// Returns `true` if the given key is preset + fn contains_key(&self, key: K) -> bool; +} + +impl VecMap for Vec<(K, V)> { + fn get_value(&self, key: K) -> Option<&V> { + match self.iter().find(|l| l.0 == key) { + Some((_, v)) => Some(v), + None => None, + } + } + + fn get_value_mut(&mut self, key: K) -> Option<&mut V> { + match self.iter_mut().find(|l| l.0 == key) { + Some((_, v)) => Some(v), + None => None, + } + } + + unsafe fn get_value_unchecked(&self, key: K) -> &V { + &self.iter().find(|l| l.0 == key).unwrap_unchecked().1 + } + + unsafe fn get_value_unchecked_mut(&mut self, key: K) -> &mut V { + &mut self.iter_mut().find(|l| l.0 == key).unwrap_unchecked().1 + } + + fn get_value_or(&mut self, key: K, or: fn() -> V) -> &V { + match self.iter().find(|l| l.0 == key) { + Some((_, v)) => v, + None => { + self.push((key, or())); + unsafe { &self.last().unwrap_unchecked().1 } + } + } + } + + fn get_value_or_mut(&mut self, key: K, or: fn() -> V) -> &mut V { + match self.iter_mut().find(|l| l.0 == key) { + Some((_, v)) => v, + None => { + self.push((key, or())); + unsafe { &mut self.last_mut().unwrap_unchecked().1 } + } + } + } + + fn contains_key(&self, key: K) -> bool { + self.iter().any(|l| l.0 == key) + } +} From d17030659a63921042c4c4aca24b5a036467bb98 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 17 Jan 2023 16:40:45 +0100 Subject: [PATCH 112/183] `remove_edge` --- crates/bevy_graph/src/graphs/edge.rs | 17 +----------- crates/bevy_graph/src/graphs/mod.rs | 6 +++++ crates/bevy_graph/src/graphs/multi/list.rs | 30 +++++++++++++++++++-- crates/bevy_graph/src/graphs/multi/map.rs | 29 +++++++++++++++++++- crates/bevy_graph/src/graphs/simple/list.rs | 20 +++++++++++++- crates/bevy_graph/src/graphs/simple/map.rs | 22 +++++++++++++-- crates/bevy_graph/src/utils/mod.rs | 2 ++ crates/bevy_graph/src/utils/vecmap.rs | 18 +++++++++++++ crates/bevy_graph/src/utils/vecset.rs | 19 +++++++++++++ 9 files changed, 141 insertions(+), 22 deletions(-) create mode 100644 crates/bevy_graph/src/utils/vecset.rs diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs index 86179682a5806..852c59f0ee8bb 100644 --- a/crates/bevy_graph/src/graphs/edge.rs +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -2,19 +2,4 @@ use super::keys::NodeIdx; /// An edge between nodes that store data of type `E`. #[derive(Clone)] -pub struct Edge { - /// the `NodeIdx` of the source node - pub src: NodeIdx, - /// the `NodeIdx` of the destination node - pub dst: NodeIdx, - /// the edge value - pub value: E, -} - -impl Edge { - /// Returns the `src` and `dst` of the edge as a tuple - #[inline] - pub const fn indices(&self) -> (NodeIdx, NodeIdx) { - (self.src, self.dst) - } -} +pub struct Edge(pub NodeIdx, pub NodeIdx, pub E); diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 29e2e80b23789..1ef99cfde197b 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -65,6 +65,12 @@ pub trait Graph { /// /// Panics if `src` or `dst` do not exist. fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool; + + /// Removes the specified node from the graph, returning its value if it existed. + fn remove_node(&mut self, index: NodeIdx) -> Option; + + /// Removes the specified edge from the graph, returning its value if it existed. + fn remove_edge(&mut self, index: EdgeIdx) -> Option; } /// A more precise trait with functions special for a simple graph diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 40215d73eee84..1e5dcddef4ba1 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -7,7 +7,7 @@ use crate::{ keys::{EdgeIdx, NodeIdx}, Graph, }, - utils::vecmap::VecMap, + utils::{vecmap::VecMap, vecset::VecSet}, }; /// Implementation of a `MultiGraph` which uses `Vec<(NodeIdx, Vec)>` for adjacencies @@ -65,7 +65,7 @@ impl Graph for MultiListGraph } unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { src, dst, value }); + let idx = self.edges.insert(Edge(src, dst, value)); self.adjacencies .get_unchecked_mut(src) .get_value_or_default_mut(dst) @@ -87,4 +87,30 @@ impl Graph for MultiListGraph fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { self.adjacencies.get(src).unwrap().contains_key(dst) } + + fn remove_node(&mut self, index: NodeIdx) -> Option { + todo!() + } + + fn remove_edge(&mut self, index: EdgeIdx) -> Option { + if let Some(Edge(src, dst, value)) = self.edges.remove(index) { + unsafe { + self.adjacencies + .get_unchecked_mut(src) + .get_value_mut(dst) + .unwrap() + .remove_by_value(&index); + if !DIRECTED { + self.adjacencies + .get_unchecked_mut(dst) + .get_value_mut(src) + .unwrap() + .remove_by_value(&index); + } + } + Some(value) + } else { + None + } + } } diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index f3eedfd980978..119a70dd78d79 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -8,6 +8,7 @@ use crate::{ keys::{EdgeIdx, NodeIdx}, Graph, }, + utils::vecset::VecSet, }; /// Implementation of a `MultiGraph` which uses `HashMap>` for adjacencies @@ -66,7 +67,7 @@ impl Graph for MultiMapGraph { } unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { src, dst, value }); + let idx = self.edges.insert(Edge(src, dst, value)); self.adjacencies .get_unchecked_mut(src) .entry(dst) @@ -90,4 +91,30 @@ impl Graph for MultiMapGraph { fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { self.adjacencies.get(src).unwrap().contains_key(&dst) } + + fn remove_node(&mut self, index: NodeIdx) -> Option { + todo!() + } + + fn remove_edge(&mut self, index: EdgeIdx) -> Option { + if let Some(Edge(src, dst, value)) = self.edges.remove(index) { + unsafe { + self.adjacencies + .get_unchecked_mut(src) + .get_mut(&dst) + .unwrap() + .remove_by_value(&index); + if !DIRECTED { + self.adjacencies + .get_unchecked_mut(dst) + .get_mut(&src) + .unwrap() + .remove_by_value(&index); + } + } + Some(value) + } else { + None + } + } } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 7479f9f7c883a..ac7145df28b1f 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -70,7 +70,7 @@ impl Graph for SimpleListGraph } unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { src, dst, value }); + let idx = self.edges.insert(Edge(src, dst, value)); self.adjacencies.get_unchecked_mut(src).push((dst, idx)); if !DIRECTED { self.adjacencies.get_unchecked_mut(dst).push((src, idx)); @@ -86,4 +86,22 @@ impl Graph for SimpleListGraph fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { unsafe { self.adjacencies.get(src).unwrap().contains_key(dst) } } + + fn remove_node(&mut self, index: NodeIdx) -> Option { + todo!() + } + + fn remove_edge(&mut self, index: EdgeIdx) -> Option { + if let Some(Edge(src, dst, value)) = self.edges.remove(index) { + unsafe { + self.adjacencies.get_unchecked_mut(src).remove_by_key(dst); + if !DIRECTED { + self.adjacencies.get_unchecked_mut(dst).remove_by_key(src); + } + } + Some(value) + } else { + None + } + } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index ab20744c5a97f..54789bc99b888 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -70,7 +70,7 @@ impl Graph for SimpleMapGraph } unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { - let idx = self.edges.insert(Edge { src, dst, value }); + let idx = self.edges.insert(Edge(src, dst, value)); self.adjacencies.get_unchecked_mut(src).insert(dst, idx); if !DIRECTED { self.adjacencies.get_unchecked_mut(dst).insert(src, idx); @@ -84,6 +84,24 @@ impl Graph for SimpleMapGraph } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - self.adjacencies.get(src).unwrap().contains_key(&dst) + self.adjacencies[src].contains_key(&dst) + } + + fn remove_node(&mut self, index: NodeIdx) -> Option { + todo!() + } + + fn remove_edge(&mut self, index: EdgeIdx) -> Option { + if let Some(Edge(src, dst, value)) = self.edges.remove(index) { + unsafe { + self.adjacencies.get_unchecked_mut(src).remove(&dst); + if !DIRECTED { + self.adjacencies.get_unchecked_mut(dst).remove(&src); + } + } + Some(value) + } else { + None + } } } diff --git a/crates/bevy_graph/src/utils/mod.rs b/crates/bevy_graph/src/utils/mod.rs index 6e0306eb91cf2..71cc2ca152202 100644 --- a/crates/bevy_graph/src/utils/mod.rs +++ b/crates/bevy_graph/src/utils/mod.rs @@ -1,2 +1,4 @@ /// Map-like methods for `Vec<(K, V)>` pub mod vecmap; +/// Set-like methods for `Vec` +pub mod vecset; diff --git a/crates/bevy_graph/src/utils/vecmap.rs b/crates/bevy_graph/src/utils/vecmap.rs index 0e4508b24b229..8d6c921bf3601 100644 --- a/crates/bevy_graph/src/utils/vecmap.rs +++ b/crates/bevy_graph/src/utils/vecmap.rs @@ -36,6 +36,12 @@ pub trait VecMap { /// Returns `true` if the given key is preset fn contains_key(&self, key: K) -> bool; + + /// Gets the index by the key + fn index_by_key(&self, key: K) -> Option; + + /// Removes the entry by the key + fn remove_by_key(&mut self, key: K) -> Option; } impl VecMap for Vec<(K, V)> { @@ -84,4 +90,16 @@ impl VecMap for Vec<(K, V)> { fn contains_key(&self, key: K) -> bool { self.iter().any(|l| l.0 == key) } + + fn index_by_key(&self, key: K) -> Option { + self.iter().position(|l| l.0 == key) + } + + fn remove_by_key(&mut self, key: K) -> Option { + if let Some(index) = self.index_by_key(key) { + Some(self.remove(index).1) + } else { + None + } + } } diff --git a/crates/bevy_graph/src/utils/vecset.rs b/crates/bevy_graph/src/utils/vecset.rs new file mode 100644 index 0000000000000..eb028eeac947a --- /dev/null +++ b/crates/bevy_graph/src/utils/vecset.rs @@ -0,0 +1,19 @@ +/// Set-like methods for `Vec` +pub trait VecSet { + fn index_by_value(&self, value: &T) -> Option; + fn remove_by_value(&mut self, value: &T) -> Option; +} + +impl VecSet for Vec { + fn index_by_value(&self, value: &T) -> Option { + self.iter().position(|l| l == value) + } + + fn remove_by_value(&mut self, value: &T) -> Option { + if let Some(index) = self.index_by_value(value) { + Some(self.remove(index)) + } else { + None + } + } +} From 3a6f22a36165d7de0228f3391e439defb912f931 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 17 Jan 2023 16:47:11 +0100 Subject: [PATCH 113/183] changes to `add_edge` signature --- crates/bevy_graph/src/algos/bfs.rs | 12 +++--- crates/bevy_graph/src/algos/dfs.rs | 12 +++--- crates/bevy_graph/src/graphs/mod.rs | 12 +++++- crates/bevy_graph/src/graphs/multi/list.rs | 37 ++++++++++--------- crates/bevy_graph/src/graphs/multi/map.rs | 41 +++++++++++---------- crates/bevy_graph/src/graphs/simple/list.rs | 25 +++++++------ crates/bevy_graph/src/graphs/simple/map.rs | 25 +++++++------ 7 files changed, 90 insertions(+), 74 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 9d4d66e02ab37..aeec463586508 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -135,13 +135,11 @@ mod test { let two = graph.add_node(2); let three = graph.add_node(3); - unsafe { - graph.add_edge_unchecked(zero, one, ()); - graph.add_edge_unchecked(zero, two, ()); - graph.add_edge_unchecked(one, two, ()); - graph.add_edge_unchecked(two, zero, ()); - graph.add_edge_unchecked(two, three, ()); - } + graph.add_edge(zero, one, ()); + graph.add_edge(zero, two, ()); + graph.add_edge(one, two, ()); + graph.add_edge(two, zero, ()); + graph.add_edge(two, three, ()); let elements = vec![0, 2, 1, 3]; diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index d37ccfd18d82d..ebe6d609ca0e4 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -132,13 +132,11 @@ mod test { let two = graph.add_node(2); let three = graph.add_node(3); - unsafe { - graph.add_edge_unchecked(zero, one, ()); - graph.add_edge_unchecked(zero, two, ()); - graph.add_edge_unchecked(one, two, ()); - graph.add_edge_unchecked(two, zero, ()); - graph.add_edge_unchecked(two, three, ()); - } + graph.add_edge(zero, one, ()); + graph.add_edge(zero, two, ()); + graph.add_edge(one, two, ()); + graph.add_edge(two, zero, ()); + graph.add_edge(two, three, ()); let elements = vec![0, 1, 2, 3]; diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 1ef99cfde197b..0a7331a214941 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -51,10 +51,18 @@ pub trait Graph { /// * `GraphError::NodeNotFound(NodeIdx)`: the given `src` or `dst` isn't preset in the graph /// * `GraphError::ContainsEdgeBetween`: there is already an edge between those nodes (not allowed in `SimpleGraph`) /// * `GraphError::Loop`: the `src` and `dst` nodes are equal, the edge would be a loop (not allowed in `SimpleGraph`) - fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> Result; + fn try_add_edge(&mut self, src: NodeIdx, dst: NodeIdx, value: E) + -> Result; /// Adds an edge between the specified nodes with the associated `value`. - unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx; + /// + /// # Panics + /// + /// look at the `Returns/Err` in the docs from [`Graph::try_add_edge`] + #[inline] + fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { + self.try_add_edge(src, dst, value).unwrap() + } /// Returns `true` if the `node` is preset in the graph. fn has_node(&self, node: NodeIdx) -> bool; diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 1e5dcddef4ba1..87af1ae2ccf2f 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -54,29 +54,32 @@ impl Graph for MultiListGraph idx } - fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> Result { + fn try_add_edge( + &mut self, + src: NodeIdx, + dst: NodeIdx, + value: E, + ) -> Result { if !self.has_node(src) { Err(GraphError::NodeNotFound(src)) } else if !self.has_node(dst) { Err(GraphError::NodeNotFound(dst)) } else { - unsafe { Ok(self.add_edge_unchecked(src, dst, value)) } - } - } - - unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { - let idx = self.edges.insert(Edge(src, dst, value)); - self.adjacencies - .get_unchecked_mut(src) - .get_value_or_default_mut(dst) - .push(idx); - if !DIRECTED { - self.adjacencies - .get_unchecked_mut(dst) - .get_value_or_default_mut(src) - .push(idx); + unsafe { + let idx = self.edges.insert(Edge(src, dst, value)); + self.adjacencies + .get_unchecked_mut(src) + .get_value_or_default_mut(dst) + .push(idx); + if !DIRECTED { + self.adjacencies + .get_unchecked_mut(dst) + .get_value_or_default_mut(src) + .push(idx); + } + Ok(idx) + } } - idx } #[inline] diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 119a70dd78d79..7052258067d54 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -56,31 +56,34 @@ impl Graph for MultiMapGraph { idx } - fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> Result { + fn try_add_edge( + &mut self, + src: NodeIdx, + dst: NodeIdx, + value: E, + ) -> Result { if !self.has_node(src) { Err(GraphError::NodeNotFound(src)) } else if !self.has_node(dst) { Err(GraphError::NodeNotFound(dst)) } else { - unsafe { Ok(self.add_edge_unchecked(src, dst, value)) } - } - } - - unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { - let idx = self.edges.insert(Edge(src, dst, value)); - self.adjacencies - .get_unchecked_mut(src) - .entry(dst) - .or_default() - .push(idx); - if !DIRECTED { - self.adjacencies - .get_unchecked_mut(dst) - .entry(src) - .or_default() - .push(idx); + unsafe { + let idx = self.edges.insert(Edge(src, dst, value)); + self.adjacencies + .get_unchecked_mut(src) + .entry(dst) + .or_default() + .push(idx); + if !DIRECTED { + self.adjacencies + .get_unchecked_mut(dst) + .entry(src) + .or_default() + .push(idx); + } + Ok(idx) + } } - idx } #[inline] diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index ac7145df28b1f..fae44e8d1ac10 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -55,7 +55,12 @@ impl Graph for SimpleListGraph idx } - fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> Result { + fn try_add_edge( + &mut self, + src: NodeIdx, + dst: NodeIdx, + value: E, + ) -> Result { if !self.has_node(src) { Err(GraphError::NodeNotFound(src)) } else if !self.has_node(dst) { @@ -65,17 +70,15 @@ impl Graph for SimpleListGraph } else if src == dst { Err(GraphError::Loop) } else { - unsafe { Ok(self.add_edge_unchecked(src, dst, value)) } - } - } - - unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { - let idx = self.edges.insert(Edge(src, dst, value)); - self.adjacencies.get_unchecked_mut(src).push((dst, idx)); - if !DIRECTED { - self.adjacencies.get_unchecked_mut(dst).push((src, idx)); + unsafe { + let idx = self.edges.insert(Edge(src, dst, value)); + self.adjacencies.get_unchecked_mut(src).push((dst, idx)); + if !DIRECTED { + self.adjacencies.get_unchecked_mut(dst).push((src, idx)); + } + Ok(idx) + } } - idx } #[inline] diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 54789bc99b888..31cc7653688cc 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -55,7 +55,12 @@ impl Graph for SimpleMapGraph idx } - fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> Result { + fn try_add_edge( + &mut self, + src: NodeIdx, + dst: NodeIdx, + value: E, + ) -> Result { if !self.has_node(src) { Err(GraphError::NodeNotFound(src)) } else if !self.has_node(dst) { @@ -65,17 +70,15 @@ impl Graph for SimpleMapGraph } else if src == dst { Err(GraphError::Loop) } else { - unsafe { Ok(self.add_edge_unchecked(src, dst, value)) } - } - } - - unsafe fn add_edge_unchecked(&mut self, src: NodeIdx, dst: NodeIdx, value: E) -> EdgeIdx { - let idx = self.edges.insert(Edge(src, dst, value)); - self.adjacencies.get_unchecked_mut(src).insert(dst, idx); - if !DIRECTED { - self.adjacencies.get_unchecked_mut(dst).insert(src, idx); + unsafe { + let idx = self.edges.insert(Edge(src, dst, value)); + self.adjacencies.get_unchecked_mut(src).insert(dst, idx); + if !DIRECTED { + self.adjacencies.get_unchecked_mut(dst).insert(src, idx); + } + Ok(idx) + } } - idx } #[inline] From 4a548f7f5db784a24b63352084b1ae232e7d19d1 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 17 Jan 2023 16:50:15 +0100 Subject: [PATCH 114/183] `clear_edges` and `clear` --- crates/bevy_graph/src/graphs/mod.rs | 6 ++++++ crates/bevy_graph/src/graphs/multi/list.rs | 11 +++++++++++ crates/bevy_graph/src/graphs/multi/map.rs | 11 +++++++++++ crates/bevy_graph/src/graphs/simple/list.rs | 11 +++++++++++ crates/bevy_graph/src/graphs/simple/map.rs | 11 +++++++++++ 5 files changed, 50 insertions(+) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 0a7331a214941..ce9834ead2d57 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -79,6 +79,12 @@ pub trait Graph { /// Removes the specified edge from the graph, returning its value if it existed. fn remove_edge(&mut self, index: EdgeIdx) -> Option; + + /// Removes all edges from the graph. + fn clear_edges(&mut self); + + /// Removes all nodes and edges from the graph. + fn clear(&mut self); } /// A more precise trait with functions special for a simple graph diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 87af1ae2ccf2f..e31805d4e557a 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -116,4 +116,15 @@ impl Graph for MultiListGraph None } } + + fn clear_edges(&mut self) { + self.adjacencies.values_mut().for_each(|list| list.clear()); + self.edges.clear(); + } + + fn clear(&mut self) { + self.adjacencies.clear(); + self.edges.clear(); + self.nodes.clear(); + } } diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 7052258067d54..d0095eb123671 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -120,4 +120,15 @@ impl Graph for MultiMapGraph { None } } + + fn clear_edges(&mut self) { + self.adjacencies.values_mut().for_each(|map| map.clear()); + self.edges.clear(); + } + + fn clear(&mut self) { + self.adjacencies.clear(); + self.edges.clear(); + self.nodes.clear(); + } } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index fae44e8d1ac10..d3b9e945dabad 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -107,4 +107,15 @@ impl Graph for SimpleListGraph None } } + + fn clear_edges(&mut self) { + self.adjacencies.values_mut().for_each(|list| list.clear()); + self.edges.clear(); + } + + fn clear(&mut self) { + self.adjacencies.clear(); + self.edges.clear(); + self.nodes.clear(); + } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 31cc7653688cc..f372a20988214 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -107,4 +107,15 @@ impl Graph for SimpleMapGraph None } } + + fn clear_edges(&mut self) { + self.adjacencies.values_mut().for_each(|map| map.clear()); + self.edges.clear(); + } + + fn clear(&mut self) { + self.adjacencies.clear(); + self.edges.clear(); + self.nodes.clear(); + } } From 840f53a95a3309bcfa5e3e8ca9b4cbad895f95d1 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 17 Jan 2023 17:48:06 +0100 Subject: [PATCH 115/183] getting nodes and edges --- crates/bevy_graph/src/algos/bfs.rs | 52 --------------------- crates/bevy_graph/src/algos/dfs.rs | 52 --------------------- crates/bevy_graph/src/graphs/mod.rs | 12 +++++ crates/bevy_graph/src/graphs/multi/list.rs | 28 +++++++++++ crates/bevy_graph/src/graphs/multi/map.rs | 28 +++++++++++ crates/bevy_graph/src/graphs/simple/list.rs | 28 +++++++++++ crates/bevy_graph/src/graphs/simple/map.rs | 28 +++++++++++ 7 files changed, 124 insertions(+), 104 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index aeec463586508..d3e12a6da9fdf 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -51,32 +51,6 @@ impl BreadthFirstSearch { } } - /// Gets an immutable reference to the value of the next node from the algorithm - /// - /// # Safety - /// - /// This function should only be called when the node from the edge exists. - /// This can happen when a node or edge gets removed but its index is still present in the BFS. - pub unsafe fn next_unchecked<'g, N, E>( - &mut self, - graph: &'g impl Graph, - ) -> Option<&'g N> { - if let Some(node) = self.queue.pop_front() { - for (idx, _) in graph.edges_of(node) { - if !self.visited.contains(&idx) { - self.visited.insert(idx); - self.queue.push_back(idx); - } - } - unsafe { - // SAFETY: the caller says its fine - Some(graph.get_node_unchecked(node)) - } - } else { - None - } - } - /// Gets a mutable reference to the value of the next node from the algorithm. pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.queue.pop_front() { @@ -91,32 +65,6 @@ impl BreadthFirstSearch { None } } - - /// Gets a mutable reference to the value of the next node from the algorithm. - /// - /// # Safety - /// - /// This function should only be called when the node from the edge exists. - /// This can happen when a node or edge gets removed but its index is still present in the BFS. - pub unsafe fn next_unchecked_mut<'g, N, E>( - &mut self, - graph: &'g mut impl Graph, - ) -> Option<&'g mut N> { - if let Some(node) = self.queue.pop_front() { - for (idx, _) in graph.edges_of(node) { - if !self.visited.contains(&idx) { - self.visited.insert(idx); - self.queue.push_back(idx); - } - } - unsafe { - // SAFETY: the caller says its fine - Some(graph.get_node_unchecked_mut(node)) - } - } else { - None - } - } } #[cfg(test)] diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index ebe6d609ca0e4..7846360d4d751 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -48,32 +48,6 @@ impl DepthFirstSearch { } } - /// Gets a reference to the value of the next node from the algorithm. - /// - /// # Safety - /// - /// This function should only be called when the node from the edge exists. - /// This can happen when a node or edge gets removed but its index is still present in the DFS. - pub unsafe fn next_unchecked<'g, N, E>( - &mut self, - graph: &'g impl Graph, - ) -> Option<&'g N> { - if let Some(node) = self.stack.pop() { - for (idx, _) in graph.edges_of(node) { - if !self.visited.contains(&idx) { - self.visited.insert(idx); - self.stack.push(idx); - } - } - unsafe { - // SAFETY: the caller says its fine - Some(graph.get_node_unchecked(node)) - } - } else { - None - } - } - /// Gets a mutable reference to the value of the next node from the algorithm. pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.stack.pop() { @@ -88,32 +62,6 @@ impl DepthFirstSearch { None } } - - /// Gets a mutable reference to the value of the next node from the algorythm - /// - /// # Safety - /// - /// This function should only be called when the node from the edge exists. - /// This can happen when a node or edge gets removed but its index is still present in the DFS. - pub unsafe fn next_unchecked_mut<'g, N, E>( - &mut self, - graph: &'g mut impl Graph, - ) -> Option<&'g mut N> { - if let Some(node) = self.stack.pop() { - for (idx, _) in graph.edges_of(node) { - if !self.visited.contains(&idx) { - self.visited.insert(idx); - self.stack.push(idx); - } - } - unsafe { - // SAFETY: the caller says its fine - Some(graph.get_node_unchecked_mut(node)) - } - } else { - None - } - } } #[cfg(test)] diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index ce9834ead2d57..f40c72dbaed68 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -85,6 +85,18 @@ pub trait Graph { /// Removes all nodes and edges from the graph. fn clear(&mut self); + + /// Returns a reference to the specified node. + fn get_node(&self, index: NodeIdx) -> Option<&N>; + + /// Returns a mutable reference to the specified node. + fn get_node_mut(&mut self, index: NodeIdx) -> Option<&mut N>; + + /// Returns a reference to the specified edge. + fn get_edge(&self, index: EdgeIdx) -> Option<&E>; + + /// Returns a mutable reference to the specified edge. + fn get_edge_mut(&mut self, index: EdgeIdx) -> Option<&mut E>; } /// A more precise trait with functions special for a simple graph diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index e31805d4e557a..9795706a7619a 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -127,4 +127,32 @@ impl Graph for MultiListGraph self.edges.clear(); self.nodes.clear(); } + + #[inline] + fn get_node(&self, index: NodeIdx) -> Option<&N> { + self.nodes.get(index) + } + + #[inline] + fn get_node_mut(&mut self, index: NodeIdx) -> Option<&mut N> { + self.nodes.get_mut(index) + } + + #[inline] + fn get_edge(&self, index: EdgeIdx) -> Option<&E> { + if let Some(Edge(_, _, value)) = self.edges.get(index) { + Some(value) + } else { + None + } + } + + #[inline] + fn get_edge_mut(&mut self, index: EdgeIdx) -> Option<&mut E> { + if let Some(Edge(_, _, value)) = self.edges.get_mut(index) { + Some(value) + } else { + None + } + } } diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index d0095eb123671..4300247e8e7fe 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -131,4 +131,32 @@ impl Graph for MultiMapGraph { self.edges.clear(); self.nodes.clear(); } + + #[inline] + fn get_node(&self, index: NodeIdx) -> Option<&N> { + self.nodes.get(index) + } + + #[inline] + fn get_node_mut(&mut self, index: NodeIdx) -> Option<&mut N> { + self.nodes.get_mut(index) + } + + #[inline] + fn get_edge(&self, index: EdgeIdx) -> Option<&E> { + if let Some(Edge(_, _, value)) = self.edges.get(index) { + Some(value) + } else { + None + } + } + + #[inline] + fn get_edge_mut(&mut self, index: EdgeIdx) -> Option<&mut E> { + if let Some(Edge(_, _, value)) = self.edges.get_mut(index) { + Some(value) + } else { + None + } + } } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index d3b9e945dabad..1bee79212471e 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -118,4 +118,32 @@ impl Graph for SimpleListGraph self.edges.clear(); self.nodes.clear(); } + + #[inline] + fn get_node(&self, index: NodeIdx) -> Option<&N> { + self.nodes.get(index) + } + + #[inline] + fn get_node_mut(&mut self, index: NodeIdx) -> Option<&mut N> { + self.nodes.get_mut(index) + } + + #[inline] + fn get_edge(&self, index: EdgeIdx) -> Option<&E> { + if let Some(Edge(_, _, value)) = self.edges.get(index) { + Some(value) + } else { + None + } + } + + #[inline] + fn get_edge_mut(&mut self, index: EdgeIdx) -> Option<&mut E> { + if let Some(Edge(_, _, value)) = self.edges.get_mut(index) { + Some(value) + } else { + None + } + } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index f372a20988214..e16d2d76fb86a 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -118,4 +118,32 @@ impl Graph for SimpleMapGraph self.edges.clear(); self.nodes.clear(); } + + #[inline] + fn get_node(&self, index: NodeIdx) -> Option<&N> { + self.nodes.get(index) + } + + #[inline] + fn get_node_mut(&mut self, index: NodeIdx) -> Option<&mut N> { + self.nodes.get_mut(index) + } + + #[inline] + fn get_edge(&self, index: EdgeIdx) -> Option<&E> { + if let Some(Edge(_, _, value)) = self.edges.get(index) { + Some(value) + } else { + None + } + } + + #[inline] + fn get_edge_mut(&mut self, index: EdgeIdx) -> Option<&mut E> { + if let Some(Edge(_, _, value)) = self.edges.get_mut(index) { + Some(value) + } else { + None + } + } } From 0781f40d2de903c1f5dd32ba5dbdcfb1b52a8c3f Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 17 Jan 2023 18:20:56 +0100 Subject: [PATCH 116/183] Add `AdjacencyStorage` --- .../src/graphs/adjacency_storage.rs | 39 ++++++++++++++ crates/bevy_graph/src/graphs/mod.rs | 7 +++ crates/bevy_graph/src/graphs/multi/list.rs | 50 ++++++++++++------ crates/bevy_graph/src/graphs/multi/map.rs | 52 ++++++++++++------- crates/bevy_graph/src/graphs/simple/list.rs | 50 +++++++++++++----- crates/bevy_graph/src/graphs/simple/map.rs | 44 +++++++++++----- 6 files changed, 183 insertions(+), 59 deletions(-) create mode 100644 crates/bevy_graph/src/graphs/adjacency_storage.rs diff --git a/crates/bevy_graph/src/graphs/adjacency_storage.rs b/crates/bevy_graph/src/graphs/adjacency_storage.rs new file mode 100644 index 0000000000000..3c38b758486df --- /dev/null +++ b/crates/bevy_graph/src/graphs/adjacency_storage.rs @@ -0,0 +1,39 @@ +/// Adjacency storage enum helper: `Directed` or `Undirected` +#[derive(Clone)] +pub enum AdjacencyStorage { + /// Undirected graphs share one storage (`S`) for incoming and outgoing edges + Undirected(S), + /// Directed graphs have two storages (`S`) for incoming and outgoing edges + Directed(S, S), +} + +impl AdjacencyStorage { + #[inline] + pub const fn incoming_mut(&mut self) -> &mut S { + match self { + AdjacencyStorage::Undirected(storage) => storage, + AdjacencyStorage::Directed(incoming, _) => incoming, + } + } + + #[inline] + pub const fn outgoing_mut(&mut self) -> &mut S { + match self { + AdjacencyStorage::Undirected(storage) => storage, + AdjacencyStorage::Directed(_, outgoing) => outgoing, + } + } + + #[inline] + pub const fn for_each_mut(&mut self, f: fn(&mut S)) { + match self { + AdjacencyStorage::Undirected(storage) => { + f(storage); + } + AdjacencyStorage::Directed(incoming, outgoing) => { + f(incoming); + f(outgoing); + } + } + } +} diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index f40c72dbaed68..2e6c18104037b 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -3,6 +3,8 @@ pub mod multi; /// All graph types implementing a `SimpleGraph` pub mod simple; +/// Adjacency storage enum helper: `Directed` or `Undirected` +pub mod adjacency_storage; /// An edge between nodes that store data of type `E`. pub mod edge; /// The `NodeIdx` and `EdgeIdx` structs @@ -97,6 +99,11 @@ pub trait Graph { /// Returns a mutable reference to the specified edge. fn get_edge_mut(&mut self, index: EdgeIdx) -> Option<&mut E>; + + /// Returns the number of edges connected to the specified node. + /// + /// In multi-graphs, edges that form self-loops add 2 to the degree. + fn degree(&self, index: NodeIdx) -> usize; } /// A more precise trait with functions special for a simple graph diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 9795706a7619a..600d3589bdcfd 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -3,6 +3,7 @@ use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ error::GraphError, graphs::{ + adjacency_storage::AdjacencyStorage, edge::Edge, keys::{EdgeIdx, NodeIdx}, Graph, @@ -17,7 +18,7 @@ use crate::{ pub struct MultiListGraph { nodes: HopSlotMap, edges: HopSlotMap>, - adjacencies: SecondaryMap)>>, + adjacencies: SecondaryMap)>>>, } impl Graph for MultiListGraph { @@ -50,7 +51,12 @@ impl Graph for MultiListGraph fn add_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); - self.adjacencies.insert(idx, Vec::new()); + let storage = if DIRECTED { + AdjacencyStorage::Directed(Vec::new(), Vec::new()) + } else { + AdjacencyStorage::Undirected(Vec::new()) + }; + self.adjacencies.insert(idx, storage); idx } @@ -69,14 +75,14 @@ impl Graph for MultiListGraph let idx = self.edges.insert(Edge(src, dst, value)); self.adjacencies .get_unchecked_mut(src) + .outgoing_mut() .get_value_or_default_mut(dst) .push(idx); - if !DIRECTED { - self.adjacencies - .get_unchecked_mut(dst) - .get_value_or_default_mut(src) - .push(idx); - } + self.adjacencies + .get_unchecked_mut(dst) + .incoming_mut() + .get_value_or_default_mut(src) + .push(idx); Ok(idx) } } @@ -88,7 +94,11 @@ impl Graph for MultiListGraph } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - self.adjacencies.get(src).unwrap().contains_key(dst) + self.adjacencies + .get(src) + .unwrap() + .outgoing_mut() + .contains_key(dst) } fn remove_node(&mut self, index: NodeIdx) -> Option { @@ -100,16 +110,16 @@ impl Graph for MultiListGraph unsafe { self.adjacencies .get_unchecked_mut(src) + .outgoing_mut() .get_value_mut(dst) .unwrap() .remove_by_value(&index); - if !DIRECTED { - self.adjacencies - .get_unchecked_mut(dst) - .get_value_mut(src) - .unwrap() - .remove_by_value(&index); - } + self.adjacencies + .get_unchecked_mut(dst) + .incoming_mut() + .get_value_mut(src) + .unwrap() + .remove_by_value(&index); } Some(value) } else { @@ -118,7 +128,9 @@ impl Graph for MultiListGraph } fn clear_edges(&mut self) { - self.adjacencies.values_mut().for_each(|list| list.clear()); + self.adjacencies + .values_mut() + .for_each(|list| list.for_each_mut(Vec::clear)); self.edges.clear(); } @@ -155,4 +167,8 @@ impl Graph for MultiListGraph None } } + + fn degree(&self, index: NodeIdx) -> usize { + todo!() + } } diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 4300247e8e7fe..9c1b012e154e7 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -4,6 +4,7 @@ use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ error::GraphError, graphs::{ + adjacency_storage::AdjacencyStorage, edge::Edge, keys::{EdgeIdx, NodeIdx}, Graph, @@ -18,7 +19,7 @@ use crate::{ pub struct MultiMapGraph { nodes: HopSlotMap, edges: HopSlotMap>, - adjacencies: SecondaryMap>>, + adjacencies: SecondaryMap>>>, } impl Graph for MultiMapGraph { @@ -52,7 +53,12 @@ impl Graph for MultiMapGraph { fn add_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); - self.adjacencies.insert(idx, HashMap::new()); + let storage = if DIRECTED { + AdjacencyStorage::Directed(HashMap::new(), HashMap::new()) + } else { + AdjacencyStorage::Undirected(HashMap::new()) + }; + self.adjacencies.insert(idx, storage); idx } @@ -71,16 +77,16 @@ impl Graph for MultiMapGraph { let idx = self.edges.insert(Edge(src, dst, value)); self.adjacencies .get_unchecked_mut(src) + .outgoing_mut() .entry(dst) .or_default() .push(idx); - if !DIRECTED { - self.adjacencies - .get_unchecked_mut(dst) - .entry(src) - .or_default() - .push(idx); - } + self.adjacencies + .get_unchecked_mut(dst) + .incoming_mut() + .entry(src) + .or_default() + .push(idx); Ok(idx) } } @@ -92,7 +98,11 @@ impl Graph for MultiMapGraph { } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - self.adjacencies.get(src).unwrap().contains_key(&dst) + self.adjacencies + .get(src) + .unwrap() + .outgoing_mut() + .contains_key(&dst) } fn remove_node(&mut self, index: NodeIdx) -> Option { @@ -104,16 +114,16 @@ impl Graph for MultiMapGraph { unsafe { self.adjacencies .get_unchecked_mut(src) + .outgoing_mut() .get_mut(&dst) .unwrap() .remove_by_value(&index); - if !DIRECTED { - self.adjacencies - .get_unchecked_mut(dst) - .get_mut(&src) - .unwrap() - .remove_by_value(&index); - } + self.adjacencies + .get_unchecked_mut(dst) + .incoming_mut() + .get_mut(&src) + .unwrap() + .remove_by_value(&index); } Some(value) } else { @@ -122,7 +132,9 @@ impl Graph for MultiMapGraph { } fn clear_edges(&mut self) { - self.adjacencies.values_mut().for_each(|map| map.clear()); + self.adjacencies + .values_mut() + .for_each(|map| map.for_each_mut(HashMap::clear)); self.edges.clear(); } @@ -159,4 +171,8 @@ impl Graph for MultiMapGraph { None } } + + fn degree(&self, index: NodeIdx) -> usize { + todo!() + } } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 1bee79212471e..e2227b0f32499 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -3,6 +3,7 @@ use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ error::GraphError, graphs::{ + adjacency_storage::AdjacencyStorage, edge::Edge, keys::{EdgeIdx, NodeIdx}, Graph, @@ -17,7 +18,7 @@ use crate::{ pub struct SimpleListGraph { nodes: HopSlotMap, edges: HopSlotMap>, - adjacencies: SecondaryMap>, + adjacencies: SecondaryMap>>, } impl Graph for SimpleListGraph { @@ -51,7 +52,12 @@ impl Graph for SimpleListGraph fn add_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); - self.adjacencies.insert(idx, Vec::new()); + let storage = if DIRECTED { + AdjacencyStorage::Directed(Vec::new(), Vec::new()) + } else { + AdjacencyStorage::Undirected(Vec::new()) + }; + self.adjacencies.insert(idx, storage); idx } @@ -72,10 +78,14 @@ impl Graph for SimpleListGraph } else { unsafe { let idx = self.edges.insert(Edge(src, dst, value)); - self.adjacencies.get_unchecked_mut(src).push((dst, idx)); - if !DIRECTED { - self.adjacencies.get_unchecked_mut(dst).push((src, idx)); - } + self.adjacencies + .get_unchecked_mut(src) + .outgoing_mut() + .push((dst, idx)); + self.adjacencies + .get_unchecked_mut(dst) + .incoming_mut() + .push((src, idx)); Ok(idx) } } @@ -87,7 +97,13 @@ impl Graph for SimpleListGraph } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - unsafe { self.adjacencies.get(src).unwrap().contains_key(dst) } + unsafe { + self.adjacencies + .get(src) + .unwrap() + .outgoing_mut() + .contains_key(dst) + } } fn remove_node(&mut self, index: NodeIdx) -> Option { @@ -97,10 +113,14 @@ impl Graph for SimpleListGraph fn remove_edge(&mut self, index: EdgeIdx) -> Option { if let Some(Edge(src, dst, value)) = self.edges.remove(index) { unsafe { - self.adjacencies.get_unchecked_mut(src).remove_by_key(dst); - if !DIRECTED { - self.adjacencies.get_unchecked_mut(dst).remove_by_key(src); - } + self.adjacencies + .get_unchecked_mut(src) + .outgoing_mut() + .remove_by_key(dst); + self.adjacencies + .get_unchecked_mut(dst) + .incoming_mut() + .remove_by_key(src); } Some(value) } else { @@ -109,7 +129,9 @@ impl Graph for SimpleListGraph } fn clear_edges(&mut self) { - self.adjacencies.values_mut().for_each(|list| list.clear()); + self.adjacencies + .values_mut() + .for_each(|list| list.for_each_mut(Vec::clear)); self.edges.clear(); } @@ -146,4 +168,8 @@ impl Graph for SimpleListGraph None } } + + fn degree(&self, index: NodeIdx) -> usize { + todo!() + } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index e16d2d76fb86a..e4243bd352885 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -4,6 +4,7 @@ use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ error::GraphError, graphs::{ + adjacency_storage::AdjacencyStorage, edge::Edge, keys::{EdgeIdx, NodeIdx}, Graph, @@ -17,7 +18,7 @@ use crate::{ pub struct SimpleMapGraph { nodes: HopSlotMap, edges: HopSlotMap>, - adjacencies: SecondaryMap>, + adjacencies: SecondaryMap>>, } impl Graph for SimpleMapGraph { @@ -51,7 +52,12 @@ impl Graph for SimpleMapGraph fn add_node(&mut self, node: N) -> NodeIdx { let idx = self.nodes.insert(node); - self.adjacencies.insert(idx, HashMap::new()); + let storage = if DIRECTED { + AdjacencyStorage::Directed(HashMap::new(), HashMap::new()) + } else { + AdjacencyStorage::Undirected(HashMap::new()) + }; + self.adjacencies.insert(idx, storage); idx } @@ -72,10 +78,14 @@ impl Graph for SimpleMapGraph } else { unsafe { let idx = self.edges.insert(Edge(src, dst, value)); - self.adjacencies.get_unchecked_mut(src).insert(dst, idx); - if !DIRECTED { - self.adjacencies.get_unchecked_mut(dst).insert(src, idx); - } + self.adjacencies + .get_unchecked_mut(src) + .outgoing_mut() + .insert(dst, idx); + self.adjacencies + .get_unchecked_mut(dst) + .incoming_mut() + .insert(src, idx); Ok(idx) } } @@ -87,7 +97,7 @@ impl Graph for SimpleMapGraph } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - self.adjacencies[src].contains_key(&dst) + self.adjacencies[src].outgoing_mut().contains_key(&dst) } fn remove_node(&mut self, index: NodeIdx) -> Option { @@ -97,10 +107,14 @@ impl Graph for SimpleMapGraph fn remove_edge(&mut self, index: EdgeIdx) -> Option { if let Some(Edge(src, dst, value)) = self.edges.remove(index) { unsafe { - self.adjacencies.get_unchecked_mut(src).remove(&dst); - if !DIRECTED { - self.adjacencies.get_unchecked_mut(dst).remove(&src); - } + self.adjacencies + .get_unchecked_mut(src) + .outgoing_mut() + .remove(&dst); + self.adjacencies + .get_unchecked_mut(dst) + .incoming_mut() + .remove(&src); } Some(value) } else { @@ -109,7 +123,9 @@ impl Graph for SimpleMapGraph } fn clear_edges(&mut self) { - self.adjacencies.values_mut().for_each(|map| map.clear()); + self.adjacencies + .values_mut() + .for_each(|map| map.for_each_mut(HashMap::clear)); self.edges.clear(); } @@ -146,4 +162,8 @@ impl Graph for SimpleMapGraph None } } + + fn degree(&self, index: NodeIdx) -> usize { + todo!() + } } From ea341641486f97066bbe7baa1728421ac13897f5 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 17 Jan 2023 19:13:58 +0100 Subject: [PATCH 117/183] =?UTF-8?q?`nodes`=20iterator=20=F0=9F=A4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/bevy_graph/src/graphs/mod.rs | 15 +++++++++++++++ crates/bevy_graph/src/graphs/multi/list.rs | 10 ++++++++++ crates/bevy_graph/src/graphs/multi/map.rs | 10 ++++++++++ crates/bevy_graph/src/graphs/simple/list.rs | 10 ++++++++++ crates/bevy_graph/src/graphs/simple/map.rs | 10 ++++++++++ 5 files changed, 55 insertions(+) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 2e6c18104037b..133cc25adbfc2 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -20,6 +20,15 @@ use self::keys::{EdgeIdx, NodeIdx}; /// A trait with all the common functions for a graph pub trait Graph { + type Nodes<'n>: Iterator + where + Self: 'n, + N: 'n; + type NodesMut<'n>: Iterator + where + Self: 'n, + N: 'n; + /// Creates a new graph fn new() -> Self where @@ -104,6 +113,12 @@ pub trait Graph { /// /// In multi-graphs, edges that form self-loops add 2 to the degree. fn degree(&self, index: NodeIdx) -> usize; + + /// Returns an iterator over all nodes. + fn nodes(&self) -> Self::Nodes<'_>; + + /// Returns a mutable iterator over all nodes. + fn nodes_mut(&mut self) -> Self::NodesMut<'_>; } /// A more precise trait with functions special for a simple graph diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 600d3589bdcfd..0c0b627480da3 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -171,4 +171,14 @@ impl Graph for MultiListGraph fn degree(&self, index: NodeIdx) -> usize { todo!() } + + type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; + fn nodes(&self) -> Self::Nodes<'_> { + self.nodes.values().into_iter() + } + + type NodesMut<'n> = slotmap::hop::ValuesMut<'n, NodeIdx, N> where Self: 'n; + fn nodes_mut(&mut self) -> Self::NodesMut<'_> { + self.nodes.values_mut().into_iter() + } } diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 9c1b012e154e7..28e1dd1a48e3f 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -175,4 +175,14 @@ impl Graph for MultiMapGraph { fn degree(&self, index: NodeIdx) -> usize { todo!() } + + type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; + fn nodes(&self) -> Self::Nodes<'_> { + self.nodes.values().into_iter() + } + + type NodesMut<'n> = slotmap::hop::ValuesMut<'n, NodeIdx, N> where Self: 'n; + fn nodes_mut(&mut self) -> Self::NodesMut<'_> { + self.nodes.values_mut().into_iter() + } } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index e2227b0f32499..69790236cdb4c 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -172,4 +172,14 @@ impl Graph for SimpleListGraph fn degree(&self, index: NodeIdx) -> usize { todo!() } + + type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; + fn nodes(&self) -> Self::Nodes<'_> { + self.nodes.values().into_iter() + } + + type NodesMut<'n> = slotmap::hop::ValuesMut<'n, NodeIdx, N> where Self: 'n; + fn nodes_mut(&mut self) -> Self::NodesMut<'_> { + self.nodes.values_mut().into_iter() + } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index e4243bd352885..be50fd9fc9caf 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -166,4 +166,14 @@ impl Graph for SimpleMapGraph fn degree(&self, index: NodeIdx) -> usize { todo!() } + + type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; + fn nodes(&self) -> Self::Nodes<'_> { + self.nodes.values().into_iter() + } + + type NodesMut<'n> = slotmap::hop::ValuesMut<'n, NodeIdx, N> where Self: 'n; + fn nodes_mut(&mut self) -> Self::NodesMut<'_> { + self.nodes.values_mut().into_iter() + } } From aa47441f8974ae4b57a073ffea6070b9be9f8de6 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 17 Jan 2023 19:24:45 +0100 Subject: [PATCH 118/183] `EdgeRef` and `EdgeMut` --- crates/bevy_graph/src/graphs/edge.rs | 44 +++++++++++++++++++++ crates/bevy_graph/src/graphs/mod.rs | 9 +++-- crates/bevy_graph/src/graphs/multi/list.rs | 14 +++---- crates/bevy_graph/src/graphs/multi/map.rs | 14 +++---- crates/bevy_graph/src/graphs/simple/list.rs | 14 +++---- crates/bevy_graph/src/graphs/simple/map.rs | 14 +++---- 6 files changed, 78 insertions(+), 31 deletions(-) diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs index 852c59f0ee8bb..4630aa95301c5 100644 --- a/crates/bevy_graph/src/graphs/edge.rs +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -1,5 +1,49 @@ +use std::ops::{Deref, DerefMut}; + use super::keys::NodeIdx; /// An edge between nodes that store data of type `E`. #[derive(Clone)] pub struct Edge(pub NodeIdx, pub NodeIdx, pub E); + +impl Edge { + /// Returns a [`EdgeRef`] of this edge + #[inline] + pub const fn as_ref_edge<'v>(&self) -> EdgeRef<'v, E> { + EdgeRef(self.0, self.1, &self.2) + } + + /// Returns a [`EdgeMut`] of this edge + #[inline] + pub const fn as_mut_edge<'v>(&self) -> EdgeMut<'v, E> { + EdgeMut(self.0, self.1, &mut self.2) + } +} + +/// An util container which holds Edge data with an immutable reference to the edge value +pub struct EdgeRef<'v, E>(pub NodeIdx, pub NodeIdx, pub &'v E); + +impl<'v, E> Deref for EdgeRef<'v, E> { + type Target = E; + + fn deref(&self) -> &Self::Target { + self.2 + } +} + +/// An util container which holds Edge data with a mutable reference to the edge value +pub struct EdgeMut<'v, E>(pub NodeIdx, pub NodeIdx, pub &'v mut E); + +impl<'v, E> Deref for EdgeMut<'v, E> { + type Target = E; + + fn deref(&self) -> &Self::Target { + self.2 + } +} + +impl<'v, E> DerefMut for EdgeMut<'v, E> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.2 + } +} diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 133cc25adbfc2..596306ac042af 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -12,7 +12,10 @@ pub mod keys; use crate::error::GraphError; -use self::keys::{EdgeIdx, NodeIdx}; +use self::{ + edge::{EdgeMut, EdgeRef}, + keys::{EdgeIdx, NodeIdx}, +}; // NOTE: There should always be a common function and if needed a more precise function which the common function wraps. // Example: `edges_between` is `trait Graph` general and has support for Simple- and Multigraphs. @@ -104,10 +107,10 @@ pub trait Graph { fn get_node_mut(&mut self, index: NodeIdx) -> Option<&mut N>; /// Returns a reference to the specified edge. - fn get_edge(&self, index: EdgeIdx) -> Option<&E>; + fn get_edge(&self, index: EdgeIdx) -> Option>; /// Returns a mutable reference to the specified edge. - fn get_edge_mut(&mut self, index: EdgeIdx) -> Option<&mut E>; + fn get_edge_mut(&mut self, index: EdgeIdx) -> Option>; /// Returns the number of edges connected to the specified node. /// diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 0c0b627480da3..34059ef2a9351 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -4,7 +4,7 @@ use crate::{ error::GraphError, graphs::{ adjacency_storage::AdjacencyStorage, - edge::Edge, + edge::{Edge, EdgeMut, EdgeRef}, keys::{EdgeIdx, NodeIdx}, Graph, }, @@ -151,18 +151,18 @@ impl Graph for MultiListGraph } #[inline] - fn get_edge(&self, index: EdgeIdx) -> Option<&E> { - if let Some(Edge(_, _, value)) = self.edges.get(index) { - Some(value) + fn get_edge(&self, index: EdgeIdx) -> Option> { + if let Some(edge) = self.edges.get(index) { + Some(edge.as_ref_edge()) } else { None } } #[inline] - fn get_edge_mut(&mut self, index: EdgeIdx) -> Option<&mut E> { - if let Some(Edge(_, _, value)) = self.edges.get_mut(index) { - Some(value) + fn get_edge_mut(&mut self, index: EdgeIdx) -> Option> { + if let Some(edge) = self.edges.get_mut(index) { + Some(edge.as_mut_edge()) } else { None } diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 28e1dd1a48e3f..bc839c35f52dd 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -5,7 +5,7 @@ use crate::{ error::GraphError, graphs::{ adjacency_storage::AdjacencyStorage, - edge::Edge, + edge::{Edge, EdgeMut, EdgeRef}, keys::{EdgeIdx, NodeIdx}, Graph, }, @@ -155,18 +155,18 @@ impl Graph for MultiMapGraph { } #[inline] - fn get_edge(&self, index: EdgeIdx) -> Option<&E> { - if let Some(Edge(_, _, value)) = self.edges.get(index) { - Some(value) + fn get_edge(&self, index: EdgeIdx) -> Option> { + if let Some(edge) = self.edges.get(index) { + Some(edge.as_ref_edge()) } else { None } } #[inline] - fn get_edge_mut(&mut self, index: EdgeIdx) -> Option<&mut E> { - if let Some(Edge(_, _, value)) = self.edges.get_mut(index) { - Some(value) + fn get_edge_mut(&mut self, index: EdgeIdx) -> Option> { + if let Some(edge) = self.edges.get_mut(index) { + Some(edge.as_mut_edge()) } else { None } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 69790236cdb4c..0a65081950063 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -4,7 +4,7 @@ use crate::{ error::GraphError, graphs::{ adjacency_storage::AdjacencyStorage, - edge::Edge, + edge::{Edge, EdgeMut, EdgeRef}, keys::{EdgeIdx, NodeIdx}, Graph, }, @@ -152,18 +152,18 @@ impl Graph for SimpleListGraph } #[inline] - fn get_edge(&self, index: EdgeIdx) -> Option<&E> { - if let Some(Edge(_, _, value)) = self.edges.get(index) { - Some(value) + fn get_edge(&self, index: EdgeIdx) -> Option> { + if let Some(edge) = self.edges.get(index) { + Some(edge.as_ref_edge()) } else { None } } #[inline] - fn get_edge_mut(&mut self, index: EdgeIdx) -> Option<&mut E> { - if let Some(Edge(_, _, value)) = self.edges.get_mut(index) { - Some(value) + fn get_edge_mut(&mut self, index: EdgeIdx) -> Option> { + if let Some(edge) = self.edges.get_mut(index) { + Some(edge.as_mut_edge()) } else { None } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index be50fd9fc9caf..af7a5e6c3427c 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -5,7 +5,7 @@ use crate::{ error::GraphError, graphs::{ adjacency_storage::AdjacencyStorage, - edge::Edge, + edge::{Edge, EdgeMut, EdgeRef}, keys::{EdgeIdx, NodeIdx}, Graph, }, @@ -146,18 +146,18 @@ impl Graph for SimpleMapGraph } #[inline] - fn get_edge(&self, index: EdgeIdx) -> Option<&E> { - if let Some(Edge(_, _, value)) = self.edges.get(index) { - Some(value) + fn get_edge(&self, index: EdgeIdx) -> Option> { + if let Some(edge) = self.edges.get(index) { + Some(edge.as_ref_edge()) } else { None } } #[inline] - fn get_edge_mut(&mut self, index: EdgeIdx) -> Option<&mut E> { - if let Some(Edge(_, _, value)) = self.edges.get_mut(index) { - Some(value) + fn get_edge_mut(&mut self, index: EdgeIdx) -> Option> { + if let Some(edge) = self.edges.get_mut(index) { + Some(edge.as_mut_edge()) } else { None } From 1245f9050bbdb268f888fb16a30242ac034135f5 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 17 Jan 2023 19:30:26 +0100 Subject: [PATCH 119/183] `edges` and `edges_mut` --- crates/bevy_graph/src/graphs/mod.rs | 14 ++++++++++++++ crates/bevy_graph/src/graphs/multi/list.rs | 12 ++++++++++++ crates/bevy_graph/src/graphs/multi/map.rs | 12 ++++++++++++ crates/bevy_graph/src/graphs/simple/list.rs | 12 ++++++++++++ crates/bevy_graph/src/graphs/simple/map.rs | 12 ++++++++++++ 5 files changed, 62 insertions(+) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 596306ac042af..b65ccd8e5bfc0 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -31,6 +31,14 @@ pub trait Graph { where Self: 'n, N: 'n; + type Edges<'e>: Iterator> + where + Self: 'e, + E: 'e; + type EdgesMut<'e>: Iterator> + where + Self: 'e, + E: 'e; /// Creates a new graph fn new() -> Self @@ -122,6 +130,12 @@ pub trait Graph { /// Returns a mutable iterator over all nodes. fn nodes_mut(&mut self) -> Self::NodesMut<'_>; + + /// Returns an iterator over all edges. + fn edges(&self) -> Self::Edges<'_>; + + /// Returns a mutable iterator over all edges. + fn edges_mut(&mut self) -> Self::EdgesMut<'_>; } /// A more precise trait with functions special for a simple graph diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 34059ef2a9351..ebd0c421f8761 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -1,3 +1,5 @@ +use std::iter::Map; + use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ @@ -181,4 +183,14 @@ impl Graph for MultiListGraph fn nodes_mut(&mut self) -> Self::NodesMut<'_> { self.nodes.values_mut().into_iter() } + + type Edges<'e> = Map>, fn(&Edge) -> EdgeRef<'e, E>> where Self: 'e; + fn edges(&self) -> Self::Edges<'_> { + self.edges.values().map(|e| e.as_ref_edge()) + } + + type EdgesMut<'e> = Map>, fn(&mut Edge) -> EdgeMut<'e, E>> where Self: 'e; + fn edges_mut(&mut self) -> Self::EdgesMut<'_> { + self.edges.values_mut().map(|e| e.as_mut_edge()) + } } diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index bc839c35f52dd..7137a88463349 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -1,3 +1,5 @@ +use std::iter::Map; + use hashbrown::HashMap; use slotmap::{HopSlotMap, SecondaryMap}; @@ -185,4 +187,14 @@ impl Graph for MultiMapGraph { fn nodes_mut(&mut self) -> Self::NodesMut<'_> { self.nodes.values_mut().into_iter() } + + type Edges<'e> = Map>, fn(&Edge) -> EdgeRef<'e, E>> where Self: 'e; + fn edges(&self) -> Self::Edges<'_> { + self.edges.values().map(|e| e.as_ref_edge()) + } + + type EdgesMut<'e> = Map>, fn(&mut Edge) -> EdgeMut<'e, E>> where Self: 'e; + fn edges_mut(&mut self) -> Self::EdgesMut<'_> { + self.edges.values_mut().map(|e| e.as_mut_edge()) + } } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 0a65081950063..5a881c47c3f59 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -1,3 +1,5 @@ +use std::iter::Map; + use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ @@ -182,4 +184,14 @@ impl Graph for SimpleListGraph fn nodes_mut(&mut self) -> Self::NodesMut<'_> { self.nodes.values_mut().into_iter() } + + type Edges<'e> = Map>, fn(&Edge) -> EdgeRef<'e, E>> where Self: 'e; + fn edges(&self) -> Self::Edges<'_> { + self.edges.values().map(|e| e.as_ref_edge()) + } + + type EdgesMut<'e> = Map>, fn(&mut Edge) -> EdgeMut<'e, E>> where Self: 'e; + fn edges_mut(&mut self) -> Self::EdgesMut<'_> { + self.edges.values_mut().map(|e| e.as_mut_edge()) + } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index af7a5e6c3427c..f7d60d13a60c0 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -1,3 +1,5 @@ +use std::iter::Map; + use hashbrown::HashMap; use slotmap::{HopSlotMap, SecondaryMap}; @@ -176,4 +178,14 @@ impl Graph for SimpleMapGraph fn nodes_mut(&mut self) -> Self::NodesMut<'_> { self.nodes.values_mut().into_iter() } + + type Edges<'e> = Map>, fn(&Edge) -> EdgeRef<'e, E>> where Self: 'e; + fn edges(&self) -> Self::Edges<'_> { + self.edges.values().map(|e| e.as_ref_edge()) + } + + type EdgesMut<'e> = Map>, fn(&mut Edge) -> EdgeMut<'e, E>> where Self: 'e; + fn edges_mut(&mut self) -> Self::EdgesMut<'_> { + self.edges.values_mut().map(|e| e.as_mut_edge()) + } } From 34a48b1cdd3eda445dbca56c457a959b51595abf Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 18 Jan 2023 16:43:09 +0100 Subject: [PATCH 120/183] Resolve all errors --- crates/bevy_graph/src/algos/bfs.rs | 24 ++++++---- crates/bevy_graph/src/algos/dfs.rs | 24 ++++++---- .../src/graphs/adjacency_storage.rs | 27 ++++++++++-- crates/bevy_graph/src/graphs/edge.rs | 4 +- crates/bevy_graph/src/graphs/mod.rs | 26 +++++++++-- crates/bevy_graph/src/graphs/multi/list.rs | 34 ++++++++++---- crates/bevy_graph/src/graphs/multi/map.rs | 34 ++++++++++---- crates/bevy_graph/src/graphs/simple/list.rs | 36 ++++++++------- crates/bevy_graph/src/graphs/simple/map.rs | 28 +++++++----- crates/bevy_graph/src/utils/vecmap.rs | 44 ++++++++++++++----- crates/bevy_graph/src/utils/vecset.rs | 2 + 11 files changed, 202 insertions(+), 81 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index d3e12a6da9fdf..6e056cd5a5cab 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -2,7 +2,7 @@ use std::collections::VecDeque; use hashbrown::HashSet; -use crate::graphs::{keys::NodeIdx, Graph}; +use crate::graphs::{edge::EdgeRef, keys::NodeIdx, Graph}; /// Implementation of the [`BFS` algorythm](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/) /// @@ -39,10 +39,13 @@ impl BreadthFirstSearch { /// Gets an immutable reference to the value of the next node from the algorithm pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { if let Some(node) = self.queue.pop_front() { - for (idx, _) in graph.edges_of(node) { - if !self.visited.contains(&idx) { - self.visited.insert(idx); - self.queue.push_back(idx); + for EdgeRef(_, dst, _) in graph + .outgoing_edges_of(node) + .map(|e| graph.get_edge(e).unwrap()) + { + if !self.visited.contains(&dst) { + self.visited.insert(dst); + self.queue.push_back(dst); } } Some(graph.get_node(node).unwrap()) @@ -54,10 +57,13 @@ impl BreadthFirstSearch { /// Gets a mutable reference to the value of the next node from the algorithm. pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.queue.pop_front() { - for (idx, _) in graph.edges_of(node) { - if !self.visited.contains(&idx) { - self.visited.insert(idx); - self.queue.push_back(idx); + for EdgeRef(_, dst, _) in graph + .outgoing_edges_of(node) + .map(|e| graph.get_edge(e).unwrap()) + { + if !self.visited.contains(&dst) { + self.visited.insert(dst); + self.queue.push_back(dst); } } Some(graph.get_node_mut(node).unwrap()) diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 7846360d4d751..124fc779b3359 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -1,6 +1,6 @@ use hashbrown::HashSet; -use crate::graphs::{keys::NodeIdx, Graph}; +use crate::graphs::{edge::EdgeRef, keys::NodeIdx, Graph}; /// Implementation of the [`DFS` algorythm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) /// @@ -36,10 +36,13 @@ impl DepthFirstSearch { /// Gets a reference to the value of the next node from the algorithm. pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { if let Some(node) = self.stack.pop() { - for (idx, _) in graph.edges_of(node) { - if !self.visited.contains(&idx) { - self.visited.insert(idx); - self.stack.push(idx); + for EdgeRef(_, dst, _) in graph + .outgoing_edges_of(node) + .map(|e| graph.get_edge(e).unwrap()) + { + if !self.visited.contains(&dst) { + self.visited.insert(dst); + self.stack.push(dst); } } Some(graph.get_node(node).unwrap()) @@ -51,10 +54,13 @@ impl DepthFirstSearch { /// Gets a mutable reference to the value of the next node from the algorithm. pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.stack.pop() { - for (idx, _) in graph.edges_of(node) { - if !self.visited.contains(&idx) { - self.visited.insert(idx); - self.stack.push(idx); + for EdgeRef(_, dst, _) in graph + .outgoing_edges_of(node) + .map(|e| graph.get_edge(e).unwrap()) + { + if !self.visited.contains(&dst) { + self.visited.insert(dst); + self.stack.push(dst); } } Some(graph.get_node_mut(node).unwrap()) diff --git a/crates/bevy_graph/src/graphs/adjacency_storage.rs b/crates/bevy_graph/src/graphs/adjacency_storage.rs index 3c38b758486df..5c19fa865434b 100644 --- a/crates/bevy_graph/src/graphs/adjacency_storage.rs +++ b/crates/bevy_graph/src/graphs/adjacency_storage.rs @@ -8,24 +8,45 @@ pub enum AdjacencyStorage { } impl AdjacencyStorage { + /// Returns an immutable reference to the incoming adjacency storage #[inline] - pub const fn incoming_mut(&mut self) -> &mut S { + pub const fn incoming(&self) -> &S { match self { AdjacencyStorage::Undirected(storage) => storage, AdjacencyStorage::Directed(incoming, _) => incoming, } } + /// Returns a mutable reference to the incoming adjacency storage #[inline] - pub const fn outgoing_mut(&mut self) -> &mut S { + pub fn incoming_mut(&mut self) -> &mut S { + match self { + AdjacencyStorage::Undirected(storage) => storage, + AdjacencyStorage::Directed(incoming, _) => incoming, + } + } + + /// Returns an immutable reference to the outgoing adjacency storage + #[inline] + pub fn outgoing(&self) -> &S { + match self { + AdjacencyStorage::Undirected(storage) => storage, + AdjacencyStorage::Directed(_, outgoing) => outgoing, + } + } + + /// Returns a mutable reference to the outgoing adjacency storage + #[inline] + pub fn outgoing_mut(&mut self) -> &mut S { match self { AdjacencyStorage::Undirected(storage) => storage, AdjacencyStorage::Directed(_, outgoing) => outgoing, } } + /// Executes a function for each storage #[inline] - pub const fn for_each_mut(&mut self, f: fn(&mut S)) { + pub fn for_each_mut(&mut self, f: fn(&mut S)) { match self { AdjacencyStorage::Undirected(storage) => { f(storage); diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs index 4630aa95301c5..32965956c7cb2 100644 --- a/crates/bevy_graph/src/graphs/edge.rs +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -9,13 +9,13 @@ pub struct Edge(pub NodeIdx, pub NodeIdx, pub E); impl Edge { /// Returns a [`EdgeRef`] of this edge #[inline] - pub const fn as_ref_edge<'v>(&self) -> EdgeRef<'v, E> { + pub const fn as_ref_edge<'v>(&'v self) -> EdgeRef<'v, E> { EdgeRef(self.0, self.1, &self.2) } /// Returns a [`EdgeMut`] of this edge #[inline] - pub const fn as_mut_edge<'v>(&self) -> EdgeMut<'v, E> { + pub fn as_mut_edge<'v>(&'v mut self) -> EdgeMut<'v, E> { EdgeMut(self.0, self.1, &mut self.2) } } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index b65ccd8e5bfc0..506fbf6f4e793 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -13,7 +13,7 @@ pub mod keys; use crate::error::GraphError; use self::{ - edge::{EdgeMut, EdgeRef}, + edge::{Edge, EdgeMut, EdgeRef}, keys::{EdgeIdx, NodeIdx}, }; @@ -23,19 +23,33 @@ use self::{ /// A trait with all the common functions for a graph pub trait Graph { + /// Iterator fix because TAIT not available type Nodes<'n>: Iterator where Self: 'n, N: 'n; + /// Iterator fix because TAIT not available type NodesMut<'n>: Iterator where Self: 'n, N: 'n; - type Edges<'e>: Iterator> + /// Iterator fix because TAIT not available + type Edges<'e>: Iterator> where Self: 'e, E: 'e; - type EdgesMut<'e>: Iterator> + /// Iterator fix because TAIT not available + type EdgesMut<'e>: Iterator> + where + Self: 'e, + E: 'e; + /// Iterator fix because TAIT not available + type IncomingEdgesOf<'e>: Iterator + where + Self: 'e, + E: 'e; + /// Iterator fix because TAIT not available + type OutgoingEdgesOf<'e>: Iterator where Self: 'e, E: 'e; @@ -136,6 +150,12 @@ pub trait Graph { /// Returns a mutable iterator over all edges. fn edges_mut(&mut self) -> Self::EdgesMut<'_>; + + /// Returns an iterator over the edge indices going into the specified node. + fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_>; + + /// Returns an iterator over the edge indices coming out of the specified node. + fn outgoing_edges_of(&self, index: NodeIdx) -> Self::OutgoingEdgesOf<'_>; } /// A more precise trait with functions special for a simple graph diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index ebd0c421f8761..b75afc9f79667 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -1,5 +1,3 @@ -use std::iter::Map; - use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ @@ -99,11 +97,11 @@ impl Graph for MultiListGraph self.adjacencies .get(src) .unwrap() - .outgoing_mut() + .outgoing() .contains_key(dst) } - fn remove_node(&mut self, index: NodeIdx) -> Option { + fn remove_node(&mut self, _index: NodeIdx) -> Option { todo!() } @@ -170,7 +168,7 @@ impl Graph for MultiListGraph } } - fn degree(&self, index: NodeIdx) -> usize { + fn degree(&self, _index: NodeIdx) -> usize { todo!() } @@ -184,13 +182,31 @@ impl Graph for MultiListGraph self.nodes.values_mut().into_iter() } - type Edges<'e> = Map>, fn(&Edge) -> EdgeRef<'e, E>> where Self: 'e; + type Edges<'e> = slotmap::hop::Values<'e, EdgeIdx, Edge> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { - self.edges.values().map(|e| e.as_ref_edge()) + self.edges.values() } - type EdgesMut<'e> = Map>, fn(&mut Edge) -> EdgeMut<'e, E>> where Self: 'e; + type EdgesMut<'e> = slotmap::hop::ValuesMut<'e, EdgeIdx, Edge> where Self: 'e; fn edges_mut(&mut self) -> Self::EdgesMut<'_> { - self.edges.values_mut().map(|e| e.as_mut_edge()) + self.edges.values_mut() + } + + type IncomingEdgesOf<'e> = std::iter::Cloned>>> where Self: 'e; + fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { + self.adjacencies[index] + .incoming() + .values() + .flatten() + .cloned() + } + + type OutgoingEdgesOf<'e> = std::iter::Cloned>>> where Self: 'e; + fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { + self.adjacencies[index] + .outgoing() + .values() + .flatten() + .cloned() } } diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 7137a88463349..0262abf132344 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -1,5 +1,3 @@ -use std::iter::Map; - use hashbrown::HashMap; use slotmap::{HopSlotMap, SecondaryMap}; @@ -103,11 +101,11 @@ impl Graph for MultiMapGraph { self.adjacencies .get(src) .unwrap() - .outgoing_mut() + .outgoing() .contains_key(&dst) } - fn remove_node(&mut self, index: NodeIdx) -> Option { + fn remove_node(&mut self, _index: NodeIdx) -> Option { todo!() } @@ -174,7 +172,7 @@ impl Graph for MultiMapGraph { } } - fn degree(&self, index: NodeIdx) -> usize { + fn degree(&self, _index: NodeIdx) -> usize { todo!() } @@ -188,13 +186,31 @@ impl Graph for MultiMapGraph { self.nodes.values_mut().into_iter() } - type Edges<'e> = Map>, fn(&Edge) -> EdgeRef<'e, E>> where Self: 'e; + type Edges<'e> = slotmap::hop::Values<'e, EdgeIdx, Edge> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { - self.edges.values().map(|e| e.as_ref_edge()) + self.edges.values() } - type EdgesMut<'e> = Map>, fn(&mut Edge) -> EdgeMut<'e, E>> where Self: 'e; + type EdgesMut<'e> = slotmap::hop::ValuesMut<'e, EdgeIdx, Edge> where Self: 'e; fn edges_mut(&mut self) -> Self::EdgesMut<'_> { - self.edges.values_mut().map(|e| e.as_mut_edge()) + self.edges.values_mut() + } + + type IncomingEdgesOf<'e> = std::iter::Cloned>>> where Self: 'e; + fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { + self.adjacencies[index] + .incoming() + .values() + .flatten() + .cloned() + } + + type OutgoingEdgesOf<'e> = std::iter::Cloned>>> where Self: 'e; + fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { + self.adjacencies[index] + .outgoing() + .values() + .flatten() + .cloned() } } diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 5a881c47c3f59..529118d65426a 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -1,5 +1,3 @@ -use std::iter::Map; - use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ @@ -99,16 +97,14 @@ impl Graph for SimpleListGraph } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - unsafe { - self.adjacencies - .get(src) - .unwrap() - .outgoing_mut() - .contains_key(dst) - } + self.adjacencies + .get(src) + .unwrap() + .outgoing() + .contains_key(dst) } - fn remove_node(&mut self, index: NodeIdx) -> Option { + fn remove_node(&mut self, _index: NodeIdx) -> Option { todo!() } @@ -171,7 +167,7 @@ impl Graph for SimpleListGraph } } - fn degree(&self, index: NodeIdx) -> usize { + fn degree(&self, _index: NodeIdx) -> usize { todo!() } @@ -185,13 +181,23 @@ impl Graph for SimpleListGraph self.nodes.values_mut().into_iter() } - type Edges<'e> = Map>, fn(&Edge) -> EdgeRef<'e, E>> where Self: 'e; + type Edges<'e> = slotmap::hop::Values<'e, EdgeIdx, Edge> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { - self.edges.values().map(|e| e.as_ref_edge()) + self.edges.values() } - type EdgesMut<'e> = Map>, fn(&mut Edge) -> EdgeMut<'e, E>> where Self: 'e; + type EdgesMut<'e> = slotmap::hop::ValuesMut<'e, EdgeIdx, Edge> where Self: 'e; fn edges_mut(&mut self) -> Self::EdgesMut<'_> { - self.edges.values_mut().map(|e| e.as_mut_edge()) + self.edges.values_mut() + } + + type IncomingEdgesOf<'e> = std::iter::Cloned> where Self: 'e; + fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { + self.adjacencies[index].incoming().values().cloned() + } + + type OutgoingEdgesOf<'e> = std::iter::Cloned> where Self: 'e; + fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { + self.adjacencies[index].outgoing().values().cloned() } } diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index f7d60d13a60c0..902e28c8bcf89 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -1,5 +1,3 @@ -use std::iter::Map; - use hashbrown::HashMap; use slotmap::{HopSlotMap, SecondaryMap}; @@ -99,10 +97,10 @@ impl Graph for SimpleMapGraph } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - self.adjacencies[src].outgoing_mut().contains_key(&dst) + self.adjacencies[src].outgoing().contains_key(&dst) } - fn remove_node(&mut self, index: NodeIdx) -> Option { + fn remove_node(&mut self, _index: NodeIdx) -> Option { todo!() } @@ -165,7 +163,7 @@ impl Graph for SimpleMapGraph } } - fn degree(&self, index: NodeIdx) -> usize { + fn degree(&self, _index: NodeIdx) -> usize { todo!() } @@ -179,13 +177,23 @@ impl Graph for SimpleMapGraph self.nodes.values_mut().into_iter() } - type Edges<'e> = Map>, fn(&Edge) -> EdgeRef<'e, E>> where Self: 'e; - fn edges(&self) -> Self::Edges<'_> { - self.edges.values().map(|e| e.as_ref_edge()) + type Edges<'e> = slotmap::hop::Values<'e, EdgeIdx, Edge> where Self: 'e; + fn edges<'e>(&'e self) -> Self::Edges<'e> { + self.edges.values() } - type EdgesMut<'e> = Map>, fn(&mut Edge) -> EdgeMut<'e, E>> where Self: 'e; + type EdgesMut<'e> = slotmap::hop::ValuesMut<'e, EdgeIdx, Edge> where Self: 'e; fn edges_mut(&mut self) -> Self::EdgesMut<'_> { - self.edges.values_mut().map(|e| e.as_mut_edge()) + self.edges.values_mut() + } + + type IncomingEdgesOf<'e> = std::iter::Cloned> where Self: 'e; + fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { + self.adjacencies[index].incoming().values().cloned() + } + + type OutgoingEdgesOf<'e> = std::iter::Cloned> where Self: 'e; + fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { + self.adjacencies[index].outgoing().values().cloned() } } diff --git a/crates/bevy_graph/src/utils/vecmap.rs b/crates/bevy_graph/src/utils/vecmap.rs index 8d6c921bf3601..84a3ca48d2ac7 100644 --- a/crates/bevy_graph/src/utils/vecmap.rs +++ b/crates/bevy_graph/src/utils/vecmap.rs @@ -1,3 +1,5 @@ +use core::slice; + /// Map-like methods for `Vec<(K, V)>` pub trait VecMap { /// Gets an immutable reference to value by key @@ -42,6 +44,9 @@ pub trait VecMap { /// Removes the entry by the key fn remove_by_key(&mut self, key: K) -> Option; + + /// Returns an iterator over the values + fn values(&self) -> Values; } impl VecMap for Vec<(K, V)> { @@ -68,22 +73,20 @@ impl VecMap for Vec<(K, V)> { } fn get_value_or(&mut self, key: K, or: fn() -> V) -> &V { - match self.iter().find(|l| l.0 == key) { - Some((_, v)) => v, - None => { - self.push((key, or())); - unsafe { &self.last().unwrap_unchecked().1 } - } + if let Some(pos) = self.iter().position(|l| l.0 == key) { + unsafe { &self.get_unchecked(pos).1 } + } else { + self.push((key, or())); + unsafe { &self.last().unwrap_unchecked().1 } } } fn get_value_or_mut(&mut self, key: K, or: fn() -> V) -> &mut V { - match self.iter_mut().find(|l| l.0 == key) { - Some((_, v)) => v, - None => { - self.push((key, or())); - unsafe { &mut self.last_mut().unwrap_unchecked().1 } - } + if let Some(pos) = self.iter().position(|l| l.0 == key) { + unsafe { &mut self.get_unchecked_mut(pos).1 } + } else { + self.push((key, or())); + unsafe { &mut self.last_mut().unwrap_unchecked().1 } } } @@ -102,4 +105,21 @@ impl VecMap for Vec<(K, V)> { None } } + + fn values(&self) -> Values { + Values { inner: self.iter() } + } +} + +/// Iterator over all values in a VecMap +pub struct Values<'s, K: PartialEq, V> { + inner: slice::Iter<'s, (K, V)>, +} + +impl<'s, K: PartialEq, V> Iterator for Values<'s, K, V> { + type Item = &'s V; + + fn next(&mut self) -> Option { + self.inner.next().map(|l| &l.1) + } } diff --git a/crates/bevy_graph/src/utils/vecset.rs b/crates/bevy_graph/src/utils/vecset.rs index eb028eeac947a..0a8e3bd40d894 100644 --- a/crates/bevy_graph/src/utils/vecset.rs +++ b/crates/bevy_graph/src/utils/vecset.rs @@ -1,6 +1,8 @@ /// Set-like methods for `Vec` pub trait VecSet { + /// Gets a index by value fn index_by_value(&self, value: &T) -> Option; + /// Removes an entry by value fn remove_by_value(&mut self, value: &T) -> Option; } From c58dec50899231256fdedd7c5b95cb6f3dccb5e4 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 18 Jan 2023 18:31:40 +0100 Subject: [PATCH 121/183] Make VecMap faster with binary search --- crates/bevy_graph/src/utils/vecmap.rs | 52 ++++++++++++--------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/crates/bevy_graph/src/utils/vecmap.rs b/crates/bevy_graph/src/utils/vecmap.rs index 84a3ca48d2ac7..3a0ed8ef3bebe 100644 --- a/crates/bevy_graph/src/utils/vecmap.rs +++ b/crates/bevy_graph/src/utils/vecmap.rs @@ -1,19 +1,13 @@ use core::slice; /// Map-like methods for `Vec<(K, V)>` -pub trait VecMap { +pub trait VecMap { /// Gets an immutable reference to value by key fn get_value(&self, key: K) -> Option<&V>; /// Gets a mutable reference to value by key fn get_value_mut(&mut self, key: K) -> Option<&mut V>; - /// Gets an immutable reference to value by key - unsafe fn get_value_unchecked(&self, key: K) -> &V; - - /// Gets a mutable reference to value by key - unsafe fn get_value_unchecked_mut(&mut self, key: K) -> &mut V; - /// Gets an immutable reference to value by key and inserts by closure when it's not preset fn get_value_or(&mut self, key: K, or: fn() -> V) -> &V; @@ -40,7 +34,7 @@ pub trait VecMap { fn contains_key(&self, key: K) -> bool; /// Gets the index by the key - fn index_by_key(&self, key: K) -> Option; + fn index_by_key(&self, key: &K) -> Option; /// Removes the entry by the key fn remove_by_key(&mut self, key: K) -> Option; @@ -49,32 +43,26 @@ pub trait VecMap { fn values(&self) -> Values; } -impl VecMap for Vec<(K, V)> { +impl VecMap for Vec<(K, V)> { fn get_value(&self, key: K) -> Option<&V> { - match self.iter().find(|l| l.0 == key) { - Some((_, v)) => Some(v), - None => None, + if let Some(index) = self.index_by_key(&key) { + unsafe { Some(&self.get_unchecked(index).1) } + } else { + None } } fn get_value_mut(&mut self, key: K) -> Option<&mut V> { - match self.iter_mut().find(|l| l.0 == key) { - Some((_, v)) => Some(v), - None => None, + if let Some(index) = self.index_by_key(&key) { + unsafe { Some(&mut self.get_unchecked_mut(index).1) } + } else { + None } } - unsafe fn get_value_unchecked(&self, key: K) -> &V { - &self.iter().find(|l| l.0 == key).unwrap_unchecked().1 - } - - unsafe fn get_value_unchecked_mut(&mut self, key: K) -> &mut V { - &mut self.iter_mut().find(|l| l.0 == key).unwrap_unchecked().1 - } - fn get_value_or(&mut self, key: K, or: fn() -> V) -> &V { - if let Some(pos) = self.iter().position(|l| l.0 == key) { - unsafe { &self.get_unchecked(pos).1 } + if let Some(index) = self.index_by_key(&key) { + unsafe { &self.get_unchecked(index).1 } } else { self.push((key, or())); unsafe { &self.last().unwrap_unchecked().1 } @@ -82,8 +70,8 @@ impl VecMap for Vec<(K, V)> { } fn get_value_or_mut(&mut self, key: K, or: fn() -> V) -> &mut V { - if let Some(pos) = self.iter().position(|l| l.0 == key) { - unsafe { &mut self.get_unchecked_mut(pos).1 } + if let Some(index) = self.index_by_key(&key) { + unsafe { &mut self.get_unchecked_mut(index).1 } } else { self.push((key, or())); unsafe { &mut self.last_mut().unwrap_unchecked().1 } @@ -94,12 +82,16 @@ impl VecMap for Vec<(K, V)> { self.iter().any(|l| l.0 == key) } - fn index_by_key(&self, key: K) -> Option { - self.iter().position(|l| l.0 == key) + #[inline] + fn index_by_key(&self, key: &K) -> Option { + match self.binary_search_by(|l| l.0.cmp(key)) { + Ok(index) => Some(index), + _ => None, + } } fn remove_by_key(&mut self, key: K) -> Option { - if let Some(index) = self.index_by_key(key) { + if let Some(index) = self.index_by_key(&key) { Some(self.remove(index).1) } else { None From 2f3ea70715961aa81ccff79c94ea6062e1e1bb58 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 18 Jan 2023 18:50:25 +0100 Subject: [PATCH 122/183] Some more graph creation funcs --- crates/bevy_graph/src/graphs/mod.rs | 16 ++++++++++++++++ crates/bevy_graph/src/graphs/multi/list.rs | 20 ++++++++++++++++++++ crates/bevy_graph/src/graphs/multi/map.rs | 20 ++++++++++++++++++++ crates/bevy_graph/src/graphs/simple/list.rs | 20 ++++++++++++++++++++ crates/bevy_graph/src/graphs/simple/map.rs | 20 ++++++++++++++++++++ 5 files changed, 96 insertions(+) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 506fbf6f4e793..041569d259d8e 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -59,6 +59,22 @@ pub trait Graph { where Self: Sized; + /// Constructs a new, empty graph with the specified node and edge capacity. + /// The graph will be able to hold exactly `node_capacity` nodes and `edge_capacity` edges + /// elements without reallocating. + /// + /// If the capacites are zero, the graph will not allocate. + fn with_capacity(node_capacity: usize, edge_capacity: usize) -> Self; + + /// Returns the number of nodes and edges the graph can hold without reallocating. + fn capacity(&self) -> (usize, usize); + + /// Returns the number of nodes the graph can hold without reallocating. + fn node_capacity(&self) -> usize; + + /// Returns the number of edges the graph can hold without reallocating. + fn edge_capacity(&self) -> usize; + /// Returns `true` if the edges in the graph are directed. fn is_directed(&self) -> bool; diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index b75afc9f79667..69866a1be0b75 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -30,6 +30,26 @@ impl Graph for MultiListGraph } } + fn with_capacity(node_capacity: usize, edge_capacity: usize) -> Self { + Self { + nodes: HopSlotMap::with_capacity_and_key(node_capacity), + edges: HopSlotMap::with_capacity_and_key(edge_capacity), + adjacencies: SecondaryMap::new(), + } + } + + fn capacity(&self) -> (usize, usize) { + (self.nodes.capacity(), self.edges.capacity()) + } + + fn node_capacity(&self) -> usize { + self.nodes.capacity() + } + + fn edge_capacity(&self) -> usize { + self.edges.capacity() + } + #[inline] fn is_directed(&self) -> bool { DIRECTED diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index 0262abf132344..fd0d8d31173a7 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -31,6 +31,26 @@ impl Graph for MultiMapGraph { } } + fn with_capacity(node_capacity: usize, edge_capacity: usize) -> Self { + Self { + nodes: HopSlotMap::with_capacity_and_key(node_capacity), + edges: HopSlotMap::with_capacity_and_key(edge_capacity), + adjacencies: SecondaryMap::new(), + } + } + + fn capacity(&self) -> (usize, usize) { + (self.nodes.capacity(), self.edges.capacity()) + } + + fn node_capacity(&self) -> usize { + self.nodes.capacity() + } + + fn edge_capacity(&self) -> usize { + self.edges.capacity() + } + #[inline] fn is_directed(&self) -> bool { DIRECTED diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 529118d65426a..3a24bc68b5657 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -30,6 +30,26 @@ impl Graph for SimpleListGraph } } + fn with_capacity(node_capacity: usize, edge_capacity: usize) -> Self { + Self { + nodes: HopSlotMap::with_capacity_and_key(node_capacity), + edges: HopSlotMap::with_capacity_and_key(edge_capacity), + adjacencies: SecondaryMap::new(), + } + } + + fn capacity(&self) -> (usize, usize) { + (self.nodes.capacity(), self.edges.capacity()) + } + + fn node_capacity(&self) -> usize { + self.nodes.capacity() + } + + fn edge_capacity(&self) -> usize { + self.edges.capacity() + } + #[inline] fn is_directed(&self) -> bool { DIRECTED diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 902e28c8bcf89..56124a191f426 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -30,6 +30,26 @@ impl Graph for SimpleMapGraph } } + fn with_capacity(node_capacity: usize, edge_capacity: usize) -> Self { + Self { + nodes: HopSlotMap::with_capacity_and_key(node_capacity), + edges: HopSlotMap::with_capacity_and_key(edge_capacity), + adjacencies: SecondaryMap::new(), + } + } + + fn capacity(&self) -> (usize, usize) { + (self.nodes.capacity(), self.edges.capacity()) + } + + fn node_capacity(&self) -> usize { + self.nodes.capacity() + } + + fn edge_capacity(&self) -> usize { + self.edges.capacity() + } + #[inline] fn is_directed(&self) -> bool { DIRECTED From 658da340236e89f23468c3da82d4696d865eb3c8 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 18 Jan 2023 18:54:31 +0100 Subject: [PATCH 123/183] Add `reserve`ing for graphs --- crates/bevy_graph/src/graphs/mod.rs | 20 ++++++++++++++++++++ crates/bevy_graph/src/graphs/multi/list.rs | 13 +++++++++++++ crates/bevy_graph/src/graphs/multi/map.rs | 13 +++++++++++++ crates/bevy_graph/src/graphs/simple/list.rs | 13 +++++++++++++ crates/bevy_graph/src/graphs/simple/map.rs | 13 +++++++++++++ 5 files changed, 72 insertions(+) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 041569d259d8e..cd1479764aece 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -75,6 +75,26 @@ pub trait Graph { /// Returns the number of edges the graph can hold without reallocating. fn edge_capacity(&self) -> usize; + /// Reserves capacity for at least `additional` more nodes to be inserted in the given `Self`. + /// The collection may reserve more space to avoid frequent reallocations. + /// After calling `reserve_nodes`, the node capacity will be greater than or equal to + /// `self.node_count() + additional`. Does nothing if capacity is already sufficient. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + fn reserve_nodes(&mut self, additional: usize); + + /// Reserves capacity for at least `additional` more edges to be inserted in the given `Self`. + /// The collection may reserve more space to avoid frequent reallocations. + /// After calling `reserve_edges`, the edge capacity will be greater than or equal to + /// `self.edge_count() + additional`. Does nothing if capacity is already sufficient. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + fn reserve_edges(&mut self, additional: usize); + /// Returns `true` if the edges in the graph are directed. fn is_directed(&self) -> bool; diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/multi/list.rs index 69866a1be0b75..cc8eea13f74b1 100644 --- a/crates/bevy_graph/src/graphs/multi/list.rs +++ b/crates/bevy_graph/src/graphs/multi/list.rs @@ -38,18 +38,31 @@ impl Graph for MultiListGraph } } + #[inline] fn capacity(&self) -> (usize, usize) { (self.nodes.capacity(), self.edges.capacity()) } + #[inline] fn node_capacity(&self) -> usize { self.nodes.capacity() } + #[inline] fn edge_capacity(&self) -> usize { self.edges.capacity() } + #[inline] + fn reserve_nodes(&mut self, additional: usize) { + self.nodes.reserve(additional) + } + + #[inline] + fn reserve_edges(&mut self, additional: usize) { + self.edges.reserve(additional) + } + #[inline] fn is_directed(&self) -> bool { DIRECTED diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/multi/map.rs index fd0d8d31173a7..b851a45b99ad7 100644 --- a/crates/bevy_graph/src/graphs/multi/map.rs +++ b/crates/bevy_graph/src/graphs/multi/map.rs @@ -39,18 +39,31 @@ impl Graph for MultiMapGraph { } } + #[inline] fn capacity(&self) -> (usize, usize) { (self.nodes.capacity(), self.edges.capacity()) } + #[inline] fn node_capacity(&self) -> usize { self.nodes.capacity() } + #[inline] fn edge_capacity(&self) -> usize { self.edges.capacity() } + #[inline] + fn reserve_nodes(&mut self, additional: usize) { + self.nodes.reserve(additional) + } + + #[inline] + fn reserve_edges(&mut self, additional: usize) { + self.edges.reserve(additional) + } + #[inline] fn is_directed(&self) -> bool { DIRECTED diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/simple/list.rs index 3a24bc68b5657..a9b367069b18a 100644 --- a/crates/bevy_graph/src/graphs/simple/list.rs +++ b/crates/bevy_graph/src/graphs/simple/list.rs @@ -38,18 +38,31 @@ impl Graph for SimpleListGraph } } + #[inline] fn capacity(&self) -> (usize, usize) { (self.nodes.capacity(), self.edges.capacity()) } + #[inline] fn node_capacity(&self) -> usize { self.nodes.capacity() } + #[inline] fn edge_capacity(&self) -> usize { self.edges.capacity() } + #[inline] + fn reserve_nodes(&mut self, additional: usize) { + self.nodes.reserve(additional) + } + + #[inline] + fn reserve_edges(&mut self, additional: usize) { + self.edges.reserve(additional) + } + #[inline] fn is_directed(&self) -> bool { DIRECTED diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/simple/map.rs index 56124a191f426..8a0010d16af3c 100644 --- a/crates/bevy_graph/src/graphs/simple/map.rs +++ b/crates/bevy_graph/src/graphs/simple/map.rs @@ -38,18 +38,31 @@ impl Graph for SimpleMapGraph } } + #[inline] fn capacity(&self) -> (usize, usize) { (self.nodes.capacity(), self.edges.capacity()) } + #[inline] fn node_capacity(&self) -> usize { self.nodes.capacity() } + #[inline] fn edge_capacity(&self) -> usize { self.edges.capacity() } + #[inline] + fn reserve_nodes(&mut self, additional: usize) { + self.nodes.reserve(additional) + } + + #[inline] + fn reserve_edges(&mut self, additional: usize) { + self.edges.reserve(additional) + } + #[inline] fn is_directed(&self) -> bool { DIRECTED From 974d0abb94e8f8a7e2026678f25118c712be3f5a Mon Sep 17 00:00:00 2001 From: DasLixou Date: Thu, 19 Jan 2023 19:29:00 +0100 Subject: [PATCH 124/183] Change file structure --- crates/bevy_graph/src/algos/bfs.rs | 2 +- crates/bevy_graph/src/algos/dfs.rs | 2 +- crates/bevy_graph/src/graphs/list/mod.rs | 5 +++++ .../src/graphs/{multi/list.rs => list/multi.rs} | 0 .../src/graphs/{simple/list.rs => list/simple.rs} | 0 crates/bevy_graph/src/graphs/map/mod.rs | 5 +++++ .../bevy_graph/src/graphs/{multi/map.rs => map/multi.rs} | 0 .../src/graphs/{simple/map.rs => map/simple.rs} | 0 crates/bevy_graph/src/graphs/mod.rs | 8 ++++---- crates/bevy_graph/src/graphs/multi/mod.rs | 5 ----- crates/bevy_graph/src/graphs/simple/mod.rs | 5 ----- 11 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 crates/bevy_graph/src/graphs/list/mod.rs rename crates/bevy_graph/src/graphs/{multi/list.rs => list/multi.rs} (100%) rename crates/bevy_graph/src/graphs/{simple/list.rs => list/simple.rs} (100%) create mode 100644 crates/bevy_graph/src/graphs/map/mod.rs rename crates/bevy_graph/src/graphs/{multi/map.rs => map/multi.rs} (100%) rename crates/bevy_graph/src/graphs/{simple/map.rs => map/simple.rs} (100%) delete mode 100644 crates/bevy_graph/src/graphs/multi/mod.rs delete mode 100644 crates/bevy_graph/src/graphs/simple/mod.rs diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 6e056cd5a5cab..b654d07d4e948 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -77,7 +77,7 @@ impl BreadthFirstSearch { mod test { use crate::{ algos::bfs::BreadthFirstSearch, - graphs::{simple::SimpleMapGraph, Graph}, + graphs::{map::SimpleMapGraph, Graph}, }; #[test] diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 124fc779b3359..fae5f1c149c80 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -74,7 +74,7 @@ impl DepthFirstSearch { mod test { use crate::{ algos::dfs::DepthFirstSearch, - graphs::{simple::SimpleMapGraph, Graph}, + graphs::{map::SimpleMapGraph, Graph}, }; #[test] diff --git a/crates/bevy_graph/src/graphs/list/mod.rs b/crates/bevy_graph/src/graphs/list/mod.rs new file mode 100644 index 0000000000000..3d7e0b9b6cf89 --- /dev/null +++ b/crates/bevy_graph/src/graphs/list/mod.rs @@ -0,0 +1,5 @@ +mod simple; +pub use simple::*; + +mod multi; +pub use multi::*; diff --git a/crates/bevy_graph/src/graphs/multi/list.rs b/crates/bevy_graph/src/graphs/list/multi.rs similarity index 100% rename from crates/bevy_graph/src/graphs/multi/list.rs rename to crates/bevy_graph/src/graphs/list/multi.rs diff --git a/crates/bevy_graph/src/graphs/simple/list.rs b/crates/bevy_graph/src/graphs/list/simple.rs similarity index 100% rename from crates/bevy_graph/src/graphs/simple/list.rs rename to crates/bevy_graph/src/graphs/list/simple.rs diff --git a/crates/bevy_graph/src/graphs/map/mod.rs b/crates/bevy_graph/src/graphs/map/mod.rs new file mode 100644 index 0000000000000..3d7e0b9b6cf89 --- /dev/null +++ b/crates/bevy_graph/src/graphs/map/mod.rs @@ -0,0 +1,5 @@ +mod simple; +pub use simple::*; + +mod multi; +pub use multi::*; diff --git a/crates/bevy_graph/src/graphs/multi/map.rs b/crates/bevy_graph/src/graphs/map/multi.rs similarity index 100% rename from crates/bevy_graph/src/graphs/multi/map.rs rename to crates/bevy_graph/src/graphs/map/multi.rs diff --git a/crates/bevy_graph/src/graphs/simple/map.rs b/crates/bevy_graph/src/graphs/map/simple.rs similarity index 100% rename from crates/bevy_graph/src/graphs/simple/map.rs rename to crates/bevy_graph/src/graphs/map/simple.rs diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index cd1479764aece..0ed0c21295219 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -1,7 +1,7 @@ -/// All graph types implementing a `MultiGraph` -pub mod multi; -/// All graph types implementing a `SimpleGraph` -pub mod simple; +/// `Vec` implementation of a graph +pub mod list; +/// `HashMap` implementation of a graph +pub mod map; /// Adjacency storage enum helper: `Directed` or `Undirected` pub mod adjacency_storage; diff --git a/crates/bevy_graph/src/graphs/multi/mod.rs b/crates/bevy_graph/src/graphs/multi/mod.rs deleted file mode 100644 index 4efa46e6469cb..0000000000000 --- a/crates/bevy_graph/src/graphs/multi/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod map; -pub use map::*; - -mod list; -pub use list::*; diff --git a/crates/bevy_graph/src/graphs/simple/mod.rs b/crates/bevy_graph/src/graphs/simple/mod.rs deleted file mode 100644 index 4efa46e6469cb..0000000000000 --- a/crates/bevy_graph/src/graphs/simple/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod map; -pub use map::*; - -mod list; -pub use list::*; From c9b2d6c797b0b65317f18fb49ca539da4e71479e Mon Sep 17 00:00:00 2001 From: DasLixou Date: Thu, 19 Jan 2023 19:54:42 +0100 Subject: [PATCH 125/183] =?UTF-8?q?Make=20`Edges`=20iter=20=F0=9F=A5=B3?= =?UTF-8?q?=F0=9F=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/bevy_graph/src/algos/bfs.rs | 10 ++---- crates/bevy_graph/src/algos/dfs.rs | 10 ++---- crates/bevy_graph/src/graphs/iters.rs | 35 +++++++++++++++++++++ crates/bevy_graph/src/graphs/list/multi.rs | 17 +++------- crates/bevy_graph/src/graphs/list/simple.rs | 9 +++--- crates/bevy_graph/src/graphs/map/multi.rs | 17 +++------- crates/bevy_graph/src/graphs/map/simple.rs | 9 +++--- crates/bevy_graph/src/graphs/mod.rs | 6 ++-- 8 files changed, 63 insertions(+), 50 deletions(-) create mode 100644 crates/bevy_graph/src/graphs/iters.rs diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index b654d07d4e948..3632dd0acd04a 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -39,10 +39,7 @@ impl BreadthFirstSearch { /// Gets an immutable reference to the value of the next node from the algorithm pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { if let Some(node) = self.queue.pop_front() { - for EdgeRef(_, dst, _) in graph - .outgoing_edges_of(node) - .map(|e| graph.get_edge(e).unwrap()) - { + for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.queue.push_back(dst); @@ -57,10 +54,7 @@ impl BreadthFirstSearch { /// Gets a mutable reference to the value of the next node from the algorithm. pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.queue.pop_front() { - for EdgeRef(_, dst, _) in graph - .outgoing_edges_of(node) - .map(|e| graph.get_edge(e).unwrap()) - { + for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.queue.push_back(dst); diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index fae5f1c149c80..bfb2b8eb5146d 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -36,10 +36,7 @@ impl DepthFirstSearch { /// Gets a reference to the value of the next node from the algorithm. pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { if let Some(node) = self.stack.pop() { - for EdgeRef(_, dst, _) in graph - .outgoing_edges_of(node) - .map(|e| graph.get_edge(e).unwrap()) - { + for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.stack.push(dst); @@ -54,10 +51,7 @@ impl DepthFirstSearch { /// Gets a mutable reference to the value of the next node from the algorithm. pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.stack.pop() { - for EdgeRef(_, dst, _) in graph - .outgoing_edges_of(node) - .map(|e| graph.get_edge(e).unwrap()) - { + for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.stack.push(dst); diff --git a/crates/bevy_graph/src/graphs/iters.rs b/crates/bevy_graph/src/graphs/iters.rs new file mode 100644 index 0000000000000..7c282634b267f --- /dev/null +++ b/crates/bevy_graph/src/graphs/iters.rs @@ -0,0 +1,35 @@ +use std::marker::PhantomData; + +use super::{edge::EdgeRef, keys::EdgeIdx, Graph}; + +/// An iterator which converts `&EdgeIdx` to a `EdgeRef` of the graph +pub struct Edges<'g, N, E: 'g, G: Graph, I: Iterator> { + graph: &'g G, + inner: I, + phantom: PhantomData<(N, E)>, +} + +impl<'g, N, E: 'g, G: Graph, I: Iterator> Edges<'g, N, E, G, I> { + /// Creates a new `Edges` iterator over a graph with the provided `inner` iterator + pub fn new(inner: I, graph: &'g G) -> Self { + Self { + graph, + inner, + phantom: PhantomData, + } + } +} + +impl<'g, N, E: 'g, G: Graph, I: Iterator> Iterator + for Edges<'g, N, E, G, I> +{ + type Item = EdgeRef<'g, E>; + + fn next(&mut self) -> Option { + if let Some(index) = self.inner.next() { + self.graph.get_edge(*index) + } else { + None + } + } +} diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index cc8eea13f74b1..c13e4be6a3a2c 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -5,6 +5,7 @@ use crate::{ graphs::{ adjacency_storage::AdjacencyStorage, edge::{Edge, EdgeMut, EdgeRef}, + iters::Edges, keys::{EdgeIdx, NodeIdx}, Graph, }, @@ -225,21 +226,13 @@ impl Graph for MultiListGraph self.edges.values_mut() } - type IncomingEdgesOf<'e> = std::iter::Cloned>>> where Self: 'e; + type IncomingEdgesOf<'e> = Edges<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - self.adjacencies[index] - .incoming() - .values() - .flatten() - .cloned() + Edges::new(self.adjacencies[index].incoming().values().flatten(), self) } - type OutgoingEdgesOf<'e> = std::iter::Cloned>>> where Self: 'e; + type OutgoingEdgesOf<'e> = Edges<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - self.adjacencies[index] - .outgoing() - .values() - .flatten() - .cloned() + Edges::new(self.adjacencies[index].outgoing().values().flatten(), self) } } diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index a9b367069b18a..1a0ea3b2d9ac3 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -5,6 +5,7 @@ use crate::{ graphs::{ adjacency_storage::AdjacencyStorage, edge::{Edge, EdgeMut, EdgeRef}, + iters::Edges, keys::{EdgeIdx, NodeIdx}, Graph, }, @@ -224,13 +225,13 @@ impl Graph for SimpleListGraph self.edges.values_mut() } - type IncomingEdgesOf<'e> = std::iter::Cloned> where Self: 'e; + type IncomingEdgesOf<'e> = Edges<'e, N, E, Self, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - self.adjacencies[index].incoming().values().cloned() + Edges::new(self.adjacencies[index].incoming().values(), self) } - type OutgoingEdgesOf<'e> = std::iter::Cloned> where Self: 'e; + type OutgoingEdgesOf<'e> = Edges<'e, N, E, Self, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - self.adjacencies[index].outgoing().values().cloned() + Edges::new(self.adjacencies[index].outgoing().values(), self) } } diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index b851a45b99ad7..6a7007b92e335 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -6,6 +6,7 @@ use crate::{ graphs::{ adjacency_storage::AdjacencyStorage, edge::{Edge, EdgeMut, EdgeRef}, + iters::Edges, keys::{EdgeIdx, NodeIdx}, Graph, }, @@ -229,21 +230,13 @@ impl Graph for MultiMapGraph { self.edges.values_mut() } - type IncomingEdgesOf<'e> = std::iter::Cloned>>> where Self: 'e; + type IncomingEdgesOf<'e> = Edges<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - self.adjacencies[index] - .incoming() - .values() - .flatten() - .cloned() + Edges::new(self.adjacencies[index].incoming().values().flatten(), self) } - type OutgoingEdgesOf<'e> = std::iter::Cloned>>> where Self: 'e; + type OutgoingEdgesOf<'e> = Edges<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - self.adjacencies[index] - .outgoing() - .values() - .flatten() - .cloned() + Edges::new(self.adjacencies[index].outgoing().values().flatten(), self) } } diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 8a0010d16af3c..5543cb1f17f1e 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -6,6 +6,7 @@ use crate::{ graphs::{ adjacency_storage::AdjacencyStorage, edge::{Edge, EdgeMut, EdgeRef}, + iters::Edges, keys::{EdgeIdx, NodeIdx}, Graph, }, @@ -220,13 +221,13 @@ impl Graph for SimpleMapGraph self.edges.values_mut() } - type IncomingEdgesOf<'e> = std::iter::Cloned> where Self: 'e; + type IncomingEdgesOf<'e> = Edges<'e, N, E, Self, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - self.adjacencies[index].incoming().values().cloned() + Edges::new(self.adjacencies[index].incoming().values(), self) } - type OutgoingEdgesOf<'e> = std::iter::Cloned> where Self: 'e; + type OutgoingEdgesOf<'e> = Edges<'e, N, E, Self, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - self.adjacencies[index].outgoing().values().cloned() + Edges::new(self.adjacencies[index].outgoing().values(), self) } } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 0ed0c21295219..3a781f9b36776 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -7,6 +7,8 @@ pub mod map; pub mod adjacency_storage; /// An edge between nodes that store data of type `E`. pub mod edge; +/// Helping `Iterator`s for graphs +pub mod iters; /// The `NodeIdx` and `EdgeIdx` structs pub mod keys; @@ -44,12 +46,12 @@ pub trait Graph { Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type IncomingEdgesOf<'e>: Iterator + type IncomingEdgesOf<'e>: Iterator> where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type OutgoingEdgesOf<'e>: Iterator + type OutgoingEdgesOf<'e>: Iterator> where Self: 'e, E: 'e; From 584f89cc785ed31226e767b15a2edcc7c2b58bcb Mon Sep 17 00:00:00 2001 From: DasLixou Date: Thu, 19 Jan 2023 19:57:45 +0100 Subject: [PATCH 126/183] Move iters to own folder --- crates/bevy_graph/src/graphs/list/multi.rs | 2 +- crates/bevy_graph/src/graphs/list/simple.rs | 2 +- crates/bevy_graph/src/graphs/map/multi.rs | 2 +- crates/bevy_graph/src/graphs/map/simple.rs | 2 +- crates/bevy_graph/src/graphs/mod.rs | 2 -- crates/bevy_graph/src/{graphs/iters.rs => iters/edges.rs} | 2 +- crates/bevy_graph/src/iters/mod.rs | 2 ++ crates/bevy_graph/src/lib.rs | 2 ++ 8 files changed, 9 insertions(+), 7 deletions(-) rename crates/bevy_graph/src/{graphs/iters.rs => iters/edges.rs} (94%) create mode 100644 crates/bevy_graph/src/iters/mod.rs diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index c13e4be6a3a2c..82951c2819dce 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -5,10 +5,10 @@ use crate::{ graphs::{ adjacency_storage::AdjacencyStorage, edge::{Edge, EdgeMut, EdgeRef}, - iters::Edges, keys::{EdgeIdx, NodeIdx}, Graph, }, + iters::Edges, utils::{vecmap::VecMap, vecset::VecSet}, }; diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 1a0ea3b2d9ac3..c4749083de4f1 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -5,10 +5,10 @@ use crate::{ graphs::{ adjacency_storage::AdjacencyStorage, edge::{Edge, EdgeMut, EdgeRef}, - iters::Edges, keys::{EdgeIdx, NodeIdx}, Graph, }, + iters::Edges, utils::vecmap::VecMap, }; diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 6a7007b92e335..761e7b4035f06 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -6,10 +6,10 @@ use crate::{ graphs::{ adjacency_storage::AdjacencyStorage, edge::{Edge, EdgeMut, EdgeRef}, - iters::Edges, keys::{EdgeIdx, NodeIdx}, Graph, }, + iters::Edges, utils::vecset::VecSet, }; diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 5543cb1f17f1e..348772ceb14ff 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -6,10 +6,10 @@ use crate::{ graphs::{ adjacency_storage::AdjacencyStorage, edge::{Edge, EdgeMut, EdgeRef}, - iters::Edges, keys::{EdgeIdx, NodeIdx}, Graph, }, + iters::Edges, }; /// Implementation of a `SimpleGraph` which uses `HashMap` for adjacencies diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 3a781f9b36776..a37efe7637d3d 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -7,8 +7,6 @@ pub mod map; pub mod adjacency_storage; /// An edge between nodes that store data of type `E`. pub mod edge; -/// Helping `Iterator`s for graphs -pub mod iters; /// The `NodeIdx` and `EdgeIdx` structs pub mod keys; diff --git a/crates/bevy_graph/src/graphs/iters.rs b/crates/bevy_graph/src/iters/edges.rs similarity index 94% rename from crates/bevy_graph/src/graphs/iters.rs rename to crates/bevy_graph/src/iters/edges.rs index 7c282634b267f..78010d0ffcd96 100644 --- a/crates/bevy_graph/src/graphs/iters.rs +++ b/crates/bevy_graph/src/iters/edges.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use super::{edge::EdgeRef, keys::EdgeIdx, Graph}; +use crate::graphs::{edge::EdgeRef, keys::EdgeIdx, Graph}; /// An iterator which converts `&EdgeIdx` to a `EdgeRef` of the graph pub struct Edges<'g, N, E: 'g, G: Graph, I: Iterator> { diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs new file mode 100644 index 0000000000000..324a7b4e706a4 --- /dev/null +++ b/crates/bevy_graph/src/iters/mod.rs @@ -0,0 +1,2 @@ +mod edges; +pub use edges::*; diff --git a/crates/bevy_graph/src/lib.rs b/crates/bevy_graph/src/lib.rs index e4b401ae6a0ea..e7bba897d0ed7 100644 --- a/crates/bevy_graph/src/lib.rs +++ b/crates/bevy_graph/src/lib.rs @@ -7,5 +7,7 @@ pub mod algos; pub mod error; /// The `Graph` trait and all graph implementations pub mod graphs; +/// Helping `Iterator`s for graphs +pub mod iters; /// Utils used by graphs pub mod utils; From 68d6b868140e14f63923eec529b90da7a099af03 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 20 Jan 2023 17:39:44 +0100 Subject: [PATCH 127/183] make ci happy --- crates/bevy_graph/src/graphs/edge.rs | 4 ++-- crates/bevy_graph/src/graphs/list/multi.rs | 20 +++++++------------- crates/bevy_graph/src/graphs/list/simple.rs | 20 ++++++-------------- crates/bevy_graph/src/graphs/map/multi.rs | 16 ++++------------ crates/bevy_graph/src/graphs/map/simple.rs | 18 +++++------------- crates/bevy_graph/src/utils/vecmap.rs | 6 +----- crates/bevy_graph/src/utils/vecset.rs | 6 +----- 7 files changed, 26 insertions(+), 64 deletions(-) diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs index 32965956c7cb2..bb52d6121934f 100644 --- a/crates/bevy_graph/src/graphs/edge.rs +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -9,13 +9,13 @@ pub struct Edge(pub NodeIdx, pub NodeIdx, pub E); impl Edge { /// Returns a [`EdgeRef`] of this edge #[inline] - pub const fn as_ref_edge<'v>(&'v self) -> EdgeRef<'v, E> { + pub const fn as_ref_edge(&self) -> EdgeRef { EdgeRef(self.0, self.1, &self.2) } /// Returns a [`EdgeMut`] of this edge #[inline] - pub fn as_mut_edge<'v>(&'v mut self) -> EdgeMut<'v, E> { + pub fn as_mut_edge(&mut self) -> EdgeMut { EdgeMut(self.0, self.1, &mut self.2) } } diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 82951c2819dce..90829092540ee 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -12,6 +12,8 @@ use crate::{ utils::{vecmap::VecMap, vecset::VecSet}, }; +type MultiListGraphStorage = AdjacencyStorage)>>; + /// Implementation of a `MultiGraph` which uses `Vec<(NodeIdx, Vec)>` for adjacencies /// /// `MultiGraph`s can hold multiple edges between two nodes and edges between the same node @@ -19,7 +21,7 @@ use crate::{ pub struct MultiListGraph { nodes: HopSlotMap, edges: HopSlotMap>, - adjacencies: SecondaryMap)>>>, + adjacencies: SecondaryMap, } impl Graph for MultiListGraph { @@ -186,20 +188,12 @@ impl Graph for MultiListGraph #[inline] fn get_edge(&self, index: EdgeIdx) -> Option> { - if let Some(edge) = self.edges.get(index) { - Some(edge.as_ref_edge()) - } else { - None - } + self.edges.get(index).map(|edge| edge.as_ref_edge()) } #[inline] fn get_edge_mut(&mut self, index: EdgeIdx) -> Option> { - if let Some(edge) = self.edges.get_mut(index) { - Some(edge.as_mut_edge()) - } else { - None - } + self.edges.get_mut(index).map(|edge| edge.as_mut_edge()) } fn degree(&self, _index: NodeIdx) -> usize { @@ -208,12 +202,12 @@ impl Graph for MultiListGraph type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; fn nodes(&self) -> Self::Nodes<'_> { - self.nodes.values().into_iter() + self.nodes.values() } type NodesMut<'n> = slotmap::hop::ValuesMut<'n, NodeIdx, N> where Self: 'n; fn nodes_mut(&mut self) -> Self::NodesMut<'_> { - self.nodes.values_mut().into_iter() + self.nodes.values_mut() } type Edges<'e> = slotmap::hop::Values<'e, EdgeIdx, Edge> where Self: 'e; diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index c4749083de4f1..47a81ef2b6655 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -56,12 +56,12 @@ impl Graph for SimpleListGraph #[inline] fn reserve_nodes(&mut self, additional: usize) { - self.nodes.reserve(additional) + self.nodes.reserve(additional); } #[inline] fn reserve_edges(&mut self, additional: usize) { - self.edges.reserve(additional) + self.edges.reserve(additional); } #[inline] @@ -185,20 +185,12 @@ impl Graph for SimpleListGraph #[inline] fn get_edge(&self, index: EdgeIdx) -> Option> { - if let Some(edge) = self.edges.get(index) { - Some(edge.as_ref_edge()) - } else { - None - } + self.edges.get(index).map(|edge| edge.as_ref_edge()) } #[inline] fn get_edge_mut(&mut self, index: EdgeIdx) -> Option> { - if let Some(edge) = self.edges.get_mut(index) { - Some(edge.as_mut_edge()) - } else { - None - } + self.edges.get_mut(index).map(|edge| edge.as_mut_edge()) } fn degree(&self, _index: NodeIdx) -> usize { @@ -207,12 +199,12 @@ impl Graph for SimpleListGraph type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; fn nodes(&self) -> Self::Nodes<'_> { - self.nodes.values().into_iter() + self.nodes.values() } type NodesMut<'n> = slotmap::hop::ValuesMut<'n, NodeIdx, N> where Self: 'n; fn nodes_mut(&mut self) -> Self::NodesMut<'_> { - self.nodes.values_mut().into_iter() + self.nodes.values_mut() } type Edges<'e> = slotmap::hop::Values<'e, EdgeIdx, Edge> where Self: 'e; diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 761e7b4035f06..7895205fef06e 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -190,20 +190,12 @@ impl Graph for MultiMapGraph { #[inline] fn get_edge(&self, index: EdgeIdx) -> Option> { - if let Some(edge) = self.edges.get(index) { - Some(edge.as_ref_edge()) - } else { - None - } + self.edges.get(index).map(|edge| edge.as_ref_edge()) } #[inline] fn get_edge_mut(&mut self, index: EdgeIdx) -> Option> { - if let Some(edge) = self.edges.get_mut(index) { - Some(edge.as_mut_edge()) - } else { - None - } + self.edges.get_mut(index).map(|edge| edge.as_mut_edge()) } fn degree(&self, _index: NodeIdx) -> usize { @@ -212,12 +204,12 @@ impl Graph for MultiMapGraph { type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; fn nodes(&self) -> Self::Nodes<'_> { - self.nodes.values().into_iter() + self.nodes.values() } type NodesMut<'n> = slotmap::hop::ValuesMut<'n, NodeIdx, N> where Self: 'n; fn nodes_mut(&mut self) -> Self::NodesMut<'_> { - self.nodes.values_mut().into_iter() + self.nodes.values_mut() } type Edges<'e> = slotmap::hop::Values<'e, EdgeIdx, Edge> where Self: 'e; diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 348772ceb14ff..0926735bf51f9 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -181,20 +181,12 @@ impl Graph for SimpleMapGraph #[inline] fn get_edge(&self, index: EdgeIdx) -> Option> { - if let Some(edge) = self.edges.get(index) { - Some(edge.as_ref_edge()) - } else { - None - } + self.edges.get(index).map(|edge| edge.as_ref_edge()) } #[inline] fn get_edge_mut(&mut self, index: EdgeIdx) -> Option> { - if let Some(edge) = self.edges.get_mut(index) { - Some(edge.as_mut_edge()) - } else { - None - } + self.edges.get_mut(index).map(|edge| edge.as_mut_edge()) } fn degree(&self, _index: NodeIdx) -> usize { @@ -203,16 +195,16 @@ impl Graph for SimpleMapGraph type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; fn nodes(&self) -> Self::Nodes<'_> { - self.nodes.values().into_iter() + self.nodes.values() } type NodesMut<'n> = slotmap::hop::ValuesMut<'n, NodeIdx, N> where Self: 'n; fn nodes_mut(&mut self) -> Self::NodesMut<'_> { - self.nodes.values_mut().into_iter() + self.nodes.values_mut() } type Edges<'e> = slotmap::hop::Values<'e, EdgeIdx, Edge> where Self: 'e; - fn edges<'e>(&'e self) -> Self::Edges<'e> { + fn edges(&self) -> Self::Edges<'_> { self.edges.values() } diff --git a/crates/bevy_graph/src/utils/vecmap.rs b/crates/bevy_graph/src/utils/vecmap.rs index 3a0ed8ef3bebe..bcdd0ea64c3a4 100644 --- a/crates/bevy_graph/src/utils/vecmap.rs +++ b/crates/bevy_graph/src/utils/vecmap.rs @@ -91,11 +91,7 @@ impl VecMap for Vec<(K, V)> { } fn remove_by_key(&mut self, key: K) -> Option { - if let Some(index) = self.index_by_key(&key) { - Some(self.remove(index).1) - } else { - None - } + self.index_by_key(&key).map(|index| self.remove(index).1) } fn values(&self) -> Values { diff --git a/crates/bevy_graph/src/utils/vecset.rs b/crates/bevy_graph/src/utils/vecset.rs index 0a8e3bd40d894..f079202e07b27 100644 --- a/crates/bevy_graph/src/utils/vecset.rs +++ b/crates/bevy_graph/src/utils/vecset.rs @@ -12,10 +12,6 @@ impl VecSet for Vec { } fn remove_by_value(&mut self, value: &T) -> Option { - if let Some(index) = self.index_by_value(value) { - Some(self.remove(index)) - } else { - None - } + self.index_by_value(value).map(|index| self.remove(index)) } } From 71c8881e7a1f820c567cdcbae8c73b3ac94f239b Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 20 Jan 2023 17:48:48 +0100 Subject: [PATCH 128/183] ci --- crates/bevy_graph/src/graphs/list/multi.rs | 8 +++----- crates/bevy_graph/src/graphs/map/multi.rs | 4 ++-- crates/bevy_graph/src/graphs/map/simple.rs | 4 ++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 90829092540ee..8692fa6adaa5e 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -12,8 +12,6 @@ use crate::{ utils::{vecmap::VecMap, vecset::VecSet}, }; -type MultiListGraphStorage = AdjacencyStorage)>>; - /// Implementation of a `MultiGraph` which uses `Vec<(NodeIdx, Vec)>` for adjacencies /// /// `MultiGraph`s can hold multiple edges between two nodes and edges between the same node @@ -21,7 +19,7 @@ type MultiListGraphStorage = AdjacencyStorage)>>; pub struct MultiListGraph { nodes: HopSlotMap, edges: HopSlotMap>, - adjacencies: SecondaryMap, + adjacencies: SecondaryMap)>>>, } impl Graph for MultiListGraph { @@ -58,12 +56,12 @@ impl Graph for MultiListGraph #[inline] fn reserve_nodes(&mut self, additional: usize) { - self.nodes.reserve(additional) + self.nodes.reserve(additional); } #[inline] fn reserve_edges(&mut self, additional: usize) { - self.edges.reserve(additional) + self.edges.reserve(additional); } #[inline] diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 7895205fef06e..41139f11bb181 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -57,12 +57,12 @@ impl Graph for MultiMapGraph { #[inline] fn reserve_nodes(&mut self, additional: usize) { - self.nodes.reserve(additional) + self.nodes.reserve(additional); } #[inline] fn reserve_edges(&mut self, additional: usize) { - self.edges.reserve(additional) + self.edges.reserve(additional); } #[inline] diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 0926735bf51f9..69baed69f1cb2 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -56,12 +56,12 @@ impl Graph for SimpleMapGraph #[inline] fn reserve_nodes(&mut self, additional: usize) { - self.nodes.reserve(additional) + self.nodes.reserve(additional); } #[inline] fn reserve_edges(&mut self, additional: usize) { - self.edges.reserve(additional) + self.edges.reserve(additional); } #[inline] From 6b20640c13f38dd2957f0df55e1752787ca5e41e Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 20 Jan 2023 17:57:27 +0100 Subject: [PATCH 129/183] doc backtick --- crates/bevy_graph/src/utils/vecmap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/utils/vecmap.rs b/crates/bevy_graph/src/utils/vecmap.rs index bcdd0ea64c3a4..7cfddeceed7c1 100644 --- a/crates/bevy_graph/src/utils/vecmap.rs +++ b/crates/bevy_graph/src/utils/vecmap.rs @@ -99,7 +99,7 @@ impl VecMap for Vec<(K, V)> { } } -/// Iterator over all values in a VecMap +/// Iterator over all values in a `VecMap` pub struct Values<'s, K: PartialEq, V> { inner: slice::Iter<'s, (K, V)>, } From d790808009983840eac3e943061a188e97a87c85 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 20 Jan 2023 18:06:23 +0100 Subject: [PATCH 130/183] Renaimg iter --- crates/bevy_graph/src/graphs/list/multi.rs | 10 +++++----- crates/bevy_graph/src/graphs/list/simple.rs | 10 +++++----- crates/bevy_graph/src/graphs/map/multi.rs | 10 +++++----- crates/bevy_graph/src/graphs/map/simple.rs | 10 +++++----- .../bevy_graph/src/iters/{edges.rs => edges_by_idx.rs} | 8 ++++---- crates/bevy_graph/src/iters/mod.rs | 4 ++-- 6 files changed, 26 insertions(+), 26 deletions(-) rename crates/bevy_graph/src/iters/{edges.rs => edges_by_idx.rs} (75%) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 8692fa6adaa5e..49ea1184b5c24 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -8,7 +8,7 @@ use crate::{ keys::{EdgeIdx, NodeIdx}, Graph, }, - iters::Edges, + iters, utils::{vecmap::VecMap, vecset::VecSet}, }; @@ -218,13 +218,13 @@ impl Graph for MultiListGraph self.edges.values_mut() } - type IncomingEdgesOf<'e> = Edges<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - Edges::new(self.adjacencies[index].incoming().values().flatten(), self) + iters::EdgesByIdx::new(self.adjacencies[index].incoming().values().flatten(), self) } - type OutgoingEdgesOf<'e> = Edges<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - Edges::new(self.adjacencies[index].outgoing().values().flatten(), self) + iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values().flatten(), self) } } diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 47a81ef2b6655..e8b4ec561d3b7 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -8,7 +8,7 @@ use crate::{ keys::{EdgeIdx, NodeIdx}, Graph, }, - iters::Edges, + iters, utils::vecmap::VecMap, }; @@ -217,13 +217,13 @@ impl Graph for SimpleListGraph self.edges.values_mut() } - type IncomingEdgesOf<'e> = Edges<'e, N, E, Self, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - Edges::new(self.adjacencies[index].incoming().values(), self) + iters::EdgesByIdx::new(self.adjacencies[index].incoming().values(), self) } - type OutgoingEdgesOf<'e> = Edges<'e, N, E, Self, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - Edges::new(self.adjacencies[index].outgoing().values(), self) + iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values(), self) } } diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 41139f11bb181..946e962a18ce7 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -9,7 +9,7 @@ use crate::{ keys::{EdgeIdx, NodeIdx}, Graph, }, - iters::Edges, + iters, utils::vecset::VecSet, }; @@ -222,13 +222,13 @@ impl Graph for MultiMapGraph { self.edges.values_mut() } - type IncomingEdgesOf<'e> = Edges<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - Edges::new(self.adjacencies[index].incoming().values().flatten(), self) + iters::EdgesByIdx::new(self.adjacencies[index].incoming().values().flatten(), self) } - type OutgoingEdgesOf<'e> = Edges<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - Edges::new(self.adjacencies[index].outgoing().values().flatten(), self) + iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values().flatten(), self) } } diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 69baed69f1cb2..5b85e8e9404cd 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -9,7 +9,7 @@ use crate::{ keys::{EdgeIdx, NodeIdx}, Graph, }, - iters::Edges, + iters, }; /// Implementation of a `SimpleGraph` which uses `HashMap` for adjacencies @@ -213,13 +213,13 @@ impl Graph for SimpleMapGraph self.edges.values_mut() } - type IncomingEdgesOf<'e> = Edges<'e, N, E, Self, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - Edges::new(self.adjacencies[index].incoming().values(), self) + iters::EdgesByIdx::new(self.adjacencies[index].incoming().values(), self) } - type OutgoingEdgesOf<'e> = Edges<'e, N, E, Self, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - Edges::new(self.adjacencies[index].outgoing().values(), self) + iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values(), self) } } diff --git a/crates/bevy_graph/src/iters/edges.rs b/crates/bevy_graph/src/iters/edges_by_idx.rs similarity index 75% rename from crates/bevy_graph/src/iters/edges.rs rename to crates/bevy_graph/src/iters/edges_by_idx.rs index 78010d0ffcd96..037c9248cdae3 100644 --- a/crates/bevy_graph/src/iters/edges.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx.rs @@ -3,14 +3,14 @@ use std::marker::PhantomData; use crate::graphs::{edge::EdgeRef, keys::EdgeIdx, Graph}; /// An iterator which converts `&EdgeIdx` to a `EdgeRef` of the graph -pub struct Edges<'g, N, E: 'g, G: Graph, I: Iterator> { +pub struct EdgesByIdx<'g, N, E: 'g, G: Graph, I: Iterator> { graph: &'g G, inner: I, phantom: PhantomData<(N, E)>, } -impl<'g, N, E: 'g, G: Graph, I: Iterator> Edges<'g, N, E, G, I> { - /// Creates a new `Edges` iterator over a graph with the provided `inner` iterator +impl<'g, N, E: 'g, G: Graph, I: Iterator> EdgesByIdx<'g, N, E, G, I> { + /// Creates a new `EdgesByIdx` iterator over a graph with the provided `inner` iterator pub fn new(inner: I, graph: &'g G) -> Self { Self { graph, @@ -21,7 +21,7 @@ impl<'g, N, E: 'g, G: Graph, I: Iterator> Edges<'g, N, } impl<'g, N, E: 'g, G: Graph, I: Iterator> Iterator - for Edges<'g, N, E, G, I> + for EdgesByIdx<'g, N, E, G, I> { type Item = EdgeRef<'g, E>; diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs index 324a7b4e706a4..95e8a31ec361e 100644 --- a/crates/bevy_graph/src/iters/mod.rs +++ b/crates/bevy_graph/src/iters/mod.rs @@ -1,2 +1,2 @@ -mod edges; -pub use edges::*; +mod edges_by_idx; +pub use edges_by_idx::*; From eabfb8528e6ebeefe79c3e9c05a56f2b065e767a Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 20 Jan 2023 18:10:44 +0100 Subject: [PATCH 131/183] Add `EdgesRef` iter --- crates/bevy_graph/src/iters/edges_ref.rs | 27 ++++++++++++++++++++++++ crates/bevy_graph/src/iters/mod.rs | 3 +++ 2 files changed, 30 insertions(+) create mode 100644 crates/bevy_graph/src/iters/edges_ref.rs diff --git a/crates/bevy_graph/src/iters/edges_ref.rs b/crates/bevy_graph/src/iters/edges_ref.rs new file mode 100644 index 0000000000000..49df915fa68d4 --- /dev/null +++ b/crates/bevy_graph/src/iters/edges_ref.rs @@ -0,0 +1,27 @@ +use std::marker::PhantomData; + +use crate::graphs::edge::{Edge, EdgeRef}; + +/// An iterator which converts `&'g Edge` to a `EdgeRef<'g, E>` +pub struct EdgesRef<'g, E: 'g, I: Iterator>> { + inner: I, + phantom: PhantomData, +} + +impl<'g, E: 'g, I: Iterator>> EdgesRef<'g, E, I> { + /// Creates a new `EdgesRef` iterator with the provided `inner` iterator + pub fn new(inner: I) -> Self { + Self { + inner, + phantom: PhantomData, + } + } +} + +impl<'g, E: 'g, I: Iterator>> Iterator for EdgesRef<'g, E, I> { + type Item = EdgeRef<'g, E>; + + fn next(&mut self) -> Option { + self.inner.next().map(|edge| edge.as_ref_edge()) + } +} diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs index 95e8a31ec361e..ba0e3b202a74d 100644 --- a/crates/bevy_graph/src/iters/mod.rs +++ b/crates/bevy_graph/src/iters/mod.rs @@ -1,2 +1,5 @@ mod edges_by_idx; pub use edges_by_idx::*; + +mod edges_ref; +pub use edges_ref::*; From ab9cdcd8fbbbb212b04264a58e6a3a6f75b0d3e0 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 20 Jan 2023 18:12:24 +0100 Subject: [PATCH 132/183] Use the new `EdgesRef` iter --- crates/bevy_graph/src/graphs/list/multi.rs | 4 ++-- crates/bevy_graph/src/graphs/list/simple.rs | 4 ++-- crates/bevy_graph/src/graphs/map/multi.rs | 4 ++-- crates/bevy_graph/src/graphs/map/simple.rs | 4 ++-- crates/bevy_graph/src/graphs/mod.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 49ea1184b5c24..776f25edca77b 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -208,9 +208,9 @@ impl Graph for MultiListGraph self.nodes.values_mut() } - type Edges<'e> = slotmap::hop::Values<'e, EdgeIdx, Edge> where Self: 'e; + type Edges<'e> = iters::EdgesRef<'e, E, slotmap::hop::Values<'e, EdgeIdx, Edge>> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { - self.edges.values() + iters::EdgesRef::new(self.edges.values()) } type EdgesMut<'e> = slotmap::hop::ValuesMut<'e, EdgeIdx, Edge> where Self: 'e; diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index e8b4ec561d3b7..e005c097b139c 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -207,9 +207,9 @@ impl Graph for SimpleListGraph self.nodes.values_mut() } - type Edges<'e> = slotmap::hop::Values<'e, EdgeIdx, Edge> where Self: 'e; + type Edges<'e> = iters::EdgesRef<'e, E, slotmap::hop::Values<'e, EdgeIdx, Edge>> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { - self.edges.values() + iters::EdgesRef::new(self.edges.values()) } type EdgesMut<'e> = slotmap::hop::ValuesMut<'e, EdgeIdx, Edge> where Self: 'e; diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 946e962a18ce7..92e3c41342bf2 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -212,9 +212,9 @@ impl Graph for MultiMapGraph { self.nodes.values_mut() } - type Edges<'e> = slotmap::hop::Values<'e, EdgeIdx, Edge> where Self: 'e; + type Edges<'e> = iters::EdgesRef<'e, E, slotmap::hop::Values<'e, EdgeIdx, Edge>> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { - self.edges.values() + iters::EdgesRef::new(self.edges.values()) } type EdgesMut<'e> = slotmap::hop::ValuesMut<'e, EdgeIdx, Edge> where Self: 'e; diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 5b85e8e9404cd..9db3f44548f76 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -203,9 +203,9 @@ impl Graph for SimpleMapGraph self.nodes.values_mut() } - type Edges<'e> = slotmap::hop::Values<'e, EdgeIdx, Edge> where Self: 'e; + type Edges<'e> = iters::EdgesRef<'e, E, slotmap::hop::Values<'e, EdgeIdx, Edge>> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { - self.edges.values() + iters::EdgesRef::new(self.edges.values()) } type EdgesMut<'e> = slotmap::hop::ValuesMut<'e, EdgeIdx, Edge> where Self: 'e; diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index a37efe7637d3d..32c0ef3c2da30 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -34,7 +34,7 @@ pub trait Graph { Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type Edges<'e>: Iterator> + type Edges<'e>: Iterator> where Self: 'e, E: 'e; From 8ffa7a84874f90c34861a92ff108de15764b87a5 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 20 Jan 2023 18:14:08 +0100 Subject: [PATCH 133/183] Add `EdgesMut` iter --- crates/bevy_graph/src/iters/edges_mut.rs | 27 ++++++++++++++++++++++++ crates/bevy_graph/src/iters/mod.rs | 3 +++ 2 files changed, 30 insertions(+) create mode 100644 crates/bevy_graph/src/iters/edges_mut.rs diff --git a/crates/bevy_graph/src/iters/edges_mut.rs b/crates/bevy_graph/src/iters/edges_mut.rs new file mode 100644 index 0000000000000..2980a456d3c6f --- /dev/null +++ b/crates/bevy_graph/src/iters/edges_mut.rs @@ -0,0 +1,27 @@ +use std::marker::PhantomData; + +use crate::graphs::edge::{Edge, EdgeMut}; + +/// An iterator which converts `&'g mut Edge` to a `EdgeMut<'g, E>` +pub struct EdgesMut<'g, E: 'g, I: Iterator>> { + inner: I, + phantom: PhantomData, +} + +impl<'g, E: 'g, I: Iterator>> EdgesMut<'g, E, I> { + /// Creates a new `EdgesMut` iterator with the provided `inner` iterator + pub fn new(inner: I) -> Self { + Self { + inner, + phantom: PhantomData, + } + } +} + +impl<'g, E: 'g, I: Iterator>> Iterator for EdgesMut<'g, E, I> { + type Item = EdgeMut<'g, E>; + + fn next(&mut self) -> Option { + self.inner.next().map(|edge| edge.as_mut_edge()) + } +} diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs index ba0e3b202a74d..516c00144682b 100644 --- a/crates/bevy_graph/src/iters/mod.rs +++ b/crates/bevy_graph/src/iters/mod.rs @@ -3,3 +3,6 @@ pub use edges_by_idx::*; mod edges_ref; pub use edges_ref::*; + +mod edges_mut; +pub use edges_mut::*; From 2ff2a2f13bd430f8bf138f8a3f10ec31df86ce7f Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 20 Jan 2023 18:15:38 +0100 Subject: [PATCH 134/183] Use new `EdgesMut` iter --- crates/bevy_graph/src/graphs/list/multi.rs | 4 ++-- crates/bevy_graph/src/graphs/list/simple.rs | 4 ++-- crates/bevy_graph/src/graphs/map/multi.rs | 4 ++-- crates/bevy_graph/src/graphs/map/simple.rs | 4 ++-- crates/bevy_graph/src/graphs/mod.rs | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 776f25edca77b..79f67f56fb378 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -213,9 +213,9 @@ impl Graph for MultiListGraph iters::EdgesRef::new(self.edges.values()) } - type EdgesMut<'e> = slotmap::hop::ValuesMut<'e, EdgeIdx, Edge> where Self: 'e; + type EdgesMut<'e> = iters::EdgesMut<'e, E, slotmap::hop::ValuesMut<'e, EdgeIdx, Edge>> where Self: 'e; fn edges_mut(&mut self) -> Self::EdgesMut<'_> { - self.edges.values_mut() + iters::EdgesMut::new(self.edges.values_mut()) } type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index e005c097b139c..40252ec3642b1 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -212,9 +212,9 @@ impl Graph for SimpleListGraph iters::EdgesRef::new(self.edges.values()) } - type EdgesMut<'e> = slotmap::hop::ValuesMut<'e, EdgeIdx, Edge> where Self: 'e; + type EdgesMut<'e> = iters::EdgesMut<'e, E, slotmap::hop::ValuesMut<'e, EdgeIdx, Edge>> where Self: 'e; fn edges_mut(&mut self) -> Self::EdgesMut<'_> { - self.edges.values_mut() + iters::EdgesMut::new(self.edges.values_mut()) } type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 92e3c41342bf2..aef27754f827d 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -217,9 +217,9 @@ impl Graph for MultiMapGraph { iters::EdgesRef::new(self.edges.values()) } - type EdgesMut<'e> = slotmap::hop::ValuesMut<'e, EdgeIdx, Edge> where Self: 'e; + type EdgesMut<'e> = iters::EdgesMut<'e, E, slotmap::hop::ValuesMut<'e, EdgeIdx, Edge>> where Self: 'e; fn edges_mut(&mut self) -> Self::EdgesMut<'_> { - self.edges.values_mut() + iters::EdgesMut::new(self.edges.values_mut()) } type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 9db3f44548f76..d314743dd0545 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -208,9 +208,9 @@ impl Graph for SimpleMapGraph iters::EdgesRef::new(self.edges.values()) } - type EdgesMut<'e> = slotmap::hop::ValuesMut<'e, EdgeIdx, Edge> where Self: 'e; + type EdgesMut<'e> = iters::EdgesMut<'e, E, slotmap::hop::ValuesMut<'e, EdgeIdx, Edge>> where Self: 'e; fn edges_mut(&mut self) -> Self::EdgesMut<'_> { - self.edges.values_mut() + iters::EdgesMut::new(self.edges.values_mut()) } type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 32c0ef3c2da30..c769de463cf16 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -13,7 +13,7 @@ pub mod keys; use crate::error::GraphError; use self::{ - edge::{Edge, EdgeMut, EdgeRef}, + edge::{EdgeMut, EdgeRef}, keys::{EdgeIdx, NodeIdx}, }; @@ -39,7 +39,7 @@ pub trait Graph { Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type EdgesMut<'e>: Iterator> + type EdgesMut<'e>: Iterator> where Self: 'e, E: 'e; From 52db276296297f441d9460f2b92e6cc62ee48f79 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 20 Jan 2023 18:21:36 +0100 Subject: [PATCH 135/183] [DIRTY] brokey iter code :c --- crates/bevy_graph/src/iters/edges_by_idx.rs | 2 +- .../bevy_graph/src/iters/edges_by_idx_mut.rs | 37 +++++++++++++++++++ crates/bevy_graph/src/iters/mod.rs | 3 ++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 crates/bevy_graph/src/iters/edges_by_idx_mut.rs diff --git a/crates/bevy_graph/src/iters/edges_by_idx.rs b/crates/bevy_graph/src/iters/edges_by_idx.rs index 037c9248cdae3..14479daf5116c 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::graphs::{edge::EdgeRef, keys::EdgeIdx, Graph}; -/// An iterator which converts `&EdgeIdx` to a `EdgeRef` of the graph +/// An iterator which converts `&EdgeIdx` to a `EdgeRef` of the graph pub struct EdgesByIdx<'g, N, E: 'g, G: Graph, I: Iterator> { graph: &'g G, inner: I, diff --git a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs new file mode 100644 index 0000000000000..2fa93a851efb0 --- /dev/null +++ b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs @@ -0,0 +1,37 @@ +use std::marker::PhantomData; + +use crate::graphs::{edge::EdgeMut, keys::EdgeIdx, Graph}; + +/// An iterator which converts `&mut EdgeIdx` to a `EdgeMut` of the graph +pub struct EdgesByIdxMut<'g, N, E: 'g, G: Graph, I: Iterator> { + graph: &'g G, + inner: I, + phantom: PhantomData<(N, E)>, +} + +impl<'g, N, E: 'g, G: Graph, I: Iterator> + EdgesByIdxMut<'g, N, E, G, I> +{ + /// Creates a new `EdgesByIdxMut` iterator over a graph with the provided `inner` iterator + pub fn new(inner: I, graph: &'g G) -> Self { + Self { + graph, + inner, + phantom: PhantomData, + } + } +} + +impl<'g, N, E: 'g, G: Graph, I: Iterator> Iterator + for EdgesByIdxMut<'g, N, E, G, I> +{ + type Item = EdgeMut<'g, E>; + + fn next(&mut self) -> Option { + if let Some(index) = self.inner.next() { + self.graph.get_edge_mut(*index) + } else { + None + } + } +} diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs index 516c00144682b..280075e6eb6f9 100644 --- a/crates/bevy_graph/src/iters/mod.rs +++ b/crates/bevy_graph/src/iters/mod.rs @@ -1,6 +1,9 @@ mod edges_by_idx; pub use edges_by_idx::*; +mod edges_by_idx_mut; +pub use edges_by_idx_mut::*; + mod edges_ref; pub use edges_ref::*; From f66274bd2b7740d6a45c72f432fd6ffa207a3a6b Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 20 Jan 2023 21:27:59 +0100 Subject: [PATCH 136/183] Add `in_degree` and `out_degree` --- crates/bevy_graph/src/graphs/list/multi.rs | 10 ++++++++++ crates/bevy_graph/src/graphs/list/simple.rs | 10 ++++++++++ crates/bevy_graph/src/graphs/map/multi.rs | 10 ++++++++++ crates/bevy_graph/src/graphs/map/simple.rs | 10 ++++++++++ crates/bevy_graph/src/graphs/mod.rs | 8 +++++++- crates/bevy_graph/src/iters/mod.rs | 5 +++-- 6 files changed, 50 insertions(+), 3 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 79f67f56fb378..355873a8366c6 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -227,4 +227,14 @@ impl Graph for MultiListGraph fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values().flatten(), self) } + + #[inline] + fn in_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].incoming().len() + } + + #[inline] + fn out_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].outgoing().len() + } } diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 40252ec3642b1..1de791f4fae4a 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -226,4 +226,14 @@ impl Graph for SimpleListGraph fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values(), self) } + + #[inline] + fn in_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].incoming().len() + } + + #[inline] + fn out_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].outgoing().len() + } } diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index aef27754f827d..abe7c8194b591 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -231,4 +231,14 @@ impl Graph for MultiMapGraph { fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values().flatten(), self) } + + #[inline] + fn in_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].incoming().len() + } + + #[inline] + fn out_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].outgoing().len() + } } diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index d314743dd0545..7972382bdc95d 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -222,4 +222,14 @@ impl Graph for SimpleMapGraph fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values(), self) } + + #[inline] + fn in_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].incoming().len() + } + + #[inline] + fn out_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].outgoing().len() + } } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index c769de463cf16..bc11344adf135 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -192,9 +192,15 @@ pub trait Graph { /// Returns an iterator over the edge indices coming out of the specified node. fn outgoing_edges_of(&self, index: NodeIdx) -> Self::OutgoingEdgesOf<'_>; + + /// Returns the number of edges going into the specified node. + fn in_degree(&self, index: NodeIdx) -> usize; + + /// Returns the number of edges coming out of the specified node. + fn out_degree(&self, index: NodeIdx) -> usize; } -/// A more precise trait with functions special for a simple graph +/// A more precise trait with functions special for simple graphs pub trait SimpleGraph: Graph { /// Returns an edge between two nodes as `EdgeIdx` fn edge_between(&self, from: NodeIdx, to: NodeIdx) -> Result, GraphError>; diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs index 280075e6eb6f9..4fd5120bb1ae3 100644 --- a/crates/bevy_graph/src/iters/mod.rs +++ b/crates/bevy_graph/src/iters/mod.rs @@ -1,8 +1,9 @@ mod edges_by_idx; pub use edges_by_idx::*; -mod edges_by_idx_mut; -pub use edges_by_idx_mut::*; +// TODO: only include when fixed +//mod edges_by_idx_mut; +//pub use edges_by_idx_mut::*; mod edges_ref; pub use edges_ref::*; From 99dfc53f279169b6357595ce9f7fa7d190053bbd Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 20 Jan 2023 22:17:44 +0100 Subject: [PATCH 137/183] Changes --- crates/bevy_graph/src/graphs/list/multi.rs | 10 ++++ crates/bevy_graph/src/graphs/list/simple.rs | 10 ++++ crates/bevy_graph/src/graphs/map/multi.rs | 10 ++++ crates/bevy_graph/src/graphs/map/simple.rs | 10 ++++ crates/bevy_graph/src/graphs/mod.rs | 54 +++++++++++++++++++++ crates/bevy_graph/src/iters/edges_by_idx.rs | 6 +++ crates/bevy_graph/src/iters/mod.rs | 3 ++ crates/bevy_graph/src/iters/nodes_by_idx.rs | 41 ++++++++++++++++ 8 files changed, 144 insertions(+) create mode 100644 crates/bevy_graph/src/iters/nodes_by_idx.rs diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 355873a8366c6..52664c0440162 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -198,6 +198,11 @@ impl Graph for MultiListGraph todo!() } + type NodeIndices<'n> = slotmap::hop::Keys<'n, NodeIdx, N> where Self: 'n; + fn node_indices(&self) -> Self::NodeIndices<'_> { + self.nodes.keys() + } + type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; fn nodes(&self) -> Self::Nodes<'_> { self.nodes.values() @@ -208,6 +213,11 @@ impl Graph for MultiListGraph self.nodes.values_mut() } + type EdgeIndices<'e> = slotmap::hop::Keys<'e, EdgeIdx, Edge> where Self: 'e; + fn edge_indices(&self) -> Self::EdgeIndices<'_> { + self.edges.keys() + } + type Edges<'e> = iters::EdgesRef<'e, E, slotmap::hop::Values<'e, EdgeIdx, Edge>> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { iters::EdgesRef::new(self.edges.values()) diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 1de791f4fae4a..ffa051b526bf7 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -197,6 +197,11 @@ impl Graph for SimpleListGraph todo!() } + type NodeIndices<'n> = slotmap::hop::Keys<'n, NodeIdx, N> where Self: 'n; + fn node_indices(&self) -> Self::NodeIndices<'_> { + self.nodes.keys() + } + type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; fn nodes(&self) -> Self::Nodes<'_> { self.nodes.values() @@ -207,6 +212,11 @@ impl Graph for SimpleListGraph self.nodes.values_mut() } + type EdgeIndices<'e> = slotmap::hop::Keys<'e, EdgeIdx, Edge> where Self: 'e; + fn edge_indices(&self) -> Self::EdgeIndices<'_> { + self.edges.keys() + } + type Edges<'e> = iters::EdgesRef<'e, E, slotmap::hop::Values<'e, EdgeIdx, Edge>> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { iters::EdgesRef::new(self.edges.values()) diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index abe7c8194b591..39794008d4df3 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -202,6 +202,11 @@ impl Graph for MultiMapGraph { todo!() } + type NodeIndices<'n> = slotmap::hop::Keys<'n, NodeIdx, N> where Self: 'n; + fn node_indices(&self) -> Self::NodeIndices<'_> { + self.nodes.keys() + } + type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; fn nodes(&self) -> Self::Nodes<'_> { self.nodes.values() @@ -212,6 +217,11 @@ impl Graph for MultiMapGraph { self.nodes.values_mut() } + type EdgeIndices<'e> = slotmap::hop::Keys<'e, EdgeIdx, Edge> where Self: 'e; + fn edge_indices(&self) -> Self::EdgeIndices<'_> { + self.edges.keys() + } + type Edges<'e> = iters::EdgesRef<'e, E, slotmap::hop::Values<'e, EdgeIdx, Edge>> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { iters::EdgesRef::new(self.edges.values()) diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 7972382bdc95d..84f52b6e9d9fa 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -193,6 +193,11 @@ impl Graph for SimpleMapGraph todo!() } + type NodeIndices<'n> = slotmap::hop::Keys<'n, NodeIdx, N> where Self: 'n; + fn node_indices(&self) -> Self::NodeIndices<'_> { + self.nodes.keys() + } + type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; fn nodes(&self) -> Self::Nodes<'_> { self.nodes.values() @@ -203,6 +208,11 @@ impl Graph for SimpleMapGraph self.nodes.values_mut() } + type EdgeIndices<'e> = slotmap::hop::Keys<'e, EdgeIdx, Edge> where Self: 'e; + fn edge_indices(&self) -> Self::EdgeIndices<'_> { + self.edges.keys() + } + type Edges<'e> = iters::EdgesRef<'e, E, slotmap::hop::Values<'e, EdgeIdx, Edge>> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { iters::EdgesRef::new(self.edges.values()) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index bc11344adf135..e9f84d2829aea 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -24,6 +24,11 @@ use self::{ /// A trait with all the common functions for a graph pub trait Graph { /// Iterator fix because TAIT not available + type NodeIndices<'n>: Iterator + where + Self: 'n, + E: 'n; + /// Iterator fix because TAIT not available type Nodes<'n>: Iterator where Self: 'n, @@ -34,6 +39,11 @@ pub trait Graph { Self: 'n, N: 'n; /// Iterator fix because TAIT not available + type EdgeIndices<'e>: Iterator + where + Self: 'e, + E: 'e; + /// Iterator fix because TAIT not available type Edges<'e>: Iterator> where Self: 'e, @@ -53,6 +63,30 @@ pub trait Graph { where Self: 'e, E: 'e; + /* + + /// Iterator fix because TAIT not available + type Sources<'n>: Iterator + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available + type SourcesMut<'n>: Iterator + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available + type Sinks<'n>: Iterator + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available + type SinksMut<'n>: Iterator + where + Self: 'n, + N: 'n; + + */ /// Creates a new graph fn new() -> Self @@ -175,12 +209,18 @@ pub trait Graph { /// In multi-graphs, edges that form self-loops add 2 to the degree. fn degree(&self, index: NodeIdx) -> usize; + /// Returns an iterator over all `NodeIdx`s. + fn node_indices(&self) -> Self::NodeIndices<'_>; + /// Returns an iterator over all nodes. fn nodes(&self) -> Self::Nodes<'_>; /// Returns a mutable iterator over all nodes. fn nodes_mut(&mut self) -> Self::NodesMut<'_>; + /// Returns an iterator over all `EdgeIdx`s. + fn edge_indices(&self) -> Self::EdgeIndices<'_>; + /// Returns an iterator over all edges. fn edges(&self) -> Self::Edges<'_>; @@ -198,6 +238,20 @@ pub trait Graph { /// Returns the number of edges coming out of the specified node. fn out_degree(&self, index: NodeIdx) -> usize; + + /* + /// Returns an iterator over all nodes with zero in-degree. + fn sources(&self) -> Self::Sources<'_>; + + /// Returns a mutable iterator over all nodes with zero in-degree. + fn sources_mut(&mut self) -> Self::SourcesMut<'_>; + + /// Returns an iterator over all nodes with zero out-degree. + fn sinks(&self) -> Self::Sinks<'_>; + + /// Returns a mutable iterator over all nodes with zero out-degree. + fn sinks_mut(&mut self) -> Self::SinksMut<'_>; + */ } /// A more precise trait with functions special for simple graphs diff --git a/crates/bevy_graph/src/iters/edges_by_idx.rs b/crates/bevy_graph/src/iters/edges_by_idx.rs index 14479daf5116c..9233258847561 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx.rs @@ -18,6 +18,12 @@ impl<'g, N, E: 'g, G: Graph, I: Iterator> EdgesByIdx<' phantom: PhantomData, } } + + /// Returns the inner iterator which yields `EdgeIdx` + #[inline] + pub fn into_indices_iter(self) -> I { + self.inner + } } impl<'g, N, E: 'g, G: Graph, I: Iterator> Iterator diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs index 4fd5120bb1ae3..47891cb0e6aaf 100644 --- a/crates/bevy_graph/src/iters/mod.rs +++ b/crates/bevy_graph/src/iters/mod.rs @@ -5,6 +5,9 @@ pub use edges_by_idx::*; //mod edges_by_idx_mut; //pub use edges_by_idx_mut::*; +mod nodes_by_idx; +pub use nodes_by_idx::*; + mod edges_ref; pub use edges_ref::*; diff --git a/crates/bevy_graph/src/iters/nodes_by_idx.rs b/crates/bevy_graph/src/iters/nodes_by_idx.rs new file mode 100644 index 0000000000000..f3349eaf8070b --- /dev/null +++ b/crates/bevy_graph/src/iters/nodes_by_idx.rs @@ -0,0 +1,41 @@ +use std::marker::PhantomData; + +use crate::graphs::{keys::NodeIdx, Graph}; + +/// An iterator which converts `NodeIdx` to a `&'g N` of the graph +pub struct NodesByIdx<'g, N: 'g, E, G: Graph, I: Iterator> { + graph: &'g G, + inner: I, + phantom: PhantomData<(N, E)>, +} + +impl<'g, N: 'g, E, G: Graph, I: Iterator> NodesByIdx<'g, N, E, G, I> { + /// Creates a new `NodesByIdx` iterator over a graph with the provided `inner` iterator + pub fn new(inner: I, graph: &'g G) -> Self { + Self { + graph, + inner, + phantom: PhantomData, + } + } + + /// Returns the inner iterator which yields `NodeIdx` + #[inline] + pub fn into_indices_iter(self) -> I { + self.inner + } +} + +impl<'g, N: 'g, E, G: Graph, I: Iterator> Iterator + for NodesByIdx<'g, N, E, G, I> +{ + type Item = &'g N; + + fn next(&mut self) -> Option { + if let Some(index) = self.inner.next() { + self.graph.get_node(index) + } else { + None + } + } +} From ed5e7ceb43af866ca013d84f67d442cd00475b5c Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 21 Jan 2023 13:39:48 +0100 Subject: [PATCH 138/183] Fix `EdgesByIdxMut` --- crates/bevy_graph/src/graphs/list/multi.rs | 21 ++++++++++++ crates/bevy_graph/src/graphs/list/simple.rs | 15 ++++++++ crates/bevy_graph/src/graphs/map/multi.rs | 21 ++++++++++++ crates/bevy_graph/src/graphs/map/simple.rs | 15 ++++++++ crates/bevy_graph/src/graphs/mod.rs | 25 +++++++++++++- .../bevy_graph/src/iters/edges_by_idx_mut.rs | 34 ++++++++++++------- crates/bevy_graph/src/iters/mod.rs | 5 ++- 7 files changed, 119 insertions(+), 17 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 52664c0440162..3b30b30c61145 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -184,6 +184,11 @@ impl Graph for MultiListGraph self.nodes.get_mut(index) } + #[inline] + unsafe fn get_edge_raw(&mut self, index: EdgeIdx) -> Option<&mut Edge> { + self.edges.get_mut(index) + } + #[inline] fn get_edge(&self, index: EdgeIdx) -> Option> { self.edges.get(index).map(|edge| edge.as_ref_edge()) @@ -233,11 +238,27 @@ impl Graph for MultiListGraph iters::EdgesByIdx::new(self.adjacencies[index].incoming().values().flatten(), self) } + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, std::iter::Flatten>>> where Self: 'e; + fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { + iters::EdgesByIdxMut::new( + self.adjacencies[index].incoming().values().flatten(), + &mut self.edges, + ) + } + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values().flatten(), self) } + type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, std::iter::Flatten>>> where Self: 'e; + fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { + iters::EdgesByIdxMut::new( + self.adjacencies[index].outgoing().values().flatten(), + &mut self.edges, + ) + } + #[inline] fn in_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].incoming().len() diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index ffa051b526bf7..b4988f92e4e60 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -183,6 +183,11 @@ impl Graph for SimpleListGraph self.nodes.get_mut(index) } + #[inline] + unsafe fn get_edge_raw(&mut self, index: EdgeIdx) -> Option<&mut Edge> { + self.edges.get_mut(index) + } + #[inline] fn get_edge(&self, index: EdgeIdx) -> Option> { self.edges.get(index).map(|edge| edge.as_ref_edge()) @@ -232,11 +237,21 @@ impl Graph for SimpleListGraph iters::EdgesByIdx::new(self.adjacencies[index].incoming().values(), self) } + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { + iters::EdgesByIdxMut::new(self.adjacencies[index].incoming().values(), &mut self.edges) + } + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values(), self) } + type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { + iters::EdgesByIdxMut::new(self.adjacencies[index].outgoing().values(), &mut self.edges) + } + #[inline] fn in_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].incoming().len() diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 39794008d4df3..7adf79fc5b62f 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -188,6 +188,11 @@ impl Graph for MultiMapGraph { self.nodes.get_mut(index) } + #[inline] + unsafe fn get_edge_raw(&mut self, index: EdgeIdx) -> Option<&mut Edge> { + self.edges.get_mut(index) + } + #[inline] fn get_edge(&self, index: EdgeIdx) -> Option> { self.edges.get(index).map(|edge| edge.as_ref_edge()) @@ -237,11 +242,27 @@ impl Graph for MultiMapGraph { iters::EdgesByIdx::new(self.adjacencies[index].incoming().values().flatten(), self) } + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, std::iter::Flatten>>> where Self: 'e; + fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { + iters::EdgesByIdxMut::new( + self.adjacencies[index].incoming().values().flatten(), + &mut self.edges, + ) + } + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values().flatten(), self) } + type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, std::iter::Flatten>>> where Self: 'e; + fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { + iters::EdgesByIdxMut::new( + self.adjacencies[index].outgoing().values().flatten(), + &mut self.edges, + ) + } + #[inline] fn in_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].incoming().len() diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 84f52b6e9d9fa..cd5cd301d9e07 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -179,6 +179,11 @@ impl Graph for SimpleMapGraph self.nodes.get_mut(index) } + #[inline] + unsafe fn get_edge_raw(&mut self, index: EdgeIdx) -> Option<&mut Edge> { + self.edges.get_mut(index) + } + #[inline] fn get_edge(&self, index: EdgeIdx) -> Option> { self.edges.get(index).map(|edge| edge.as_ref_edge()) @@ -228,11 +233,21 @@ impl Graph for SimpleMapGraph iters::EdgesByIdx::new(self.adjacencies[index].incoming().values(), self) } + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { + iters::EdgesByIdxMut::new(self.adjacencies[index].incoming().values(), &mut self.edges) + } + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values(), self) } + type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { + iters::EdgesByIdxMut::new(self.adjacencies[index].outgoing().values(), &mut self.edges) + } + #[inline] fn in_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].incoming().len() diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index e9f84d2829aea..ca23f338d6b09 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -13,7 +13,7 @@ pub mod keys; use crate::error::GraphError; use self::{ - edge::{EdgeMut, EdgeRef}, + edge::{Edge, EdgeMut, EdgeRef}, keys::{EdgeIdx, NodeIdx}, }; @@ -59,7 +59,17 @@ pub trait Graph { Self: 'e, E: 'e; /// Iterator fix because TAIT not available + type IncomingEdgesOfMut<'e>: Iterator> + where + Self: 'e, + E: 'e; + /// Iterator fix because TAIT not available type OutgoingEdgesOf<'e>: Iterator> + where + Self: 'e, + E: 'e; + /// Iterator fix because TAIT not available + type OutgoingEdgesOfMut<'e>: Iterator> where Self: 'e, E: 'e; @@ -198,6 +208,13 @@ pub trait Graph { /// Returns a mutable reference to the specified node. fn get_node_mut(&mut self, index: NodeIdx) -> Option<&mut N>; + /// Returns a raw edge handle to the specified edge. + /// + /// # Safety + /// + /// This function should only be called when you really know what you are doing. + unsafe fn get_edge_raw(&mut self, index: EdgeIdx) -> Option<&mut Edge>; + /// Returns a reference to the specified edge. fn get_edge(&self, index: EdgeIdx) -> Option>; @@ -230,9 +247,15 @@ pub trait Graph { /// Returns an iterator over the edge indices going into the specified node. fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_>; + /// Returns a mutable iterator over the edges going into the specified node. + fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_>; + /// Returns an iterator over the edge indices coming out of the specified node. fn outgoing_edges_of(&self, index: NodeIdx) -> Self::OutgoingEdgesOf<'_>; + /// Returns a mutable iterator over the edges coming out of the specified node. + fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::OutgoingEdgesOfMut<'_>; + /// Returns the number of edges going into the specified node. fn in_degree(&self, index: NodeIdx) -> usize; diff --git a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs index 2fa93a851efb0..7c5baf3ce0fd9 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs @@ -1,35 +1,43 @@ use std::marker::PhantomData; -use crate::graphs::{edge::EdgeMut, keys::EdgeIdx, Graph}; +use slotmap::HopSlotMap; -/// An iterator which converts `&mut EdgeIdx` to a `EdgeMut` of the graph -pub struct EdgesByIdxMut<'g, N, E: 'g, G: Graph, I: Iterator> { - graph: &'g G, +use crate::graphs::{ + edge::{Edge, EdgeMut}, + keys::EdgeIdx, +}; + +/// An iterator which converts `&EdgeIdx` to a `EdgeMut` of the graph +pub struct EdgesByIdxMut<'g, N, E: 'g, I: Iterator> { + edges: &'g mut HopSlotMap>, inner: I, phantom: PhantomData<(N, E)>, } -impl<'g, N, E: 'g, G: Graph, I: Iterator> - EdgesByIdxMut<'g, N, E, G, I> -{ +impl<'g, N, E: 'g, I: Iterator> EdgesByIdxMut<'g, N, E, I> { /// Creates a new `EdgesByIdxMut` iterator over a graph with the provided `inner` iterator - pub fn new(inner: I, graph: &'g G) -> Self { + pub fn new(inner: I, edges: &'g mut HopSlotMap>) -> Self { Self { - graph, + edges, inner, phantom: PhantomData, } } } -impl<'g, N, E: 'g, G: Graph, I: Iterator> Iterator - for EdgesByIdxMut<'g, N, E, G, I> -{ +impl<'g, N, E: 'g, I: Iterator> Iterator for EdgesByIdxMut<'g, N, E, I> { type Item = EdgeMut<'g, E>; fn next(&mut self) -> Option { if let Some(index) = self.inner.next() { - self.graph.get_edge_mut(*index) + // Unsafe necessary because Rust can't deduce that we won't + // return multiple references to the same value. + unsafe { + self.edges.get_mut(*index).map(|edge| { + let ptr: *mut E = &mut edge.2; + EdgeMut(edge.0, edge.1, &mut *ptr) + }) + } } else { None } diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs index 47891cb0e6aaf..a9141f48085bf 100644 --- a/crates/bevy_graph/src/iters/mod.rs +++ b/crates/bevy_graph/src/iters/mod.rs @@ -1,9 +1,8 @@ mod edges_by_idx; pub use edges_by_idx::*; -// TODO: only include when fixed -//mod edges_by_idx_mut; -//pub use edges_by_idx_mut::*; +mod edges_by_idx_mut; +pub use edges_by_idx_mut::*; mod nodes_by_idx; pub use nodes_by_idx::*; From 1500cc8c023c926539dcc9974256608b8c7f0468 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 21 Jan 2023 13:45:57 +0100 Subject: [PATCH 139/183] Cleanup --- crates/bevy_graph/src/graphs/list/multi.rs | 18 ++++++++---- crates/bevy_graph/src/graphs/list/simple.rs | 12 ++++---- crates/bevy_graph/src/graphs/map/multi.rs | 18 ++++++++---- crates/bevy_graph/src/graphs/map/simple.rs | 12 ++++---- crates/bevy_graph/src/iters/edges_by_idx.rs | 28 ++++++++----------- .../bevy_graph/src/iters/edges_by_idx_mut.rs | 15 +++------- crates/bevy_graph/src/iters/nodes_by_idx.rs | 25 ++++++----------- 7 files changed, 61 insertions(+), 67 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 3b30b30c61145..d488c0b92eb8e 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -233,12 +233,15 @@ impl Graph for MultiListGraph iters::EdgesMut::new(self.edges.values_mut()) } - type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - iters::EdgesByIdx::new(self.adjacencies[index].incoming().values().flatten(), self) + iters::EdgesByIdx::new( + self.adjacencies[index].incoming().values().flatten(), + &self.edges, + ) } - type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, std::iter::Flatten>>> where Self: 'e; + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new( self.adjacencies[index].incoming().values().flatten(), @@ -246,12 +249,15 @@ impl Graph for MultiListGraph ) } - type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values().flatten(), self) + iters::EdgesByIdx::new( + self.adjacencies[index].outgoing().values().flatten(), + &self.edges, + ) } - type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, std::iter::Flatten>>> where Self: 'e; + type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new( self.adjacencies[index].outgoing().values().flatten(), diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index b4988f92e4e60..c44a6dde6a02c 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -232,22 +232,22 @@ impl Graph for SimpleListGraph iters::EdgesMut::new(self.edges.values_mut()) } - type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - iters::EdgesByIdx::new(self.adjacencies[index].incoming().values(), self) + iters::EdgesByIdx::new(self.adjacencies[index].incoming().values(), &self.edges) } - type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new(self.adjacencies[index].incoming().values(), &mut self.edges) } - type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values(), self) + iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values(), &self.edges) } - type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new(self.adjacencies[index].outgoing().values(), &mut self.edges) } diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 7adf79fc5b62f..62aeeb0964a0a 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -237,12 +237,15 @@ impl Graph for MultiMapGraph { iters::EdgesMut::new(self.edges.values_mut()) } - type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - iters::EdgesByIdx::new(self.adjacencies[index].incoming().values().flatten(), self) + iters::EdgesByIdx::new( + self.adjacencies[index].incoming().values().flatten(), + &self.edges, + ) } - type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, std::iter::Flatten>>> where Self: 'e; + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new( self.adjacencies[index].incoming().values().flatten(), @@ -250,12 +253,15 @@ impl Graph for MultiMapGraph { ) } - type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, std::iter::Flatten>>> where Self: 'e; + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values().flatten(), self) + iters::EdgesByIdx::new( + self.adjacencies[index].outgoing().values().flatten(), + &self.edges, + ) } - type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, std::iter::Flatten>>> where Self: 'e; + type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new( self.adjacencies[index].outgoing().values().flatten(), diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index cd5cd301d9e07..c5a5f933ca195 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -228,22 +228,22 @@ impl Graph for SimpleMapGraph iters::EdgesMut::new(self.edges.values_mut()) } - type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - iters::EdgesByIdx::new(self.adjacencies[index].incoming().values(), self) + iters::EdgesByIdx::new(self.adjacencies[index].incoming().values(), &self.edges) } - type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new(self.adjacencies[index].incoming().values(), &mut self.edges) } - type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, N, E, Self, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values(), self) + iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values(), &self.edges) } - type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, N, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new(self.adjacencies[index].outgoing().values(), &mut self.edges) } diff --git a/crates/bevy_graph/src/iters/edges_by_idx.rs b/crates/bevy_graph/src/iters/edges_by_idx.rs index 9233258847561..c3b4e87e7ea29 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx.rs @@ -1,22 +1,20 @@ -use std::marker::PhantomData; +use slotmap::HopSlotMap; -use crate::graphs::{edge::EdgeRef, keys::EdgeIdx, Graph}; +use crate::graphs::{ + edge::{Edge, EdgeRef}, + keys::EdgeIdx, +}; /// An iterator which converts `&EdgeIdx` to a `EdgeRef` of the graph -pub struct EdgesByIdx<'g, N, E: 'g, G: Graph, I: Iterator> { - graph: &'g G, +pub struct EdgesByIdx<'g, E: 'g, I: Iterator> { + edges: &'g HopSlotMap>, inner: I, - phantom: PhantomData<(N, E)>, } -impl<'g, N, E: 'g, G: Graph, I: Iterator> EdgesByIdx<'g, N, E, G, I> { +impl<'g, E: 'g, I: Iterator> EdgesByIdx<'g, E, I> { /// Creates a new `EdgesByIdx` iterator over a graph with the provided `inner` iterator - pub fn new(inner: I, graph: &'g G) -> Self { - Self { - graph, - inner, - phantom: PhantomData, - } + pub fn new(inner: I, edges: &'g HopSlotMap>) -> Self { + Self { edges, inner } } /// Returns the inner iterator which yields `EdgeIdx` @@ -26,14 +24,12 @@ impl<'g, N, E: 'g, G: Graph, I: Iterator> EdgesByIdx<' } } -impl<'g, N, E: 'g, G: Graph, I: Iterator> Iterator - for EdgesByIdx<'g, N, E, G, I> -{ +impl<'g, E: 'g, I: Iterator> Iterator for EdgesByIdx<'g, E, I> { type Item = EdgeRef<'g, E>; fn next(&mut self) -> Option { if let Some(index) = self.inner.next() { - self.graph.get_edge(*index) + self.edges.get(*index).map(|edge| edge.as_ref_edge()) } else { None } diff --git a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs index 7c5baf3ce0fd9..621d58b795b61 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use slotmap::HopSlotMap; use crate::graphs::{ @@ -8,24 +6,19 @@ use crate::graphs::{ }; /// An iterator which converts `&EdgeIdx` to a `EdgeMut` of the graph -pub struct EdgesByIdxMut<'g, N, E: 'g, I: Iterator> { +pub struct EdgesByIdxMut<'g, E: 'g, I: Iterator> { edges: &'g mut HopSlotMap>, inner: I, - phantom: PhantomData<(N, E)>, } -impl<'g, N, E: 'g, I: Iterator> EdgesByIdxMut<'g, N, E, I> { +impl<'g, E: 'g, I: Iterator> EdgesByIdxMut<'g, E, I> { /// Creates a new `EdgesByIdxMut` iterator over a graph with the provided `inner` iterator pub fn new(inner: I, edges: &'g mut HopSlotMap>) -> Self { - Self { - edges, - inner, - phantom: PhantomData, - } + Self { edges, inner } } } -impl<'g, N, E: 'g, I: Iterator> Iterator for EdgesByIdxMut<'g, N, E, I> { +impl<'g, E: 'g, I: Iterator> Iterator for EdgesByIdxMut<'g, E, I> { type Item = EdgeMut<'g, E>; fn next(&mut self) -> Option { diff --git a/crates/bevy_graph/src/iters/nodes_by_idx.rs b/crates/bevy_graph/src/iters/nodes_by_idx.rs index f3349eaf8070b..09eb7bba87cc0 100644 --- a/crates/bevy_graph/src/iters/nodes_by_idx.rs +++ b/crates/bevy_graph/src/iters/nodes_by_idx.rs @@ -1,22 +1,17 @@ -use std::marker::PhantomData; +use slotmap::HopSlotMap; -use crate::graphs::{keys::NodeIdx, Graph}; +use crate::graphs::keys::NodeIdx; /// An iterator which converts `NodeIdx` to a `&'g N` of the graph -pub struct NodesByIdx<'g, N: 'g, E, G: Graph, I: Iterator> { - graph: &'g G, +pub struct NodesByIdx<'g, N: 'g, I: Iterator> { + nodes: &'g HopSlotMap, inner: I, - phantom: PhantomData<(N, E)>, } -impl<'g, N: 'g, E, G: Graph, I: Iterator> NodesByIdx<'g, N, E, G, I> { +impl<'g, N: 'g, I: Iterator> NodesByIdx<'g, N, I> { /// Creates a new `NodesByIdx` iterator over a graph with the provided `inner` iterator - pub fn new(inner: I, graph: &'g G) -> Self { - Self { - graph, - inner, - phantom: PhantomData, - } + pub fn new(inner: I, nodes: &'g HopSlotMap) -> Self { + Self { nodes, inner } } /// Returns the inner iterator which yields `NodeIdx` @@ -26,14 +21,12 @@ impl<'g, N: 'g, E, G: Graph, I: Iterator> NodesByIdx<'g, N } } -impl<'g, N: 'g, E, G: Graph, I: Iterator> Iterator - for NodesByIdx<'g, N, E, G, I> -{ +impl<'g, N: 'g, I: Iterator> Iterator for NodesByIdx<'g, N, I> { type Item = &'g N; fn next(&mut self) -> Option { if let Some(index) = self.inner.next() { - self.graph.get_node(index) + self.nodes.get(index) } else { None } From c7f410b84979c288df0afabff34b945166267d72 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 21 Jan 2023 13:46:43 +0100 Subject: [PATCH 140/183] backticks --- crates/bevy_graph/src/graphs/edge.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs index bb52d6121934f..968e526af609a 100644 --- a/crates/bevy_graph/src/graphs/edge.rs +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -20,7 +20,7 @@ impl Edge { } } -/// An util container which holds Edge data with an immutable reference to the edge value +/// An util container which holds `Edge` data with an immutable reference to the edge value pub struct EdgeRef<'v, E>(pub NodeIdx, pub NodeIdx, pub &'v E); impl<'v, E> Deref for EdgeRef<'v, E> { @@ -31,7 +31,7 @@ impl<'v, E> Deref for EdgeRef<'v, E> { } } -/// An util container which holds Edge data with a mutable reference to the edge value +/// An util container which holds `Edge` data with a mutable reference to the edge value pub struct EdgeMut<'v, E>(pub NodeIdx, pub NodeIdx, pub &'v mut E); impl<'v, E> Deref for EdgeMut<'v, E> { From f3230a39c38628d3905c9ad50e573537f7e8d5b1 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 21 Jan 2023 17:23:24 +0100 Subject: [PATCH 141/183] Add `reverse_edge` --- crates/bevy_graph/src/graphs/list/multi.rs | 30 ++++++++++++++++++++- crates/bevy_graph/src/graphs/list/simple.rs | 14 +++++++++- crates/bevy_graph/src/graphs/map/multi.rs | 30 ++++++++++++++++++++- crates/bevy_graph/src/graphs/map/simple.rs | 14 +++++++++- crates/bevy_graph/src/graphs/mod.rs | 6 +++++ 5 files changed, 90 insertions(+), 4 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index d488c0b92eb8e..d09cc5a794e3f 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -6,7 +6,7 @@ use crate::{ adjacency_storage::AdjacencyStorage, edge::{Edge, EdgeMut, EdgeRef}, keys::{EdgeIdx, NodeIdx}, - Graph, + DirectedGraph, Graph, }, iters, utils::{vecmap::VecMap, vecset::VecSet}, @@ -275,3 +275,31 @@ impl Graph for MultiListGraph self.adjacencies[index].outgoing().len() } } + +impl DirectedGraph for MultiListGraph { + fn reverse_edge(&mut self, index: EdgeIdx) { + if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { + self.adjacencies[*src] + .outgoing_mut() + .get_value_mut(*dst) + .unwrap() + .remove_by_value(&index); + self.adjacencies[*dst] + .incoming_mut() + .get_value_mut(*src) + .unwrap() + .remove_by_value(&index); + std::mem::swap(src, dst); + self.adjacencies[*dst] + .outgoing_mut() + .get_value_mut(*src) + .unwrap() + .push(index); + self.adjacencies[*src] + .incoming_mut() + .get_value_mut(*dst) + .unwrap() + .push(index); + } + } +} diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index c44a6dde6a02c..a28fe30717cee 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -6,7 +6,7 @@ use crate::{ adjacency_storage::AdjacencyStorage, edge::{Edge, EdgeMut, EdgeRef}, keys::{EdgeIdx, NodeIdx}, - Graph, + DirectedGraph, Graph, }, iters, utils::vecmap::VecMap, @@ -262,3 +262,15 @@ impl Graph for SimpleListGraph self.adjacencies[index].outgoing().len() } } + +impl DirectedGraph for SimpleListGraph { + fn reverse_edge(&mut self, index: EdgeIdx) { + if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { + self.adjacencies[*src].outgoing_mut().remove_by_key(*dst); + self.adjacencies[*dst].incoming_mut().remove_by_key(*src); + std::mem::swap(src, dst); + self.adjacencies[*dst].outgoing_mut().push((*src, index)); + self.adjacencies[*src].incoming_mut().push((*dst, index)); + } + } +} diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 62aeeb0964a0a..8ccf4f41eebaf 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -7,7 +7,7 @@ use crate::{ adjacency_storage::AdjacencyStorage, edge::{Edge, EdgeMut, EdgeRef}, keys::{EdgeIdx, NodeIdx}, - Graph, + DirectedGraph, Graph, }, iters, utils::vecset::VecSet, @@ -279,3 +279,31 @@ impl Graph for MultiMapGraph { self.adjacencies[index].outgoing().len() } } + +impl DirectedGraph for MultiMapGraph { + fn reverse_edge(&mut self, index: EdgeIdx) { + if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { + self.adjacencies[*src] + .outgoing_mut() + .get_mut(dst) + .unwrap() + .remove_by_value(&index); + self.adjacencies[*dst] + .incoming_mut() + .get_mut(src) + .unwrap() + .remove_by_value(&index); + std::mem::swap(src, dst); + self.adjacencies[*dst] + .outgoing_mut() + .get_mut(src) + .unwrap() + .push(index); + self.adjacencies[*src] + .incoming_mut() + .get_mut(dst) + .unwrap() + .push(index); + } + } +} diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index c5a5f933ca195..b748843466fc8 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -7,7 +7,7 @@ use crate::{ adjacency_storage::AdjacencyStorage, edge::{Edge, EdgeMut, EdgeRef}, keys::{EdgeIdx, NodeIdx}, - Graph, + DirectedGraph, Graph, }, iters, }; @@ -258,3 +258,15 @@ impl Graph for SimpleMapGraph self.adjacencies[index].outgoing().len() } } + +impl DirectedGraph for SimpleMapGraph { + fn reverse_edge(&mut self, index: EdgeIdx) { + if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { + self.adjacencies[*src].outgoing_mut().remove(dst); + self.adjacencies[*dst].incoming_mut().remove(src); + std::mem::swap(src, dst); + self.adjacencies[*dst].outgoing_mut().insert(*src, index); + self.adjacencies[*src].incoming_mut().insert(*dst, index); + } + } +} diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index ca23f338d6b09..08d16e08d7b30 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -289,3 +289,9 @@ pub trait SimpleGraph: Graph { /// This function should only be called when the nodes and the edge between exists. unsafe fn edge_between_unchecked(&self, from: NodeIdx, to: NodeIdx) -> EdgeIdx; } + +/// A more precise trait with functions special for directed graphs +pub trait DirectedGraph: Graph { + /// Reverse the direction of the specified edge. + fn reverse_edge(&mut self, index: EdgeIdx); +} From 1c6511ec53ea31f0a96f735876cea193c4c601b0 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 21 Jan 2023 17:34:04 +0100 Subject: [PATCH 142/183] Add `reverse` function --- crates/bevy_graph/src/graphs/list/multi.rs | 20 ++++++++++++++++++++ crates/bevy_graph/src/graphs/list/simple.rs | 12 ++++++++++++ crates/bevy_graph/src/graphs/map/multi.rs | 20 ++++++++++++++++++++ crates/bevy_graph/src/graphs/map/simple.rs | 12 ++++++++++++ crates/bevy_graph/src/graphs/mod.rs | 3 +++ 5 files changed, 67 insertions(+) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index d09cc5a794e3f..cb1ece6f14d0f 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -277,6 +277,26 @@ impl Graph for MultiListGraph } impl DirectedGraph for MultiListGraph { + fn reverse(&mut self) { + self.adjacencies + .values_mut() + .for_each(|list| list.for_each_mut(Vec::clear)); + + for (index, Edge(src, dst, _)) in &mut self.edges { + std::mem::swap(src, dst); + self.adjacencies[*dst] + .outgoing_mut() + .get_value_mut(*src) + .unwrap() + .push(index); + self.adjacencies[*src] + .incoming_mut() + .get_value_mut(*dst) + .unwrap() + .push(index); + } + } + fn reverse_edge(&mut self, index: EdgeIdx) { if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { self.adjacencies[*src] diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index a28fe30717cee..54d24c1e37834 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -264,6 +264,18 @@ impl Graph for SimpleListGraph } impl DirectedGraph for SimpleListGraph { + fn reverse(&mut self) { + self.adjacencies + .values_mut() + .for_each(|list| list.for_each_mut(Vec::clear)); + + for (index, Edge(src, dst, _)) in &mut self.edges { + std::mem::swap(src, dst); + self.adjacencies[*dst].outgoing_mut().push((*src, index)); + self.adjacencies[*src].incoming_mut().push((*dst, index)); + } + } + fn reverse_edge(&mut self, index: EdgeIdx) { if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { self.adjacencies[*src].outgoing_mut().remove_by_key(*dst); diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 8ccf4f41eebaf..c48a34d71efb7 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -281,6 +281,26 @@ impl Graph for MultiMapGraph { } impl DirectedGraph for MultiMapGraph { + fn reverse(&mut self) { + self.adjacencies + .values_mut() + .for_each(|map| map.for_each_mut(HashMap::clear)); + + for (index, Edge(src, dst, _)) in &mut self.edges { + std::mem::swap(src, dst); + self.adjacencies[*dst] + .outgoing_mut() + .get_mut(src) + .unwrap() + .push(index); + self.adjacencies[*src] + .incoming_mut() + .get_mut(dst) + .unwrap() + .push(index); + } + } + fn reverse_edge(&mut self, index: EdgeIdx) { if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { self.adjacencies[*src] diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index b748843466fc8..a3d2240d35324 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -260,6 +260,18 @@ impl Graph for SimpleMapGraph } impl DirectedGraph for SimpleMapGraph { + fn reverse(&mut self) { + self.adjacencies + .values_mut() + .for_each(|map| map.for_each_mut(HashMap::clear)); + + for (index, Edge(src, dst, _)) in &mut self.edges { + std::mem::swap(src, dst); + self.adjacencies[*dst].outgoing_mut().insert(*src, index); + self.adjacencies[*src].incoming_mut().insert(*dst, index); + } + } + fn reverse_edge(&mut self, index: EdgeIdx) { if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { self.adjacencies[*src].outgoing_mut().remove(dst); diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 08d16e08d7b30..e41bf5bd27fc7 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -292,6 +292,9 @@ pub trait SimpleGraph: Graph { /// A more precise trait with functions special for directed graphs pub trait DirectedGraph: Graph { + /// Reverse the direction of all edges in the graph. + fn reverse(&mut self); + /// Reverse the direction of the specified edge. fn reverse_edge(&mut self, index: EdgeIdx); } From 7776f943b7ad349f03d59252cde3ba7a3f92e332 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 21 Jan 2023 17:36:12 +0100 Subject: [PATCH 143/183] Fix `with_capacity` adjacencies --- crates/bevy_graph/src/graphs/list/multi.rs | 2 +- crates/bevy_graph/src/graphs/list/simple.rs | 2 +- crates/bevy_graph/src/graphs/map/multi.rs | 2 +- crates/bevy_graph/src/graphs/map/simple.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index cb1ece6f14d0f..b2aa2a47410de 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -35,7 +35,7 @@ impl Graph for MultiListGraph Self { nodes: HopSlotMap::with_capacity_and_key(node_capacity), edges: HopSlotMap::with_capacity_and_key(edge_capacity), - adjacencies: SecondaryMap::new(), + adjacencies: SecondaryMap::with_capacity(node_capacity), } } diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 54d24c1e37834..b433ad36c7442 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -35,7 +35,7 @@ impl Graph for SimpleListGraph Self { nodes: HopSlotMap::with_capacity_and_key(node_capacity), edges: HopSlotMap::with_capacity_and_key(edge_capacity), - adjacencies: SecondaryMap::new(), + adjacencies: SecondaryMap::with_capacity(node_capacity), } } diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index c48a34d71efb7..23cc9c204648d 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -36,7 +36,7 @@ impl Graph for MultiMapGraph { Self { nodes: HopSlotMap::with_capacity_and_key(node_capacity), edges: HopSlotMap::with_capacity_and_key(edge_capacity), - adjacencies: SecondaryMap::new(), + adjacencies: SecondaryMap::with_capacity(node_capacity), } } diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index a3d2240d35324..0cbb723479ae5 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -35,7 +35,7 @@ impl Graph for SimpleMapGraph Self { nodes: HopSlotMap::with_capacity_and_key(node_capacity), edges: HopSlotMap::with_capacity_and_key(edge_capacity), - adjacencies: SecondaryMap::new(), + adjacencies: SecondaryMap::with_capacity(node_capacity), } } From fb4ac2c4595733efac14fc4e72ae8a17669e0e0a Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 21 Jan 2023 18:28:34 +0100 Subject: [PATCH 144/183] [WIP] Source and Sink iters --- crates/bevy_graph/src/graphs/keys.rs | 4 +- crates/bevy_graph/src/graphs/list/multi.rs | 26 +++++++++++- crates/bevy_graph/src/graphs/list/simple.rs | 26 +++++++++++- crates/bevy_graph/src/graphs/map/multi.rs | 26 +++++++++++- crates/bevy_graph/src/graphs/map/simple.rs | 26 +++++++++++- crates/bevy_graph/src/graphs/mod.rs | 6 +-- crates/bevy_graph/src/iters/mod.rs | 9 ++++ .../bevy_graph/src/iters/nodes_by_idx_mut.rs | 41 +++++++++++++++++++ crates/bevy_graph/src/iters/sources.rs | 23 +++++++++++ crates/bevy_graph/src/iters/zip_in_degree.rs | 37 +++++++++++++++++ 10 files changed, 215 insertions(+), 9 deletions(-) create mode 100644 crates/bevy_graph/src/iters/nodes_by_idx_mut.rs create mode 100644 crates/bevy_graph/src/iters/sources.rs create mode 100644 crates/bevy_graph/src/iters/zip_in_degree.rs diff --git a/crates/bevy_graph/src/graphs/keys.rs b/crates/bevy_graph/src/graphs/keys.rs index d769f4e806e68..046a10a24e98b 100644 --- a/crates/bevy_graph/src/graphs/keys.rs +++ b/crates/bevy_graph/src/graphs/keys.rs @@ -1,8 +1,8 @@ use slotmap::new_key_type; new_key_type! { - /// a key that holds an index to a node in a graph + /// A key that holds an index to a node in a graph. pub struct NodeIdx; - /// a key that holds an index to an edge in a graph + /// A key that holds an index to an edge in a graph. pub struct EdgeIdx; } diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index b2aa2a47410de..b615eb72fe09c 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -12,6 +12,8 @@ use crate::{ utils::{vecmap::VecMap, vecset::VecSet}, }; +type MultiListStorage = Vec<(NodeIdx, Vec)>; + /// Implementation of a `MultiGraph` which uses `Vec<(NodeIdx, Vec)>` for adjacencies /// /// `MultiGraph`s can hold multiple edges between two nodes and edges between the same node @@ -19,7 +21,7 @@ use crate::{ pub struct MultiListGraph { nodes: HopSlotMap, edges: HopSlotMap>, - adjacencies: SecondaryMap)>>>, + adjacencies: SecondaryMap>, } impl Graph for MultiListGraph { @@ -274,6 +276,28 @@ impl Graph for MultiListGraph fn out_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].outgoing().len() } + + type Sources<'n> = iters::NodesByIdx<'n, N, iters::Sources>>> where Self: 'n; + fn sources(&self) -> Self::Sources<'_> { + iters::NodesByIdx::new( + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.keys(), + &self.adjacencies, + )), + &self.nodes, + ) + } + + /*type SourcesMut<'n> = iters::NodesByIdxMut<'n, N, iters::Sources>>> where Self: 'n; + fn sources_mut(&mut self) -> Self::SourcesMut<'_> { + iters::NodesByIdxMut::new( + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.keys(), + &self.adjacencies, + )), + &mut self.nodes, + ) + }*/ } impl DirectedGraph for MultiListGraph { diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index b433ad36c7442..284599288c95d 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -12,6 +12,8 @@ use crate::{ utils::vecmap::VecMap, }; +type SimpleListStorage = Vec<(NodeIdx, EdgeIdx)>; + /// Implementation of a `SimpleGraph` which uses `Vec<(NodeIdx, EdgeIdx)>` for adjacencies /// /// `SimpleGraph`s can only hold one edge between two nodes and can't have edges between the same node @@ -19,7 +21,7 @@ use crate::{ pub struct SimpleListGraph { nodes: HopSlotMap, edges: HopSlotMap>, - adjacencies: SecondaryMap>>, + adjacencies: SecondaryMap>, } impl Graph for SimpleListGraph { @@ -261,6 +263,28 @@ impl Graph for SimpleListGraph fn out_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].outgoing().len() } + + type Sources<'n> = iters::NodesByIdx<'n, N, iters::Sources>>> where Self: 'n; + fn sources(&self) -> Self::Sources<'_> { + iters::NodesByIdx::new( + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.keys(), + &self.adjacencies, + )), + &self.nodes, + ) + } + + /*type SourcesMut<'n> = iters::NodesByIdxMut<'n, N, iters::Sources>>> where Self: 'n; + fn sources_mut(&mut self) -> Self::SourcesMut<'_> { + iters::NodesByIdxMut::new( + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.keys(), + &self.adjacencies, + )), + &mut self.nodes, + ) + }*/ } impl DirectedGraph for SimpleListGraph { diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 23cc9c204648d..172ef4b3666f4 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -13,6 +13,8 @@ use crate::{ utils::vecset::VecSet, }; +type MultiMapStorage = HashMap>; + /// Implementation of a `MultiGraph` which uses `HashMap>` for adjacencies /// /// `MultiGraph`s can hold multiple edges between two nodes and edges between the same node @@ -20,7 +22,7 @@ use crate::{ pub struct MultiMapGraph { nodes: HopSlotMap, edges: HopSlotMap>, - adjacencies: SecondaryMap>>>, + adjacencies: SecondaryMap>, } impl Graph for MultiMapGraph { @@ -278,6 +280,28 @@ impl Graph for MultiMapGraph { fn out_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].outgoing().len() } + + type Sources<'n> = iters::NodesByIdx<'n, N, iters::Sources>>> where Self: 'n; + fn sources(&self) -> Self::Sources<'_> { + iters::NodesByIdx::new( + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.keys(), + &self.adjacencies, + )), + &self.nodes, + ) + } + + /*type SourcesMut<'n> = iters::NodesByIdxMut<'n, N, iters::Sources>>> where Self: 'n; + fn sources_mut(&mut self) -> Self::SourcesMut<'_> { + iters::NodesByIdxMut::new( + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.keys(), + &self.adjacencies, + )), + &mut self.nodes, + ) + }*/ } impl DirectedGraph for MultiMapGraph { diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 0cbb723479ae5..f0eb7518cadcd 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -12,6 +12,8 @@ use crate::{ iters, }; +type SimpleMapStorage = HashMap; + /// Implementation of a `SimpleGraph` which uses `HashMap` for adjacencies /// /// `SimpleGraph`s can only hold one edge between two nodes and can't have edges between the same node @@ -19,7 +21,7 @@ use crate::{ pub struct SimpleMapGraph { nodes: HopSlotMap, edges: HopSlotMap>, - adjacencies: SecondaryMap>>, + adjacencies: SecondaryMap>, } impl Graph for SimpleMapGraph { @@ -257,6 +259,28 @@ impl Graph for SimpleMapGraph fn out_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].outgoing().len() } + + type Sources<'n> = iters::NodesByIdx<'n, N, iters::Sources>>> where Self: 'n; + fn sources(&self) -> Self::Sources<'_> { + iters::NodesByIdx::new( + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.keys(), + &self.adjacencies, + )), + &self.nodes, + ) + } + + /*type SourcesMut<'n> = iters::NodesByIdxMut<'n, N, iters::Sources>>> where Self: 'n; + fn sources_mut(&mut self) -> Self::SourcesMut<'_> { + iters::NodesByIdxMut::new( + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.keys(), + &self.adjacencies, + )), + &mut self.nodes, + ) + }*/ } impl DirectedGraph for SimpleMapGraph { diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index e41bf5bd27fc7..07a3de97c82cc 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -73,13 +73,13 @@ pub trait Graph { where Self: 'e, E: 'e; - /* - /// Iterator fix because TAIT not available type Sources<'n>: Iterator where Self: 'n, N: 'n; + + /* /// Iterator fix because TAIT not available type SourcesMut<'n>: Iterator where @@ -262,10 +262,10 @@ pub trait Graph { /// Returns the number of edges coming out of the specified node. fn out_degree(&self, index: NodeIdx) -> usize; - /* /// Returns an iterator over all nodes with zero in-degree. fn sources(&self) -> Self::Sources<'_>; + /* /// Returns a mutable iterator over all nodes with zero in-degree. fn sources_mut(&mut self) -> Self::SourcesMut<'_>; diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs index a9141f48085bf..95289504e701f 100644 --- a/crates/bevy_graph/src/iters/mod.rs +++ b/crates/bevy_graph/src/iters/mod.rs @@ -7,8 +7,17 @@ pub use edges_by_idx_mut::*; mod nodes_by_idx; pub use nodes_by_idx::*; +mod nodes_by_idx_mut; +pub use nodes_by_idx_mut::*; + mod edges_ref; pub use edges_ref::*; mod edges_mut; pub use edges_mut::*; + +mod zip_in_degree; +pub use zip_in_degree::*; + +mod sources; +pub use sources::*; diff --git a/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs b/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs new file mode 100644 index 0000000000000..5d8d370696ca4 --- /dev/null +++ b/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs @@ -0,0 +1,41 @@ +use slotmap::HopSlotMap; + +use crate::graphs::keys::NodeIdx; + +/// An iterator which converts `NodeIdx` to a `&'g mut N` of the graph +pub struct NodesByIdxMut<'g, N: 'g, I: Iterator> { + nodes: &'g mut HopSlotMap, + inner: I, +} + +impl<'g, N: 'g, I: Iterator> NodesByIdxMut<'g, N, I> { + /// Creates a new `NodesByIdxMut` iterator over a graph with the provided `inner` iterator + pub fn new(inner: I, nodes: &'g mut HopSlotMap) -> Self { + Self { nodes, inner } + } + + /// Returns the inner iterator which yields `NodeIdx` + #[inline] + pub fn into_indices_iter(self) -> I { + self.inner + } +} + +impl<'g, N: 'g, I: Iterator> Iterator for NodesByIdxMut<'g, N, I> { + type Item = &'g mut N; + + fn next(&mut self) -> Option { + if let Some(index) = self.inner.next() { + // Unsafe necessary because Rust can't deduce that we won't + // return multiple references to the same value. + unsafe { + self.nodes.get_mut(index).map(|node| { + let ptr: *mut N = &mut *node; + &mut *ptr + }) + } + } else { + None + } + } +} diff --git a/crates/bevy_graph/src/iters/sources.rs b/crates/bevy_graph/src/iters/sources.rs new file mode 100644 index 0000000000000..1a87dc723ed22 --- /dev/null +++ b/crates/bevy_graph/src/iters/sources.rs @@ -0,0 +1,23 @@ +use crate::graphs::keys::NodeIdx; + +/// An iterator which iterates every source `NodeIdx` of a graph +pub struct Sources> { + inner: I, +} + +impl> Sources { + /// An iterator which iterates every sink node of a graph + pub fn new(inner: I) -> Self { + Self { inner } + } +} + +impl> Iterator for Sources { + type Item = NodeIdx; + + fn next(&mut self) -> Option { + self.inner + .find(|(_, in_degree)| *in_degree == 0) + .map(|(index, _)| index) + } +} diff --git a/crates/bevy_graph/src/iters/zip_in_degree.rs b/crates/bevy_graph/src/iters/zip_in_degree.rs new file mode 100644 index 0000000000000..9ba61718d429f --- /dev/null +++ b/crates/bevy_graph/src/iters/zip_in_degree.rs @@ -0,0 +1,37 @@ +use hashbrown::HashMap; +use slotmap::SecondaryMap; + +use crate::graphs::{adjacency_storage::AdjacencyStorage, keys::NodeIdx}; + +/// An iterator which zips the `in_degree` of a `NodeIdx` with it +pub struct ZipInDegree<'g, S, I: Iterator> { + adjacencies: &'g SecondaryMap>, + inner: I, +} + +impl<'g, S, I: Iterator> ZipInDegree<'g, S, I> { + /// Creates a new `ZipInDegree` iterator with the provided `inner` iterator + pub fn new(inner: I, adjacencies: &'g SecondaryMap>) -> Self { + Self { adjacencies, inner } + } +} + +impl<'g, T, I: Iterator> Iterator for ZipInDegree<'g, Vec, I> { + type Item = (NodeIdx, usize); + + fn next(&mut self) -> Option { + self.inner + .next() + .map(|index| (index, self.adjacencies[index].incoming().len())) + } +} + +impl<'g, K, V, I: Iterator> Iterator for ZipInDegree<'g, HashMap, I> { + type Item = (NodeIdx, usize); + + fn next(&mut self) -> Option { + self.inner + .next() + .map(|index| (index, self.adjacencies[index].incoming().len())) + } +} From 96c2aa5a5e7ddb7dee49566dbba25b9c4c0f15ee Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 21 Jan 2023 20:05:08 +0100 Subject: [PATCH 145/183] Rework on `Source` iter --- crates/bevy_graph/src/graphs/list/multi.rs | 13 +++----- crates/bevy_graph/src/graphs/list/simple.rs | 13 +++----- crates/bevy_graph/src/graphs/map/multi.rs | 13 +++----- crates/bevy_graph/src/graphs/map/simple.rs | 13 +++----- crates/bevy_graph/src/iters/sources.rs | 20 +++++++---- crates/bevy_graph/src/iters/sources_mut.rs | 35 ++++++++++++++++++++ crates/bevy_graph/src/iters/zip_in_degree.rs | 28 +++++++++------- 7 files changed, 84 insertions(+), 51 deletions(-) create mode 100644 crates/bevy_graph/src/iters/sources_mut.rs diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index b615eb72fe09c..bdbbc0283b5a1 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -277,15 +277,12 @@ impl Graph for MultiListGraph self.adjacencies[index].outgoing().len() } - type Sources<'n> = iters::NodesByIdx<'n, N, iters::Sources>>> where Self: 'n; + type Sources<'n> = iters::Sources<&'n N, iters::ZipInDegree<'n, MultiListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sources(&self) -> Self::Sources<'_> { - iters::NodesByIdx::new( - iters::Sources::new(iters::ZipInDegree::new( - self.nodes.keys(), - &self.adjacencies, - )), - &self.nodes, - ) + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.iter(), + &self.adjacencies, + )) } /*type SourcesMut<'n> = iters::NodesByIdxMut<'n, N, iters::Sources>>> where Self: 'n; diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 284599288c95d..d486389d2c788 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -264,15 +264,12 @@ impl Graph for SimpleListGraph self.adjacencies[index].outgoing().len() } - type Sources<'n> = iters::NodesByIdx<'n, N, iters::Sources>>> where Self: 'n; + type Sources<'n> = iters::Sources<&'n N, iters::ZipInDegree<'n, SimpleListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sources(&self) -> Self::Sources<'_> { - iters::NodesByIdx::new( - iters::Sources::new(iters::ZipInDegree::new( - self.nodes.keys(), - &self.adjacencies, - )), - &self.nodes, - ) + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.iter(), + &self.adjacencies, + )) } /*type SourcesMut<'n> = iters::NodesByIdxMut<'n, N, iters::Sources>>> where Self: 'n; diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 172ef4b3666f4..faa306c44a758 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -281,15 +281,12 @@ impl Graph for MultiMapGraph { self.adjacencies[index].outgoing().len() } - type Sources<'n> = iters::NodesByIdx<'n, N, iters::Sources>>> where Self: 'n; + type Sources<'n> = iters::Sources<&'n N, iters::ZipInDegree<'n, MultiMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sources(&self) -> Self::Sources<'_> { - iters::NodesByIdx::new( - iters::Sources::new(iters::ZipInDegree::new( - self.nodes.keys(), - &self.adjacencies, - )), - &self.nodes, - ) + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.iter(), + &self.adjacencies, + )) } /*type SourcesMut<'n> = iters::NodesByIdxMut<'n, N, iters::Sources>>> where Self: 'n; diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index f0eb7518cadcd..940ad252a218f 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -260,15 +260,12 @@ impl Graph for SimpleMapGraph self.adjacencies[index].outgoing().len() } - type Sources<'n> = iters::NodesByIdx<'n, N, iters::Sources>>> where Self: 'n; + type Sources<'n> = iters::Sources<&'n N, iters::ZipInDegree<'n, SimpleMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sources(&self) -> Self::Sources<'_> { - iters::NodesByIdx::new( - iters::Sources::new(iters::ZipInDegree::new( - self.nodes.keys(), - &self.adjacencies, - )), - &self.nodes, - ) + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.iter(), + &self.adjacencies, + )) } /*type SourcesMut<'n> = iters::NodesByIdxMut<'n, N, iters::Sources>>> where Self: 'n; diff --git a/crates/bevy_graph/src/iters/sources.rs b/crates/bevy_graph/src/iters/sources.rs index 1a87dc723ed22..f2b7a8de9fb95 100644 --- a/crates/bevy_graph/src/iters/sources.rs +++ b/crates/bevy_graph/src/iters/sources.rs @@ -1,23 +1,29 @@ +use std::marker::PhantomData; + use crate::graphs::keys::NodeIdx; /// An iterator which iterates every source `NodeIdx` of a graph -pub struct Sources> { +pub struct Sources> { inner: I, + phantom: PhantomData, } -impl> Sources { - /// An iterator which iterates every sink node of a graph +impl> Sources { + /// An iterator which iterates every source node of a graph pub fn new(inner: I) -> Self { - Self { inner } + Self { + inner, + phantom: PhantomData, + } } } -impl> Iterator for Sources { - type Item = NodeIdx; +impl> Iterator for Sources { + type Item = N; fn next(&mut self) -> Option { self.inner .find(|(_, in_degree)| *in_degree == 0) - .map(|(index, _)| index) + .map(|((_, node), _)| node) } } diff --git a/crates/bevy_graph/src/iters/sources_mut.rs b/crates/bevy_graph/src/iters/sources_mut.rs new file mode 100644 index 0000000000000..cf898989f09a0 --- /dev/null +++ b/crates/bevy_graph/src/iters/sources_mut.rs @@ -0,0 +1,35 @@ +use std::marker::PhantomData; + +use crate::graphs::{keys::NodeIdx, Graph}; + +/// An iterator which iterates every source node of a graph +pub struct SourcesMut<'g, N: 'g, E, G: Graph, I: Iterator> { + graph: &'g mut G, + inner: I, + phantom: PhantomData<(N, E)>, +} + +impl<'g, N: 'g, E, G: Graph, I: Iterator> + SourcesMut<'g, N, E, G, I> +{ + /// An iterator which iterates every source node of a graph + pub fn new(inner: I, graph: &'g mut G) -> Self { + Self { + inner, + graph, + phantom: PhantomData, + } + } +} + +impl<'g, N: 'g, E, G: Graph, I: Iterator> Iterator + for SourcesMut<'g, N, E, G, I> +{ + type Item = &'g mut N; + + fn next(&mut self) -> Option { + self.inner + .find(|(index, _)| self.graph.in_degree(*index) == 0) + .map(|(_, n)| n) + } +} diff --git a/crates/bevy_graph/src/iters/zip_in_degree.rs b/crates/bevy_graph/src/iters/zip_in_degree.rs index 9ba61718d429f..9ff544c17ac26 100644 --- a/crates/bevy_graph/src/iters/zip_in_degree.rs +++ b/crates/bevy_graph/src/iters/zip_in_degree.rs @@ -4,34 +4,38 @@ use slotmap::SecondaryMap; use crate::graphs::{adjacency_storage::AdjacencyStorage, keys::NodeIdx}; /// An iterator which zips the `in_degree` of a `NodeIdx` with it -pub struct ZipInDegree<'g, S, I: Iterator> { +pub struct ZipInDegree<'g, S, N, I: Iterator> { adjacencies: &'g SecondaryMap>, inner: I, } -impl<'g, S, I: Iterator> ZipInDegree<'g, S, I> { +impl<'g, S, N, I: Iterator> ZipInDegree<'g, S, N, I> { /// Creates a new `ZipInDegree` iterator with the provided `inner` iterator pub fn new(inner: I, adjacencies: &'g SecondaryMap>) -> Self { Self { adjacencies, inner } } } -impl<'g, T, I: Iterator> Iterator for ZipInDegree<'g, Vec, I> { - type Item = (NodeIdx, usize); +impl<'g, T, N, I: Iterator> Iterator for ZipInDegree<'g, Vec, N, I> { + type Item = ((NodeIdx, N), usize); fn next(&mut self) -> Option { - self.inner - .next() - .map(|index| (index, self.adjacencies[index].incoming().len())) + self.inner.next().map(|(index, node)| { + let in_degree = self.adjacencies[index].incoming().len(); + ((index, node), in_degree) + }) } } -impl<'g, K, V, I: Iterator> Iterator for ZipInDegree<'g, HashMap, I> { - type Item = (NodeIdx, usize); +impl<'g, K, V, N, I: Iterator> Iterator + for ZipInDegree<'g, HashMap, N, I> +{ + type Item = ((NodeIdx, N), usize); fn next(&mut self) -> Option { - self.inner - .next() - .map(|index| (index, self.adjacencies[index].incoming().len())) + self.inner.next().map(|(index, node)| { + let in_degree = self.adjacencies[index].incoming().len(); + ((index, node), in_degree) + }) } } From dbb082d51e8de9cc43c6a4de6cc2c768cfdefc80 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 21 Jan 2023 20:07:07 +0100 Subject: [PATCH 146/183] Finally `SourcesMut` --- crates/bevy_graph/src/graphs/list/multi.rs | 15 ++++----- crates/bevy_graph/src/graphs/list/simple.rs | 15 ++++----- crates/bevy_graph/src/graphs/map/multi.rs | 15 ++++----- crates/bevy_graph/src/graphs/map/simple.rs | 15 ++++----- crates/bevy_graph/src/graphs/mod.rs | 6 ++-- crates/bevy_graph/src/iters/sources_mut.rs | 35 --------------------- 6 files changed, 27 insertions(+), 74 deletions(-) delete mode 100644 crates/bevy_graph/src/iters/sources_mut.rs diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index bdbbc0283b5a1..71dfdd7cba353 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -285,16 +285,13 @@ impl Graph for MultiListGraph )) } - /*type SourcesMut<'n> = iters::NodesByIdxMut<'n, N, iters::Sources>>> where Self: 'n; + type SourcesMut<'n> = iters::Sources<&'n mut N, iters::ZipInDegree<'n, MultiListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sources_mut(&mut self) -> Self::SourcesMut<'_> { - iters::NodesByIdxMut::new( - iters::Sources::new(iters::ZipInDegree::new( - self.nodes.keys(), - &self.adjacencies, - )), - &mut self.nodes, - ) - }*/ + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.iter_mut(), + &self.adjacencies, + )) + } } impl DirectedGraph for MultiListGraph { diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index d486389d2c788..ae24559379634 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -272,16 +272,13 @@ impl Graph for SimpleListGraph )) } - /*type SourcesMut<'n> = iters::NodesByIdxMut<'n, N, iters::Sources>>> where Self: 'n; + type SourcesMut<'n> = iters::Sources<&'n mut N, iters::ZipInDegree<'n, SimpleListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sources_mut(&mut self) -> Self::SourcesMut<'_> { - iters::NodesByIdxMut::new( - iters::Sources::new(iters::ZipInDegree::new( - self.nodes.keys(), - &self.adjacencies, - )), - &mut self.nodes, - ) - }*/ + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.iter_mut(), + &self.adjacencies, + )) + } } impl DirectedGraph for SimpleListGraph { diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index faa306c44a758..90048dadfcae0 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -289,16 +289,13 @@ impl Graph for MultiMapGraph { )) } - /*type SourcesMut<'n> = iters::NodesByIdxMut<'n, N, iters::Sources>>> where Self: 'n; + type SourcesMut<'n> = iters::Sources<&'n mut N, iters::ZipInDegree<'n, MultiMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sources_mut(&mut self) -> Self::SourcesMut<'_> { - iters::NodesByIdxMut::new( - iters::Sources::new(iters::ZipInDegree::new( - self.nodes.keys(), - &self.adjacencies, - )), - &mut self.nodes, - ) - }*/ + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.iter_mut(), + &self.adjacencies, + )) + } } impl DirectedGraph for MultiMapGraph { diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 940ad252a218f..9c7a66d3c22bb 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -268,16 +268,13 @@ impl Graph for SimpleMapGraph )) } - /*type SourcesMut<'n> = iters::NodesByIdxMut<'n, N, iters::Sources>>> where Self: 'n; + type SourcesMut<'n> = iters::Sources<&'n mut N, iters::ZipInDegree<'n, SimpleMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sources_mut(&mut self) -> Self::SourcesMut<'_> { - iters::NodesByIdxMut::new( - iters::Sources::new(iters::ZipInDegree::new( - self.nodes.keys(), - &self.adjacencies, - )), - &mut self.nodes, - ) - }*/ + iters::Sources::new(iters::ZipInDegree::new( + self.nodes.iter_mut(), + &self.adjacencies, + )) + } } impl DirectedGraph for SimpleMapGraph { diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 07a3de97c82cc..aef12b2fb6aa0 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -78,13 +78,13 @@ pub trait Graph { where Self: 'n, N: 'n; - - /* /// Iterator fix because TAIT not available type SourcesMut<'n>: Iterator where Self: 'n, N: 'n; + + /* /// Iterator fix because TAIT not available type Sinks<'n>: Iterator where @@ -265,10 +265,10 @@ pub trait Graph { /// Returns an iterator over all nodes with zero in-degree. fn sources(&self) -> Self::Sources<'_>; - /* /// Returns a mutable iterator over all nodes with zero in-degree. fn sources_mut(&mut self) -> Self::SourcesMut<'_>; + /* /// Returns an iterator over all nodes with zero out-degree. fn sinks(&self) -> Self::Sinks<'_>; diff --git a/crates/bevy_graph/src/iters/sources_mut.rs b/crates/bevy_graph/src/iters/sources_mut.rs deleted file mode 100644 index cf898989f09a0..0000000000000 --- a/crates/bevy_graph/src/iters/sources_mut.rs +++ /dev/null @@ -1,35 +0,0 @@ -use std::marker::PhantomData; - -use crate::graphs::{keys::NodeIdx, Graph}; - -/// An iterator which iterates every source node of a graph -pub struct SourcesMut<'g, N: 'g, E, G: Graph, I: Iterator> { - graph: &'g mut G, - inner: I, - phantom: PhantomData<(N, E)>, -} - -impl<'g, N: 'g, E, G: Graph, I: Iterator> - SourcesMut<'g, N, E, G, I> -{ - /// An iterator which iterates every source node of a graph - pub fn new(inner: I, graph: &'g mut G) -> Self { - Self { - inner, - graph, - phantom: PhantomData, - } - } -} - -impl<'g, N: 'g, E, G: Graph, I: Iterator> Iterator - for SourcesMut<'g, N, E, G, I> -{ - type Item = &'g mut N; - - fn next(&mut self) -> Option { - self.inner - .find(|(index, _)| self.graph.in_degree(*index) == 0) - .map(|(_, n)| n) - } -} From 069f6b361863be54294618c2a7a429f7d11b38f7 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 21 Jan 2023 20:13:58 +0100 Subject: [PATCH 147/183] =?UTF-8?q?Add=20`Sinks`=20=F0=9F=98=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/bevy_graph/src/graphs/list/multi.rs | 24 +++++++++-- crates/bevy_graph/src/graphs/list/simple.rs | 24 +++++++++-- crates/bevy_graph/src/graphs/map/multi.rs | 24 +++++++++-- crates/bevy_graph/src/graphs/map/simple.rs | 24 +++++++++-- crates/bevy_graph/src/graphs/mod.rs | 6 --- crates/bevy_graph/src/iters/mod.rs | 7 +++- .../iters/{sources.rs => sources_sinks.rs} | 12 +++--- crates/bevy_graph/src/iters/zip_out_degree.rs | 41 +++++++++++++++++++ 8 files changed, 132 insertions(+), 30 deletions(-) rename crates/bevy_graph/src/iters/{sources.rs => sources_sinks.rs} (54%) create mode 100644 crates/bevy_graph/src/iters/zip_out_degree.rs diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 71dfdd7cba353..7bc7703bf5c91 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -277,17 +277,33 @@ impl Graph for MultiListGraph self.adjacencies[index].outgoing().len() } - type Sources<'n> = iters::Sources<&'n N, iters::ZipInDegree<'n, MultiListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + type Sources<'n> = iters::SourcesSinks<&'n N, iters::ZipInDegree<'n, MultiListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sources(&self) -> Self::Sources<'_> { - iters::Sources::new(iters::ZipInDegree::new( + iters::SourcesSinks::new(iters::ZipInDegree::new( self.nodes.iter(), &self.adjacencies, )) } - type SourcesMut<'n> = iters::Sources<&'n mut N, iters::ZipInDegree<'n, MultiListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + type SourcesMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipInDegree<'n, MultiListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sources_mut(&mut self) -> Self::SourcesMut<'_> { - iters::Sources::new(iters::ZipInDegree::new( + iters::SourcesSinks::new(iters::ZipInDegree::new( + self.nodes.iter_mut(), + &self.adjacencies, + )) + } + + type Sinks<'n> = iters::SourcesSinks<&'n N, iters::ZipOutDegree<'n, MultiListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + fn sinks(&self) -> Self::Sinks<'_> { + iters::SourcesSinks::new(iters::ZipOutDegree::new( + self.nodes.iter(), + &self.adjacencies, + )) + } + + type SinksMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipOutDegree<'n, MultiListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + fn sinks_mut(&mut self) -> Self::SinksMut<'_> { + iters::SourcesSinks::new(iters::ZipOutDegree::new( self.nodes.iter_mut(), &self.adjacencies, )) diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index ae24559379634..8928bef000721 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -264,17 +264,33 @@ impl Graph for SimpleListGraph self.adjacencies[index].outgoing().len() } - type Sources<'n> = iters::Sources<&'n N, iters::ZipInDegree<'n, SimpleListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + type Sources<'n> = iters::SourcesSinks<&'n N, iters::ZipInDegree<'n, SimpleListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sources(&self) -> Self::Sources<'_> { - iters::Sources::new(iters::ZipInDegree::new( + iters::SourcesSinks::new(iters::ZipInDegree::new( self.nodes.iter(), &self.adjacencies, )) } - type SourcesMut<'n> = iters::Sources<&'n mut N, iters::ZipInDegree<'n, SimpleListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + type SourcesMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipInDegree<'n, SimpleListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sources_mut(&mut self) -> Self::SourcesMut<'_> { - iters::Sources::new(iters::ZipInDegree::new( + iters::SourcesSinks::new(iters::ZipInDegree::new( + self.nodes.iter_mut(), + &self.adjacencies, + )) + } + + type Sinks<'n> = iters::SourcesSinks<&'n N, iters::ZipOutDegree<'n, SimpleListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + fn sinks(&self) -> Self::Sinks<'_> { + iters::SourcesSinks::new(iters::ZipOutDegree::new( + self.nodes.iter(), + &self.adjacencies, + )) + } + + type SinksMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipOutDegree<'n, SimpleListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + fn sinks_mut(&mut self) -> Self::SinksMut<'_> { + iters::SourcesSinks::new(iters::ZipOutDegree::new( self.nodes.iter_mut(), &self.adjacencies, )) diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 90048dadfcae0..141476a62fe1e 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -281,17 +281,33 @@ impl Graph for MultiMapGraph { self.adjacencies[index].outgoing().len() } - type Sources<'n> = iters::Sources<&'n N, iters::ZipInDegree<'n, MultiMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + type Sources<'n> = iters::SourcesSinks<&'n N, iters::ZipInDegree<'n, MultiMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sources(&self) -> Self::Sources<'_> { - iters::Sources::new(iters::ZipInDegree::new( + iters::SourcesSinks::new(iters::ZipInDegree::new( self.nodes.iter(), &self.adjacencies, )) } - type SourcesMut<'n> = iters::Sources<&'n mut N, iters::ZipInDegree<'n, MultiMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + type SourcesMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipInDegree<'n, MultiMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sources_mut(&mut self) -> Self::SourcesMut<'_> { - iters::Sources::new(iters::ZipInDegree::new( + iters::SourcesSinks::new(iters::ZipInDegree::new( + self.nodes.iter_mut(), + &self.adjacencies, + )) + } + + type Sinks<'n> = iters::SourcesSinks<&'n N, iters::ZipOutDegree<'n, MultiMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + fn sinks(&self) -> Self::Sinks<'_> { + iters::SourcesSinks::new(iters::ZipOutDegree::new( + self.nodes.iter(), + &self.adjacencies, + )) + } + + type SinksMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipOutDegree<'n, MultiMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + fn sinks_mut(&mut self) -> Self::SinksMut<'_> { + iters::SourcesSinks::new(iters::ZipOutDegree::new( self.nodes.iter_mut(), &self.adjacencies, )) diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 9c7a66d3c22bb..45fd2490d3eb8 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -260,17 +260,33 @@ impl Graph for SimpleMapGraph self.adjacencies[index].outgoing().len() } - type Sources<'n> = iters::Sources<&'n N, iters::ZipInDegree<'n, SimpleMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + type Sources<'n> = iters::SourcesSinks<&'n N, iters::ZipInDegree<'n, SimpleMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sources(&self) -> Self::Sources<'_> { - iters::Sources::new(iters::ZipInDegree::new( + iters::SourcesSinks::new(iters::ZipInDegree::new( self.nodes.iter(), &self.adjacencies, )) } - type SourcesMut<'n> = iters::Sources<&'n mut N, iters::ZipInDegree<'n, SimpleMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + type SourcesMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipInDegree<'n, SimpleMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sources_mut(&mut self) -> Self::SourcesMut<'_> { - iters::Sources::new(iters::ZipInDegree::new( + iters::SourcesSinks::new(iters::ZipInDegree::new( + self.nodes.iter_mut(), + &self.adjacencies, + )) + } + + type Sinks<'n> = iters::SourcesSinks<&'n N, iters::ZipOutDegree<'n, SimpleMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + fn sinks(&self) -> Self::Sinks<'_> { + iters::SourcesSinks::new(iters::ZipOutDegree::new( + self.nodes.iter(), + &self.adjacencies, + )) + } + + type SinksMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipOutDegree<'n, SimpleMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + fn sinks_mut(&mut self) -> Self::SinksMut<'_> { + iters::SourcesSinks::new(iters::ZipOutDegree::new( self.nodes.iter_mut(), &self.adjacencies, )) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index aef12b2fb6aa0..3a627d49fde13 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -83,8 +83,6 @@ pub trait Graph { where Self: 'n, N: 'n; - - /* /// Iterator fix because TAIT not available type Sinks<'n>: Iterator where @@ -96,8 +94,6 @@ pub trait Graph { Self: 'n, N: 'n; - */ - /// Creates a new graph fn new() -> Self where @@ -268,13 +264,11 @@ pub trait Graph { /// Returns a mutable iterator over all nodes with zero in-degree. fn sources_mut(&mut self) -> Self::SourcesMut<'_>; - /* /// Returns an iterator over all nodes with zero out-degree. fn sinks(&self) -> Self::Sinks<'_>; /// Returns a mutable iterator over all nodes with zero out-degree. fn sinks_mut(&mut self) -> Self::SinksMut<'_>; - */ } /// A more precise trait with functions special for simple graphs diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs index 95289504e701f..0334131dc53eb 100644 --- a/crates/bevy_graph/src/iters/mod.rs +++ b/crates/bevy_graph/src/iters/mod.rs @@ -19,5 +19,8 @@ pub use edges_mut::*; mod zip_in_degree; pub use zip_in_degree::*; -mod sources; -pub use sources::*; +mod zip_out_degree; +pub use zip_out_degree::*; + +mod sources_sinks; +pub use sources_sinks::*; diff --git a/crates/bevy_graph/src/iters/sources.rs b/crates/bevy_graph/src/iters/sources_sinks.rs similarity index 54% rename from crates/bevy_graph/src/iters/sources.rs rename to crates/bevy_graph/src/iters/sources_sinks.rs index f2b7a8de9fb95..abf80b0b660b2 100644 --- a/crates/bevy_graph/src/iters/sources.rs +++ b/crates/bevy_graph/src/iters/sources_sinks.rs @@ -2,14 +2,14 @@ use std::marker::PhantomData; use crate::graphs::keys::NodeIdx; -/// An iterator which iterates every source `NodeIdx` of a graph -pub struct Sources> { +/// An iterator which iterates every source / sink node of a graph +pub struct SourcesSinks> { inner: I, phantom: PhantomData, } -impl> Sources { - /// An iterator which iterates every source node of a graph +impl> SourcesSinks { + /// An iterator which iterates every source / sink node of a graph pub fn new(inner: I) -> Self { Self { inner, @@ -18,12 +18,12 @@ impl> Sources { } } -impl> Iterator for Sources { +impl> Iterator for SourcesSinks { type Item = N; fn next(&mut self) -> Option { self.inner - .find(|(_, in_degree)| *in_degree == 0) + .find(|(_, in_out_degree)| *in_out_degree == 0) .map(|((_, node), _)| node) } } diff --git a/crates/bevy_graph/src/iters/zip_out_degree.rs b/crates/bevy_graph/src/iters/zip_out_degree.rs new file mode 100644 index 0000000000000..6f64d7d91f5d6 --- /dev/null +++ b/crates/bevy_graph/src/iters/zip_out_degree.rs @@ -0,0 +1,41 @@ +use hashbrown::HashMap; +use slotmap::SecondaryMap; + +use crate::graphs::{adjacency_storage::AdjacencyStorage, keys::NodeIdx}; + +/// An iterator which zips the `out_degree` of a `NodeIdx` with it +pub struct ZipOutDegree<'g, S, N, I: Iterator> { + adjacencies: &'g SecondaryMap>, + inner: I, +} + +impl<'g, S, N, I: Iterator> ZipOutDegree<'g, S, N, I> { + /// Creates a new `ZipOutDegree` iterator with the provided `inner` iterator + pub fn new(inner: I, adjacencies: &'g SecondaryMap>) -> Self { + Self { adjacencies, inner } + } +} + +impl<'g, T, N, I: Iterator> Iterator for ZipOutDegree<'g, Vec, N, I> { + type Item = ((NodeIdx, N), usize); + + fn next(&mut self) -> Option { + self.inner.next().map(|(index, node)| { + let in_degree = self.adjacencies[index].outgoing().len(); + ((index, node), in_degree) + }) + } +} + +impl<'g, K, V, N, I: Iterator> Iterator + for ZipOutDegree<'g, HashMap, N, I> +{ + type Item = ((NodeIdx, N), usize); + + fn next(&mut self) -> Option { + self.inner.next().map(|(index, node)| { + let in_degree = self.adjacencies[index].outgoing().len(); + ((index, node), in_degree) + }) + } +} From 507d99161d508d476ae1dd846ef913a6c7e8fcac Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 22 Jan 2023 13:31:47 +0100 Subject: [PATCH 148/183] Add `in_neighbors(_mut)` and `out_neighbors(_mut)` --- crates/bevy_graph/src/graphs/list/multi.rs | 35 +++++++++++++--- crates/bevy_graph/src/graphs/list/simple.rs | 35 +++++++++++++--- crates/bevy_graph/src/graphs/map/multi.rs | 35 +++++++++++++--- crates/bevy_graph/src/graphs/map/simple.rs | 35 +++++++++++++--- crates/bevy_graph/src/graphs/mod.rs | 40 +++++++++++++++++-- crates/bevy_graph/src/iters/nodes_by_idx.rs | 10 ++--- .../bevy_graph/src/iters/nodes_by_idx_mut.rs | 10 ++--- crates/bevy_graph/src/utils/vecmap.rs | 20 ++++++++++ 8 files changed, 182 insertions(+), 38 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 7bc7703bf5c91..5d480c05fb292 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -235,6 +235,16 @@ impl Graph for MultiListGraph iters::EdgesMut::new(self.edges.values_mut()) } + #[inline] + fn in_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].incoming().len() + } + + #[inline] + fn out_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].outgoing().len() + } + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new( @@ -267,14 +277,27 @@ impl Graph for MultiListGraph ) } - #[inline] - fn in_degree(&self, index: NodeIdx) -> usize { - self.adjacencies[index].incoming().len() + type InNeighbors<'n> = iters::NodesByIdx<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, Vec>> where Self: 'n; + fn in_neighbors(&self, index: NodeIdx) -> Self::InNeighbors<'_> { + iters::NodesByIdx::new(self.adjacencies[index].incoming().keys(), &self.nodes) } - #[inline] - fn out_degree(&self, index: NodeIdx) -> usize { - self.adjacencies[index].outgoing().len() + type InNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, Vec>> where Self: 'n; + fn in_neighbors_mut(&mut self, index: NodeIdx) -> Self::InNeighborsMut<'_> { + iters::NodesByIdxMut::new(self.adjacencies[index].incoming().keys(), &mut self.nodes) + } + + type OutNeighbors<'n> = iters::NodesByIdx<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, Vec>> where Self: 'n; + fn out_neighbors(&self, index: NodeIdx) -> Self::OutNeighbors<'_> { + iters::NodesByIdx::new(self.adjacencies[index].outgoing().keys(), &self.nodes) + } + + type OutNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, Vec>> where Self: 'n; + fn out_neighbors_mut(&mut self, index: NodeIdx) -> Self::OutNeighborsMut<'_> { + iters::NodesByIdxMut::new( + self.adjacencies[index].outgoing_mut().keys(), + &mut self.nodes, + ) } type Sources<'n> = iters::SourcesSinks<&'n N, iters::ZipInDegree<'n, MultiListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 8928bef000721..0ad4a5c78e5ee 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -234,6 +234,16 @@ impl Graph for SimpleListGraph iters::EdgesMut::new(self.edges.values_mut()) } + #[inline] + fn in_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].incoming().len() + } + + #[inline] + fn out_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].outgoing().len() + } + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].incoming().values(), &self.edges) @@ -254,14 +264,27 @@ impl Graph for SimpleListGraph iters::EdgesByIdxMut::new(self.adjacencies[index].outgoing().values(), &mut self.edges) } - #[inline] - fn in_degree(&self, index: NodeIdx) -> usize { - self.adjacencies[index].incoming().len() + type InNeighbors<'n> = iters::NodesByIdx<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + fn in_neighbors(&self, index: NodeIdx) -> Self::InNeighbors<'_> { + iters::NodesByIdx::new(self.adjacencies[index].incoming().keys(), &self.nodes) } - #[inline] - fn out_degree(&self, index: NodeIdx) -> usize { - self.adjacencies[index].outgoing().len() + type InNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + fn in_neighbors_mut(&mut self, index: NodeIdx) -> Self::InNeighborsMut<'_> { + iters::NodesByIdxMut::new(self.adjacencies[index].incoming().keys(), &mut self.nodes) + } + + type OutNeighbors<'n> = iters::NodesByIdx<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + fn out_neighbors(&self, index: NodeIdx) -> Self::OutNeighbors<'_> { + iters::NodesByIdx::new(self.adjacencies[index].outgoing().keys(), &self.nodes) + } + + type OutNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + fn out_neighbors_mut(&mut self, index: NodeIdx) -> Self::OutNeighborsMut<'_> { + iters::NodesByIdxMut::new( + self.adjacencies[index].outgoing_mut().keys(), + &mut self.nodes, + ) } type Sources<'n> = iters::SourcesSinks<&'n N, iters::ZipInDegree<'n, SimpleListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 141476a62fe1e..9136e5b48a3f6 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -247,6 +247,16 @@ impl Graph for MultiMapGraph { ) } + #[inline] + fn in_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].incoming().len() + } + + #[inline] + fn out_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].outgoing().len() + } + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new( @@ -271,14 +281,27 @@ impl Graph for MultiMapGraph { ) } - #[inline] - fn in_degree(&self, index: NodeIdx) -> usize { - self.adjacencies[index].incoming().len() + type InNeighbors<'n> = iters::NodesByIdx<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, Vec>> where Self: 'n; + fn in_neighbors(&self, index: NodeIdx) -> Self::InNeighbors<'_> { + iters::NodesByIdx::new(self.adjacencies[index].incoming().keys(), &self.nodes) } - #[inline] - fn out_degree(&self, index: NodeIdx) -> usize { - self.adjacencies[index].outgoing().len() + type InNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, Vec>> where Self: 'n; + fn in_neighbors_mut(&mut self, index: NodeIdx) -> Self::InNeighborsMut<'_> { + iters::NodesByIdxMut::new(self.adjacencies[index].incoming().keys(), &mut self.nodes) + } + + type OutNeighbors<'n> = iters::NodesByIdx<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, Vec>> where Self: 'n; + fn out_neighbors(&self, index: NodeIdx) -> Self::OutNeighbors<'_> { + iters::NodesByIdx::new(self.adjacencies[index].outgoing().keys(), &self.nodes) + } + + type OutNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, Vec>> where Self: 'n; + fn out_neighbors_mut(&mut self, index: NodeIdx) -> Self::OutNeighborsMut<'_> { + iters::NodesByIdxMut::new( + self.adjacencies[index].outgoing_mut().keys(), + &mut self.nodes, + ) } type Sources<'n> = iters::SourcesSinks<&'n N, iters::ZipInDegree<'n, MultiMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 45fd2490d3eb8..856faeb69e846 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -230,6 +230,16 @@ impl Graph for SimpleMapGraph iters::EdgesMut::new(self.edges.values_mut()) } + #[inline] + fn in_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].incoming().len() + } + + #[inline] + fn out_degree(&self, index: NodeIdx) -> usize { + self.adjacencies[index].outgoing().len() + } + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].incoming().values(), &self.edges) @@ -250,14 +260,27 @@ impl Graph for SimpleMapGraph iters::EdgesByIdxMut::new(self.adjacencies[index].outgoing().values(), &mut self.edges) } - #[inline] - fn in_degree(&self, index: NodeIdx) -> usize { - self.adjacencies[index].incoming().len() + type InNeighbors<'n> = iters::NodesByIdx<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + fn in_neighbors(&self, index: NodeIdx) -> Self::InNeighbors<'_> { + iters::NodesByIdx::new(self.adjacencies[index].incoming().keys(), &self.nodes) } - #[inline] - fn out_degree(&self, index: NodeIdx) -> usize { - self.adjacencies[index].outgoing().len() + type InNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + fn in_neighbors_mut(&mut self, index: NodeIdx) -> Self::InNeighborsMut<'_> { + iters::NodesByIdxMut::new(self.adjacencies[index].incoming().keys(), &mut self.nodes) + } + + type OutNeighbors<'n> = iters::NodesByIdx<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + fn out_neighbors(&self, index: NodeIdx) -> Self::OutNeighbors<'_> { + iters::NodesByIdx::new(self.adjacencies[index].outgoing().keys(), &self.nodes) + } + + type OutNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + fn out_neighbors_mut(&mut self, index: NodeIdx) -> Self::OutNeighborsMut<'_> { + iters::NodesByIdxMut::new( + self.adjacencies[index].outgoing_mut().keys(), + &mut self.nodes, + ) } type Sources<'n> = iters::SourcesSinks<&'n N, iters::ZipInDegree<'n, SimpleMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 3a627d49fde13..c1a89d18252ca 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -74,6 +74,26 @@ pub trait Graph { Self: 'e, E: 'e; /// Iterator fix because TAIT not available + type InNeighbors<'n>: Iterator + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available + type InNeighborsMut<'n>: Iterator + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available + type OutNeighbors<'n>: Iterator + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available + type OutNeighborsMut<'n>: Iterator + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available type Sources<'n>: Iterator where Self: 'n, @@ -240,6 +260,12 @@ pub trait Graph { /// Returns a mutable iterator over all edges. fn edges_mut(&mut self) -> Self::EdgesMut<'_>; + /// Returns the number of edges going into the specified node. + fn in_degree(&self, index: NodeIdx) -> usize; + + /// Returns the number of edges coming out of the specified node. + fn out_degree(&self, index: NodeIdx) -> usize; + /// Returns an iterator over the edge indices going into the specified node. fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_>; @@ -252,11 +278,17 @@ pub trait Graph { /// Returns a mutable iterator over the edges coming out of the specified node. fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::OutgoingEdgesOfMut<'_>; - /// Returns the number of edges going into the specified node. - fn in_degree(&self, index: NodeIdx) -> usize; + /// Returns an iterator over the the specified node's direct predecessors. + fn in_neighbors(&self, index: NodeIdx) -> Self::InNeighbors<'_>; - /// Returns the number of edges coming out of the specified node. - fn out_degree(&self, index: NodeIdx) -> usize; + /// Returns a mutable iterator over the the specified node's direct predecessors. + fn in_neighbors_mut(&mut self, index: NodeIdx) -> Self::InNeighborsMut<'_>; + + /// Returns an iterator over the the specified node's direct successors. + fn out_neighbors(&self, index: NodeIdx) -> Self::OutNeighbors<'_>; + + /// Returns a mutable iterator over the the specified node's direct successors. + fn out_neighbors_mut(&mut self, index: NodeIdx) -> Self::OutNeighborsMut<'_>; /// Returns an iterator over all nodes with zero in-degree. fn sources(&self) -> Self::Sources<'_>; diff --git a/crates/bevy_graph/src/iters/nodes_by_idx.rs b/crates/bevy_graph/src/iters/nodes_by_idx.rs index 09eb7bba87cc0..894f9d25f3ccc 100644 --- a/crates/bevy_graph/src/iters/nodes_by_idx.rs +++ b/crates/bevy_graph/src/iters/nodes_by_idx.rs @@ -2,13 +2,13 @@ use slotmap::HopSlotMap; use crate::graphs::keys::NodeIdx; -/// An iterator which converts `NodeIdx` to a `&'g N` of the graph -pub struct NodesByIdx<'g, N: 'g, I: Iterator> { +/// An iterator which converts `&NodeIdx` to a `&'g N` of the graph +pub struct NodesByIdx<'g, N: 'g, I: Iterator> { nodes: &'g HopSlotMap, inner: I, } -impl<'g, N: 'g, I: Iterator> NodesByIdx<'g, N, I> { +impl<'g, N: 'g, I: Iterator> NodesByIdx<'g, N, I> { /// Creates a new `NodesByIdx` iterator over a graph with the provided `inner` iterator pub fn new(inner: I, nodes: &'g HopSlotMap) -> Self { Self { nodes, inner } @@ -21,12 +21,12 @@ impl<'g, N: 'g, I: Iterator> NodesByIdx<'g, N, I> { } } -impl<'g, N: 'g, I: Iterator> Iterator for NodesByIdx<'g, N, I> { +impl<'g, N: 'g, I: Iterator> Iterator for NodesByIdx<'g, N, I> { type Item = &'g N; fn next(&mut self) -> Option { if let Some(index) = self.inner.next() { - self.nodes.get(index) + self.nodes.get(*index) } else { None } diff --git a/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs b/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs index 5d8d370696ca4..98a132234764b 100644 --- a/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs +++ b/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs @@ -2,13 +2,13 @@ use slotmap::HopSlotMap; use crate::graphs::keys::NodeIdx; -/// An iterator which converts `NodeIdx` to a `&'g mut N` of the graph -pub struct NodesByIdxMut<'g, N: 'g, I: Iterator> { +/// An iterator which converts `&NodeIdx` to a `&'g mut N` of the graph +pub struct NodesByIdxMut<'g, N: 'g, I: Iterator> { nodes: &'g mut HopSlotMap, inner: I, } -impl<'g, N: 'g, I: Iterator> NodesByIdxMut<'g, N, I> { +impl<'g, N: 'g, I: Iterator> NodesByIdxMut<'g, N, I> { /// Creates a new `NodesByIdxMut` iterator over a graph with the provided `inner` iterator pub fn new(inner: I, nodes: &'g mut HopSlotMap) -> Self { Self { nodes, inner } @@ -21,7 +21,7 @@ impl<'g, N: 'g, I: Iterator> NodesByIdxMut<'g, N, I> { } } -impl<'g, N: 'g, I: Iterator> Iterator for NodesByIdxMut<'g, N, I> { +impl<'g, N: 'g, I: Iterator> Iterator for NodesByIdxMut<'g, N, I> { type Item = &'g mut N; fn next(&mut self) -> Option { @@ -29,7 +29,7 @@ impl<'g, N: 'g, I: Iterator> Iterator for NodesByIdxMut<'g, N, I // Unsafe necessary because Rust can't deduce that we won't // return multiple references to the same value. unsafe { - self.nodes.get_mut(index).map(|node| { + self.nodes.get_mut(*index).map(|node| { let ptr: *mut N = &mut *node; &mut *ptr }) diff --git a/crates/bevy_graph/src/utils/vecmap.rs b/crates/bevy_graph/src/utils/vecmap.rs index 7cfddeceed7c1..b2bd526361f3d 100644 --- a/crates/bevy_graph/src/utils/vecmap.rs +++ b/crates/bevy_graph/src/utils/vecmap.rs @@ -39,6 +39,9 @@ pub trait VecMap { /// Removes the entry by the key fn remove_by_key(&mut self, key: K) -> Option; + /// Returns an iterator over the keys + fn keys(&self) -> Keys; + /// Returns an iterator over the values fn values(&self) -> Values; } @@ -94,11 +97,28 @@ impl VecMap for Vec<(K, V)> { self.index_by_key(&key).map(|index| self.remove(index).1) } + fn keys(&self) -> Keys { + Keys { inner: self.iter() } + } + fn values(&self) -> Values { Values { inner: self.iter() } } } +/// Iterator over all keys in a `VecMap` +pub struct Keys<'s, K: PartialEq, V> { + inner: slice::Iter<'s, (K, V)>, +} + +impl<'s, K: PartialEq, V> Iterator for Keys<'s, K, V> { + type Item = &'s K; + + fn next(&mut self) -> Option { + self.inner.next().map(|l| &l.0) + } +} + /// Iterator over all values in a `VecMap` pub struct Values<'s, K: PartialEq, V> { inner: slice::Iter<'s, (K, V)>, From 5947d27086b802c2fcc3e6995b63c62a03f64ae1 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 22 Jan 2023 15:04:51 +0100 Subject: [PATCH 149/183] implement `degree` for directed graphs --- crates/bevy_graph/src/graphs/list/multi.rs | 8 ++++++-- crates/bevy_graph/src/graphs/list/simple.rs | 8 ++++++-- crates/bevy_graph/src/graphs/map/multi.rs | 8 ++++++-- crates/bevy_graph/src/graphs/map/simple.rs | 8 ++++++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 5d480c05fb292..e311cce914e14 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -201,8 +201,12 @@ impl Graph for MultiListGraph self.edges.get_mut(index).map(|edge| edge.as_mut_edge()) } - fn degree(&self, _index: NodeIdx) -> usize { - todo!() + fn degree(&self, index: NodeIdx) -> usize { + if DIRECTED { + self.in_degree(index) + self.out_degree(index) + } else { + todo!() + } } type NodeIndices<'n> = slotmap::hop::Keys<'n, NodeIdx, N> where Self: 'n; diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 0ad4a5c78e5ee..85a28ea2d42a5 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -200,8 +200,12 @@ impl Graph for SimpleListGraph self.edges.get_mut(index).map(|edge| edge.as_mut_edge()) } - fn degree(&self, _index: NodeIdx) -> usize { - todo!() + fn degree(&self, index: NodeIdx) -> usize { + if DIRECTED { + self.in_degree(index) + self.out_degree(index) + } else { + todo!() + } } type NodeIndices<'n> = slotmap::hop::Keys<'n, NodeIdx, N> where Self: 'n; diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 9136e5b48a3f6..8e527e2da39a2 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -205,8 +205,12 @@ impl Graph for MultiMapGraph { self.edges.get_mut(index).map(|edge| edge.as_mut_edge()) } - fn degree(&self, _index: NodeIdx) -> usize { - todo!() + fn degree(&self, index: NodeIdx) -> usize { + if DIRECTED { + self.in_degree(index) + self.out_degree(index) + } else { + todo!() + } } type NodeIndices<'n> = slotmap::hop::Keys<'n, NodeIdx, N> where Self: 'n; diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 856faeb69e846..dc564ca6d3eb8 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -196,8 +196,12 @@ impl Graph for SimpleMapGraph self.edges.get_mut(index).map(|edge| edge.as_mut_edge()) } - fn degree(&self, _index: NodeIdx) -> usize { - todo!() + fn degree(&self, index: NodeIdx) -> usize { + if DIRECTED { + self.in_degree(index) + self.out_degree(index) + } else { + todo!() + } } type NodeIndices<'n> = slotmap::hop::Keys<'n, NodeIdx, N> where Self: 'n; From 3c3a37dfa31b661d380b8b01530020a7fd9dc808 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 22 Jan 2023 15:15:24 +0100 Subject: [PATCH 150/183] Store `EdgeIdx` in `Edge` --- crates/bevy_graph/src/algos/bfs.rs | 4 ++-- crates/bevy_graph/src/algos/dfs.rs | 4 ++-- crates/bevy_graph/src/graphs/edge.rs | 12 ++++++------ crates/bevy_graph/src/graphs/list/multi.rs | 10 ++++++---- crates/bevy_graph/src/graphs/list/simple.rs | 10 ++++++---- crates/bevy_graph/src/graphs/map/multi.rs | 10 ++++++---- crates/bevy_graph/src/graphs/map/simple.rs | 10 ++++++---- crates/bevy_graph/src/iters/edges_by_idx_mut.rs | 2 +- 8 files changed, 35 insertions(+), 27 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 3632dd0acd04a..f1eb1546c0ff5 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -39,7 +39,7 @@ impl BreadthFirstSearch { /// Gets an immutable reference to the value of the next node from the algorithm pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { if let Some(node) = self.queue.pop_front() { - for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { + for EdgeRef(_, dst, _, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.queue.push_back(dst); @@ -54,7 +54,7 @@ impl BreadthFirstSearch { /// Gets a mutable reference to the value of the next node from the algorithm. pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.queue.pop_front() { - for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { + for EdgeRef(_, dst, _, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.queue.push_back(dst); diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index bfb2b8eb5146d..1d3083ecd0e0d 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -36,7 +36,7 @@ impl DepthFirstSearch { /// Gets a reference to the value of the next node from the algorithm. pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { if let Some(node) = self.stack.pop() { - for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { + for EdgeRef(_, dst, _, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.stack.push(dst); @@ -51,7 +51,7 @@ impl DepthFirstSearch { /// Gets a mutable reference to the value of the next node from the algorithm. pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.stack.pop() { - for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { + for EdgeRef(_, dst, _, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.stack.push(dst); diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs index 968e526af609a..16bd1fba0b14d 100644 --- a/crates/bevy_graph/src/graphs/edge.rs +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -1,27 +1,27 @@ use std::ops::{Deref, DerefMut}; -use super::keys::NodeIdx; +use super::keys::{EdgeIdx, NodeIdx}; /// An edge between nodes that store data of type `E`. #[derive(Clone)] -pub struct Edge(pub NodeIdx, pub NodeIdx, pub E); +pub struct Edge(pub NodeIdx, pub NodeIdx, pub E, pub EdgeIdx); impl Edge { /// Returns a [`EdgeRef`] of this edge #[inline] pub const fn as_ref_edge(&self) -> EdgeRef { - EdgeRef(self.0, self.1, &self.2) + EdgeRef(self.0, self.1, &self.2, self.3) } /// Returns a [`EdgeMut`] of this edge #[inline] pub fn as_mut_edge(&mut self) -> EdgeMut { - EdgeMut(self.0, self.1, &mut self.2) + EdgeMut(self.0, self.1, &mut self.2, self.3) } } /// An util container which holds `Edge` data with an immutable reference to the edge value -pub struct EdgeRef<'v, E>(pub NodeIdx, pub NodeIdx, pub &'v E); +pub struct EdgeRef<'v, E>(pub NodeIdx, pub NodeIdx, pub &'v E, pub EdgeIdx); impl<'v, E> Deref for EdgeRef<'v, E> { type Target = E; @@ -32,7 +32,7 @@ impl<'v, E> Deref for EdgeRef<'v, E> { } /// An util container which holds `Edge` data with a mutable reference to the edge value -pub struct EdgeMut<'v, E>(pub NodeIdx, pub NodeIdx, pub &'v mut E); +pub struct EdgeMut<'v, E>(pub NodeIdx, pub NodeIdx, pub &'v mut E, pub EdgeIdx); impl<'v, E> Deref for EdgeMut<'v, E> { type Target = E; diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index e311cce914e14..fb81770f0d168 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -108,7 +108,9 @@ impl Graph for MultiListGraph Err(GraphError::NodeNotFound(dst)) } else { unsafe { - let idx = self.edges.insert(Edge(src, dst, value)); + let idx = self + .edges + .insert_with_key(|index| Edge(src, dst, value, index)); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() @@ -142,7 +144,7 @@ impl Graph for MultiListGraph } fn remove_edge(&mut self, index: EdgeIdx) -> Option { - if let Some(Edge(src, dst, value)) = self.edges.remove(index) { + if let Some(Edge(src, dst, value, _)) = self.edges.remove(index) { unsafe { self.adjacencies .get_unchecked_mut(src) @@ -343,7 +345,7 @@ impl DirectedGraph for MultiListGraph { .values_mut() .for_each(|list| list.for_each_mut(Vec::clear)); - for (index, Edge(src, dst, _)) in &mut self.edges { + for (index, Edge(src, dst, _, _)) in &mut self.edges { std::mem::swap(src, dst); self.adjacencies[*dst] .outgoing_mut() @@ -359,7 +361,7 @@ impl DirectedGraph for MultiListGraph { } fn reverse_edge(&mut self, index: EdgeIdx) { - if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { + if let Some(Edge(src, dst, _, _)) = self.edges.get_mut(index) { self.adjacencies[*src] .outgoing_mut() .get_value_mut(*dst) diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 85a28ea2d42a5..36132e339b9d0 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -113,7 +113,9 @@ impl Graph for SimpleListGraph Err(GraphError::Loop) } else { unsafe { - let idx = self.edges.insert(Edge(src, dst, value)); + let idx = self + .edges + .insert_with_key(|index| Edge(src, dst, value, index)); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() @@ -145,7 +147,7 @@ impl Graph for SimpleListGraph } fn remove_edge(&mut self, index: EdgeIdx) -> Option { - if let Some(Edge(src, dst, value)) = self.edges.remove(index) { + if let Some(Edge(src, dst, value, _)) = self.edges.remove(index) { unsafe { self.adjacencies .get_unchecked_mut(src) @@ -330,7 +332,7 @@ impl DirectedGraph for SimpleListGraph { .values_mut() .for_each(|list| list.for_each_mut(Vec::clear)); - for (index, Edge(src, dst, _)) in &mut self.edges { + for (index, Edge(src, dst, _, _)) in &mut self.edges { std::mem::swap(src, dst); self.adjacencies[*dst].outgoing_mut().push((*src, index)); self.adjacencies[*src].incoming_mut().push((*dst, index)); @@ -338,7 +340,7 @@ impl DirectedGraph for SimpleListGraph { } fn reverse_edge(&mut self, index: EdgeIdx) { - if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { + if let Some(Edge(src, dst, _, _)) = self.edges.get_mut(index) { self.adjacencies[*src].outgoing_mut().remove_by_key(*dst); self.adjacencies[*dst].incoming_mut().remove_by_key(*src); std::mem::swap(src, dst); diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 8e527e2da39a2..f88feccdd62d3 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -110,7 +110,9 @@ impl Graph for MultiMapGraph { Err(GraphError::NodeNotFound(dst)) } else { unsafe { - let idx = self.edges.insert(Edge(src, dst, value)); + let idx = self + .edges + .insert_with_key(|index| Edge(src, dst, value, index)); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() @@ -146,7 +148,7 @@ impl Graph for MultiMapGraph { } fn remove_edge(&mut self, index: EdgeIdx) -> Option { - if let Some(Edge(src, dst, value)) = self.edges.remove(index) { + if let Some(Edge(src, dst, value, _)) = self.edges.remove(index) { unsafe { self.adjacencies .get_unchecked_mut(src) @@ -347,7 +349,7 @@ impl DirectedGraph for MultiMapGraph { .values_mut() .for_each(|map| map.for_each_mut(HashMap::clear)); - for (index, Edge(src, dst, _)) in &mut self.edges { + for (index, Edge(src, dst, _, _)) in &mut self.edges { std::mem::swap(src, dst); self.adjacencies[*dst] .outgoing_mut() @@ -363,7 +365,7 @@ impl DirectedGraph for MultiMapGraph { } fn reverse_edge(&mut self, index: EdgeIdx) { - if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { + if let Some(Edge(src, dst, _, _)) = self.edges.get_mut(index) { self.adjacencies[*src] .outgoing_mut() .get_mut(dst) diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index dc564ca6d3eb8..b11f7554b6b70 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -113,7 +113,9 @@ impl Graph for SimpleMapGraph Err(GraphError::Loop) } else { unsafe { - let idx = self.edges.insert(Edge(src, dst, value)); + let idx = self + .edges + .insert_with_key(|index| Edge(src, dst, value, index)); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() @@ -141,7 +143,7 @@ impl Graph for SimpleMapGraph } fn remove_edge(&mut self, index: EdgeIdx) -> Option { - if let Some(Edge(src, dst, value)) = self.edges.remove(index) { + if let Some(Edge(src, dst, value, _)) = self.edges.remove(index) { unsafe { self.adjacencies .get_unchecked_mut(src) @@ -326,7 +328,7 @@ impl DirectedGraph for SimpleMapGraph { .values_mut() .for_each(|map| map.for_each_mut(HashMap::clear)); - for (index, Edge(src, dst, _)) in &mut self.edges { + for (index, Edge(src, dst, _, _)) in &mut self.edges { std::mem::swap(src, dst); self.adjacencies[*dst].outgoing_mut().insert(*src, index); self.adjacencies[*src].incoming_mut().insert(*dst, index); @@ -334,7 +336,7 @@ impl DirectedGraph for SimpleMapGraph { } fn reverse_edge(&mut self, index: EdgeIdx) { - if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { + if let Some(Edge(src, dst, _, _)) = self.edges.get_mut(index) { self.adjacencies[*src].outgoing_mut().remove(dst); self.adjacencies[*dst].incoming_mut().remove(src); std::mem::swap(src, dst); diff --git a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs index 621d58b795b61..0a7a557a58cea 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs @@ -28,7 +28,7 @@ impl<'g, E: 'g, I: Iterator> Iterator for EdgesByIdxMut<'g, unsafe { self.edges.get_mut(*index).map(|edge| { let ptr: *mut E = &mut edge.2; - EdgeMut(edge.0, edge.1, &mut *ptr) + EdgeMut(edge.0, edge.1, &mut *ptr, edge.3) }) } } else { From 1192e3db075fa70cf0ff82ab0fa8743f6b91b07b Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 22 Jan 2023 15:23:33 +0100 Subject: [PATCH 151/183] Add umimplemented `edges_of` --- crates/bevy_graph/src/graphs/list/multi.rs | 10 ++++++++++ crates/bevy_graph/src/graphs/list/simple.rs | 10 ++++++++++ crates/bevy_graph/src/graphs/map/multi.rs | 10 ++++++++++ crates/bevy_graph/src/graphs/map/simple.rs | 10 ++++++++++ crates/bevy_graph/src/graphs/mod.rs | 16 ++++++++++++++++ 5 files changed, 56 insertions(+) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index fb81770f0d168..8b356c3f62b26 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -241,6 +241,16 @@ impl Graph for MultiListGraph iters::EdgesMut::new(self.edges.values_mut()) } + type EdgesOf<'e> = std::iter::Empty> where Self: 'e; + fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { + todo!() + } + + type EdgesOfMut<'e> = std::iter::Empty> where Self: 'e; + fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { + todo!() + } + #[inline] fn in_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].incoming().len() diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 36132e339b9d0..ac17a3a540518 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -240,6 +240,16 @@ impl Graph for SimpleListGraph iters::EdgesMut::new(self.edges.values_mut()) } + type EdgesOf<'e> = std::iter::Empty> where Self: 'e; + fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { + todo!() + } + + type EdgesOfMut<'e> = std::iter::Empty> where Self: 'e; + fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { + todo!() + } + #[inline] fn in_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].incoming().len() diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index f88feccdd62d3..d8955f5eff294 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -245,6 +245,16 @@ impl Graph for MultiMapGraph { iters::EdgesMut::new(self.edges.values_mut()) } + type EdgesOf<'e> = std::iter::Empty> where Self: 'e; + fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { + todo!() + } + + type EdgesOfMut<'e> = std::iter::Empty> where Self: 'e; + fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { + todo!() + } + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new( diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index b11f7554b6b70..380ac711e95d7 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -236,6 +236,16 @@ impl Graph for SimpleMapGraph iters::EdgesMut::new(self.edges.values_mut()) } + type EdgesOf<'e> = std::iter::Empty> where Self: 'e; + fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { + todo!() + } + + type EdgesOfMut<'e> = std::iter::Empty> where Self: 'e; + fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { + todo!() + } + #[inline] fn in_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].incoming().len() diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index c1a89d18252ca..e866d3cf0be4c 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -54,6 +54,16 @@ pub trait Graph { Self: 'e, E: 'e; /// Iterator fix because TAIT not available + type EdgesOf<'e>: Iterator> + where + Self: 'e, + E: 'e; + /// Iterator fix because TAIT not available + type EdgesOfMut<'e>: Iterator> + where + Self: 'e, + E: 'e; + /// Iterator fix because TAIT not available type IncomingEdgesOf<'e>: Iterator> where Self: 'e, @@ -260,6 +270,12 @@ pub trait Graph { /// Returns a mutable iterator over all edges. fn edges_mut(&mut self) -> Self::EdgesMut<'_>; + /// Returns an iterator over the edges of the specified node. + fn edges_of(&self, index: NodeIdx) -> Self::EdgesOf<'_>; + + /// Returns a mutable iterator over the edges of the specified node. + fn edges_of_mut(&mut self, index: NodeIdx) -> Self::EdgesOfMut<'_>; + /// Returns the number of edges going into the specified node. fn in_degree(&self, index: NodeIdx) -> usize; From 38424ac3bc37b741b36504d8f2f389e6ad4dd390 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 22 Jan 2023 15:40:04 +0100 Subject: [PATCH 152/183] implement `remove_node` --- crates/bevy_graph/src/graphs/list/multi.rs | 32 +++++++++++++++++++-- crates/bevy_graph/src/graphs/list/simple.rs | 28 ++++++++++++++++-- crates/bevy_graph/src/graphs/map/multi.rs | 32 +++++++++++++++++++-- crates/bevy_graph/src/graphs/map/simple.rs | 28 ++++++++++++++++-- 4 files changed, 112 insertions(+), 8 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 8b356c3f62b26..3cf51fca2d732 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -139,8 +139,36 @@ impl Graph for MultiListGraph .contains_key(dst) } - fn remove_node(&mut self, _index: NodeIdx) -> Option { - todo!() + fn remove_node(&mut self, index: NodeIdx) -> Option { + if self.has_node(index) { + let edges_to_remove = self + .edges_of(index) + .map(|edge| edge.3) + .collect::>(); + for edge_idx in edges_to_remove { + unsafe { + let Edge(src, dst, _, _) = self.edges.remove(edge_idx).unwrap_unchecked(); + self.adjacencies + .get_unchecked_mut(src) + .outgoing_mut() + .get_value_mut(dst) + .unwrap() + .remove_by_value(&edge_idx); + self.adjacencies + .get_unchecked_mut(dst) + .incoming_mut() + .get_value_mut(src) + .unwrap() + .remove_by_value(&edge_idx); + } + } + unsafe { + self.adjacencies.remove(index).unwrap_unchecked(); + } + self.nodes.remove(index) + } else { + None + } } fn remove_edge(&mut self, index: EdgeIdx) -> Option { diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index ac17a3a540518..72dc7c8da9585 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -142,8 +142,32 @@ impl Graph for SimpleListGraph .contains_key(dst) } - fn remove_node(&mut self, _index: NodeIdx) -> Option { - todo!() + fn remove_node(&mut self, index: NodeIdx) -> Option { + if self.has_node(index) { + let edges_to_remove = self + .edges_of(index) + .map(|edge| edge.3) + .collect::>(); + for edge_idx in edges_to_remove { + unsafe { + let Edge(src, dst, _, _) = self.edges.remove(edge_idx).unwrap_unchecked(); + self.adjacencies + .get_unchecked_mut(src) + .outgoing_mut() + .remove_by_key(dst); + self.adjacencies + .get_unchecked_mut(dst) + .incoming_mut() + .remove_by_key(src); + } + } + unsafe { + self.adjacencies.remove(index).unwrap_unchecked(); + } + self.nodes.remove(index) + } else { + None + } } fn remove_edge(&mut self, index: EdgeIdx) -> Option { diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index d8955f5eff294..d71486a0379b7 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -143,8 +143,36 @@ impl Graph for MultiMapGraph { .contains_key(&dst) } - fn remove_node(&mut self, _index: NodeIdx) -> Option { - todo!() + fn remove_node(&mut self, index: NodeIdx) -> Option { + if self.has_node(index) { + let edges_to_remove = self + .edges_of(index) + .map(|edge| edge.3) + .collect::>(); + for edge_idx in edges_to_remove { + unsafe { + let Edge(src, dst, _, _) = self.edges.remove(edge_idx).unwrap_unchecked(); + self.adjacencies + .get_unchecked_mut(src) + .outgoing_mut() + .get_mut(&dst) + .unwrap() + .remove_by_value(&edge_idx); + self.adjacencies + .get_unchecked_mut(dst) + .incoming_mut() + .get_mut(&src) + .unwrap() + .remove_by_value(&edge_idx); + } + } + unsafe { + self.adjacencies.remove(index).unwrap_unchecked(); + } + self.nodes.remove(index) + } else { + None + } } fn remove_edge(&mut self, index: EdgeIdx) -> Option { diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 380ac711e95d7..811d412011de5 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -138,8 +138,32 @@ impl Graph for SimpleMapGraph self.adjacencies[src].outgoing().contains_key(&dst) } - fn remove_node(&mut self, _index: NodeIdx) -> Option { - todo!() + fn remove_node(&mut self, index: NodeIdx) -> Option { + if self.has_node(index) { + let edges_to_remove = self + .edges_of(index) + .map(|edge| edge.3) + .collect::>(); + for edge_idx in edges_to_remove { + unsafe { + let Edge(src, dst, _, _) = self.edges.remove(edge_idx).unwrap_unchecked(); + self.adjacencies + .get_unchecked_mut(src) + .outgoing_mut() + .remove(&dst); + self.adjacencies + .get_unchecked_mut(dst) + .incoming_mut() + .remove(&src); + } + } + unsafe { + self.adjacencies.remove(index).unwrap_unchecked(); + } + self.nodes.remove(index) + } else { + None + } } fn remove_edge(&mut self, index: EdgeIdx) -> Option { From caed68e1bc0be59d71a28eee12d24e3d6ed738e2 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 22 Jan 2023 20:10:50 +0100 Subject: [PATCH 153/183] Revert saving `EdgeIdx` in `Edge` --- crates/bevy_graph/src/graphs/edge.rs | 12 +++++------ crates/bevy_graph/src/graphs/list/multi.rs | 21 +++++++++---------- crates/bevy_graph/src/graphs/list/simple.rs | 21 +++++++++---------- crates/bevy_graph/src/graphs/map/multi.rs | 21 +++++++++---------- crates/bevy_graph/src/graphs/map/simple.rs | 20 +++++++++--------- crates/bevy_graph/src/iters/edges_by_idx.rs | 16 +++++++++----- .../bevy_graph/src/iters/edges_by_idx_mut.rs | 20 ++++++++++++++---- crates/bevy_graph/src/iters/edges_mut.rs | 14 ++++++++++++- crates/bevy_graph/src/iters/edges_ref.rs | 14 ++++++++++++- crates/bevy_graph/src/iters/nodes_by_idx.rs | 9 +++++--- .../bevy_graph/src/iters/nodes_by_idx_mut.rs | 9 +++++--- crates/bevy_graph/src/iters/sources_sinks.rs | 21 +++++++++++++------ crates/bevy_graph/src/utils/mod.rs | 2 ++ .../bevy_graph/src/utils/wrapped_iterator.rs | 5 +++++ 14 files changed, 133 insertions(+), 72 deletions(-) create mode 100644 crates/bevy_graph/src/utils/wrapped_iterator.rs diff --git a/crates/bevy_graph/src/graphs/edge.rs b/crates/bevy_graph/src/graphs/edge.rs index 16bd1fba0b14d..968e526af609a 100644 --- a/crates/bevy_graph/src/graphs/edge.rs +++ b/crates/bevy_graph/src/graphs/edge.rs @@ -1,27 +1,27 @@ use std::ops::{Deref, DerefMut}; -use super::keys::{EdgeIdx, NodeIdx}; +use super::keys::NodeIdx; /// An edge between nodes that store data of type `E`. #[derive(Clone)] -pub struct Edge(pub NodeIdx, pub NodeIdx, pub E, pub EdgeIdx); +pub struct Edge(pub NodeIdx, pub NodeIdx, pub E); impl Edge { /// Returns a [`EdgeRef`] of this edge #[inline] pub const fn as_ref_edge(&self) -> EdgeRef { - EdgeRef(self.0, self.1, &self.2, self.3) + EdgeRef(self.0, self.1, &self.2) } /// Returns a [`EdgeMut`] of this edge #[inline] pub fn as_mut_edge(&mut self) -> EdgeMut { - EdgeMut(self.0, self.1, &mut self.2, self.3) + EdgeMut(self.0, self.1, &mut self.2) } } /// An util container which holds `Edge` data with an immutable reference to the edge value -pub struct EdgeRef<'v, E>(pub NodeIdx, pub NodeIdx, pub &'v E, pub EdgeIdx); +pub struct EdgeRef<'v, E>(pub NodeIdx, pub NodeIdx, pub &'v E); impl<'v, E> Deref for EdgeRef<'v, E> { type Target = E; @@ -32,7 +32,7 @@ impl<'v, E> Deref for EdgeRef<'v, E> { } /// An util container which holds `Edge` data with a mutable reference to the edge value -pub struct EdgeMut<'v, E>(pub NodeIdx, pub NodeIdx, pub &'v mut E, pub EdgeIdx); +pub struct EdgeMut<'v, E>(pub NodeIdx, pub NodeIdx, pub &'v mut E); impl<'v, E> Deref for EdgeMut<'v, E> { type Target = E; diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 3cf51fca2d732..8db3f378c98bc 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -9,7 +9,7 @@ use crate::{ DirectedGraph, Graph, }, iters, - utils::{vecmap::VecMap, vecset::VecSet}, + utils::{vecmap::VecMap, vecset::VecSet, wrapped_iterator::WrappedIterator}, }; type MultiListStorage = Vec<(NodeIdx, Vec)>; @@ -108,9 +108,7 @@ impl Graph for MultiListGraph Err(GraphError::NodeNotFound(dst)) } else { unsafe { - let idx = self - .edges - .insert_with_key(|index| Edge(src, dst, value, index)); + let idx = self.edges.insert(Edge(src, dst, value)); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() @@ -143,11 +141,12 @@ impl Graph for MultiListGraph if self.has_node(index) { let edges_to_remove = self .edges_of(index) - .map(|edge| edge.3) + .into_inner() + .cloned() .collect::>(); for edge_idx in edges_to_remove { unsafe { - let Edge(src, dst, _, _) = self.edges.remove(edge_idx).unwrap_unchecked(); + let Edge(src, dst, _) = self.edges.remove(edge_idx).unwrap_unchecked(); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() @@ -172,7 +171,7 @@ impl Graph for MultiListGraph } fn remove_edge(&mut self, index: EdgeIdx) -> Option { - if let Some(Edge(src, dst, value, _)) = self.edges.remove(index) { + if let Some(Edge(src, dst, value)) = self.edges.remove(index) { unsafe { self.adjacencies .get_unchecked_mut(src) @@ -269,12 +268,12 @@ impl Graph for MultiListGraph iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = std::iter::Empty> where Self: 'e; + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { todo!() } - type EdgesOfMut<'e> = std::iter::Empty> where Self: 'e; + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { todo!() } @@ -383,7 +382,7 @@ impl DirectedGraph for MultiListGraph { .values_mut() .for_each(|list| list.for_each_mut(Vec::clear)); - for (index, Edge(src, dst, _, _)) in &mut self.edges { + for (index, Edge(src, dst, _)) in &mut self.edges { std::mem::swap(src, dst); self.adjacencies[*dst] .outgoing_mut() @@ -399,7 +398,7 @@ impl DirectedGraph for MultiListGraph { } fn reverse_edge(&mut self, index: EdgeIdx) { - if let Some(Edge(src, dst, _, _)) = self.edges.get_mut(index) { + if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { self.adjacencies[*src] .outgoing_mut() .get_value_mut(*dst) diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 72dc7c8da9585..df7b7cf3c4e00 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -9,7 +9,7 @@ use crate::{ DirectedGraph, Graph, }, iters, - utils::vecmap::VecMap, + utils::{vecmap::VecMap, wrapped_iterator::WrappedIterator}, }; type SimpleListStorage = Vec<(NodeIdx, EdgeIdx)>; @@ -113,9 +113,7 @@ impl Graph for SimpleListGraph Err(GraphError::Loop) } else { unsafe { - let idx = self - .edges - .insert_with_key(|index| Edge(src, dst, value, index)); + let idx = self.edges.insert(Edge(src, dst, value)); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() @@ -146,11 +144,12 @@ impl Graph for SimpleListGraph if self.has_node(index) { let edges_to_remove = self .edges_of(index) - .map(|edge| edge.3) + .into_inner() + .cloned() .collect::>(); for edge_idx in edges_to_remove { unsafe { - let Edge(src, dst, _, _) = self.edges.remove(edge_idx).unwrap_unchecked(); + let Edge(src, dst, _) = self.edges.remove(edge_idx).unwrap_unchecked(); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() @@ -171,7 +170,7 @@ impl Graph for SimpleListGraph } fn remove_edge(&mut self, index: EdgeIdx) -> Option { - if let Some(Edge(src, dst, value, _)) = self.edges.remove(index) { + if let Some(Edge(src, dst, value)) = self.edges.remove(index) { unsafe { self.adjacencies .get_unchecked_mut(src) @@ -264,12 +263,12 @@ impl Graph for SimpleListGraph iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = std::iter::Empty> where Self: 'e; + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { todo!() } - type EdgesOfMut<'e> = std::iter::Empty> where Self: 'e; + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { todo!() } @@ -366,7 +365,7 @@ impl DirectedGraph for SimpleListGraph { .values_mut() .for_each(|list| list.for_each_mut(Vec::clear)); - for (index, Edge(src, dst, _, _)) in &mut self.edges { + for (index, Edge(src, dst, _)) in &mut self.edges { std::mem::swap(src, dst); self.adjacencies[*dst].outgoing_mut().push((*src, index)); self.adjacencies[*src].incoming_mut().push((*dst, index)); @@ -374,7 +373,7 @@ impl DirectedGraph for SimpleListGraph { } fn reverse_edge(&mut self, index: EdgeIdx) { - if let Some(Edge(src, dst, _, _)) = self.edges.get_mut(index) { + if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { self.adjacencies[*src].outgoing_mut().remove_by_key(*dst); self.adjacencies[*dst].incoming_mut().remove_by_key(*src); std::mem::swap(src, dst); diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index d71486a0379b7..567c713a880e5 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -10,7 +10,7 @@ use crate::{ DirectedGraph, Graph, }, iters, - utils::vecset::VecSet, + utils::{vecset::VecSet, wrapped_iterator::WrappedIterator}, }; type MultiMapStorage = HashMap>; @@ -110,9 +110,7 @@ impl Graph for MultiMapGraph { Err(GraphError::NodeNotFound(dst)) } else { unsafe { - let idx = self - .edges - .insert_with_key(|index| Edge(src, dst, value, index)); + let idx = self.edges.insert(Edge(src, dst, value)); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() @@ -147,11 +145,12 @@ impl Graph for MultiMapGraph { if self.has_node(index) { let edges_to_remove = self .edges_of(index) - .map(|edge| edge.3) + .into_inner() + .cloned() .collect::>(); for edge_idx in edges_to_remove { unsafe { - let Edge(src, dst, _, _) = self.edges.remove(edge_idx).unwrap_unchecked(); + let Edge(src, dst, _) = self.edges.remove(edge_idx).unwrap_unchecked(); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() @@ -176,7 +175,7 @@ impl Graph for MultiMapGraph { } fn remove_edge(&mut self, index: EdgeIdx) -> Option { - if let Some(Edge(src, dst, value, _)) = self.edges.remove(index) { + if let Some(Edge(src, dst, value)) = self.edges.remove(index) { unsafe { self.adjacencies .get_unchecked_mut(src) @@ -273,12 +272,12 @@ impl Graph for MultiMapGraph { iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = std::iter::Empty> where Self: 'e; + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { todo!() } - type EdgesOfMut<'e> = std::iter::Empty> where Self: 'e; + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { todo!() } @@ -387,7 +386,7 @@ impl DirectedGraph for MultiMapGraph { .values_mut() .for_each(|map| map.for_each_mut(HashMap::clear)); - for (index, Edge(src, dst, _, _)) in &mut self.edges { + for (index, Edge(src, dst, _)) in &mut self.edges { std::mem::swap(src, dst); self.adjacencies[*dst] .outgoing_mut() @@ -403,7 +402,7 @@ impl DirectedGraph for MultiMapGraph { } fn reverse_edge(&mut self, index: EdgeIdx) { - if let Some(Edge(src, dst, _, _)) = self.edges.get_mut(index) { + if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { self.adjacencies[*src] .outgoing_mut() .get_mut(dst) diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 811d412011de5..a7e8dbaa7fde8 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -10,6 +10,7 @@ use crate::{ DirectedGraph, Graph, }, iters, + utils::wrapped_iterator::WrappedIterator, }; type SimpleMapStorage = HashMap; @@ -113,9 +114,7 @@ impl Graph for SimpleMapGraph Err(GraphError::Loop) } else { unsafe { - let idx = self - .edges - .insert_with_key(|index| Edge(src, dst, value, index)); + let idx = self.edges.insert(Edge(src, dst, value)); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() @@ -142,11 +141,12 @@ impl Graph for SimpleMapGraph if self.has_node(index) { let edges_to_remove = self .edges_of(index) - .map(|edge| edge.3) + .into_inner() + .cloned() .collect::>(); for edge_idx in edges_to_remove { unsafe { - let Edge(src, dst, _, _) = self.edges.remove(edge_idx).unwrap_unchecked(); + let Edge(src, dst, _) = self.edges.remove(edge_idx).unwrap_unchecked(); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() @@ -167,7 +167,7 @@ impl Graph for SimpleMapGraph } fn remove_edge(&mut self, index: EdgeIdx) -> Option { - if let Some(Edge(src, dst, value, _)) = self.edges.remove(index) { + if let Some(Edge(src, dst, value)) = self.edges.remove(index) { unsafe { self.adjacencies .get_unchecked_mut(src) @@ -260,12 +260,12 @@ impl Graph for SimpleMapGraph iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = std::iter::Empty> where Self: 'e; + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { todo!() } - type EdgesOfMut<'e> = std::iter::Empty> where Self: 'e; + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { todo!() } @@ -362,7 +362,7 @@ impl DirectedGraph for SimpleMapGraph { .values_mut() .for_each(|map| map.for_each_mut(HashMap::clear)); - for (index, Edge(src, dst, _, _)) in &mut self.edges { + for (index, Edge(src, dst, _)) in &mut self.edges { std::mem::swap(src, dst); self.adjacencies[*dst].outgoing_mut().insert(*src, index); self.adjacencies[*src].incoming_mut().insert(*dst, index); @@ -370,7 +370,7 @@ impl DirectedGraph for SimpleMapGraph { } fn reverse_edge(&mut self, index: EdgeIdx) { - if let Some(Edge(src, dst, _, _)) = self.edges.get_mut(index) { + if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { self.adjacencies[*src].outgoing_mut().remove(dst); self.adjacencies[*dst].incoming_mut().remove(src); std::mem::swap(src, dst); diff --git a/crates/bevy_graph/src/iters/edges_by_idx.rs b/crates/bevy_graph/src/iters/edges_by_idx.rs index c3b4e87e7ea29..d734aa91fe49d 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx.rs @@ -1,8 +1,11 @@ use slotmap::HopSlotMap; -use crate::graphs::{ - edge::{Edge, EdgeRef}, - keys::EdgeIdx, +use crate::{ + graphs::{ + edge::{Edge, EdgeRef}, + keys::EdgeIdx, + }, + utils::wrapped_iterator::WrappedIterator, }; /// An iterator which converts `&EdgeIdx` to a `EdgeRef` of the graph @@ -16,10 +19,13 @@ impl<'g, E: 'g, I: Iterator> EdgesByIdx<'g, E, I> { pub fn new(inner: I, edges: &'g HopSlotMap>) -> Self { Self { edges, inner } } +} - /// Returns the inner iterator which yields `EdgeIdx` +impl<'g, E: 'g, I: Iterator> WrappedIterator, I> + for EdgesByIdx<'g, E, I> +{ #[inline] - pub fn into_indices_iter(self) -> I { + fn into_inner(self) -> I { self.inner } } diff --git a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs index 0a7a557a58cea..17b90c44124ea 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs @@ -1,8 +1,11 @@ use slotmap::HopSlotMap; -use crate::graphs::{ - edge::{Edge, EdgeMut}, - keys::EdgeIdx, +use crate::{ + graphs::{ + edge::{Edge, EdgeMut}, + keys::EdgeIdx, + }, + utils::wrapped_iterator::WrappedIterator, }; /// An iterator which converts `&EdgeIdx` to a `EdgeMut` of the graph @@ -18,6 +21,15 @@ impl<'g, E: 'g, I: Iterator> EdgesByIdxMut<'g, E, I> { } } +impl<'g, E: 'g, I: Iterator> WrappedIterator, I> + for EdgesByIdxMut<'g, E, I> +{ + #[inline] + fn into_inner(self) -> I { + self.inner + } +} + impl<'g, E: 'g, I: Iterator> Iterator for EdgesByIdxMut<'g, E, I> { type Item = EdgeMut<'g, E>; @@ -28,7 +40,7 @@ impl<'g, E: 'g, I: Iterator> Iterator for EdgesByIdxMut<'g, unsafe { self.edges.get_mut(*index).map(|edge| { let ptr: *mut E = &mut edge.2; - EdgeMut(edge.0, edge.1, &mut *ptr, edge.3) + EdgeMut(edge.0, edge.1, &mut *ptr) }) } } else { diff --git a/crates/bevy_graph/src/iters/edges_mut.rs b/crates/bevy_graph/src/iters/edges_mut.rs index 2980a456d3c6f..b56678870fcc7 100644 --- a/crates/bevy_graph/src/iters/edges_mut.rs +++ b/crates/bevy_graph/src/iters/edges_mut.rs @@ -1,6 +1,9 @@ use std::marker::PhantomData; -use crate::graphs::edge::{Edge, EdgeMut}; +use crate::{ + graphs::edge::{Edge, EdgeMut}, + utils::wrapped_iterator::WrappedIterator, +}; /// An iterator which converts `&'g mut Edge` to a `EdgeMut<'g, E>` pub struct EdgesMut<'g, E: 'g, I: Iterator>> { @@ -18,6 +21,15 @@ impl<'g, E: 'g, I: Iterator>> EdgesMut<'g, E, I> { } } +impl<'g, E: 'g, I: Iterator>> WrappedIterator, I> + for EdgesMut<'g, E, I> +{ + #[inline] + fn into_inner(self) -> I { + self.inner + } +} + impl<'g, E: 'g, I: Iterator>> Iterator for EdgesMut<'g, E, I> { type Item = EdgeMut<'g, E>; diff --git a/crates/bevy_graph/src/iters/edges_ref.rs b/crates/bevy_graph/src/iters/edges_ref.rs index 49df915fa68d4..70b14b3bf8881 100644 --- a/crates/bevy_graph/src/iters/edges_ref.rs +++ b/crates/bevy_graph/src/iters/edges_ref.rs @@ -1,6 +1,9 @@ use std::marker::PhantomData; -use crate::graphs::edge::{Edge, EdgeRef}; +use crate::{ + graphs::edge::{Edge, EdgeRef}, + utils::wrapped_iterator::WrappedIterator, +}; /// An iterator which converts `&'g Edge` to a `EdgeRef<'g, E>` pub struct EdgesRef<'g, E: 'g, I: Iterator>> { @@ -18,6 +21,15 @@ impl<'g, E: 'g, I: Iterator>> EdgesRef<'g, E, I> { } } +impl<'g, E: 'g, I: Iterator>> WrappedIterator, I> + for EdgesRef<'g, E, I> +{ + #[inline] + fn into_inner(self) -> I { + self.inner + } +} + impl<'g, E: 'g, I: Iterator>> Iterator for EdgesRef<'g, E, I> { type Item = EdgeRef<'g, E>; diff --git a/crates/bevy_graph/src/iters/nodes_by_idx.rs b/crates/bevy_graph/src/iters/nodes_by_idx.rs index 894f9d25f3ccc..c51135fb7001a 100644 --- a/crates/bevy_graph/src/iters/nodes_by_idx.rs +++ b/crates/bevy_graph/src/iters/nodes_by_idx.rs @@ -1,6 +1,6 @@ use slotmap::HopSlotMap; -use crate::graphs::keys::NodeIdx; +use crate::{graphs::keys::NodeIdx, utils::wrapped_iterator::WrappedIterator}; /// An iterator which converts `&NodeIdx` to a `&'g N` of the graph pub struct NodesByIdx<'g, N: 'g, I: Iterator> { @@ -13,10 +13,13 @@ impl<'g, N: 'g, I: Iterator> NodesByIdx<'g, N, I> { pub fn new(inner: I, nodes: &'g HopSlotMap) -> Self { Self { nodes, inner } } +} - /// Returns the inner iterator which yields `NodeIdx` +impl<'g, N: 'g, I: Iterator> WrappedIterator + for NodesByIdx<'g, N, I> +{ #[inline] - pub fn into_indices_iter(self) -> I { + fn into_inner(self) -> I { self.inner } } diff --git a/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs b/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs index 98a132234764b..8671512abfe4c 100644 --- a/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs +++ b/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs @@ -1,6 +1,6 @@ use slotmap::HopSlotMap; -use crate::graphs::keys::NodeIdx; +use crate::{graphs::keys::NodeIdx, utils::wrapped_iterator::WrappedIterator}; /// An iterator which converts `&NodeIdx` to a `&'g mut N` of the graph pub struct NodesByIdxMut<'g, N: 'g, I: Iterator> { @@ -13,10 +13,13 @@ impl<'g, N: 'g, I: Iterator> NodesByIdxMut<'g, N, I> { pub fn new(inner: I, nodes: &'g mut HopSlotMap) -> Self { Self { nodes, inner } } +} - /// Returns the inner iterator which yields `NodeIdx` +impl<'g, N: 'g, I: Iterator> WrappedIterator + for NodesByIdxMut<'g, N, I> +{ #[inline] - pub fn into_indices_iter(self) -> I { + fn into_inner(self) -> I { self.inner } } diff --git a/crates/bevy_graph/src/iters/sources_sinks.rs b/crates/bevy_graph/src/iters/sources_sinks.rs index abf80b0b660b2..cfb5179c7f305 100644 --- a/crates/bevy_graph/src/iters/sources_sinks.rs +++ b/crates/bevy_graph/src/iters/sources_sinks.rs @@ -1,14 +1,14 @@ use std::marker::PhantomData; -use crate::graphs::keys::NodeIdx; +use crate::{graphs::keys::NodeIdx, utils::wrapped_iterator::WrappedIterator}; /// An iterator which iterates every source / sink node of a graph -pub struct SourcesSinks> { +pub struct SourcesSinks> { inner: I, - phantom: PhantomData, + phantom: PhantomData, } -impl> SourcesSinks { +impl> SourcesSinks { /// An iterator which iterates every source / sink node of a graph pub fn new(inner: I) -> Self { Self { @@ -18,8 +18,17 @@ impl> SourcesSinks { } } -impl> Iterator for SourcesSinks { - type Item = N; +impl> WrappedIterator + for SourcesSinks +{ + #[inline] + fn into_inner(self) -> I { + self.inner + } +} + +impl> Iterator for SourcesSinks { + type Item = T; fn next(&mut self) -> Option { self.inner diff --git a/crates/bevy_graph/src/utils/mod.rs b/crates/bevy_graph/src/utils/mod.rs index 71cc2ca152202..92b7509b9bab5 100644 --- a/crates/bevy_graph/src/utils/mod.rs +++ b/crates/bevy_graph/src/utils/mod.rs @@ -2,3 +2,5 @@ pub mod vecmap; /// Set-like methods for `Vec` pub mod vecset; +/// Trait with helping function for getting the inner iterator of a wrapping iterator +pub mod wrapped_iterator; diff --git a/crates/bevy_graph/src/utils/wrapped_iterator.rs b/crates/bevy_graph/src/utils/wrapped_iterator.rs new file mode 100644 index 0000000000000..2f899c4359ec9 --- /dev/null +++ b/crates/bevy_graph/src/utils/wrapped_iterator.rs @@ -0,0 +1,5 @@ +/// Trait with helping function for getting the inner iterator of a wrapping iterator. +pub trait WrappedIterator, T, I: Iterator>: Iterator { + /// Gets the inner iterator the current one is wrapping around. + fn into_inner(self) -> I; +} From 0dfbe39f187e38b77341b78d5eb60c2c605e6051 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 22 Jan 2023 20:11:23 +0100 Subject: [PATCH 154/183] yeah forgot about algos lol --- crates/bevy_graph/src/algos/bfs.rs | 4 ++-- crates/bevy_graph/src/algos/dfs.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index f1eb1546c0ff5..3632dd0acd04a 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -39,7 +39,7 @@ impl BreadthFirstSearch { /// Gets an immutable reference to the value of the next node from the algorithm pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { if let Some(node) = self.queue.pop_front() { - for EdgeRef(_, dst, _, _) in graph.outgoing_edges_of(node) { + for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.queue.push_back(dst); @@ -54,7 +54,7 @@ impl BreadthFirstSearch { /// Gets a mutable reference to the value of the next node from the algorithm. pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.queue.pop_front() { - for EdgeRef(_, dst, _, _) in graph.outgoing_edges_of(node) { + for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.queue.push_back(dst); diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 1d3083ecd0e0d..bfb2b8eb5146d 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -36,7 +36,7 @@ impl DepthFirstSearch { /// Gets a reference to the value of the next node from the algorithm. pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { if let Some(node) = self.stack.pop() { - for EdgeRef(_, dst, _, _) in graph.outgoing_edges_of(node) { + for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.stack.push(dst); @@ -51,7 +51,7 @@ impl DepthFirstSearch { /// Gets a mutable reference to the value of the next node from the algorithm. pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { if let Some(node) = self.stack.pop() { - for EdgeRef(_, dst, _, _) in graph.outgoing_edges_of(node) { + for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.stack.push(dst); From d393fde20f098ee6b4cb0b83b397fe57e8bed762 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 22 Jan 2023 20:13:12 +0100 Subject: [PATCH 155/183] docs --- crates/bevy_graph/src/algos/bfs.rs | 2 +- crates/bevy_graph/src/algos/dfs.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 3632dd0acd04a..5bf776c858b73 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -4,7 +4,7 @@ use hashbrown::HashSet; use crate::graphs::{edge::EdgeRef, keys::NodeIdx, Graph}; -/// Implementation of the [`BFS` algorythm](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/) +/// Implementation of the [`BFS` algorithm](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/) /// /// when `d` is the distance between a node and the startnode, /// it will evaluate every node with `d=1`, then continue with `d=2` and so on. diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index bfb2b8eb5146d..5507d2c7279d6 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -2,7 +2,7 @@ use hashbrown::HashSet; use crate::graphs::{edge::EdgeRef, keys::NodeIdx, Graph}; -/// Implementation of the [`DFS` algorythm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) +/// Implementation of the [`DFS` algorithm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) /// /// it will evaluate every node from the start as deep as it can and then continue at the next sibling node from the top. pub struct DepthFirstSearch { From 7349546b0d297790794a3bef5534c88895d30dea Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 23 Jan 2023 14:44:26 +0100 Subject: [PATCH 156/183] Add `GraphIterator` trait for BFS and DFS --- crates/bevy_graph/src/algos/bfs.rs | 15 ++++++++++----- crates/bevy_graph/src/algos/dfs.rs | 15 ++++++++++----- crates/bevy_graph/src/algos/mod.rs | 17 +++++++++++++++++ 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 5bf776c858b73..2e1609347a465 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -4,6 +4,8 @@ use hashbrown::HashSet; use crate::graphs::{edge::EdgeRef, keys::NodeIdx, Graph}; +use super::GraphIterator; + /// Implementation of the [`BFS` algorithm](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/) /// /// when `d` is the distance between a node and the startnode, @@ -35,9 +37,13 @@ impl BreadthFirstSearch { Self { queue, visited } } +} + +impl<'g, N: 'g, E, G: Graph> GraphIterator<'g, N, E, G> for BreadthFirstSearch { + type Item = &'g N; + type ItemMut = &'g mut N; - /// Gets an immutable reference to the value of the next node from the algorithm - pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { + fn next(&mut self, graph: &'g G) -> Option { if let Some(node) = self.queue.pop_front() { for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { @@ -51,8 +57,7 @@ impl BreadthFirstSearch { } } - /// Gets a mutable reference to the value of the next node from the algorithm. - pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { + fn next_mut(&mut self, graph: &'g mut G) -> Option { if let Some(node) = self.queue.pop_front() { for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { @@ -70,7 +75,7 @@ impl BreadthFirstSearch { #[cfg(test)] mod test { use crate::{ - algos::bfs::BreadthFirstSearch, + algos::{bfs::BreadthFirstSearch, GraphIterator}, graphs::{map::SimpleMapGraph, Graph}, }; diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 5507d2c7279d6..d94174877959e 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -2,6 +2,8 @@ use hashbrown::HashSet; use crate::graphs::{edge::EdgeRef, keys::NodeIdx, Graph}; +use super::GraphIterator; + /// Implementation of the [`DFS` algorithm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) /// /// it will evaluate every node from the start as deep as it can and then continue at the next sibling node from the top. @@ -32,9 +34,13 @@ impl DepthFirstSearch { Self { stack, visited } } +} + +impl<'g, N: 'g, E, G: Graph> GraphIterator<'g, N, E, G> for DepthFirstSearch { + type Item = &'g N; + type ItemMut = &'g mut N; - /// Gets a reference to the value of the next node from the algorithm. - pub fn next<'g, N, E>(&mut self, graph: &'g impl Graph) -> Option<&'g N> { + fn next(&mut self, graph: &'g G) -> Option { if let Some(node) = self.stack.pop() { for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { @@ -48,8 +54,7 @@ impl DepthFirstSearch { } } - /// Gets a mutable reference to the value of the next node from the algorithm. - pub fn next_mut<'g, N, E>(&mut self, graph: &'g mut impl Graph) -> Option<&'g mut N> { + fn next_mut(&mut self, graph: &'g mut G) -> Option { if let Some(node) = self.stack.pop() { for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { @@ -67,7 +72,7 @@ impl DepthFirstSearch { #[cfg(test)] mod test { use crate::{ - algos::dfs::DepthFirstSearch, + algos::{dfs::DepthFirstSearch, GraphIterator}, graphs::{map::SimpleMapGraph, Graph}, }; diff --git a/crates/bevy_graph/src/algos/mod.rs b/crates/bevy_graph/src/algos/mod.rs index cde0fa3130c06..56a2ae3b3290d 100644 --- a/crates/bevy_graph/src/algos/mod.rs +++ b/crates/bevy_graph/src/algos/mod.rs @@ -1,4 +1,21 @@ +use crate::graphs::Graph; + /// Implementation of the [`BFS` algorythm](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/) pub mod bfs; /// Implementation of the [`DFS` algorythm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) pub mod dfs; + +/// A special iterator-like trait for iterations over data in graphs. +pub trait GraphIterator<'g, N, E, G: Graph> { + /// The type of the elements being iterated over immutable. + type Item; + + /// Gets an immutable reference to the value of the next node from the algorithm and advances. + fn next(&mut self, graph: &'g G) -> Option; + + /// The type of the elements being iterated over mutable. + type ItemMut; + + /// Gets a mutable reference to the value of the next node from the algorithm and advances. + fn next_mut(&mut self, graph: &'g mut G) -> Option; +} From bad59717dd92504915377b0caa0947c69657f2f5 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 23 Jan 2023 16:05:43 +0100 Subject: [PATCH 157/183] Make `BFS/DFS` return `NodeIdx` and wrap them --- crates/bevy_graph/src/algos/bfs.rs | 73 +++++++++------------ crates/bevy_graph/src/algos/dfs.rs | 73 +++++++++------------ crates/bevy_graph/src/algos/mod.rs | 17 ----- crates/bevy_graph/src/graphs/list/multi.rs | 8 ++- crates/bevy_graph/src/graphs/list/simple.rs | 8 ++- crates/bevy_graph/src/graphs/map/multi.rs | 8 ++- crates/bevy_graph/src/graphs/map/simple.rs | 8 ++- crates/bevy_graph/src/graphs/mod.rs | 9 +++ crates/bevy_graph/src/iters/nodes_by_idx.rs | 29 +++++--- 9 files changed, 117 insertions(+), 116 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 2e1609347a465..aa16051e2ea00 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -1,71 +1,60 @@ -use std::collections::VecDeque; +use std::{collections::VecDeque, marker::PhantomData}; use hashbrown::HashSet; -use crate::graphs::{edge::EdgeRef, keys::NodeIdx, Graph}; - -use super::GraphIterator; +use crate::{ + graphs::{edge::EdgeRef, keys::NodeIdx, Graph}, + iters, +}; /// Implementation of the [`BFS` algorithm](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/) /// /// when `d` is the distance between a node and the startnode, /// it will evaluate every node with `d=1`, then continue with `d=2` and so on. -pub struct BreadthFirstSearch { +pub struct BreadthFirstSearch<'g, N, E, G: Graph> { + graph: &'g G, queue: VecDeque, visited: HashSet, + phantom: PhantomData<(N, E)>, } -impl BreadthFirstSearch { +impl<'g, N, E, G: Graph> BreadthFirstSearch<'g, N, E, G> { /// Creates a new `BreadthFirstSearch` with a start node - pub fn new(start: NodeIdx) -> Self { - let mut queue = VecDeque::new(); - let mut visited = HashSet::new(); - - visited.insert(start); - queue.push_back(start); - - Self { queue, visited } - } - - /// Creates a new `BreadthFirstSearch` with a start node and the count of nodes for capacity reserving - pub fn with_capacity(start: NodeIdx, node_count: usize) -> Self { + pub fn new(graph: &'g G, start: NodeIdx) -> Self { + let node_count = graph.node_count(); let mut queue = VecDeque::with_capacity(node_count); let mut visited = HashSet::with_capacity(node_count); visited.insert(start); queue.push_back(start); - Self { queue, visited } + Self { + graph, + queue, + visited, + phantom: PhantomData, + } } -} -impl<'g, N: 'g, E, G: Graph> GraphIterator<'g, N, E, G> for BreadthFirstSearch { - type Item = &'g N; - type ItemMut = &'g mut N; - - fn next(&mut self, graph: &'g G) -> Option { - if let Some(node) = self.queue.pop_front() { - for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { - if !self.visited.contains(&dst) { - self.visited.insert(dst); - self.queue.push_back(dst); - } - } - Some(graph.get_node(node).unwrap()) - } else { - None - } + /// Creates a new `BreadthFirstSearch` wrapped inside an `NodesByIdx` iterator + pub fn new_ref(graph: &'g G, start: NodeIdx) -> iters::NodesByIdx<'g, N, NodeIdx, Self> { + let inner = Self::new(graph, start); + iters::NodesByIdx::from_graph(inner, graph) } +} + +impl<'g, N, E, G: Graph> Iterator for BreadthFirstSearch<'g, N, E, G> { + type Item = NodeIdx; - fn next_mut(&mut self, graph: &'g mut G) -> Option { + fn next(&mut self) -> Option { if let Some(node) = self.queue.pop_front() { - for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { + for EdgeRef(_, dst, _) in self.graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.queue.push_back(dst); } } - Some(graph.get_node_mut(node).unwrap()) + Some(node) } else { None } @@ -75,7 +64,7 @@ impl<'g, N: 'g, E, G: Graph> GraphIterator<'g, N, E, G> for BreadthFirstSe #[cfg(test)] mod test { use crate::{ - algos::{bfs::BreadthFirstSearch, GraphIterator}, + algos::bfs::BreadthFirstSearch, graphs::{map::SimpleMapGraph, Graph}, }; @@ -98,8 +87,8 @@ mod test { let mut counted_elements = Vec::with_capacity(4); - let mut bfs = BreadthFirstSearch::with_capacity(zero, graph.node_count()); - while let Some(node) = bfs.next(&graph) { + let bfs = BreadthFirstSearch::new_ref(&graph, zero); + for node in bfs { counted_elements.push(*node); } diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index d94174877959e..eb8be33dcf075 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -1,68 +1,59 @@ -use hashbrown::HashSet; +use std::marker::PhantomData; -use crate::graphs::{edge::EdgeRef, keys::NodeIdx, Graph}; +use hashbrown::HashSet; -use super::GraphIterator; +use crate::{ + graphs::{edge::EdgeRef, keys::NodeIdx, Graph}, + iters, +}; /// Implementation of the [`DFS` algorithm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) /// /// it will evaluate every node from the start as deep as it can and then continue at the next sibling node from the top. -pub struct DepthFirstSearch { +pub struct DepthFirstSearch<'g, N, E, G: Graph> { + graph: &'g G, stack: Vec, visited: HashSet, + phantom: PhantomData<(N, E)>, } -impl DepthFirstSearch { +impl<'g, N, E, G: Graph> DepthFirstSearch<'g, N, E, G> { /// Creates a new `DepthFirstSearch` with a start node - pub fn new(start: NodeIdx) -> Self { - let mut stack = Vec::new(); - let mut visited = HashSet::new(); - - visited.insert(start); - stack.push(start); - - Self { stack, visited } - } - - /// Creates a new `DepthFirstSearch` with a start node and the count of nodes for capacity reserving - pub fn with_capacity(start: NodeIdx, node_count: usize) -> Self { + pub fn new(graph: &'g G, start: NodeIdx) -> Self { + let node_count = graph.node_count(); let mut stack = Vec::with_capacity(node_count); let mut visited = HashSet::with_capacity(node_count); visited.insert(start); stack.push(start); - Self { stack, visited } + Self { + graph, + stack, + visited, + phantom: PhantomData, + } } -} - -impl<'g, N: 'g, E, G: Graph> GraphIterator<'g, N, E, G> for DepthFirstSearch { - type Item = &'g N; - type ItemMut = &'g mut N; - fn next(&mut self, graph: &'g G) -> Option { - if let Some(node) = self.stack.pop() { - for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { - if !self.visited.contains(&dst) { - self.visited.insert(dst); - self.stack.push(dst); - } - } - Some(graph.get_node(node).unwrap()) - } else { - None - } + /// Creates a new `DepthFirstSearch` wrapped inside an `NodesByIdx` iterator + pub fn new_ref(graph: &'g G, start: NodeIdx) -> iters::NodesByIdx<'g, N, NodeIdx, Self> { + let inner = Self::new(graph, start); + iters::NodesByIdx::from_graph(inner, graph) } +} + +impl<'g, N, E, G: Graph> Iterator for DepthFirstSearch<'g, N, E, G> { + type Item = NodeIdx; - fn next_mut(&mut self, graph: &'g mut G) -> Option { + fn next(&mut self) -> Option { if let Some(node) = self.stack.pop() { - for EdgeRef(_, dst, _) in graph.outgoing_edges_of(node) { + for EdgeRef(_, dst, _) in self.graph.outgoing_edges_of(node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.stack.push(dst); } } - Some(graph.get_node_mut(node).unwrap()) + Some(node) } else { None } @@ -72,7 +63,7 @@ impl<'g, N: 'g, E, G: Graph> GraphIterator<'g, N, E, G> for DepthFirstSear #[cfg(test)] mod test { use crate::{ - algos::{dfs::DepthFirstSearch, GraphIterator}, + algos::dfs::DepthFirstSearch, graphs::{map::SimpleMapGraph, Graph}, }; @@ -95,8 +86,8 @@ mod test { let mut counted_elements = Vec::with_capacity(4); - let mut dfs = DepthFirstSearch::with_capacity(zero, graph.node_count()); - while let Some(node) = dfs.next(&graph) { + let dfs = DepthFirstSearch::new_ref(&graph, zero); + for node in dfs { counted_elements.push(*node); } diff --git a/crates/bevy_graph/src/algos/mod.rs b/crates/bevy_graph/src/algos/mod.rs index 56a2ae3b3290d..cde0fa3130c06 100644 --- a/crates/bevy_graph/src/algos/mod.rs +++ b/crates/bevy_graph/src/algos/mod.rs @@ -1,21 +1,4 @@ -use crate::graphs::Graph; - /// Implementation of the [`BFS` algorythm](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/) pub mod bfs; /// Implementation of the [`DFS` algorythm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) pub mod dfs; - -/// A special iterator-like trait for iterations over data in graphs. -pub trait GraphIterator<'g, N, E, G: Graph> { - /// The type of the elements being iterated over immutable. - type Item; - - /// Gets an immutable reference to the value of the next node from the algorithm and advances. - fn next(&mut self, graph: &'g G) -> Option; - - /// The type of the elements being iterated over mutable. - type ItemMut; - - /// Gets a mutable reference to the value of the next node from the algorithm and advances. - fn next_mut(&mut self, graph: &'g mut G) -> Option; -} diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 8db3f378c98bc..34877ec932b76 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -243,6 +243,10 @@ impl Graph for MultiListGraph self.nodes.keys() } + unsafe fn nodes_raw(&self) -> &slotmap::HopSlotMap { + &self.nodes + } + type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; fn nodes(&self) -> Self::Nodes<'_> { self.nodes.values() @@ -320,7 +324,7 @@ impl Graph for MultiListGraph ) } - type InNeighbors<'n> = iters::NodesByIdx<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, Vec>> where Self: 'n; + type InNeighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, crate::utils::vecmap::Keys<'n, NodeIdx, Vec>> where Self: 'n; fn in_neighbors(&self, index: NodeIdx) -> Self::InNeighbors<'_> { iters::NodesByIdx::new(self.adjacencies[index].incoming().keys(), &self.nodes) } @@ -330,7 +334,7 @@ impl Graph for MultiListGraph iters::NodesByIdxMut::new(self.adjacencies[index].incoming().keys(), &mut self.nodes) } - type OutNeighbors<'n> = iters::NodesByIdx<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, Vec>> where Self: 'n; + type OutNeighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, crate::utils::vecmap::Keys<'n, NodeIdx, Vec>> where Self: 'n; fn out_neighbors(&self, index: NodeIdx) -> Self::OutNeighbors<'_> { iters::NodesByIdx::new(self.adjacencies[index].outgoing().keys(), &self.nodes) } diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index df7b7cf3c4e00..2dadae26f580e 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -238,6 +238,10 @@ impl Graph for SimpleListGraph self.nodes.keys() } + unsafe fn nodes_raw(&self) -> &slotmap::HopSlotMap { + &self.nodes + } + type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; fn nodes(&self) -> Self::Nodes<'_> { self.nodes.values() @@ -303,7 +307,7 @@ impl Graph for SimpleListGraph iters::EdgesByIdxMut::new(self.adjacencies[index].outgoing().values(), &mut self.edges) } - type InNeighbors<'n> = iters::NodesByIdx<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + type InNeighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; fn in_neighbors(&self, index: NodeIdx) -> Self::InNeighbors<'_> { iters::NodesByIdx::new(self.adjacencies[index].incoming().keys(), &self.nodes) } @@ -313,7 +317,7 @@ impl Graph for SimpleListGraph iters::NodesByIdxMut::new(self.adjacencies[index].incoming().keys(), &mut self.nodes) } - type OutNeighbors<'n> = iters::NodesByIdx<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + type OutNeighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; fn out_neighbors(&self, index: NodeIdx) -> Self::OutNeighbors<'_> { iters::NodesByIdx::new(self.adjacencies[index].outgoing().keys(), &self.nodes) } diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 567c713a880e5..ad052c9eea647 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -247,6 +247,10 @@ impl Graph for MultiMapGraph { self.nodes.keys() } + unsafe fn nodes_raw(&self) -> &slotmap::HopSlotMap { + &self.nodes + } + type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; fn nodes(&self) -> Self::Nodes<'_> { self.nodes.values() @@ -324,7 +328,7 @@ impl Graph for MultiMapGraph { ) } - type InNeighbors<'n> = iters::NodesByIdx<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, Vec>> where Self: 'n; + type InNeighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, hashbrown::hash_map::Keys<'n, NodeIdx, Vec>> where Self: 'n; fn in_neighbors(&self, index: NodeIdx) -> Self::InNeighbors<'_> { iters::NodesByIdx::new(self.adjacencies[index].incoming().keys(), &self.nodes) } @@ -334,7 +338,7 @@ impl Graph for MultiMapGraph { iters::NodesByIdxMut::new(self.adjacencies[index].incoming().keys(), &mut self.nodes) } - type OutNeighbors<'n> = iters::NodesByIdx<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, Vec>> where Self: 'n; + type OutNeighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, hashbrown::hash_map::Keys<'n, NodeIdx, Vec>> where Self: 'n; fn out_neighbors(&self, index: NodeIdx) -> Self::OutNeighbors<'_> { iters::NodesByIdx::new(self.adjacencies[index].outgoing().keys(), &self.nodes) } diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index a7e8dbaa7fde8..cc1d488e924a5 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -235,6 +235,10 @@ impl Graph for SimpleMapGraph self.nodes.keys() } + unsafe fn nodes_raw(&self) -> &slotmap::HopSlotMap { + &self.nodes + } + type Nodes<'n> = slotmap::hop::Values<'n, NodeIdx, N> where Self: 'n; fn nodes(&self) -> Self::Nodes<'_> { self.nodes.values() @@ -300,7 +304,7 @@ impl Graph for SimpleMapGraph iters::EdgesByIdxMut::new(self.adjacencies[index].outgoing().values(), &mut self.edges) } - type InNeighbors<'n> = iters::NodesByIdx<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + type InNeighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; fn in_neighbors(&self, index: NodeIdx) -> Self::InNeighbors<'_> { iters::NodesByIdx::new(self.adjacencies[index].incoming().keys(), &self.nodes) } @@ -310,7 +314,7 @@ impl Graph for SimpleMapGraph iters::NodesByIdxMut::new(self.adjacencies[index].incoming().keys(), &mut self.nodes) } - type OutNeighbors<'n> = iters::NodesByIdx<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + type OutNeighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; fn out_neighbors(&self, index: NodeIdx) -> Self::OutNeighbors<'_> { iters::NodesByIdx::new(self.adjacencies[index].outgoing().keys(), &self.nodes) } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index e866d3cf0be4c..2e0381c92a788 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -10,6 +10,8 @@ pub mod edge; /// The `NodeIdx` and `EdgeIdx` structs pub mod keys; +use slotmap::HopSlotMap; + use crate::error::GraphError; use self::{ @@ -255,6 +257,13 @@ pub trait Graph { /// Returns an iterator over all `NodeIdx`s. fn node_indices(&self) -> Self::NodeIndices<'_>; + /// Returns a raw handle to the nodes slotmap. + /// + /// # Safety + /// + /// This function should only be called when you really know what you are doing. + unsafe fn nodes_raw(&self) -> &HopSlotMap; + /// Returns an iterator over all nodes. fn nodes(&self) -> Self::Nodes<'_>; diff --git a/crates/bevy_graph/src/iters/nodes_by_idx.rs b/crates/bevy_graph/src/iters/nodes_by_idx.rs index c51135fb7001a..b865add935b22 100644 --- a/crates/bevy_graph/src/iters/nodes_by_idx.rs +++ b/crates/bevy_graph/src/iters/nodes_by_idx.rs @@ -1,22 +1,35 @@ +use std::borrow::Borrow; + use slotmap::HopSlotMap; -use crate::{graphs::keys::NodeIdx, utils::wrapped_iterator::WrappedIterator}; +use crate::{ + graphs::{keys::NodeIdx, Graph}, + utils::wrapped_iterator::WrappedIterator, +}; -/// An iterator which converts `&NodeIdx` to a `&'g N` of the graph -pub struct NodesByIdx<'g, N: 'g, I: Iterator> { +/// An iterator which converts `(&)NodeIdx` to a `&'g N` of the graph +pub struct NodesByIdx<'g, N: 'g, B: Borrow, I: Iterator> { nodes: &'g HopSlotMap, inner: I, } -impl<'g, N: 'g, I: Iterator> NodesByIdx<'g, N, I> { +impl<'g, N: 'g, B: Borrow, I: Iterator> NodesByIdx<'g, N, B, I> { + /// Creates a new `NodesByIdx` iterator over a graph with the provided `inner` iterator + pub fn from_graph(inner: I, graph: &'g impl Graph) -> Self { + Self { + nodes: unsafe { graph.nodes_raw() }, + inner, + } + } + /// Creates a new `NodesByIdx` iterator over a graph with the provided `inner` iterator pub fn new(inner: I, nodes: &'g HopSlotMap) -> Self { Self { nodes, inner } } } -impl<'g, N: 'g, I: Iterator> WrappedIterator - for NodesByIdx<'g, N, I> +impl<'g, N: 'g, B: Borrow, I: Iterator> WrappedIterator + for NodesByIdx<'g, N, B, I> { #[inline] fn into_inner(self) -> I { @@ -24,12 +37,12 @@ impl<'g, N: 'g, I: Iterator> WrappedIterator } } -impl<'g, N: 'g, I: Iterator> Iterator for NodesByIdx<'g, N, I> { +impl<'g, N: 'g, B: Borrow, I: Iterator> Iterator for NodesByIdx<'g, N, B, I> { type Item = &'g N; fn next(&mut self) -> Option { if let Some(index) = self.inner.next() { - self.nodes.get(*index) + self.nodes.get(*index.borrow()) } else { None } From 639e8eceebe7a1641a07fe04720634c276fe41e7 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 23 Jan 2023 16:14:14 +0100 Subject: [PATCH 158/183] Add `new_mut` to algos --- crates/bevy_graph/src/algos/bfs.rs | 11 +++++++ crates/bevy_graph/src/algos/dfs.rs | 11 +++++++ crates/bevy_graph/src/graphs/list/multi.rs | 8 +++-- crates/bevy_graph/src/graphs/list/simple.rs | 8 +++-- crates/bevy_graph/src/graphs/map/multi.rs | 8 +++-- crates/bevy_graph/src/graphs/map/simple.rs | 8 +++-- crates/bevy_graph/src/graphs/mod.rs | 9 +++++- .../bevy_graph/src/iters/nodes_by_idx_mut.rs | 29 ++++++++++++++----- 8 files changed, 75 insertions(+), 17 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index aa16051e2ea00..38cc48a5b24f4 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -41,6 +41,17 @@ impl<'g, N, E, G: Graph> BreadthFirstSearch<'g, N, E, G> { let inner = Self::new(graph, start); iters::NodesByIdx::from_graph(inner, graph) } + + /// Creates a new `BreadthFirstSearch` wrapped inside an `NodesByIdxMut` iterator + pub fn new_mut(graph: &'g mut G, start: NodeIdx) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { + unsafe { + // SAFETY: We know `NodesByIdxMut` doesn't intercept (deletes nodes) at all. + let ptr: *mut G = &mut *graph; + let inner = Self::new(&*ptr, start); + + iters::NodesByIdxMut::from_graph(inner, graph) + } + } } impl<'g, N, E, G: Graph> Iterator for BreadthFirstSearch<'g, N, E, G> { diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index eb8be33dcf075..10803b8542c95 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -40,6 +40,17 @@ impl<'g, N, E, G: Graph> DepthFirstSearch<'g, N, E, G> { let inner = Self::new(graph, start); iters::NodesByIdx::from_graph(inner, graph) } + + /// Creates a new `BreadthFirstSearch` wrapped inside an `NodesByIdxMut` iterator + pub fn new_mut(graph: &'g mut G, start: NodeIdx) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { + unsafe { + // SAFETY: We know `NodesByIdxMut` doesn't intercept (deletes nodes) at all. + let ptr: *mut G = &mut *graph; + let inner = Self::new(&*ptr, start); + + iters::NodesByIdxMut::from_graph(inner, graph) + } + } } impl<'g, N, E, G: Graph> Iterator for DepthFirstSearch<'g, N, E, G> { diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 34877ec932b76..1f83504ccdf5c 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -252,6 +252,10 @@ impl Graph for MultiListGraph self.nodes.values() } + unsafe fn nodes_mut_raw(&mut self) -> &mut HopSlotMap { + &mut self.nodes + } + type NodesMut<'n> = slotmap::hop::ValuesMut<'n, NodeIdx, N> where Self: 'n; fn nodes_mut(&mut self) -> Self::NodesMut<'_> { self.nodes.values_mut() @@ -329,7 +333,7 @@ impl Graph for MultiListGraph iters::NodesByIdx::new(self.adjacencies[index].incoming().keys(), &self.nodes) } - type InNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, Vec>> where Self: 'n; + type InNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, crate::utils::vecmap::Keys<'n, NodeIdx, Vec>> where Self: 'n; fn in_neighbors_mut(&mut self, index: NodeIdx) -> Self::InNeighborsMut<'_> { iters::NodesByIdxMut::new(self.adjacencies[index].incoming().keys(), &mut self.nodes) } @@ -339,7 +343,7 @@ impl Graph for MultiListGraph iters::NodesByIdx::new(self.adjacencies[index].outgoing().keys(), &self.nodes) } - type OutNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, Vec>> where Self: 'n; + type OutNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, crate::utils::vecmap::Keys<'n, NodeIdx, Vec>> where Self: 'n; fn out_neighbors_mut(&mut self, index: NodeIdx) -> Self::OutNeighborsMut<'_> { iters::NodesByIdxMut::new( self.adjacencies[index].outgoing_mut().keys(), diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 2dadae26f580e..205c275002a46 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -247,6 +247,10 @@ impl Graph for SimpleListGraph self.nodes.values() } + unsafe fn nodes_mut_raw(&mut self) -> &mut HopSlotMap { + &mut self.nodes + } + type NodesMut<'n> = slotmap::hop::ValuesMut<'n, NodeIdx, N> where Self: 'n; fn nodes_mut(&mut self) -> Self::NodesMut<'_> { self.nodes.values_mut() @@ -312,7 +316,7 @@ impl Graph for SimpleListGraph iters::NodesByIdx::new(self.adjacencies[index].incoming().keys(), &self.nodes) } - type InNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + type InNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; fn in_neighbors_mut(&mut self, index: NodeIdx) -> Self::InNeighborsMut<'_> { iters::NodesByIdxMut::new(self.adjacencies[index].incoming().keys(), &mut self.nodes) } @@ -322,7 +326,7 @@ impl Graph for SimpleListGraph iters::NodesByIdx::new(self.adjacencies[index].outgoing().keys(), &self.nodes) } - type OutNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + type OutNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; fn out_neighbors_mut(&mut self, index: NodeIdx) -> Self::OutNeighborsMut<'_> { iters::NodesByIdxMut::new( self.adjacencies[index].outgoing_mut().keys(), diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index ad052c9eea647..c54657bf8a0d6 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -256,6 +256,10 @@ impl Graph for MultiMapGraph { self.nodes.values() } + unsafe fn nodes_mut_raw(&mut self) -> &mut HopSlotMap { + &mut self.nodes + } + type NodesMut<'n> = slotmap::hop::ValuesMut<'n, NodeIdx, N> where Self: 'n; fn nodes_mut(&mut self) -> Self::NodesMut<'_> { self.nodes.values_mut() @@ -333,7 +337,7 @@ impl Graph for MultiMapGraph { iters::NodesByIdx::new(self.adjacencies[index].incoming().keys(), &self.nodes) } - type InNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, Vec>> where Self: 'n; + type InNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, hashbrown::hash_map::Keys<'n, NodeIdx, Vec>> where Self: 'n; fn in_neighbors_mut(&mut self, index: NodeIdx) -> Self::InNeighborsMut<'_> { iters::NodesByIdxMut::new(self.adjacencies[index].incoming().keys(), &mut self.nodes) } @@ -343,7 +347,7 @@ impl Graph for MultiMapGraph { iters::NodesByIdx::new(self.adjacencies[index].outgoing().keys(), &self.nodes) } - type OutNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, Vec>> where Self: 'n; + type OutNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, hashbrown::hash_map::Keys<'n, NodeIdx, Vec>> where Self: 'n; fn out_neighbors_mut(&mut self, index: NodeIdx) -> Self::OutNeighborsMut<'_> { iters::NodesByIdxMut::new( self.adjacencies[index].outgoing_mut().keys(), diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index cc1d488e924a5..870d4a2672945 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -249,6 +249,10 @@ impl Graph for SimpleMapGraph self.nodes.values_mut() } + unsafe fn nodes_mut_raw(&mut self) -> &mut HopSlotMap { + &mut self.nodes + } + type EdgeIndices<'e> = slotmap::hop::Keys<'e, EdgeIdx, Edge> where Self: 'e; fn edge_indices(&self) -> Self::EdgeIndices<'_> { self.edges.keys() @@ -309,7 +313,7 @@ impl Graph for SimpleMapGraph iters::NodesByIdx::new(self.adjacencies[index].incoming().keys(), &self.nodes) } - type InNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + type InNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; fn in_neighbors_mut(&mut self, index: NodeIdx) -> Self::InNeighborsMut<'_> { iters::NodesByIdxMut::new(self.adjacencies[index].incoming().keys(), &mut self.nodes) } @@ -319,7 +323,7 @@ impl Graph for SimpleMapGraph iters::NodesByIdx::new(self.adjacencies[index].outgoing().keys(), &self.nodes) } - type OutNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; + type OutNeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>> where Self: 'n; fn out_neighbors_mut(&mut self, index: NodeIdx) -> Self::OutNeighborsMut<'_> { iters::NodesByIdxMut::new( self.adjacencies[index].outgoing_mut().keys(), diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 2e0381c92a788..72b46ce2ea31a 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -257,7 +257,7 @@ pub trait Graph { /// Returns an iterator over all `NodeIdx`s. fn node_indices(&self) -> Self::NodeIndices<'_>; - /// Returns a raw handle to the nodes slotmap. + /// Returns a immutable raw handle to the nodes slotmap. /// /// # Safety /// @@ -267,6 +267,13 @@ pub trait Graph { /// Returns an iterator over all nodes. fn nodes(&self) -> Self::Nodes<'_>; + /// Returns a mutable raw handle to the nodes slotmap. + /// + /// # Safety + /// + /// This function should only be called when you really know what you are doing. + unsafe fn nodes_mut_raw(&mut self) -> &mut HopSlotMap; + /// Returns a mutable iterator over all nodes. fn nodes_mut(&mut self) -> Self::NodesMut<'_>; diff --git a/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs b/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs index 8671512abfe4c..b8b3d971dcef2 100644 --- a/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs +++ b/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs @@ -1,22 +1,35 @@ +use std::borrow::Borrow; + use slotmap::HopSlotMap; -use crate::{graphs::keys::NodeIdx, utils::wrapped_iterator::WrappedIterator}; +use crate::{ + graphs::{keys::NodeIdx, Graph}, + utils::wrapped_iterator::WrappedIterator, +}; -/// An iterator which converts `&NodeIdx` to a `&'g mut N` of the graph -pub struct NodesByIdxMut<'g, N: 'g, I: Iterator> { +/// An iterator which converts `(&)NodeIdx` to a `&'g mut N` of the graph +pub struct NodesByIdxMut<'g, N: 'g, B: Borrow, I: Iterator> { nodes: &'g mut HopSlotMap, inner: I, } -impl<'g, N: 'g, I: Iterator> NodesByIdxMut<'g, N, I> { +impl<'g, N: 'g, B: Borrow, I: Iterator> NodesByIdxMut<'g, N, B, I> { + /// Creates a new `NodesByIdxMut` iterator over a graph with the provided `inner` iterator + pub fn from_graph(inner: I, graph: &'g mut impl Graph) -> Self { + Self { + nodes: unsafe { graph.nodes_mut_raw() }, + inner, + } + } + /// Creates a new `NodesByIdxMut` iterator over a graph with the provided `inner` iterator pub fn new(inner: I, nodes: &'g mut HopSlotMap) -> Self { Self { nodes, inner } } } -impl<'g, N: 'g, I: Iterator> WrappedIterator - for NodesByIdxMut<'g, N, I> +impl<'g, N: 'g, B: Borrow, I: Iterator> WrappedIterator + for NodesByIdxMut<'g, N, B, I> { #[inline] fn into_inner(self) -> I { @@ -24,7 +37,7 @@ impl<'g, N: 'g, I: Iterator> WrappedIterator> Iterator for NodesByIdxMut<'g, N, I> { +impl<'g, N: 'g, B: Borrow, I: Iterator> Iterator for NodesByIdxMut<'g, N, B, I> { type Item = &'g mut N; fn next(&mut self) -> Option { @@ -32,7 +45,7 @@ impl<'g, N: 'g, I: Iterator> Iterator for NodesByIdxMut<'g, // Unsafe necessary because Rust can't deduce that we won't // return multiple references to the same value. unsafe { - self.nodes.get_mut(*index).map(|node| { + self.nodes.get_mut(*index.borrow()).map(|node| { let ptr: *mut N = &mut *node; &mut *ptr }) From 222b73b5ddd34591f1b84098f21c96414c3f085c Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 23 Jan 2023 16:20:55 +0100 Subject: [PATCH 159/183] Add `from_graph` also for other `ByIdx(Mut)` iters --- crates/bevy_graph/src/graphs/list/multi.rs | 20 +++++++---- crates/bevy_graph/src/graphs/list/simple.rs | 20 +++++++---- crates/bevy_graph/src/graphs/map/multi.rs | 34 ++++++++++++------- crates/bevy_graph/src/graphs/map/simple.rs | 20 +++++++---- crates/bevy_graph/src/graphs/mod.rs | 14 ++++++++ crates/bevy_graph/src/iters/edges_by_idx.rs | 27 +++++++++++---- .../bevy_graph/src/iters/edges_by_idx_mut.rs | 25 ++++++++++---- 7 files changed, 115 insertions(+), 45 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 1f83504ccdf5c..2cf65f234f8ed 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -266,22 +266,30 @@ impl Graph for MultiListGraph self.edges.keys() } + unsafe fn edges_raw(&self) -> &HopSlotMap> { + &self.edges + } + type Edges<'e> = iters::EdgesRef<'e, E, slotmap::hop::Values<'e, EdgeIdx, Edge>> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { iters::EdgesRef::new(self.edges.values()) } + unsafe fn edges_mut_raw(&mut self) -> &mut HopSlotMap> { + &mut self.edges + } + type EdgesMut<'e> = iters::EdgesMut<'e, E, slotmap::hop::ValuesMut<'e, EdgeIdx, Edge>> where Self: 'e; fn edges_mut(&mut self) -> Self::EdgesMut<'_> { iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { todo!() } - type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { todo!() } @@ -296,7 +304,7 @@ impl Graph for MultiListGraph self.adjacencies[index].outgoing().len() } - type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Flatten>>> where Self: 'e; + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new( self.adjacencies[index].incoming().values().flatten(), @@ -304,7 +312,7 @@ impl Graph for MultiListGraph ) } - type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Flatten>>> where Self: 'e; + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new( self.adjacencies[index].incoming().values().flatten(), @@ -312,7 +320,7 @@ impl Graph for MultiListGraph ) } - type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Flatten>>> where Self: 'e; + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new( self.adjacencies[index].outgoing().values().flatten(), @@ -320,7 +328,7 @@ impl Graph for MultiListGraph ) } - type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Flatten>>> where Self: 'e; + type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new( self.adjacencies[index].outgoing().values().flatten(), diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 205c275002a46..919ac5edc3743 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -261,22 +261,30 @@ impl Graph for SimpleListGraph self.edges.keys() } + unsafe fn edges_raw(&self) -> &HopSlotMap> { + &self.edges + } + type Edges<'e> = iters::EdgesRef<'e, E, slotmap::hop::Values<'e, EdgeIdx, Edge>> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { iters::EdgesRef::new(self.edges.values()) } + unsafe fn edges_mut_raw(&mut self) -> &mut HopSlotMap> { + &mut self.edges + } + type EdgesMut<'e> = iters::EdgesMut<'e, E, slotmap::hop::ValuesMut<'e, EdgeIdx, Edge>> where Self: 'e; fn edges_mut(&mut self) -> Self::EdgesMut<'_> { iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { todo!() } - type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { todo!() } @@ -291,22 +299,22 @@ impl Graph for SimpleListGraph self.adjacencies[index].outgoing().len() } - type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].incoming().values(), &self.edges) } - type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new(self.adjacencies[index].incoming().values(), &mut self.edges) } - type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values(), &self.edges) } - type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new(self.adjacencies[index].outgoing().values(), &mut self.edges) } diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index c54657bf8a0d6..a58ac37c7ede1 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -270,34 +270,34 @@ impl Graph for MultiMapGraph { self.edges.keys() } + unsafe fn edges_raw(&self) -> &HopSlotMap> { + &self.edges + } + type Edges<'e> = iters::EdgesRef<'e, E, slotmap::hop::Values<'e, EdgeIdx, Edge>> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { iters::EdgesRef::new(self.edges.values()) } + unsafe fn edges_mut_raw(&mut self) -> &mut HopSlotMap> { + &mut self.edges + } + type EdgesMut<'e> = iters::EdgesMut<'e, E, slotmap::hop::ValuesMut<'e, EdgeIdx, Edge>> where Self: 'e; fn edges_mut(&mut self) -> Self::EdgesMut<'_> { iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { todo!() } - type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { todo!() } - type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Flatten>>> where Self: 'e; - fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { - iters::EdgesByIdx::new( - self.adjacencies[index].incoming().values().flatten(), - &self.edges, - ) - } - #[inline] fn in_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].incoming().len() @@ -308,7 +308,15 @@ impl Graph for MultiMapGraph { self.adjacencies[index].outgoing().len() } - type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Flatten>>> where Self: 'e; + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Flatten>>> where Self: 'e; + fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { + iters::EdgesByIdx::new( + self.adjacencies[index].incoming().values().flatten(), + &self.edges, + ) + } + + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Flatten>>> where Self: 'e; fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new( self.adjacencies[index].incoming().values().flatten(), @@ -316,7 +324,7 @@ impl Graph for MultiMapGraph { ) } - type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Flatten>>> where Self: 'e; + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new( self.adjacencies[index].outgoing().values().flatten(), @@ -324,7 +332,7 @@ impl Graph for MultiMapGraph { ) } - type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Flatten>>> where Self: 'e; + type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Flatten>>> where Self: 'e; fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new( self.adjacencies[index].outgoing().values().flatten(), diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 870d4a2672945..a9321625228c1 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -258,22 +258,30 @@ impl Graph for SimpleMapGraph self.edges.keys() } + unsafe fn edges_raw(&self) -> &HopSlotMap> { + &self.edges + } + type Edges<'e> = iters::EdgesRef<'e, E, slotmap::hop::Values<'e, EdgeIdx, Edge>> where Self: 'e; fn edges(&self) -> Self::Edges<'_> { iters::EdgesRef::new(self.edges.values()) } + unsafe fn edges_mut_raw(&mut self) -> &mut HopSlotMap> { + &mut self.edges + } + type EdgesMut<'e> = iters::EdgesMut<'e, E, slotmap::hop::ValuesMut<'e, EdgeIdx, Edge>> where Self: 'e; fn edges_mut(&mut self) -> Self::EdgesMut<'_> { iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = iters::EdgesByIdx<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { todo!() } - type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { todo!() } @@ -288,22 +296,22 @@ impl Graph for SimpleMapGraph self.adjacencies[index].outgoing().len() } - type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].incoming().values(), &self.edges) } - type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type IncomingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn incoming_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new(self.adjacencies[index].incoming().values(), &mut self.edges) } - type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type OutgoingEdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of(&self, index: NodeIdx) -> Self::IncomingEdgesOf<'_> { iters::EdgesByIdx::new(self.adjacencies[index].outgoing().values(), &self.edges) } - type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; + type OutgoingEdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>> where Self: 'e; fn outgoing_edges_of_mut(&mut self, index: NodeIdx) -> Self::IncomingEdgesOfMut<'_> { iters::EdgesByIdxMut::new(self.adjacencies[index].outgoing().values(), &mut self.edges) } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 72b46ce2ea31a..8960d7c748995 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -280,9 +280,23 @@ pub trait Graph { /// Returns an iterator over all `EdgeIdx`s. fn edge_indices(&self) -> Self::EdgeIndices<'_>; + /// Returns a immutable raw handle to the edges slotmap. + /// + /// # Safety + /// + /// This function should only be called when you really know what you are doing. + unsafe fn edges_raw(&self) -> &HopSlotMap>; + /// Returns an iterator over all edges. fn edges(&self) -> Self::Edges<'_>; + /// Returns a mutable raw handle to the edges slotmap. + /// + /// # Safety + /// + /// This function should only be called when you really know what you are doing. + unsafe fn edges_mut_raw(&mut self) -> &mut HopSlotMap>; + /// Returns a mutable iterator over all edges. fn edges_mut(&mut self) -> Self::EdgesMut<'_>; diff --git a/crates/bevy_graph/src/iters/edges_by_idx.rs b/crates/bevy_graph/src/iters/edges_by_idx.rs index d734aa91fe49d..0685af08e1022 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx.rs @@ -1,28 +1,39 @@ +use std::borrow::Borrow; + use slotmap::HopSlotMap; use crate::{ graphs::{ edge::{Edge, EdgeRef}, keys::EdgeIdx, + Graph, }, utils::wrapped_iterator::WrappedIterator, }; -/// An iterator which converts `&EdgeIdx` to a `EdgeRef` of the graph -pub struct EdgesByIdx<'g, E: 'g, I: Iterator> { +/// An iterator which converts `(&)EdgeIdx` to a `EdgeRef` of the graph +pub struct EdgesByIdx<'g, E: 'g, B: Borrow, I: Iterator> { edges: &'g HopSlotMap>, inner: I, } -impl<'g, E: 'g, I: Iterator> EdgesByIdx<'g, E, I> { +impl<'g, E: 'g, B: Borrow, I: Iterator> EdgesByIdx<'g, E, B, I> { + /// Creates a new `EdgesByIdx` iterator over a graph with the provided `inner` iterator + pub fn from_graph(inner: I, graph: &'g mut impl Graph) -> Self { + Self { + edges: unsafe { graph.edges_raw() }, + inner, + } + } + /// Creates a new `EdgesByIdx` iterator over a graph with the provided `inner` iterator pub fn new(inner: I, edges: &'g HopSlotMap>) -> Self { Self { edges, inner } } } -impl<'g, E: 'g, I: Iterator> WrappedIterator, I> - for EdgesByIdx<'g, E, I> +impl<'g, E: 'g, B: Borrow, I: Iterator> WrappedIterator, I> + for EdgesByIdx<'g, E, B, I> { #[inline] fn into_inner(self) -> I { @@ -30,12 +41,14 @@ impl<'g, E: 'g, I: Iterator> WrappedIterator> Iterator for EdgesByIdx<'g, E, I> { +impl<'g, E: 'g, B: Borrow, I: Iterator> Iterator for EdgesByIdx<'g, E, B, I> { type Item = EdgeRef<'g, E>; fn next(&mut self) -> Option { if let Some(index) = self.inner.next() { - self.edges.get(*index).map(|edge| edge.as_ref_edge()) + self.edges + .get(*index.borrow()) + .map(|edge| edge.as_ref_edge()) } else { None } diff --git a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs index 17b90c44124ea..bab2dd7d242ea 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs @@ -1,28 +1,39 @@ +use std::borrow::Borrow; + use slotmap::HopSlotMap; use crate::{ graphs::{ edge::{Edge, EdgeMut}, keys::EdgeIdx, + Graph, }, utils::wrapped_iterator::WrappedIterator, }; -/// An iterator which converts `&EdgeIdx` to a `EdgeMut` of the graph -pub struct EdgesByIdxMut<'g, E: 'g, I: Iterator> { +/// An iterator which converts `(&)EdgeIdx` to a `EdgeMut` of the graph +pub struct EdgesByIdxMut<'g, E: 'g, B: Borrow, I: Iterator> { edges: &'g mut HopSlotMap>, inner: I, } -impl<'g, E: 'g, I: Iterator> EdgesByIdxMut<'g, E, I> { +impl<'g, E: 'g, B: Borrow, I: Iterator> EdgesByIdxMut<'g, E, B, I> { + /// Creates a new `EdgesByIdxMut` iterator over a graph with the provided `inner` iterator + pub fn from_graph(inner: I, graph: &'g mut impl Graph) -> Self { + Self { + edges: unsafe { graph.edges_mut_raw() }, + inner, + } + } + /// Creates a new `EdgesByIdxMut` iterator over a graph with the provided `inner` iterator pub fn new(inner: I, edges: &'g mut HopSlotMap>) -> Self { Self { edges, inner } } } -impl<'g, E: 'g, I: Iterator> WrappedIterator, I> - for EdgesByIdxMut<'g, E, I> +impl<'g, E: 'g, B: Borrow, I: Iterator> WrappedIterator, I> + for EdgesByIdxMut<'g, E, B, I> { #[inline] fn into_inner(self) -> I { @@ -30,7 +41,7 @@ impl<'g, E: 'g, I: Iterator> WrappedIterator> Iterator for EdgesByIdxMut<'g, E, I> { +impl<'g, E: 'g, B: Borrow, I: Iterator> Iterator for EdgesByIdxMut<'g, E, B, I> { type Item = EdgeMut<'g, E>; fn next(&mut self) -> Option { @@ -38,7 +49,7 @@ impl<'g, E: 'g, I: Iterator> Iterator for EdgesByIdxMut<'g, // Unsafe necessary because Rust can't deduce that we won't // return multiple references to the same value. unsafe { - self.edges.get_mut(*index).map(|edge| { + self.edges.get_mut(*index.borrow()).map(|edge| { let ptr: *mut E = &mut edge.2; EdgeMut(edge.0, edge.1, &mut *ptr) }) From ee88d17a95613f3bf9f831337d5cf8549c3a045c Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 23 Jan 2023 18:46:06 +0100 Subject: [PATCH 160/183] Work on customizing algos --- crates/bevy_graph/src/algos/bfs.rs | 32 ++++++++++++++++++++++-------- crates/bevy_graph/src/algos/dfs.rs | 30 ++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 38cc48a5b24f4..9ba6281552e55 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -11,16 +11,19 @@ use crate::{ /// /// when `d` is the distance between a node and the startnode, /// it will evaluate every node with `d=1`, then continue with `d=2` and so on. -pub struct BreadthFirstSearch<'g, N, E, G: Graph> { +pub struct BreadthFirstSearch<'g, N, E: 'g, G: Graph, I: Iterator>> { graph: &'g G, queue: VecDeque, visited: HashSet, + visitor: fn(&'g G, NodeIdx) -> I, phantom: PhantomData<(N, E)>, } -impl<'g, N, E, G: Graph> BreadthFirstSearch<'g, N, E, G> { - /// Creates a new `BreadthFirstSearch` with a start node - pub fn new(graph: &'g G, start: NodeIdx) -> Self { +impl<'g, N, E: 'g, G: Graph, I: Iterator>> + BreadthFirstSearch<'g, N, E, G, I> +{ + /// Creates a new `BreadthFirstSearch` with a start node and a custom visitor + pub fn custom(graph: &'g G, start: NodeIdx, visitor: fn(&'g G, NodeIdx) -> I) -> Self { let node_count = graph.node_count(); let mut queue = VecDeque::with_capacity(node_count); let mut visited = HashSet::with_capacity(node_count); @@ -32,17 +35,28 @@ impl<'g, N, E, G: Graph> BreadthFirstSearch<'g, N, E, G> { graph, queue, visited, + visitor, phantom: PhantomData, } } +} + +impl<'g, N, E: 'g, G: Graph> BreadthFirstSearch<'g, N, E, G, G::OutgoingEdgesOf<'g>> { + /// Creates a new `BreadthFirstSearch` with a start node and the default visitor of `outgoing` + #[inline] + pub fn new(graph: &'g G, start: NodeIdx) -> Self { + Self::custom(graph, start, |graph, index| graph.outgoing_edges_of(index)) + } - /// Creates a new `BreadthFirstSearch` wrapped inside an `NodesByIdx` iterator + /// Creates a new `BreadthFirstSearch` with a start node and the default visitor of `outgoing` wrapped inside an `NodesByIdx` iterator + #[inline] pub fn new_ref(graph: &'g G, start: NodeIdx) -> iters::NodesByIdx<'g, N, NodeIdx, Self> { let inner = Self::new(graph, start); iters::NodesByIdx::from_graph(inner, graph) } - /// Creates a new `BreadthFirstSearch` wrapped inside an `NodesByIdxMut` iterator + /// Creates a new `BreadthFirstSearch` with a start node and the default visitor of `outgoing` wrapped inside an `NodesByIdxMut` iterator + #[inline] pub fn new_mut(graph: &'g mut G, start: NodeIdx) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { unsafe { // SAFETY: We know `NodesByIdxMut` doesn't intercept (deletes nodes) at all. @@ -54,12 +68,14 @@ impl<'g, N, E, G: Graph> BreadthFirstSearch<'g, N, E, G> { } } -impl<'g, N, E, G: Graph> Iterator for BreadthFirstSearch<'g, N, E, G> { +impl<'g, N, E: 'g, G: Graph, I: Iterator>> Iterator + for BreadthFirstSearch<'g, N, E, G, I> +{ type Item = NodeIdx; fn next(&mut self) -> Option { if let Some(node) = self.queue.pop_front() { - for EdgeRef(_, dst, _) in self.graph.outgoing_edges_of(node) { + for EdgeRef(_, dst, _) in (self.visitor)(self.graph, node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.queue.push_back(dst); diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 10803b8542c95..696fd1a74d584 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -10,16 +10,19 @@ use crate::{ /// Implementation of the [`DFS` algorithm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) /// /// it will evaluate every node from the start as deep as it can and then continue at the next sibling node from the top. -pub struct DepthFirstSearch<'g, N, E, G: Graph> { +pub struct DepthFirstSearch<'g, N, E: 'g, G: Graph, I: Iterator>> { graph: &'g G, stack: Vec, visited: HashSet, + visitor: fn(&'g G, NodeIdx) -> I, phantom: PhantomData<(N, E)>, } -impl<'g, N, E, G: Graph> DepthFirstSearch<'g, N, E, G> { - /// Creates a new `DepthFirstSearch` with a start node - pub fn new(graph: &'g G, start: NodeIdx) -> Self { +impl<'g, N, E: 'g, G: Graph, I: Iterator>> + DepthFirstSearch<'g, N, E, G, I> +{ + /// Creates a new `DepthFirstSearch` with a start node and a custom visitor + pub fn custom(graph: &'g G, start: NodeIdx, visitor: fn(&'g G, NodeIdx) -> I) -> Self { let node_count = graph.node_count(); let mut stack = Vec::with_capacity(node_count); let mut visited = HashSet::with_capacity(node_count); @@ -31,17 +34,26 @@ impl<'g, N, E, G: Graph> DepthFirstSearch<'g, N, E, G> { graph, stack, visited, + visitor, phantom: PhantomData, } } +} + +impl<'g, N, E: 'g, G: Graph> DepthFirstSearch<'g, N, E, G, G::OutgoingEdgesOf<'g>> { + /// Creates a new `DepthFirstSearch` with a start node and the default visitor of `outgoing` + #[inline] + pub fn new(graph: &'g G, start: NodeIdx) -> Self { + Self::custom(graph, start, |graph, index| graph.outgoing_edges_of(index)) + } - /// Creates a new `DepthFirstSearch` wrapped inside an `NodesByIdx` iterator + /// Creates a new `DepthFirstSearch` with a start node and the default visitor of `outgoing` wrapped inside an `NodesByIdx` iterator pub fn new_ref(graph: &'g G, start: NodeIdx) -> iters::NodesByIdx<'g, N, NodeIdx, Self> { let inner = Self::new(graph, start); iters::NodesByIdx::from_graph(inner, graph) } - /// Creates a new `BreadthFirstSearch` wrapped inside an `NodesByIdxMut` iterator + /// Creates a new `DepthFirstSearch` with a start node and the default visitor of `outgoing` wrapped inside an `NodesByIdxMut` iterator pub fn new_mut(graph: &'g mut G, start: NodeIdx) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { unsafe { // SAFETY: We know `NodesByIdxMut` doesn't intercept (deletes nodes) at all. @@ -53,12 +65,14 @@ impl<'g, N, E, G: Graph> DepthFirstSearch<'g, N, E, G> { } } -impl<'g, N, E, G: Graph> Iterator for DepthFirstSearch<'g, N, E, G> { +impl<'g, N, E: 'g, G: Graph, I: Iterator>> Iterator + for DepthFirstSearch<'g, N, E, G, I> +{ type Item = NodeIdx; fn next(&mut self) -> Option { if let Some(node) = self.stack.pop() { - for EdgeRef(_, dst, _) in self.graph.outgoing_edges_of(node) { + for EdgeRef(_, dst, _) in (self.visitor)(self.graph, node) { if !self.visited.contains(&dst) { self.visited.insert(dst); self.stack.push(dst); From 14a98e83cab80ade70ae0a28dd426c045122719c Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 23 Jan 2023 19:00:01 +0100 Subject: [PATCH 161/183] Add `custom_ref` and `custom_mut` for algos --- crates/bevy_graph/src/algos/bfs.rs | 27 +++++++++++++++++++++++++++ crates/bevy_graph/src/algos/dfs.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 9ba6281552e55..1235b9fd1a7e9 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -39,6 +39,33 @@ impl<'g, N, E: 'g, G: Graph, I: Iterator>> phantom: PhantomData, } } + + /// Creates a new `BreadthFirstSearch` with a start node and a custom visitor wrapped inside an `NodesByIdx` iterator + #[inline] + pub fn custom_ref( + graph: &'g G, + start: NodeIdx, + visitor: fn(&'g G, NodeIdx) -> I, + ) -> iters::NodesByIdx<'g, N, NodeIdx, Self> { + let inner = Self::custom(graph, start, visitor); + iters::NodesByIdx::from_graph(inner, graph) + } + + /// Creates a new `BreadthFirstSearch` with a start node and a custom visitor wrapped inside an `NodesByIdxMut` iterator + #[inline] + pub fn custom_mut( + graph: &'g mut G, + start: NodeIdx, + visitor: fn(&'g G, NodeIdx) -> I, + ) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { + unsafe { + // SAFETY: We know `NodesByIdxMut` doesn't intercept (deletes nodes) at all. + let ptr: *mut G = &mut *graph; + let inner = Self::custom(&*ptr, start, visitor); + + iters::NodesByIdxMut::from_graph(inner, graph) + } + } } impl<'g, N, E: 'g, G: Graph> BreadthFirstSearch<'g, N, E, G, G::OutgoingEdgesOf<'g>> { diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index 696fd1a74d584..a8cd0a44b22ba 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -38,6 +38,33 @@ impl<'g, N, E: 'g, G: Graph, I: Iterator>> phantom: PhantomData, } } + + /// Creates a new `DepthFirstSearch` with a start node and a custom visitor wrapped inside an `NodesByIdx` iterator + #[inline] + pub fn custom_ref( + graph: &'g G, + start: NodeIdx, + visitor: fn(&'g G, NodeIdx) -> I, + ) -> iters::NodesByIdx<'g, N, NodeIdx, Self> { + let inner = Self::custom(graph, start, visitor); + iters::NodesByIdx::from_graph(inner, graph) + } + + /// Creates a new `DepthFirstSearch` with a start node and a custom visitor wrapped inside an `NodesByIdxMut` iterator + #[inline] + pub fn custom_mut( + graph: &'g mut G, + start: NodeIdx, + visitor: fn(&'g G, NodeIdx) -> I, + ) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { + unsafe { + // SAFETY: We know `NodesByIdxMut` doesn't intercept (deletes nodes) at all. + let ptr: *mut G = &mut *graph; + let inner = Self::custom(&*ptr, start, visitor); + + iters::NodesByIdxMut::from_graph(inner, graph) + } + } } impl<'g, N, E: 'g, G: Graph> DepthFirstSearch<'g, N, E, G, G::OutgoingEdgesOf<'g>> { From 4bc80f29da2dbb91cb83041bbd3b97985bd654ea Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 23 Jan 2023 19:01:44 +0100 Subject: [PATCH 162/183] Add `ancestors(_mut)` and `descendants(_mut)` --- crates/bevy_graph/src/graphs/list/multi.rs | 25 ++++++++++++++++ crates/bevy_graph/src/graphs/list/simple.rs | 25 ++++++++++++++++ crates/bevy_graph/src/graphs/map/multi.rs | 25 ++++++++++++++++ crates/bevy_graph/src/graphs/map/simple.rs | 25 ++++++++++++++++ crates/bevy_graph/src/graphs/mod.rs | 33 +++++++++++++++++++++ 5 files changed, 133 insertions(+) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 2cf65f234f8ed..72d37b05021ae 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -1,6 +1,7 @@ use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ + algos::dfs::DepthFirstSearch, error::GraphError, graphs::{ adjacency_storage::AdjacencyStorage, @@ -438,4 +439,28 @@ impl DirectedGraph for MultiListGraph { .push(index); } } + + type Ancestors<'n> = iters::NodesByIdx<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::IncomingEdgesOf<'n>>> where Self: 'n; + fn ancestors(&self, index: NodeIdx) -> Self::Ancestors<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_ref(self, index, |graph, node| graph.incoming_edges_of(node)) + } + + type AncestorsMut<'n> = iters::NodesByIdxMut<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::IncomingEdgesOf<'n>>> where Self: 'n; + fn ancestors_mut(&mut self, index: NodeIdx) -> Self::AncestorsMut<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_mut(self, index, |graph, node| graph.incoming_edges_of(node)) + } + + type Descendants<'n> = iters::NodesByIdx<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::OutgoingEdgesOf<'n>>> where Self: 'n; + fn descendants(&self, index: NodeIdx) -> Self::Descendants<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_ref(self, index, |graph, node| graph.outgoing_edges_of(node)) + } + + type DescendantsMut<'n> = iters::NodesByIdxMut<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::OutgoingEdgesOf<'n>>> where Self: 'n; + fn descendants_mut(&mut self, index: NodeIdx) -> Self::DescendantsMut<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_mut(self, index, |graph, node| graph.outgoing_edges_of(node)) + } } diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 919ac5edc3743..c64df7ba63491 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -1,6 +1,7 @@ use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ + algos::dfs::DepthFirstSearch, error::GraphError, graphs::{ adjacency_storage::AdjacencyStorage, @@ -397,4 +398,28 @@ impl DirectedGraph for SimpleListGraph { self.adjacencies[*src].incoming_mut().push((*dst, index)); } } + + type Ancestors<'n> = iters::NodesByIdx<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::IncomingEdgesOf<'n>>> where Self: 'n; + fn ancestors(&self, index: NodeIdx) -> Self::Ancestors<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_ref(self, index, |graph, node| graph.incoming_edges_of(node)) + } + + type AncestorsMut<'n> = iters::NodesByIdxMut<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::IncomingEdgesOf<'n>>> where Self: 'n; + fn ancestors_mut(&mut self, index: NodeIdx) -> Self::AncestorsMut<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_mut(self, index, |graph, node| graph.incoming_edges_of(node)) + } + + type Descendants<'n> = iters::NodesByIdx<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::OutgoingEdgesOf<'n>>> where Self: 'n; + fn descendants(&self, index: NodeIdx) -> Self::Descendants<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_ref(self, index, |graph, node| graph.outgoing_edges_of(node)) + } + + type DescendantsMut<'n> = iters::NodesByIdxMut<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::OutgoingEdgesOf<'n>>> where Self: 'n; + fn descendants_mut(&mut self, index: NodeIdx) -> Self::DescendantsMut<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_mut(self, index, |graph, node| graph.outgoing_edges_of(node)) + } } diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index a58ac37c7ede1..2407b1f375cd3 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -2,6 +2,7 @@ use hashbrown::HashMap; use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ + algos::dfs::DepthFirstSearch, error::GraphError, graphs::{ adjacency_storage::AdjacencyStorage, @@ -442,4 +443,28 @@ impl DirectedGraph for MultiMapGraph { .push(index); } } + + type Ancestors<'n> = iters::NodesByIdx<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::IncomingEdgesOf<'n>>> where Self: 'n; + fn ancestors(&self, index: NodeIdx) -> Self::Ancestors<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_ref(self, index, |graph, node| graph.incoming_edges_of(node)) + } + + type AncestorsMut<'n> = iters::NodesByIdxMut<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::IncomingEdgesOf<'n>>> where Self: 'n; + fn ancestors_mut(&mut self, index: NodeIdx) -> Self::AncestorsMut<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_mut(self, index, |graph, node| graph.incoming_edges_of(node)) + } + + type Descendants<'n> = iters::NodesByIdx<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::OutgoingEdgesOf<'n>>> where Self: 'n; + fn descendants(&self, index: NodeIdx) -> Self::Descendants<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_ref(self, index, |graph, node| graph.outgoing_edges_of(node)) + } + + type DescendantsMut<'n> = iters::NodesByIdxMut<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::OutgoingEdgesOf<'n>>> where Self: 'n; + fn descendants_mut(&mut self, index: NodeIdx) -> Self::DescendantsMut<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_mut(self, index, |graph, node| graph.outgoing_edges_of(node)) + } } diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index a9321625228c1..7728d2772de40 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -2,6 +2,7 @@ use hashbrown::HashMap; use slotmap::{HopSlotMap, SecondaryMap}; use crate::{ + algos::dfs::DepthFirstSearch, error::GraphError, graphs::{ adjacency_storage::AdjacencyStorage, @@ -394,4 +395,28 @@ impl DirectedGraph for SimpleMapGraph { self.adjacencies[*src].incoming_mut().insert(*dst, index); } } + + type Ancestors<'n> = iters::NodesByIdx<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::IncomingEdgesOf<'n>>> where Self: 'n; + fn ancestors(&self, index: NodeIdx) -> Self::Ancestors<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_ref(self, index, |graph, node| graph.incoming_edges_of(node)) + } + + type AncestorsMut<'n> = iters::NodesByIdxMut<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::IncomingEdgesOf<'n>>> where Self: 'n; + fn ancestors_mut(&mut self, index: NodeIdx) -> Self::AncestorsMut<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_mut(self, index, |graph, node| graph.incoming_edges_of(node)) + } + + type Descendants<'n> = iters::NodesByIdx<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::OutgoingEdgesOf<'n>>> where Self: 'n; + fn descendants(&self, index: NodeIdx) -> Self::Descendants<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_ref(self, index, |graph, node| graph.outgoing_edges_of(node)) + } + + type DescendantsMut<'n> = iters::NodesByIdxMut<'n, N, NodeIdx, DepthFirstSearch<'n, N, E, Self, Self::OutgoingEdgesOf<'n>>> where Self: 'n; + fn descendants_mut(&mut self, index: NodeIdx) -> Self::DescendantsMut<'_> { + // use DFS here, Vec should be faster than VecDeque + DepthFirstSearch::custom_mut(self, index, |graph, node| graph.outgoing_edges_of(node)) + } } diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 8960d7c748995..f4a9d2089f584 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -364,9 +364,42 @@ pub trait SimpleGraph: Graph { /// A more precise trait with functions special for directed graphs pub trait DirectedGraph: Graph { + /// Iterator fix because TAIT not available + type Ancestors<'n>: Iterator + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available + type AncestorsMut<'n>: Iterator + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available + type Descendants<'n>: Iterator + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available + type DescendantsMut<'n>: Iterator + where + Self: 'n, + N: 'n; + /// Reverse the direction of all edges in the graph. fn reverse(&mut self); /// Reverse the direction of the specified edge. fn reverse_edge(&mut self, index: EdgeIdx); + + /// Returns an iterator that visits all nodes that can reach the specified node. + fn ancestors(&self, index: NodeIdx) -> Self::Ancestors<'_>; + + /// Returns a mutable iterator that visits all nodes that can reach the specifed node. + fn ancestors_mut(&mut self, index: NodeIdx) -> Self::AncestorsMut<'_>; + + /// Returns iterator that visits all nodes that are reachable from the specified node. + fn descendants(&self, index: NodeIdx) -> Self::Descendants<'_>; + + /// Returns a mutable iterator that visits all nodes that are reachable from the specified node. + fn descendants_mut(&mut self, index: NodeIdx) -> Self::DescendantsMut<'_>; } From 05f639a033a51ff79068c6b150798dabafd7eb99 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 23 Jan 2023 21:06:12 +0100 Subject: [PATCH 163/183] Add `edges_of(_mut)` for simple graphs --- crates/bevy_graph/src/graphs/list/simple.rs | 38 ++++++++++++++++----- crates/bevy_graph/src/graphs/map/simple.rs | 38 ++++++++++++++++----- crates/bevy_graph/src/utils/iter_choice.rs | 33 ++++++++++++++++++ crates/bevy_graph/src/utils/mod.rs | 2 ++ 4 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 crates/bevy_graph/src/utils/iter_choice.rs diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index c64df7ba63491..ee99ddf4dd56b 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -10,7 +10,7 @@ use crate::{ DirectedGraph, Graph, }, iters, - utils::{vecmap::VecMap, wrapped_iterator::WrappedIterator}, + utils::{iter_choice::IterChoice, vecmap::VecMap, wrapped_iterator::WrappedIterator}, }; type SimpleListStorage = Vec<(NodeIdx, EdgeIdx)>; @@ -280,14 +280,34 @@ impl Graph for SimpleListGraph iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; - fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { - todo!() - } - - type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; - fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { - todo!() + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Chain, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>>, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>>> where Self: 'e; + fn edges_of(&self, index: NodeIdx) -> Self::EdgesOf<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .values() + .chain(self.adjacencies[index].outgoing().values()), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().values()) + }; + iters::EdgesByIdx::new(inner, &self.edges) + } + + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Chain, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>>, crate::utils::vecmap::Values<'e, NodeIdx, EdgeIdx>>> where Self: 'e; + fn edges_of_mut(&mut self, index: NodeIdx) -> Self::EdgesOfMut<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .values() + .chain(self.adjacencies[index].outgoing().values()), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().values()) + }; + iters::EdgesByIdxMut::new(inner, &mut self.edges) } #[inline] diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 7728d2772de40..5e22337c3b374 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -11,7 +11,7 @@ use crate::{ DirectedGraph, Graph, }, iters, - utils::wrapped_iterator::WrappedIterator, + utils::{iter_choice::IterChoice, wrapped_iterator::WrappedIterator}, }; type SimpleMapStorage = HashMap; @@ -277,14 +277,34 @@ impl Graph for SimpleMapGraph iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; - fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { - todo!() - } - - type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; - fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { - todo!() + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Chain, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>>, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>>> where Self: 'e; + fn edges_of(&self, index: NodeIdx) -> Self::EdgesOf<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .values() + .chain(self.adjacencies[index].outgoing().values()), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().values()) + }; + iters::EdgesByIdx::new(inner, &self.edges) + } + + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Chain, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>>, hashbrown::hash_map::Values<'e, NodeIdx, EdgeIdx>>> where Self: 'e; + fn edges_of_mut(&mut self, index: NodeIdx) -> Self::EdgesOfMut<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .values() + .chain(self.adjacencies[index].outgoing().values()), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().values()) + }; + iters::EdgesByIdxMut::new(inner, &mut self.edges) } #[inline] diff --git a/crates/bevy_graph/src/utils/iter_choice.rs b/crates/bevy_graph/src/utils/iter_choice.rs new file mode 100644 index 0000000000000..7a8c94ef0aad4 --- /dev/null +++ b/crates/bevy_graph/src/utils/iter_choice.rs @@ -0,0 +1,33 @@ +/// Iterator type holding chosen iterator +pub enum IterChoice, J: Iterator> { + /// The first iter possibility + First(I), + /// The second iter possibility + Second(J), +} + +impl, J: Iterator> IterChoice { + /// Returns an [`IterChoice`] with the first possibility + #[inline] + pub fn new_first(iter: I) -> Self { + Self::First(iter) + } + + /// Returns an [`IterChoice`] with the second possibility + #[inline] + pub fn new_second(iter: J) -> Self { + Self::Second(iter) + } +} + +impl, J: Iterator> Iterator for IterChoice { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + match self { + IterChoice::First(iter) => iter.next(), + IterChoice::Second(iter) => iter.next(), + } + } +} diff --git a/crates/bevy_graph/src/utils/mod.rs b/crates/bevy_graph/src/utils/mod.rs index 92b7509b9bab5..5b8aefada9517 100644 --- a/crates/bevy_graph/src/utils/mod.rs +++ b/crates/bevy_graph/src/utils/mod.rs @@ -1,3 +1,5 @@ +/// Iterator type holding chosen iterator +pub mod iter_choice; /// Map-like methods for `Vec<(K, V)>` pub mod vecmap; /// Set-like methods for `Vec` From cd2c6939a60b629333b1d072eab35a9d1872fdb3 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Mon, 23 Jan 2023 21:31:15 +0100 Subject: [PATCH 164/183] Hopefully working `edges_of(_mut)` for multi graph --- crates/bevy_graph/src/graphs/list/multi.rs | 46 ++++++++++++--- crates/bevy_graph/src/graphs/map/multi.rs | 44 ++++++++++++--- .../bevy_graph/src/iters/loop_safety_iter.rs | 56 +++++++++++++++++++ crates/bevy_graph/src/iters/mod.rs | 3 + 4 files changed, 131 insertions(+), 18 deletions(-) create mode 100644 crates/bevy_graph/src/iters/loop_safety_iter.rs diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 72d37b05021ae..f302c75938132 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -10,7 +10,9 @@ use crate::{ DirectedGraph, Graph, }, iters, - utils::{vecmap::VecMap, vecset::VecSet, wrapped_iterator::WrappedIterator}, + utils::{ + iter_choice::IterChoice, vecmap::VecMap, vecset::VecSet, wrapped_iterator::WrappedIterator, + }, }; type MultiListStorage = Vec<(NodeIdx, Vec)>; @@ -285,14 +287,40 @@ impl Graph for MultiListGraph iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; - fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { - todo!() - } - - type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; - fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { - todo!() + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, iters::LoopSafetyIter<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Flatten>, crate::utils::vecmap::Values<'e, NodeIdx, Vec>>>, std::iter::Flatten>>>>> where Self: 'e; + fn edges_of(&self, index: NodeIdx) -> Self::EdgesOf<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .values() + .chain(self.adjacencies[index].outgoing().values()) + .flatten(), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().values().flatten()) + }; + iters::EdgesByIdx::new(iters::LoopSafetyIter::new(inner, &self.edges), &self.edges) + } + + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, iters::LoopSafetyIter<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Flatten>, crate::utils::vecmap::Values<'e, NodeIdx, Vec>>>, std::iter::Flatten>>>>> where Self: 'e; + fn edges_of_mut(&mut self, index: NodeIdx) -> Self::EdgesOfMut<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .values() + .chain(self.adjacencies[index].outgoing().values()) + .flatten(), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().values().flatten()) + }; + unsafe { + // SAFETY: EdgesByIdxMut should'nt be able to do any bad stuff for LoopSafetyIter + let ptr: *mut HopSlotMap> = &mut self.edges; + iters::EdgesByIdxMut::new(iters::LoopSafetyIter::new(inner, &*ptr), &mut self.edges) + } } #[inline] diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 2407b1f375cd3..5b6244c183bdb 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -11,7 +11,7 @@ use crate::{ DirectedGraph, Graph, }, iters, - utils::{vecset::VecSet, wrapped_iterator::WrappedIterator}, + utils::{iter_choice::IterChoice, vecset::VecSet, wrapped_iterator::WrappedIterator}, }; type MultiMapStorage = HashMap>; @@ -289,14 +289,40 @@ impl Graph for MultiMapGraph { iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; - fn edges_of(&self, _index: NodeIdx) -> Self::EdgesOf<'_> { - todo!() - } - - type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Empty<&'e EdgeIdx>> where Self: 'e; - fn edges_of_mut(&mut self, _index: NodeIdx) -> Self::EdgesOfMut<'_> { - todo!() + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, iters::LoopSafetyIter<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Flatten>, hashbrown::hash_map::Values<'e, NodeIdx, Vec>>>, std::iter::Flatten>>>>> where Self: 'e; + fn edges_of(&self, index: NodeIdx) -> Self::EdgesOf<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .values() + .chain(self.adjacencies[index].outgoing().values()) + .flatten(), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().values().flatten()) + }; + iters::EdgesByIdx::new(iters::LoopSafetyIter::new(inner, &self.edges), &self.edges) + } + + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, iters::LoopSafetyIter<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Flatten>, hashbrown::hash_map::Values<'e, NodeIdx, Vec>>>, std::iter::Flatten>>>>> where Self: 'e; + fn edges_of_mut(&mut self, index: NodeIdx) -> Self::EdgesOfMut<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .values() + .chain(self.adjacencies[index].outgoing().values()) + .flatten(), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().values().flatten()) + }; + unsafe { + // SAFETY: EdgesByIdxMut should'nt be able to do any bad stuff for LoopSafetyIter + let ptr: *mut HopSlotMap> = &mut self.edges; + iters::EdgesByIdxMut::new(iters::LoopSafetyIter::new(inner, &*ptr), &mut self.edges) + } } #[inline] diff --git a/crates/bevy_graph/src/iters/loop_safety_iter.rs b/crates/bevy_graph/src/iters/loop_safety_iter.rs new file mode 100644 index 0000000000000..7227ac2b711b3 --- /dev/null +++ b/crates/bevy_graph/src/iters/loop_safety_iter.rs @@ -0,0 +1,56 @@ +use std::borrow::Borrow; + +use hashbrown::HashSet; +use slotmap::HopSlotMap; + +use crate::graphs::{edge::Edge, keys::EdgeIdx, Graph}; + +/// Iterator over `(&)EdgeIdx` which guarantees that loops will only come once +pub struct LoopSafetyIter<'g, E: 'g, B: Borrow, I: Iterator> { + edges: &'g HopSlotMap>, + loops: HashSet, + inner: I, +} + +impl<'g, E: 'g, B: Borrow, I: Iterator> LoopSafetyIter<'g, E, B, I> { + /// Creates a new `LoopSafetyIter` iterator over a graph with the provided `inner` iterator + pub fn from_graph(inner: I, graph: &'g mut impl Graph) -> Self { + Self { + edges: unsafe { graph.edges_raw() }, + loops: HashSet::new(), + inner, + } + } + + /// Creates a new `LoopSafetyIter` iterator over a graph with the provided `inner` iterator + pub fn new(inner: I, edges: &'g HopSlotMap>) -> Self { + Self { + edges, + loops: HashSet::new(), + inner, + } + } +} + +impl<'g, E: 'g, B: Borrow, I: Iterator> Iterator + for LoopSafetyIter<'g, E, B, I> +{ + type Item = B; + + fn next(&mut self) -> Option { + if let Some(index) = self.inner.next() { + let edge_idx = *index.borrow(); + let Edge(src, dst, _) = unsafe { self.edges.get_unchecked(edge_idx) }; + if src == dst { + if self.loops.contains(&edge_idx) { + return self.next(); + } else { + self.loops.insert(edge_idx); + } + } + Some(index) + } else { + None + } + } +} diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs index 0334131dc53eb..dde4ccd113532 100644 --- a/crates/bevy_graph/src/iters/mod.rs +++ b/crates/bevy_graph/src/iters/mod.rs @@ -24,3 +24,6 @@ pub use zip_out_degree::*; mod sources_sinks; pub use sources_sinks::*; + +mod loop_safety_iter; +pub use loop_safety_iter::*; From d204e1e7a8a84d418096aeb049a0d9b8d43a37fe Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 24 Jan 2023 14:14:21 +0100 Subject: [PATCH 165/183] Finish `degree` --- crates/bevy_graph/src/graphs/list/multi.rs | 2 +- crates/bevy_graph/src/graphs/list/simple.rs | 2 +- crates/bevy_graph/src/graphs/map/multi.rs | 2 +- crates/bevy_graph/src/graphs/map/simple.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index f302c75938132..8b2759c7e1e9c 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -237,7 +237,7 @@ impl Graph for MultiListGraph if DIRECTED { self.in_degree(index) + self.out_degree(index) } else { - todo!() + self.adjacencies[index].incoming().len() } } diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index ee99ddf4dd56b..3f10454cd2faa 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -230,7 +230,7 @@ impl Graph for SimpleListGraph if DIRECTED { self.in_degree(index) + self.out_degree(index) } else { - todo!() + self.adjacencies[index].incoming().len() } } diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 5b6244c183bdb..f6b7b97a5d986 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -239,7 +239,7 @@ impl Graph for MultiMapGraph { if DIRECTED { self.in_degree(index) + self.out_degree(index) } else { - todo!() + self.adjacencies[index].incoming().len() } } diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 5e22337c3b374..deb21228ce94a 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -227,7 +227,7 @@ impl Graph for SimpleMapGraph if DIRECTED { self.in_degree(index) + self.out_degree(index) } else { - todo!() + self.adjacencies[index].incoming().len() } } From c9a0581ea58cc37ef601f6ce987ae914de830ddb Mon Sep 17 00:00:00 2001 From: DasLixou Date: Tue, 24 Jan 2023 14:19:51 +0100 Subject: [PATCH 166/183] CI --- crates/bevy_graph/src/iters/loop_safety_iter.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/bevy_graph/src/iters/loop_safety_iter.rs b/crates/bevy_graph/src/iters/loop_safety_iter.rs index 7227ac2b711b3..4a0693e190e1d 100644 --- a/crates/bevy_graph/src/iters/loop_safety_iter.rs +++ b/crates/bevy_graph/src/iters/loop_safety_iter.rs @@ -44,9 +44,8 @@ impl<'g, E: 'g, B: Borrow, I: Iterator> Iterator if src == dst { if self.loops.contains(&edge_idx) { return self.next(); - } else { - self.loops.insert(edge_idx); } + self.loops.insert(edge_idx); } Some(index) } else { From f37b72ab2f90eb2771eaa3fb9bb8a16633820c84 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 25 Jan 2023 15:13:32 +0100 Subject: [PATCH 167/183] Make WrappedIterator simpler --- crates/bevy_graph/src/graphs/mod.rs | 30 +++++++++---------- crates/bevy_graph/src/iters/edges_by_idx.rs | 6 ++-- .../bevy_graph/src/iters/edges_by_idx_mut.rs | 6 ++-- crates/bevy_graph/src/iters/edges_mut.rs | 6 ++-- crates/bevy_graph/src/iters/edges_ref.rs | 6 ++-- crates/bevy_graph/src/iters/nodes_by_idx.rs | 6 ++-- .../bevy_graph/src/iters/nodes_by_idx_mut.rs | 6 ++-- crates/bevy_graph/src/iters/sources_sinks.rs | 10 +++---- .../bevy_graph/src/utils/wrapped_iterator.rs | 7 +++-- 9 files changed, 49 insertions(+), 34 deletions(-) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index f4a9d2089f584..55a3724725e47 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -12,7 +12,7 @@ pub mod keys; use slotmap::HopSlotMap; -use crate::error::GraphError; +use crate::{error::GraphError, utils::wrapped_iterator::WrappedIterator}; use self::{ edge::{Edge, EdgeMut, EdgeRef}, @@ -56,72 +56,72 @@ pub trait Graph { Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type EdgesOf<'e>: Iterator> + type EdgesOf<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type EdgesOfMut<'e>: Iterator> + type EdgesOfMut<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type IncomingEdgesOf<'e>: Iterator> + type IncomingEdgesOf<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type IncomingEdgesOfMut<'e>: Iterator> + type IncomingEdgesOfMut<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type OutgoingEdgesOf<'e>: Iterator> + type OutgoingEdgesOf<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type OutgoingEdgesOfMut<'e>: Iterator> + type OutgoingEdgesOfMut<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type InNeighbors<'n>: Iterator + type InNeighbors<'n>: Iterator + WrappedIterator<&'n NodeIdx> where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type InNeighborsMut<'n>: Iterator + type InNeighborsMut<'n>: Iterator + WrappedIterator<&'n NodeIdx> where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type OutNeighbors<'n>: Iterator + type OutNeighbors<'n>: Iterator + WrappedIterator<&'n NodeIdx> where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type OutNeighborsMut<'n>: Iterator + type OutNeighborsMut<'n>: Iterator + WrappedIterator<&'n NodeIdx> where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type Sources<'n>: Iterator + type Sources<'n>: Iterator + WrappedIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type SourcesMut<'n>: Iterator + type SourcesMut<'n>: Iterator + WrappedIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type Sinks<'n>: Iterator + type Sinks<'n>: Iterator + WrappedIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type SinksMut<'n>: Iterator + type SinksMut<'n>: Iterator + WrappedIterator where Self: 'n, N: 'n; diff --git a/crates/bevy_graph/src/iters/edges_by_idx.rs b/crates/bevy_graph/src/iters/edges_by_idx.rs index 0685af08e1022..8efb4289b9ff4 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx.rs @@ -32,11 +32,13 @@ impl<'g, E: 'g, B: Borrow, I: Iterator> EdgesByIdx<'g, E, B, } } -impl<'g, E: 'g, B: Borrow, I: Iterator> WrappedIterator, I> +impl<'g, E: 'g, B: Borrow, I: Iterator> WrappedIterator for EdgesByIdx<'g, E, B, I> { + type Inner = I; + #[inline] - fn into_inner(self) -> I { + fn into_inner(self) -> Self::Inner { self.inner } } diff --git a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs index bab2dd7d242ea..d704446f87db7 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs @@ -32,11 +32,13 @@ impl<'g, E: 'g, B: Borrow, I: Iterator> EdgesByIdxMut<'g, E, } } -impl<'g, E: 'g, B: Borrow, I: Iterator> WrappedIterator, I> +impl<'g, E: 'g, B: Borrow, I: Iterator> WrappedIterator for EdgesByIdxMut<'g, E, B, I> { + type Inner = I; + #[inline] - fn into_inner(self) -> I { + fn into_inner(self) -> Self::Inner { self.inner } } diff --git a/crates/bevy_graph/src/iters/edges_mut.rs b/crates/bevy_graph/src/iters/edges_mut.rs index b56678870fcc7..70378aa3615a9 100644 --- a/crates/bevy_graph/src/iters/edges_mut.rs +++ b/crates/bevy_graph/src/iters/edges_mut.rs @@ -21,11 +21,13 @@ impl<'g, E: 'g, I: Iterator>> EdgesMut<'g, E, I> { } } -impl<'g, E: 'g, I: Iterator>> WrappedIterator, I> +impl<'g, E: 'g, I: Iterator>> WrappedIterator<&'g mut Edge> for EdgesMut<'g, E, I> { + type Inner = I; + #[inline] - fn into_inner(self) -> I { + fn into_inner(self) -> Self::Inner { self.inner } } diff --git a/crates/bevy_graph/src/iters/edges_ref.rs b/crates/bevy_graph/src/iters/edges_ref.rs index 70b14b3bf8881..89d48999d6628 100644 --- a/crates/bevy_graph/src/iters/edges_ref.rs +++ b/crates/bevy_graph/src/iters/edges_ref.rs @@ -21,11 +21,13 @@ impl<'g, E: 'g, I: Iterator>> EdgesRef<'g, E, I> { } } -impl<'g, E: 'g, I: Iterator>> WrappedIterator, I> +impl<'g, E: 'g, I: Iterator>> WrappedIterator<&'g Edge> for EdgesRef<'g, E, I> { + type Inner = I; + #[inline] - fn into_inner(self) -> I { + fn into_inner(self) -> Self::Inner { self.inner } } diff --git a/crates/bevy_graph/src/iters/nodes_by_idx.rs b/crates/bevy_graph/src/iters/nodes_by_idx.rs index b865add935b22..ecd9c20d4ca3b 100644 --- a/crates/bevy_graph/src/iters/nodes_by_idx.rs +++ b/crates/bevy_graph/src/iters/nodes_by_idx.rs @@ -28,11 +28,13 @@ impl<'g, N: 'g, B: Borrow, I: Iterator> NodesByIdx<'g, N, B, } } -impl<'g, N: 'g, B: Borrow, I: Iterator> WrappedIterator +impl<'g, N: 'g, B: Borrow, I: Iterator> WrappedIterator for NodesByIdx<'g, N, B, I> { + type Inner = I; + #[inline] - fn into_inner(self) -> I { + fn into_inner(self) -> Self::Inner { self.inner } } diff --git a/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs b/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs index b8b3d971dcef2..007c9fb852fe0 100644 --- a/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs +++ b/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs @@ -28,11 +28,13 @@ impl<'g, N: 'g, B: Borrow, I: Iterator> NodesByIdxMut<'g, N, } } -impl<'g, N: 'g, B: Borrow, I: Iterator> WrappedIterator +impl<'g, N: 'g, B: Borrow, I: Iterator> WrappedIterator for NodesByIdxMut<'g, N, B, I> { + type Inner = I; + #[inline] - fn into_inner(self) -> I { + fn into_inner(self) -> Self::Inner { self.inner } } diff --git a/crates/bevy_graph/src/iters/sources_sinks.rs b/crates/bevy_graph/src/iters/sources_sinks.rs index cfb5179c7f305..88b46b174158d 100644 --- a/crates/bevy_graph/src/iters/sources_sinks.rs +++ b/crates/bevy_graph/src/iters/sources_sinks.rs @@ -18,12 +18,12 @@ impl> SourcesSinks { } } -impl> WrappedIterator - for SourcesSinks -{ +impl> WrappedIterator for SourcesSinks { + type Inner = std::iter::Map NodeIdx>; + #[inline] - fn into_inner(self) -> I { - self.inner + fn into_inner(self) -> Self::Inner { + self.inner.map(|((index, _), _)| index) } } diff --git a/crates/bevy_graph/src/utils/wrapped_iterator.rs b/crates/bevy_graph/src/utils/wrapped_iterator.rs index 2f899c4359ec9..7c7118c214380 100644 --- a/crates/bevy_graph/src/utils/wrapped_iterator.rs +++ b/crates/bevy_graph/src/utils/wrapped_iterator.rs @@ -1,5 +1,8 @@ /// Trait with helping function for getting the inner iterator of a wrapping iterator. -pub trait WrappedIterator, T, I: Iterator>: Iterator { +pub trait WrappedIterator: Iterator { + /// The inner iterator type. + type Inner: Iterator; + /// Gets the inner iterator the current one is wrapping around. - fn into_inner(self) -> I; + fn into_inner(self) -> Self::Inner; } From aff9c04ec050b25be88aeeaa590e6774491bc762 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 25 Jan 2023 16:24:41 +0100 Subject: [PATCH 168/183] =?UTF-8?q?Lemme=20just=20implement=20that=20?= =?UTF-8?q?=F0=9F=92=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/bevy_graph/src/graphs/list/multi.rs | 97 ++++++++++++++----- crates/bevy_graph/src/graphs/list/simple.rs | 59 +++++++++-- crates/bevy_graph/src/graphs/map/multi.rs | 97 ++++++++++++++----- crates/bevy_graph/src/graphs/map/simple.rs | 59 +++++++++-- crates/bevy_graph/src/graphs/mod.rs | 32 ++++++ .../iters/{sources_sinks.rs => isolated.rs} | 12 +-- .../bevy_graph/src/iters/loop_safety_iter.rs | 52 +++------- crates/bevy_graph/src/iters/mod.rs | 10 +- crates/bevy_graph/src/iters/tuple_extract.rs | 36 +++++++ crates/bevy_graph/src/iters/zip_degree.rs | 53 ++++++++++ crates/bevy_graph/src/utils/vecmap.rs | 20 ++++ 11 files changed, 418 insertions(+), 109 deletions(-) rename crates/bevy_graph/src/iters/{sources_sinks.rs => isolated.rs} (69%) create mode 100644 crates/bevy_graph/src/iters/tuple_extract.rs create mode 100644 crates/bevy_graph/src/iters/zip_degree.rs diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 8b2759c7e1e9c..2e52ba042da55 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -287,40 +287,89 @@ impl Graph for MultiListGraph iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, iters::LoopSafetyIter<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Flatten>, crate::utils::vecmap::Values<'e, NodeIdx, Vec>>>, std::iter::Flatten>>>>> where Self: 'e; + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Flatten, iters::LoopSafetyIter<'e, &'e Vec, IterChoice<(&'e NodeIdx, &'e Vec), std::iter::Chain>, crate::utils::vecmap::TupleIter<'e, NodeIdx, Vec>>, crate::utils::vecmap::TupleIter<'e, NodeIdx, Vec>>>, false>>> where Self: 'e; fn edges_of(&self, index: NodeIdx) -> Self::EdgesOf<'_> { let inner = if DIRECTED { IterChoice::new_first( self.adjacencies[index] .incoming() - .values() - .chain(self.adjacencies[index].outgoing().values()) - .flatten(), + .tuple_iter() + .chain(self.adjacencies[index].outgoing().tuple_iter()), ) } else { - IterChoice::new_second(self.adjacencies[index].incoming().values().flatten()) + IterChoice::new_second(self.adjacencies[index].incoming().tuple_iter()) }; - iters::EdgesByIdx::new(iters::LoopSafetyIter::new(inner, &self.edges), &self.edges) + iters::EdgesByIdx::new( + iters::TupleExtract::new_second(iters::LoopSafetyIter::new(inner, index)).flatten(), + &self.edges, + ) } - type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, iters::LoopSafetyIter<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Flatten>, crate::utils::vecmap::Values<'e, NodeIdx, Vec>>>, std::iter::Flatten>>>>> where Self: 'e; + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Flatten, iters::LoopSafetyIter<'e, &'e Vec, IterChoice<(&'e NodeIdx, &'e Vec), std::iter::Chain>, crate::utils::vecmap::TupleIter<'e, NodeIdx, Vec>>, crate::utils::vecmap::TupleIter<'e, NodeIdx, Vec>>>, false>>> where Self: 'e; fn edges_of_mut(&mut self, index: NodeIdx) -> Self::EdgesOfMut<'_> { let inner = if DIRECTED { IterChoice::new_first( self.adjacencies[index] .incoming() - .values() - .chain(self.adjacencies[index].outgoing().values()) - .flatten(), + .tuple_iter() + .chain(self.adjacencies[index].outgoing().tuple_iter()), ) } else { - IterChoice::new_second(self.adjacencies[index].incoming().values().flatten()) + IterChoice::new_second(self.adjacencies[index].incoming().tuple_iter()) }; - unsafe { - // SAFETY: EdgesByIdxMut should'nt be able to do any bad stuff for LoopSafetyIter - let ptr: *mut HopSlotMap> = &mut self.edges; - iters::EdgesByIdxMut::new(iters::LoopSafetyIter::new(inner, &*ptr), &mut self.edges) - } + iters::EdgesByIdxMut::new( + iters::TupleExtract::new_second(iters::LoopSafetyIter::new(inner, index)).flatten(), + &mut self.edges, + ) + } + + type Neighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, iters::TupleExtract<&'n NodeIdx, &'n Vec, iters::LoopSafetyIter<'n, &'n Vec, IterChoice<(&'n NodeIdx, &'n Vec), std::iter::Chain>, crate::utils::vecmap::TupleIter<'n, NodeIdx, Vec>>, crate::utils::vecmap::TupleIter<'n, NodeIdx, Vec>>>, true>> where Self: 'n; + fn neighbors(&self, index: NodeIdx) -> Self::Neighbors<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .tuple_iter() + .chain(self.adjacencies[index].outgoing().tuple_iter()), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().tuple_iter()) + }; + iters::NodesByIdx::new( + iters::TupleExtract::new_first(iters::LoopSafetyIter::new(inner, index)), + &self.nodes, + ) + } + + type NeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, iters::TupleExtract<&'n NodeIdx, &'n Vec, iters::LoopSafetyIter<'n, &'n Vec, IterChoice<(&'n NodeIdx, &'n Vec), std::iter::Chain>, crate::utils::vecmap::TupleIter<'n, NodeIdx, Vec>>, crate::utils::vecmap::TupleIter<'n, NodeIdx, Vec>>>, true>> where Self: 'n; + fn neighbors_mut(&mut self, index: NodeIdx) -> Self::NeighborsMut<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .tuple_iter() + .chain(self.adjacencies[index].outgoing().tuple_iter()), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().tuple_iter()) + }; + iters::NodesByIdxMut::new( + iters::TupleExtract::new_first(iters::LoopSafetyIter::new(inner, index)), + &mut self.nodes, + ) + } + + type Isolated<'n> = iters::Isolated<&'n N, iters::ZipDegree<'n, MultiListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>, DIRECTED>> where Self: 'n; + fn isolated(&self) -> Self::Isolated<'_> { + iters::Isolated::new(iters::ZipDegree::new(self.nodes.iter(), &self.adjacencies)) + } + + type IsolatedMut<'n> = iters::Isolated<&'n mut N, iters::ZipDegree<'n, MultiListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>, DIRECTED>> where Self: 'n; + fn isolated_mut(&mut self) -> Self::IsolatedMut<'_> { + iters::Isolated::new(iters::ZipDegree::new( + self.nodes.iter_mut(), + &self.adjacencies, + )) } #[inline] @@ -388,33 +437,33 @@ impl Graph for MultiListGraph ) } - type Sources<'n> = iters::SourcesSinks<&'n N, iters::ZipInDegree<'n, MultiListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + type Sources<'n> = iters::Isolated<&'n N, iters::ZipInDegree<'n, MultiListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sources(&self) -> Self::Sources<'_> { - iters::SourcesSinks::new(iters::ZipInDegree::new( + iters::Isolated::new(iters::ZipInDegree::new( self.nodes.iter(), &self.adjacencies, )) } - type SourcesMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipInDegree<'n, MultiListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + type SourcesMut<'n> = iters::Isolated<&'n mut N, iters::ZipInDegree<'n, MultiListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sources_mut(&mut self) -> Self::SourcesMut<'_> { - iters::SourcesSinks::new(iters::ZipInDegree::new( + iters::Isolated::new(iters::ZipInDegree::new( self.nodes.iter_mut(), &self.adjacencies, )) } - type Sinks<'n> = iters::SourcesSinks<&'n N, iters::ZipOutDegree<'n, MultiListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + type Sinks<'n> = iters::Isolated<&'n N, iters::ZipOutDegree<'n, MultiListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sinks(&self) -> Self::Sinks<'_> { - iters::SourcesSinks::new(iters::ZipOutDegree::new( + iters::Isolated::new(iters::ZipOutDegree::new( self.nodes.iter(), &self.adjacencies, )) } - type SinksMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipOutDegree<'n, MultiListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + type SinksMut<'n> = iters::Isolated<&'n mut N, iters::ZipOutDegree<'n, MultiListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sinks_mut(&mut self) -> Self::SinksMut<'_> { - iters::SourcesSinks::new(iters::ZipOutDegree::new( + iters::Isolated::new(iters::ZipOutDegree::new( self.nodes.iter_mut(), &self.adjacencies, )) diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 3f10454cd2faa..59d9fc87ce79d 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -310,6 +310,49 @@ impl Graph for SimpleListGraph iters::EdgesByIdxMut::new(inner, &mut self.edges) } + type Neighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, IterChoice<&'n NodeIdx, std::iter::Chain, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>>, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>>> where Self: 'n; + fn neighbors(&self, index: NodeIdx) -> Self::Neighbors<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .keys() + .chain(self.adjacencies[index].outgoing().keys()), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().keys()) + }; + iters::NodesByIdx::new(inner, &self.nodes) + } + + type NeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, IterChoice<&'n NodeIdx, std::iter::Chain, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>>, crate::utils::vecmap::Keys<'n, NodeIdx, EdgeIdx>>> where Self: 'n; + fn neighbors_mut(&mut self, index: NodeIdx) -> Self::NeighborsMut<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .keys() + .chain(self.adjacencies[index].outgoing().keys()), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().keys()) + }; + iters::NodesByIdxMut::new(inner, &mut self.nodes) + } + + type Isolated<'n> = iters::Isolated<&'n N, iters::ZipDegree<'n, SimpleListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>, DIRECTED>> where Self: 'n; + fn isolated(&self) -> Self::Isolated<'_> { + iters::Isolated::new(iters::ZipDegree::new(self.nodes.iter(), &self.adjacencies)) + } + + type IsolatedMut<'n> = iters::Isolated<&'n mut N, iters::ZipDegree<'n, SimpleListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>, DIRECTED>> where Self: 'n; + fn isolated_mut(&mut self) -> Self::IsolatedMut<'_> { + iters::Isolated::new(iters::ZipDegree::new( + self.nodes.iter_mut(), + &self.adjacencies, + )) + } + #[inline] fn in_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].incoming().len() @@ -363,33 +406,33 @@ impl Graph for SimpleListGraph ) } - type Sources<'n> = iters::SourcesSinks<&'n N, iters::ZipInDegree<'n, SimpleListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + type Sources<'n> = iters::Isolated<&'n N, iters::ZipInDegree<'n, SimpleListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sources(&self) -> Self::Sources<'_> { - iters::SourcesSinks::new(iters::ZipInDegree::new( + iters::Isolated::new(iters::ZipInDegree::new( self.nodes.iter(), &self.adjacencies, )) } - type SourcesMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipInDegree<'n, SimpleListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + type SourcesMut<'n> = iters::Isolated<&'n mut N, iters::ZipInDegree<'n, SimpleListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sources_mut(&mut self) -> Self::SourcesMut<'_> { - iters::SourcesSinks::new(iters::ZipInDegree::new( + iters::Isolated::new(iters::ZipInDegree::new( self.nodes.iter_mut(), &self.adjacencies, )) } - type Sinks<'n> = iters::SourcesSinks<&'n N, iters::ZipOutDegree<'n, SimpleListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + type Sinks<'n> = iters::Isolated<&'n N, iters::ZipOutDegree<'n, SimpleListStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sinks(&self) -> Self::Sinks<'_> { - iters::SourcesSinks::new(iters::ZipOutDegree::new( + iters::Isolated::new(iters::ZipOutDegree::new( self.nodes.iter(), &self.adjacencies, )) } - type SinksMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipOutDegree<'n, SimpleListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + type SinksMut<'n> = iters::Isolated<&'n mut N, iters::ZipOutDegree<'n, SimpleListStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sinks_mut(&mut self) -> Self::SinksMut<'_> { - iters::SourcesSinks::new(iters::ZipOutDegree::new( + iters::Isolated::new(iters::ZipOutDegree::new( self.nodes.iter_mut(), &self.adjacencies, )) diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index f6b7b97a5d986..3ee52294f4062 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -289,40 +289,89 @@ impl Graph for MultiMapGraph { iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, iters::LoopSafetyIter<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Flatten>, hashbrown::hash_map::Values<'e, NodeIdx, Vec>>>, std::iter::Flatten>>>>> where Self: 'e; + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Flatten, iters::LoopSafetyIter<'e, &'e Vec, IterChoice<(&'e NodeIdx, &'e Vec), std::iter::Chain>, hashbrown::hash_map::Iter<'e, NodeIdx, Vec>>, hashbrown::hash_map::Iter<'e, NodeIdx, Vec>>>, false>>> where Self: 'e; fn edges_of(&self, index: NodeIdx) -> Self::EdgesOf<'_> { let inner = if DIRECTED { IterChoice::new_first( self.adjacencies[index] .incoming() - .values() - .chain(self.adjacencies[index].outgoing().values()) - .flatten(), + .iter() + .chain(self.adjacencies[index].outgoing().iter()), ) } else { - IterChoice::new_second(self.adjacencies[index].incoming().values().flatten()) + IterChoice::new_second(self.adjacencies[index].incoming().iter()) }; - iters::EdgesByIdx::new(iters::LoopSafetyIter::new(inner, &self.edges), &self.edges) + iters::EdgesByIdx::new( + iters::TupleExtract::new_second(iters::LoopSafetyIter::new(inner, index)).flatten(), + &self.edges, + ) } - type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, iters::LoopSafetyIter<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Flatten>, hashbrown::hash_map::Values<'e, NodeIdx, Vec>>>, std::iter::Flatten>>>>> where Self: 'e; + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Flatten, iters::LoopSafetyIter<'e, &'e Vec, IterChoice<(&'e NodeIdx, &'e Vec), std::iter::Chain>, hashbrown::hash_map::Iter<'e, NodeIdx, Vec>>, hashbrown::hash_map::Iter<'e, NodeIdx, Vec>>>, false>>> where Self: 'e; fn edges_of_mut(&mut self, index: NodeIdx) -> Self::EdgesOfMut<'_> { let inner = if DIRECTED { IterChoice::new_first( self.adjacencies[index] .incoming() - .values() - .chain(self.adjacencies[index].outgoing().values()) - .flatten(), + .iter() + .chain(self.adjacencies[index].outgoing().iter()), ) } else { - IterChoice::new_second(self.adjacencies[index].incoming().values().flatten()) + IterChoice::new_second(self.adjacencies[index].incoming().iter()) }; - unsafe { - // SAFETY: EdgesByIdxMut should'nt be able to do any bad stuff for LoopSafetyIter - let ptr: *mut HopSlotMap> = &mut self.edges; - iters::EdgesByIdxMut::new(iters::LoopSafetyIter::new(inner, &*ptr), &mut self.edges) - } + iters::EdgesByIdxMut::new( + iters::TupleExtract::new_second(iters::LoopSafetyIter::new(inner, index)).flatten(), + &mut self.edges, + ) + } + + type Neighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, iters::TupleExtract<&'n NodeIdx, &'n Vec, iters::LoopSafetyIter<'n, &'n Vec, IterChoice<(&'n NodeIdx, &'n Vec), std::iter::Chain>, hashbrown::hash_map::Iter<'n, NodeIdx, Vec>>, hashbrown::hash_map::Iter<'n, NodeIdx, Vec>>>, true>> where Self: 'n; + fn neighbors(&self, index: NodeIdx) -> Self::Neighbors<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .iter() + .chain(self.adjacencies[index].outgoing().iter()), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().iter()) + }; + iters::NodesByIdx::new( + iters::TupleExtract::new_first(iters::LoopSafetyIter::new(inner, index)), + &self.nodes, + ) + } + + type NeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, iters::TupleExtract<&'n NodeIdx, &'n Vec, iters::LoopSafetyIter<'n, &'n Vec, IterChoice<(&'n NodeIdx, &'n Vec), std::iter::Chain>, hashbrown::hash_map::Iter<'n, NodeIdx, Vec>>, hashbrown::hash_map::Iter<'n, NodeIdx, Vec>>>, true>> where Self: 'n; + fn neighbors_mut(&mut self, index: NodeIdx) -> Self::NeighborsMut<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .iter() + .chain(self.adjacencies[index].outgoing().iter()), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().iter()) + }; + iters::NodesByIdxMut::new( + iters::TupleExtract::new_first(iters::LoopSafetyIter::new(inner, index)), + &mut self.nodes, + ) + } + + type Isolated<'n> = iters::Isolated<&'n N, iters::ZipDegree<'n, MultiMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>, DIRECTED>> where Self: 'n; + fn isolated(&self) -> Self::Isolated<'_> { + iters::Isolated::new(iters::ZipDegree::new(self.nodes.iter(), &self.adjacencies)) + } + + type IsolatedMut<'n> = iters::Isolated<&'n mut N, iters::ZipDegree<'n, MultiMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>, DIRECTED>> where Self: 'n; + fn isolated_mut(&mut self) -> Self::IsolatedMut<'_> { + iters::Isolated::new(iters::ZipDegree::new( + self.nodes.iter_mut(), + &self.adjacencies, + )) } #[inline] @@ -390,33 +439,33 @@ impl Graph for MultiMapGraph { ) } - type Sources<'n> = iters::SourcesSinks<&'n N, iters::ZipInDegree<'n, MultiMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + type Sources<'n> = iters::Isolated<&'n N, iters::ZipInDegree<'n, MultiMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sources(&self) -> Self::Sources<'_> { - iters::SourcesSinks::new(iters::ZipInDegree::new( + iters::Isolated::new(iters::ZipInDegree::new( self.nodes.iter(), &self.adjacencies, )) } - type SourcesMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipInDegree<'n, MultiMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + type SourcesMut<'n> = iters::Isolated<&'n mut N, iters::ZipInDegree<'n, MultiMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sources_mut(&mut self) -> Self::SourcesMut<'_> { - iters::SourcesSinks::new(iters::ZipInDegree::new( + iters::Isolated::new(iters::ZipInDegree::new( self.nodes.iter_mut(), &self.adjacencies, )) } - type Sinks<'n> = iters::SourcesSinks<&'n N, iters::ZipOutDegree<'n, MultiMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + type Sinks<'n> = iters::Isolated<&'n N, iters::ZipOutDegree<'n, MultiMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sinks(&self) -> Self::Sinks<'_> { - iters::SourcesSinks::new(iters::ZipOutDegree::new( + iters::Isolated::new(iters::ZipOutDegree::new( self.nodes.iter(), &self.adjacencies, )) } - type SinksMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipOutDegree<'n, MultiMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + type SinksMut<'n> = iters::Isolated<&'n mut N, iters::ZipOutDegree<'n, MultiMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sinks_mut(&mut self) -> Self::SinksMut<'_> { - iters::SourcesSinks::new(iters::ZipOutDegree::new( + iters::Isolated::new(iters::ZipOutDegree::new( self.nodes.iter_mut(), &self.adjacencies, )) diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index deb21228ce94a..ff704c8647744 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -307,6 +307,49 @@ impl Graph for SimpleMapGraph iters::EdgesByIdxMut::new(inner, &mut self.edges) } + type Neighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, IterChoice<&'n NodeIdx, std::iter::Chain, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>>, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>>> where Self: 'n; + fn neighbors(&self, index: NodeIdx) -> Self::Neighbors<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .keys() + .chain(self.adjacencies[index].outgoing().keys()), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().keys()) + }; + iters::NodesByIdx::new(inner, &self.nodes) + } + + type NeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, IterChoice<&'n NodeIdx, std::iter::Chain, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>>, hashbrown::hash_map::Keys<'n, NodeIdx, EdgeIdx>>> where Self: 'n; + fn neighbors_mut(&mut self, index: NodeIdx) -> Self::NeighborsMut<'_> { + let inner = if DIRECTED { + IterChoice::new_first( + self.adjacencies[index] + .incoming() + .keys() + .chain(self.adjacencies[index].outgoing().keys()), + ) + } else { + IterChoice::new_second(self.adjacencies[index].incoming().keys()) + }; + iters::NodesByIdxMut::new(inner, &mut self.nodes) + } + + type Isolated<'n> = iters::Isolated<&'n N, iters::ZipDegree<'n, SimpleMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>, DIRECTED>> where Self: 'n; + fn isolated(&self) -> Self::Isolated<'_> { + iters::Isolated::new(iters::ZipDegree::new(self.nodes.iter(), &self.adjacencies)) + } + + type IsolatedMut<'n> = iters::Isolated<&'n mut N, iters::ZipDegree<'n, SimpleMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>, DIRECTED>> where Self: 'n; + fn isolated_mut(&mut self) -> Self::IsolatedMut<'_> { + iters::Isolated::new(iters::ZipDegree::new( + self.nodes.iter_mut(), + &self.adjacencies, + )) + } + #[inline] fn in_degree(&self, index: NodeIdx) -> usize { self.adjacencies[index].incoming().len() @@ -360,33 +403,33 @@ impl Graph for SimpleMapGraph ) } - type Sources<'n> = iters::SourcesSinks<&'n N, iters::ZipInDegree<'n, SimpleMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + type Sources<'n> = iters::Isolated<&'n N, iters::ZipInDegree<'n, SimpleMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sources(&self) -> Self::Sources<'_> { - iters::SourcesSinks::new(iters::ZipInDegree::new( + iters::Isolated::new(iters::ZipInDegree::new( self.nodes.iter(), &self.adjacencies, )) } - type SourcesMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipInDegree<'n, SimpleMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + type SourcesMut<'n> = iters::Isolated<&'n mut N, iters::ZipInDegree<'n, SimpleMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sources_mut(&mut self) -> Self::SourcesMut<'_> { - iters::SourcesSinks::new(iters::ZipInDegree::new( + iters::Isolated::new(iters::ZipInDegree::new( self.nodes.iter_mut(), &self.adjacencies, )) } - type Sinks<'n> = iters::SourcesSinks<&'n N, iters::ZipOutDegree<'n, SimpleMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; + type Sinks<'n> = iters::Isolated<&'n N, iters::ZipOutDegree<'n, SimpleMapStorage, &'n N, slotmap::hop::Iter<'n, NodeIdx, N>>> where Self: 'n; fn sinks(&self) -> Self::Sinks<'_> { - iters::SourcesSinks::new(iters::ZipOutDegree::new( + iters::Isolated::new(iters::ZipOutDegree::new( self.nodes.iter(), &self.adjacencies, )) } - type SinksMut<'n> = iters::SourcesSinks<&'n mut N, iters::ZipOutDegree<'n, SimpleMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; + type SinksMut<'n> = iters::Isolated<&'n mut N, iters::ZipOutDegree<'n, SimpleMapStorage, &'n mut N, slotmap::hop::IterMut<'n, NodeIdx, N>>> where Self: 'n; fn sinks_mut(&mut self) -> Self::SinksMut<'_> { - iters::SourcesSinks::new(iters::ZipOutDegree::new( + iters::Isolated::new(iters::ZipOutDegree::new( self.nodes.iter_mut(), &self.adjacencies, )) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 55a3724725e47..3572d11057e51 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -66,6 +66,26 @@ pub trait Graph { Self: 'e, E: 'e; /// Iterator fix because TAIT not available + type Neighbors<'n>: Iterator + WrappedIterator<&'n NodeIdx> + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available + type NeighborsMut<'n>: Iterator + WrappedIterator<&'n NodeIdx> + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available + type Isolated<'n>: Iterator + WrappedIterator + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available + type IsolatedMut<'n>: Iterator + WrappedIterator + where + Self: 'n, + N: 'n; + /// Iterator fix because TAIT not available type IncomingEdgesOf<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> where Self: 'e, @@ -306,6 +326,18 @@ pub trait Graph { /// Returns a mutable iterator over the edges of the specified node. fn edges_of_mut(&mut self, index: NodeIdx) -> Self::EdgesOfMut<'_>; + /// Returns an iterator over the nodes the share an edge with the specified node. + fn neighbors(&self, index: NodeIdx) -> Self::Neighbors<'_>; + + /// Returns a mutable iterator over the nodes the share an edge with the specified node. + fn neighbors_mut(&mut self, index: NodeIdx) -> Self::NeighborsMut<'_>; + + /// Returns an iterator over all nodes with zero degree. + fn isolated(&self) -> Self::Isolated<'_>; + + /// Returns a mutable iterator over all nodes with zero degree. + fn isolated_mut(&mut self) -> Self::IsolatedMut<'_>; + /// Returns the number of edges going into the specified node. fn in_degree(&self, index: NodeIdx) -> usize; diff --git a/crates/bevy_graph/src/iters/sources_sinks.rs b/crates/bevy_graph/src/iters/isolated.rs similarity index 69% rename from crates/bevy_graph/src/iters/sources_sinks.rs rename to crates/bevy_graph/src/iters/isolated.rs index 88b46b174158d..6928388fec184 100644 --- a/crates/bevy_graph/src/iters/sources_sinks.rs +++ b/crates/bevy_graph/src/iters/isolated.rs @@ -2,14 +2,14 @@ use std::marker::PhantomData; use crate::{graphs::keys::NodeIdx, utils::wrapped_iterator::WrappedIterator}; -/// An iterator which iterates every source / sink node of a graph -pub struct SourcesSinks> { +/// An iterator which filters out every non-isolated node of a sub-iterator +pub struct Isolated> { inner: I, phantom: PhantomData, } -impl> SourcesSinks { - /// An iterator which iterates every source / sink node of a graph +impl> Isolated { + /// Creates a new `Isolated` iterator pub fn new(inner: I) -> Self { Self { inner, @@ -18,7 +18,7 @@ impl> SourcesSinks { } } -impl> WrappedIterator for SourcesSinks { +impl> WrappedIterator for Isolated { type Inner = std::iter::Map NodeIdx>; #[inline] @@ -27,7 +27,7 @@ impl> WrappedIterator for } } -impl> Iterator for SourcesSinks { +impl> Iterator for Isolated { type Item = T; fn next(&mut self) -> Option { diff --git a/crates/bevy_graph/src/iters/loop_safety_iter.rs b/crates/bevy_graph/src/iters/loop_safety_iter.rs index 4a0693e190e1d..d61e1f31f4a1b 100644 --- a/crates/bevy_graph/src/iters/loop_safety_iter.rs +++ b/crates/bevy_graph/src/iters/loop_safety_iter.rs @@ -1,53 +1,31 @@ -use std::borrow::Borrow; +use crate::graphs::keys::NodeIdx; -use hashbrown::HashSet; -use slotmap::HopSlotMap; - -use crate::graphs::{edge::Edge, keys::EdgeIdx, Graph}; - -/// Iterator over `(&)EdgeIdx` which guarantees that loops will only come once -pub struct LoopSafetyIter<'g, E: 'g, B: Borrow, I: Iterator> { - edges: &'g HopSlotMap>, - loops: HashSet, +/// Iterator which guarantees that loops will only come once by skipping itself in adjacencies +pub struct LoopSafetyIter<'g, V: 'g, I: Iterator> { + index_to_skip: NodeIdx, inner: I, } -impl<'g, E: 'g, B: Borrow, I: Iterator> LoopSafetyIter<'g, E, B, I> { - /// Creates a new `LoopSafetyIter` iterator over a graph with the provided `inner` iterator - pub fn from_graph(inner: I, graph: &'g mut impl Graph) -> Self { - Self { - edges: unsafe { graph.edges_raw() }, - loops: HashSet::new(), - inner, - } - } - - /// Creates a new `LoopSafetyIter` iterator over a graph with the provided `inner` iterator - pub fn new(inner: I, edges: &'g HopSlotMap>) -> Self { +impl<'g, V: 'g, I: Iterator> LoopSafetyIter<'g, V, I> { + /// Creates a new `LoopSafetyIter` iterator with the provided `inner` iterator and the `NodeIdx` it should skip + pub fn new(inner: I, index_to_skip: NodeIdx) -> Self { Self { - edges, - loops: HashSet::new(), inner, + index_to_skip, } } } -impl<'g, E: 'g, B: Borrow, I: Iterator> Iterator - for LoopSafetyIter<'g, E, B, I> -{ - type Item = B; +impl<'g, V: 'g, I: Iterator> Iterator for LoopSafetyIter<'g, V, I> { + type Item = (&'g NodeIdx, V); fn next(&mut self) -> Option { - if let Some(index) = self.inner.next() { - let edge_idx = *index.borrow(); - let Edge(src, dst, _) = unsafe { self.edges.get_unchecked(edge_idx) }; - if src == dst { - if self.loops.contains(&edge_idx) { - return self.next(); - } - self.loops.insert(edge_idx); + if let Some(i) = self.inner.next() { + if i.0 == &self.index_to_skip { + self.next() + } else { + Some(i) } - Some(index) } else { None } diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs index dde4ccd113532..1c5a129e06a2a 100644 --- a/crates/bevy_graph/src/iters/mod.rs +++ b/crates/bevy_graph/src/iters/mod.rs @@ -16,14 +16,20 @@ pub use edges_ref::*; mod edges_mut; pub use edges_mut::*; +mod zip_degree; +pub use zip_degree::*; + mod zip_in_degree; pub use zip_in_degree::*; mod zip_out_degree; pub use zip_out_degree::*; -mod sources_sinks; -pub use sources_sinks::*; +mod isolated; +pub use isolated::*; mod loop_safety_iter; pub use loop_safety_iter::*; + +mod tuple_extract; +pub use tuple_extract::*; diff --git a/crates/bevy_graph/src/iters/tuple_extract.rs b/crates/bevy_graph/src/iters/tuple_extract.rs new file mode 100644 index 0000000000000..1f451e1e756ac --- /dev/null +++ b/crates/bevy_graph/src/iters/tuple_extract.rs @@ -0,0 +1,36 @@ +/// Iterator which iterates the `FIRST` or second entry in a tuple +pub struct TupleExtract, const FIRST: bool> { + inner: I, +} + +impl> TupleExtract { + /// Creates a `TupleExtract` iterator which extracts the *first* entry + pub fn new_first(inner: I) -> Self { + Self { inner } + } +} + +impl> TupleExtract { + /// Creates a `TupleExtract` iterator which extracts the *second* entry + pub fn new_second(inner: I) -> Self { + Self { inner } + } +} + +impl> Iterator for TupleExtract { + type Item = F; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(f, _s)| f) + } +} + +impl> Iterator for TupleExtract { + type Item = S; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(_f, s)| s) + } +} diff --git a/crates/bevy_graph/src/iters/zip_degree.rs b/crates/bevy_graph/src/iters/zip_degree.rs new file mode 100644 index 0000000000000..44c6434ea1822 --- /dev/null +++ b/crates/bevy_graph/src/iters/zip_degree.rs @@ -0,0 +1,53 @@ +use hashbrown::HashMap; +use slotmap::SecondaryMap; + +use crate::graphs::{adjacency_storage::AdjacencyStorage, keys::NodeIdx}; + +/// An iterator which zips the `degree` of a `NodeIdx` with it +pub struct ZipDegree<'g, S, N, I: Iterator, const DIRECTED: bool> { + adjacencies: &'g SecondaryMap>, + inner: I, +} + +impl<'g, S, N, I: Iterator, const DIRECTED: bool> + ZipDegree<'g, S, N, I, DIRECTED> +{ + /// Creates a new `ZipDegree` iterator with the provided `inner` iterator + pub fn new(inner: I, adjacencies: &'g SecondaryMap>) -> Self { + Self { adjacencies, inner } + } +} + +impl<'g, T, N, I: Iterator, const DIRECTED: bool> Iterator + for ZipDegree<'g, Vec, N, I, DIRECTED> +{ + type Item = ((NodeIdx, N), usize); + + fn next(&mut self) -> Option { + self.inner.next().map(|(index, node)| { + let degree = if DIRECTED { + self.adjacencies[index].incoming().len() + self.adjacencies[index].outgoing().len() + } else { + self.adjacencies[index].incoming().len() + }; + ((index, node), degree) + }) + } +} + +impl<'g, K, V, N, I: Iterator, const DIRECTED: bool> Iterator + for ZipDegree<'g, HashMap, N, I, DIRECTED> +{ + type Item = ((NodeIdx, N), usize); + + fn next(&mut self) -> Option { + self.inner.next().map(|(index, node)| { + let degree = if DIRECTED { + self.adjacencies[index].incoming().len() + self.adjacencies[index].outgoing().len() + } else { + self.adjacencies[index].incoming().len() + }; + ((index, node), degree) + }) + } +} diff --git a/crates/bevy_graph/src/utils/vecmap.rs b/crates/bevy_graph/src/utils/vecmap.rs index b2bd526361f3d..daf2d1cd9fcfa 100644 --- a/crates/bevy_graph/src/utils/vecmap.rs +++ b/crates/bevy_graph/src/utils/vecmap.rs @@ -39,6 +39,9 @@ pub trait VecMap { /// Removes the entry by the key fn remove_by_key(&mut self, key: K) -> Option; + /// Returns an iterator over the entries + fn tuple_iter(&self) -> TupleIter; + /// Returns an iterator over the keys fn keys(&self) -> Keys; @@ -97,6 +100,10 @@ impl VecMap for Vec<(K, V)> { self.index_by_key(&key).map(|index| self.remove(index).1) } + fn tuple_iter(&self) -> TupleIter { + TupleIter { inner: self.iter() } + } + fn keys(&self) -> Keys { Keys { inner: self.iter() } } @@ -131,3 +138,16 @@ impl<'s, K: PartialEq, V> Iterator for Values<'s, K, V> { self.inner.next().map(|l| &l.1) } } + +/// Iterator over all entries in a `VecMap` in an entry-like tuple +pub struct TupleIter<'s, K: PartialEq, V> { + inner: slice::Iter<'s, (K, V)>, +} + +impl<'s, K: PartialEq, V> Iterator for TupleIter<'s, K, V> { + type Item = (&'s K, &'s V); + + fn next(&mut self) -> Option { + self.inner.next().map(|l| (&l.0, &l.1)) + } +} From 9befe866373f9f66fa9e1fe0ae18f6bd26d87234 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 25 Jan 2023 16:27:26 +0100 Subject: [PATCH 169/183] Start of simple integration tests --- crates/bevy_graph/tests/simple_map.rs | 64 +++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 crates/bevy_graph/tests/simple_map.rs diff --git a/crates/bevy_graph/tests/simple_map.rs b/crates/bevy_graph/tests/simple_map.rs new file mode 100644 index 0000000000000..888de8f989191 --- /dev/null +++ b/crates/bevy_graph/tests/simple_map.rs @@ -0,0 +1,64 @@ +use bevy_graph::{ + graphs::{ + keys::{EdgeIdx, NodeIdx}, + map::SimpleMapGraph, + Graph, + }, + utils::wrapped_iterator::WrappedIterator, +}; + +#[test] +fn undirected() { + let mut graph = SimpleMapGraph::<&str, i32, false>::new(); + + assert!(!graph.is_directed()); + assert!(!graph.is_multigraph()); + + assert_eq!(graph.node_count(), 0); + let jakob = graph.add_node("Jakob"); + let edgar = graph.add_node("Edgar"); + let bernhard = graph.add_node("Bernhard"); + assert_eq!(graph.node_count(), 3); + + assert_eq!(graph.edge_count(), 0); + let je = graph.add_edge(jakob, edgar, 12); + let eb = graph.add_edge(edgar, bernhard, 7); + assert_eq!(graph.edge_count(), 2); + + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(graph.contains_edge_between(edgar, jakob)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + + assert_eq!(graph.degree(jakob), 1); + assert_eq!(graph.degree(edgar), 2); + + assert_eq!( + &graph + .edges_of(jakob) + .into_inner() + .collect::>(), + &[&je] + ); + assert_eq!( + &graph + .edges_of(edgar) + .into_inner() + .collect::>(), + &[&je, &eb] + ); + + assert_eq!( + &graph + .neighbors(jakob) + .into_inner() + .collect::>(), + &[&edgar] + ); + assert_eq!( + &graph + .neighbors(edgar) + .into_inner() + .collect::>(), + &[&jakob, &bernhard] + ); +} From 05518226d5a0f58c5180684fb875db2df0b797ed Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 27 Jan 2023 15:33:00 +0100 Subject: [PATCH 170/183] Rename `has_node` to `contains_node` --- crates/bevy_graph/src/graphs/list/multi.rs | 8 ++++---- crates/bevy_graph/src/graphs/list/simple.rs | 8 ++++---- crates/bevy_graph/src/graphs/map/multi.rs | 8 ++++---- crates/bevy_graph/src/graphs/map/simple.rs | 8 ++++---- crates/bevy_graph/src/graphs/mod.rs | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 2e52ba042da55..bc8c8bd6f5e9b 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -105,9 +105,9 @@ impl Graph for MultiListGraph dst: NodeIdx, value: E, ) -> Result { - if !self.has_node(src) { + if !self.contains_node(src) { Err(GraphError::NodeNotFound(src)) - } else if !self.has_node(dst) { + } else if !self.contains_node(dst) { Err(GraphError::NodeNotFound(dst)) } else { unsafe { @@ -128,7 +128,7 @@ impl Graph for MultiListGraph } #[inline] - fn has_node(&self, node: NodeIdx) -> bool { + fn contains_node(&self, node: NodeIdx) -> bool { self.nodes.contains_key(node) } @@ -141,7 +141,7 @@ impl Graph for MultiListGraph } fn remove_node(&mut self, index: NodeIdx) -> Option { - if self.has_node(index) { + if self.contains_node(index) { let edges_to_remove = self .edges_of(index) .into_inner() diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 59d9fc87ce79d..1a3dfd9cf3761 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -104,9 +104,9 @@ impl Graph for SimpleListGraph dst: NodeIdx, value: E, ) -> Result { - if !self.has_node(src) { + if !self.contains_node(src) { Err(GraphError::NodeNotFound(src)) - } else if !self.has_node(dst) { + } else if !self.contains_node(dst) { Err(GraphError::NodeNotFound(dst)) } else if self.contains_edge_between(src, dst) { Err(GraphError::ContainsEdgeBetween) @@ -129,7 +129,7 @@ impl Graph for SimpleListGraph } #[inline] - fn has_node(&self, node: NodeIdx) -> bool { + fn contains_node(&self, node: NodeIdx) -> bool { self.nodes.contains_key(node) } @@ -142,7 +142,7 @@ impl Graph for SimpleListGraph } fn remove_node(&mut self, index: NodeIdx) -> Option { - if self.has_node(index) { + if self.contains_node(index) { let edges_to_remove = self .edges_of(index) .into_inner() diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 3ee52294f4062..63a6cccb68b98 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -105,9 +105,9 @@ impl Graph for MultiMapGraph { dst: NodeIdx, value: E, ) -> Result { - if !self.has_node(src) { + if !self.contains_node(src) { Err(GraphError::NodeNotFound(src)) - } else if !self.has_node(dst) { + } else if !self.contains_node(dst) { Err(GraphError::NodeNotFound(dst)) } else { unsafe { @@ -130,7 +130,7 @@ impl Graph for MultiMapGraph { } #[inline] - fn has_node(&self, node: NodeIdx) -> bool { + fn contains_node(&self, node: NodeIdx) -> bool { self.nodes.contains_key(node) } @@ -143,7 +143,7 @@ impl Graph for MultiMapGraph { } fn remove_node(&mut self, index: NodeIdx) -> Option { - if self.has_node(index) { + if self.contains_node(index) { let edges_to_remove = self .edges_of(index) .into_inner() diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index ff704c8647744..b5ba588655b80 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -105,9 +105,9 @@ impl Graph for SimpleMapGraph dst: NodeIdx, value: E, ) -> Result { - if !self.has_node(src) { + if !self.contains_node(src) { Err(GraphError::NodeNotFound(src)) - } else if !self.has_node(dst) { + } else if !self.contains_node(dst) { Err(GraphError::NodeNotFound(dst)) } else if self.contains_edge_between(src, dst) { Err(GraphError::ContainsEdgeBetween) @@ -130,7 +130,7 @@ impl Graph for SimpleMapGraph } #[inline] - fn has_node(&self, node: NodeIdx) -> bool { + fn contains_node(&self, node: NodeIdx) -> bool { self.nodes.contains_key(node) } @@ -139,7 +139,7 @@ impl Graph for SimpleMapGraph } fn remove_node(&mut self, index: NodeIdx) -> Option { - if self.has_node(index) { + if self.contains_node(index) { let edges_to_remove = self .edges_of(index) .into_inner() diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 3572d11057e51..ca5303bf90d41 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -228,8 +228,8 @@ pub trait Graph { self.try_add_edge(src, dst, value).unwrap() } - /// Returns `true` if the `node` is preset in the graph. - fn has_node(&self, node: NodeIdx) -> bool; + /// Returns `true` if the graph contains the `node`. + fn contains_node(&self, node: NodeIdx) -> bool; /// Returns `true` if an edge between the specified nodes exists. /// From 0a3a25713b55f5f72ac3661eb923089199cf7773 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 27 Jan 2023 15:40:02 +0100 Subject: [PATCH 171/183] Add `find_node` and `find_edge` --- crates/bevy_graph/src/graphs/list/multi.rs | 18 ++++++++++++++++++ crates/bevy_graph/src/graphs/list/simple.rs | 18 ++++++++++++++++++ crates/bevy_graph/src/graphs/map/multi.rs | 18 ++++++++++++++++++ crates/bevy_graph/src/graphs/map/simple.rs | 18 ++++++++++++++++++ crates/bevy_graph/src/graphs/mod.rs | 10 ++++++++++ 5 files changed, 82 insertions(+) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index bc8c8bd6f5e9b..fe3c016e8f8be 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -218,6 +218,15 @@ impl Graph for MultiListGraph self.nodes.get_mut(index) } + fn find_node(&self, value: &N) -> Option + where + N: PartialEq, + { + self.nodes + .iter() + .find_map(|(key, val)| if val == value { Some(key) } else { None }) + } + #[inline] unsafe fn get_edge_raw(&mut self, index: EdgeIdx) -> Option<&mut Edge> { self.edges.get_mut(index) @@ -233,6 +242,15 @@ impl Graph for MultiListGraph self.edges.get_mut(index).map(|edge| edge.as_mut_edge()) } + fn find_edge(&self, value: &E) -> Option + where + E: PartialEq, + { + self.edges + .iter() + .find_map(|(key, val)| if &val.2 == value { Some(key) } else { None }) + } + fn degree(&self, index: NodeIdx) -> usize { if DIRECTED { self.in_degree(index) + self.out_degree(index) diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 1a3dfd9cf3761..cfc5ff3ecee70 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -211,6 +211,15 @@ impl Graph for SimpleListGraph self.nodes.get_mut(index) } + fn find_node(&self, value: &N) -> Option + where + N: PartialEq, + { + self.nodes + .iter() + .find_map(|(key, val)| if val == value { Some(key) } else { None }) + } + #[inline] unsafe fn get_edge_raw(&mut self, index: EdgeIdx) -> Option<&mut Edge> { self.edges.get_mut(index) @@ -226,6 +235,15 @@ impl Graph for SimpleListGraph self.edges.get_mut(index).map(|edge| edge.as_mut_edge()) } + fn find_edge(&self, value: &E) -> Option + where + E: PartialEq, + { + self.edges + .iter() + .find_map(|(key, val)| if &val.2 == value { Some(key) } else { None }) + } + fn degree(&self, index: NodeIdx) -> usize { if DIRECTED { self.in_degree(index) + self.out_degree(index) diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 63a6cccb68b98..da7017b2abe60 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -220,6 +220,15 @@ impl Graph for MultiMapGraph { self.nodes.get_mut(index) } + fn find_node(&self, value: &N) -> Option + where + N: PartialEq, + { + self.nodes + .iter() + .find_map(|(key, val)| if val == value { Some(key) } else { None }) + } + #[inline] unsafe fn get_edge_raw(&mut self, index: EdgeIdx) -> Option<&mut Edge> { self.edges.get_mut(index) @@ -235,6 +244,15 @@ impl Graph for MultiMapGraph { self.edges.get_mut(index).map(|edge| edge.as_mut_edge()) } + fn find_edge(&self, value: &E) -> Option + where + E: PartialEq, + { + self.edges + .iter() + .find_map(|(key, val)| if &val.2 == value { Some(key) } else { None }) + } + fn degree(&self, index: NodeIdx) -> usize { if DIRECTED { self.in_degree(index) + self.out_degree(index) diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index b5ba588655b80..8f5e1482544b8 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -208,6 +208,15 @@ impl Graph for SimpleMapGraph self.nodes.get_mut(index) } + fn find_node(&self, value: &N) -> Option + where + N: PartialEq, + { + self.nodes + .iter() + .find_map(|(key, val)| if val == value { Some(key) } else { None }) + } + #[inline] unsafe fn get_edge_raw(&mut self, index: EdgeIdx) -> Option<&mut Edge> { self.edges.get_mut(index) @@ -223,6 +232,15 @@ impl Graph for SimpleMapGraph self.edges.get_mut(index).map(|edge| edge.as_mut_edge()) } + fn find_edge(&self, value: &E) -> Option + where + E: PartialEq, + { + self.edges + .iter() + .find_map(|(key, val)| if &val.2 == value { Some(key) } else { None }) + } + fn degree(&self, index: NodeIdx) -> usize { if DIRECTED { self.in_degree(index) + self.out_degree(index) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index ca5303bf90d41..8282b6b08d392 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -256,6 +256,11 @@ pub trait Graph { /// Returns a mutable reference to the specified node. fn get_node_mut(&mut self, index: NodeIdx) -> Option<&mut N>; + /// Returns the `NodeIdx` by a node value when it could be found in the graph. + fn find_node(&self, value: &N) -> Option + where + N: PartialEq; + /// Returns a raw edge handle to the specified edge. /// /// # Safety @@ -269,6 +274,11 @@ pub trait Graph { /// Returns a mutable reference to the specified edge. fn get_edge_mut(&mut self, index: EdgeIdx) -> Option>; + /// Returns the `NodeIdx` by a node value when it could be found in the graph. + fn find_edge(&self, value: &E) -> Option + where + E: PartialEq; + /// Returns the number of edges connected to the specified node. /// /// In multi-graphs, edges that form self-loops add 2 to the degree. From 4a22a17c0d189778bfec82aa108308cd8af00038 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 27 Jan 2023 15:44:18 +0100 Subject: [PATCH 172/183] Test the new funcs --- crates/bevy_graph/src/graphs/mod.rs | 2 +- crates/bevy_graph/tests/simple_map.rs | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 8282b6b08d392..27c70a6bfccce 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -274,7 +274,7 @@ pub trait Graph { /// Returns a mutable reference to the specified edge. fn get_edge_mut(&mut self, index: EdgeIdx) -> Option>; - /// Returns the `NodeIdx` by a node value when it could be found in the graph. + /// Returns the *first found* `EdgeIdx` by a edge value when it could be found in the graph. fn find_edge(&self, value: &E) -> Option where E: PartialEq; diff --git a/crates/bevy_graph/tests/simple_map.rs b/crates/bevy_graph/tests/simple_map.rs index 888de8f989191..42c950afb73b1 100644 --- a/crates/bevy_graph/tests/simple_map.rs +++ b/crates/bevy_graph/tests/simple_map.rs @@ -20,6 +20,13 @@ fn undirected() { let bernhard = graph.add_node("Bernhard"); assert_eq!(graph.node_count(), 3); + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(edgar)); + assert!(graph.contains_node(bernhard)); + + assert_eq!(graph.find_node(&"Edgar"), Some(edgar)); + assert_eq!(graph.find_node(&"NoIReallyDon'tExist"), None); + assert_eq!(graph.edge_count(), 0); let je = graph.add_edge(jakob, edgar, 12); let eb = graph.add_edge(edgar, bernhard, 7); @@ -29,6 +36,9 @@ fn undirected() { assert!(graph.contains_edge_between(edgar, jakob)); assert!(!graph.contains_edge_between(jakob, bernhard)); + assert_eq!(graph.find_edge(&12), Some(je)); + assert_eq!(graph.find_edge(&0), None); + assert_eq!(graph.degree(jakob), 1); assert_eq!(graph.degree(edgar), 2); From 638d503e750190256ab0c47c656908201e02035d Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 27 Jan 2023 15:48:15 +0100 Subject: [PATCH 173/183] tests: unordered eq --- crates/bevy_graph/tests/simple_map.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/bevy_graph/tests/simple_map.rs b/crates/bevy_graph/tests/simple_map.rs index 42c950afb73b1..c9d803f3cd8e7 100644 --- a/crates/bevy_graph/tests/simple_map.rs +++ b/crates/bevy_graph/tests/simple_map.rs @@ -6,6 +6,7 @@ use bevy_graph::{ }, utils::wrapped_iterator::WrappedIterator, }; +use hashbrown::HashSet; #[test] fn undirected() { @@ -27,6 +28,11 @@ fn undirected() { assert_eq!(graph.find_node(&"Edgar"), Some(edgar)); assert_eq!(graph.find_node(&"NoIReallyDon'tExist"), None); + assert_eq!( + &graph.node_indices().collect::>(), + &[jakob, edgar, bernhard].into() + ); + assert_eq!(graph.edge_count(), 0); let je = graph.add_edge(jakob, edgar, 12); let eb = graph.add_edge(edgar, bernhard, 7); @@ -46,29 +52,29 @@ fn undirected() { &graph .edges_of(jakob) .into_inner() - .collect::>(), - &[&je] + .collect::>(), + &[&je].into() ); assert_eq!( &graph .edges_of(edgar) .into_inner() - .collect::>(), - &[&je, &eb] + .collect::>(), + &[&je, &eb].into() ); assert_eq!( &graph .neighbors(jakob) .into_inner() - .collect::>(), - &[&edgar] + .collect::>(), + &[&edgar].into() ); assert_eq!( &graph .neighbors(edgar) .into_inner() - .collect::>(), - &[&jakob, &bernhard] + .collect::>(), + &[&jakob, &bernhard].into() ); } From e79151b4872468699c068284b0ad1eac39d0940f Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 27 Jan 2023 16:14:10 +0100 Subject: [PATCH 174/183] Now finally ever iter is nonborrowed index --- crates/bevy_graph/src/graphs/list/multi.rs | 6 +- crates/bevy_graph/src/graphs/list/simple.rs | 7 ++- crates/bevy_graph/src/graphs/map/multi.rs | 7 ++- crates/bevy_graph/src/graphs/map/simple.rs | 5 +- crates/bevy_graph/src/graphs/mod.rs | 38 ++++++------- crates/bevy_graph/src/iters/edges_by_idx.rs | 21 +++++-- .../bevy_graph/src/iters/edges_by_idx_mut.rs | 21 +++++-- crates/bevy_graph/src/iters/edges_mut.rs | 16 +----- crates/bevy_graph/src/iters/edges_ref.rs | 16 +----- crates/bevy_graph/src/iters/isolated.rs | 35 +++++++++--- crates/bevy_graph/src/iters/nodes_by_idx.rs | 21 +++++-- .../bevy_graph/src/iters/nodes_by_idx_mut.rs | 21 +++++-- crates/bevy_graph/src/utils/mod.rs | 4 +- .../src/utils/wrapped_indices_iterator.rs | 8 +++ .../bevy_graph/src/utils/wrapped_iterator.rs | 8 --- crates/bevy_graph/tests/simple_map.rs | 55 ++++++++++++------- 16 files changed, 169 insertions(+), 120 deletions(-) create mode 100644 crates/bevy_graph/src/utils/wrapped_indices_iterator.rs delete mode 100644 crates/bevy_graph/src/utils/wrapped_iterator.rs diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index fe3c016e8f8be..95a8f87e103d2 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -11,7 +11,8 @@ use crate::{ }, iters, utils::{ - iter_choice::IterChoice, vecmap::VecMap, vecset::VecSet, wrapped_iterator::WrappedIterator, + iter_choice::IterChoice, vecmap::VecMap, vecset::VecSet, + wrapped_indices_iterator::WrappedIndicesIterator, }, }; @@ -144,8 +145,7 @@ impl Graph for MultiListGraph if self.contains_node(index) { let edges_to_remove = self .edges_of(index) - .into_inner() - .cloned() + .into_indices() .collect::>(); for edge_idx in edges_to_remove { unsafe { diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index cfc5ff3ecee70..6e6b5a6e19c6e 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -10,7 +10,9 @@ use crate::{ DirectedGraph, Graph, }, iters, - utils::{iter_choice::IterChoice, vecmap::VecMap, wrapped_iterator::WrappedIterator}, + utils::{ + iter_choice::IterChoice, vecmap::VecMap, wrapped_indices_iterator::WrappedIndicesIterator, + }, }; type SimpleListStorage = Vec<(NodeIdx, EdgeIdx)>; @@ -145,8 +147,7 @@ impl Graph for SimpleListGraph if self.contains_node(index) { let edges_to_remove = self .edges_of(index) - .into_inner() - .cloned() + .into_indices() .collect::>(); for edge_idx in edges_to_remove { unsafe { diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index da7017b2abe60..601da1fe162ce 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -11,7 +11,9 @@ use crate::{ DirectedGraph, Graph, }, iters, - utils::{iter_choice::IterChoice, vecset::VecSet, wrapped_iterator::WrappedIterator}, + utils::{ + iter_choice::IterChoice, vecset::VecSet, wrapped_indices_iterator::WrappedIndicesIterator, + }, }; type MultiMapStorage = HashMap>; @@ -146,8 +148,7 @@ impl Graph for MultiMapGraph { if self.contains_node(index) { let edges_to_remove = self .edges_of(index) - .into_inner() - .cloned() + .into_indices() .collect::>(); for edge_idx in edges_to_remove { unsafe { diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index 8f5e1482544b8..c137fc503031a 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -11,7 +11,7 @@ use crate::{ DirectedGraph, Graph, }, iters, - utils::{iter_choice::IterChoice, wrapped_iterator::WrappedIterator}, + utils::{iter_choice::IterChoice, wrapped_indices_iterator::WrappedIndicesIterator}, }; type SimpleMapStorage = HashMap; @@ -142,8 +142,7 @@ impl Graph for SimpleMapGraph if self.contains_node(index) { let edges_to_remove = self .edges_of(index) - .into_inner() - .cloned() + .into_indices() .collect::>(); for edge_idx in edges_to_remove { unsafe { diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 27c70a6bfccce..933ab26554c67 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -12,7 +12,7 @@ pub mod keys; use slotmap::HopSlotMap; -use crate::{error::GraphError, utils::wrapped_iterator::WrappedIterator}; +use crate::{error::GraphError, utils::wrapped_indices_iterator::WrappedIndicesIterator}; use self::{ edge::{Edge, EdgeMut, EdgeRef}, @@ -56,92 +56,92 @@ pub trait Graph { Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type EdgesOf<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> + type EdgesOf<'e>: Iterator> + WrappedIndicesIterator where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type EdgesOfMut<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> + type EdgesOfMut<'e>: Iterator> + WrappedIndicesIterator where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type Neighbors<'n>: Iterator + WrappedIterator<&'n NodeIdx> + type Neighbors<'n>: Iterator + WrappedIndicesIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type NeighborsMut<'n>: Iterator + WrappedIterator<&'n NodeIdx> + type NeighborsMut<'n>: Iterator + WrappedIndicesIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type Isolated<'n>: Iterator + WrappedIterator + type Isolated<'n>: Iterator + WrappedIndicesIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type IsolatedMut<'n>: Iterator + WrappedIterator + type IsolatedMut<'n>: Iterator + WrappedIndicesIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type IncomingEdgesOf<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> + type IncomingEdgesOf<'e>: Iterator> + WrappedIndicesIterator where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type IncomingEdgesOfMut<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> + type IncomingEdgesOfMut<'e>: Iterator> + WrappedIndicesIterator where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type OutgoingEdgesOf<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> + type OutgoingEdgesOf<'e>: Iterator> + WrappedIndicesIterator where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type OutgoingEdgesOfMut<'e>: Iterator> + WrappedIterator<&'e EdgeIdx> + type OutgoingEdgesOfMut<'e>: Iterator> + WrappedIndicesIterator where Self: 'e, E: 'e; /// Iterator fix because TAIT not available - type InNeighbors<'n>: Iterator + WrappedIterator<&'n NodeIdx> + type InNeighbors<'n>: Iterator + WrappedIndicesIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type InNeighborsMut<'n>: Iterator + WrappedIterator<&'n NodeIdx> + type InNeighborsMut<'n>: Iterator + WrappedIndicesIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type OutNeighbors<'n>: Iterator + WrappedIterator<&'n NodeIdx> + type OutNeighbors<'n>: Iterator + WrappedIndicesIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type OutNeighborsMut<'n>: Iterator + WrappedIterator<&'n NodeIdx> + type OutNeighborsMut<'n>: Iterator + WrappedIndicesIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type Sources<'n>: Iterator + WrappedIterator + type Sources<'n>: Iterator + WrappedIndicesIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type SourcesMut<'n>: Iterator + WrappedIterator + type SourcesMut<'n>: Iterator + WrappedIndicesIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type Sinks<'n>: Iterator + WrappedIterator + type Sinks<'n>: Iterator + WrappedIndicesIterator where Self: 'n, N: 'n; /// Iterator fix because TAIT not available - type SinksMut<'n>: Iterator + WrappedIterator + type SinksMut<'n>: Iterator + WrappedIndicesIterator where Self: 'n, N: 'n; diff --git a/crates/bevy_graph/src/iters/edges_by_idx.rs b/crates/bevy_graph/src/iters/edges_by_idx.rs index 8efb4289b9ff4..c3b44e772932c 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx.rs @@ -8,7 +8,7 @@ use crate::{ keys::EdgeIdx, Graph, }, - utils::wrapped_iterator::WrappedIterator, + utils::wrapped_indices_iterator::WrappedIndicesIterator, }; /// An iterator which converts `(&)EdgeIdx` to a `EdgeRef` of the graph @@ -32,13 +32,24 @@ impl<'g, E: 'g, B: Borrow, I: Iterator> EdgesByIdx<'g, E, B, } } -impl<'g, E: 'g, B: Borrow, I: Iterator> WrappedIterator - for EdgesByIdx<'g, E, B, I> +impl<'g, E: 'g, I: Iterator> WrappedIndicesIterator + for EdgesByIdx<'g, E, &'g EdgeIdx, I> { - type Inner = I; + type IndicesIter = std::iter::Cloned; #[inline] - fn into_inner(self) -> Self::Inner { + fn into_indices(self) -> Self::IndicesIter { + self.inner.cloned() + } +} + +impl<'g, E: 'g, I: Iterator> WrappedIndicesIterator + for EdgesByIdx<'g, E, EdgeIdx, I> +{ + type IndicesIter = I; + + #[inline] + fn into_indices(self) -> Self::IndicesIter { self.inner } } diff --git a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs index d704446f87db7..d6d806b54027a 100644 --- a/crates/bevy_graph/src/iters/edges_by_idx_mut.rs +++ b/crates/bevy_graph/src/iters/edges_by_idx_mut.rs @@ -8,7 +8,7 @@ use crate::{ keys::EdgeIdx, Graph, }, - utils::wrapped_iterator::WrappedIterator, + utils::wrapped_indices_iterator::WrappedIndicesIterator, }; /// An iterator which converts `(&)EdgeIdx` to a `EdgeMut` of the graph @@ -32,13 +32,24 @@ impl<'g, E: 'g, B: Borrow, I: Iterator> EdgesByIdxMut<'g, E, } } -impl<'g, E: 'g, B: Borrow, I: Iterator> WrappedIterator - for EdgesByIdxMut<'g, E, B, I> +impl<'g, E: 'g, I: Iterator> WrappedIndicesIterator + for EdgesByIdxMut<'g, E, &'g EdgeIdx, I> { - type Inner = I; + type IndicesIter = std::iter::Cloned; #[inline] - fn into_inner(self) -> Self::Inner { + fn into_indices(self) -> Self::IndicesIter { + self.inner.cloned() + } +} + +impl<'g, E: 'g, I: Iterator> WrappedIndicesIterator + for EdgesByIdxMut<'g, E, EdgeIdx, I> +{ + type IndicesIter = I; + + #[inline] + fn into_indices(self) -> Self::IndicesIter { self.inner } } diff --git a/crates/bevy_graph/src/iters/edges_mut.rs b/crates/bevy_graph/src/iters/edges_mut.rs index 70378aa3615a9..2980a456d3c6f 100644 --- a/crates/bevy_graph/src/iters/edges_mut.rs +++ b/crates/bevy_graph/src/iters/edges_mut.rs @@ -1,9 +1,6 @@ use std::marker::PhantomData; -use crate::{ - graphs::edge::{Edge, EdgeMut}, - utils::wrapped_iterator::WrappedIterator, -}; +use crate::graphs::edge::{Edge, EdgeMut}; /// An iterator which converts `&'g mut Edge` to a `EdgeMut<'g, E>` pub struct EdgesMut<'g, E: 'g, I: Iterator>> { @@ -21,17 +18,6 @@ impl<'g, E: 'g, I: Iterator>> EdgesMut<'g, E, I> { } } -impl<'g, E: 'g, I: Iterator>> WrappedIterator<&'g mut Edge> - for EdgesMut<'g, E, I> -{ - type Inner = I; - - #[inline] - fn into_inner(self) -> Self::Inner { - self.inner - } -} - impl<'g, E: 'g, I: Iterator>> Iterator for EdgesMut<'g, E, I> { type Item = EdgeMut<'g, E>; diff --git a/crates/bevy_graph/src/iters/edges_ref.rs b/crates/bevy_graph/src/iters/edges_ref.rs index 89d48999d6628..49df915fa68d4 100644 --- a/crates/bevy_graph/src/iters/edges_ref.rs +++ b/crates/bevy_graph/src/iters/edges_ref.rs @@ -1,9 +1,6 @@ use std::marker::PhantomData; -use crate::{ - graphs::edge::{Edge, EdgeRef}, - utils::wrapped_iterator::WrappedIterator, -}; +use crate::graphs::edge::{Edge, EdgeRef}; /// An iterator which converts `&'g Edge` to a `EdgeRef<'g, E>` pub struct EdgesRef<'g, E: 'g, I: Iterator>> { @@ -21,17 +18,6 @@ impl<'g, E: 'g, I: Iterator>> EdgesRef<'g, E, I> { } } -impl<'g, E: 'g, I: Iterator>> WrappedIterator<&'g Edge> - for EdgesRef<'g, E, I> -{ - type Inner = I; - - #[inline] - fn into_inner(self) -> Self::Inner { - self.inner - } -} - impl<'g, E: 'g, I: Iterator>> Iterator for EdgesRef<'g, E, I> { type Item = EdgeRef<'g, E>; diff --git a/crates/bevy_graph/src/iters/isolated.rs b/crates/bevy_graph/src/iters/isolated.rs index 6928388fec184..042d76dcd78e1 100644 --- a/crates/bevy_graph/src/iters/isolated.rs +++ b/crates/bevy_graph/src/iters/isolated.rs @@ -1,10 +1,10 @@ use std::marker::PhantomData; -use crate::{graphs::keys::NodeIdx, utils::wrapped_iterator::WrappedIterator}; +use crate::{graphs::keys::NodeIdx, utils::wrapped_indices_iterator::WrappedIndicesIterator}; /// An iterator which filters out every non-isolated node of a sub-iterator pub struct Isolated> { - inner: I, + inner: InnerIsolated, phantom: PhantomData, } @@ -12,17 +12,22 @@ impl> Isolated { /// Creates a new `Isolated` iterator pub fn new(inner: I) -> Self { Self { - inner, + inner: InnerIsolated { + inner, + phantom: PhantomData, + }, phantom: PhantomData, } } } -impl> WrappedIterator for Isolated { - type Inner = std::iter::Map NodeIdx>; +impl> WrappedIndicesIterator + for Isolated +{ + type IndicesIter = std::iter::Map, fn(((NodeIdx, T), usize)) -> NodeIdx>; #[inline] - fn into_inner(self) -> Self::Inner { + fn into_indices(self) -> Self::IndicesIter { self.inner.map(|((index, _), _)| index) } } @@ -31,8 +36,20 @@ impl> Iterator for Isolated { type Item = T; fn next(&mut self) -> Option { - self.inner - .find(|(_, in_out_degree)| *in_out_degree == 0) - .map(|((_, node), _)| node) + self.inner.next().map(|((_, node), _)| node) + } +} + +/// An iterator which filters out every non-isolated node of a sub-iterator +pub struct InnerIsolated> { + inner: I, + phantom: PhantomData, +} + +impl> Iterator for InnerIsolated { + type Item = ((NodeIdx, T), usize); + + fn next(&mut self) -> Option { + self.inner.find(|(_, in_out_degree)| *in_out_degree == 0) } } diff --git a/crates/bevy_graph/src/iters/nodes_by_idx.rs b/crates/bevy_graph/src/iters/nodes_by_idx.rs index ecd9c20d4ca3b..c1913d9bffbad 100644 --- a/crates/bevy_graph/src/iters/nodes_by_idx.rs +++ b/crates/bevy_graph/src/iters/nodes_by_idx.rs @@ -4,7 +4,7 @@ use slotmap::HopSlotMap; use crate::{ graphs::{keys::NodeIdx, Graph}, - utils::wrapped_iterator::WrappedIterator, + utils::wrapped_indices_iterator::WrappedIndicesIterator, }; /// An iterator which converts `(&)NodeIdx` to a `&'g N` of the graph @@ -28,13 +28,24 @@ impl<'g, N: 'g, B: Borrow, I: Iterator> NodesByIdx<'g, N, B, } } -impl<'g, N: 'g, B: Borrow, I: Iterator> WrappedIterator - for NodesByIdx<'g, N, B, I> +impl<'g, N: 'g, I: Iterator> WrappedIndicesIterator + for NodesByIdx<'g, N, &'g NodeIdx, I> { - type Inner = I; + type IndicesIter = std::iter::Cloned; #[inline] - fn into_inner(self) -> Self::Inner { + fn into_indices(self) -> Self::IndicesIter { + self.inner.cloned() + } +} + +impl<'g, N: 'g, I: Iterator> WrappedIndicesIterator + for NodesByIdx<'g, N, NodeIdx, I> +{ + type IndicesIter = I; + + #[inline] + fn into_indices(self) -> Self::IndicesIter { self.inner } } diff --git a/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs b/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs index 007c9fb852fe0..1e58664a8b7f3 100644 --- a/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs +++ b/crates/bevy_graph/src/iters/nodes_by_idx_mut.rs @@ -4,7 +4,7 @@ use slotmap::HopSlotMap; use crate::{ graphs::{keys::NodeIdx, Graph}, - utils::wrapped_iterator::WrappedIterator, + utils::wrapped_indices_iterator::WrappedIndicesIterator, }; /// An iterator which converts `(&)NodeIdx` to a `&'g mut N` of the graph @@ -28,13 +28,24 @@ impl<'g, N: 'g, B: Borrow, I: Iterator> NodesByIdxMut<'g, N, } } -impl<'g, N: 'g, B: Borrow, I: Iterator> WrappedIterator - for NodesByIdxMut<'g, N, B, I> +impl<'g, N: 'g, I: Iterator> WrappedIndicesIterator + for NodesByIdxMut<'g, N, &'g NodeIdx, I> { - type Inner = I; + type IndicesIter = std::iter::Cloned; #[inline] - fn into_inner(self) -> Self::Inner { + fn into_indices(self) -> Self::IndicesIter { + self.inner.cloned() + } +} + +impl<'g, N: 'g, I: Iterator> WrappedIndicesIterator + for NodesByIdxMut<'g, N, NodeIdx, I> +{ + type IndicesIter = I; + + #[inline] + fn into_indices(self) -> Self::IndicesIter { self.inner } } diff --git a/crates/bevy_graph/src/utils/mod.rs b/crates/bevy_graph/src/utils/mod.rs index 5b8aefada9517..31adcdf161c06 100644 --- a/crates/bevy_graph/src/utils/mod.rs +++ b/crates/bevy_graph/src/utils/mod.rs @@ -4,5 +4,5 @@ pub mod iter_choice; pub mod vecmap; /// Set-like methods for `Vec` pub mod vecset; -/// Trait with helping function for getting the inner iterator of a wrapping iterator -pub mod wrapped_iterator; +/// Trait with helping function for yielding the index instead of the value. +pub mod wrapped_indices_iterator; diff --git a/crates/bevy_graph/src/utils/wrapped_indices_iterator.rs b/crates/bevy_graph/src/utils/wrapped_indices_iterator.rs new file mode 100644 index 0000000000000..0eb46f9cba751 --- /dev/null +++ b/crates/bevy_graph/src/utils/wrapped_indices_iterator.rs @@ -0,0 +1,8 @@ +/// Trait with helping function for yielding the index instead of the value. +pub trait WrappedIndicesIterator: Iterator { + /// The indices iterator type. + type IndicesIter: Iterator; + + /// Returns an iterator which yields the index instead of the value. + fn into_indices(self) -> Self::IndicesIter; +} diff --git a/crates/bevy_graph/src/utils/wrapped_iterator.rs b/crates/bevy_graph/src/utils/wrapped_iterator.rs deleted file mode 100644 index 7c7118c214380..0000000000000 --- a/crates/bevy_graph/src/utils/wrapped_iterator.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Trait with helping function for getting the inner iterator of a wrapping iterator. -pub trait WrappedIterator: Iterator { - /// The inner iterator type. - type Inner: Iterator; - - /// Gets the inner iterator the current one is wrapping around. - fn into_inner(self) -> Self::Inner; -} diff --git a/crates/bevy_graph/tests/simple_map.rs b/crates/bevy_graph/tests/simple_map.rs index c9d803f3cd8e7..15fc6dcb1662a 100644 --- a/crates/bevy_graph/tests/simple_map.rs +++ b/crates/bevy_graph/tests/simple_map.rs @@ -4,7 +4,7 @@ use bevy_graph::{ map::SimpleMapGraph, Graph, }, - utils::wrapped_iterator::WrappedIterator, + utils::wrapped_indices_iterator::WrappedIndicesIterator, }; use hashbrown::HashSet; @@ -19,18 +19,20 @@ fn undirected() { let jakob = graph.add_node("Jakob"); let edgar = graph.add_node("Edgar"); let bernhard = graph.add_node("Bernhard"); - assert_eq!(graph.node_count(), 3); + let no_friends_manny = graph.add_node("No Friends Manny"); + assert_eq!(graph.node_count(), 4); assert!(graph.contains_node(jakob)); assert!(graph.contains_node(edgar)); assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); assert_eq!(graph.find_node(&"Edgar"), Some(edgar)); assert_eq!(graph.find_node(&"NoIReallyDon'tExist"), None); assert_eq!( - &graph.node_indices().collect::>(), - &[jakob, edgar, bernhard].into() + graph.node_indices().collect::>(), + [jakob, edgar, bernhard, no_friends_manny].into() ); assert_eq!(graph.edge_count(), 0); @@ -45,36 +47,49 @@ fn undirected() { assert_eq!(graph.find_edge(&12), Some(je)); assert_eq!(graph.find_edge(&0), None); + assert_eq!( + graph.edge_indices().collect::>(), + [je, eb].into() + ); + assert_eq!(graph.degree(jakob), 1); assert_eq!(graph.degree(edgar), 2); assert_eq!( - &graph + graph .edges_of(jakob) - .into_inner() - .collect::>(), - &[&je].into() + .into_indices() + .collect::>(), + [je].into() ); assert_eq!( - &graph + graph .edges_of(edgar) - .into_inner() - .collect::>(), - &[&je, &eb].into() + .into_indices() + .collect::>(), + [je, eb].into() ); assert_eq!( - &graph + graph .neighbors(jakob) - .into_inner() - .collect::>(), - &[&edgar].into() + .into_indices() + .collect::>(), + [edgar].into() ); assert_eq!( - &graph + graph .neighbors(edgar) - .into_inner() - .collect::>(), - &[&jakob, &bernhard].into() + .into_indices() + .collect::>(), + [jakob, bernhard].into() + ); + + assert_eq!( + graph + .isolated() + .into_indices() + .collect::>(), + [no_friends_manny].into() ); } From 2a55cbd2a38a0ef4389b8d2b06d459db32c04895 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Fri, 27 Jan 2023 16:21:10 +0100 Subject: [PATCH 175/183] =?UTF-8?q?Undirected=20Simple=20List=20works=20as?= =?UTF-8?q?well=20=F0=9F=A4=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/bevy_graph/tests/simple_list.rs | 95 ++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 crates/bevy_graph/tests/simple_list.rs diff --git a/crates/bevy_graph/tests/simple_list.rs b/crates/bevy_graph/tests/simple_list.rs new file mode 100644 index 0000000000000..725efec018cdd --- /dev/null +++ b/crates/bevy_graph/tests/simple_list.rs @@ -0,0 +1,95 @@ +use bevy_graph::{ + graphs::{ + keys::{EdgeIdx, NodeIdx}, + list::SimpleListGraph, + Graph, + }, + utils::wrapped_indices_iterator::WrappedIndicesIterator, +}; +use hashbrown::HashSet; + +#[test] +fn undirected() { + let mut graph = SimpleListGraph::<&str, i32, false>::new(); + + assert!(!graph.is_directed()); + assert!(!graph.is_multigraph()); + + assert_eq!(graph.node_count(), 0); + let jakob = graph.add_node("Jakob"); + let edgar = graph.add_node("Edgar"); + let bernhard = graph.add_node("Bernhard"); + let no_friends_manny = graph.add_node("No Friends Manny"); + assert_eq!(graph.node_count(), 4); + + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(edgar)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + + assert_eq!(graph.find_node(&"Edgar"), Some(edgar)); + assert_eq!(graph.find_node(&"NoIReallyDon'tExist"), None); + + assert_eq!( + graph.node_indices().collect::>(), + [jakob, edgar, bernhard, no_friends_manny].into() + ); + + assert_eq!(graph.edge_count(), 0); + let je = graph.add_edge(jakob, edgar, 12); + let eb = graph.add_edge(edgar, bernhard, 7); + assert_eq!(graph.edge_count(), 2); + + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(graph.contains_edge_between(edgar, jakob)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + + assert_eq!(graph.find_edge(&12), Some(je)); + assert_eq!(graph.find_edge(&0), None); + + assert_eq!( + graph.edge_indices().collect::>(), + [je, eb].into() + ); + + assert_eq!(graph.degree(jakob), 1); + assert_eq!(graph.degree(edgar), 2); + + assert_eq!( + graph + .edges_of(jakob) + .into_indices() + .collect::>(), + [je].into() + ); + assert_eq!( + graph + .edges_of(edgar) + .into_indices() + .collect::>(), + [je, eb].into() + ); + + assert_eq!( + graph + .neighbors(jakob) + .into_indices() + .collect::>(), + [edgar].into() + ); + assert_eq!( + graph + .neighbors(edgar) + .into_indices() + .collect::>(), + [jakob, bernhard].into() + ); + + assert_eq!( + graph + .isolated() + .into_indices() + .collect::>(), + [no_friends_manny].into() + ); +} From 4bbd4c0ec119f9a20088563a1292b063aefe260e Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 28 Jan 2023 16:49:40 +0100 Subject: [PATCH 176/183] Add tests for `directed` simple graphs and ... * Fix `reverse(_edge)` --- crates/bevy_graph/src/graphs/list/multi.rs | 20 +-- crates/bevy_graph/src/graphs/list/simple.rs | 12 +- crates/bevy_graph/src/graphs/map/multi.rs | 20 +-- crates/bevy_graph/src/graphs/map/simple.rs | 12 +- crates/bevy_graph/tests/simple_list.rs | 146 +++++++++++++++++++- crates/bevy_graph/tests/simple_map.rs | 146 +++++++++++++++++++- 6 files changed, 322 insertions(+), 34 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 95a8f87e103d2..3784a8544d663 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -495,15 +495,15 @@ impl DirectedGraph for MultiListGraph { .for_each(|list| list.for_each_mut(Vec::clear)); for (index, Edge(src, dst, _)) in &mut self.edges { - std::mem::swap(src, dst); - self.adjacencies[*dst] + std::mem::swap(src, dst); // *dst is now *src + self.adjacencies[*src] .outgoing_mut() - .get_value_mut(*src) + .get_value_mut(*dst) .unwrap() .push(index); - self.adjacencies[*src] + self.adjacencies[*dst] .incoming_mut() - .get_value_mut(*dst) + .get_value_mut(*src) .unwrap() .push(index); } @@ -521,15 +521,15 @@ impl DirectedGraph for MultiListGraph { .get_value_mut(*src) .unwrap() .remove_by_value(&index); - std::mem::swap(src, dst); - self.adjacencies[*dst] + std::mem::swap(src, dst); // *dst is now *src + self.adjacencies[*src] .outgoing_mut() - .get_value_mut(*src) + .get_value_mut(*dst) .unwrap() .push(index); - self.adjacencies[*src] + self.adjacencies[*dst] .incoming_mut() - .get_value_mut(*dst) + .get_value_mut(*src) .unwrap() .push(index); } diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 6e6b5a6e19c6e..adc7a002f9b77 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -465,9 +465,9 @@ impl DirectedGraph for SimpleListGraph { .for_each(|list| list.for_each_mut(Vec::clear)); for (index, Edge(src, dst, _)) in &mut self.edges { - std::mem::swap(src, dst); - self.adjacencies[*dst].outgoing_mut().push((*src, index)); - self.adjacencies[*src].incoming_mut().push((*dst, index)); + std::mem::swap(src, dst); // *dst is now *src + self.adjacencies[*src].outgoing_mut().push((*dst, index)); + self.adjacencies[*dst].incoming_mut().push((*src, index)); } } @@ -475,9 +475,9 @@ impl DirectedGraph for SimpleListGraph { if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { self.adjacencies[*src].outgoing_mut().remove_by_key(*dst); self.adjacencies[*dst].incoming_mut().remove_by_key(*src); - std::mem::swap(src, dst); - self.adjacencies[*dst].outgoing_mut().push((*src, index)); - self.adjacencies[*src].incoming_mut().push((*dst, index)); + std::mem::swap(src, dst); // *dst is now *src + self.adjacencies[*src].outgoing_mut().push((*dst, index)); + self.adjacencies[*dst].incoming_mut().push((*src, index)); } } diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 601da1fe162ce..774c0a1e94aa2 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -498,15 +498,15 @@ impl DirectedGraph for MultiMapGraph { .for_each(|map| map.for_each_mut(HashMap::clear)); for (index, Edge(src, dst, _)) in &mut self.edges { - std::mem::swap(src, dst); - self.adjacencies[*dst] + std::mem::swap(src, dst); // *dst is now *src + self.adjacencies[*src] .outgoing_mut() - .get_mut(src) + .get_mut(dst) .unwrap() .push(index); - self.adjacencies[*src] + self.adjacencies[*dst] .incoming_mut() - .get_mut(dst) + .get_mut(src) .unwrap() .push(index); } @@ -524,15 +524,15 @@ impl DirectedGraph for MultiMapGraph { .get_mut(src) .unwrap() .remove_by_value(&index); - std::mem::swap(src, dst); - self.adjacencies[*dst] + std::mem::swap(src, dst); // *dst is now *src + self.adjacencies[*src] .outgoing_mut() - .get_mut(src) + .get_mut(dst) .unwrap() .push(index); - self.adjacencies[*src] + self.adjacencies[*dst] .incoming_mut() - .get_mut(dst) + .get_mut(src) .unwrap() .push(index); } diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index c137fc503031a..c3d42f66d08b1 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -460,9 +460,9 @@ impl DirectedGraph for SimpleMapGraph { .for_each(|map| map.for_each_mut(HashMap::clear)); for (index, Edge(src, dst, _)) in &mut self.edges { - std::mem::swap(src, dst); - self.adjacencies[*dst].outgoing_mut().insert(*src, index); - self.adjacencies[*src].incoming_mut().insert(*dst, index); + std::mem::swap(src, dst); // *dst is now *src + self.adjacencies[*src].outgoing_mut().insert(*dst, index); + self.adjacencies[*dst].incoming_mut().insert(*src, index); } } @@ -470,9 +470,9 @@ impl DirectedGraph for SimpleMapGraph { if let Some(Edge(src, dst, _)) = self.edges.get_mut(index) { self.adjacencies[*src].outgoing_mut().remove(dst); self.adjacencies[*dst].incoming_mut().remove(src); - std::mem::swap(src, dst); - self.adjacencies[*dst].outgoing_mut().insert(*src, index); - self.adjacencies[*src].incoming_mut().insert(*dst, index); + std::mem::swap(src, dst); // *dst is now *src + self.adjacencies[*src].outgoing_mut().insert(*dst, index); + self.adjacencies[*dst].incoming_mut().insert(*src, index); } } diff --git a/crates/bevy_graph/tests/simple_list.rs b/crates/bevy_graph/tests/simple_list.rs index 725efec018cdd..91d1ae4eabc6e 100644 --- a/crates/bevy_graph/tests/simple_list.rs +++ b/crates/bevy_graph/tests/simple_list.rs @@ -2,7 +2,7 @@ use bevy_graph::{ graphs::{ keys::{EdgeIdx, NodeIdx}, list::SimpleListGraph, - Graph, + Graph, DirectedGraph, }, utils::wrapped_indices_iterator::WrappedIndicesIterator, }; @@ -93,3 +93,147 @@ fn undirected() { [no_friends_manny].into() ); } + +#[test] +fn directed() { + let mut graph = SimpleListGraph::<&str, i32, true>::new(); + + assert!(graph.is_directed()); + assert!(!graph.is_multigraph()); + + assert_eq!(graph.node_count(), 0); + let jakob = graph.add_node("Jakob"); + let edgar = graph.add_node("Edgar"); + let bernhard = graph.add_node("Bernhard"); + let no_friends_manny = graph.add_node("No Friends Manny"); + assert_eq!(graph.node_count(), 4); + + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(edgar)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + + assert_eq!(graph.find_node(&"Edgar"), Some(edgar)); + assert_eq!(graph.find_node(&"NoIReallyDon'tExist"), None); + + assert_eq!( + graph.node_indices().collect::>(), + [jakob, edgar, bernhard, no_friends_manny].into() + ); + + assert_eq!(graph.edge_count(), 0); + let je = graph.add_edge(jakob, edgar, 12); + let eb = graph.add_edge(edgar, bernhard, 7); + assert_eq!(graph.edge_count(), 2); + + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(!graph.contains_edge_between(edgar, jakob)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + + assert_eq!(graph.find_edge(&12), Some(je)); + assert_eq!(graph.find_edge(&0), None); + + assert_eq!( + graph.edge_indices().collect::>(), + [je, eb].into() + ); + + assert_eq!(graph.degree(jakob), 1); + assert_eq!(graph.degree(edgar), 2); + assert_eq!(graph.out_degree(edgar), 1); + assert_eq!(graph.in_degree(edgar), 1); + + assert_eq!( + graph + .edges_of(jakob) + .into_indices() + .collect::>(), + [je].into() + ); + assert_eq!( + graph + .edges_of(edgar) + .into_indices() + .collect::>(), + [je, eb].into() + ); + assert_eq!( + graph + .incoming_edges_of(edgar) + .into_indices() + .collect::>(), + [je].into() + ); + assert_eq!( + graph + .outgoing_edges_of(edgar) + .into_indices() + .collect::>(), + [eb].into() + ); + + assert_eq!( + graph + .neighbors(jakob) + .into_indices() + .collect::>(), + [edgar].into() + ); + assert_eq!( + graph + .neighbors(edgar) + .into_indices() + .collect::>(), + [jakob, bernhard].into() + ); + assert_eq!( + graph + .in_neighbors(edgar) + .into_indices() + .collect::>(), + [jakob].into() + ); + assert_eq!( + graph + .out_neighbors(edgar) + .into_indices() + .collect::>(), + [bernhard].into() + ); + + assert_eq!( + graph + .isolated() + .into_indices() + .collect::>(), + [no_friends_manny].into() + ); + + assert_eq!( + graph.sources().into_indices().collect::>(), + [jakob, no_friends_manny].into() + ); + assert_eq!( + graph.sinks().into_indices().collect::>(), + [bernhard, no_friends_manny].into() + ); + + graph.reverse(); + + assert_eq!( + graph.sinks().into_indices().collect::>(), + [jakob, no_friends_manny].into() + ); + assert_eq!( + graph.sources().into_indices().collect::>(), + [bernhard, no_friends_manny].into() + ); + + assert!(!graph.contains_edge_between(jakob, edgar)); + assert!(graph.contains_edge_between(edgar, jakob)); + + graph.reverse_edge(je); + + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(!graph.contains_edge_between(edgar, jakob)); +} diff --git a/crates/bevy_graph/tests/simple_map.rs b/crates/bevy_graph/tests/simple_map.rs index 15fc6dcb1662a..08413e48a7abf 100644 --- a/crates/bevy_graph/tests/simple_map.rs +++ b/crates/bevy_graph/tests/simple_map.rs @@ -2,7 +2,7 @@ use bevy_graph::{ graphs::{ keys::{EdgeIdx, NodeIdx}, map::SimpleMapGraph, - Graph, + DirectedGraph, Graph, }, utils::wrapped_indices_iterator::WrappedIndicesIterator, }; @@ -93,3 +93,147 @@ fn undirected() { [no_friends_manny].into() ); } + +#[test] +fn directed() { + let mut graph = SimpleMapGraph::<&str, i32, true>::new(); + + assert!(graph.is_directed()); + assert!(!graph.is_multigraph()); + + assert_eq!(graph.node_count(), 0); + let jakob = graph.add_node("Jakob"); + let edgar = graph.add_node("Edgar"); + let bernhard = graph.add_node("Bernhard"); + let no_friends_manny = graph.add_node("No Friends Manny"); + assert_eq!(graph.node_count(), 4); + + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(edgar)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + + assert_eq!(graph.find_node(&"Edgar"), Some(edgar)); + assert_eq!(graph.find_node(&"NoIReallyDon'tExist"), None); + + assert_eq!( + graph.node_indices().collect::>(), + [jakob, edgar, bernhard, no_friends_manny].into() + ); + + assert_eq!(graph.edge_count(), 0); + let je = graph.add_edge(jakob, edgar, 12); + let eb = graph.add_edge(edgar, bernhard, 7); + assert_eq!(graph.edge_count(), 2); + + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(!graph.contains_edge_between(edgar, jakob)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + + assert_eq!(graph.find_edge(&12), Some(je)); + assert_eq!(graph.find_edge(&0), None); + + assert_eq!( + graph.edge_indices().collect::>(), + [je, eb].into() + ); + + assert_eq!(graph.degree(jakob), 1); + assert_eq!(graph.degree(edgar), 2); + assert_eq!(graph.out_degree(edgar), 1); + assert_eq!(graph.in_degree(edgar), 1); + + assert_eq!( + graph + .edges_of(jakob) + .into_indices() + .collect::>(), + [je].into() + ); + assert_eq!( + graph + .edges_of(edgar) + .into_indices() + .collect::>(), + [je, eb].into() + ); + assert_eq!( + graph + .incoming_edges_of(edgar) + .into_indices() + .collect::>(), + [je].into() + ); + assert_eq!( + graph + .outgoing_edges_of(edgar) + .into_indices() + .collect::>(), + [eb].into() + ); + + assert_eq!( + graph + .neighbors(jakob) + .into_indices() + .collect::>(), + [edgar].into() + ); + assert_eq!( + graph + .neighbors(edgar) + .into_indices() + .collect::>(), + [jakob, bernhard].into() + ); + assert_eq!( + graph + .in_neighbors(edgar) + .into_indices() + .collect::>(), + [jakob].into() + ); + assert_eq!( + graph + .out_neighbors(edgar) + .into_indices() + .collect::>(), + [bernhard].into() + ); + + assert_eq!( + graph + .isolated() + .into_indices() + .collect::>(), + [no_friends_manny].into() + ); + + assert_eq!( + graph.sources().into_indices().collect::>(), + [jakob, no_friends_manny].into() + ); + assert_eq!( + graph.sinks().into_indices().collect::>(), + [bernhard, no_friends_manny].into() + ); + + graph.reverse(); + + assert_eq!( + graph.sinks().into_indices().collect::>(), + [jakob, no_friends_manny].into() + ); + assert_eq!( + graph.sources().into_indices().collect::>(), + [bernhard, no_friends_manny].into() + ); + + assert!(!graph.contains_edge_between(jakob, edgar)); + assert!(graph.contains_edge_between(edgar, jakob)); + + graph.reverse_edge(je); + + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(!graph.contains_edge_between(edgar, jakob)); +} From d3f356e74b7e56782348120a1a417bfac53b81c0 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sat, 28 Jan 2023 17:19:45 +0100 Subject: [PATCH 177/183] `remove_[node/edge]` tests and list fix --- crates/bevy_graph/src/graphs/list/simple.rs | 12 +++++- crates/bevy_graph/src/utils/vecmap.rs | 5 +-- crates/bevy_graph/tests/simple_list.rs | 41 ++++++++++++++++++++- crates/bevy_graph/tests/simple_map.rs | 39 ++++++++++++++++++++ 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index adc7a002f9b77..2c1366439da1e 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -149,9 +149,19 @@ impl Graph for SimpleListGraph .edges_of(index) .into_indices() .collect::>(); + println!("{:?}", self.adjacencies[index].incoming()); + println!("{:?}", self.adjacencies[index].outgoing()); + println!("{edges_to_remove:?}"); + println!( + "{:?}", + self.edges + .iter() + .map(|edge| edge.0) + .collect::>() + ); for edge_idx in edges_to_remove { unsafe { - let Edge(src, dst, _) = self.edges.remove(edge_idx).unwrap_unchecked(); + let Edge(src, dst, _) = self.edges.remove(edge_idx).unwrap(); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() diff --git a/crates/bevy_graph/src/utils/vecmap.rs b/crates/bevy_graph/src/utils/vecmap.rs index daf2d1cd9fcfa..f877d5f141c47 100644 --- a/crates/bevy_graph/src/utils/vecmap.rs +++ b/crates/bevy_graph/src/utils/vecmap.rs @@ -90,10 +90,7 @@ impl VecMap for Vec<(K, V)> { #[inline] fn index_by_key(&self, key: &K) -> Option { - match self.binary_search_by(|l| l.0.cmp(key)) { - Ok(index) => Some(index), - _ => None, - } + self.iter().position(|l| l.0.eq(key)) } fn remove_by_key(&mut self, key: K) -> Option { diff --git a/crates/bevy_graph/tests/simple_list.rs b/crates/bevy_graph/tests/simple_list.rs index 91d1ae4eabc6e..1ed5df31ee427 100644 --- a/crates/bevy_graph/tests/simple_list.rs +++ b/crates/bevy_graph/tests/simple_list.rs @@ -2,7 +2,7 @@ use bevy_graph::{ graphs::{ keys::{EdgeIdx, NodeIdx}, list::SimpleListGraph, - Graph, DirectedGraph, + DirectedGraph, Graph, }, utils::wrapped_indices_iterator::WrappedIndicesIterator, }; @@ -92,6 +92,25 @@ fn undirected() { .collect::>(), [no_friends_manny].into() ); + + assert!(graph.contains_edge_between(edgar, bernhard)); + graph.remove_edge(eb); + assert_eq!(graph.edge_count(), 1); + + assert!(!graph.contains_edge_between(edgar, bernhard)); + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(graph.contains_edge_between(edgar, jakob)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + + graph.remove_node(edgar); + assert_eq!(graph.node_count(), 3); + + assert!(!graph.contains_node(edgar)); + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + + assert_eq!(graph.edge_count(), 0); } #[test] @@ -236,4 +255,24 @@ fn directed() { assert!(graph.contains_edge_between(jakob, edgar)); assert!(!graph.contains_edge_between(edgar, jakob)); + + graph.reverse_edge(eb); // just for more readable tests - rereverse it + + assert!(graph.contains_edge_between(edgar, bernhard)); + graph.remove_edge(eb); + assert_eq!(graph.edge_count(), 1); + + assert!(!graph.contains_edge_between(edgar, bernhard)); + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + + graph.remove_node(edgar); + assert_eq!(graph.node_count(), 3); + + assert!(!graph.contains_node(edgar)); + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + + assert_eq!(graph.edge_count(), 0); } diff --git a/crates/bevy_graph/tests/simple_map.rs b/crates/bevy_graph/tests/simple_map.rs index 08413e48a7abf..858ad0c6f2bd4 100644 --- a/crates/bevy_graph/tests/simple_map.rs +++ b/crates/bevy_graph/tests/simple_map.rs @@ -92,6 +92,25 @@ fn undirected() { .collect::>(), [no_friends_manny].into() ); + + assert!(graph.contains_edge_between(edgar, bernhard)); + graph.remove_edge(eb); + assert_eq!(graph.edge_count(), 1); + + assert!(!graph.contains_edge_between(edgar, bernhard)); + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(graph.contains_edge_between(edgar, jakob)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + + graph.remove_node(edgar); + assert_eq!(graph.node_count(), 3); + + assert!(!graph.contains_node(edgar)); + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + + assert_eq!(graph.edge_count(), 0); } #[test] @@ -236,4 +255,24 @@ fn directed() { assert!(graph.contains_edge_between(jakob, edgar)); assert!(!graph.contains_edge_between(edgar, jakob)); + + graph.reverse_edge(eb); // just for more readable tests - rereverse it + + assert!(graph.contains_edge_between(edgar, bernhard)); + graph.remove_edge(eb); + assert_eq!(graph.edge_count(), 1); + + assert!(!graph.contains_edge_between(edgar, bernhard)); + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + + graph.remove_node(edgar); + assert_eq!(graph.node_count(), 3); + + assert!(!graph.contains_node(edgar)); + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + + assert_eq!(graph.edge_count(), 0); } From 1ca6cb3e60f57ba6dceb17379fd8161af6cbf685 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 29 Jan 2023 11:47:35 +0100 Subject: [PATCH 178/183] Big fixes --- crates/bevy_graph/src/graphs/list/multi.rs | 75 +++-- crates/bevy_graph/src/graphs/list/simple.rs | 12 +- crates/bevy_graph/src/graphs/map/multi.rs | 63 ++-- .../bevy_graph/src/iters/loop_safety_iter.rs | 53 +++- crates/bevy_graph/src/iters/mod.rs | 6 + .../src/iters/node_just_once_iter.rs | 39 +++ .../bevy_graph/src/iters/skip_index_iter.rs | 33 ++ crates/bevy_graph/tests/multi_map.rs | 295 ++++++++++++++++++ 8 files changed, 492 insertions(+), 84 deletions(-) create mode 100644 crates/bevy_graph/src/iters/node_just_once_iter.rs create mode 100644 crates/bevy_graph/src/iters/skip_index_iter.rs create mode 100644 crates/bevy_graph/tests/multi_map.rs diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 3784a8544d663..72da53a66b4a3 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -134,11 +134,10 @@ impl Graph for MultiListGraph } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - self.adjacencies - .get(src) - .unwrap() - .outgoing() - .contains_key(dst) + match self.adjacencies.get(src).unwrap().outgoing().get_value(dst) { + Some(adjacencies) => !adjacencies.is_empty(), + None => false, + } } fn remove_node(&mut self, index: NodeIdx) -> Option { @@ -305,43 +304,61 @@ impl Graph for MultiListGraph iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Flatten, iters::LoopSafetyIter<'e, &'e Vec, IterChoice<(&'e NodeIdx, &'e Vec), std::iter::Chain>, crate::utils::vecmap::TupleIter<'e, NodeIdx, Vec>>, crate::utils::vecmap::TupleIter<'e, NodeIdx, Vec>>>, false>>> where Self: 'e; + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Flatten, std::iter::Chain>, iters::SkipIndexIter<'e, &'e Vec, crate::utils::vecmap::TupleIter<'e, NodeIdx, Vec>>>, false>>, iters::LoopSafetyIter<'e, E, &'e EdgeIdx, std::iter::Flatten, crate::utils::vecmap::TupleIter<'e, NodeIdx, Vec>, false>>>>> where Self: 'e; fn edges_of(&self, index: NodeIdx) -> Self::EdgesOf<'_> { let inner = if DIRECTED { IterChoice::new_first( - self.adjacencies[index] - .incoming() - .tuple_iter() - .chain(self.adjacencies[index].outgoing().tuple_iter()), + iters::TupleExtract::new_second( + self.adjacencies[index].incoming().tuple_iter().chain( + iters::SkipIndexIter::new( + self.adjacencies[index].outgoing().tuple_iter(), + index, + ), // the outgoing will skip self to ensure loops will only come once (from incoming) + ), + ) + .flatten(), ) } else { - IterChoice::new_second(self.adjacencies[index].incoming().tuple_iter()) + IterChoice::new_second(iters::LoopSafetyIter::new( + iters::TupleExtract::new_second(self.adjacencies[index].incoming().tuple_iter()) + .flatten(), + &self.edges, + )) }; - iters::EdgesByIdx::new( - iters::TupleExtract::new_second(iters::LoopSafetyIter::new(inner, index)).flatten(), - &self.edges, - ) + iters::EdgesByIdx::new(inner, &self.edges) } - type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Flatten, iters::LoopSafetyIter<'e, &'e Vec, IterChoice<(&'e NodeIdx, &'e Vec), std::iter::Chain>, crate::utils::vecmap::TupleIter<'e, NodeIdx, Vec>>, crate::utils::vecmap::TupleIter<'e, NodeIdx, Vec>>>, false>>> where Self: 'e; + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Flatten, std::iter::Chain>, iters::SkipIndexIter<'e, &'e Vec, crate::utils::vecmap::TupleIter<'e, NodeIdx, Vec>>>, false>>, iters::LoopSafetyIter<'e, E, &'e EdgeIdx, std::iter::Flatten, crate::utils::vecmap::TupleIter<'e, NodeIdx, Vec>, false>>>>> where Self: 'e; fn edges_of_mut(&mut self, index: NodeIdx) -> Self::EdgesOfMut<'_> { let inner = if DIRECTED { IterChoice::new_first( - self.adjacencies[index] - .incoming() - .tuple_iter() - .chain(self.adjacencies[index].outgoing().tuple_iter()), + iters::TupleExtract::new_second( + self.adjacencies[index].incoming().tuple_iter().chain( + iters::SkipIndexIter::new( + self.adjacencies[index].outgoing().tuple_iter(), + index, + ), // the outgoing will skip self to ensure loops will only come once (from incoming) + ), + ) + .flatten(), ) } else { - IterChoice::new_second(self.adjacencies[index].incoming().tuple_iter()) + unsafe { + // SAFETY: it should be ok - no data will be removed + let ptr: *mut HopSlotMap> = &mut *(&mut self.edges); + IterChoice::new_second(iters::LoopSafetyIter::new( + iters::TupleExtract::new_second( + self.adjacencies[index].incoming().tuple_iter(), + ) + .flatten(), + &*ptr, + )) + } }; - iters::EdgesByIdxMut::new( - iters::TupleExtract::new_second(iters::LoopSafetyIter::new(inner, index)).flatten(), - &mut self.edges, - ) + iters::EdgesByIdxMut::new(inner, &mut self.edges) } - type Neighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, iters::TupleExtract<&'n NodeIdx, &'n Vec, iters::LoopSafetyIter<'n, &'n Vec, IterChoice<(&'n NodeIdx, &'n Vec), std::iter::Chain>, crate::utils::vecmap::TupleIter<'n, NodeIdx, Vec>>, crate::utils::vecmap::TupleIter<'n, NodeIdx, Vec>>>, true>> where Self: 'n; + type Neighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, iters::NodeJustOnceIter<&'n NodeIdx, iters::TupleExtract<&'n NodeIdx, &'n Vec, IterChoice<(&'n NodeIdx, &'n Vec), std::iter::Chain>, crate::utils::vecmap::TupleIter<'n, NodeIdx, Vec>>, crate::utils::vecmap::TupleIter<'n, NodeIdx, Vec>>, true>>> where Self: 'n; fn neighbors(&self, index: NodeIdx) -> Self::Neighbors<'_> { let inner = if DIRECTED { IterChoice::new_first( @@ -354,12 +371,12 @@ impl Graph for MultiListGraph IterChoice::new_second(self.adjacencies[index].incoming().tuple_iter()) }; iters::NodesByIdx::new( - iters::TupleExtract::new_first(iters::LoopSafetyIter::new(inner, index)), + iters::NodeJustOnceIter::new(iters::TupleExtract::new_first(inner)), &self.nodes, ) } - type NeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, iters::TupleExtract<&'n NodeIdx, &'n Vec, iters::LoopSafetyIter<'n, &'n Vec, IterChoice<(&'n NodeIdx, &'n Vec), std::iter::Chain>, crate::utils::vecmap::TupleIter<'n, NodeIdx, Vec>>, crate::utils::vecmap::TupleIter<'n, NodeIdx, Vec>>>, true>> where Self: 'n; + type NeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, iters::NodeJustOnceIter<&'n NodeIdx, iters::TupleExtract<&'n NodeIdx, &'n Vec, IterChoice<(&'n NodeIdx, &'n Vec), std::iter::Chain>, crate::utils::vecmap::TupleIter<'n, NodeIdx, Vec>>, crate::utils::vecmap::TupleIter<'n, NodeIdx, Vec>>, true>>> where Self: 'n; fn neighbors_mut(&mut self, index: NodeIdx) -> Self::NeighborsMut<'_> { let inner = if DIRECTED { IterChoice::new_first( @@ -372,7 +389,7 @@ impl Graph for MultiListGraph IterChoice::new_second(self.adjacencies[index].incoming().tuple_iter()) }; iters::NodesByIdxMut::new( - iters::TupleExtract::new_first(iters::LoopSafetyIter::new(inner, index)), + iters::NodeJustOnceIter::new(iters::TupleExtract::new_first(inner)), &mut self.nodes, ) } diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index 2c1366439da1e..adc7a002f9b77 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -149,19 +149,9 @@ impl Graph for SimpleListGraph .edges_of(index) .into_indices() .collect::>(); - println!("{:?}", self.adjacencies[index].incoming()); - println!("{:?}", self.adjacencies[index].outgoing()); - println!("{edges_to_remove:?}"); - println!( - "{:?}", - self.edges - .iter() - .map(|edge| edge.0) - .collect::>() - ); for edge_idx in edges_to_remove { unsafe { - let Edge(src, dst, _) = self.edges.remove(edge_idx).unwrap(); + let Edge(src, dst, _) = self.edges.remove(edge_idx).unwrap_unchecked(); self.adjacencies .get_unchecked_mut(src) .outgoing_mut() diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 774c0a1e94aa2..0abf936d1a5cd 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -137,11 +137,10 @@ impl Graph for MultiMapGraph { } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - self.adjacencies - .get(src) - .unwrap() - .outgoing() - .contains_key(&dst) + match self.adjacencies.get(src).unwrap().outgoing().get(&dst) { + Some(adjacencies) => !adjacencies.is_empty(), + None => false, + } } fn remove_node(&mut self, index: NodeIdx) -> Option { @@ -308,43 +307,49 @@ impl Graph for MultiMapGraph { iters::EdgesMut::new(self.edges.values_mut()) } - type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Flatten, iters::LoopSafetyIter<'e, &'e Vec, IterChoice<(&'e NodeIdx, &'e Vec), std::iter::Chain>, hashbrown::hash_map::Iter<'e, NodeIdx, Vec>>, hashbrown::hash_map::Iter<'e, NodeIdx, Vec>>>, false>>> where Self: 'e; + type EdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Flatten, std::iter::Chain>, iters::SkipIndexIter<'e, &'e Vec, hashbrown::hash_map::Iter<'e, NodeIdx, Vec>>>, false>>, iters::LoopSafetyIter<'e, E, &'e EdgeIdx, std::iter::Flatten, hashbrown::hash_map::Iter<'e, NodeIdx, Vec>, false>>>>> where Self: 'e; fn edges_of(&self, index: NodeIdx) -> Self::EdgesOf<'_> { let inner = if DIRECTED { IterChoice::new_first( - self.adjacencies[index] - .incoming() - .iter() - .chain(self.adjacencies[index].outgoing().iter()), + iters::TupleExtract::new_second(self.adjacencies[index].incoming().iter().chain( + iters::SkipIndexIter::new(self.adjacencies[index].outgoing().iter(), index), // the outgoing will skip self to ensure loops will only come once (from incoming) + )) + .flatten(), ) } else { - IterChoice::new_second(self.adjacencies[index].incoming().iter()) + IterChoice::new_second(iters::LoopSafetyIter::new( + iters::TupleExtract::new_second(self.adjacencies[index].incoming().iter()) + .flatten(), + &self.edges, + )) }; - iters::EdgesByIdx::new( - iters::TupleExtract::new_second(iters::LoopSafetyIter::new(inner, index)).flatten(), - &self.edges, - ) + iters::EdgesByIdx::new(inner, &self.edges) } - type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, std::iter::Flatten, iters::LoopSafetyIter<'e, &'e Vec, IterChoice<(&'e NodeIdx, &'e Vec), std::iter::Chain>, hashbrown::hash_map::Iter<'e, NodeIdx, Vec>>, hashbrown::hash_map::Iter<'e, NodeIdx, Vec>>>, false>>> where Self: 'e; + type EdgesOfMut<'e> = iters::EdgesByIdxMut<'e, E, &'e EdgeIdx, IterChoice<&'e EdgeIdx, std::iter::Flatten, std::iter::Chain>, iters::SkipIndexIter<'e, &'e Vec, hashbrown::hash_map::Iter<'e, NodeIdx, Vec>>>, false>>, iters::LoopSafetyIter<'e, E, &'e EdgeIdx, std::iter::Flatten, hashbrown::hash_map::Iter<'e, NodeIdx, Vec>, false>>>>> where Self: 'e; fn edges_of_mut(&mut self, index: NodeIdx) -> Self::EdgesOfMut<'_> { let inner = if DIRECTED { IterChoice::new_first( - self.adjacencies[index] - .incoming() - .iter() - .chain(self.adjacencies[index].outgoing().iter()), + iters::TupleExtract::new_second(self.adjacencies[index].incoming().iter().chain( + iters::SkipIndexIter::new(self.adjacencies[index].outgoing().iter(), index), // the outgoing will skip self to ensure loops will only come once (from incoming) + )) + .flatten(), ) } else { - IterChoice::new_second(self.adjacencies[index].incoming().iter()) + unsafe { + // SAFETY: it should be ok - no data will be removed + let ptr: *mut HopSlotMap> = &mut *(&mut self.edges); + IterChoice::new_second(iters::LoopSafetyIter::new( + iters::TupleExtract::new_second(self.adjacencies[index].incoming().iter()) + .flatten(), + &*ptr, + )) + } }; - iters::EdgesByIdxMut::new( - iters::TupleExtract::new_second(iters::LoopSafetyIter::new(inner, index)).flatten(), - &mut self.edges, - ) + iters::EdgesByIdxMut::new(inner, &mut self.edges) } - type Neighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, iters::TupleExtract<&'n NodeIdx, &'n Vec, iters::LoopSafetyIter<'n, &'n Vec, IterChoice<(&'n NodeIdx, &'n Vec), std::iter::Chain>, hashbrown::hash_map::Iter<'n, NodeIdx, Vec>>, hashbrown::hash_map::Iter<'n, NodeIdx, Vec>>>, true>> where Self: 'n; + type Neighbors<'n> = iters::NodesByIdx<'n, N, &'n NodeIdx, iters::NodeJustOnceIter<&'n NodeIdx, iters::TupleExtract<&'n NodeIdx, &'n Vec, IterChoice<(&'n NodeIdx, &'n Vec), std::iter::Chain>, hashbrown::hash_map::Iter<'n, NodeIdx, Vec>>, hashbrown::hash_map::Iter<'n, NodeIdx, Vec>>, true>>> where Self: 'n; fn neighbors(&self, index: NodeIdx) -> Self::Neighbors<'_> { let inner = if DIRECTED { IterChoice::new_first( @@ -357,12 +362,12 @@ impl Graph for MultiMapGraph { IterChoice::new_second(self.adjacencies[index].incoming().iter()) }; iters::NodesByIdx::new( - iters::TupleExtract::new_first(iters::LoopSafetyIter::new(inner, index)), + iters::NodeJustOnceIter::new(iters::TupleExtract::new_first(inner)), &self.nodes, ) } - type NeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, iters::TupleExtract<&'n NodeIdx, &'n Vec, iters::LoopSafetyIter<'n, &'n Vec, IterChoice<(&'n NodeIdx, &'n Vec), std::iter::Chain>, hashbrown::hash_map::Iter<'n, NodeIdx, Vec>>, hashbrown::hash_map::Iter<'n, NodeIdx, Vec>>>, true>> where Self: 'n; + type NeighborsMut<'n> = iters::NodesByIdxMut<'n, N, &'n NodeIdx, iters::NodeJustOnceIter<&'n NodeIdx, iters::TupleExtract<&'n NodeIdx, &'n Vec, IterChoice<(&'n NodeIdx, &'n Vec), std::iter::Chain>, hashbrown::hash_map::Iter<'n, NodeIdx, Vec>>, hashbrown::hash_map::Iter<'n, NodeIdx, Vec>>, true>>> where Self: 'n; fn neighbors_mut(&mut self, index: NodeIdx) -> Self::NeighborsMut<'_> { let inner = if DIRECTED { IterChoice::new_first( @@ -375,7 +380,7 @@ impl Graph for MultiMapGraph { IterChoice::new_second(self.adjacencies[index].incoming().iter()) }; iters::NodesByIdxMut::new( - iters::TupleExtract::new_first(iters::LoopSafetyIter::new(inner, index)), + iters::NodeJustOnceIter::new(iters::TupleExtract::new_first(inner)), &mut self.nodes, ) } diff --git a/crates/bevy_graph/src/iters/loop_safety_iter.rs b/crates/bevy_graph/src/iters/loop_safety_iter.rs index d61e1f31f4a1b..7227ac2b711b3 100644 --- a/crates/bevy_graph/src/iters/loop_safety_iter.rs +++ b/crates/bevy_graph/src/iters/loop_safety_iter.rs @@ -1,31 +1,54 @@ -use crate::graphs::keys::NodeIdx; +use std::borrow::Borrow; -/// Iterator which guarantees that loops will only come once by skipping itself in adjacencies -pub struct LoopSafetyIter<'g, V: 'g, I: Iterator> { - index_to_skip: NodeIdx, +use hashbrown::HashSet; +use slotmap::HopSlotMap; + +use crate::graphs::{edge::Edge, keys::EdgeIdx, Graph}; + +/// Iterator over `(&)EdgeIdx` which guarantees that loops will only come once +pub struct LoopSafetyIter<'g, E: 'g, B: Borrow, I: Iterator> { + edges: &'g HopSlotMap>, + loops: HashSet, inner: I, } -impl<'g, V: 'g, I: Iterator> LoopSafetyIter<'g, V, I> { - /// Creates a new `LoopSafetyIter` iterator with the provided `inner` iterator and the `NodeIdx` it should skip - pub fn new(inner: I, index_to_skip: NodeIdx) -> Self { +impl<'g, E: 'g, B: Borrow, I: Iterator> LoopSafetyIter<'g, E, B, I> { + /// Creates a new `LoopSafetyIter` iterator over a graph with the provided `inner` iterator + pub fn from_graph(inner: I, graph: &'g mut impl Graph) -> Self { + Self { + edges: unsafe { graph.edges_raw() }, + loops: HashSet::new(), + inner, + } + } + + /// Creates a new `LoopSafetyIter` iterator over a graph with the provided `inner` iterator + pub fn new(inner: I, edges: &'g HopSlotMap>) -> Self { Self { + edges, + loops: HashSet::new(), inner, - index_to_skip, } } } -impl<'g, V: 'g, I: Iterator> Iterator for LoopSafetyIter<'g, V, I> { - type Item = (&'g NodeIdx, V); +impl<'g, E: 'g, B: Borrow, I: Iterator> Iterator + for LoopSafetyIter<'g, E, B, I> +{ + type Item = B; fn next(&mut self) -> Option { - if let Some(i) = self.inner.next() { - if i.0 == &self.index_to_skip { - self.next() - } else { - Some(i) + if let Some(index) = self.inner.next() { + let edge_idx = *index.borrow(); + let Edge(src, dst, _) = unsafe { self.edges.get_unchecked(edge_idx) }; + if src == dst { + if self.loops.contains(&edge_idx) { + return self.next(); + } else { + self.loops.insert(edge_idx); + } } + Some(index) } else { None } diff --git a/crates/bevy_graph/src/iters/mod.rs b/crates/bevy_graph/src/iters/mod.rs index 1c5a129e06a2a..4bb0fc42c1965 100644 --- a/crates/bevy_graph/src/iters/mod.rs +++ b/crates/bevy_graph/src/iters/mod.rs @@ -28,8 +28,14 @@ pub use zip_out_degree::*; mod isolated; pub use isolated::*; +mod skip_index_iter; +pub use skip_index_iter::*; + mod loop_safety_iter; pub use loop_safety_iter::*; mod tuple_extract; pub use tuple_extract::*; + +mod node_just_once_iter; +pub use node_just_once_iter::*; diff --git a/crates/bevy_graph/src/iters/node_just_once_iter.rs b/crates/bevy_graph/src/iters/node_just_once_iter.rs new file mode 100644 index 0000000000000..e1622f8144694 --- /dev/null +++ b/crates/bevy_graph/src/iters/node_just_once_iter.rs @@ -0,0 +1,39 @@ +use std::borrow::Borrow; + +use hashbrown::HashSet; + +use crate::graphs::keys::NodeIdx; + +/// Iterator over `(&)NodeIdx` which guarantees that a value will only come once +pub struct NodeJustOnceIter, I: Iterator> { + duplicates: HashSet, + inner: I, +} + +impl, I: Iterator> NodeJustOnceIter { + /// Creates a new `NodeJustOnceIter` iterator over a graph with the provided `inner` iterator + pub fn new(inner: I) -> Self { + Self { + duplicates: HashSet::new(), + inner, + } + } +} + +impl, I: Iterator> Iterator for NodeJustOnceIter { + type Item = B; + + fn next(&mut self) -> Option { + if let Some(index) = self.inner.next() { + let node_idx = *index.borrow(); + if self.duplicates.contains(&node_idx) { + return self.next(); + } else { + self.duplicates.insert(node_idx); + } + Some(index) + } else { + None + } + } +} diff --git a/crates/bevy_graph/src/iters/skip_index_iter.rs b/crates/bevy_graph/src/iters/skip_index_iter.rs new file mode 100644 index 0000000000000..15ba68d3bf384 --- /dev/null +++ b/crates/bevy_graph/src/iters/skip_index_iter.rs @@ -0,0 +1,33 @@ +use crate::graphs::keys::NodeIdx; + +/// Iterator which guarantees that loops will only come once by skipping itself in adjacencies +pub struct SkipIndexIter<'g, V: 'g, I: Iterator> { + index_to_skip: NodeIdx, + inner: I, +} + +impl<'g, V: 'g, I: Iterator> SkipIndexIter<'g, V, I> { + /// Creates a new `LoopSafetyIter` iterator with the provided `inner` iterator and the `NodeIdx` it should skip + pub fn new(inner: I, index_to_skip: NodeIdx) -> Self { + Self { + inner, + index_to_skip, + } + } +} + +impl<'g, V: 'g, I: Iterator> Iterator for SkipIndexIter<'g, V, I> { + type Item = (&'g NodeIdx, V); + + fn next(&mut self) -> Option { + if let Some(i) = self.inner.next() { + if i.0 == &self.index_to_skip { + self.next() + } else { + Some(i) + } + } else { + None + } + } +} diff --git a/crates/bevy_graph/tests/multi_map.rs b/crates/bevy_graph/tests/multi_map.rs new file mode 100644 index 0000000000000..a6d146967ec40 --- /dev/null +++ b/crates/bevy_graph/tests/multi_map.rs @@ -0,0 +1,295 @@ +use bevy_graph::{ + graphs::{ + keys::{EdgeIdx, NodeIdx}, + map::MultiMapGraph, + DirectedGraph, Graph, + }, + utils::wrapped_indices_iterator::WrappedIndicesIterator, +}; +use hashbrown::HashSet; + +#[test] +fn undirected() { + let mut graph = MultiMapGraph::<&str, i32, false>::new(); + + assert!(!graph.is_directed()); + assert!(graph.is_multigraph()); + + assert_eq!(graph.node_count(), 0); + let jakob = graph.add_node("Jakob"); + let edgar = graph.add_node("Edgar"); + let bernhard = graph.add_node("Bernhard"); + let no_friends_manny = graph.add_node("No Friends Manny"); + let ego = graph.add_node("Ego"); + assert_eq!(graph.node_count(), 5); + + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(edgar)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + assert!(graph.contains_node(ego)); + + assert_eq!(graph.find_node(&"Edgar"), Some(edgar)); + assert_eq!(graph.find_node(&"NoIReallyDon'tExist"), None); + + assert_eq!( + graph.node_indices().collect::>(), + [jakob, edgar, bernhard, no_friends_manny, ego].into() + ); + + assert_eq!(graph.edge_count(), 0); + let je = graph.add_edge(jakob, edgar, 12); + let je2 = graph.add_edge(jakob, edgar, 2); + let eb = graph.add_edge(edgar, bernhard, 7); + let ego_self = graph.add_edge(ego, ego, 3); + assert_eq!(graph.edge_count(), 4); + + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(graph.contains_edge_between(edgar, jakob)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + assert!(graph.contains_edge_between(ego, ego)); + + assert_eq!(graph.find_edge(&12), Some(je)); + assert_eq!(graph.find_edge(&2), Some(je2)); + assert_eq!(graph.find_edge(&0), None); + + assert_eq!( + graph.edge_indices().collect::>(), + [je, je2, eb, ego_self].into() + ); + + //assert_eq!(graph.degree(jakob), 2); + //assert_eq!(graph.degree(edgar), 3); + + assert_eq!( + graph + .edges_of(jakob) + .into_indices() + .collect::>(), + [je, je2].into() + ); + assert_eq!( + graph + .edges_of(edgar) + .into_indices() + .collect::>(), + [je, je2, eb].into() + ); + + assert_eq!( + graph + .neighbors(jakob) + .into_indices() + .collect::>(), + [edgar].into() + ); + assert_eq!( + graph + .neighbors(edgar) + .into_indices() + .collect::>(), + [jakob, bernhard].into() + ); + + assert_eq!( + graph + .isolated() + .into_indices() + .collect::>(), + [no_friends_manny].into() + ); + + assert_eq!( + graph + .edges_of(ego) + .into_indices() + .collect::>(), + [ego_self].into() + ); + + assert!(graph.contains_edge_between(edgar, bernhard)); + graph.remove_edge(eb); + assert_eq!(graph.edge_count(), 3); + + assert!(!graph.contains_edge_between(edgar, bernhard)); + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(graph.contains_edge_between(edgar, jakob)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + assert!(graph.contains_edge_between(ego, ego)); + + graph.remove_node(edgar); + assert_eq!(graph.node_count(), 4); + + assert!(!graph.contains_node(edgar)); + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + assert!(graph.contains_node(ego)); + + assert_eq!(graph.edge_count(), 1); +} + +/*#[test] +fn directed() { + let mut graph = MultiMapGraph::<&str, i32, true>::new(); + + assert!(graph.is_directed()); + assert!(graph.is_multigraph()); + + assert_eq!(graph.node_count(), 0); + let jakob = graph.add_node("Jakob"); + let edgar = graph.add_node("Edgar"); + let bernhard = graph.add_node("Bernhard"); + let no_friends_manny = graph.add_node("No Friends Manny"); + assert_eq!(graph.node_count(), 4); + + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(edgar)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + + assert_eq!(graph.find_node(&"Edgar"), Some(edgar)); + assert_eq!(graph.find_node(&"NoIReallyDon'tExist"), None); + + assert_eq!( + graph.node_indices().collect::>(), + [jakob, edgar, bernhard, no_friends_manny].into() + ); + + assert_eq!(graph.edge_count(), 0); + let je = graph.add_edge(jakob, edgar, 12); + let eb = graph.add_edge(edgar, bernhard, 7); + assert_eq!(graph.edge_count(), 2); + + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(!graph.contains_edge_between(edgar, jakob)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + + assert_eq!(graph.find_edge(&12), Some(je)); + assert_eq!(graph.find_edge(&0), None); + + assert_eq!( + graph.edge_indices().collect::>(), + [je, eb].into() + ); + + assert_eq!(graph.degree(jakob), 1); + assert_eq!(graph.degree(edgar), 2); + assert_eq!(graph.out_degree(edgar), 1); + assert_eq!(graph.in_degree(edgar), 1); + + assert_eq!( + graph + .edges_of(jakob) + .into_indices() + .collect::>(), + [je].into() + ); + assert_eq!( + graph + .edges_of(edgar) + .into_indices() + .collect::>(), + [je, eb].into() + ); + assert_eq!( + graph + .incoming_edges_of(edgar) + .into_indices() + .collect::>(), + [je].into() + ); + assert_eq!( + graph + .outgoing_edges_of(edgar) + .into_indices() + .collect::>(), + [eb].into() + ); + + assert_eq!( + graph + .neighbors(jakob) + .into_indices() + .collect::>(), + [edgar].into() + ); + assert_eq!( + graph + .neighbors(edgar) + .into_indices() + .collect::>(), + [jakob, bernhard].into() + ); + assert_eq!( + graph + .in_neighbors(edgar) + .into_indices() + .collect::>(), + [jakob].into() + ); + assert_eq!( + graph + .out_neighbors(edgar) + .into_indices() + .collect::>(), + [bernhard].into() + ); + + assert_eq!( + graph + .isolated() + .into_indices() + .collect::>(), + [no_friends_manny].into() + ); + + assert_eq!( + graph.sources().into_indices().collect::>(), + [jakob, no_friends_manny].into() + ); + assert_eq!( + graph.sinks().into_indices().collect::>(), + [bernhard, no_friends_manny].into() + ); + + graph.reverse(); + + assert_eq!( + graph.sinks().into_indices().collect::>(), + [jakob, no_friends_manny].into() + ); + assert_eq!( + graph.sources().into_indices().collect::>(), + [bernhard, no_friends_manny].into() + ); + + assert!(!graph.contains_edge_between(jakob, edgar)); + assert!(graph.contains_edge_between(edgar, jakob)); + + graph.reverse_edge(je); + + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(!graph.contains_edge_between(edgar, jakob)); + + graph.reverse_edge(eb); // just for more readable tests - rereverse it + + assert!(graph.contains_edge_between(edgar, bernhard)); + graph.remove_edge(eb); + assert_eq!(graph.edge_count(), 1); + + assert!(!graph.contains_edge_between(edgar, bernhard)); + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + + graph.remove_node(edgar); + assert_eq!(graph.node_count(), 3); + + assert!(!graph.contains_node(edgar)); + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + + assert_eq!(graph.edge_count(), 0); +} +*/ From 2f23d10af76bc243f3746f078df74b5117273cda Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 29 Jan 2023 11:59:16 +0100 Subject: [PATCH 179/183] Fix everything --- crates/bevy_graph/src/graphs/list/multi.rs | 30 ++++++++++------ crates/bevy_graph/src/graphs/map/multi.rs | 34 ++++++++++++------ crates/bevy_graph/tests/multi_map.rs | 41 +++++++++++++--------- 3 files changed, 66 insertions(+), 39 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 72da53a66b4a3..3ace1dcca9544 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -254,7 +254,11 @@ impl Graph for MultiListGraph if DIRECTED { self.in_degree(index) + self.out_degree(index) } else { - self.adjacencies[index].incoming().len() + self.adjacencies[index] + .incoming() + .iter() + .map(|(_, vec)| vec.len()) + .sum() } } @@ -409,12 +413,20 @@ impl Graph for MultiListGraph #[inline] fn in_degree(&self, index: NodeIdx) -> usize { - self.adjacencies[index].incoming().len() + self.adjacencies[index] + .incoming() + .iter() + .map(|(_, vec)| vec.len()) + .sum() } #[inline] fn out_degree(&self, index: NodeIdx) -> usize { - self.adjacencies[index].outgoing().len() + self.adjacencies[index] + .outgoing() + .iter() + .map(|(_, vec)| vec.len()) + .sum() } type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Flatten>>> where Self: 'e; @@ -515,13 +527,11 @@ impl DirectedGraph for MultiListGraph { std::mem::swap(src, dst); // *dst is now *src self.adjacencies[*src] .outgoing_mut() - .get_value_mut(*dst) - .unwrap() + .get_value_or_default_mut(*dst) .push(index); self.adjacencies[*dst] .incoming_mut() - .get_value_mut(*src) - .unwrap() + .get_value_or_default_mut(*src) .push(index); } } @@ -541,13 +551,11 @@ impl DirectedGraph for MultiListGraph { std::mem::swap(src, dst); // *dst is now *src self.adjacencies[*src] .outgoing_mut() - .get_value_mut(*dst) - .unwrap() + .get_value_or_default_mut(*dst) .push(index); self.adjacencies[*dst] .incoming_mut() - .get_value_mut(*src) - .unwrap() + .get_value_or_default_mut(*src) .push(index); } } diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 0abf936d1a5cd..fdd91558f46fc 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -257,7 +257,11 @@ impl Graph for MultiMapGraph { if DIRECTED { self.in_degree(index) + self.out_degree(index) } else { - self.adjacencies[index].incoming().len() + self.adjacencies[index] + .incoming() + .iter() + .map(|(_, vec)| vec.len()) + .sum() } } @@ -400,12 +404,20 @@ impl Graph for MultiMapGraph { #[inline] fn in_degree(&self, index: NodeIdx) -> usize { - self.adjacencies[index].incoming().len() + self.adjacencies[index] + .incoming() + .iter() + .map(|(_, vec)| vec.len()) + .sum() } #[inline] fn out_degree(&self, index: NodeIdx) -> usize { - self.adjacencies[index].outgoing().len() + self.adjacencies[index] + .outgoing() + .iter() + .map(|(_, vec)| vec.len()) + .sum() } type IncomingEdgesOf<'e> = iters::EdgesByIdx<'e, E, &'e EdgeIdx, std::iter::Flatten>>> where Self: 'e; @@ -506,13 +518,13 @@ impl DirectedGraph for MultiMapGraph { std::mem::swap(src, dst); // *dst is now *src self.adjacencies[*src] .outgoing_mut() - .get_mut(dst) - .unwrap() + .entry(*dst) + .or_default() .push(index); self.adjacencies[*dst] .incoming_mut() - .get_mut(src) - .unwrap() + .entry(*src) + .or_default() .push(index); } } @@ -532,13 +544,13 @@ impl DirectedGraph for MultiMapGraph { std::mem::swap(src, dst); // *dst is now *src self.adjacencies[*src] .outgoing_mut() - .get_mut(dst) - .unwrap() + .entry(*dst) + .or_default() .push(index); self.adjacencies[*dst] .incoming_mut() - .get_mut(src) - .unwrap() + .entry(*src) + .or_default() .push(index); } } diff --git a/crates/bevy_graph/tests/multi_map.rs b/crates/bevy_graph/tests/multi_map.rs index a6d146967ec40..77894b214ecf2 100644 --- a/crates/bevy_graph/tests/multi_map.rs +++ b/crates/bevy_graph/tests/multi_map.rs @@ -58,8 +58,8 @@ fn undirected() { [je, je2, eb, ego_self].into() ); - //assert_eq!(graph.degree(jakob), 2); - //assert_eq!(graph.degree(edgar), 3); + assert_eq!(graph.degree(jakob), 2); + assert_eq!(graph.degree(edgar), 3); assert_eq!( graph @@ -129,7 +129,7 @@ fn undirected() { assert_eq!(graph.edge_count(), 1); } -/*#[test] +#[test] fn directed() { let mut graph = MultiMapGraph::<&str, i32, true>::new(); @@ -141,7 +141,8 @@ fn directed() { let edgar = graph.add_node("Edgar"); let bernhard = graph.add_node("Bernhard"); let no_friends_manny = graph.add_node("No Friends Manny"); - assert_eq!(graph.node_count(), 4); + let ego = graph.add_node("Ego"); + assert_eq!(graph.node_count(), 5); assert!(graph.contains_node(jakob)); assert!(graph.contains_node(edgar)); @@ -153,51 +154,55 @@ fn directed() { assert_eq!( graph.node_indices().collect::>(), - [jakob, edgar, bernhard, no_friends_manny].into() + [jakob, edgar, bernhard, no_friends_manny, ego].into() ); assert_eq!(graph.edge_count(), 0); let je = graph.add_edge(jakob, edgar, 12); + let je2 = graph.add_edge(jakob, edgar, 2); let eb = graph.add_edge(edgar, bernhard, 7); - assert_eq!(graph.edge_count(), 2); + let ego_self = graph.add_edge(ego, ego, 3); + assert_eq!(graph.edge_count(), 4); assert!(graph.contains_edge_between(jakob, edgar)); assert!(!graph.contains_edge_between(edgar, jakob)); assert!(!graph.contains_edge_between(jakob, bernhard)); + assert!(graph.contains_edge_between(ego, ego)); assert_eq!(graph.find_edge(&12), Some(je)); + assert_eq!(graph.find_edge(&2), Some(je2)); assert_eq!(graph.find_edge(&0), None); assert_eq!( graph.edge_indices().collect::>(), - [je, eb].into() + [je, je2, eb, ego_self].into() ); - assert_eq!(graph.degree(jakob), 1); - assert_eq!(graph.degree(edgar), 2); + assert_eq!(graph.degree(jakob), 2); + assert_eq!(graph.degree(edgar), 3); assert_eq!(graph.out_degree(edgar), 1); - assert_eq!(graph.in_degree(edgar), 1); + assert_eq!(graph.in_degree(edgar), 2); assert_eq!( graph .edges_of(jakob) .into_indices() .collect::>(), - [je].into() + [je, je2].into() ); assert_eq!( graph .edges_of(edgar) .into_indices() .collect::>(), - [je, eb].into() + [je, je2, eb].into() ); assert_eq!( graph .incoming_edges_of(edgar) .into_indices() .collect::>(), - [je].into() + [je, je2].into() ); assert_eq!( graph @@ -268,6 +273,7 @@ fn directed() { assert!(graph.contains_edge_between(edgar, jakob)); graph.reverse_edge(je); + graph.reverse_edge(je2); assert!(graph.contains_edge_between(jakob, edgar)); assert!(!graph.contains_edge_between(edgar, jakob)); @@ -276,20 +282,21 @@ fn directed() { assert!(graph.contains_edge_between(edgar, bernhard)); graph.remove_edge(eb); - assert_eq!(graph.edge_count(), 1); + assert_eq!(graph.edge_count(), 3); assert!(!graph.contains_edge_between(edgar, bernhard)); assert!(graph.contains_edge_between(jakob, edgar)); assert!(!graph.contains_edge_between(jakob, bernhard)); + assert!(graph.contains_edge_between(ego, ego)); graph.remove_node(edgar); - assert_eq!(graph.node_count(), 3); + assert_eq!(graph.node_count(), 4); assert!(!graph.contains_node(edgar)); assert!(graph.contains_node(jakob)); assert!(graph.contains_node(bernhard)); assert!(graph.contains_node(no_friends_manny)); + assert!(graph.contains_node(ego)); - assert_eq!(graph.edge_count(), 0); + assert_eq!(graph.edge_count(), 1); } -*/ From dc294ed9b8e2cbffba8ef33bf42db92afe51fbc2 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 29 Jan 2023 12:00:06 +0100 Subject: [PATCH 180/183] Add tests for `multi_list` --- crates/bevy_graph/tests/multi_list.rs | 302 ++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 crates/bevy_graph/tests/multi_list.rs diff --git a/crates/bevy_graph/tests/multi_list.rs b/crates/bevy_graph/tests/multi_list.rs new file mode 100644 index 0000000000000..88296e04f4124 --- /dev/null +++ b/crates/bevy_graph/tests/multi_list.rs @@ -0,0 +1,302 @@ +use bevy_graph::{ + graphs::{ + keys::{EdgeIdx, NodeIdx}, + list::MultiListGraph, + DirectedGraph, Graph, + }, + utils::wrapped_indices_iterator::WrappedIndicesIterator, +}; +use hashbrown::HashSet; + +#[test] +fn undirected() { + let mut graph = MultiListGraph::<&str, i32, false>::new(); + + assert!(!graph.is_directed()); + assert!(graph.is_multigraph()); + + assert_eq!(graph.node_count(), 0); + let jakob = graph.add_node("Jakob"); + let edgar = graph.add_node("Edgar"); + let bernhard = graph.add_node("Bernhard"); + let no_friends_manny = graph.add_node("No Friends Manny"); + let ego = graph.add_node("Ego"); + assert_eq!(graph.node_count(), 5); + + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(edgar)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + assert!(graph.contains_node(ego)); + + assert_eq!(graph.find_node(&"Edgar"), Some(edgar)); + assert_eq!(graph.find_node(&"NoIReallyDon'tExist"), None); + + assert_eq!( + graph.node_indices().collect::>(), + [jakob, edgar, bernhard, no_friends_manny, ego].into() + ); + + assert_eq!(graph.edge_count(), 0); + let je = graph.add_edge(jakob, edgar, 12); + let je2 = graph.add_edge(jakob, edgar, 2); + let eb = graph.add_edge(edgar, bernhard, 7); + let ego_self = graph.add_edge(ego, ego, 3); + assert_eq!(graph.edge_count(), 4); + + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(graph.contains_edge_between(edgar, jakob)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + assert!(graph.contains_edge_between(ego, ego)); + + assert_eq!(graph.find_edge(&12), Some(je)); + assert_eq!(graph.find_edge(&2), Some(je2)); + assert_eq!(graph.find_edge(&0), None); + + assert_eq!( + graph.edge_indices().collect::>(), + [je, je2, eb, ego_self].into() + ); + + assert_eq!(graph.degree(jakob), 2); + assert_eq!(graph.degree(edgar), 3); + + assert_eq!( + graph + .edges_of(jakob) + .into_indices() + .collect::>(), + [je, je2].into() + ); + assert_eq!( + graph + .edges_of(edgar) + .into_indices() + .collect::>(), + [je, je2, eb].into() + ); + + assert_eq!( + graph + .neighbors(jakob) + .into_indices() + .collect::>(), + [edgar].into() + ); + assert_eq!( + graph + .neighbors(edgar) + .into_indices() + .collect::>(), + [jakob, bernhard].into() + ); + + assert_eq!( + graph + .isolated() + .into_indices() + .collect::>(), + [no_friends_manny].into() + ); + + assert_eq!( + graph + .edges_of(ego) + .into_indices() + .collect::>(), + [ego_self].into() + ); + + assert!(graph.contains_edge_between(edgar, bernhard)); + graph.remove_edge(eb); + assert_eq!(graph.edge_count(), 3); + + assert!(!graph.contains_edge_between(edgar, bernhard)); + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(graph.contains_edge_between(edgar, jakob)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + assert!(graph.contains_edge_between(ego, ego)); + + graph.remove_node(edgar); + assert_eq!(graph.node_count(), 4); + + assert!(!graph.contains_node(edgar)); + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + assert!(graph.contains_node(ego)); + + assert_eq!(graph.edge_count(), 1); +} + +#[test] +fn directed() { + let mut graph = MultiListGraph::<&str, i32, true>::new(); + + assert!(graph.is_directed()); + assert!(graph.is_multigraph()); + + assert_eq!(graph.node_count(), 0); + let jakob = graph.add_node("Jakob"); + let edgar = graph.add_node("Edgar"); + let bernhard = graph.add_node("Bernhard"); + let no_friends_manny = graph.add_node("No Friends Manny"); + let ego = graph.add_node("Ego"); + assert_eq!(graph.node_count(), 5); + + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(edgar)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + + assert_eq!(graph.find_node(&"Edgar"), Some(edgar)); + assert_eq!(graph.find_node(&"NoIReallyDon'tExist"), None); + + assert_eq!( + graph.node_indices().collect::>(), + [jakob, edgar, bernhard, no_friends_manny, ego].into() + ); + + assert_eq!(graph.edge_count(), 0); + let je = graph.add_edge(jakob, edgar, 12); + let je2 = graph.add_edge(jakob, edgar, 2); + let eb = graph.add_edge(edgar, bernhard, 7); + let ego_self = graph.add_edge(ego, ego, 3); + assert_eq!(graph.edge_count(), 4); + + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(!graph.contains_edge_between(edgar, jakob)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + assert!(graph.contains_edge_between(ego, ego)); + + assert_eq!(graph.find_edge(&12), Some(je)); + assert_eq!(graph.find_edge(&2), Some(je2)); + assert_eq!(graph.find_edge(&0), None); + + assert_eq!( + graph.edge_indices().collect::>(), + [je, je2, eb, ego_self].into() + ); + + assert_eq!(graph.degree(jakob), 2); + assert_eq!(graph.degree(edgar), 3); + assert_eq!(graph.out_degree(edgar), 1); + assert_eq!(graph.in_degree(edgar), 2); + + assert_eq!( + graph + .edges_of(jakob) + .into_indices() + .collect::>(), + [je, je2].into() + ); + assert_eq!( + graph + .edges_of(edgar) + .into_indices() + .collect::>(), + [je, je2, eb].into() + ); + assert_eq!( + graph + .incoming_edges_of(edgar) + .into_indices() + .collect::>(), + [je, je2].into() + ); + assert_eq!( + graph + .outgoing_edges_of(edgar) + .into_indices() + .collect::>(), + [eb].into() + ); + + assert_eq!( + graph + .neighbors(jakob) + .into_indices() + .collect::>(), + [edgar].into() + ); + assert_eq!( + graph + .neighbors(edgar) + .into_indices() + .collect::>(), + [jakob, bernhard].into() + ); + assert_eq!( + graph + .in_neighbors(edgar) + .into_indices() + .collect::>(), + [jakob].into() + ); + assert_eq!( + graph + .out_neighbors(edgar) + .into_indices() + .collect::>(), + [bernhard].into() + ); + + assert_eq!( + graph + .isolated() + .into_indices() + .collect::>(), + [no_friends_manny].into() + ); + + assert_eq!( + graph.sources().into_indices().collect::>(), + [jakob, no_friends_manny].into() + ); + assert_eq!( + graph.sinks().into_indices().collect::>(), + [bernhard, no_friends_manny].into() + ); + + graph.reverse(); + + assert_eq!( + graph.sinks().into_indices().collect::>(), + [jakob, no_friends_manny].into() + ); + assert_eq!( + graph.sources().into_indices().collect::>(), + [bernhard, no_friends_manny].into() + ); + + assert!(!graph.contains_edge_between(jakob, edgar)); + assert!(graph.contains_edge_between(edgar, jakob)); + + graph.reverse_edge(je); + graph.reverse_edge(je2); + + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(!graph.contains_edge_between(edgar, jakob)); + + graph.reverse_edge(eb); // just for more readable tests - rereverse it + + assert!(graph.contains_edge_between(edgar, bernhard)); + graph.remove_edge(eb); + assert_eq!(graph.edge_count(), 3); + + assert!(!graph.contains_edge_between(edgar, bernhard)); + assert!(graph.contains_edge_between(jakob, edgar)); + assert!(!graph.contains_edge_between(jakob, bernhard)); + assert!(graph.contains_edge_between(ego, ego)); + + graph.remove_node(edgar); + assert_eq!(graph.node_count(), 4); + + assert!(!graph.contains_node(edgar)); + assert!(graph.contains_node(jakob)); + assert!(graph.contains_node(bernhard)); + assert!(graph.contains_node(no_friends_manny)); + assert!(graph.contains_node(ego)); + + assert_eq!(graph.edge_count(), 1); +} From 573ed2ea0ec30b929d3741c93935a6fec2c33d10 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Sun, 29 Jan 2023 12:05:52 +0100 Subject: [PATCH 181/183] the final clippy touches --- crates/bevy_graph/src/graphs/list/multi.rs | 2 +- crates/bevy_graph/src/graphs/map/multi.rs | 2 +- crates/bevy_graph/src/iters/loop_safety_iter.rs | 3 +-- crates/bevy_graph/src/iters/node_just_once_iter.rs | 3 +-- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 3ace1dcca9544..16c74d43e57cd 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -349,7 +349,7 @@ impl Graph for MultiListGraph } else { unsafe { // SAFETY: it should be ok - no data will be removed - let ptr: *mut HopSlotMap> = &mut *(&mut self.edges); + let ptr: *mut HopSlotMap> = &mut self.edges; IterChoice::new_second(iters::LoopSafetyIter::new( iters::TupleExtract::new_second( self.adjacencies[index].incoming().tuple_iter(), diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index fdd91558f46fc..9d7b2223b2e29 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -342,7 +342,7 @@ impl Graph for MultiMapGraph { } else { unsafe { // SAFETY: it should be ok - no data will be removed - let ptr: *mut HopSlotMap> = &mut *(&mut self.edges); + let ptr: *mut HopSlotMap> = &mut self.edges; IterChoice::new_second(iters::LoopSafetyIter::new( iters::TupleExtract::new_second(self.adjacencies[index].incoming().iter()) .flatten(), diff --git a/crates/bevy_graph/src/iters/loop_safety_iter.rs b/crates/bevy_graph/src/iters/loop_safety_iter.rs index 7227ac2b711b3..4a0693e190e1d 100644 --- a/crates/bevy_graph/src/iters/loop_safety_iter.rs +++ b/crates/bevy_graph/src/iters/loop_safety_iter.rs @@ -44,9 +44,8 @@ impl<'g, E: 'g, B: Borrow, I: Iterator> Iterator if src == dst { if self.loops.contains(&edge_idx) { return self.next(); - } else { - self.loops.insert(edge_idx); } + self.loops.insert(edge_idx); } Some(index) } else { diff --git a/crates/bevy_graph/src/iters/node_just_once_iter.rs b/crates/bevy_graph/src/iters/node_just_once_iter.rs index e1622f8144694..6407cb8e46fe4 100644 --- a/crates/bevy_graph/src/iters/node_just_once_iter.rs +++ b/crates/bevy_graph/src/iters/node_just_once_iter.rs @@ -28,9 +28,8 @@ impl, I: Iterator> Iterator for NodeJustOnceIter Date: Sat, 8 Jul 2023 18:48:20 +0000 Subject: [PATCH 182/183] Update BFS/DFS Safety comments --- crates/bevy_graph/src/algos/bfs.rs | 4 ++-- crates/bevy_graph/src/algos/dfs.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_graph/src/algos/bfs.rs b/crates/bevy_graph/src/algos/bfs.rs index 1235b9fd1a7e9..93706418ec3a2 100644 --- a/crates/bevy_graph/src/algos/bfs.rs +++ b/crates/bevy_graph/src/algos/bfs.rs @@ -59,7 +59,7 @@ impl<'g, N, E: 'g, G: Graph, I: Iterator>> visitor: fn(&'g G, NodeIdx) -> I, ) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { unsafe { - // SAFETY: We know `NodesByIdxMut` doesn't intercept (deletes nodes) at all. + // SAFETY: `BreadthFirstSearch` assueres that every node gets visited only once let ptr: *mut G = &mut *graph; let inner = Self::custom(&*ptr, start, visitor); @@ -86,7 +86,7 @@ impl<'g, N, E: 'g, G: Graph> BreadthFirstSearch<'g, N, E, G, G::OutgoingEd #[inline] pub fn new_mut(graph: &'g mut G, start: NodeIdx) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { unsafe { - // SAFETY: We know `NodesByIdxMut` doesn't intercept (deletes nodes) at all. + // SAFETY: `BreadthFirstSearch` assueres that every node gets visited only once let ptr: *mut G = &mut *graph; let inner = Self::new(&*ptr, start); diff --git a/crates/bevy_graph/src/algos/dfs.rs b/crates/bevy_graph/src/algos/dfs.rs index a8cd0a44b22ba..4327717142477 100644 --- a/crates/bevy_graph/src/algos/dfs.rs +++ b/crates/bevy_graph/src/algos/dfs.rs @@ -58,7 +58,7 @@ impl<'g, N, E: 'g, G: Graph, I: Iterator>> visitor: fn(&'g G, NodeIdx) -> I, ) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { unsafe { - // SAFETY: We know `NodesByIdxMut` doesn't intercept (deletes nodes) at all. + // SAFETY: `DepthFirstSearch` assueres that every node gets visited only once let ptr: *mut G = &mut *graph; let inner = Self::custom(&*ptr, start, visitor); @@ -83,7 +83,7 @@ impl<'g, N, E: 'g, G: Graph> DepthFirstSearch<'g, N, E, G, G::OutgoingEdge /// Creates a new `DepthFirstSearch` with a start node and the default visitor of `outgoing` wrapped inside an `NodesByIdxMut` iterator pub fn new_mut(graph: &'g mut G, start: NodeIdx) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { unsafe { - // SAFETY: We know `NodesByIdxMut` doesn't intercept (deletes nodes) at all. + // SAFETY: `DepthFirstSearch` assueres that every node gets visited only once let ptr: *mut G = &mut *graph; let inner = Self::new(&*ptr, start); From 4e9e959a6c33ecd52a8ef8c9698e1127771bdf67 Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Sat, 8 Jul 2023 19:00:31 +0000 Subject: [PATCH 183/183] fix: `contains_edge_between` panics no more --- crates/bevy_graph/src/graphs/list/multi.rs | 11 ++++++++--- crates/bevy_graph/src/graphs/list/simple.rs | 10 +++++----- crates/bevy_graph/src/graphs/map/multi.rs | 11 ++++++++--- crates/bevy_graph/src/graphs/map/simple.rs | 6 +++++- crates/bevy_graph/src/graphs/mod.rs | 4 +--- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/crates/bevy_graph/src/graphs/list/multi.rs b/crates/bevy_graph/src/graphs/list/multi.rs index 16c74d43e57cd..98e7cb3091ff8 100644 --- a/crates/bevy_graph/src/graphs/list/multi.rs +++ b/crates/bevy_graph/src/graphs/list/multi.rs @@ -134,9 +134,14 @@ impl Graph for MultiListGraph } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - match self.adjacencies.get(src).unwrap().outgoing().get_value(dst) { - Some(adjacencies) => !adjacencies.is_empty(), - None => false, + if let Some(a1) = self.adjacencies.get(src) { + if let Some(a2) = a1.outgoing().get_value(dst) { + !a2.is_empty() + } else { + false + } + } else { + false } } diff --git a/crates/bevy_graph/src/graphs/list/simple.rs b/crates/bevy_graph/src/graphs/list/simple.rs index adc7a002f9b77..8778ad494d351 100644 --- a/crates/bevy_graph/src/graphs/list/simple.rs +++ b/crates/bevy_graph/src/graphs/list/simple.rs @@ -136,11 +136,11 @@ impl Graph for SimpleListGraph } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - self.adjacencies - .get(src) - .unwrap() - .outgoing() - .contains_key(dst) + if let Some(a) = self.adjacencies.get(src) { + a.outgoing().contains_key(dst) + } else { + false + } } fn remove_node(&mut self, index: NodeIdx) -> Option { diff --git a/crates/bevy_graph/src/graphs/map/multi.rs b/crates/bevy_graph/src/graphs/map/multi.rs index 9d7b2223b2e29..dc4fa453a5ddd 100644 --- a/crates/bevy_graph/src/graphs/map/multi.rs +++ b/crates/bevy_graph/src/graphs/map/multi.rs @@ -137,9 +137,14 @@ impl Graph for MultiMapGraph { } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - match self.adjacencies.get(src).unwrap().outgoing().get(&dst) { - Some(adjacencies) => !adjacencies.is_empty(), - None => false, + if let Some(a1) = self.adjacencies.get(src) { + if let Some(a2) = a1.outgoing().get(&dst) { + !a2.is_empty() + } else { + false + } + } else { + false } } diff --git a/crates/bevy_graph/src/graphs/map/simple.rs b/crates/bevy_graph/src/graphs/map/simple.rs index c3d42f66d08b1..177c9c0736d1f 100644 --- a/crates/bevy_graph/src/graphs/map/simple.rs +++ b/crates/bevy_graph/src/graphs/map/simple.rs @@ -135,7 +135,11 @@ impl Graph for SimpleMapGraph } fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool { - self.adjacencies[src].outgoing().contains_key(&dst) + if let Some(a) = self.adjacencies.get(src) { + a.outgoing().contains_key(&dst) + } else { + false + } } fn remove_node(&mut self, index: NodeIdx) -> Option { diff --git a/crates/bevy_graph/src/graphs/mod.rs b/crates/bevy_graph/src/graphs/mod.rs index 933ab26554c67..003aa22e796ba 100644 --- a/crates/bevy_graph/src/graphs/mod.rs +++ b/crates/bevy_graph/src/graphs/mod.rs @@ -233,9 +233,7 @@ pub trait Graph { /// Returns `true` if an edge between the specified nodes exists. /// - /// # Panics - /// - /// Panics if `src` or `dst` do not exist. + /// NOTE: When `src` or `dst` node isn't present, `false` will be returned. fn contains_edge_between(&self, src: NodeIdx, dst: NodeIdx) -> bool; /// Removes the specified node from the graph, returning its value if it existed.