use super::{IdTrait, Registry};
use std::hash::{Hash, Hasher};
use std::mem;
struct IndexOnlyWrapper<ID: IdTrait>(ID);
impl<ID: IdTrait> PartialEq for IndexOnlyWrapper<ID> {
fn eq(&self, other: &Self) -> bool {
self.0.index() == other.0.index()
}
}
impl<ID: IdTrait> Eq for IndexOnlyWrapper<ID> {}
impl<ID: IdTrait> Hash for IndexOnlyWrapper<ID> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.index().hash(state);
}
}
pub struct IdMap<ID: IdTrait, V> {
map: hashbrown::HashMap<IndexOnlyWrapper<ID>, V>,
}
impl<ID: IdTrait, V> IdMap<ID, V> {
pub fn new() -> Self {
Self {
map: hashbrown::HashMap::new(),
}
}
pub fn get(&self, id: ID) -> Option<&V> {
let (k, v) = self.map.get_key_value(&IndexOnlyWrapper(id))?;
if k.0 == id {
Some(v)
} else {
None
}
}
pub fn get_mut(&mut self, id: ID) -> Option<&mut V> {
match self.map.entry(IndexOnlyWrapper(id)) {
hashbrown::hash_map::Entry::Occupied(view) => {
if view.key().0 == id {
return Some(view.into_mut());
}
if view.key().0.generation() < id.generation() {
view.remove();
}
}
hashbrown::hash_map::Entry::Vacant(_) => {}
}
None
}
pub fn insert(&mut self, id: ID, value: V) -> Option<V> {
match self.map.raw_entry_mut().from_key(&IndexOnlyWrapper(id)) {
hashbrown::hash_map::RawEntryMut::Occupied(mut view) => {
if view.key().0 == id {
return Some(mem::replace(view.into_mut(), value));
}
if view.key().0.generation() < id.generation() {
*view.key_mut() = IndexOnlyWrapper(id);
*view.get_mut() = value;
}
}
hashbrown::hash_map::RawEntryMut::Vacant(view) => {
view.insert(IndexOnlyWrapper(id), value);
}
}
None
}
pub fn remove(&mut self, id: ID) -> Option<V> {
match self.map.entry(IndexOnlyWrapper(id)) {
hashbrown::hash_map::Entry::Occupied(view) => {
if view.key().0 == id {
return Some(view.remove());
}
if view.key().0.generation() < id.generation() {
view.remove();
}
}
hashbrown::hash_map::Entry::Vacant(_) => {}
}
None
}
pub fn vacuum<T>(&mut self, registry: &Registry<T, ID>) {
self.map.retain(|k, _v| registry.contains_id(k.0));
}
}
impl<ID: IdTrait, V> std::ops::Index<ID> for IdMap<ID, V> {
type Output = V;
fn index(&self, id: ID) -> &V {
self.get(id).unwrap()
}
}
impl<ID: IdTrait, V> std::ops::IndexMut<ID> for IdMap<ID, V> {
fn index_mut(&mut self, id: ID) -> &mut V {
self.get_mut(id).unwrap()
}
}
pub struct IdFlatMap<ID: IdTrait, V> {
vec: Vec<V>,
map: hashbrown::HashMap<IndexOnlyWrapper<ID>, usize>,
reverse_map: hashbrown::HashMap<usize, ID>,
}
impl<ID: IdTrait, V> IdFlatMap<ID, V> {
pub fn new() -> Self {
Self {
vec: Vec::new(),
map: hashbrown::HashMap::new(),
reverse_map: hashbrown::HashMap::new(),
}
}
pub fn as_slice(&self) -> &[V] {
self.vec.as_slice()
}
pub fn as_mut_slice(&mut self) -> &mut [V] {
self.vec.as_mut_slice()
}
pub fn get(&self, id: ID) -> Option<&V> {
let (&IndexOnlyWrapper(previous_id), &vec_index) =
self.map.get_key_value(&IndexOnlyWrapper(id))?;
if previous_id == id {
debug_assert!(vec_index < self.vec.len());
self.vec.get(vec_index)
} else {
None
}
}
pub fn get_mut(&mut self, id: ID) -> Option<&mut V> {
match self.map.entry(IndexOnlyWrapper(id)) {
hashbrown::hash_map::Entry::Occupied(view) => {
let previous_id = view.key().0;
let vec_index = *view.get();
if previous_id == id {
debug_assert!(vec_index < self.vec.len());
return self.vec.get_mut(vec_index);
}
if previous_id.generation() < id.generation() {
view.remove();
self.finish_remove(vec_index);
}
}
hashbrown::hash_map::Entry::Vacant(_) => {}
}
None
}
pub fn insert(&mut self, id: ID, value: V) -> Option<V> {
match self.map.raw_entry_mut().from_key(&IndexOnlyWrapper(id)) {
hashbrown::hash_map::RawEntryMut::Occupied(mut view) => {
let previous_id = view.key().0;
let vec_index = *view.get();
if previous_id == id {
return Some(mem::replace(&mut self.vec[vec_index], value));
}
if previous_id.generation() < id.generation() {
self.vec[vec_index] = value;
*view.key_mut() = IndexOnlyWrapper(id);
self.reverse_map.insert(vec_index, id);
}
}
hashbrown::hash_map::RawEntryMut::Vacant(view) => {
let vec_index = self.vec.len();
self.vec.push(value);
view.insert(IndexOnlyWrapper(id), vec_index);
self.reverse_map.insert(vec_index, id);
}
}
None
}
fn finish_remove(&mut self, vec_index: usize) -> V {
let end_index = self.vec.len() - 1;
let end_id = self.reverse_map[&end_index];
let value = self.vec.swap_remove(vec_index);
if vec_index != end_index {
debug_assert!(self.map.contains_key(&IndexOnlyWrapper(end_id)));
self.map.insert(IndexOnlyWrapper(end_id), vec_index);
self.reverse_map.insert(vec_index, end_id);
}
self.reverse_map.remove(&end_index);
value
}
pub fn remove(&mut self, id: ID) -> Option<V> {
match self.map.entry(IndexOnlyWrapper(id)) {
hashbrown::hash_map::Entry::Occupied(view) => {
let previous_id = view.key().0;
let vec_index = *view.get();
if id.generation() < previous_id.generation() {
return None;
}
view.remove();
let value = self.finish_remove(vec_index);
if previous_id == id {
Some(value)
} else {
None
}
}
hashbrown::hash_map::Entry::Vacant(_) => {
None
}
}
}
pub fn vacuum<T>(&mut self, registry: &Registry<T, ID>) {
let to_remove: Vec<ID> = self
.map
.keys()
.filter_map(|id| (!registry.contains_id(id.0)).then_some(id.0))
.collect();
for id in to_remove {
self.remove(id);
}
}
}
impl<ID: IdTrait, V> std::ops::Index<ID> for IdFlatMap<ID, V> {
type Output = V;
fn index(&self, id: ID) -> &V {
self.get(id).unwrap()
}
}
impl<ID: IdTrait, V> std::ops::IndexMut<ID> for IdFlatMap<ID, V> {
fn index_mut(&mut self, id: ID) -> &mut V {
self.get_mut(id).unwrap()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_id_map() {
let mut reg = Registry::new();
let id0 = reg.insert(());
let id1 = reg.insert(());
let id2 = reg.insert(());
reg.remove(id2);
reg.remove(id1);
let id1_new = reg.insert(());
assert_eq!(id1_new.index(), 1);
let mut map = IdMap::new();
map.insert(id0, "foo");
map.insert(id1, "bar");
map.insert(id2, "baz");
assert_eq!(map.get(id0), Some(&"foo"));
assert_eq!(map.get(id1), Some(&"bar"));
assert_eq!(map.get(id2), Some(&"baz"));
assert_eq!(map.insert(id0, "FOO"), Some("foo"));
assert_eq!(map.get(id0), Some(&"FOO"));
assert_eq!(map.get(id1_new), None);
assert_eq!(map.get(id1), Some(&"bar"));
assert_eq!(map.get_mut(id1_new), None);
assert_eq!(map.get(id1), None);
assert_eq!(map.get(id2), Some(&"baz"));
map.vacuum(®);
assert_eq!(map.get(id2), None);
}
#[test]
fn test_id_flat_map() {
let mut reg = Registry::new();
let id0 = reg.insert(());
let id1 = reg.insert(());
let id2 = reg.insert(());
reg.remove(id2);
reg.remove(id1);
let id1_new = reg.insert(());
assert_eq!(id1_new.index(), 1);
let mut map = IdFlatMap::new();
map.insert(id0, "foo");
map.insert(id1, "bar");
map.insert(id2, "baz");
assert_eq!(map.get(id0), Some(&"foo"));
assert_eq!(map.get(id1), Some(&"bar"));
assert_eq!(map.get(id2), Some(&"baz"));
assert_eq!(map.reverse_map.get(&0), Some(&id0));
assert_eq!(map.reverse_map.get(&1), Some(&id1));
assert_eq!(map.reverse_map.get(&2), Some(&id2));
assert_eq!(map.as_slice(), &["foo", "bar", "baz"]);
map.as_mut_slice()[2] = "BAZ";
assert_eq!(map.as_slice(), &["foo", "bar", "BAZ"]);
assert_eq!(map[id2], "BAZ");
assert_eq!(map.insert(id0, "FOO"), Some("foo"));
assert_eq!(map.get(id0), Some(&"FOO"));
assert_eq!(map.get(id1_new), None);
assert_eq!(map.get(id1), Some(&"bar"));
assert_eq!(map.as_slice(), &["FOO", "bar", "BAZ"]);
assert_eq!(map.get_mut(id1_new), None);
assert_eq!(map.get(id1), None);
assert_eq!(map.as_slice(), &["FOO", "BAZ"]);
assert_eq!(map.reverse_map.get(&0), Some(&id0));
assert_eq!(map.reverse_map.get(&1), Some(&id2));
assert_eq!(map.reverse_map.get(&2), None);
assert_eq!(map.get(id2), Some(&"BAZ"));
map.vacuum(®);
assert_eq!(map.get(id2), None);
assert_eq!(map.as_slice(), &["FOO"]);
assert_eq!(map.reverse_map.get(&0), Some(&id0));
assert_eq!(map.reverse_map.get(&1), None);
assert_eq!(map.reverse_map.get(&2), None);
}
}