Optimization: use IdHasher for AnyMap

This commit is contained in:
Emil Ernerfeldt 2021-10-09 15:52:16 +02:00
parent cca11ea9cc
commit bc54a49413
6 changed files with 189 additions and 174 deletions

View file

@ -1,53 +1,64 @@
use crate::any::element::{AnyMapElement, AnyMapTrait}; use crate::any::element::{AnyMapElement, AnyMapTrait};
use crate::epaint::ahash::AHashMap;
use std::any::TypeId; use std::any::TypeId;
use std::hash::Hash; use std::collections::hash_map::RandomState;
use std::collections::HashMap;
use std::hash::{BuildHasher, Hash};
/// Stores any object by `Key`. /// Stores any object by `K`.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct AnyMap<Key: Hash + Eq>(AHashMap<Key, AnyMapElement>); pub struct AnyMap<K: Hash + Eq, S: BuildHasher + Default = RandomState>(
HashMap<K, AnyMapElement, S>,
);
impl<Key: Hash + Eq> Default for AnyMap<Key> { impl<K, S> Default for AnyMap<K, S>
where
K: Hash + Eq,
S: BuildHasher + Default,
{
fn default() -> Self { fn default() -> Self {
AnyMap(AHashMap::new()) AnyMap(HashMap::default())
} }
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
impl<Key: Hash + Eq> AnyMap<Key> { impl<K, S> AnyMap<K, S>
where
K: Hash + Eq,
S: BuildHasher + Default,
{
#[inline] #[inline]
pub fn get<T: AnyMapTrait>(&mut self, key: &Key) -> Option<&T> { pub fn get<T: AnyMapTrait>(&mut self, key: &K) -> Option<&T> {
self.get_mut(key).map(|x| &*x) self.get_mut(key).map(|x| &*x)
} }
#[inline] #[inline]
pub fn get_mut<T: AnyMapTrait>(&mut self, key: &Key) -> Option<&mut T> { pub fn get_mut<T: AnyMapTrait>(&mut self, key: &K) -> Option<&mut T> {
self.0.get_mut(key)?.get_mut() self.0.get_mut(key)?.get_mut()
} }
#[inline] #[inline]
pub fn get_or_insert_with<T: AnyMapTrait>( pub fn get_or_insert_with<T: AnyMapTrait>(
&mut self, &mut self,
key: Key, key: K,
or_insert_with: impl FnOnce() -> T, or_insert_with: impl FnOnce() -> T,
) -> &T { ) -> &T {
&*self.get_mut_or_insert_with(key, or_insert_with) &*self.get_mut_or_insert_with(key, or_insert_with)
} }
#[inline] #[inline]
pub fn get_or_default<T: AnyMapTrait + Default>(&mut self, key: Key) -> &T { pub fn get_or_default<T: AnyMapTrait + Default>(&mut self, key: K) -> &T {
self.get_or_insert_with(key, Default::default) self.get_or_insert_with(key, Default::default)
} }
#[inline] #[inline]
pub fn get_or<T: AnyMapTrait>(&mut self, key: Key, value: T) -> &T { pub fn get_or<T: AnyMapTrait>(&mut self, key: K, value: T) -> &T {
&*self.get_mut_or_insert_with(key, || value) &*self.get_mut_or_insert_with(key, || value)
} }
pub fn get_mut_or_insert_with<T: AnyMapTrait>( pub fn get_mut_or_insert_with<T: AnyMapTrait>(
&mut self, &mut self,
key: Key, key: K,
or_insert_with: impl FnOnce() -> T, or_insert_with: impl FnOnce() -> T,
) -> &mut T { ) -> &mut T {
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
@ -61,17 +72,17 @@ impl<Key: Hash + Eq> AnyMap<Key> {
} }
#[inline] #[inline]
pub fn get_mut_or_default<T: AnyMapTrait + Default>(&mut self, key: Key) -> &mut T { pub fn get_mut_or_default<T: AnyMapTrait + Default>(&mut self, key: K) -> &mut T {
self.get_mut_or_insert_with(key, Default::default) self.get_mut_or_insert_with(key, Default::default)
} }
#[inline] #[inline]
pub fn insert<T: AnyMapTrait>(&mut self, key: Key, element: T) { pub fn insert<T: AnyMapTrait>(&mut self, key: K, element: T) {
self.0.insert(key, AnyMapElement::new(element)); self.0.insert(key, AnyMapElement::new(element));
} }
#[inline] #[inline]
pub fn remove(&mut self, key: &Key) { pub fn remove(&mut self, key: &K) {
self.0.remove(key); self.0.remove(key);
} }

View file

@ -27,7 +27,7 @@
//! //!
//! # `serializable` //! # `serializable`
//! //!
//! [`TypeMap`] and [`serializable::TypeMap`] has exactly the same interface, but [`serializable::TypeMap`] only requires serde traits for stored object under `persistent` feature. Same thing for [`AnyMap`] and [`serializable::AnyMap`]. //! [`TypeMap`] and [`serializable::TypeMap`] has exactly the same interface, but [`serializable::TypeMap`] only requires serde traits for stored object under `persistent` feature. Same thing for [`AnyMap`] and [`serializable::IdAnyMap`].
//! //!
//! # What could break //! # What could break
//! //!
@ -35,7 +35,7 @@
//! //!
//! First, serialized `TypeId` in [`serializable::TypeMap`] could broke if you updated the version of the Rust compiler between runs. //! First, serialized `TypeId` in [`serializable::TypeMap`] could broke if you updated the version of the Rust compiler between runs.
//! //!
//! Second, count and reset all instances of a type in [`serializable::AnyMap`] could return an incorrect value for the same reason. //! Second, count and reset all instances of a type in [`serializable::IdAnyMap`] could return an incorrect value for the same reason.
//! //!
//! Deserialization errors of loaded elements of these storages can be determined only when you call `get_...` functions, they not logged and not provided to a user, on this errors value is just replaced with `or_insert()`/default value. //! Deserialization errors of loaded elements of these storages can be determined only when you call `get_...` functions, they not logged and not provided to a user, on this errors value is just replaced with `or_insert()`/default value.
//! //!

View file

@ -1,54 +1,49 @@
use crate::any::serializable::element::{AnyMapElement, AnyMapTrait}; use crate::any::serializable::element::{AnyMapElement, AnyMapTrait};
use crate::any::serializable::type_id::TypeId; use crate::any::serializable::type_id::TypeId;
use crate::epaint::ahash::AHashMap; use crate::{Id, IdMap};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::hash::Hash;
/// Stores any object by `Key`, and can be de/serialized. // I gave up making this general over any key and hash builder, like for `AnyMap`,
#[derive(Clone, Debug, Deserialize, Serialize)] // hence the disabled test later on.
pub struct AnyMap<Key: Hash + Eq>(AHashMap<Key, AnyMapElement>); /// Stores any object by [`Id`], and can be de/serialized.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
impl<Key: Hash + Eq> Default for AnyMap<Key> { pub struct IdAnyMap(IdMap<AnyMapElement>);
fn default() -> Self {
AnyMap(AHashMap::new())
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
impl<Key: Hash + Eq> AnyMap<Key> { impl IdAnyMap {
#[inline] #[inline]
pub fn get<T: AnyMapTrait>(&mut self, key: &Key) -> Option<&T> { pub fn get<T: AnyMapTrait>(&mut self, key: &Id) -> Option<&T> {
self.get_mut(key).map(|x| &*x) self.get_mut(key).map(|x| &*x)
} }
#[inline] #[inline]
pub fn get_mut<T: AnyMapTrait>(&mut self, key: &Key) -> Option<&mut T> { pub fn get_mut<T: AnyMapTrait>(&mut self, key: &Id) -> Option<&mut T> {
self.0.get_mut(key)?.get_mut() self.0.get_mut(key)?.get_mut()
} }
#[inline] #[inline]
pub fn get_or_insert_with<T: AnyMapTrait>( pub fn get_or_insert_with<T: AnyMapTrait>(
&mut self, &mut self,
key: Key, key: Id,
or_insert_with: impl FnOnce() -> T, or_insert_with: impl FnOnce() -> T,
) -> &T { ) -> &T {
&*self.get_mut_or_insert_with(key, or_insert_with) &*self.get_mut_or_insert_with(key, or_insert_with)
} }
#[inline] #[inline]
pub fn get_or_default<T: AnyMapTrait + Default>(&mut self, key: Key) -> &T { pub fn get_or_default<T: AnyMapTrait + Default>(&mut self, key: Id) -> &T {
self.get_or_insert_with(key, Default::default) self.get_or_insert_with(key, Default::default)
} }
#[inline] #[inline]
pub fn get_or<T: AnyMapTrait>(&mut self, key: Key, value: T) -> &T { pub fn get_or<T: AnyMapTrait>(&mut self, key: Id, value: T) -> &T {
&*self.get_mut_or_insert_with(key, || value) &*self.get_mut_or_insert_with(key, || value)
} }
pub fn get_mut_or_insert_with<T: AnyMapTrait>( pub fn get_mut_or_insert_with<T: AnyMapTrait>(
&mut self, &mut self,
key: Key, key: Id,
or_insert_with: impl FnOnce() -> T, or_insert_with: impl FnOnce() -> T,
) -> &mut T { ) -> &mut T {
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
@ -61,17 +56,17 @@ impl<Key: Hash + Eq> AnyMap<Key> {
} }
} }
pub fn get_mut_or_default<T: AnyMapTrait + Default>(&mut self, key: Key) -> &mut T { pub fn get_mut_or_default<T: AnyMapTrait + Default>(&mut self, key: Id) -> &mut T {
self.get_mut_or_insert_with(key, Default::default) self.get_mut_or_insert_with(key, Default::default)
} }
#[inline] #[inline]
pub fn insert<T: AnyMapTrait>(&mut self, key: Key, element: T) { pub fn insert<T: AnyMapTrait>(&mut self, key: Id, element: T) {
self.0.insert(key, AnyMapElement::new(element)); self.0.insert(key, AnyMapElement::new(element));
} }
#[inline] #[inline]
pub fn remove(&mut self, key: &Key) { pub fn remove(&mut self, key: &Id) {
self.0.remove(key); self.0.remove(key);
} }
@ -99,171 +94,171 @@ impl<Key: Hash + Eq> AnyMap<Key> {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#[test] // #[test]
fn discard_different_struct() { // fn discard_different_struct() {
use serde::{Deserialize, Serialize}; // use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] // #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
struct State1 { // struct State1 {
a: i32, // a: i32,
} // }
#[derive(Clone, Debug, Serialize, Deserialize)] // #[derive(Clone, Debug, Serialize, Deserialize)]
struct State2 { // struct State2 {
b: String, // b: String,
} // }
let file_string = { // let file_string = {
let mut map: AnyMap<i32> = Default::default(); // let mut map: AnyMap<i32> = Default::default();
map.insert(1, State1 { a: 42 }); // map.insert(1, State1 { a: 42 });
serde_json::to_string(&map).unwrap() // serde_json::to_string(&map).unwrap()
}; // };
let mut map: AnyMap<i32> = serde_json::from_str(&file_string).unwrap(); // let mut map: AnyMap<i32> = serde_json::from_str(&file_string).unwrap();
assert!(map.get::<State2>(&1).is_none()); // assert!(map.get::<State2>(&1).is_none());
assert_eq!(map.get::<State1>(&1), Some(&State1 { a: 42 })); // assert_eq!(map.get::<State1>(&1), Some(&State1 { a: 42 }));
} // }
#[test] // #[test]
fn new_field_between_runs() { // fn new_field_between_runs() {
use serde::{Deserialize, Serialize}; // use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)] // #[derive(Clone, Debug, Serialize, Deserialize)]
struct State { // struct State {
a: i32, // a: i32,
} // }
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] // #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
struct StateNew { // struct StateNew {
a: i32, // a: i32,
#[serde(default)] // #[serde(default)]
b: String, // b: String,
} // }
let file_string = { // let file_string = {
let mut map: AnyMap<i32> = Default::default(); // let mut map: AnyMap<i32> = Default::default();
map.insert(1, State { a: 42 }); // map.insert(1, State { a: 42 });
serde_json::to_string(&map).unwrap() // serde_json::to_string(&map).unwrap()
}; // };
let mut map: AnyMap<i32> = serde_json::from_str(&file_string).unwrap(); // let mut map: AnyMap<i32> = serde_json::from_str(&file_string).unwrap();
assert_eq!( // assert_eq!(
map.get::<StateNew>(&1), // map.get::<StateNew>(&1),
Some(&StateNew { // Some(&StateNew {
a: 42, // a: 42,
b: String::default() // b: String::default()
}) // })
); // );
} // }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#[test] // #[test]
fn basic_usage() { // fn basic_usage() {
#[derive(Debug, Clone, Eq, PartialEq, Default, Deserialize, Serialize)] // #[derive(Debug, Clone, Eq, PartialEq, Default, Deserialize, Serialize)]
struct State { // struct State {
a: i32, // a: i32,
} // }
let mut map: AnyMap<i32> = Default::default(); // let mut map: AnyMap<i32> = Default::default();
assert!(map.get::<State>(&0).is_none()); // assert!(map.get::<State>(&0).is_none());
map.insert(0, State { a: 42 }); // map.insert(0, State { a: 42 });
assert_eq!(*map.get::<State>(&0).unwrap(), State { a: 42 }); // assert_eq!(*map.get::<State>(&0).unwrap(), State { a: 42 });
assert!(map.get::<State>(&1).is_none()); // assert!(map.get::<State>(&1).is_none());
map.get_mut::<State>(&0).unwrap().a = 43; // map.get_mut::<State>(&0).unwrap().a = 43;
assert_eq!(*map.get::<State>(&0).unwrap(), State { a: 43 }); // assert_eq!(*map.get::<State>(&0).unwrap(), State { a: 43 });
map.remove(&0); // map.remove(&0);
assert!(map.get::<State>(&0).is_none()); // assert!(map.get::<State>(&0).is_none());
assert_eq!( // assert_eq!(
*map.get_or_insert_with(0, || State { a: 55 }), // *map.get_or_insert_with(0, || State { a: 55 }),
State { a: 55 } // State { a: 55 }
); // );
map.remove(&0); // map.remove(&0);
assert_eq!( // assert_eq!(
*map.get_mut_or_insert_with(0, || State { a: 56 }), // *map.get_mut_or_insert_with(0, || State { a: 56 }),
State { a: 56 } // State { a: 56 }
); // );
map.remove(&0); // map.remove(&0);
assert_eq!(*map.get_or_default::<State>(0), State { a: 0 }); // assert_eq!(*map.get_or_default::<State>(0), State { a: 0 });
map.remove(&0); // map.remove(&0);
assert_eq!(*map.get_mut_or_default::<State>(0), State { a: 0 }); // assert_eq!(*map.get_mut_or_default::<State>(0), State { a: 0 });
} // }
#[test] // #[test]
fn different_type_same_id() { // fn different_type_same_id() {
#[derive(Debug, Clone, Eq, PartialEq, Default, Deserialize, Serialize)] // #[derive(Debug, Clone, Eq, PartialEq, Default, Deserialize, Serialize)]
struct State { // struct State {
a: i32, // a: i32,
} // }
let mut map: AnyMap<i32> = Default::default(); // let mut map: AnyMap<i32> = Default::default();
map.insert(0, State { a: 42 }); // map.insert(0, State { a: 42 });
assert_eq!(*map.get::<State>(&0).unwrap(), State { a: 42 }); // assert_eq!(*map.get::<State>(&0).unwrap(), State { a: 42 });
assert!(map.get::<i32>(&0).is_none()); // assert!(map.get::<i32>(&0).is_none());
map.insert(0, 255i32); // map.insert(0, 255i32);
assert_eq!(*map.get::<i32>(&0).unwrap(), 255); // assert_eq!(*map.get::<i32>(&0).unwrap(), 255);
assert!(map.get::<State>(&0).is_none()); // assert!(map.get::<State>(&0).is_none());
} // }
#[test] // #[test]
fn cloning() { // fn cloning() {
#[derive(Debug, Clone, Eq, PartialEq, Default, Deserialize, Serialize)] // #[derive(Debug, Clone, Eq, PartialEq, Default, Deserialize, Serialize)]
struct State { // struct State {
a: i32, // a: i32,
} // }
let mut map: AnyMap<i32> = Default::default(); // let mut map: AnyMap<i32> = Default::default();
map.insert(0, State::default()); // map.insert(0, State::default());
map.insert(10, 10i32); // map.insert(10, 10i32);
map.insert(11, 11i32); // map.insert(11, 11i32);
let mut cloned_map = map.clone(); // let mut cloned_map = map.clone();
map.insert(12, 12i32); // map.insert(12, 12i32);
map.insert(1, State { a: 10 }); // map.insert(1, State { a: 10 });
assert_eq!(*cloned_map.get::<State>(&0).unwrap(), State { a: 0 }); // assert_eq!(*cloned_map.get::<State>(&0).unwrap(), State { a: 0 });
assert!(cloned_map.get::<State>(&1).is_none()); // assert!(cloned_map.get::<State>(&1).is_none());
assert_eq!(*cloned_map.get::<i32>(&10).unwrap(), 10i32); // assert_eq!(*cloned_map.get::<i32>(&10).unwrap(), 10i32);
assert_eq!(*cloned_map.get::<i32>(&11).unwrap(), 11i32); // assert_eq!(*cloned_map.get::<i32>(&11).unwrap(), 11i32);
assert!(cloned_map.get::<i32>(&12).is_none()); // assert!(cloned_map.get::<i32>(&12).is_none());
} // }
#[test] // #[test]
fn counting() { // fn counting() {
#[derive(Debug, Clone, Eq, PartialEq, Default, Deserialize, Serialize)] // #[derive(Debug, Clone, Eq, PartialEq, Default, Deserialize, Serialize)]
struct State { // struct State {
a: i32, // a: i32,
} // }
let mut map: AnyMap<i32> = Default::default(); // let mut map: AnyMap<i32> = Default::default();
map.insert(0, State::default()); // map.insert(0, State::default());
map.insert(1, State { a: 10 }); // map.insert(1, State { a: 10 });
map.insert(10, 10i32); // map.insert(10, 10i32);
map.insert(11, 11i32); // map.insert(11, 11i32);
map.insert(12, 12i32); // map.insert(12, 12i32);
assert_eq!(map.count::<State>(), 2); // assert_eq!(map.count::<State>(), 2);
assert_eq!(map.count::<i32>(), 3); // assert_eq!(map.count::<i32>(), 3);
map.remove_by_type::<State>(); // map.remove_by_type::<State>();
assert_eq!(map.count::<State>(), 0); // assert_eq!(map.count::<State>(), 0);
assert_eq!(map.count::<i32>(), 3); // assert_eq!(map.count::<i32>(), 3);
map.clear(); // map.clear();
assert_eq!(map.count::<State>(), 0); // assert_eq!(map.count::<State>(), 0);
assert_eq!(map.count::<i32>(), 0); // assert_eq!(map.count::<i32>(), 0);
} // }

View file

@ -3,4 +3,4 @@ mod element;
mod type_id; mod type_id;
mod type_map; mod type_map;
pub use self::{any_map::AnyMap, element::AnyMapTrait, type_map::TypeMap}; pub use self::{any_map::IdAnyMap, element::AnyMapTrait, type_map::TypeMap};

View file

@ -116,7 +116,16 @@ impl std::hash::Hasher for IdHasher {
} }
} }
pub type BuilIdHasher = std::hash::BuildHasherDefault<IdHasher>; #[derive(Copy, Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct BuilIdHasher {}
impl std::hash::BuildHasher for BuilIdHasher {
type Hasher = IdHasher;
fn build_hasher(&self) -> IdHasher {
IdHasher::default()
}
}
/// `IdMap<V>` is a `HashMap<Id, V>` optimized by knowing that `Id` has good entropy, and doesn't need more hashing. /// `IdMap<V>` is a `HashMap<Id, V>` optimized by knowing that `Id` has good entropy, and doesn't need more hashing.
pub type IdMap<V> = std::collections::HashMap<Id, V, BuilIdHasher>; pub type IdMap<V> = std::collections::HashMap<Id, V, BuilIdHasher>;

View file

@ -37,16 +37,16 @@ pub struct Memory {
/// This map stores current states for all widgets with custom `Id`s. /// This map stores current states for all widgets with custom `Id`s.
/// This will be saved between different program runs if you use the `persistence` feature. /// This will be saved between different program runs if you use the `persistence` feature.
#[cfg(feature = "persistence")] #[cfg(feature = "persistence")]
pub id_data: any::serializable::AnyMap<Id>, pub id_data: any::serializable::IdAnyMap,
/// This map stores current states for all widgets with custom `Id`s. /// This map stores current states for all widgets with custom `Id`s.
/// This will be saved between different program runs if you use the `persistence` feature. /// This will be saved between different program runs if you use the `persistence` feature.
#[cfg(not(feature = "persistence"))] #[cfg(not(feature = "persistence"))]
pub id_data: any::AnyMap<Id>, pub id_data: any::AnyMap<Id, crate::id::BuilIdHasher>,
/// Same as `id_data`, but this data will not be saved between runs. /// Same as `id_data`, but this data will not be saved between runs.
#[cfg_attr(feature = "serde", serde(skip))] #[cfg_attr(feature = "serde", serde(skip))]
pub id_data_temp: any::AnyMap<Id>, pub id_data_temp: any::AnyMap<Id, crate::id::BuilIdHasher>,
// ------------------------------------------ // ------------------------------------------
/// Can be used to cache computations from one frame to another. /// Can be used to cache computations from one frame to another.