delay exception memoization, deftype cross-protocol method merge, more map-like dispatch
Further clojure.core.cache fixes (198 -> 257 of its assertions): - delay: a throwing body re-ran on every force and never became realized?. Run it once like Clojure's Delay — cache the exception, mark realized, re-throw the same on each deref. Fixes value-fn memoization / cache-stampede protection. - deftype/defrecord: a method name appearing in two protocols with different arities (data.priority-map's seq is in IPersistentMap [this] AND Sorted [this asc]) registered per-protocol and shadowed; merge clauses by name across all protocols into one multi-arity fn. - empty?/peek/pop (IPersistentStack) dispatch through a deftype's methods; (= a- deftype other) uses its equiv method (so caches compare to their backing map); seq handles a host iterator (iterator-seq over .iterator). - pop of an empty PersistentQueue returns it, like the JVM (was an error). JVM-certified corpus rows. make test + shakesmoke green.
This commit is contained in:
parent
c445aaeaa2
commit
5d0989a860
7 changed files with 614 additions and 581 deletions
|
|
@ -228,15 +228,21 @@
|
|||
;; (delay body) -> (make-delay (fn [] body)) (overlay macro); force/deref run the
|
||||
;; thunk once under a lock and cache the value (JVM delays are thread-safe). force
|
||||
;; (overlay) is (if (delay? x) (deref x) x), so it works once delay?/deref do.
|
||||
(define-record-type jolt-delay (fields thunk (mutable realized?) (mutable value) mu)
|
||||
(define-record-type jolt-delay (fields thunk (mutable realized?) (mutable value) (mutable exn) mu)
|
||||
(nongenerative jolt-delay-v1))
|
||||
(define (jolt-make-delay thunk) (make-jolt-delay thunk #f jolt-nil (make-mutex)))
|
||||
(define (jolt-make-delay thunk) (make-jolt-delay thunk #f jolt-nil #f (make-mutex)))
|
||||
;; run the thunk once, like Clojure's Delay: if it throws, cache the exception
|
||||
;; (the delay IS realized) and re-throw it on every deref — do NOT re-run the
|
||||
;; body (so value-fns memoize and there is no cache-stampede / retried side
|
||||
;; effect). Store the exception inside the lock, re-raise outside it so the mutex
|
||||
;; is always released.
|
||||
(define (jolt-delay-force d)
|
||||
(with-mutex (jolt-delay-mu d)
|
||||
(unless (jolt-delay-realized? d)
|
||||
(jolt-delay-value-set! d (jolt-invoke (jolt-delay-thunk d)))
|
||||
(jolt-delay-realized?-set! d #t)))
|
||||
(jolt-delay-value d))
|
||||
(guard (e (#t (jolt-delay-exn-set! d e) (jolt-delay-realized?-set! d #t)))
|
||||
(jolt-delay-value-set! d (jolt-invoke (jolt-delay-thunk d)))
|
||||
(jolt-delay-realized?-set! d #t))))
|
||||
(if (jolt-delay-exn d) (raise (jolt-delay-exn d)) (jolt-delay-value d)))
|
||||
|
||||
;; --- deref extension --------------------------------------------------------
|
||||
;; Chain the fully-built jolt-deref (atoms/vars/volatiles/reduced) with futures,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue