Struct ReusableHashMap

Source
pub struct ReusableHashMap<K: 'static, V: 'static, S: 'static + BuildHasher + Default = RandomState> { /* private fields */ }
Expand description

A wrapper around HashMap that allows for reusing its allocation across different key and value types, provided they are compatible.

ReusableHashMap is designed for performance-critical scenarios where heap allocations are a bottleneck. By recycling the HashMap’s allocation, you can avoid the overhead of deallocating and reallocating memory between operations.

The core of this mechanism is the recycle method, which returns a ReusableHashMapGuard. This guard provides temporary, exclusive access to the underlying HashMap. When the guard is dropped, the map is cleared, but its allocation is preserved and ready for the next use.

The type parameters K and V must be 'static to ensure that the ReusableHashMap can hold any value type. The actual lifetime and type constraints are enforced on the recycle method.

§Safety

This struct uses UnsafeCell to hold the HashMap, which allows for mutating the map’s contents even with a shared reference. The safety of this operation is guaranteed by the recycle method, which requires a mutable reference to self, ensuring that only one ReusableHashMapGuard can exist at a time. This prevents concurrent access and data races.

§Examples

Basic reuse with the same types:

use triple_r::ReusableHashMap;

let mut reusable_map = ReusableHashMap::<String, i32>::default();

// First use
{
    let mut map_guard = reusable_map.recycle::<String, i32>();
    map_guard.insert("one".to_string(), 1);
    assert_eq!(map_guard.get("one"), Some(&1));
} // map_guard is dropped here, and the map is cleared.

// The map is now empty, but its allocation is ready for reuse.
// Second use
{
    let mut map_guard = reusable_map.recycle::<String, i32>();
    assert!(map_guard.is_empty());
    map_guard.insert("two".to_string(), 2);
    assert_eq!(map_guard.len(), 1);
}

Reusing a map with different lifetimes:

use triple_r::{ReusableHashMap, ReuseCastInto};

// This trait implementation is necessary to allow the cast.
// It is already implemented for references in the crate.
// unsafe impl<'l1, 'l2, T: ?Sized> ReuseCastInto<&'l2 T> for &'l1 T {}

let mut reusable_map = ReusableHashMap::<&'static str, i32>::default();

{
    let key = "temporary";
    let mut map_guard = reusable_map.recycle::<&str, i32>();
    map_guard.insert(key, 100);
    assert_eq!(map_guard.get(key), Some(&100));
} // The guard is dropped, and `key` can no longer be accessed through it.

Implementations§

Source§

impl<K1, V1, S> ReusableHashMap<K1, V1, S>
where K1: 'static, V1: 'static, S: 'static + BuildHasher + Default,

Source

pub fn recycle<'parent, K2, V2>( &'parent mut self, ) -> ReusableHashMapGuard<'parent, K1, V1, K2, V2, S>
where K1: ReuseCastInto<K2>, V1: ReuseCastInto<V2>,

Borrows the HashMap for temporary use, returning a guard that allows access to it.

This method allows you to “cast” the key and value types of the HashMap to new types (K2, V2), provided that the original types (K1, V1) implement ReuseCastInto<K2> and ReuseCastInto<V2> respectively.

Taking &mut self as a parameter is crucial for safety, as it ensures that only one ReusableHashMapGuard can exist at any given time for a specific ReusableHashMap. This prevents data races.

When the returned guard is dropped, the map is cleared, but its memory allocation is preserved for future use.

§Type Parameters
  • 'parent: The lifetime of the returned guard, tied to the mutable borrow of self.
  • K2, V2: The new key and value types to use for the HashMap.
§Safety

This method performs a transmutation of the HashMap’s generic types. It is safe because:

  1. The ReuseCastInto trait bounds ensure that the type transmutation is valid (e.g., &'static str to &'a str).
  2. The borrow checker ensures the returned guard does not outlive self.
  3. The &mut self receiver prevents multiple guards from being created simultaneously.
§Examples
use triple_r::ReusableHashMap;

let mut map = ReusableHashMap::<String, String>::default();
{
    let mut guard = map.recycle::<String, String>();
    guard.insert("key".to_string(), "value".to_string());
    assert_eq!(guard.len(), 1);
} // Guard is dropped, map is cleared.

assert!(map.recycle::<String, String>().is_empty());

Trait Implementations§

Source§

impl<K: Debug + 'static, V: Debug + 'static, S: Debug + 'static + BuildHasher + Default> Debug for ReusableHashMap<K, V, S>

Source§

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

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

impl<K: 'static, V: 'static, S: 'static + BuildHasher + Default> Default for ReusableHashMap<K, V, S>

Source§

fn default() -> Self

Creates a new, empty ReusableHashMap with the default hasher.

§Examples
use triple_r::ReusableHashMap;

let mut map = ReusableHashMap::<String, i32>::default();
assert_eq!(map.recycle::<String, i32>().capacity(), 0);
Source§

impl<K: Send, V: Send, S: 'static + Send + BuildHasher + Default> Send for ReusableHashMap<K, V, S>

Source§

impl<K: Send, V: Send, S: 'static + Send + BuildHasher + Default> Sync for ReusableHashMap<K, V, S>

Auto Trait Implementations§

§

impl<K, V, S = RandomState> !Freeze for ReusableHashMap<K, V, S>

§

impl<K, V, S = RandomState> !RefUnwindSafe for ReusableHashMap<K, V, S>

§

impl<K, V, S> Unpin for ReusableHashMap<K, V, S>
where S: Unpin, K: Unpin, V: Unpin,

§

impl<K, V, S> UnwindSafe for ReusableHashMap<K, V, S>
where K: UnwindSafe, V: UnwindSafe, S: 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> 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<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.