Create dense allocator for net IDs.
Ensures that the net indexes are a contiguous range, which Logic World assumes.
This commit is contained in:
parent
934055d060
commit
70f2a170b6
4 changed files with 139 additions and 30 deletions
91
src/misc/dense_store.rs
Normal file
91
src/misc/dense_store.rs
Normal 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>,
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
//! Miscellaneous internal utilities.
|
//! Miscellaneous internal utilities.
|
||||||
|
|
||||||
|
pub mod dense_store;
|
||||||
pub mod object_store;
|
pub mod object_store;
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ impl<T> ObjectStore<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains(&self, address: Address<T>) -> bool {
|
// pub fn contains(&self, address: Address<T>) -> bool {
|
||||||
self.get(address).is_some()
|
// self.get(address).is_some()
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn insert(&mut self, item: T) -> Address<T> {
|
pub fn insert(&mut self, item: T) -> Address<T> {
|
||||||
if let Some(entry) = self.entries.get_mut(self.first_vacant) {
|
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)))
|
.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)> {
|
// pub fn iter_mut(&mut self) -> impl Iterator<Item = (Address<T>, &mut T)> {
|
||||||
self.entries
|
// self.entries
|
||||||
.iter_mut()
|
// .iter_mut()
|
||||||
.enumerate()
|
// .enumerate()
|
||||||
.flat_map(|(index, entry)| entry.get_mut().map(|item| (Address::from_raw(index), item)))
|
// .flat_map(|(index, entry)| entry.get_mut().map(|item| (Address::from_raw(index), item)))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Entry<T> {
|
enum Entry<T> {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ mod serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
latest::ModInfo,
|
latest::ModInfo,
|
||||||
misc::object_store::{Address, ObjectStore},
|
misc::{
|
||||||
|
dense_store::{DenseStore, Index},
|
||||||
|
object_store::{Address, ObjectStore},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
|
|
@ -16,9 +19,7 @@ pub struct Sandbox {
|
||||||
root_components: HashSet<ComponentId>,
|
root_components: HashSet<ComponentId>,
|
||||||
components: ObjectStore<ComponentInfo>,
|
components: ObjectStore<ComponentInfo>,
|
||||||
wires: ObjectStore<WireInfo>,
|
wires: ObjectStore<WireInfo>,
|
||||||
|
nets: DenseStore<NetInfo>,
|
||||||
next_net: u32,
|
|
||||||
nets: HashMap<NetId, NetInfo>,
|
|
||||||
|
|
||||||
next_type: u16,
|
next_type: u16,
|
||||||
component_types: HashMap<String, u16>,
|
component_types: HashMap<String, u16>,
|
||||||
|
|
@ -38,9 +39,7 @@ impl Sandbox {
|
||||||
root_components: HashSet::new(),
|
root_components: HashSet::new(),
|
||||||
components: ObjectStore::new(),
|
components: ObjectStore::new(),
|
||||||
wires: ObjectStore::new(),
|
wires: ObjectStore::new(),
|
||||||
|
nets: DenseStore::new(),
|
||||||
next_net: 0,
|
|
||||||
nets: HashMap::new(),
|
|
||||||
|
|
||||||
next_type: component_types.values().copied().max().unwrap_or(0),
|
next_type: component_types.values().copied().max().unwrap_or(0),
|
||||||
component_types,
|
component_types,
|
||||||
|
|
@ -164,7 +163,7 @@ impl Sandbox {
|
||||||
// Register wire references in pegs and net.
|
// Register wire references in pegs and net.
|
||||||
self.get_peg_mut(&addr_a).unwrap().wires.insert(wire_id);
|
self.get_peg_mut(&addr_a).unwrap().wires.insert(wire_id);
|
||||||
self.get_peg_mut(&addr_b).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)
|
Ok(wire_id)
|
||||||
}
|
}
|
||||||
|
|
@ -209,10 +208,10 @@ impl Sandbox {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove peg-net cross-references. Remove nets if empty.
|
// 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);
|
net.pegs.remove(&peg_addr);
|
||||||
if net.size() == 0 {
|
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.
|
// 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.
|
// The pegs might not exist if a component was just removed.
|
||||||
// That is expected and should not panic/error:
|
// That is expected and should not panic/error:
|
||||||
if let Some(peg) = self.get_peg_mut(&wire.a) {
|
if let Some(peg) = self.get_peg_mut(&wire.a) {
|
||||||
|
|
@ -271,9 +270,27 @@ impl Sandbox {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_net(&mut self) -> NetId {
|
fn make_net(&mut self) -> NetId {
|
||||||
let id = NetId(self.next_net);
|
NetId(self.nets.insert(NetInfo {
|
||||||
self.next_net += 1;
|
wires: HashSet::new(),
|
||||||
id
|
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 {
|
fn merge_nets(&mut self, id_a: NetId, id_b: NetId) -> NetId {
|
||||||
|
|
@ -282,8 +299,8 @@ impl Sandbox {
|
||||||
return id_a;
|
return id_a;
|
||||||
}
|
}
|
||||||
|
|
||||||
let a = &self.nets[&id_a];
|
let a = self.nets.get(id_a.0).unwrap();
|
||||||
let b = &self.nets[&id_b];
|
let b = &self.nets.get(id_b.0).unwrap();
|
||||||
// Merge the smaller net into the larger net.
|
// Merge the smaller net into the larger net.
|
||||||
let (id_dest, id_src) = if a.size() >= b.size() {
|
let (id_dest, id_src) = if a.size() >= b.size() {
|
||||||
(id_a, id_b)
|
(id_a, id_b)
|
||||||
|
|
@ -291,7 +308,7 @@ impl Sandbox {
|
||||||
(id_b, id_a)
|
(id_b, id_a)
|
||||||
};
|
};
|
||||||
|
|
||||||
let src = self.nets.remove(&id_src).unwrap();
|
let src = self.remove_net(id_src).unwrap();
|
||||||
// Update net cross-references:
|
// Update net cross-references:
|
||||||
for wire_id in &src.wires {
|
for wire_id in &src.wires {
|
||||||
self.wires.get_mut(wire_id.0).unwrap().net_id = id_dest;
|
self.wires.get_mut(wire_id.0).unwrap().net_id = id_dest;
|
||||||
|
|
@ -301,7 +318,7 @@ impl Sandbox {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move references from src into dest:
|
// 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.pegs.extend(src.pegs);
|
||||||
dest.wires.extend(src.wires);
|
dest.wires.extend(src.wires);
|
||||||
|
|
||||||
|
|
@ -433,15 +450,15 @@ impl<'a> ComponentBuilder<'a> {
|
||||||
pub struct ComponentId(Address<ComponentInfo>);
|
pub struct ComponentId(Address<ComponentInfo>);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct NetId(u32);
|
pub struct NetId(Index<NetInfo>);
|
||||||
|
|
||||||
impl NetId {
|
impl NetId {
|
||||||
fn into_raw(self) -> i32 {
|
fn into_raw(self) -> i32 {
|
||||||
self.0.try_into().unwrap()
|
self.0.into_raw().try_into().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_raw(raw: i32) -> Self {
|
fn from_raw(raw: i32) -> Self {
|
||||||
Self(raw.try_into().unwrap())
|
Self(Index::from_raw(raw.try_into().unwrap()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue