Create dense allocator for net IDs.

Ensures that the net indexes are a contiguous range, which Logic World assumes.
This commit is contained in:
Adam Gausmann 2022-11-08 22:44:54 -06:00
parent 934055d060
commit 70f2a170b6
4 changed files with 139 additions and 30 deletions

91
src/misc/dense_store.rs Normal file
View file

@ -0,0 +1,91 @@
use std::{
fmt::Debug,
hash::{Hash, Hasher},
marker::PhantomData,
};
pub struct DenseStore<T> {
items: Vec<T>,
}
impl<T> DenseStore<T> {
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn get(&self, index: Index<T>) -> Option<&T> {
self.items.get(index.into_raw())
}
pub fn get_mut(&mut self, index: Index<T>) -> Option<&mut T> {
self.items.get_mut(index.into_raw())
}
pub fn insert(&mut self, item: T) -> Index<T> {
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<T>) -> Option<(T, Rename<T>)> {
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<T>(usize, PhantomData<T>);
impl<T> Index<T> {
pub fn from_raw(raw: usize) -> Self {
Self(raw, PhantomData)
}
pub fn into_raw(self) -> usize {
self.0
}
}
impl<T> Debug for Index<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Index").field(&self.0).finish()
}
}
impl<T> Clone for Index<T> {
fn clone(&self) -> Self {
Self(self.0, PhantomData)
}
}
impl<T> Copy for Index<T> {}
impl<T> PartialEq for Index<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T> Eq for Index<T> {}
impl<T> Hash for Index<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
pub struct Rename<T> {
pub src: Index<T>,
pub dest: Index<T>,
}

View file

@ -1,3 +1,4 @@
//! Miscellaneous internal utilities.
pub mod dense_store;
pub mod object_store;

View file

@ -29,9 +29,9 @@ impl<T> ObjectStore<T> {
}
}
pub fn contains(&self, address: Address<T>) -> bool {
self.get(address).is_some()
}
// pub fn contains(&self, address: Address<T>) -> bool {
// self.get(address).is_some()
// }
pub fn insert(&mut self, item: T) -> Address<T> {
if let Some(entry) = self.entries.get_mut(self.first_vacant) {
@ -91,12 +91,12 @@ impl<T> ObjectStore<T> {
.flat_map(|(index, entry)| entry.get().map(|item| (Address::from_raw(index), item)))
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (Address<T>, &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<Item = (Address<T>, &mut T)> {
// self.entries
// .iter_mut()
// .enumerate()
// .flat_map(|(index, entry)| entry.get_mut().map(|item| (Address::from_raw(index), item)))
// }
}
enum Entry<T> {

View file

@ -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<ComponentId>,
components: ObjectStore<ComponentInfo>,
wires: ObjectStore<WireInfo>,
next_net: u32,
nets: HashMap<NetId, NetInfo>,
nets: DenseStore<NetInfo>,
next_type: u16,
component_types: HashMap<String, u16>,
@ -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<NetInfo> {
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<ComponentInfo>);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NetId(u32);
pub struct NetId(Index<NetInfo>);
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()))
}
}