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,
impl<K1, V1, S> ReusableHashMap<K1, V1, S>where
K1: 'static,
V1: 'static,
S: 'static + BuildHasher + Default,
Sourcepub fn recycle<'parent, K2, V2>(
&'parent mut self,
) -> ReusableHashMapGuard<'parent, K1, V1, K2, V2, S>where
K1: ReuseCastInto<K2>,
V1: ReuseCastInto<V2>,
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 ofself.K2,V2: The new key and value types to use for theHashMap.
§Safety
This method performs a transmutation of the HashMap’s generic types.
It is safe because:
- The
ReuseCastIntotrait bounds ensure that the type transmutation is valid (e.g.,&'static strto&'a str). - The borrow checker ensures the returned guard does not outlive
self. - The
&mut selfreceiver 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());