diff options
-rw-r--r-- | src/clj/clojure/core.clj | 211 | ||||
-rw-r--r-- | src/jvm/clojure/lang/ArrayChunk.java | 15 | ||||
-rw-r--r-- | src/jvm/clojure/lang/ChunkBuffer.java | 12 | ||||
-rw-r--r-- | src/jvm/clojure/lang/ChunkedCons.java | 29 | ||||
-rw-r--r-- | src/jvm/clojure/lang/IChunk.java | 20 | ||||
-rw-r--r-- | src/jvm/clojure/lang/IChunkedSeq.java | 2 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LazilyPersistentVector.java | 2 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentVector.java | 2 |
8 files changed, 189 insertions, 104 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index f44fce09..8ed4aaf1 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -523,6 +523,78 @@ (if or# or# (or ~@next))))) ;;;;;;;;;;;;;;;;;;; sequence fns ;;;;;;;;;;;;;;;;;;;;;;; +(defn zero? + "Returns true if num is zero, else false" + {:tag Boolean + :inline (fn [x] `(. clojure.lang.Numbers (isZero ~x)))} + [x] (. clojure.lang.Numbers (isZero x))) + +(defn count + "Returns the number of items in the collection. (count nil) returns + 0. Also works on strings, arrays, and Java Collections and Maps" + [coll] (clojure.lang.RT/count coll)) + +(defn int + "Coerce to int" + {:tag Integer + :inline (fn [x] `(. clojure.lang.RT (intCast ~x)))} + [x] (. clojure.lang.RT (intCast x))) + +(defn nth + "Returns the value at the index. get returns nil if index out of + bounds, nth throws an exception unless not-found is supplied. nth + also works for strings, Java arrays, regex Matchers and Lists, and, + in O(n) time, for sequences." + {:inline (fn [c i] `(. clojure.lang.RT (nth ~c ~i))) + :inline-arities #{2}} + ([coll index] (. clojure.lang.RT (nth coll index))) + ([coll index not-found] (. clojure.lang.RT (nth coll index not-found)))) + +(defn < + "Returns non-nil if nums are in monotonically increasing order, + otherwise false." + {:inline (fn [x y] `(. clojure.lang.Numbers (lt ~x ~y))) + :inline-arities #{2}} + ([x] true) + ([x y] (. clojure.lang.Numbers (lt x y))) + ([x y & more] + (if (< x y) + (if (next more) + (recur y (first more) (next more)) + (< y (first more))) + false))) + +(defn inc + "Returns a number one greater than num." + {:inline (fn [x] `(. clojure.lang.Numbers (inc ~x)))} + [x] (. clojure.lang.Numbers (inc x))) + +(defn #^clojure.lang.ChunkBuffer chunk-buffer [capacity] + (clojure.lang.ChunkBuffer. capacity)) + +(defn chunk-append [#^clojure.lang.ChunkBuffer b x] + (.add b x)) + +(defn chunk [#^clojure.lang.ChunkBuffer b] + (.chunk b)) + +(defn #^clojure.lang.IChunk chunk-first [#^clojure.lang.IChunkedSeq s] + (.chunkedFirst s)) + +(defn #^clojure.lang.ISeq chunk-rest [#^clojure.lang.IChunkedSeq s] + (.chunkedMore s)) + +(defn #^clojure.lang.ISeq chunk-next [#^clojure.lang.IChunkedSeq s] + (.chunkedNext s)) + +(defn chunk-cons [chunk rest] + (if (zero? (count chunk)) + rest + (clojure.lang.ChunkedCons. chunk rest))) + +(defn chunked-seq? [s] + (instance? clojure.lang.IChunkedSeq s)) + (defn reduce "f should be a function of 2 arguments. If val is not supplied, returns the result of applying f to the first 2 items in coll, then @@ -536,19 +608,17 @@ ([f coll] (let [s (seq coll)] (if s - (if (instance? clojure.lang.IReduce s) - (. #^clojure.lang.IReduce s (reduce f)) - (reduce f (first s) (next s))) + (reduce f (first s) (next s)) (f)))) ([f val coll] (let [s (seq coll)] - (if (instance? clojure.lang.IReduce s) - (. #^clojure.lang.IReduce s (reduce f val)) - ((fn [f val s] - (if s - (recur f (f val (first s)) (next s)) - val)) - f val s))))) + (if s + (if (chunked-seq? s) + (recur f + (.reduce (chunk-first s) f val) + (chunk-next s)) + (recur f (f val (first s)) (next s))) + val)))) (defn reverse "Returns a seq of the items in coll in reverse order. Not lazy." @@ -596,20 +666,6 @@ ([x y & more] (reduce - (- x y) more))) -(defn < - "Returns non-nil if nums are in monotonically increasing order, - otherwise false." - {:inline (fn [x y] `(. clojure.lang.Numbers (lt ~x ~y))) - :inline-arities #{2}} - ([x] true) - ([x y] (. clojure.lang.Numbers (lt x y))) - ([x y & more] - (if (< x y) - (if (next more) - (recur y (first more) (next more)) - (< y (first more))) - false))) - (defn <= "Returns non-nil if nums are in monotonically non-decreasing order, otherwise false." @@ -679,11 +735,6 @@ ([x y & more] (reduce min (min x y) more))) -(defn inc - "Returns a number one greater than num." - {:inline (fn [x] `(. clojure.lang.Numbers (inc ~x)))} - [x] (. clojure.lang.Numbers (inc x))) - (defn dec "Returns a number one less than num." {:inline (fn [x] `(. clojure.lang.Numbers (dec ~x)))} @@ -749,12 +800,6 @@ :inline (fn [x] `(. clojure.lang.Numbers (isNeg ~x)))} [x] (. clojure.lang.Numbers (isNeg x))) -(defn zero? - "Returns true if num is zero, else false" - {:tag Boolean - :inline (fn [x] `(. clojure.lang.Numbers (isZero ~x)))} - [x] (. clojure.lang.Numbers (isZero x))) - (defn quot "quot[ient] of dividing numerator by denominator." [num div] @@ -856,10 +901,7 @@ -(defn count - "Returns the number of items in the collection. (count nil) returns - 0. Also works on strings, arrays, and Java Collections and Maps" - [coll] (. clojure.lang.RT (count coll))) + ;;list stuff (defn peek @@ -874,16 +916,6 @@ as next/butlast." [coll] (. clojure.lang.RT (pop coll))) -(defn nth - "Returns the value at the index. get returns nil if index out of - bounds, nth throws an exception unless not-found is supplied. nth - also works for strings, Java arrays, regex Matchers and Lists, and, - in O(n) time, for sequences." - {:inline (fn [c i] `(. clojure.lang.RT (nth ~c ~i))) - :inline-arities #{2}} - ([coll index] (. clojure.lang.RT (nth coll index))) - ([coll index not-found] (. clojure.lang.RT (nth coll index not-found)))) - ;;map stuff (defn contains? @@ -1538,6 +1570,21 @@ :arglists '([pred coll])} not-any? (comp not some)) +;will be redefed later with arg checks +(defmacro dotimes + "bindings => name n + + Repeatedly executes body (presumably for side-effects) with name + bound to integers from 0 through n-1." + [bindings & body] + (let [i (first bindings) + n (second bindings)] + `(let [n# (int ~n)] + (loop [~i (int 0)] + (when (< ~i n#) + ~@body + (recur (inc ~i))))))) + (defn map "Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set @@ -1547,7 +1594,14 @@ ([f coll] (lazy-seq (when-let [s (seq coll)] - (cons (f (first s)) (map f (rest s)))))) + (if (chunked-seq? s) + (let [c (chunk-first s) + size (int (count c)) + b (chunk-buffer size)] + (dotimes [i size] + (chunk-append b (f (.nth c i)))) + (chunk-cons (chunk b) (map f (chunk-rest s)))) + (cons (f (first s)) (map f (rest s))))))) ([f c1 c2] (lazy-seq (let [s1 (seq c1) s2 (seq c2)] @@ -1575,15 +1629,21 @@ (apply concat (apply map f colls))) (defn filter - "Returns a lazy sequence of the items in coll for which - (pred item) returns true. pred must be free of side-effects." - [pred coll] - (let [step (fn [p c] - (when-let [s (seq c)] - (if (p (first s)) - (cons (first s) (filter p (rest s))) - (recur p (rest s)))))] - (lazy-seq (step pred coll)))) + ([pred coll] + (lazy-seq + (when-let [s (seq coll)] + (if (chunked-seq? s) + (let [c (chunk-first s) + size (count c) + b (chunk-buffer size)] + (dotimes [i size] + (when (pred (.nth c i)) + (chunk-append b (.nth c i)))) + (chunk-cons (chunk b) (filter pred (chunk-rest s)))) + (let [f (first s) r (rest s)] + (if (pred f) + (cons f (filter pred r)) + (filter pred r)))))))) (defn remove @@ -1665,19 +1725,24 @@ "Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects" [f x] (cons x (lazy-seq (iterate f (f x))))) -(defn range +(defn range "Returns a lazy seq of nums from start (inclusive) to end (exclusive), by step, where start defaults to 0 and step to 1." - ([end] (if (and (> end 0) (<= end (. Integer MAX_VALUE))) - (new clojure.lang.Range 0 end) - (take end (iterate inc 0)))) - ([start end] (if (and (< start end) - (>= start (. Integer MIN_VALUE)) - (<= end (. Integer MAX_VALUE))) - (new clojure.lang.Range start end) - (take (- end start) (iterate inc start)))) + ([end] (range 0 end 1)) + ([start end] (range start end 1)) ([start end step] - (take-while (partial (if (pos? step) > <) end) (iterate (partial + step) start)))) + (lazy-seq + (let [b (chunk-buffer 32) + comp (if (pos? step) < >)] + (loop [i start] + (if (and (< (count b) 32) + (comp i end)) + (do + (chunk-append b i) + (recur (+ i step))) + (chunk-cons (chunk b) + (when (comp i end) + (range i end step))))))))) (defn merge "Returns a map that consists of the rest of the maps conj-ed onto @@ -1952,12 +2017,6 @@ :inline (fn [x] `(. clojure.lang.Numbers (num ~x)))} [x] (. clojure.lang.Numbers (num x))) -(defn int - "Coerce to int" - {:tag Integer - :inline (fn [x] `(. clojure.lang.RT (intCast ~x)))} - [x] (. clojure.lang.RT (intCast x))) - (defn long "Coerce to long" {:tag Long @@ -4237,7 +4296,7 @@ Returns a promise object that can be read with deref/@, and set, once only, with deliver. Calls to deref/@ prior to delivery will block. All subsequent derefs will return the same delivered value - without blocking." + without blocking." [] (let [d (java.util.concurrent.CountDownLatch. 1) v (atom nil)] diff --git a/src/jvm/clojure/lang/ArrayChunk.java b/src/jvm/clojure/lang/ArrayChunk.java index 08f863cf..d5a5a77b 100644 --- a/src/jvm/clojure/lang/ArrayChunk.java +++ b/src/jvm/clojure/lang/ArrayChunk.java @@ -12,7 +12,7 @@ package clojure.lang; -public final class ArrayChunk implements Indexed{ +public final class ArrayChunk implements IChunk{ final Object[] array; final int off; @@ -39,4 +39,17 @@ public Object nth(int i){ public int count(){ return end - off; } + +public IChunk dropFirst(){ + if(off==end) + throw new IllegalStateException("dropFirst of empty chunk"); + return new ArrayChunk(array, off + 1, end); +} + +public Object reduce(IFn f, Object start) throws Exception{ + Object ret = f.invoke(start, array[off]); + for(int x = off + 1; x < end; x++) + ret = f.invoke(ret, array[x]); + return ret; +} } diff --git a/src/jvm/clojure/lang/ChunkBuffer.java b/src/jvm/clojure/lang/ChunkBuffer.java index aee01e0e..fd484c90 100644 --- a/src/jvm/clojure/lang/ChunkBuffer.java +++ b/src/jvm/clojure/lang/ChunkBuffer.java @@ -14,24 +14,24 @@ package clojure.lang; final public class ChunkBuffer implements Counted{ Object[] buffer; - int offset; + int end; public ChunkBuffer(int capacity){ buffer = new Object[capacity]; - offset = 0; + end = 0; } public void add(Object o){ - buffer[offset++] = o; + buffer[end++] = o; } -public Indexed chunk(){ - ArrayChunk ret = new ArrayChunk(buffer, 0, offset); +public IChunk chunk(){ + ArrayChunk ret = new ArrayChunk(buffer, 0, end); buffer = null; return ret; } public int count(){ - return offset; + return end; } } diff --git a/src/jvm/clojure/lang/ChunkedCons.java b/src/jvm/clojure/lang/ChunkedCons.java index 37f5f47c..b52bc2b6 100644 --- a/src/jvm/clojure/lang/ChunkedCons.java +++ b/src/jvm/clojure/lang/ChunkedCons.java @@ -14,51 +14,44 @@ package clojure.lang; final public class ChunkedCons extends ASeq implements IChunkedSeq{ -final Indexed chunk; +final IChunk chunk; final ISeq _more; -final int offset; -ChunkedCons(IPersistentMap meta, Indexed chunk, int offset, ISeq more){ +ChunkedCons(IPersistentMap meta, IChunk chunk, ISeq more){ super(meta); this.chunk = chunk; - this.offset = offset; this._more = more; } -public ChunkedCons(Indexed chunk, ISeq more){ - this(chunk, 0, more); -} -public ChunkedCons(Indexed chunk, int offset, ISeq more){ - this.chunk = chunk; - this.offset = offset; - this._more = more; +public ChunkedCons(IChunk chunk, ISeq more){ + this(null,chunk, more); } public Obj withMeta(IPersistentMap meta){ if(meta != _meta) - return new ChunkedCons(meta, chunk, offset, _more); + return new ChunkedCons(meta, chunk, _more); return this; } public Object first(){ - return chunk.nth(offset); + return chunk.nth(0); } public ISeq next(){ - if(offset + 1 < chunk.count()) - return new ChunkedCons(chunk, offset + 1, _more); + if(chunk.count() > 1) + return new ChunkedCons(chunk.dropFirst(), _more); return chunkedNext(); } public ISeq more(){ - if(offset + 1 < chunk.count()) - return new ChunkedCons(chunk, offset + 1, _more); + if(chunk.count() > 1) + return new ChunkedCons(chunk.dropFirst(), _more); if(_more == null) return PersistentList.EMPTY; return _more; } -public Indexed chunkedFirst(){ +public IChunk chunkedFirst(){ return chunk; } diff --git a/src/jvm/clojure/lang/IChunk.java b/src/jvm/clojure/lang/IChunk.java new file mode 100644 index 00000000..fd667161 --- /dev/null +++ b/src/jvm/clojure/lang/IChunk.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Rich Hickey. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * which can be found in the file epl-v10.html 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 Jun 18, 2009 */ + +package clojure.lang; + +public interface IChunk extends Indexed{ + +IChunk dropFirst(); + +Object reduce(IFn f, Object start) throws Exception; +} diff --git a/src/jvm/clojure/lang/IChunkedSeq.java b/src/jvm/clojure/lang/IChunkedSeq.java index f53c3534..1f69dd3f 100644 --- a/src/jvm/clojure/lang/IChunkedSeq.java +++ b/src/jvm/clojure/lang/IChunkedSeq.java @@ -14,7 +14,7 @@ package clojure.lang; public interface IChunkedSeq extends ISeq{ -Indexed chunkedFirst() throws Exception; +IChunk chunkedFirst() throws Exception; ISeq chunkedNext() throws Exception; diff --git a/src/jvm/clojure/lang/LazilyPersistentVector.java b/src/jvm/clojure/lang/LazilyPersistentVector.java index 9ffd9170..f3562cae 100644 --- a/src/jvm/clojure/lang/LazilyPersistentVector.java +++ b/src/jvm/clojure/lang/LazilyPersistentVector.java @@ -83,7 +83,7 @@ static class ChunkedSeq extends ASeq implements IChunkedSeq, IndexedSeq{ return chunkedNext(); } - public Indexed chunkedFirst(){ + public IChunk chunkedFirst(){ return new ArrayChunk(array, offset, end); } diff --git a/src/jvm/clojure/lang/PersistentVector.java b/src/jvm/clojure/lang/PersistentVector.java index 87bd11d7..5c662556 100644 --- a/src/jvm/clojure/lang/PersistentVector.java +++ b/src/jvm/clojure/lang/PersistentVector.java @@ -207,7 +207,7 @@ static public final class ChunkedSeq extends ASeq implements IChunkedSeq{ this.offset = offset; } - public Indexed chunkedFirst() throws Exception{ + public IChunk chunkedFirst() throws Exception{ return new ArrayChunk(node, offset); } |