|
448 | 448 | (recur (first zs) (rest zs)))))]
|
449 | 449 | (cat (concat x y) zs))))
|
450 | 450 |
|
| 451 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;; streams ;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 452 | +(defn stream |
| 453 | + "Creates a stream of the items in coll." |
| 454 | + {:tag clojure.lang.AStream} |
| 455 | + [coll] (clojure.lang.RT/stream coll)) |
| 456 | + |
| 457 | +(defn stream-iter |
| 458 | + "Returns an iter on (stream coll). Only one iter on a stream is |
| 459 | + supported at a time." |
| 460 | + {:tag clojure.lang.AStream$Iter} |
| 461 | + [coll] (.iter (stream coll))) |
| 462 | + |
| 463 | +(defn next! |
| 464 | + "Takes a stream iter and an eos value, returns (and consumes) the next element in the stream, or eos." |
| 465 | + [#^clojure.lang.AStream$Iter iter eos] (.next iter eos)) |
| 466 | + |
| 467 | +(defn push-back! |
| 468 | + "Takes a stream iter and pushes x onto front of stream, returns iter." |
| 469 | + [#^clojure.lang.AStream$Iter iter x] (.pushBack iter x)) |
| 470 | + |
| 471 | +(defn detach! |
| 472 | + "Takes a stream iter and disconnects it from the underlying stream, |
| 473 | + returning the stream. All further operations on the iter will fail." |
| 474 | + [#^clojure.lang.AStream$Iter iter] (.detach iter)) |
| 475 | + |
451 | 476 | ;;;;;;;;;;;;;;;;at this point all the support for syntax-quote exists;;;;;;;;;;;;;;;;;;;;;;
|
452 | 477 | (defmacro if-not
|
453 | 478 | "Evaluates test. If logical false, evaluates and returns then expr, otherwise else expr, if supplied, else nil."
|
|
1274 | 1299 | (. ref (touch))
|
1275 | 1300 | (. ref (get)))
|
1276 | 1301 |
|
| 1302 | +(def #^{:private true :tag clojure.lang.Closer} *io-context* nil) |
| 1303 | + |
1277 | 1304 | (defmacro sync
|
1278 | 1305 | "transaction-flags => TBD, pass nil for now
|
1279 | 1306 |
|
1280 | 1307 | Runs the exprs (in an implicit do) in a transaction that encompasses
|
1281 | 1308 | exprs and any nested calls. Starts a transaction if none is already
|
1282 | 1309 | running on this thread. Any uncaught exception will abort the
|
1283 | 1310 | transaction and flow out of sync. The exprs may be run more than
|
1284 |
| - once, but any effects on Refs will be atomic." |
| 1311 | + once, but any effects on Refs will be atomic. Transactions are not |
| 1312 | + allowed in io! blocks - will throw IllegalStateException." |
1285 | 1313 | [flags-ignored-for-now & body]
|
1286 |
| - `(. clojure.lang.LockingTransaction |
1287 |
| - (runInTransaction (fn [] ~@body)))) |
| 1314 | + `(if *io-context* |
| 1315 | + (throw (IllegalStateException. "Transaction in io!")) |
| 1316 | + (. clojure.lang.LockingTransaction |
| 1317 | + (runInTransaction (fn [] ~@body))))) |
1288 | 1318 |
|
1289 | 1319 |
|
1290 |
| -(defmacro io! |
1291 |
| - "If an io! block occurs in a transaction, throws an |
1292 |
| - IllegalStateException, else runs body in an implicit do. If the |
1293 |
| - first expression in body is a literal string, will use that as the |
1294 |
| - exception message." |
1295 |
| - [& body] |
1296 |
| - (let [message (when (string? (first body)) (first body)) |
1297 |
| - body (if message (rest body) body)] |
1298 |
| - `(if (clojure.lang.LockingTransaction/isRunning) |
1299 |
| - (throw (new IllegalStateException ~(or message "I/O in transaction"))) |
1300 |
| - (do ~@body)))) |
1301 | 1320 |
|
1302 | 1321 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; fn stuff ;;;;;;;;;;;;;;;;
|
1303 | 1322 |
|
|
1380 | 1399 | (map f (rest c1) (rest c2) (rest c3)))))
|
1381 | 1400 | ([f c1 c2 c3 & colls]
|
1382 | 1401 | (let [step (fn step [cs]
|
1383 |
| - (when (every? seq cs) |
| 1402 | + (when (every? seq cs) |
1384 | 1403 | (lazy-cons (map first cs) (step (map rest cs)))))]
|
1385 | 1404 | (map #(apply f %) (step (conj colls c3 c2 c1))))))
|
1386 | 1405 |
|
| 1406 | +(defn map-stream |
| 1407 | + "Returns a stream consisting of the result of applying f to the |
| 1408 | + set of first items of each coll, followed by applying f to the set |
| 1409 | + of second items in each coll, until any one of the colls is |
| 1410 | + exhausted. Any remaining items in other colls are ignored. Function |
| 1411 | + f should accept number-of-colls arguments." |
| 1412 | + ([f coll] |
| 1413 | + (identity (let [iter (stream-iter coll)] |
| 1414 | + (stream |
| 1415 | + #(let [x (next! iter %)] |
| 1416 | + (if (= % x) x (f x))))))) |
| 1417 | + ([f c1 c2] |
| 1418 | + (identity (let [s1 (stream-iter c1), s2 (stream-iter c2)] |
| 1419 | + (stream |
| 1420 | + #(let [x1 (next! s1 %), x2 (next! s2 %)] |
| 1421 | + (if (or (= % x1) (= % x2)) |
| 1422 | + % |
| 1423 | + (f x1 x2))))))) |
| 1424 | + ([f c1 c2 c3] |
| 1425 | + (identity (let [s1 (stream-iter c1), s2 (stream-iter c2), s3 (stream-iter c3)] |
| 1426 | + (stream |
| 1427 | + #(let [x1 (next! s1 %), x2 (next! s2 %), x3 (next! s3 %)] |
| 1428 | + (if (or (= % x1) (= % x2) (= % x3)) |
| 1429 | + % |
| 1430 | + (f x1 x2 x3))))))) |
| 1431 | + ([f c1 c2 c3 & colls] |
| 1432 | + (identity (let [iters (map stream-iter (list* c1 c2 c3 colls))] |
| 1433 | + (stream |
| 1434 | + (fn [eos] |
| 1435 | + (let [xs (seq (map #(next! % eos) iters))] |
| 1436 | + (if (some #{eos} xs) |
| 1437 | + eos |
| 1438 | + (apply f xs))))))))) |
| 1439 | + |
1387 | 1440 | (defn mapcat
|
1388 | 1441 | "Returns the result of applying concat to the result of applying map
|
1389 | 1442 | to f and colls. Thus function f should return a collection."
|
1390 | 1443 | [f & colls]
|
1391 | 1444 | (apply concat (apply map f colls)))
|
1392 | 1445 |
|
1393 | 1446 | (defn filter
|
1394 |
| - "Returns a lazy seq of the items in coll for which |
| 1447 | + "Returns a stream of the items in coll for which |
1395 | 1448 | (pred item) returns true. pred must be free of side-effects."
|
1396 | 1449 | [pred coll]
|
1397 |
| - (when (seq coll) |
1398 |
| - (if (pred (first coll)) |
1399 |
| - (lazy-cons (first coll) (filter pred (rest coll))) |
1400 |
| - (recur pred (rest coll))))) |
| 1450 | + (seq |
| 1451 | + (let [iter (stream-iter coll)] |
| 1452 | + (stream |
| 1453 | + #(let [x (next! iter %)] |
| 1454 | + (if (or (= % x) (pred x)) |
| 1455 | + x |
| 1456 | + (recur %))))))) |
| 1457 | + |
| 1458 | +;(defn filter |
| 1459 | +; "Returns a lazy seq of the items in coll for which |
| 1460 | +; (pred item) returns true. pred must be free of side-effects." |
| 1461 | +; [pred coll] |
| 1462 | +; (when (seq coll) |
| 1463 | +; (if (pred (first coll)) |
| 1464 | +; (lazy-cons (first coll) (filter pred (rest coll))) |
| 1465 | +; (recur pred (rest coll))))) |
1401 | 1466 |
|
1402 | 1467 | (defn remove
|
1403 | 1468 | "Returns a lazy seq of the items in coll for which
|
|
1633 | 1698 | (dorun n coll)
|
1634 | 1699 | coll))
|
1635 | 1700 |
|
1636 |
| -(defn await |
1637 |
| - "Blocks the current thread (indefinitely!) until all actions |
1638 |
| - dispatched thus far, from this thread or agent, to the agent(s) have |
1639 |
| - occurred." |
1640 |
| - [& agents] |
1641 |
| - (io! "await in transaction" |
1642 |
| - (when *agent* |
1643 |
| - (throw (new Exception "Can't await in agent action"))) |
1644 |
| - (let [latch (new java.util.concurrent.CountDownLatch (count agents)) |
1645 |
| - count-down (fn [agent] (. latch (countDown)) agent)] |
1646 |
| - (doseq [agent agents] |
1647 |
| - (send agent count-down)) |
1648 |
| - (. latch (await))))) |
1649 |
| - |
1650 |
| -(defn await1 [#^clojure.lang.Agent a] |
1651 |
| - (when (pos? (.getQueueCount a)) |
1652 |
| - (await a)) |
1653 |
| - a) |
1654 |
| - |
1655 |
| -(defn await-for |
1656 |
| - "Blocks the current thread until all actions dispatched thus |
1657 |
| - far (from this thread or agent) to the agents have occurred, or the |
1658 |
| - timeout (in milliseconds) has elapsed. Returns nil if returning due |
1659 |
| - to timeout, non-nil otherwise." |
1660 |
| - [timeout-ms & agents] |
1661 |
| - (io! "await-for in transaction" |
1662 |
| - (when *agent* |
1663 |
| - (throw (new Exception "Can't await in agent action"))) |
1664 |
| - (let [latch (new java.util.concurrent.CountDownLatch (count agents)) |
1665 |
| - count-down (fn [agent] (. latch (countDown)) agent)] |
1666 |
| - (doseq [agent agents] |
1667 |
| - (send agent count-down)) |
1668 |
| - (. latch (await timeout-ms (. java.util.concurrent.TimeUnit MILLISECONDS)))))) |
1669 | 1701 |
|
1670 | 1702 | (defmacro dotimes
|
1671 | 1703 | "bindings => name n
|
|
1947 | 1979 | :else (throw (IllegalArgumentException.
|
1948 | 1980 | "with-open only allows Symbols in bindings"))))
|
1949 | 1981 |
|
| 1982 | + |
| 1983 | +(defmacro io! |
| 1984 | + "If an io! block occurs in a transaction, throws an |
| 1985 | + IllegalStateException, else runs body in an implicit do. If the |
| 1986 | + first expression in body is a literal string, will use that as the |
| 1987 | + exception message. Establishes a dynamic io context for use with io-scope." |
| 1988 | + [& body] |
| 1989 | + (let [message (when (string? (first body)) (first body)) |
| 1990 | + body (if message (rest body) body)] |
| 1991 | + `(if (clojure.lang.LockingTransaction/isRunning) |
| 1992 | + (throw (new IllegalStateException ~(or message "I/O in transaction"))) |
| 1993 | + (binding [*io-context* (clojure.lang.Closer.)] |
| 1994 | + (try |
| 1995 | + ~@body |
| 1996 | + (finally |
| 1997 | + (.close *io-context*))))))) |
| 1998 | + |
| 1999 | +(def *scope* nil) |
| 2000 | + |
| 2001 | +(defn run-scope-actions [] |
| 2002 | + (let [failed (= (first *scope*) :failed) |
| 2003 | + entries (if failed (rest *scope*) *scope*)] |
| 2004 | + (doseq [e entries] |
| 2005 | + (let [cause (first e) |
| 2006 | + action (second e)] |
| 2007 | + (when (or (= cause :exits) |
| 2008 | + (and (= cause :fails) failed) |
| 2009 | + (and (= cause :succeeds) (not failed))) |
| 2010 | + (action)))))) |
| 2011 | + |
| 2012 | +(defmacro scope |
| 2013 | + "Creates a scope for use with when-scope." |
| 2014 | + [& body] |
| 2015 | + `(binding [*scope* (list)] |
| 2016 | + (try |
| 2017 | + ~@body |
| 2018 | + (catch Throwable t# |
| 2019 | + (set! *scope* (conj *scope* :failed)) |
| 2020 | + (throw t#)) |
| 2021 | + (finally |
| 2022 | + (run-scope-actions))))) |
| 2023 | + |
| 2024 | +(defmacro when-scope |
| 2025 | + "Causes a body of expressions to be executed at the termination of |
| 2026 | + the nearest dynamically enclosing scope (created with scope). If no |
| 2027 | + scope is in effect, throws IllegalStateException. Cause must be one of: |
| 2028 | +
|
| 2029 | + :exits - will run unconditionally on scope exit |
| 2030 | + :fails - will run only if scope exits due to an exception |
| 2031 | + :succeeds - will run only if scope exits normally" |
| 2032 | + |
| 2033 | + [cause & body] |
| 2034 | + `(do |
| 2035 | + (when-not *scope* |
| 2036 | + (throw (IllegalStateException. "No scope in effect"))) |
| 2037 | + (set! *scope* (conj *scope* [~cause (fn [] ~@body)])))) |
| 2038 | + |
| 2039 | +(defn await |
| 2040 | + "Blocks the current thread (indefinitely!) until all actions |
| 2041 | + dispatched thus far, from this thread or agent, to the agent(s) have |
| 2042 | + occurred." |
| 2043 | + [& agents] |
| 2044 | + (io! "await in transaction" |
| 2045 | + (when *agent* |
| 2046 | + (throw (new Exception "Can't await in agent action"))) |
| 2047 | + (let [latch (new java.util.concurrent.CountDownLatch (count agents)) |
| 2048 | + count-down (fn [agent] (. latch (countDown)) agent)] |
| 2049 | + (doseq [agent agents] |
| 2050 | + (send agent count-down)) |
| 2051 | + (. latch (await))))) |
| 2052 | + |
| 2053 | +(defn await1 [#^clojure.lang.Agent a] |
| 2054 | + (when (pos? (.getQueueCount a)) |
| 2055 | + (await a)) |
| 2056 | + a) |
| 2057 | + |
| 2058 | +(defn await-for |
| 2059 | + "Blocks the current thread until all actions dispatched thus |
| 2060 | + far (from this thread or agent) to the agents have occurred, or the |
| 2061 | + timeout (in milliseconds) has elapsed. Returns nil if returning due |
| 2062 | + to timeout, non-nil otherwise." |
| 2063 | + [timeout-ms & agents] |
| 2064 | + (io! "await-for in transaction" |
| 2065 | + (when *agent* |
| 2066 | + (throw (new Exception "Can't await in agent action"))) |
| 2067 | + (let [latch (new java.util.concurrent.CountDownLatch (count agents)) |
| 2068 | + count-down (fn [agent] (. latch (countDown)) agent)] |
| 2069 | + (doseq [agent agents] |
| 2070 | + (send agent count-down)) |
| 2071 | + (. latch (await timeout-ms (. java.util.concurrent.TimeUnit MILLISECONDS)))))) |
| 2072 | + |
1950 | 2073 | (defmacro doto
|
1951 | 2074 | "Evaluates x then calls all of the methods and functions with the
|
1952 | 2075 | value of x supplied at the from of the given arguments. The forms
|
|
2883 | 3006 | exprs and any nested calls. Starts a transaction if none is already
|
2884 | 3007 | running on this thread. Any uncaught exception will abort the
|
2885 | 3008 | transaction and flow out of dosync. The exprs may be run more than
|
2886 |
| - once, but any effects on Refs will be atomic." |
| 3009 | + once, but any effects on Refs will be atomic. Transactions are not |
| 3010 | + allowed in io! blocks - will throw IllegalStateException." |
2887 | 3011 | [& exprs]
|
2888 | 3012 | `(sync nil ~@exprs))
|
2889 | 3013 |
|
|
3772 | 3896 | (load "genclass")
|
3773 | 3897 |
|
3774 | 3898 |
|
| 3899 | + |
0 commit comments