Module rustc_utils::cache
source · Expand description
Data structures for memoizing computations.
Contruct new caches using Default::default
, then construct/retrieve
elements with get
. get
should only ever be used with one,
compute
function1.
In terms of choice,
CopyCache
should be used for expensive computations that create cheap (i.e. small) values.Cache
should be used for expensive computations that create expensive (i.e. large) values.
Both types of caches implement recursion breaking. In general because
caches are supposed to be used as simple &
(no mut
) the reference may be
freely copied, including into the compute
closure. What this means is that
a compute
may call get
on the cache again. This is usually
safe and can be used to compute data structures that recursively depend on
one another, dynamic-programming style. However if a get
on a key k
itself calls get
again on the same k
this will either create an infinite
recursion or an inconsistent cache1.
Consider a simple example where we compute the Fibonacci Series with a
CopyCache
:
struct Fib(CopyCache<u32, u32>);
impl Fib {
fn get(&self, i: u32) -> u32 {
self.0.get(i, |_| {
if this <= 1 {
return this;
}
let fib_1 = self.get(this - 1);
let fib_2 = self.get(this - 2);
fib_1 + fib_2
})
}
}
let cache = Fib(Default::default());
let fib_5 = cache.get(5);
This use of recursive get
calls is perfectly legal.
However if we made an error and called chache.get(this, ...)
(forgetting
the decrement) we would have created an inadvertend infinite recursion.
To avoid this scenario both caches are implemented to detect when a
recursive call as described is performed and get
will panic. If your code
uses recursive construction and would like to handle this case gracefully
use get_maybe_recursive
instead wich returns
None
from get(k)
iff k
this call (potentially transitively)
originates from another get(k)
call.
For any given cache value
get
should only ever be used with one, referentially transparentcompute
function. Essentially this means runningcompute(k)
should always return the same value independent of the state of it’s environment. Violation of this rule can introduces non-determinism in your program. ↩
Structs
- Cache for non-copyable types.
- Cache for copyable types.