PdfBudgetedCache<K, V> class

One bounded, least-recently-used cache that every in-package cache is built on, so the eviction rules live (and are property-tested) in exactly one place instead of being re-derived - subtly differently, and with a fresh off-by-one each time - at six call sites.

A key map provides lookups and a linked list tracks recency, so touching an entry or evicting the oldest one takes constant time even when the cache is full. Two independent bounds cap growth, either or both of which a call site may leave off:

  • a weight budget (maxWeight) measured in whatever unit the weigher returns - decoded image bytes, exact-raster pixels, retained command slots. Eviction under this budget skips weight-0 entries (they free nothing yet cost a re-decode to rebuild) and never drops the single most-recently-used entry, so a lone page larger than the whole budget is still available for the render that just asked for it - unless rejectOversize is set, in which case an entry heavier than the whole budget is never stored (the record cache's policy).
  • an entry count (maxEntries), which does see weight-0 entries - the bound that stops image-free / vector-first buffers piling up one per page on a long scroll (issue #283, the weight-0 unbounded-growth bug).

Values that outlive their cache slot are handled by three hooks:

  • cloner - when a value is handed out while a master stays cached (a ui.Image shared by clone), take and putAndClone return cloner(value) so a caller disposing its copy, or eviction dropping the master, can never pull pixels out from under a picture still painting.
  • disposer - run on every value the cache drops (eviction, evict, clear, dispose, or a same-key overwrite), so retained engine resources are released deterministically.
  • onEvicted - optional diagnostics invoked only when a weight/count or coordinated process budget evicts an entry. Explicit invalidation, clearing, and same-key replacement do not count as policy evictions.

Registering with PdfCacheRegistry (via clearsUnderMemoryPressure: true) wires the cache into the one coordinated memory-pressure path.

Constructors

PdfBudgetedCache({int weigher(V value)?, int? maxWeight, int? maxEntries, void disposer(V value)?, V cloner(V value)?, void onEvicted(K key, V value)?, bool rejectOversize = false, bool clearsUnderMemoryPressure = false, String debugLabel = 'cache'})
Creates a cache bounded by maxWeight (using weigher) and/or maxEntries. At least one bound should be given or the cache grows without limit. maxEntries is floored at 1 so the cache always keeps the most-recently-used entry. When clearsUnderMemoryPressure is set the cache registers with PdfCacheRegistry for its lifetime (until dispose).

Properties

debugLabel → String
A short name used in registry accounting and diagnostics.
final
evictions → int
Entries dropped by an eviction bound (not counting evict/clear).
no setter
hashCode → int
The hash code for this object.
no setterinherited
hits → int
Lookups served from a retained value.
no setter
keys → Iterable<K>
The retained keys, least-recently used first.
no setter
length → int
Number of retained entries.
no setter
maxEntries → int?
The count cap, or null when the cache is unbounded by entry count.
no setter
maxWeight ↔ int
The weight budget (in the weigher's unit). Lowering it trims to the new budget at once; raising it lets later inserts fill the extra room. Only meaningful when a weigher was supplied.
getter/setter pair
misses → int
Lookups that missed.
no setter
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
values → Iterable<V>
The retained values, least-recently used first.
no setter
weight → int
Total weight currently retained (occupancy, not a reservation).
no setter

Methods

clear() → void
Empties the cache, disposing every retained value. Counters survive - a clear is a cache operation, not a fresh measurement. Any clones already handed out are unaffected.
containsKey(K key) → bool
Whether a value is retained for key, without touching LRU order.
dispose() → void
Empties the cache and detaches it from the memory-pressure registry. Further puts are dropped (returning the value uncached).
evict(K key) → void
Drops (and disposes) the retained value for key. A no-op on a miss.
evictWhere(bool test(K key)) → void
Drops (and disposes) every retained entry whose key satisfies test. Used for targeted, per-page invalidation - a render worker evicting just the pages an incremental revision changed instead of clearing the whole cache. Counters and every non-matching entry are untouched.
getOrAdd(K key, V ifAbsent()) → V
The value for key, computing and storing it with ifAbsent on a miss. The compute-once counterpart of take/put used by caches whose values are built lazily (text layouts, per-page derived objects). The stored value is returned directly (no clone) - the master is shared, not handed out. A hit marks the entry most-recently used and never runs ifAbsent.
lookup(K key) → V?
The stored value for key, counted as a hit or miss like take but without touching LRU order or running the cloner; null on a miss.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
peek(K key) → V?
The retained value for key without touching LRU order or the hit/miss counters, or null on a miss. Returns the master itself, never a clone - for read-only inspection (staleness checks, rebinding), not handing out.
put(K key, V value) → V
Stores value under key (the cache takes ownership, disposing any previous value for that key) and evicts down to the bounds. Returns value itself - the caller has handed it off. Use putAndClone when the caller needs its own independent copy of a shared value.
putAndClone(K key, V value) → V
Stores value as the retained master (like put) and returns an independent cloner copy for the caller to use and dispose, so a caller that both populates and paints in one step never shares the exact object the cache may later evict. Requires a cloner.
remapKeys(K keyFor(K key)) → void
Re-keys retained entries without disposing their values or changing LRU order.
resetCounters() → void
Zeroes the hit/miss/eviction counters (they survive clear, which is a cache operation, not a fresh measurement). Used by benchmarks that reuse a warm cache across measurement passes.
take(K key) → V?
The value for key - a clone when a cloner was supplied, else the stored value - moved to most-recently-used, or null on a miss.
toString() → String
A string representation of this object.
inherited
trimToWeight(int target) → void
Evicts least-recently-used weight-bearing entries until retained weight is at or under target (floored at 0). Like the budget eviction in _trim, the most-recently-used entry is protected and weight-0 entries are skipped (evicting them frees nothing). A no-op without a weigher.
weightOf(K key) → int?
The weight of the retained entry for key, or null on a miss. Does not touch LRU order - a pure peek.

Operators

operator ==(Object other) → bool
The equality operator.
inherited