From 70f2a170b6b4b2c2a542a5609ad5fc82ebafe142 Mon Sep 17 00:00:00 2001 From: Adam Gausmann Date: Tue, 8 Nov 2022 22:44:54 -0600 Subject: [PATCH] Create dense allocator for net IDs. Ensures that the net indexes are a contiguous range, which Logic World assumes. --- src/misc/dense_store.rs | 91 ++++++++++++++++++++++++++++++++++++++++ src/misc/mod.rs | 1 + src/misc/object_store.rs | 18 ++++---- src/sandbox/mod.rs | 59 ++++++++++++++++---------- 4 files changed, 139 insertions(+), 30 deletions(-) create mode 100644 src/misc/dense_store.rs diff --git a/src/misc/dense_store.rs b/src/misc/dense_store.rs new file mode 100644 index 0000000..8afbce2 --- /dev/null +++ b/src/misc/dense_store.rs @@ -0,0 +1,91 @@ +use std::{ + fmt::Debug, + hash::{Hash, Hasher}, + marker::PhantomData, +}; + +pub struct DenseStore { + items: Vec, +} + +impl DenseStore { + pub fn new() -> Self { + Self { items: Vec::new() } + } + + pub fn get(&self, index: Index) -> Option<&T> { + self.items.get(index.into_raw()) + } + + pub fn get_mut(&mut self, index: Index) -> Option<&mut T> { + self.items.get_mut(index.into_raw()) + } + + pub fn insert(&mut self, item: T) -> Index { + let index = Index::from_raw(self.items.len()); + self.items.push(item); + index + } + + #[must_use = "DenseStore::remove() renames an index; all external references must be replaced"] + pub fn remove(&mut self, index: Index) -> Option<(T, Rename)> { + let raw = index.into_raw(); + if self.items.get(raw).is_some() { + let removed = self.items.swap_remove(raw); + Some(( + removed, + Rename { + src: Index::from_raw(self.items.len()), + dest: index, + }, + )) + } else { + None + } + } +} + +pub struct Index(usize, PhantomData); + +impl Index { + pub fn from_raw(raw: usize) -> Self { + Self(raw, PhantomData) + } + + pub fn into_raw(self) -> usize { + self.0 + } +} + +impl Debug for Index { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("Index").field(&self.0).finish() + } +} + +impl Clone for Index { + fn clone(&self) -> Self { + Self(self.0, PhantomData) + } +} + +impl Copy for Index {} + +impl PartialEq for Index { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl Eq for Index {} + +impl Hash for Index { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + +pub struct Rename { + pub src: Index, + pub dest: Index, +} diff --git a/src/misc/mod.rs b/src/misc/mod.rs index 7eacced..64328b3 100644 --- a/src/misc/mod.rs +++ b/src/misc/mod.rs @@ -1,3 +1,4 @@ //! Miscellaneous internal utilities. +pub mod dense_store; pub mod object_store; diff --git a/src/misc/object_store.rs b/src/misc/object_store.rs index 761c210..d2418ea 100644 --- a/src/misc/object_store.rs +++ b/src/misc/object_store.rs @@ -29,9 +29,9 @@ impl ObjectStore { } } - pub fn contains(&self, address: Address) -> bool { - self.get(address).is_some() - } + // pub fn contains(&self, address: Address) -> bool { + // self.get(address).is_some() + // } pub fn insert(&mut self, item: T) -> Address { if let Some(entry) = self.entries.get_mut(self.first_vacant) { @@ -91,12 +91,12 @@ impl ObjectStore { .flat_map(|(index, entry)| entry.get().map(|item| (Address::from_raw(index), item))) } - pub fn iter_mut(&mut self) -> impl Iterator, &mut T)> { - self.entries - .iter_mut() - .enumerate() - .flat_map(|(index, entry)| entry.get_mut().map(|item| (Address::from_raw(index), item))) - } + // pub fn iter_mut(&mut self) -> impl Iterator, &mut T)> { + // self.entries + // .iter_mut() + // .enumerate() + // .flat_map(|(index, entry)| entry.get_mut().map(|item| (Address::from_raw(index), item))) + // } } enum Entry { diff --git a/src/sandbox/mod.rs b/src/sandbox/mod.rs index 937b753..ddfc797 100644 --- a/src/sandbox/mod.rs +++ b/src/sandbox/mod.rs @@ -4,7 +4,10 @@ mod serialize; use crate::{ latest::ModInfo, - misc::object_store::{Address, ObjectStore}, + misc::{ + dense_store::{DenseStore, Index}, + object_store::{Address, ObjectStore}, + }, }; use std::{ collections::{HashMap, HashSet}, @@ -16,9 +19,7 @@ pub struct Sandbox { root_components: HashSet, components: ObjectStore, wires: ObjectStore, - - next_net: u32, - nets: HashMap, + nets: DenseStore, next_type: u16, component_types: HashMap, @@ -38,9 +39,7 @@ impl Sandbox { root_components: HashSet::new(), components: ObjectStore::new(), wires: ObjectStore::new(), - - next_net: 0, - nets: HashMap::new(), + nets: DenseStore::new(), next_type: component_types.values().copied().max().unwrap_or(0), component_types, @@ -164,7 +163,7 @@ impl Sandbox { // Register wire references in pegs and net. self.get_peg_mut(&addr_a).unwrap().wires.insert(wire_id); self.get_peg_mut(&addr_b).unwrap().wires.insert(wire_id); - self.nets.get_mut(&net_id).unwrap().wires.insert(wire_id); + self.nets.get_mut(net_id.0).unwrap().wires.insert(wire_id); Ok(wire_id) } @@ -209,10 +208,10 @@ impl Sandbox { } // Remove peg-net cross-references. Remove nets if empty. - let net = self.nets.get_mut(&peg.net_id).unwrap(); + let net = self.nets.get_mut(peg.net_id.0).unwrap(); net.pegs.remove(&peg_addr); if net.size() == 0 { - self.nets.remove(&peg.net_id); + self.remove_net(peg.net_id); } } @@ -244,7 +243,7 @@ impl Sandbox { }; // Remove wire-net and wire-peg cross-references. - self.nets.get_mut(&wire.net_id).unwrap().wires.remove(&id); + self.nets.get_mut(wire.net_id.0).unwrap().wires.remove(&id); // The pegs might not exist if a component was just removed. // That is expected and should not panic/error: if let Some(peg) = self.get_peg_mut(&wire.a) { @@ -271,9 +270,27 @@ impl Sandbox { } fn make_net(&mut self) -> NetId { - let id = NetId(self.next_net); - self.next_net += 1; - id + NetId(self.nets.insert(NetInfo { + wires: HashSet::new(), + pegs: HashSet::new(), + })) + } + + fn remove_net(&mut self, net_id: NetId) -> Option { + if let Some((net, rename)) = self.nets.remove(net_id.0) { + // Rename all the references to the net that was moved into this position. + let renamed = self.nets.get(rename.dest).unwrap(); + for wire_id in &renamed.wires { + self.wires.get_mut(wire_id.0).unwrap().net_id = NetId(rename.dest); + } + //TODO remove this clone, reduce size of get_peg_mut borrow + for peg_id in &renamed.pegs.clone() { + self.get_peg_mut(peg_id).unwrap().net_id = NetId(rename.dest); + } + Some(net) + } else { + None + } } fn merge_nets(&mut self, id_a: NetId, id_b: NetId) -> NetId { @@ -282,8 +299,8 @@ impl Sandbox { return id_a; } - let a = &self.nets[&id_a]; - let b = &self.nets[&id_b]; + let a = self.nets.get(id_a.0).unwrap(); + let b = &self.nets.get(id_b.0).unwrap(); // Merge the smaller net into the larger net. let (id_dest, id_src) = if a.size() >= b.size() { (id_a, id_b) @@ -291,7 +308,7 @@ impl Sandbox { (id_b, id_a) }; - let src = self.nets.remove(&id_src).unwrap(); + let src = self.remove_net(id_src).unwrap(); // Update net cross-references: for wire_id in &src.wires { self.wires.get_mut(wire_id.0).unwrap().net_id = id_dest; @@ -301,7 +318,7 @@ impl Sandbox { } // Move references from src into dest: - let dest = self.nets.get_mut(&id_dest).unwrap(); + let dest = self.nets.get_mut(id_dest.0).unwrap(); dest.pegs.extend(src.pegs); dest.wires.extend(src.wires); @@ -433,15 +450,15 @@ impl<'a> ComponentBuilder<'a> { pub struct ComponentId(Address); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct NetId(u32); +pub struct NetId(Index); impl NetId { fn into_raw(self) -> i32 { - self.0.try_into().unwrap() + self.0.into_raw().try_into().unwrap() } fn from_raw(raw: i32) -> Self { - Self(raw.try_into().unwrap()) + Self(Index::from_raw(raw.try_into().unwrap())) } }