diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/clj/clojure/boot.clj | 30 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Delay.java | 10 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LazyCons.java | 76 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LazySeq.java | 71 | ||||
-rw-r--r-- | src/jvm/clojure/lang/TransactionalHashMap.java | 9 |
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){ |