summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/clj/clojure/boot.clj30
-rw-r--r--src/jvm/clojure/lang/Delay.java10
-rw-r--r--src/jvm/clojure/lang/LazyCons.java76
-rw-r--r--src/jvm/clojure/lang/LazySeq.java71
-rw-r--r--src/jvm/clojure/lang/TransactionalHashMap.java9
5 files changed, 138 insertions, 58 deletions
diff --git a/src/clj/clojure/boot.clj b/src/clj/clojure/boot.clj
index 2ef57acb..eb7bc765 100644
--- a/src/clj/clojure/boot.clj
+++ b/src/clj/clojure/boot.clj
@@ -369,12 +369,20 @@
(spread (cons item more)))
(defmacro delay
- "Takes a body of expressions and yields a function than will invoke
- the body only the first time it is called, and will cache the result
- and return it on all calls"
+ "Takes a body of expressions and yields a Delay object than will
+ invoke the body only the first time it is forced (with force), and
+ will cache the result and return it on all subsequent force calls"
[& body]
(list 'new 'clojure.lang.Delay (list* `fn [] body)))
+(defn delay?
+ "returns true if x is a Delay created with delay"
+ [x] (instance? clojure.lang.Delay x))
+
+(defn force
+ "If x is a Delay, returns the (possibly cached) value of its expression, else returns x"
+ [x] (. clojure.lang.Delay (force x)))
+
(defn fnseq
"Returns a seq object whose first is first and whose rest is the
value produced by calling restfn with no arguments. restfn will be
@@ -392,7 +400,17 @@
same node of the seq evaluates first/rest-expr once - the values they yield are
cached."
[first-expr & rest-expr]
- (list 'new 'clojure.lang.LazySeq (list `fn [] first-expr) (list* `fn [] rest-expr)))
+ (list 'new 'clojure.lang.LazyCons (list `fn [] first-expr) (list* `fn [] rest-expr)))
+
+(defmacro lazy-seq
+ "Expands to code which produces a seq object whose first is the
+ value of first-expr and whose rest is the value of rest-expr,
+ neither of which is evaluated until first/rest is called. Each expr
+ will be evaluated every step in the sequence, e.g. calling
+ first/rest repeatedly on the same node of the seq evaluates
+ first/rest-expr repeatedly - the values they yield are not cached."
+ [first-expr rest-expr]
+ (list 'new 'clojure.lang.LazySeq (list `fn (list [] first-expr) (list [(gensym)] rest-expr))))
(defn concat
"Returns a lazy seq representing the concatenation of the elements in x + xs."
@@ -933,7 +951,7 @@
is :default."
([name dispatch-fn] `(defmulti ~name ~dispatch-fn :default))
([name dispatch-fn default-val]
- `(def ~name (new clojure.lang.MultiFn ~dispatch-fn ~default-val))))
+ `(def ~(with-meta name {:tag 'clojure.lang.MultiFn}) (new clojure.lang.MultiFn ~dispatch-fn ~default-val))))
(defmacro defmethod
"Creates and installs a new method of multimethod associated with dispatch-value. "
@@ -2876,7 +2894,7 @@ not-every? (comp not every?))
h))))
-(defn none=
+(defn distinct?
"Returns true if no two of the arguments are equal"
{:tag Boolean}
([x] true)
diff --git a/src/jvm/clojure/lang/Delay.java b/src/jvm/clojure/lang/Delay.java
index 18a8d1c1..cee45d87 100644
--- a/src/jvm/clojure/lang/Delay.java
+++ b/src/jvm/clojure/lang/Delay.java
@@ -12,7 +12,7 @@
package clojure.lang;
-public class Delay extends AFn{
+public class Delay{
Object val;
IFn fn;
@@ -21,11 +21,13 @@ public Delay(IFn fn){
this.val = null;
}
-public Object invoke() throws Exception{
- return get();
+static public Object force(Object x) throws Exception{
+ return (x instanceof Delay) ?
+ ((Delay) x).get()
+ : x;
}
-synchronized public Object get() throws Exception{
+synchronized Object get() throws Exception{
if(fn != null)
{
val = fn.invoke();
diff --git a/src/jvm/clojure/lang/LazyCons.java b/src/jvm/clojure/lang/LazyCons.java
new file mode 100644
index 00000000..dc9e7344
--- /dev/null
+++ b/src/jvm/clojure/lang/LazyCons.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) Rich Hickey. All rights reserved.
+ * The use and distribution terms for this software are covered by the
+ * Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
+ * which can be found in the file CPL.TXT at the root of this distribution.
+ * By using this software in any fashion, you are agreeing to be bound by
+ * the terms of this license.
+ * You must not remove this notice, or any other, from this software.
+ **/
+
+/* rich Aug 9, 2008 */
+
+package clojure.lang;
+
+public class LazyCons extends ASeq{
+IFn _firstFn;
+Object _first;
+IFn _restFn;
+ISeq _rest;
+
+public LazyCons(IFn firstFn, IFn restFn){
+ this._firstFn = firstFn;
+ this._restFn = restFn;
+ this._first = null;
+ this._rest = null;
+}
+
+LazyCons(IPersistentMap meta, Object first, ISeq rest){
+ super(meta);
+ this._first = first;
+ this._rest = rest;
+}
+
+synchronized public Object first(){
+ if(_firstFn != null)
+ {
+ try
+ {
+ _first = _firstFn.invoke();
+ }
+ catch(Exception ex)
+ {
+ throw new RuntimeException(ex);
+ }
+ _firstFn = null;
+ }
+ return _first;
+}
+
+synchronized public ISeq rest(){
+ //force sequential evaluation
+ first();
+ if(_restFn != null)
+ {
+ try
+ {
+ _rest = RT.seq(_restFn.invoke());
+ }
+ catch(Exception ex)
+ {
+ throw new RuntimeException(ex);
+ }
+ _restFn = null;
+ }
+ return _rest;
+}
+
+synchronized public LazyCons withMeta(IPersistentMap meta){
+ if(meta == meta())
+ return this;
+ //force before copying
+ rest();
+ return new LazyCons(meta, _first, _rest);
+}
+
+}
diff --git a/src/jvm/clojure/lang/LazySeq.java b/src/jvm/clojure/lang/LazySeq.java
index 7fad8017..8e335c74 100644
--- a/src/jvm/clojure/lang/LazySeq.java
+++ b/src/jvm/clojure/lang/LazySeq.java
@@ -13,65 +13,44 @@
package clojure.lang;
public class LazySeq extends ASeq{
+final IFn f;
-IFn _firstFn;
-Object _first;
-IFn _restFn;
-ISeq _rest;
-
-public LazySeq(IFn firstFn, IFn restFn){
- this._firstFn = firstFn;
- this._restFn = restFn;
- this._first = null;
- this._rest = null;
-}
-
-LazySeq(IPersistentMap meta, Object first, ISeq rest){
- super(meta);
- this._first = first;
- this._rest = rest;
+public LazySeq(IFn f){
+ this.f = f;
}
-synchronized public Object first(){
- if(_firstFn != null)
+public Object first(){
+ try
+ {
+ return f.invoke();
+ }
+ catch(Exception e)
{
- try
- {
- _first = _firstFn.invoke();
- }
- catch(Exception ex)
- {
- throw new RuntimeException(ex);
- }
- _firstFn = null;
+ throw new RuntimeException(e);
}
- return _first;
}
-synchronized public ISeq rest(){
- //force sequential evaluation
- first();
- if(_restFn != null)
+public ISeq rest(){
+ try
{
- try
- {
- _rest = RT.seq(_restFn.invoke());
- }
- catch(Exception ex)
- {
- throw new RuntimeException(ex);
- }
- _restFn = null;
+ return (ISeq) f.invoke(null);
}
- return _rest;
+ catch(Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+}
+
+LazySeq(IPersistentMap meta, IFn f){
+ super(meta);
+ this.f = f;
}
-synchronized public LazySeq withMeta(IPersistentMap meta){
+public Obj withMeta(IPersistentMap meta){
if(meta == meta())
return this;
- //force before copying
- rest();
- return new LazySeq(meta, _first, _rest);
+ return new LazySeq(meta, f);
}
+
}
diff --git a/src/jvm/clojure/lang/TransactionalHashMap.java b/src/jvm/clojure/lang/TransactionalHashMap.java
index 1bc3fc06..656f4ee8 100644
--- a/src/jvm/clojure/lang/TransactionalHashMap.java
+++ b/src/jvm/clojure/lang/TransactionalHashMap.java
@@ -22,8 +22,13 @@ IPersistentMap mapAt(int bin){
return (IPersistentMap) bins[bin].get();
}
-int binFor(Object k){
- return k.hashCode() % bins.length;
+final int binFor(Object k){
+ //spread hashes, a la Cliff Click
+ int h = k.hashCode();
+ h ^= (h >>> 20) ^ (h >>> 12);
+ h ^= (h >>> 7) ^ (h >>> 4);
+ return h % bins.length;
+// return k.hashCode() % bins.length;
}
Entry entryAt(Object k){