fn_cache/
hash_cache.rs

1use std::collections::hash_map::RandomState;
2use std::collections::HashMap;
3
4use core::cmp::Eq;
5use core::hash::BuildHasher;
6use core::hash::Hash;
7
8use derive_more::derive::{Deref, DerefMut, From};
9
10use crate::container::{
11	ContainerClear, ContainerLen, ContainerRemove, ContainerReserve, SparseContainer,
12};
13use crate::generic_cache::{GenericCache, RefCache};
14
15/// A cache for a function which uses a [`HashMap`].
16///
17/// The cache takes ownership of all inputs, but
18/// only passes a reference to the function,
19/// allowing it to store the input in the cache
20/// without any copies or clones.
21///
22/// The requirements for a `HashMap` must be met,
23/// specifically the keys must implement `Eq` and
24/// `Hash`, and the following propery must hold:
25///
26/// ```k1 == k2 -> hash(k1) == hash(k2)```
27#[derive(Deref, DerefMut, From)]
28pub struct HashCache<'f, I, O, S = RandomState>
29where
30	I: Eq + Hash,
31	S: BuildHasher,
32{
33	raw: GenericCache<'f, HashMap<I, O, S>>,
34}
35
36impl<'f, I, O> HashCache<'f, I, O, RandomState>
37where
38	I: Eq + Hash,
39{
40	pub fn new(f: impl Fn(&I) -> O + Send + 'f) -> Self {
41		Self {
42			raw: GenericCache::new(f),
43		}
44	}
45
46	pub fn recursive(f: impl Fn(&mut RefCache<HashMap<I, O>>, &I) -> O + Send + 'f) -> Self {
47		Self {
48			raw: GenericCache::recursive(f),
49		}
50	}
51}
52
53impl<'f, I, O, S> HashCache<'f, I, O, S>
54where
55	I: Eq + Hash,
56	S: BuildHasher,
57{
58	pub fn with_hasher(hash_builder: S, f: impl Fn(&I) -> O + Send + 'f) -> Self {
59		Self {
60			raw: GenericCache::with_cache(HashMap::with_hasher(hash_builder), f),
61		}
62	}
63
64	pub fn recursive_with_hasher(
65		hash_builder: S,
66		f: impl Fn(&mut RefCache<HashMap<I, O, S>>, &I) -> O + Send + 'f,
67	) -> Self {
68		Self {
69			raw: GenericCache::recursive_with_cache(HashMap::with_hasher(hash_builder), f),
70		}
71	}
72}
73
74impl<I, O, S> SparseContainer for std::collections::HashMap<I, O, S>
75where
76	I: Eq + std::hash::Hash,
77	S: std::hash::BuildHasher,
78{
79	type Input = I;
80	type Output = O;
81
82	fn has(&self, input: &I) -> bool {
83		self.contains_key(input)
84	}
85	fn get(&self, input: &I) -> Option<&O> {
86		self.get(input)
87	}
88
89	fn put(&mut self, input: I, output: O) -> &O {
90		self.entry(input).or_insert(output)
91	}
92}
93
94impl<I, O, S> ContainerLen for std::collections::HashMap<I, O, S>
95where
96	I: Eq + std::hash::Hash,
97	S: std::hash::BuildHasher,
98{
99	fn len(&self) -> usize {
100		self.len()
101	}
102}
103
104impl<I, O, S> ContainerClear for std::collections::HashMap<I, O, S>
105where
106	I: Eq + std::hash::Hash,
107	S: std::hash::BuildHasher,
108{
109	fn clear(&mut self) {
110		self.clear()
111	}
112}
113
114impl<I, O, S> ContainerReserve for std::collections::HashMap<I, O, S>
115where
116	I: Eq + std::hash::Hash,
117	S: std::hash::BuildHasher,
118{
119	fn reserve(&mut self, additional: usize) {
120		self.reserve(additional)
121	}
122}
123
124impl<I, O, S> ContainerRemove for std::collections::HashMap<I, O, S>
125where
126	I: Eq + std::hash::Hash,
127	S: std::hash::BuildHasher,
128{
129	fn remove(&mut self, input: &I) -> Option<O> {
130		self.remove(input)
131	}
132}