A generic in-memory cache with LRU/LFU/ARC/WindowTinyLfu eviction, TTL expiry, and a memoizing get-or-insert helper
Dependencies
moon add jhshuai/moonlardermoon run cmd/main --target wasm-gclet cache : Larder[String, Int] = Larder::new(capacity=100, default_ttl_ms=60_000L)
cache.set("answer", 42, now_ms=0L)
cache.get("answer", now_ms=1_000L) // Some(42)
// Memoize an expensive computation: recomputed only on a miss or expiry.
let value = cache.get_or_insert_with("expensive", now_ms=0L, fn() {
compute_expensive_thing()
})cache.set("short-lived", "value", now_ms=0L, ttl_ms=5_000L)cache.set_many([("a", 1), ("b", 2), ("c", 3)], now_ms=0L)
let found = cache.get_many(["a", "missing", "c"], now_ms=0L)
// found == [("a", 1), ("c", 3)] - only the hits, in the order askedlet by_size : Larder[String, Bytes] = Larder::new(
capacity=10 * 1024 * 1024, // 10 MiB total, not 10 MiB per entry
weigher=fn(_key, value) { value.length() },
)let cache : Larder[String, Int] = Larder::new(capacity=100, policy=Lfu)let cache : Larder[String, Int] = Larder::new(capacity=100, policy=Arc)let sketch : FrequencySketch[String] = FrequencySketch::new(capacity=10_000)
sketch.increment("popular-key")
sketch.increment("popular-key")
sketch.estimate("popular-key") // 2 - never lower than the true count,
// possibly higher from hash collisionslet cache : Larder[String, Int] = Larder::new(capacity=100, admission_filter=true)let cache : Larder[String, Int] = Larder::new(capacity=100, policy=WindowTinyLfu)let snapshot : Json = ToJson::to_json(cache)
let restored : Larder[String, Int] = @json.from_json(snapshot)let cache : Larder[String, Handle] = Larder::new(
capacity=1000,
on_remove=fn(_key, handle, _cause) { handle.close() },
)moon bench --target wasm-gc| capacity | get, real | get, naive | ratio | set, real | set, naive | ratio |
|---|---|---|---|---|---|---|
| 100 | 86 ns | 849 ns | ~10x | 141 ns | 827 ns | ~5.9x |
| 1,000 | 28.6 ns | 4.09 µs | ~143x | 72.3 ns | 6.92 µs | ~96x |
| 10,000 | 26.1 ns | 87.7 µs | ~3,360x | 211 ns | 169.3 µs | ~800x |
impl Show for FrequencySketch[K]impl Debug for FrequencySketch[K]pub struct Larder[K, V] {
table : Map[K, Slot[V]]
policy : EvictionPolicy
capacity : Int
default_ttl_ms : Int64?
weigher : (K, V) -> Int
on_remove : (K, V, RemovalCause) -> Unit
current_weight : Int
freq_buckets : Map[Int, Map[K, Unit]]
min_freq : Int
arc_t1 : Map[K, Unit]
arc_t2 : Map[K, Unit]
arc_b1 : Map[K, Unit]
arc_b2 : Map[K, Unit]
arc_p : Int
sketch : FrequencySketch[K]?
rejected_count : Int
wtlfu_window : Map[K, Unit]
wtlfu_probation : Map[K, Unit]
wtlfu_protected : Map[K, Unit]
wtlfu_window_capacity : Int
wtlfu_protected_capacity : Int
hit_count : Int
miss_count : Int
eviction_count : Int
expiration_count : Int
}fn[K : Hash + Eq, V] Larder::from_array(entries : Array[(K, V)], capacity~ : Int, default_ttl_ms? : Int64, weigher? : (K, V) -> Int, policy? : EvictionPolicy, admission_filter? : Bool, on_remove? : (K, V, RemovalCause) -> Unit, now_ms~ : Int64) -> Larder[K, V]fn[K : Hash + Eq, V] Larder::new(capacity~ : Int, default_ttl_ms? : Int64, weigher? : (K, V) -> Int, policy? : EvictionPolicy, admission_filter? : Bool, on_remove? : (K, V, RemovalCause) -> Unit) -> Larder[K, V]Install
Download zipA generic in-memory cache with LRU/LFU/ARC/WindowTinyLfu eviction, TTL expiry, and a memoizing get-or-insert helper
Dependencies