Memoize hashing (#1876)

* Implement memoization wrapper for hashing

* Fix pattern matching errors

* Revert proper point modification hash calculiton

* Remove unused hashing code

* Code review and bug fixes

* Improve pattern matching

* Fix tests

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Dennis Kobert
2024-08-01 13:42:15 +02:00
committed by GitHub
parent 44ffb635e9
commit a6af5d4831
19 changed files with 224 additions and 466 deletions

View File

@@ -43,6 +43,7 @@ pub mod application_io;
pub mod quantization;
use core::any::TypeId;
pub use memo::MemoHash;
pub use raster::Color;
pub use types::Cow;

View File

@@ -142,3 +142,101 @@ impl<I, T, N> MonitorNode<I, T, N> {
MonitorNode { io: Arc::new(Mutex::new(None)), node }
}
}
use core::hash::{Hash, Hasher};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct MemoHash<T: Hash> {
hash: u64,
value: T,
}
#[cfg(feature = "serde")]
impl<'de, T: serde::Deserialize<'de> + Hash> serde::Deserialize<'de> for MemoHash<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
T::deserialize(deserializer).map(|value| Self::new(value))
}
}
#[cfg(feature = "serde")]
impl<T: Hash + serde::Serialize> serde::Serialize for MemoHash<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.value.serialize(serializer)
}
}
#[cfg(feature = "std")]
impl<T: Hash> MemoHash<T> {
pub fn new(value: T) -> Self {
let hash = Self::calc_hash(&value);
Self { hash, value }
}
pub fn new_with_hash(value: T, hash: u64) -> Self {
Self { hash, value }
}
fn calc_hash(data: &T) -> u64 {
let mut hasher = std::collections::hash_map::DefaultHasher::new();
data.hash(&mut hasher);
hasher.finish()
}
pub fn inner_mut<'a>(&'a mut self) -> MemoHashGuard<'a, T> {
MemoHashGuard { inner: self }
}
pub fn into_inner<'a>(self) -> T {
self.value
}
pub fn hash_code(&self) -> u64 {
self.hash
}
}
impl<T: Hash> From<T> for MemoHash<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}
impl<T: Hash> Hash for MemoHash<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.hash.hash(state)
}
}
impl<T: Hash> core::ops::Deref for MemoHash<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
pub struct MemoHashGuard<'a, T: Hash> {
inner: &'a mut MemoHash<T>,
}
impl<'a, T: Hash> core::ops::Drop for MemoHashGuard<'a, T> {
fn drop(&mut self) {
let hash = MemoHash::<T>::calc_hash(&self.inner.value);
self.inner.hash = hash;
}
}
impl<'a, T: Hash> core::ops::Deref for MemoHashGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner.value
}
}
impl<'a, T: Hash> core::ops::DerefMut for MemoHashGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner.value
}
}

View File

@@ -830,9 +830,9 @@ impl Color {
/// ```
/// use graphene_core::raster::color::Color;
/// let color1 = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61).to_gamma_srgb();
/// assert_eq!("3240a261", color1.rgb_optional_a_hex())
/// let color2 = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61).to_gamma_srgb();
/// assert_eq!("3240a2", color2.rgb_optional_a_hex())
/// assert_eq!("3240a261", color1.rgb_optional_a_hex());
/// let color2 = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0xFF).to_gamma_srgb();
/// assert_eq!("5267fa", color2.rgb_optional_a_hex());
/// ```
#[cfg(feature = "std")]
pub fn rgb_optional_a_hex(&self) -> String {

View File

@@ -1,4 +1,5 @@
use super::*;
use crate::uuid::generate_uuid;
use crate::Node;
use bezier_rs::BezierHandles;
@@ -18,15 +19,7 @@ pub struct PointModification {
impl Hash for PointModification {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.add.hash(state);
let mut remove = self.remove.iter().collect::<Vec<_>>();
remove.sort_unstable();
remove.hash(state);
let mut delta = self.delta.iter().map(|(&a, &b)| (a, [b.x.to_bits(), b.y.to_bits()])).collect::<Vec<_>>();
delta.sort_unstable();
delta.hash(state);
generate_uuid().hash(state)
}
}
@@ -104,36 +97,6 @@ pub struct SegmentModification {
stroke: HashMap<SegmentId, StrokeId>,
}
impl Hash for SegmentModification {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.add.hash(state);
let mut remove = self.remove.iter().collect::<Vec<_>>();
remove.sort_unstable();
remove.hash(state);
let mut start_point = self.start_point.iter().map(|(&a, &b)| (a, b)).collect::<Vec<_>>();
start_point.sort_unstable();
start_point.hash(state);
let mut end_point = self.end_point.iter().map(|(&a, &b)| (a, b)).collect::<Vec<_>>();
end_point.sort_unstable();
end_point.hash(state);
let mut handle_primary = self.handle_primary.iter().map(|(&a, &b)| (a, b.map(|b| [b.x.to_bits(), b.y.to_bits()]))).collect::<Vec<_>>();
handle_primary.sort_unstable();
handle_primary.hash(state);
let mut handle_end = self.handle_end.iter().map(|(&a, &b)| (a, b.map(|b| [b.x.to_bits(), b.y.to_bits()]))).collect::<Vec<_>>();
handle_end.sort_unstable();
handle_end.hash(state);
let mut stroke = self.stroke.iter().map(|(&a, &b)| (a, b)).collect::<Vec<_>>();
stroke.sort_unstable();
stroke.hash(state);
}
}
impl SegmentModification {
/// Apply this modification to the specified [`SegmentDomain`].
pub fn apply(&self, segment_domain: &mut SegmentDomain, point_domain: &PointDomain) {
@@ -289,24 +252,6 @@ pub struct RegionModification {
fill: HashMap<RegionId, FillId>,
}
impl Hash for RegionModification {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.add.hash(state);
let mut remove = self.remove.iter().collect::<Vec<_>>();
remove.sort_unstable();
remove.hash(state);
let mut segment_range = self.segment_range.iter().map(|(&a, b)| (a, (*b.start(), *b.end()))).collect::<Vec<_>>();
segment_range.sort_unstable();
segment_range.hash(state);
let mut fill = self.fill.iter().map(|(&a, &b)| (a, b)).collect::<Vec<_>>();
fill.sort_unstable();
fill.hash(state);
}
}
impl RegionModification {
/// Apply this modification to the specified [`RegionDomain`].
pub fn apply(&self, region_domain: &mut RegionDomain) {
@@ -460,19 +405,7 @@ impl VectorModification {
impl core::hash::Hash for VectorModification {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.points.hash(state);
self.segments.hash(state);
self.regions.hash(state);
let mut add_g1_continuous = self.add_g1_continuous.iter().copied().collect::<Vec<_>>();
add_g1_continuous.sort_unstable();
add_g1_continuous.hash(state);
let mut remove_g1_continuous = self.remove_g1_continuous.iter().copied().collect::<Vec<_>>();
remove_g1_continuous.sort_unstable();
remove_g1_continuous.hash(state);
generate_uuid().hash(state)
}
}