Skip to content

Instantly share code, notes, and snippets.

@cemerick
Created December 19, 2010 15:02
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cemerick/747395 to your computer and use it in GitHub Desktop.
Save cemerick/747395 to your computer and use it in GitHub Desktop.
(ns com.snowtide.clojure.memoize)
(defn- mutable-memoize
[f #^java.util.Map map]
(fn [& args]
(if-let [e (find map args)]
(val e)
(let [ret (apply f args)]
(.put map args ret)
ret))))
(defn soft-memoize
[f]
(let [m (java.util.concurrent.ConcurrentHashMap.)
rq (java.lang.ref.ReferenceQueue.)
memoized (mutable-memoize
#(java.lang.ref.SoftReference. (apply f %&) rq)
m)]
(fn clear-fn [& args]
; clearCache conveniently exists to poll the queue and scrub a CHM
; used in Clojure's Keyword and DynamicClassLoader, so it's not going anywhere
(clojure.lang.Util/clearCache rq m)
(let [^java.lang.ref.SoftReference ref (apply memoized args)
val (.get ref)]
(if (.isEnqueued ref)
; reference enqueued since our clearCache call above, retry
(apply clear-fn args)
val)))))
(defn weak-memoize
"Same as memoize, but uses a WeakHashMap for storing argument keys and result values.
**Be aware of what this entails for persistence of values: lose your keys, and
the associated value may get recalculated, depending upon the behaviour of the GC**"
[f]
(mutable-memoize f (java.util.WeakHashMap.)))
(defn lru-map
"Returns a least-recently-used cache implemented on top of LinkedHashMap
that uses eviction-fn to control cache eviction.
eviction-fn is a fn of two arguments (the LinkedHashMap cache and the
LRU map entry) that is called by the LHM when a new entry is added to
the cache. Returning a truthy value will result in the LRU entry being
evicted from the cache. (See LinkedHashMap.removeEldestEntry for more details.)
e.g. An LRU cache with a max size of 100 can be obtained via:
(lru-map (fn [m e] (> (count m) 100)))"
[eviction-fn]
(proxy [java.util.LinkedHashMap] [16 0.75 true]
(removeEldestEntry [entry]
(boolean (eviction-fn this entry)))))
(defn lru-memoize
"Same as memoize, but uses a LinkedHashMap-based LRU cache.
See `lru-map` for info about eviction-fn."
[f eviction-fn]
(mutable-memoize f (lru-map eviction-fn)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment