summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2008-12-11 14:28:00 +0000
committerRich Hickey <richhickey@gmail.com>2008-12-11 14:28:00 +0000
commitc5e8c6f06292fab26d29cb951d8400394e0f8258 (patch)
treebca2cef66acef4a4ef2b36433bcb884bfcddea48 /src
parentd49f0d32473d8387696049b8b10b8403d86e05e4 (diff)
added if-not, memoize, and io!
io! blocks will throw exceptions when run in transactions made await and await-for use io!
Diffstat (limited to 'src')
-rw-r--r--src/clj/clojure/core.clj50
-rw-r--r--src/jvm/clojure/lang/LockingTransaction.java4
2 files changed, 46 insertions, 8 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index e1e8d707..8d46be01 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -444,6 +444,12 @@
(cat (concat x y) zs))))
;;;;;;;;;;;;;;;;at this point all the support for syntax-quote exists;;;;;;;;;;;;;;;;;;;;;;
+(defmacro if-not
+ "Evaluates test. If logical false, evaluates and returns then expr, otherwise else expr, if supplied, else nil."
+ ([test then] `(if-not ~test ~then nil))
+ ([test then else]
+ `(if (not ~test) ~then ~else)))
+
(defn =
"Equality. Returns true if x equals y, false if not. Same as
Java x.equals(y) except it also works for nil, and compares
@@ -1187,6 +1193,17 @@
(runInTransaction (fn [] ~@body))))
+(defmacro io!
+ "If an io! block occurs in a transaction, throws an
+ IllegalStateException, else runs body in an implicit do. If the
+ first expression in body is a literal string, will use that as the
+ exception message."
+ [& body]
+ (let [message (when (string? (first body)) (first body))
+ body (if message (rest body) body)]
+ `(if (clojure.lang.LockingTransaction/isRunning)
+ (throw (new IllegalStateException ~(or message "I/O in transaction")))
+ (do ~@body))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; fn stuff ;;;;;;;;;;;;;;;;
@@ -1522,13 +1539,14 @@
dispatched thus far, from this thread or agent, to the agent(s) have
occurred."
[& agents]
+ (io! "await in transaction"
(when *agent*
(throw (new Exception "Can't await in agent action")))
(let [latch (new java.util.concurrent.CountDownLatch (count agents))
count-down (fn [agent] (. latch (countDown)) agent)]
(doseq [agent agents]
(send agent count-down))
- (. latch (await))))
+ (. latch (await)))))
(defn await1 [#^clojure.lang.Agent a]
(when (pos? (.getQueueCount a))
@@ -1541,13 +1559,14 @@
timeout (in milliseconds) has elapsed. Returns nil if returning due
to timeout, non-nil otherwise."
[timeout-ms & agents]
- (when *agent*
- (throw (new Exception "Can't await in agent action")))
- (let [latch (new java.util.concurrent.CountDownLatch (count agents))
- count-down (fn [agent] (. latch (countDown)) agent)]
- (doseq [agent agents]
- (send agent count-down))
- (. latch (await timeout-ms (. java.util.concurrent.TimeUnit MILLISECONDS)))))
+ (io! "await-for in transaction"
+ (when *agent*
+ (throw (new Exception "Can't await in agent action")))
+ (let [latch (new java.util.concurrent.CountDownLatch (count agents))
+ count-down (fn [agent] (. latch (countDown)) agent)]
+ (doseq [agent agents]
+ (send agent count-down))
+ (. latch (await timeout-ms (. java.util.concurrent.TimeUnit MILLISECONDS))))))
(defmacro dotimes
"bindings => name n
@@ -3572,6 +3591,21 @@
~@body
(recur))))
+(declare atom swap!)
+
+(defn memoize
+ "Returns a memoized version of a referentially transparent function. The
+ memoized version of the function keeps a cache of the mapping from arguments
+ to results and, when calls with the same arguments are repeated often, has
+ higher performance at the expense of higher memory use."
+ [f]
+ (let [mem (atom {})]
+ (fn [& args]
+ (if-let [e (find @mem args)]
+ (val e)
+ (let [ret (apply f args)]
+ (swap! mem assoc args ret)
+ ret)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; helper files ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/src/jvm/clojure/lang/LockingTransaction.java b/src/jvm/clojure/lang/LockingTransaction.java
index b71cf784..9ef38f1e 100644
--- a/src/jvm/clojure/lang/LockingTransaction.java
+++ b/src/jvm/clojure/lang/LockingTransaction.java
@@ -181,6 +181,10 @@ static LockingTransaction getEx(){
return t;
}
+static public boolean isRunning(){
+ return getRunning() != null;
+}
+
static LockingTransaction getRunning(){
LockingTransaction t = transaction.get();
if(t == null || t.info == null)