From ca3c15858d870cc96a459c531178614d1a302a97 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Wed, 20 Sep 2023 15:19:59 +0200 Subject: [PATCH] Use portable hash function for `CacheKey` (#7533) --- Cargo.lock | 7 ++ crates/ruff_cache/Cargo.toml | 1 + crates/ruff_cache/src/cache_key.rs | 123 ++++++++++++++++++++------- crates/ruff_cache/src/filetime.rs | 2 +- crates/ruff_cache/tests/cache_key.rs | 13 ++- 5 files changed, 105 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc4bee1f2f..a9d3035cf6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2058,6 +2058,7 @@ dependencies = [ "itertools 0.11.0", "regex", "ruff_macros", + "seahash", ] [[package]] @@ -2665,6 +2666,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "semver" version = "1.0.18" diff --git a/crates/ruff_cache/Cargo.toml b/crates/ruff_cache/Cargo.toml index b166bbf36a..7adcf640bc 100644 --- a/crates/ruff_cache/Cargo.toml +++ b/crates/ruff_cache/Cargo.toml @@ -16,6 +16,7 @@ glob = { workspace = true } globset = { workspace = true } regex = { workspace = true } filetime = { workspace = true } +seahash = "4.1.0" [dev-dependencies] ruff_macros = { path = "../ruff_macros" } diff --git a/crates/ruff_cache/src/cache_key.rs b/crates/ruff_cache/src/cache_key.rs index c62e580d1e..ccc0e41c0e 100644 --- a/crates/ruff_cache/src/cache_key.rs +++ b/crates/ruff_cache/src/cache_key.rs @@ -1,41 +1,13 @@ use std::borrow::Cow; -use std::collections::hash_map::DefaultHasher; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::hash::{Hash, Hasher}; use std::num::NonZeroU8; -use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; use glob::Pattern; use itertools::Itertools; use regex::Regex; - -#[derive(Clone, Debug, Default)] -pub struct CacheKeyHasher { - inner: DefaultHasher, -} - -impl CacheKeyHasher { - pub fn new() -> Self { - Self { - inner: DefaultHasher::new(), - } - } -} - -impl Deref for CacheKeyHasher { - type Target = DefaultHasher; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for CacheKeyHasher { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} +use seahash::SeaHasher; /// A type that be used as part of a cache key. /// @@ -255,14 +227,14 @@ impl_cache_key_tuple! { T B C D E F G H I J K L } impl CacheKey for str { #[inline] fn cache_key(&self, state: &mut CacheKeyHasher) { - self.hash(&mut **state); + self.hash(&mut *state); } } impl CacheKey for String { #[inline] fn cache_key(&self, state: &mut CacheKeyHasher) { - self.hash(&mut **state); + self.hash(&mut *state); } } @@ -360,14 +332,14 @@ impl CacheKey for BTreeMap { impl CacheKey for Path { #[inline] fn cache_key(&self, state: &mut CacheKeyHasher) { - self.hash(&mut **state); + self.hash(&mut *state); } } impl CacheKey for PathBuf { #[inline] fn cache_key(&self, state: &mut CacheKeyHasher) { - self.hash(&mut **state); + self.as_path().cache_key(state); } } @@ -391,3 +363,88 @@ impl CacheKey for Pattern { self.as_str().cache_key(state); } } + +#[derive(Clone, Default)] +pub struct CacheKeyHasher { + inner: SeaHasher, +} + +impl CacheKeyHasher { + pub fn new() -> Self { + Self { + inner: SeaHasher::new(), + } + } +} + +impl Hasher for CacheKeyHasher { + #[inline] + fn finish(&self) -> u64 { + self.inner.finish() + } + + #[inline] + fn write(&mut self, bytes: &[u8]) { + self.inner.write(bytes); + } + + #[inline] + fn write_u8(&mut self, i: u8) { + self.inner.write_u8(i); + } + + #[inline] + fn write_u16(&mut self, i: u16) { + self.inner.write_u16(i); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.inner.write_u32(i); + } + + #[inline] + fn write_u64(&mut self, i: u64) { + self.inner.write_u64(i); + } + + #[inline] + fn write_u128(&mut self, i: u128) { + self.inner.write_u128(i); + } + + #[inline] + fn write_usize(&mut self, i: usize) { + self.inner.write_usize(i); + } + + #[inline] + fn write_i8(&mut self, i: i8) { + self.inner.write_i8(i); + } + + #[inline] + fn write_i16(&mut self, i: i16) { + self.inner.write_i16(i); + } + + #[inline] + fn write_i32(&mut self, i: i32) { + self.inner.write_i32(i); + } + + #[inline] + fn write_i64(&mut self, i: i64) { + self.inner.write_i64(i); + } + + #[inline] + fn write_i128(&mut self, i: i128) { + self.inner.write_i128(i); + } + + #[inline] + fn write_isize(&mut self, i: isize) { + self.inner.write_isize(i); + } +} diff --git a/crates/ruff_cache/src/filetime.rs b/crates/ruff_cache/src/filetime.rs index 29c2d074a5..3733173759 100644 --- a/crates/ruff_cache/src/filetime.rs +++ b/crates/ruff_cache/src/filetime.rs @@ -6,6 +6,6 @@ use crate::{CacheKey, CacheKeyHasher}; impl CacheKey for FileTime { fn cache_key(&self, state: &mut CacheKeyHasher) { - self.hash(&mut **state); + self.hash(&mut *state); } } diff --git a/crates/ruff_cache/tests/cache_key.rs b/crates/ruff_cache/tests/cache_key.rs index 43e8f09203..898d430d4e 100644 --- a/crates/ruff_cache/tests/cache_key.rs +++ b/crates/ruff_cache/tests/cache_key.rs @@ -1,4 +1,3 @@ -use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use ruff_cache::{CacheKey, CacheKeyHasher}; @@ -29,7 +28,7 @@ fn unit_struct_cache_key() { UnitStruct.cache_key(&mut key); - let mut hash = DefaultHasher::new(); + let mut hash = CacheKeyHasher::new(); UnitStruct.hash(&mut hash); assert_eq!(hash.finish(), key.finish()); @@ -46,7 +45,7 @@ fn named_field_struct() { named_fields.cache_key(&mut key); - let mut hash = DefaultHasher::new(); + let mut hash = CacheKeyHasher::new(); named_fields.hash(&mut hash); assert_eq!(hash.finish(), key.finish()); @@ -60,7 +59,7 @@ fn unnamed_field_struct() { unnamed_fields.cache_key(&mut key); - let mut hash = DefaultHasher::new(); + let mut hash = CacheKeyHasher::new(); unnamed_fields.hash(&mut hash); assert_eq!(hash.finish(), key.finish()); @@ -73,7 +72,7 @@ fn enum_unit_variant() { let variant = Enum::Unit; variant.cache_key(&mut key); - let mut hash = DefaultHasher::new(); + let mut hash = CacheKeyHasher::new(); variant.hash(&mut hash); assert_eq!(hash.finish(), key.finish()); @@ -89,7 +88,7 @@ fn enum_named_fields_variant() { }; variant.cache_key(&mut key); - let mut hash = DefaultHasher::new(); + let mut hash = CacheKeyHasher::new(); variant.hash(&mut hash); assert_eq!(hash.finish(), key.finish()); @@ -102,7 +101,7 @@ fn enum_unnamed_fields_variant() { let variant = Enum::UnnamedFields("Hello".to_string(), "World".to_string()); variant.cache_key(&mut key); - let mut hash = DefaultHasher::new(); + let mut hash = CacheKeyHasher::new(); variant.hash(&mut hash); assert_eq!(hash.finish(), key.finish());