CachedHash

Struct CachedHash 

Source
pub struct CachedHash<T: Eq + Hash, BH: BuildHasher = BuildHasherDefault<DefaultHasher>> { /* private fields */ }
Expand description

For a type T, CachedHash wraps T and implements Hash in a way that caches T’s hash value. The first time the hash is computed, it is stored and returned on subsequent calls. When the stored value is accessed mutably the hash is invalidated and needs to be recomputed again. CachedHash implements Deref and DerefMut so it can be used as a drop-in replacement for T.

In order for the hash to be invalidated correctly the stored type cannot use interior mutability in a way that affects the hash. If this is the case, you can use CachedHash::invalidate_hash to invalidate the hash manually.

By default the internal hash is computed using DefaultHasher. You can change this by providing a custom Hasher to CachedHash::new_with_hasher or even a custom BuildHasher to CachedHash::new_with_build_hasher. For most use cases you should not need to do this.

Note that the hash of a value of type T and the same value wrapped in CachedHash are generally different.

§Why is this useful?

Sometimes you have a type that is expensive to hash (for example because) it is very large) but you need to store and move it between multiple HashSets In this case you can wrap the type in CachedHash to cache the hash value only once.

However, when the type is modified often CachedHash loses its advantage as the hash will get invalidated on every modification. CachedHash also needs to store the u64 hash value which takes up some space.

You can run cargo bench to see some simple naive benchmarks comparing a plain HashSet with a HashSet that stores values wrapped in CachedHash.

§Details

Whenever the hash is requested if it is not already computed it is computed using the hasher provided by the BH BuildHasher and stored as an “internal hash”. Note that this is not the same as the hash returned by the Hash implementation. That implementation feeds the internal hash into the hasher provided to the hash function. This means that the resulting hash is the hash of the hash of the stored value.

However, there is one more issue. If we wanted to represent both the full range of hash values and the possibility of the hash not being computed yet, we would need 65 bits. In order to save space we need to reserve one value as a sentinel (this also lets us work with the stored “maybe-hash” atomically). This means that we need to artificially create a hash collision. Current implementation does this by changing the “internal hash” from 0 to 1 if it ends up being zero. This is generally not an issue. However, if you are using a custom hasher this might affect you.

This behaviour is not guaranteed and may change in the future. If this behaviour does not fit for your use case please open an issue.

Implementations§

Source§

impl<T: Eq + Hash> CachedHash<T>

Source

pub fn new(value: T) -> Self

Creates a new CachedHash with the given value using DefaultHasher.

Note that the BuildHasher stored in the structure is a zero-sized type that is both Send and Sync so it will not affect the Send and Sync properties of CachedHash nor its size.

Source§

impl<T: Eq + Hash, H: Hasher + Default> CachedHash<T, BuildHasherDefault<H>>

Source

pub fn new_with_hasher(value: T) -> Self

Creates a new CachedHash with the given value using a provided hasher type implementing Default.

Note that the BuildHasher stored in the structure is a zero-sized type that is both Send and Sync so it will not affect the Send and Sync properties of CachedHash nor its size.

Source§

impl<T: Eq + Hash, BH: BuildHasher> CachedHash<T, BH>

Source

pub const fn new_with_build_hasher(value: T, build_hasher: BH) -> Self

Creates a new CachedHash with the given value and BuildHasher.

Note that build_hasher is stored in the structure and as such it can cause the type to stop being Send and Sync if the hasher is not. It can also increase the size of the structure.

Source

pub fn invalidate_hash(this: &mut Self)

Explicitly invalidates the cached hash. This should not be necessary in most cases as the hash will be automatically invalidated when the value is accessed mutably. However, if the value uses interior mutability in a way that affects the hash, you will need to call this function manually whenever the hash might have changed.

Source

pub fn take_value(this: Self) -> T

Destructs the CachedHash and returns the stored value.

Source

pub const fn get(this: &Self) -> &T

Explicitly returns an immutable reference to the stored value.

Most of the time this will not be necessary as CachedHash implements Deref so autoderef rules will automatically dereference it to the stored value.

Source

pub fn get_mut(this: &mut Self) -> &mut T

Explicitly returns a mutable reference to the stored value and invalidates the cached hash.

Most of the time this will not be necessary as CachedHash implements DerefMut so autoderef rules will automatically dereference it to the stored value. (Such dereference still invalidates the stored hash.)

Trait Implementations§

Source§

impl<T: Eq + Hash, BH: BuildHasher> AsMut<T> for CachedHash<T, BH>

Source§

fn as_mut(&mut self) -> &mut T

Converts this type into a mutable reference of the (usually inferred) input type.
Source§

impl<T: Eq + Hash, BH: BuildHasher> AsRef<T> for CachedHash<T, BH>

Source§

fn as_ref(&self) -> &T

Converts this type into a shared reference of the (usually inferred) input type.
Source§

impl<T: Eq + Hash, BH: BuildHasher> Borrow<T> for CachedHash<T, BH>

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T: Eq + Hash, BH: BuildHasher> BorrowMut<T> for CachedHash<T, BH>

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T: Eq + Hash + Clone, BH: BuildHasher + Clone> Clone for CachedHash<T, BH>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug + Eq + Hash, BH: Debug + BuildHasher> Debug for CachedHash<T, BH>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T: Eq + Hash, BH: BuildHasher> Deref for CachedHash<T, BH>

Source§

type Target = T

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.
Source§

impl<T: Eq + Hash, BH: BuildHasher> DerefMut for CachedHash<T, BH>

Source§

fn deref_mut(&mut self) -> &mut Self::Target

Mutably dereferences the value.
Source§

impl<T: Eq + Hash, H: Hasher + Default> From<T> for CachedHash<T, BuildHasherDefault<H>>

Source§

fn from(value: T) -> Self

Converts to this type from the input type.
Source§

impl<T: Eq + Hash, BH: BuildHasher> Hash for CachedHash<T, BH>

Source§

fn hash<H2: Hasher>(&self, state: &mut H2)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<T: Eq + Hash + Ord> Ord for CachedHash<T>

Source§

fn cmp(&self, other: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl<T: Eq + Hash, BH: BuildHasher> PartialEq for CachedHash<T, BH>

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T: Eq + Hash + PartialOrd> PartialOrd for CachedHash<T>

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl<T: Eq + Hash, BH: BuildHasher> Eq for CachedHash<T, BH>

Auto Trait Implementations§

§

impl<T, BH = BuildHasherDefault<DefaultHasher>> !Freeze for CachedHash<T, BH>

§

impl<T, BH> RefUnwindSafe for CachedHash<T, BH>

§

impl<T, BH> Send for CachedHash<T, BH>
where T: Send, BH: Send,

§

impl<T, BH> Sync for CachedHash<T, BH>
where T: Sync, BH: Sync,

§

impl<T, BH> Unpin for CachedHash<T, BH>
where T: Unpin, BH: Unpin,

§

impl<T, BH> UnwindSafe for CachedHash<T, BH>
where T: UnwindSafe, BH: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<!> for T

Source§

fn from(t: !) -> T

Converts to this type from the input type.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.