use alloy::primitives::{Address, StorageValue, U256};
use parking_lot::Mutex;
use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Default)]
struct Inner {
map: HashMap<(Address, U256), StorageValue>,
}
#[derive(Default)]
pub struct StorageMemo {
inner: Mutex<Inner>,
hits: AtomicU64,
misses: AtomicU64,
}
impl StorageMemo {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn get(&self, address: Address, index: U256) -> Option<StorageValue> {
let inner = self.inner.lock();
let hit = inner.map.get(&(address, index)).copied();
if hit.is_some() {
self.hits.fetch_add(1, Ordering::Relaxed);
} else {
self.misses.fetch_add(1, Ordering::Relaxed);
}
hit
}
pub fn put(&self, address: Address, index: U256, value: StorageValue) {
self.inner.lock().map.insert((address, index), value);
}
#[must_use]
pub fn stats(&self) -> (u64, u64) {
(
self.hits.load(Ordering::Relaxed),
self.misses.load(Ordering::Relaxed),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trip_and_stats() {
let memo = StorageMemo::new();
let addr = Address::ZERO;
let key = U256::from(7u64);
assert_eq!(memo.get(addr, key), None);
memo.put(addr, key, StorageValue::from(42u64));
assert_eq!(memo.get(addr, key), Some(StorageValue::from(42u64)));
let (h, m) = memo.stats();
assert_eq!((h, m), (1, 1));
}
}