mirror of
https://github.com/typst/typst
synced 2025-08-20 01:48:34 +08:00
Introduce HashLock
type
This factors out the memoized hash part of `LazyHash` for manual use
This commit is contained in:
parent
d2736918fb
commit
2f401f26e1
@ -30,9 +30,10 @@ use siphasher::sip128::{Hasher128, SipHasher13};
|
|||||||
/// # Usage
|
/// # Usage
|
||||||
/// If the value is expected to be cloned, it is best used inside of an `Arc`
|
/// If the value is expected to be cloned, it is best used inside of an `Arc`
|
||||||
/// or `Rc` to best re-use the hash once it has been computed.
|
/// or `Rc` to best re-use the hash once it has been computed.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct LazyHash<T: ?Sized> {
|
pub struct LazyHash<T: ?Sized> {
|
||||||
/// The hash for the value.
|
/// The hash for the value.
|
||||||
hash: AtomicU128,
|
hash: HashLock,
|
||||||
/// The underlying value.
|
/// The underlying value.
|
||||||
value: T,
|
value: T,
|
||||||
}
|
}
|
||||||
@ -48,16 +49,7 @@ impl<T> LazyHash<T> {
|
|||||||
/// Wraps an item without pre-computed hash.
|
/// Wraps an item without pre-computed hash.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(value: T) -> Self {
|
pub fn new(value: T) -> Self {
|
||||||
Self { hash: AtomicU128::new(0), value }
|
Self { hash: HashLock::new(), value }
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrap an item with a pre-computed hash.
|
|
||||||
///
|
|
||||||
/// **Important:** The hash must be correct for the value. This cannot be
|
|
||||||
/// enforced at compile time, so use with caution.
|
|
||||||
#[inline]
|
|
||||||
pub fn reuse<U: ?Sized>(value: T, existing: &LazyHash<U>) -> Self {
|
|
||||||
LazyHash { hash: AtomicU128::new(existing.load_hash()), value }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the wrapped value.
|
/// Returns the wrapped value.
|
||||||
@ -67,33 +59,11 @@ impl<T> LazyHash<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized> LazyHash<T> {
|
|
||||||
/// Get the hash, returns zero if not computed yet.
|
|
||||||
#[inline]
|
|
||||||
fn load_hash(&self) -> u128 {
|
|
||||||
// We only need atomicity and no synchronization of other operations, so
|
|
||||||
// `Relaxed` is fine.
|
|
||||||
self.hash.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Hash + ?Sized + 'static> LazyHash<T> {
|
impl<T: Hash + ?Sized + 'static> LazyHash<T> {
|
||||||
/// Get the hash or compute it if not set yet.
|
/// Get the hash or compute it if not set yet.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn load_or_compute_hash(&self) -> u128 {
|
fn load_or_compute_hash(&self) -> u128 {
|
||||||
let mut hash = self.load_hash();
|
self.hash.get_or_insert_with(|| hash_item(&self.value))
|
||||||
if hash == 0 {
|
|
||||||
hash = hash_item(&self.value);
|
|
||||||
self.hash.store(hash, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
hash
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reset the hash to zero.
|
|
||||||
#[inline]
|
|
||||||
fn reset_hash(&mut self) {
|
|
||||||
// Because we have a mutable reference, we can skip the atomic.
|
|
||||||
*self.hash.get_mut() = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,23 +110,14 @@ impl<T: ?Sized> Deref for LazyHash<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash + ?Sized + 'static> DerefMut for LazyHash<T> {
|
impl<T: ?Sized + 'static> DerefMut for LazyHash<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.reset_hash();
|
self.hash.reset();
|
||||||
&mut self.value
|
&mut self.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash + Clone + 'static> Clone for LazyHash<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
hash: AtomicU128::new(self.load_hash()),
|
|
||||||
value: self.value.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Debug> Debug for LazyHash<T> {
|
impl<T: Debug> Debug for LazyHash<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.value.fmt(f)
|
self.value.fmt(f)
|
||||||
@ -233,3 +194,51 @@ impl<T: Debug> Debug for ManuallyHash<T> {
|
|||||||
self.value.fmt(f)
|
self.value.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Storage for lazy hash computation.
|
||||||
|
pub struct HashLock(AtomicU128);
|
||||||
|
|
||||||
|
impl HashLock {
|
||||||
|
/// Create a new unset hash cell.
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self(AtomicU128::new(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the hash or compute it if not set yet.
|
||||||
|
#[inline]
|
||||||
|
pub fn get_or_insert_with(&self, f: impl FnOnce() -> u128) -> u128 {
|
||||||
|
let mut hash = self.get();
|
||||||
|
if hash == 0 {
|
||||||
|
hash = f();
|
||||||
|
self.0.store(hash, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
hash
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset the hash to unset.
|
||||||
|
#[inline]
|
||||||
|
pub fn reset(&mut self) {
|
||||||
|
// Because we have a mutable reference, we can skip the atomic.
|
||||||
|
*self.0.get_mut() = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the hash, returns zero if not computed yet.
|
||||||
|
#[inline]
|
||||||
|
fn get(&self) -> u128 {
|
||||||
|
// We only need atomicity and no synchronization of other operations, so
|
||||||
|
// `Relaxed` is fine.
|
||||||
|
self.0.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for HashLock {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for HashLock {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(AtomicU128::new(self.get()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ mod scalar;
|
|||||||
pub use self::bitset::{BitSet, SmallBitSet};
|
pub use self::bitset::{BitSet, SmallBitSet};
|
||||||
pub use self::deferred::Deferred;
|
pub use self::deferred::Deferred;
|
||||||
pub use self::duration::format_duration;
|
pub use self::duration::format_duration;
|
||||||
pub use self::hash::{LazyHash, ManuallyHash};
|
pub use self::hash::{HashLock, LazyHash, ManuallyHash};
|
||||||
pub use self::pico::{PicoStr, ResolvedPicoStr};
|
pub use self::pico::{PicoStr, ResolvedPicoStr};
|
||||||
pub use self::round::{round_int_with_precision, round_with_precision};
|
pub use self::round::{round_int_with_precision, round_with_precision};
|
||||||
pub use self::scalar::Scalar;
|
pub use self::scalar::Scalar;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user