use crate::dep_graph::DepNodeIndex; use crate::query::plumbing::{QueryLookup, QueryState}; use crate::query::QueryContext; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sharded::Sharded; use std::default::Default; use std::hash::Hash; use std::marker::PhantomData; pub trait CacheSelector { type Cache: QueryCache; } pub trait QueryCache: Default { type Key: Hash; type Value; type Sharded: Default; /// Checks if the query is already computed and in the cache. /// It returns the shard index and a lock guard to the shard, /// which will be used if the query is not in the cache and we need /// to compute it. fn lookup( &self, state: &QueryState, key: Self::Key, // `on_hit` can be called while holding a lock to the query state shard. on_hit: OnHit, on_miss: OnMiss, ) -> R where OnHit: FnOnce(&Self::Value, DepNodeIndex) -> R, OnMiss: FnOnce(Self::Key, QueryLookup<'_, CTX, Self::Key, Self::Sharded>) -> R; fn complete( &self, tcx: CTX, lock_sharded_storage: &mut Self::Sharded, key: Self::Key, value: Self::Value, index: DepNodeIndex, ); fn iter( &self, shards: &Sharded, get_shard: impl Fn(&mut L) -> &mut Self::Sharded, f: impl for<'a> FnOnce( Box + 'a>, ) -> R, ) -> R; } pub struct DefaultCacheSelector; impl CacheSelector for DefaultCacheSelector { type Cache = DefaultCache; } pub struct DefaultCache(PhantomData<(K, V)>); impl Default for DefaultCache { fn default() -> Self { DefaultCache(PhantomData) } } impl QueryCache for DefaultCache { type Key = K; type Value = V; type Sharded = FxHashMap; #[inline(always)] fn lookup( &self, state: &QueryState, key: K, on_hit: OnHit, on_miss: OnMiss, ) -> R where OnHit: FnOnce(&V, DepNodeIndex) -> R, OnMiss: FnOnce(K, QueryLookup<'_, CTX, K, Self::Sharded>) -> R, { let mut lookup = state.get_lookup(&key); let lock = &mut *lookup.lock; let result = lock.cache.raw_entry().from_key_hashed_nocheck(lookup.key_hash, &key); if let Some((_, value)) = result { on_hit(&value.0, value.1) } else { on_miss(key, lookup) } } #[inline] fn complete( &self, _: CTX, lock_sharded_storage: &mut Self::Sharded, key: K, value: V, index: DepNodeIndex, ) { lock_sharded_storage.insert(key, (value, index)); } fn iter( &self, shards: &Sharded, get_shard: impl Fn(&mut L) -> &mut Self::Sharded, f: impl for<'a> FnOnce(Box + 'a>) -> R, ) -> R { let mut shards = shards.lock_shards(); let mut shards: Vec<_> = shards.iter_mut().map(|shard| get_shard(shard)).collect(); let results = shards.iter_mut().flat_map(|shard| shard.iter()).map(|(k, v)| (k, &v.0, v.1)); f(Box::new(results)) } }