ilusm.dev

lru

LRU cache with optional TTL - create a fixed-capacity cache, get values (auto-evicting expired entries on access), set with an optional TTL in milliseconds, check presence, delete, clear, query size, list keys in LRU order, peek the most recently used entry, register an eviction callback, and sweep all expired entries.

Load with: use lru

What this module does

lru implements a least-recently-used cache. The underlying data structure is an object (data) of key → {val, exp} records plus an order list that tracks access recency. When the cache reaches its capacity, the oldest (least-recently-used) entry is evicted.

Entries can carry a TTL (time-to-live) in milliseconds. Expired entries are lazily removed on lrugt access. You can also proactively sweep all expired entries with lruex.

Quick example

use lru

# Create a cache with capacity 100
c = lrunw(100)

# Register eviction callback
c = lruev(c, \(key, val) prn("evicted: " + key))

# Set values (with optional TTL in ms)
c = lrust(c, "user:1", {name: "Alice"}, 60000)  # TTL 1 minute
c = lrust(c, "user:2", {name: "Bob"}, nil)       # no TTL

# Get (returns nil if missing or expired)
prn(lrugt(c, "user:1"))

# Check / delete
prn(lruhs(c, "user:1"))  # tru
c = lrudl(c, "user:1")

# Sweep expired entries
c = lruex(c)

# Stats
prn(lrusz(c))   # number of entries
prn(lruky(c))   # keys in LRU order

Functions

Lifecycle

lrunw(cap) / lru.new(cap)

Creates a new LRU cache with integer capacity cap.

lruev(cache, fn) / lru.ev(cache, fn)

Registers an eviction callback fn(key, val) called whenever an entry is evicted due to capacity overflow.

lruclr(cache) / lru.clr(cache)

Removes all entries from the cache.

Read and write

lrugt(cache, key) / lru.get(cache, key)

Gets the value for key. Returns nil if absent. If the entry has a TTL and it has expired, the entry is deleted and nil is returned. On a hit, moves the entry to most-recently-used position.

lrust(cache, key, val, ttl) / lru.set(cache, key, val, ttl)

Sets key to val with optional TTL in milliseconds (nil = no expiry). If the key exists, updates in place. If at capacity, evicts the LRU entry first.

lrupk(cache)

Returns the most-recently-used value without modifying the access order.

Inspection and cleanup

lruhs(cache, key) / lru.has(cache, key)

Returns tru if key exists and is not expired.

lrudl(cache, key) / lru.del(cache, key)

Removes an entry by key.

lrusz(cache) / lru.sz(cache)

Returns the number of entries in the cache.

lruky(cache) / lru.kys(cache)

Returns a copy of the key list in LRU order (oldest first).

lruex(cache) / lru.exp(cache)

Sweeps all entries and deletes any that have expired. Call periodically to avoid stale data accumulating.

Notes

  • TTL expiry is lazy (checked on access) or explicit (via lruex). There is no background timer.
  • Requires tim and trl.