From 9664f1a31acea3f16ff81143c4fadcdb49b9b0e3 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Sat, 4 Jan 2025 01:35:42 +0100 Subject: [PATCH] fix: get rid of some indeterminism by using B-trees instead of hash maps I have replaced all instances of `HashMap<...>` with `BTreeMap<...>`, of `HashSet<...>` with `BTreeSet<...>`, and all the uses of the `Hash` trait with `Ord`. I have done a few manual tests and found the behavior to be deterministic between the GUI application launches. However, undoing an autoroute command and then manually executing it once again continues to produce variable results. I suppose this is because of some bug in the code where edits are applied. Hence, the issue https://codeberg.org/topola/topola/issues/46 is only partially resolved. --- crates/specctra-core/src/mesadata.rs | 20 ++++++++-------- crates/topola-egui/src/config.rs | 8 +++---- src/autorouter/ratsnest.rs | 6 ++--- src/autorouter/selection.rs | 12 +++++----- src/board/mod.rs | 14 +++++------ src/drawing/band.rs | 7 ++---- src/drawing/bend.rs | 2 +- src/drawing/dot.rs | 2 +- src/drawing/graph.rs | 2 +- src/drawing/seg.rs | 2 +- src/geometry/edit.rs | 35 ++++++++++++++------------- src/geometry/geometry.rs | 2 +- src/geometry/recording_with_rtree.rs | 29 +++++++++++----------- src/graph.rs | 20 +++++++++------- src/router/astar.rs | 36 +++++++++++++--------------- src/router/navmesh.rs | 13 +++++----- src/specctra/design.rs | 11 +++++---- 17 files changed, 110 insertions(+), 111 deletions(-) diff --git a/crates/specctra-core/src/mesadata.rs b/crates/specctra-core/src/mesadata.rs index cef56d4..dd51d27 100644 --- a/crates/specctra-core/src/mesadata.rs +++ b/crates/specctra-core/src/mesadata.rs @@ -5,8 +5,8 @@ //! Module for handling Specctra's mesadata - design rules, as well as layers //! or net properties -use bimap::BiHashMap; -use std::collections::HashMap; +use bimap::BiBTreeMap; +use std::collections::BTreeMap; use crate::{ rules::{AccessRules, Conditions}, @@ -74,22 +74,22 @@ pub struct SpecctraMesadata { // net class name -> rule /// A map from net class names to their specific `SpecctraRule` constraints. /// These rules are applied to all nets belonging to the respective net clas - class_rules: HashMap, + class_rules: BTreeMap, // layername <-> layer for Layout /// A bidirectional map between layer indices and layer names, allowing translation /// between index-based layers in the layout and user-defined layer names. - pub layer_layername: BiHashMap, + pub layer_layername: BiBTreeMap, // netname <-> net for Layout /// A bidirectional map between network indices and network names in the PCB layout, /// providing an easy way to reference nets by name or index. - pub net_netname: BiHashMap, + pub net_netname: BiBTreeMap, // net -> netclass /// A map that associates network indices with their respective net class names. /// This is used to apply net class-specific routing rules to each net. - net_netclass: HashMap, + net_netclass: BTreeMap, } impl SpecctraMesadata { @@ -98,7 +98,7 @@ impl SpecctraMesadata { /// This function extracts the necessary metadata from the `Pcb` struct, such as /// layer-to-layer name mappings, net-to-net name mappings, and net class rules. pub fn from_pcb(pcb: &Pcb) -> Self { - let layer_layername = BiHashMap::from_iter( + let layer_layername = BiBTreeMap::from_iter( pcb.structure .layers .iter() @@ -119,11 +119,11 @@ impl SpecctraMesadata { tmp.sort_unstable(); tmp.dedup(); - BiHashMap::from_iter(tmp.into_iter().cloned().enumerate()) + BiBTreeMap::from_iter(tmp.into_iter().cloned().enumerate()) }; - let mut net_netclass = HashMap::new(); - let class_rules = HashMap::from_iter( + let mut net_netclass = BTreeMap::new(); + let class_rules = BTreeMap::from_iter( pcb.network .classes .iter() diff --git a/crates/topola-egui/src/config.rs b/crates/topola-egui/src/config.rs index ca361b8..84cef2c 100644 --- a/crates/topola-egui/src/config.rs +++ b/crates/topola-egui/src/config.rs @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -use std::collections::HashMap; +use std::collections::BTreeMap; #[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(default)] @@ -28,7 +28,7 @@ pub struct Colors { #[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)] pub struct LayerColors { default: LayerColor, - colors: HashMap, + colors: BTreeMap, } impl LayerColors { @@ -54,7 +54,7 @@ impl Default for Config { normal: egui::Color32::from_rgb(255, 255, 255), highlighted: egui::Color32::from_rgb(255, 255, 255), }, - colors: HashMap::from([ + colors: BTreeMap::from([ ( "F.Cu".to_string(), LayerColor { @@ -106,7 +106,7 @@ impl Default for Config { normal: egui::Color32::from_rgb(0, 0, 0), highlighted: egui::Color32::from_rgb(0, 0, 0), }, - colors: HashMap::from([ + colors: BTreeMap::from([ ( "F.Cu".to_string(), LayerColor { diff --git a/src/autorouter/ratsnest.rs b/src/autorouter/ratsnest.rs index 14cecaf..6b7b1dc 100644 --- a/src/autorouter/ratsnest.rs +++ b/src/autorouter/ratsnest.rs @@ -7,7 +7,7 @@ //! structures for representing graph nodes and edges with associated metadata, //! as well as functions for constructing and manipulating these graphs. -use std::collections::HashMap; +use std::collections::BTreeMap; use enum_dispatch::enum_dispatch; use geo::Point; @@ -27,7 +27,7 @@ use crate::{ primitive::MakePrimitiveShape, rules::AccessRules, }, - geometry::{compound::ManageCompounds, shape::AccessShape}, + geometry::shape::AccessShape, graph::{GenericIndex, GetPetgraphIndex}, layout::{ poly::{MakePolyShape, PolyWeight}, @@ -92,7 +92,7 @@ impl Ratsnest { graph: UnGraph::default(), }; - let mut triangulations = HashMap::new(); + let mut triangulations = BTreeMap::new(); let node_bound = layout.drawing().geometry().graph().node_bound(); for layer in 0..layout.drawing().layer_count() { diff --git a/src/autorouter/selection.rs b/src/autorouter/selection.rs index f378bf0..8b8fb01 100644 --- a/src/autorouter/selection.rs +++ b/src/autorouter/selection.rs @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -use std::collections::HashSet; +use std::collections::BTreeSet; use rstar::AABB; use serde::{Deserialize, Serialize}; @@ -10,12 +10,12 @@ use serde::{Deserialize, Serialize}; use crate::{ board::{mesadata::AccessMesadata, BandName, Board}, drawing::graph::{GetLayer, MakePrimitive, PrimitiveIndex}, - geometry::{compound::ManageCompounds, GenericNode}, + geometry::GenericNode, graph::{GenericIndex, GetPetgraphIndex}, layout::{poly::PolyWeight, CompoundWeight, NodeIndex}, }; -#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] pub struct PinSelector { pub pin: String, pub layer: String, @@ -58,7 +58,7 @@ impl PinSelector { } #[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct PinSelection(HashSet); +pub struct PinSelection(BTreeSet); impl PinSelection { pub fn new() -> Self { @@ -87,7 +87,7 @@ impl PinSelection { } } -#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] pub struct BandSelector { pub band: BandName, } @@ -118,7 +118,7 @@ impl BandSelector { } #[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct BandSelection(HashSet); +pub struct BandSelection(BTreeSet); impl BandSelection { pub fn new() -> Self { diff --git a/src/board/mod.rs b/src/board/mod.rs index 8916e59..d1f0fe9 100644 --- a/src/board/mod.rs +++ b/src/board/mod.rs @@ -10,9 +10,9 @@ pub mod mesadata { pub use specctra_core::mesadata::AccessMesadata; } -use std::{cmp::Ordering, collections::HashMap}; +use std::{cmp::Ordering, collections::BTreeMap}; -use bimap::BiHashMap; +use bimap::BiBTreeMap; use derive_getters::Getters; use serde::{Deserialize, Serialize}; @@ -35,7 +35,7 @@ use crate::{ }; /// Represents a band between two pins. -#[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, Deserialize, Eq, PartialOrd, Ord, PartialEq, Serialize)] pub struct BandName(String, String); impl BandName { @@ -60,9 +60,9 @@ pub struct Board { layout: Layout, // TODO: Simplify access logic to these members so that `#[getter(skip)]`s can be removed. #[getter(skip)] - node_to_pinname: HashMap, + node_to_pinname: BTreeMap, #[getter(skip)] - band_bandname: BiHashMap, + band_bandname: BiBTreeMap, } impl Board { @@ -70,8 +70,8 @@ impl Board { pub fn new(layout: Layout) -> Self { Self { layout, - node_to_pinname: HashMap::new(), - band_bandname: BiHashMap::new(), + node_to_pinname: BTreeMap::new(), + band_bandname: BiBTreeMap::new(), } } diff --git a/src/drawing/band.rs b/src/drawing/band.rs index 025ad09..6e3af7e 100644 --- a/src/drawing/band.rs +++ b/src/drawing/band.rs @@ -2,9 +2,6 @@ // // SPDX-License-Identifier: MIT -// FIXME (implement Hash for BandUid and such) -#![allow(clippy::derived_hash_with_manual_eq)] - use enum_dispatch::enum_dispatch; use petgraph::stable_graph::NodeIndex; @@ -22,7 +19,7 @@ use super::{ Drawing, }; -#[derive(Debug, Hash, Clone, Copy)] +#[derive(Clone, Copy, Debug, Ord, PartialOrd)] pub struct BandUid(pub BandTermsegIndex, pub BandTermsegIndex); impl BandUid { @@ -45,7 +42,7 @@ impl PartialEq for BandUid { impl Eq for BandUid {} #[enum_dispatch(GetPetgraphIndex)] -#[derive(Debug, Hash, Clone, Copy)] +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum BandTermsegIndex { Straight(LoneLooseSegIndex), Bended(SeqLooseSegIndex), diff --git a/src/drawing/bend.rs b/src/drawing/bend.rs index e98a875..119d9b3 100644 --- a/src/drawing/bend.rs +++ b/src/drawing/bend.rs @@ -18,7 +18,7 @@ use crate::{ use petgraph::stable_graph::NodeIndex; #[enum_dispatch(GetPetgraphIndex, MakePrimitive)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum BendIndex { Fixed(FixedBendIndex), Loose(LooseBendIndex), diff --git a/src/drawing/dot.rs b/src/drawing/dot.rs index 169b40e..f48925d 100644 --- a/src/drawing/dot.rs +++ b/src/drawing/dot.rs @@ -20,7 +20,7 @@ use crate::{ }; #[enum_dispatch(GetPetgraphIndex, MakePrimitive)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum DotIndex { Fixed(FixedDotIndex), Loose(LooseDotIndex), diff --git a/src/drawing/graph.rs b/src/drawing/graph.rs index 3ecfdde..42c10fe 100644 --- a/src/drawing/graph.rs +++ b/src/drawing/graph.rs @@ -89,7 +89,7 @@ macro_rules! impl_loose_weight { // TODO: This enum shouldn't exist: we shouldn't be carrying the tag around like this. Instead we // should be getting it from the graph when it's needed. #[enum_dispatch(GetPetgraphIndex, MakePrimitive)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum PrimitiveIndex { FixedDot(FixedDotIndex), LooseDot(LooseDotIndex), diff --git a/src/drawing/seg.rs b/src/drawing/seg.rs index 0aebdf2..5d35507 100644 --- a/src/drawing/seg.rs +++ b/src/drawing/seg.rs @@ -18,7 +18,7 @@ use crate::{ use petgraph::stable_graph::NodeIndex; #[enum_dispatch(GetPetgraphIndex, MakePrimitive)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum SegIndex { Fixed(FixedSegIndex), LoneLoose(LoneLooseSegIndex), diff --git a/src/geometry/edit.rs b/src/geometry/edit.rs index 2e9e1f4..a2013f4 100644 --- a/src/geometry/edit.rs +++ b/src/geometry/edit.rs @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -use std::{collections::HashMap, hash::Hash, marker::PhantomData}; +use std::{collections::BTreeMap, marker::PhantomData}; use crate::{ drawing::graph::{GetLayer, Retag}, @@ -17,10 +17,10 @@ pub trait ApplyGeometryEdit< SW: AccessSegWeight + GetLayer, BW: AccessBendWeight + GetLayer, CW: Copy, - PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Hash + Copy, - DI: GetPetgraphIndex + Into + Eq + Hash + Copy, - SI: GetPetgraphIndex + Into + Eq + Hash + Copy, - BI: GetPetgraphIndex + Into + Eq + Hash + Copy, + PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Ord + Copy, + DI: GetPetgraphIndex + Into + Eq + Ord + Copy, + SI: GetPetgraphIndex + Into + Eq + Ord + Copy, + BI: GetPetgraphIndex + Into + Eq + Ord + Copy, > { fn apply(&mut self, edit: &GeometryEdit); @@ -28,10 +28,11 @@ pub trait ApplyGeometryEdit< #[derive(Debug, Clone)] pub struct GeometryEdit { - pub(super) dots: HashMap, Option)>, - pub(super) segs: HashMap, Option<((DI, DI), SW)>)>, - pub(super) bends: HashMap, Option<((DI, DI, DI), BW)>)>, - pub(super) compounds: HashMap, (Option<(Vec, CW)>, Option<(Vec, CW)>)>, + pub(super) dots: BTreeMap, Option)>, + pub(super) segs: BTreeMap, Option<((DI, DI), SW)>)>, + pub(super) bends: BTreeMap, Option<((DI, DI, DI), BW)>)>, + pub(super) compounds: + BTreeMap, (Option<(Vec, CW)>, Option<(Vec, CW)>)>, primitive_weight_marker: PhantomData, } @@ -41,18 +42,18 @@ impl< SW: AccessSegWeight + GetLayer, BW: AccessBendWeight + GetLayer, CW: Copy, - PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Hash + Copy, - DI: GetPetgraphIndex + Into + Eq + Hash + Copy, - SI: GetPetgraphIndex + Into + Eq + Hash + Copy, - BI: GetPetgraphIndex + Into + Eq + Hash + Copy, + PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Ord + Copy, + DI: GetPetgraphIndex + Into + Eq + Ord + Copy, + SI: GetPetgraphIndex + Into + Eq + Ord + Copy, + BI: GetPetgraphIndex + Into + Eq + Ord + Copy, > GeometryEdit { pub fn new() -> Self { Self { - dots: HashMap::new(), - segs: HashMap::new(), - bends: HashMap::new(), - compounds: HashMap::new(), + dots: BTreeMap::new(), + segs: BTreeMap::new(), + bends: BTreeMap::new(), + compounds: BTreeMap::new(), primitive_weight_marker: PhantomData, } } diff --git a/src/geometry/geometry.rs b/src/geometry/geometry.rs index 5846bb5..8bdda13 100644 --- a/src/geometry/geometry.rs +++ b/src/geometry/geometry.rs @@ -64,7 +64,7 @@ pub enum GeometryLabel { Compound, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] pub enum GenericNode { Primitive(P), Compound(C), diff --git a/src/geometry/recording_with_rtree.rs b/src/geometry/recording_with_rtree.rs index 39903f6..ab213ee 100644 --- a/src/geometry/recording_with_rtree.rs +++ b/src/geometry/recording_with_rtree.rs @@ -2,8 +2,7 @@ // // SPDX-License-Identifier: MIT -use std::collections::hash_map::Entry as HashMapEntry; -use std::hash::Hash; +use std::collections::btree_map::Entry as BTreeMapEntry; use geo::Point; use petgraph::stable_graph::StableDiGraph; @@ -33,10 +32,10 @@ impl< SW: AccessSegWeight + GetLayer, BW: AccessBendWeight + GetLayer, CW: Copy, - PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Hash + Copy, - DI: GetPetgraphIndex + Into + Eq + Hash + Copy, - SI: GetPetgraphIndex + Into + Eq + Hash + Copy, - BI: GetPetgraphIndex + Into + Eq + Hash + Copy, + PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Ord + Copy, + DI: GetPetgraphIndex + Into + Eq + Ord + Copy, + SI: GetPetgraphIndex + Into + Eq + Ord + Copy, + BI: GetPetgraphIndex + Into + Eq + Ord + Copy, > RecordingGeometryWithRtree { pub fn new(layer_count: usize) -> Self { @@ -316,23 +315,23 @@ impl< } } -fn edit_remove_from_map( - map: &mut std::collections::HashMap, Option)>, +fn edit_remove_from_map( + map: &mut std::collections::BTreeMap, Option)>, index: I, data: T, ) where - I: core::cmp::Eq + Hash, + I: core::cmp::Eq + Ord, { let to_be_inserted = (Some(data), None); match map.entry(index) { - HashMapEntry::Occupied(mut occ) => { + BTreeMapEntry::Occupied(mut occ) => { if let (None, Some(_)) = occ.get() { occ.remove(); } else { *occ.get_mut() = to_be_inserted; } } - HashMapEntry::Vacant(vac) => { + BTreeMapEntry::Vacant(vac) => { vac.insert(to_be_inserted); } } @@ -344,10 +343,10 @@ impl< SW: AccessSegWeight + GetLayer, BW: AccessBendWeight + GetLayer, CW: Copy, - PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Hash + Copy, - DI: GetPetgraphIndex + Into + Eq + Hash + Copy, - SI: GetPetgraphIndex + Into + Eq + Hash + Copy, - BI: GetPetgraphIndex + Into + Eq + Hash + Copy, + PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Ord + Copy, + DI: GetPetgraphIndex + Into + Eq + Ord + Copy, + SI: GetPetgraphIndex + Into + Eq + Ord + Copy, + BI: GetPetgraphIndex + Into + Eq + Ord + Copy, > ApplyGeometryEdit for RecordingGeometryWithRtree { diff --git a/src/graph.rs b/src/graph.rs index 492d5e1..d0ed84d 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -2,10 +2,7 @@ // // SPDX-License-Identifier: MIT -use std::{ - hash::{Hash, Hasher}, - marker::PhantomData, -}; +use std::{cmp::Ordering, marker::PhantomData}; use enum_dispatch::enum_dispatch; use petgraph::stable_graph::NodeIndex; @@ -50,6 +47,8 @@ impl core::clone::Clone for GenericIndex { } } +impl core::marker::Copy for GenericIndex {} + impl core::fmt::Debug for GenericIndex { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("GenericIndex") @@ -65,12 +64,17 @@ impl PartialEq for GenericIndex { } } -impl core::marker::Copy for GenericIndex {} impl Eq for GenericIndex {} -impl Hash for GenericIndex { - fn hash(&self, state: &mut H) { - self.node_index.hash(state) +impl PartialOrd for GenericIndex { + fn partial_cmp(&self, other: &Self) -> Option { + self.node_index.partial_cmp(&other.node_index) + } +} + +impl Ord for GenericIndex { + fn cmp(&self, other: &Self) -> Ordering { + self.node_index.cmp(&other.node_index) } } diff --git a/src/router/astar.rs b/src/router/astar.rs index f50b81b..5886c7e 100644 --- a/src/router/astar.rs +++ b/src/router/astar.rs @@ -3,10 +3,8 @@ // // SPDX-License-Identifier: MIT -use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::collections::{BinaryHeap, HashMap, VecDeque}; +use std::collections::{btree_map::Entry, BTreeMap, BinaryHeap, VecDeque}; -use std::hash::Hash; use std::ops::ControlFlow; use petgraph::algo::Measure; @@ -63,19 +61,19 @@ impl Ord for MinScored { pub struct PathTracker where G: GraphBase, - G::NodeId: Eq + Hash, + G::NodeId: Eq + Ord, { - came_from: HashMap, + came_from: BTreeMap, } impl PathTracker where G: GraphBase, - G::NodeId: Eq + Hash, + G::NodeId: Eq + Ord, { fn new() -> PathTracker { PathTracker { - came_from: HashMap::new(), + came_from: BTreeMap::new(), } } @@ -101,7 +99,7 @@ where pub trait AstarStrategy where G: GraphBase, - G::NodeId: Eq + Hash, + G::NodeId: Eq + Ord, for<'a> &'a G: IntoEdges + MakeEdgeRef, K: Measure + Copy, { @@ -122,14 +120,14 @@ pub trait MakeEdgeRef: IntoEdgeReferences { pub struct Astar where G: GraphBase, - G::NodeId: Eq + Hash, + G::NodeId: Eq + Ord, for<'a> &'a G: IntoEdges + MakeEdgeRef, K: Measure + Copy, { pub graph: G, pub visit_next: BinaryHeap>, - pub scores: HashMap, - pub estimate_scores: HashMap, + pub scores: BTreeMap, + pub estimate_scores: BTreeMap, pub path_tracker: PathTracker, pub maybe_curr_node: Option, // FIXME: To work around edge references borrowing from the graph we collect then reiterate over tem. @@ -154,7 +152,7 @@ pub enum AstarError { impl Astar where G: GraphBase, - G::NodeId: Eq + Hash, + G::NodeId: Eq + Ord, for<'a> &'a G: IntoEdges + MakeEdgeRef, K: Measure + Copy, { @@ -162,8 +160,8 @@ where let mut this = Self { graph, visit_next: BinaryHeap::new(), - scores: HashMap::new(), - estimate_scores: HashMap::new(), + scores: BTreeMap::new(), + estimate_scores: BTreeMap::new(), path_tracker: PathTracker::::new(), maybe_curr_node: None, edge_ids: VecDeque::new(), @@ -182,7 +180,7 @@ impl> Step, R), AstarCo for Astar where G: GraphBase, - G::NodeId: Eq + Hash, + G::NodeId: Eq + Ord, for<'a> &'a G: IntoEdges + MakeEdgeRef, K: Measure + Copy, { @@ -209,7 +207,7 @@ where let next_score = node_score + edge_cost; match self.scores.entry(next) { - Occupied(mut entry) => { + Entry::Occupied(mut entry) => { // No need to add neighbors that we have already reached through a // shorter path than now. if *entry.get() <= next_score { @@ -217,7 +215,7 @@ where } entry.insert(next_score); } - Vacant(entry) => { + Entry::Vacant(entry) => { entry.insert(next_score); } } @@ -248,7 +246,7 @@ where } match self.estimate_scores.entry(node) { - Occupied(mut entry) => { + Entry::Occupied(mut entry) => { // If the node has already been visited with an equal or lower score than // now, then we do not need to re-visit it. if *entry.get() <= estimate_score { @@ -256,7 +254,7 @@ where } entry.insert(estimate_score); } - Vacant(entry) => { + Entry::Vacant(entry) => { entry.insert(estimate_score); } } diff --git a/src/router/navmesh.rs b/src/router/navmesh.rs index 952719f..a4d3195 100644 --- a/src/router/navmesh.rs +++ b/src/router/navmesh.rs @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -use std::collections::HashMap; +use std::collections::BTreeMap; use enum_dispatch::enum_dispatch; use geo::Point; @@ -37,7 +37,7 @@ use crate::{ use super::RouterOptions; -#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct NavvertexIndex(NodeIndex); impl GetPetgraphIndex for NavvertexIndex { @@ -50,7 +50,7 @@ impl GetPetgraphIndex for NavvertexIndex { /// counterclockwise. Unlike their constituents, binavvertices are themselves /// not considered navvertices. #[enum_dispatch(GetPetgraphIndex, MakePrimitive)] -#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BinavvertexNodeIndex { FixedDot(FixedDotIndex), FixedBend(FixedBendIndex), @@ -84,7 +84,7 @@ impl From for GearIndex { /// /// The name "trianvertex" is a shortening of "triangulation vertex". #[enum_dispatch(GetPetgraphIndex, MakePrimitive)] -#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] enum TrianvertexNodeIndex { FixedDot(FixedDotIndex), FixedBend(FixedBendIndex), @@ -210,8 +210,7 @@ impl Navmesh { let mut origin_navvertex = None; let mut destination_navvertex = None; - // `HashMap` is obviously suboptimal here. - let mut map = HashMap::new(); + let mut map = BTreeMap::new(); for trianvertex in triangulation.node_identifiers() { if trianvertex == origin.into() { @@ -302,7 +301,7 @@ impl Navmesh { fn add_node_to_graph_and_map_as_binavvertex( graph: &mut UnGraph, - map: &mut HashMap, NodeIndex)>>, + map: &mut BTreeMap, NodeIndex)>>, trianvertex: TrianvertexNodeIndex, node: BinavvertexNodeIndex, ) { diff --git a/src/specctra/design.rs b/src/specctra/design.rs index 14fd348..97e764e 100644 --- a/src/specctra/design.rs +++ b/src/specctra/design.rs @@ -6,8 +6,9 @@ //! Design DSN file, creating the [`Board`] object from the file, as well as //! exporting the session file +use std::collections::{btree_map::Entry as BTreeMapEntry, BTreeMap}; + use geo::{point, Point, Rotate}; -use std::collections::{hash_map::Entry as HashMapEntry, HashMap}; use crate::{ board::{mesadata::AccessMesadata, Board}, @@ -73,7 +74,7 @@ impl SpecctraDesign { let mesadata = board.mesadata(); let drawing = board.layout().drawing(); - let mut net_outs = HashMap::::new(); + let mut net_outs = BTreeMap::::new(); for index in drawing.primitive_nodes() { let primitive = index.primitive(drawing); @@ -131,8 +132,8 @@ impl SpecctraDesign { }; let net_out = match net_outs.entry(net) { - HashMapEntry::Occupied(occ) => occ.into_mut(), - HashMapEntry::Vacant(vac) => vac.insert(structure::NetOut { + BTreeMapEntry::Occupied(occ) => occ.into_mut(), + BTreeMapEntry::Vacant(vac) => vac.insert(structure::NetOut { name: mesadata .net_netname(net) .ok_or_else(|| { @@ -208,7 +209,7 @@ impl SpecctraDesign { }) // flatten the nested iters into a single stream of tuples .flatten() - .collect::>(); + .collect::>(); // add pins from components for component in &self.pcb.placement.components {