diff options
author | Rich Hickey <richhickey@gmail.com> | 2006-06-11 16:28:11 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2006-06-11 16:28:11 +0000 |
commit | 6aed462896af74c4a6e692147dcf8fab6b5b6cbd (patch) | |
tree | bf428c30b7eab0ccbcb04b8173157d47d9da6f01 | |
parent | d1a992e60915cf5715e7b796e340f18cfe9df0bf (diff) |
renamed org.clojure to clojure
54 files changed, 2800 insertions, 604 deletions
diff --git a/src/jvm/clojure/runtime/AFn.java b/src/jvm/clojure/runtime/AFn.java index 323fe732..6405b07a 100644 --- a/src/jvm/clojure/runtime/AFn.java +++ b/src/jvm/clojure/runtime/AFn.java @@ -10,87 +10,87 @@ /* rich Mar 25, 2006 4:05:37 PM */ -package org.clojure.runtime; +package clojure.runtime; public class AFn extends Obj implements IFn{ -public Object invoke(ThreadLocalData tld) throws Exception +public Object invoke() throws Exception { return throwArity(); } -public Object invoke(ThreadLocalData tld, Object arg1) throws Exception +public Object invoke( Object arg1) throws Exception { return throwArity(); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2) throws Exception +public Object invoke( Object arg1, Object arg2) throws Exception { return throwArity(); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3) throws Exception { return throwArity(); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4) throws Exception { return throwArity(); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception { return throwArity(); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Cons args) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq args) throws Exception { return throwArity(); } -public Object applyTo(ThreadLocalData tld, Cons arglist) throws Exception { - return applyToHelper(this, tld, arglist); +public Object applyTo( ISeq arglist) throws Exception { + return applyToHelper(this, arglist); } -static public Object applyToHelper(IFn ifn,ThreadLocalData tld, Cons arglist) throws Exception +static public Object applyToHelper(IFn ifn, ISeq arglist) throws Exception { switch(RT.boundedLength(arglist, 5)) { case 0: - return ifn.invoke(tld); + return ifn.invoke(); case 1: - return ifn.invoke(tld, arglist.first); + return ifn.invoke( arglist.first()); case 2: - return ifn.invoke(tld, arglist.first - , (arglist = arglist.rest).first + return ifn.invoke( arglist.first() + , (arglist = arglist.rest()).first() ); case 3: - return ifn.invoke(tld, arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first + return ifn.invoke( arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() ); case 4: - return ifn.invoke(tld, arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first + return ifn.invoke( arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() ); case 5: - return ifn.invoke(tld, arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first + return ifn.invoke( arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() ); default: - return ifn.invoke(tld, arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , arglist.rest); + return ifn.invoke( arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , arglist.rest()); } } diff --git a/src/jvm/clojure/runtime/AGenerator.java b/src/jvm/clojure/runtime/AGenerator.java index 03b35dac..1494f06e 100644 --- a/src/jvm/clojure/runtime/AGenerator.java +++ b/src/jvm/clojure/runtime/AGenerator.java @@ -10,7 +10,7 @@ /* rich Apr 3, 2006 */ -package org.clojure.runtime; +package clojure.runtime; public abstract class AGenerator implements Iter{ diff --git a/src/jvm/clojure/runtime/Accessor.java b/src/jvm/clojure/runtime/Accessor.java index b69bb0bb..2367861a 100644 --- a/src/jvm/clojure/runtime/Accessor.java +++ b/src/jvm/clojure/runtime/Accessor.java @@ -10,7 +10,7 @@ /* rich Apr 19, 2006 */ -package org.clojure.runtime; +package clojure.runtime; public class Accessor extends Symbol implements IFn{ @@ -22,18 +22,17 @@ Accessor(String name) } -public Object invoke(ThreadLocalData tld) throws Exception { +public Object invoke() throws Exception { return AFn.throwArity(); } /** * Indexer implements IFn for attr access * This single arg version is the getter - * @param tld * @param obj - must be Obj * @return the value of the attr or nil if not found * @throws Exception */ -public Object invoke(ThreadLocalData tld, Object obj) throws Exception +public Object invoke( Object obj) throws Exception { return Reflector.invokeInstanceMember(memberName,obj); @@ -42,42 +41,41 @@ public Object invoke(ThreadLocalData tld, Object obj) throws Exception /** * Indexer implements IFn for attr access * This two arg version is the setter - * @param tld * @param obj - must be Obj * @param val * @return val * @throws Exception */ -public Object invoke(ThreadLocalData tld, Object obj, Object val) throws Exception +public Object invoke( Object obj, Object val) throws Exception { return Reflector.invokeInstanceMember(memberName,obj,val); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3) throws Exception { return Reflector.invokeInstanceMember(memberName,arg1,arg2,arg3); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4) throws Exception { return Reflector.invokeInstanceMember(memberName,arg1,arg2,arg3,arg4); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception { return Reflector.invokeInstanceMember(memberName,arg1,arg2,arg3,arg4,arg5); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Cons args) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq args) throws Exception { return Reflector.invokeInstanceMember(memberName,arg1,arg2,arg3,arg4,arg5,args); } -public Object applyTo(ThreadLocalData tld, Cons arglist) throws Exception { - return AFn.applyToHelper(this, tld, arglist); +public Object applyTo( ISeq arglist) throws Exception { + return AFn.applyToHelper(this, arglist); } } diff --git a/src/jvm/clojure/runtime/BigNum.java b/src/jvm/clojure/runtime/BigNum.java index 3955fe6a..952520e4 100644 --- a/src/jvm/clojure/runtime/BigNum.java +++ b/src/jvm/clojure/runtime/BigNum.java @@ -10,7 +10,7 @@ /* rich Mar 28, 2006 10:08:33 AM */ -package org.clojure.runtime; +package clojure.runtime; import java.math.BigInteger; @@ -171,25 +171,25 @@ public Num divide(RatioNum x) return Num.divide(x.numerator, x.denominator.multiply(val)); } -public Object truncateDivide(ThreadLocalData tld, Num num) +public Object truncateDivide( Num num) { - return num.truncateBy(tld, val); + return num.truncateBy( val); } -public Object truncateBy(ThreadLocalData tld, int div) +public Object truncateBy( int div) { - return Num.truncateBigints(tld, val, BigInteger.valueOf(div)); + return Num.truncateBigints( val, BigInteger.valueOf(div)); } -public Object truncateBy(ThreadLocalData tld, BigInteger div) +public Object truncateBy( BigInteger div) { - return Num.truncateBigints(tld, val, div); + return Num.truncateBigints( val, div); } -public Object truncateBy(ThreadLocalData tld, RatioNum div) +public Object truncateBy( RatioNum div) { - Num q = (Num) Num.truncate(tld, div.denominator.multiply(val), div.numerator); - return RT.setValues(tld, q, q.multiplyBy(div).subtractFrom(this)); + Num q = (Num) Num.truncate( div.denominator.multiply(val), div.numerator); + return RT.setValues( q, q.multiplyBy(div).subtractFrom(this)); } public Num negate() diff --git a/src/jvm/clojure/runtime/Binding.java b/src/jvm/clojure/runtime/Binding.java new file mode 100644 index 00000000..cf0e8031 --- /dev/null +++ b/src/jvm/clojure/runtime/Binding.java @@ -0,0 +1,25 @@ +/**
+ * 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.
+ **/
+
+package clojure.runtime;
+
+public class Binding {
+public Object val;
+public Binding rest;
+
+public Binding(Object val) {
+ this.val = val;
+}
+
+public Binding(Object val, Binding rest) {
+ this.val = val;
+ this.rest = rest;
+}
+}
diff --git a/src/jvm/clojure/runtime/Box.java b/src/jvm/clojure/runtime/Box.java index e1129029..9909a667 100644 --- a/src/jvm/clojure/runtime/Box.java +++ b/src/jvm/clojure/runtime/Box.java @@ -10,7 +10,7 @@ /* rich Mar 27, 2006 8:40:19 PM */ -package org.clojure.runtime; +package clojure.runtime; public class Box{ diff --git a/src/jvm/clojure/runtime/Cons.java b/src/jvm/clojure/runtime/Cons.java index 8cdd3bd9..5a32bd51 100644 --- a/src/jvm/clojure/runtime/Cons.java +++ b/src/jvm/clojure/runtime/Cons.java @@ -10,27 +10,28 @@ /* rich Mar 25, 2006 11:01:29 AM */ -package org.clojure.runtime; +package clojure.runtime; -public class Cons extends Obj implements Iter{ +public class Cons implements ISeq, ISequential{ -public final Object first; -public final Cons rest; +private final Object _first; +private final ISeq _rest; -public Cons(Object first, Cons rest) +public Cons(Object first, ISeq rest) { - this.first = first; - this.rest = rest; + this._first = first; + this._rest = rest; } -public Object get() - { - return first; - } +public Object first() { + return _first; +} -public Iter iterate() - { - return rest; - } +public ISeq rest() { + return _rest; +} +public ISeq seq() { + return this; +} } diff --git a/src/jvm/clojure/runtime/DoubleNum.java b/src/jvm/clojure/runtime/DoubleNum.java index 00ec7c7a..72f3a979 100644 --- a/src/jvm/clojure/runtime/DoubleNum.java +++ b/src/jvm/clojure/runtime/DoubleNum.java @@ -10,7 +10,7 @@ /* rich Mar 28, 2006 10:13:45 AM */ -package org.clojure.runtime; +package clojure.runtime; import java.math.BigInteger; import java.math.BigDecimal; @@ -160,40 +160,40 @@ public Num divide(RatioNum x) return Num.from(x.doubleValue() / val); } -static Object truncate(ThreadLocalData tld, double n, double d) +static Object truncate(double n, double d) { double q = n / d; if(q <= Integer.MAX_VALUE && q >= Integer.MIN_VALUE) { - return RT.setValues(tld, Num.from((int) q), + return RT.setValues(Num.from((int) q), Num.from(n - ((int) q) * d)); } else { //bigint quotient Num bq = Num.from(new BigDecimal(q).toBigInteger()); - return RT.setValues(tld, bq, + return RT.setValues(bq, Num.from(n - bq.doubleValue() * d)); } } -public Object truncateBy(ThreadLocalData tld, BigInteger x) +public Object truncateBy( BigInteger x) { - return truncate(tld, val, x.doubleValue()); + return truncate( val, x.doubleValue()); } -public Object truncateBy(ThreadLocalData tld, int x) +public Object truncateBy( int x) { - return truncate(tld, val, x); + return truncate( val, x); } -public Object truncateBy(ThreadLocalData tld, RatioNum x) +public Object truncateBy( RatioNum x) { - return truncate(tld, val, x.doubleValue()); + return truncate( val, x.doubleValue()); } -public Object truncateDivide(ThreadLocalData tld, Num num) +public Object truncateDivide( Num num) { - return truncate(tld, num.doubleValue(), val); + return truncate( num.doubleValue(), val); } public Num negate() diff --git a/src/jvm/clojure/runtime/FixNum.java b/src/jvm/clojure/runtime/FixNum.java index 31ecf1cb..31de19c8 100644 --- a/src/jvm/clojure/runtime/FixNum.java +++ b/src/jvm/clojure/runtime/FixNum.java @@ -10,7 +10,7 @@ /* rich Mar 28, 2006 10:09:27 AM */ -package org.clojure.runtime; +package clojure.runtime; import java.math.BigInteger; @@ -146,25 +146,25 @@ public Num multiply(RatioNum x) return x.multiply(val); } -public Object truncateDivide(ThreadLocalData tld, Num num) +public Object truncateDivide( Num num) { - return num.truncateBy(tld, val); + return num.truncateBy( val); } -public Object truncateBy(ThreadLocalData tld, int div) +public Object truncateBy( int div) { - return RT.setValues(tld, Num.from(val / div), Num.from(val % div)); + return RT.setValues( Num.from(val / div), Num.from(val % div)); } -public Object truncateBy(ThreadLocalData tld, BigInteger div) +public Object truncateBy( BigInteger div) { - return Num.truncateBigints(tld, BigInteger.valueOf(val), div); + return Num.truncateBigints( BigInteger.valueOf(val), div); } -public Object truncateBy(ThreadLocalData tld, RatioNum div) +public Object truncateBy( RatioNum div) { - Num q = (Num) Num.truncate(tld, div.denominator.multiply(val), div.numerator); - return RT.setValues(tld, q, q.multiplyBy(div).subtractFrom(this)); + Num q = (Num) Num.truncate( div.denominator.multiply(val), div.numerator); + return RT.setValues( q, q.multiplyBy(div).subtractFrom(this)); } public Num divideBy(Num rhs) diff --git a/src/jvm/clojure/runtime/FloatNum.java b/src/jvm/clojure/runtime/FloatNum.java index 8ea7b6de..477ddc6d 100644 --- a/src/jvm/clojure/runtime/FloatNum.java +++ b/src/jvm/clojure/runtime/FloatNum.java @@ -10,7 +10,7 @@ /* rich Mar 28, 2006 10:17:21 AM */ -package org.clojure.runtime; +package clojure.runtime; public abstract class FloatNum extends RealNum { diff --git a/src/jvm/clojure/runtime/FnSeq.java b/src/jvm/clojure/runtime/FnSeq.java new file mode 100644 index 00000000..430e6e8c --- /dev/null +++ b/src/jvm/clojure/runtime/FnSeq.java @@ -0,0 +1,30 @@ +/**
+ * 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.
+ **/
+
+package clojure.runtime;
+
+public class FnSeq implements ISeq{
+
+Object _first;
+IFn restFn;
+
+public FnSeq(Object first, IFn restFn) {
+ this._first = first;
+ this.restFn = restFn;
+}
+
+public Object first() {
+ return _first;
+}
+
+public ISeq rest() throws Exception {
+ return (ISeq) restFn.invoke();
+}
+}
diff --git a/src/jvm/clojure/runtime/IFn.java b/src/jvm/clojure/runtime/IFn.java index f5d1194f..3af6ea95 100644 --- a/src/jvm/clojure/runtime/IFn.java +++ b/src/jvm/clojure/runtime/IFn.java @@ -10,25 +10,25 @@ /* rich Mar 25, 2006 3:54:03 PM */ -package org.clojure.runtime; +package clojure.runtime; public interface IFn{ -public Object invoke(ThreadLocalData tld) throws Exception; +public Object invoke() throws Exception; -public Object invoke(ThreadLocalData tld, Object arg1) throws Exception; +public Object invoke(Object arg1) throws Exception; -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2) throws Exception; +public Object invoke(Object arg1, Object arg2) throws Exception; -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3) throws Exception; +public Object invoke(Object arg1, Object arg2, Object arg3) throws Exception; -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception; +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4) throws Exception; -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception; -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, - Cons args) throws Exception; +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, + ISeq args) throws Exception; -public Object applyTo(ThreadLocalData tld, Cons arglist) throws Exception; +public Object applyTo(ISeq arglist) throws Exception; } diff --git a/src/jvm/clojure/runtime/IMapEntry.java b/src/jvm/clojure/runtime/IMapEntry.java index fcf93a8b..9b090a82 100644 --- a/src/jvm/clojure/runtime/IMapEntry.java +++ b/src/jvm/clojure/runtime/IMapEntry.java @@ -8,7 +8,7 @@ * You must not remove this notice, or any other, from this software.
*/
-package org.clojure.runtime;
+package clojure.runtime;
public interface IMapEntry {
Object key();
diff --git a/src/jvm/clojure/runtime/IObj.java b/src/jvm/clojure/runtime/IObj.java index e4284aba..cfaa25ab 100644 --- a/src/jvm/clojure/runtime/IObj.java +++ b/src/jvm/clojure/runtime/IObj.java @@ -8,7 +8,7 @@ * You must not remove this notice, or any other, from this software.
**/
-package org.clojure.runtime;
+package clojure.runtime;
/**
* Created by IntelliJ IDEA.
@@ -18,9 +18,9 @@ package org.clojure.runtime; * To change this template use File | Settings | File Templates.
*/
public interface IObj {
-Object put(ThreadLocalData tld, Comparable key, Object val) throws Exception;
+Object put( Comparable key, Object val) throws Exception;
-Object get(ThreadLocalData tld, Comparable key) throws Exception;
+Object get( Comparable key) throws Exception;
-boolean has(ThreadLocalData tld, Comparable key) throws Exception;
+boolean has( Comparable key) throws Exception;
}
diff --git a/src/jvm/clojure/runtime/IPersistentMap.java b/src/jvm/clojure/runtime/IPersistentMap.java new file mode 100644 index 00000000..444aa45b --- /dev/null +++ b/src/jvm/clojure/runtime/IPersistentMap.java @@ -0,0 +1,31 @@ +/**
+ * 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.
+ */
+
+package clojure.runtime;
+
+
+public interface IPersistentMap extends Iterable, ISequential {
+
+int count();
+
+boolean contains(Object key);
+
+IMapEntry find(Object key);
+
+IPersistentMap add(Object key);
+
+IPersistentMap put(Object key, Object val);
+
+IPersistentMap remove(Object key);
+
+Object get(Object key);
+
+int capacity();
+}
diff --git a/src/jvm/clojure/runtime/ISeq.java b/src/jvm/clojure/runtime/ISeq.java new file mode 100644 index 00000000..2721f9e2 --- /dev/null +++ b/src/jvm/clojure/runtime/ISeq.java @@ -0,0 +1,24 @@ +package clojure.runtime;
+
+/**
+ * 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.
+ */
+
+/**
+ * A persistent, functional, sequence interface
+ *
+ * ISeqs are immutable values, i.e. neither first(), nor rest() changes
+ * or invalidates the ISeq
+ */
+public interface ISeq {
+
+Object first() throws Exception;
+
+ISeq rest() throws Exception;
+}
diff --git a/src/jvm/clojure/runtime/ISequential.java b/src/jvm/clojure/runtime/ISequential.java new file mode 100644 index 00000000..ecbb12e2 --- /dev/null +++ b/src/jvm/clojure/runtime/ISequential.java @@ -0,0 +1,18 @@ +package clojure.runtime;
+
+/**
+ * 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.
+ */
+
+
+public interface ISequential {
+
+ISeq seq() throws Exception;
+
+}
diff --git a/src/jvm/clojure/runtime/Indexer.java b/src/jvm/clojure/runtime/Indexer.java index 5eebe489..10cd3bf0 100644 --- a/src/jvm/clojure/runtime/Indexer.java +++ b/src/jvm/clojure/runtime/Indexer.java @@ -10,7 +10,7 @@ /* rich Apr 19, 2006 */ -package org.clojure.runtime; +package clojure.runtime; public class Indexer extends AFn{ } diff --git a/src/jvm/clojure/runtime/IntegerNum.java b/src/jvm/clojure/runtime/IntegerNum.java index 6c801dd3..916d812c 100644 --- a/src/jvm/clojure/runtime/IntegerNum.java +++ b/src/jvm/clojure/runtime/IntegerNum.java @@ -10,7 +10,7 @@ /* rich Mar 28, 2006 10:11:55 AM */ -package org.clojure.runtime; +package clojure.runtime; public abstract class IntegerNum extends RationalNum { diff --git a/src/jvm/clojure/runtime/Iter.java b/src/jvm/clojure/runtime/Iter.java index 82e1db5a..017347df 100644 --- a/src/jvm/clojure/runtime/Iter.java +++ b/src/jvm/clojure/runtime/Iter.java @@ -10,7 +10,7 @@ /* rich Apr 3, 2006 10:54:14 AM */ -package org.clojure.runtime; +package clojure.runtime; /** diff --git a/src/jvm/clojure/runtime/IteratorIter.java b/src/jvm/clojure/runtime/IteratorIter.java index bfcec41a..e699ad75 100644 --- a/src/jvm/clojure/runtime/IteratorIter.java +++ b/src/jvm/clojure/runtime/IteratorIter.java @@ -10,7 +10,7 @@ /* rich Apr 3, 2006 */ -package org.clojure.runtime; +package clojure.runtime; import java.util.Iterator; diff --git a/src/jvm/clojure/runtime/Keyword.java b/src/jvm/clojure/runtime/Keyword.java index 63ea4d7d..424f149c 100644 --- a/src/jvm/clojure/runtime/Keyword.java +++ b/src/jvm/clojure/runtime/Keyword.java @@ -10,7 +10,7 @@ /* rich Mar 29, 2006 10:39:05 AM */ -package org.clojure.runtime; +package clojure.runtime; public class Keyword extends Symbol implements IFn{ @@ -28,62 +28,60 @@ Keyword(String name) } -public Object invoke(ThreadLocalData tld) throws Exception { +public Object invoke() throws Exception { return AFn.throwArity(); } /** * Indexer implements IFn for attr access * This single arg version is the getter - * @param tld * @param obj - must be Obj * @return the value of the attr or nil if not found * @throws Exception */ -public Object invoke(ThreadLocalData tld, Object obj) throws Exception +public Object invoke(Object obj) throws Exception { if (obj == null) return null; - return ((IObj)obj).get(tld,this); + return ((IObj)obj).get(this); } /** * Indexer implements IFn for attr access * This two arg version is the setter - * @param tld * @param obj - must be Obj * @param val * @return val * @throws Exception */ -public Object invoke(ThreadLocalData tld, Object obj, Object val) throws Exception +public Object invoke(Object obj, Object val) throws Exception { - return ((IObj)obj).put(tld,this,val); + return ((IObj)obj).put(this,val); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3) throws Exception { return AFn.throwArity(); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4) throws Exception { return AFn.throwArity(); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception { return AFn.throwArity(); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Cons args) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq args) throws Exception { return AFn.throwArity(); } -public Object applyTo(ThreadLocalData tld, Cons arglist) throws Exception { - return AFn.applyToHelper(this, tld, arglist); +public Object applyTo( ISeq arglist) throws Exception { + return AFn.applyToHelper(this, arglist); } } diff --git a/src/jvm/clojure/runtime/LineNumberingPushbackReader.java b/src/jvm/clojure/runtime/LineNumberingPushbackReader.java index a3a10e1a..bb21c4cc 100644 --- a/src/jvm/clojure/runtime/LineNumberingPushbackReader.java +++ b/src/jvm/clojure/runtime/LineNumberingPushbackReader.java @@ -8,7 +8,7 @@ * You must not remove this notice, or any other, from this software.
*/
-package org.clojure.runtime;
+package clojure.runtime;
import java.io.PushbackReader;
import java.io.Reader;
diff --git a/src/jvm/clojure/runtime/Namespace.java b/src/jvm/clojure/runtime/Namespace.java index 04a7d40e..ecb609cc 100644 --- a/src/jvm/clojure/runtime/Namespace.java +++ b/src/jvm/clojure/runtime/Namespace.java @@ -10,7 +10,7 @@ /* rich Mar 27, 2006 1:29:39 PM */ -package org.clojure.runtime; +package clojure.runtime; import java.util.HashMap; import java.util.IdentityHashMap; diff --git a/src/jvm/clojure/runtime/Num.java b/src/jvm/clojure/runtime/Num.java index 182955e2..6e3c8252 100644 --- a/src/jvm/clojure/runtime/Num.java +++ b/src/jvm/clojure/runtime/Num.java @@ -10,7 +10,7 @@ /* rich Mar 28, 2006 10:07:33 AM */ -package org.clojure.runtime; +package clojure.runtime; import java.math.BigInteger; @@ -115,23 +115,23 @@ abstract public Num divide(BigInteger x); abstract public Num divide(RatioNum x); -static public Object truncate(ThreadLocalData tld, Object num, Object div) +static public Object truncate(Object num, Object div) { - return Num.from(div).truncateDivide(tld, Num.from(num)); + return Num.from(div).truncateDivide( Num.from(num)); } -abstract public Object truncateDivide(ThreadLocalData tld, Num rhs); +abstract public Object truncateDivide(Num rhs); -abstract public Object truncateBy(ThreadLocalData tld, int x); +abstract public Object truncateBy(int x); -abstract public Object truncateBy(ThreadLocalData tld, BigInteger x); +abstract public Object truncateBy(BigInteger x); -abstract public Object truncateBy(ThreadLocalData tld, RatioNum x); +abstract public Object truncateBy(RatioNum x); -static public Object truncateBigints(ThreadLocalData tld, BigInteger n, BigInteger d) +static public Object truncateBigints(BigInteger n, BigInteger d) { BigInteger[] result = n.divideAndRemainder(d); - return RT.setValues(tld, Num.from(result[0]), Num.from(result[1])); + return RT.setValues(Num.from(result[0]), Num.from(result[1])); } static public Num divide(BigInteger n, BigInteger d) diff --git a/src/jvm/clojure/runtime/Obj.java b/src/jvm/clojure/runtime/Obj.java index c8aa532d..c7b64740 100644 --- a/src/jvm/clojure/runtime/Obj.java +++ b/src/jvm/clojure/runtime/Obj.java @@ -10,7 +10,7 @@ /* rich Mar 25, 2006 3:44:58 PM */ -package org.clojure.runtime; +package clojure.runtime; import java.util.IdentityHashMap; @@ -19,7 +19,7 @@ public class Obj implements IObj { IdentityHashMap attrs; public static final int INITIAL_SIZE = 7; -public Object put(ThreadLocalData tld, Comparable key, Object val) +public Object put( Comparable key, Object val) { if(attrs == null) attrs = new IdentityHashMap(INITIAL_SIZE); @@ -27,14 +27,14 @@ public Object put(ThreadLocalData tld, Comparable key, Object val) return val; } -public Object get(ThreadLocalData tld, Comparable key) +public Object get( Comparable key) { if(attrs == null) return null; return attrs.get(key); } -public boolean has(ThreadLocalData tld, Comparable key){ +public boolean has( Comparable key){ if(attrs == null) return false; return attrs.containsKey(key); diff --git a/src/jvm/clojure/runtime/PersistentArray.java b/src/jvm/clojure/runtime/PersistentArray.java index b581ecf6..631f5258 100644 --- a/src/jvm/clojure/runtime/PersistentArray.java +++ b/src/jvm/clojure/runtime/PersistentArray.java @@ -10,7 +10,7 @@ /* rich Jun 2, 2006 */ -package org.clojure.runtime; +package clojure.runtime; //import java.util.concurrent.atomic.AtomicInteger; //import java.util.concurrent.atomic.AtomicReferenceArray; @@ -46,26 +46,32 @@ import java.util.Random; * I added hybrid most-recent-sequential-range + shared-bitset idea, multi-thread-safety */ -public class PersistentArray implements Iterable{ +public class PersistentArray implements Iterable, ISequential{ public Iterator iterator(){ return new ValIter(this); } +public ISeq seq() { + if(length() > 0) + return new Seq(this, 0); + return null; +} + static class Master{ - final Entry[] array; - final Object defaultVal; + final Entry[] array; + final Object defaultVal; int rev; int load; - final int maxLoad; + final int maxLoad; final float loadFactor; Master(int size,Object defaultVal, float loadFactor){ - this.array = new Entry[size];//new AtomicReferenceArray(size); - this.defaultVal = defaultVal; + this.array = new Entry[size];//new AtomicReferenceArray(size); + this.defaultVal = defaultVal; this.rev = 0;//new AtomicInteger(0); this.load = 0;//new AtomicInteger(0); - this.maxLoad = (int) (size * loadFactor); + this.maxLoad = (int) (size * loadFactor); this.loadFactor = loadFactor; } } @@ -103,6 +109,26 @@ static class EntryLink extends Entry{ } } +static class Seq implements ISeq{ + final PersistentArray p; + final int i; + + Seq(PersistentArray p, int i){ + this.p = p; + this.i = i; + } + + public Object first() { + return p.get(i); + } + + public ISeq rest() { + if(i+1 < p.length()) + return new Seq(p, i + 1); + return null; + } +} + static class ValIter implements Iterator{ PersistentArray p; int i; diff --git a/src/jvm/clojure/runtime/PersistentArrayIdentityMap.java b/src/jvm/clojure/runtime/PersistentArrayIdentityMap.java new file mode 100644 index 00000000..147a1d91 --- /dev/null +++ b/src/jvm/clojure/runtime/PersistentArrayIdentityMap.java @@ -0,0 +1,35 @@ +/**
+ * 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.
+ **/
+
+package clojure.runtime;
+
+/**
+ * ArrayMap using identity (==) comparison instead of equals
+ */
+public class PersistentArrayIdentityMap extends PersistentArrayMap {
+
+public static PersistentArrayIdentityMap EMPTY = new PersistentArrayIdentityMap();
+
+
+private PersistentArrayIdentityMap() {
+}
+
+IPersistentMap empty() {
+ return EMPTY;
+}
+
+public PersistentArrayIdentityMap(Object[] init) {
+ super(init);
+}
+
+boolean equalKey(Object k1, Object k2) {
+ return k1 == k2;
+}
+}
diff --git a/src/jvm/clojure/runtime/PersistentArrayMap.java b/src/jvm/clojure/runtime/PersistentArrayMap.java new file mode 100644 index 00000000..19ea16f5 --- /dev/null +++ b/src/jvm/clojure/runtime/PersistentArrayMap.java @@ -0,0 +1,212 @@ +/**
+ * 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.
+ **/
+
+package clojure.runtime;
+
+import java.util.Iterator;
+
+/**
+ * Simple implementation of persistent map on an array
+
+ * Note that instances of this class are constant values
+ * i.e. add/remove etc return new values
+ *
+ * Copies array on every change, so only appropriate for _very_small_ maps
+ *
+ * null keys and values are ok, but you won't be able to distinguish a null value via get - use contains/find
+ */
+
+public class PersistentArrayMap implements IPersistentMap, ISequential {
+
+final Object[] array;
+
+public static PersistentArrayMap EMPTY = new PersistentArrayMap();
+
+protected PersistentArrayMap(){
+ this.array = RT.EMPTY_ARRAY;
+}
+
+/**
+ * This ctor captures/aliases the passed array, so do not modify later
+ * @param init {key1,val1,key2,val2,...}
+ */
+public PersistentArrayMap(Object[] init){
+ this.array = init;
+}
+
+public int count() {
+ return array.length/2;
+}
+
+public boolean contains(Object key){
+ return indexOf(key) >= 0;
+}
+
+public IMapEntry find(Object key) {
+ int i = indexOf(key);
+ if(i >= 0)
+ return new Iter(array,i);
+ return null;
+}
+
+public IPersistentMap add(Object key) {
+
+ return put(key,null);
+}
+
+public IPersistentMap put(Object key, Object val) {
+ int i = indexOf(key);
+ Object[] newArray;
+ if(i >= 0) //already have key, same-sized replacement
+ {
+ if(array[i+1] == val) //no change, no op
+ return this;
+ newArray = array.clone();
+ newArray[i+1] = val;
+ }
+ else //didn't have key, grow
+ {
+ newArray = new Object[array.length + 2];
+ if(array.length > 0)
+ System.arraycopy(array,0,newArray,2,array.length);
+ newArray[0] = key;
+ newArray[1] = val;
+ }
+ return new PersistentArrayMap(newArray);
+}
+
+public IPersistentMap remove(Object key) {
+ int i = indexOf(key);
+ if(i >= 0) //have key, will remove
+ {
+ int newlen = array.length - 2;
+ if(newlen == 0)
+ return empty();
+ Object[] newArray = new Object[newlen];
+ for(int s=0,d=0;s<array.length;s += 2)
+ {
+ if(!equalKey(array[s],key)) //skip removal key
+ {
+ newArray[d] = array[s];
+ newArray[d+1] = array[s+1];
+ d += 2;
+ }
+ }
+ return new PersistentArrayMap(newArray);
+ }
+ //don't have key, no op
+ return this;
+}
+
+IPersistentMap empty() {
+ return EMPTY;
+}
+
+public Object get(Object key) {
+ int i = indexOf(key);
+ if(i >= 0)
+ return array[i + 1];
+ return null;
+}
+
+public int capacity() {
+ return count();
+}
+
+int indexOf(Object key){
+ for(int i=0;i<array.length;i+=2)
+ {
+ if(equalKey(array[i],key))
+ return i;
+ }
+ return -1;
+}
+
+boolean equalKey(Object k1,Object k2){
+ if(k1 == null)
+ return k2 == null;
+ return k1.equals(k2);
+}
+
+public Iterator iterator() {
+ return new Iter(array);
+}
+
+public ISeq seq() {
+ if(array.length > 0)
+ return new Seq(array,0);
+ return null;
+}
+
+static class Seq implements ISeq, IMapEntry{
+ final Object[] array;
+ final int i;
+
+ Seq(Object[] array, int i){
+ this.array = array;
+ this.i = i;
+ }
+
+ public Object key() {
+ return array[i];
+ }
+
+ public Object val() {
+ return array[i+1];
+ }
+
+ public Object first() {
+ return this;
+ }
+
+ public ISeq rest() {
+ if(i+2 < array.length)
+ return new Seq(array, i + 2);
+ return null;
+ }
+}
+
+static class Iter implements Iterator,IMapEntry{
+ Object[] array;
+ int i;
+
+ //for iterator
+ Iter(Object[] array){
+ this(array,-2);
+ }
+
+ //for find
+ Iter(Object[] array, int i){
+ this.array = array;
+ this.i = i;
+ }
+
+ public boolean hasNext() {
+ return i < array.length - 2;
+ }
+
+ public Object next() {
+ i+=2;
+ return this;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object key() {
+ return array[i];
+ }
+
+ public Object val() {
+ return array[i+1];
+ }
+}
+}
diff --git a/src/jvm/clojure/runtime/PersistentHashtableIdentityMap.java b/src/jvm/clojure/runtime/PersistentHashtableIdentityMap.java new file mode 100644 index 00000000..5a3c9b56 --- /dev/null +++ b/src/jvm/clojure/runtime/PersistentHashtableIdentityMap.java @@ -0,0 +1,96 @@ +/**
+ * 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.
+ **/
+
+package clojure.runtime;
+
+import java.util.Iterator;
+
+public class PersistentHashtableIdentityMap extends PersistentHashtableMap {
+
+public PersistentHashtableIdentityMap(int initialCapacity) {
+ super(initialCapacity);
+}
+
+public PersistentHashtableIdentityMap(Object[] init) {
+ super(init);
+}
+
+PersistentHashtableIdentityMap(int count, PersistentArray array) {
+ super(count, array);
+}
+
+PersistentHashtableIdentityMap(int i, PersistentArray newArray, int growAtCount) {
+ super(i, newArray, growAtCount);
+}
+
+
+public Iterator<IMapEntry> iterator() {
+ return new Iter(array);
+}
+
+
+static class Iter implements Iterator{
+ PersistentArray buckets;
+ int b;
+ PersistentListIdentityMap e;
+
+ Iter(PersistentArray buckets){
+ this.buckets = buckets;
+ this.b = -1;
+ nextBucket();
+ }
+
+ private void nextBucket() {
+ e = null;
+ for(b = b+1;b<buckets.length();b++)
+ {
+ PersistentListIdentityMap a = (PersistentListIdentityMap) buckets.get(b);
+ if(a != null && a != PersistentListIdentityMap.EMPTY)
+ {
+ e = a;
+ break;
+ }
+ }
+ }
+
+ public boolean hasNext() {
+ return e != null;
+ }
+
+ public Object next() {
+ PersistentListIdentityMap ret = e;
+ e = e.next();
+ if(e == PersistentListIdentityMap.EMPTY)
+ nextBucket();
+ return ret;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+}
+
+IPersistentMap create(int capacity) {
+ return new PersistentHashtableIdentityMap(capacity);
+}
+
+IPersistentMap create(int count, PersistentArray array) {
+ return new PersistentHashtableIdentityMap(count, array);
+}
+
+IPersistentMap create(int i, PersistentArray newArray, int growAtCount){
+ return new PersistentHashtableIdentityMap(i, newArray, growAtCount);
+}
+
+IPersistentMap createListMap(Object key, Object val){
+ return PersistentListIdentityMap.create(key,val);
+}
+
+}
diff --git a/src/jvm/clojure/runtime/PersistentHashtableMap.java b/src/jvm/clojure/runtime/PersistentHashtableMap.java new file mode 100644 index 00000000..24b46453 --- /dev/null +++ b/src/jvm/clojure/runtime/PersistentHashtableMap.java @@ -0,0 +1,255 @@ +/**
+ * 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.
+ **/
+
+package clojure.runtime;
+
+import java.util.Iterator;
+import java.math.BigInteger;
+
+public class PersistentHashtableMap implements IPersistentMap {
+
+static final float FILL_FACTOR = 0.75f;
+
+final PersistentArray array;
+final int _count;
+final int growAtCount;
+
+public PersistentHashtableMap(int initialCapacity) {
+ array = new PersistentArray(calcPrimeCapacity(initialCapacity));
+ _count = 0;
+ this.growAtCount = (int) (this.array.length()*FILL_FACTOR);
+}
+
+/**
+ * @param init {key1,val1,key2,val2,...}
+ */
+public PersistentHashtableMap(Object[] init){
+ //start halfway to a rehash
+ PersistentArray narray = new PersistentArray(calcPrimeCapacity(init.length));
+ for(int i=0;i<init.length;i+=2)
+ {
+ narray = doPut(bucketFor(init[i],narray),init[i], init[i + 1],narray);
+ }
+ this.array = narray;
+ this._count = init.length/2; //hmmm... presumes no dupe keys in init
+ this.growAtCount = (int) (this.array.length()*FILL_FACTOR);
+}
+
+PersistentHashtableMap(int count,PersistentArray array) {
+ this._count = count;
+ this.array = array;
+ this.growAtCount = (int) (this.array.length()*FILL_FACTOR);
+}
+
+PersistentHashtableMap(int count,PersistentArray array,int growAt) {
+ this._count = count;
+ this.array = array;
+ this.growAtCount = growAt;
+}
+
+int calcPrimeCapacity(int capacity) {
+ return BigInteger.valueOf((long) (capacity/FILL_FACTOR)).nextProbablePrime().intValue();
+}
+
+public int count() {
+ return _count;
+}
+
+public boolean contains(Object key) {
+ IPersistentMap entries = entriesFor(key);
+ return entries != null && entries.contains(key);
+}
+
+public IMapEntry find(Object key) {
+ IPersistentMap entries = entriesFor(key);
+ if(entries != null)
+ return entries.find(key);
+ return null;
+}
+
+public IPersistentMap add(Object key) {
+ return put(key, null);
+}
+
+public IPersistentMap put(Object key, Object val) {
+ if(_count > growAtCount)
+ return grow().put(key, val);
+ int i = bucketFor(key,array);
+ int incr = 1;
+ PersistentArray newArray = doPut(i, key, val, array);
+ if(newArray == array)
+ return this;
+ if(array.get(i) != null && ((IPersistentMap)newArray.get(i)).count() == ((IPersistentMap)array.get(i)).count()) //key already there, no growth
+ incr = 0;
+ return create(_count + incr, newArray, growAtCount);
+}
+
+PersistentArray doPut(int i,Object key,Object val,PersistentArray array){
+ IPersistentMap entries = (IPersistentMap) array.get(i);
+ IPersistentMap newEntries;
+ if (entries != null)
+ {
+ newEntries = entries.put(key, val);
+ if(newEntries == entries) //already there with same value, no op
+ return array;
+ }
+ else
+ newEntries = createListMap(key, val);
+ //newEntries = createArrayMap(new Object[]{key, val});
+
+ return array.set(i, newEntries);
+}
+
+public IPersistentMap remove(Object key) {
+ int i = bucketFor(key,array);
+ IPersistentMap entries = (IPersistentMap) array.get(i);
+ if (entries != null)
+ {
+ IPersistentMap newEntries = entries.remove(key);
+ if (newEntries != entries)
+ return create(_count - 1, array.set(i, newEntries));
+ }
+ //not there, no op
+ return this;
+}
+
+public Object get(Object key) {
+ IPersistentMap entries = entriesFor(key);
+ if(entries != null)
+ return entries.get(key);
+ return null;
+}
+
+public int capacity() {
+ return array.length();
+}
+
+IPersistentMap grow(){
+ PersistentArray newArray = new PersistentArray(calcPrimeCapacity(_count * 2));
+ for (Object o : this)
+ {
+ IMapEntry e = (IMapEntry) o;
+ newArray = doPut(bucketFor(e.key(),newArray),e.key(), e.val(),newArray);
+ }
+ return create(_count,newArray);
+}
+
+public Iterator iterator() {
+ return new Iter(array);
+}
+
+public ISeq seq() throws Exception {
+ return Seq.create(array);
+}
+
+static class Seq implements ISeq{
+ PersistentArray buckets;
+ int b;
+ ISeq e;
+
+
+ static public Seq create(PersistentArray buckets) throws Exception {
+ return next(buckets, -1, null);
+ }
+
+ static Seq next(PersistentArray buckets, int b, ISeq e) throws Exception {
+ if(e != null && e.rest() != null)
+ return new Seq(buckets,b,e.rest());
+ for(b = b+1;b<buckets.length();b++)
+ {
+ ISequential a = (ISequential) buckets.get(b);
+ if(a != null && a.seq() != null)
+ return new Seq(buckets,b,a.seq());
+ }
+ return null;
+ }
+
+ Seq(PersistentArray buckets, int b, ISeq e) {
+ this.buckets = buckets;
+ this.b = b;
+ this.e = e;
+ }
+
+ public Object first() throws Exception {
+ return e.first();
+ }
+
+ public ISeq rest() throws Exception {
+ return next(buckets,b,e);
+ }
+}
+
+static class Iter implements Iterator{
+ PersistentArray buckets;
+ int b;
+ PersistentListMap e;
+
+ Iter(PersistentArray buckets){
+ this.buckets = buckets;
+ this.b = -1;
+ nextBucket();
+ }
+
+ private void nextBucket() {
+ e = null;
+ for(b = b+1;b<buckets.length();b++)
+ {
+ PersistentListMap a = (PersistentListMap) buckets.get(b);
+ if(a != null && a != PersistentListMap.EMPTY)
+ {
+ e = a;
+ break;
+ }
+ }
+ }
+
+ public boolean hasNext() {
+ return e != null;
+ }
+
+ public Object next() {
+ PersistentListMap ret = e;
+ e = e.next();
+ if(e == PersistentListMap.EMPTY)
+ nextBucket();
+ return ret;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+}
+
+final IPersistentMap entriesFor(Object key){
+ return (IPersistentMap) array.get(bucketFor(key,array));
+}
+
+static int bucketFor(Object key, PersistentArray array) {
+ return (key.hashCode() & 0x7fffffff)%array.length();
+}
+
+IPersistentMap create(int capacity) {
+ return new PersistentHashtableMap(capacity);
+}
+
+IPersistentMap create(int count,PersistentArray array) {
+ return new PersistentHashtableMap(count, array);
+}
+
+IPersistentMap create(int i, PersistentArray newArray, int growAtCount){
+ return new PersistentHashtableMap(i, newArray, growAtCount);
+}
+
+
+IPersistentMap createListMap(Object key, Object val){
+ return PersistentListMap.create(key,val);
+}
+
+}
diff --git a/src/jvm/clojure/runtime/PersistentHybridIdentityMap.java b/src/jvm/clojure/runtime/PersistentHybridIdentityMap.java new file mode 100644 index 00000000..79548198 --- /dev/null +++ b/src/jvm/clojure/runtime/PersistentHybridIdentityMap.java @@ -0,0 +1,47 @@ +/**
+ * 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.
+ **/
+
+package clojure.runtime;
+
+public class PersistentHybridIdentityMap extends PersistentHybridMap{
+
+public PersistentHybridIdentityMap(Object[] init) {
+ super(init);
+}
+
+public PersistentHybridIdentityMap(int initialCapacity) {
+ super(initialCapacity);
+}
+
+PersistentHybridIdentityMap(IPersistentMap impl) {
+ super(impl);
+}
+
+public IPersistentMap create(IPersistentMap impl) {
+ return new PersistentHybridIdentityMap(impl);
+}
+
+public PersistentArrayMap createArrayMap(Object[] init) {
+ return new PersistentArrayIdentityMap(init);
+}
+
+IPersistentMap createArrayMap() {
+ return PersistentArrayIdentityMap.EMPTY;
+}
+
+IPersistentMap createHashtableMap(Object[] init) {
+ return new PersistentHashtableIdentityMap(init);
+}
+
+IPersistentMap createHashtableMap(int initialCapacity) {
+ return new PersistentHashtableIdentityMap(initialCapacity);
+}
+
+}
diff --git a/src/jvm/clojure/runtime/PersistentHybridMap.java b/src/jvm/clojure/runtime/PersistentHybridMap.java new file mode 100644 index 00000000..b7eebe1f --- /dev/null +++ b/src/jvm/clojure/runtime/PersistentHybridMap.java @@ -0,0 +1,104 @@ +/**
+ * 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.
+ **/
+
+package clojure.runtime;
+
+import java.util.Iterator;
+
+public class PersistentHybridMap implements IPersistentMap{
+
+IPersistentMap impl;
+static final int CAPACITY_THRESHOLD = 42;
+
+public PersistentHybridMap(Object[] init){
+ if(init.length/2 < CAPACITY_THRESHOLD)
+ impl = createArrayMap(init);
+ impl = createHashtableMap(init);
+}
+
+public PersistentHybridMap(int initialCapacity){
+ if(initialCapacity < CAPACITY_THRESHOLD)
+ impl = createArrayMap();
+ else
+ impl = createHashtableMap(initialCapacity);
+}
+
+PersistentHybridMap(IPersistentMap impl){
+ this.impl = impl;
+}
+
+public int count() {
+ return impl.count();
+}
+
+public boolean contains(Object key) {
+ return impl.contains(key);
+}
+
+public IMapEntry find(Object key) {
+ return impl.find(key);
+}
+
+public IPersistentMap add(Object key) {
+ return put(key, null);
+}
+
+public IPersistentMap put(Object key, Object val) {
+ IPersistentMap newImpl = impl.put(key,val);
+ if(newImpl.capacity() == CAPACITY_THRESHOLD)
+ {
+ newImpl = createHashtableMap(((PersistentArrayMap)newImpl).array);
+ }
+ return create(newImpl);
+}
+
+public IPersistentMap remove(Object key) {
+ IPersistentMap newImpl = impl.remove(key);
+ if(newImpl != impl)
+ return create(newImpl);
+ return this;
+}
+
+public Object get(Object key) {
+ return impl.get(key);
+}
+
+public int capacity() {
+ return impl.capacity();
+}
+
+public Iterator iterator() {
+ return ((Iterable)impl).iterator();
+}
+
+public IPersistentMap create(IPersistentMap impl) {
+ return new PersistentHybridMap(impl);
+}
+
+public PersistentArrayMap createArrayMap(Object[] init) {
+ return new PersistentArrayMap(init);
+}
+
+IPersistentMap createArrayMap() {
+ return PersistentArrayMap.EMPTY;
+}
+
+IPersistentMap createHashtableMap(Object[] init) {
+ return new PersistentHashtableMap(init);
+}
+
+IPersistentMap createHashtableMap(int initialCapacity) {
+ return new PersistentHashtableMap(initialCapacity);
+}
+
+public ISeq seq() throws Exception {
+ return impl.seq();
+}
+}
diff --git a/src/jvm/clojure/runtime/PersistentListIdentityMap.java b/src/jvm/clojure/runtime/PersistentListIdentityMap.java new file mode 100644 index 00000000..ac34f936 --- /dev/null +++ b/src/jvm/clojure/runtime/PersistentListIdentityMap.java @@ -0,0 +1,286 @@ +/**
+ * 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.
+ **/
+
+package clojure.runtime;
+
+import java.util.Iterator;
+
+/**
+ * Implementation of persistent map on a linked list
+ * Uses identity (==) comparison, vs equals() of PersistentListMap
+
+ * Note that instances of this class are constant values
+ * i.e. add/remove etc return new values
+ *
+ * Lookups/changes are linear, so only appropriate for _very_small_ maps
+ * PersistentArrayMap is generally faster, but this class avoids the double allocation,
+ * and so is better/faster as a bucket for hash tables
+ *
+ * null keys and values are ok, but you won't be able to distinguish a null value via get - use contains/find
+ *
+ * code duplication here is kind of gross, but most efficient
+ */
+
+public class PersistentListIdentityMap implements IPersistentMap, IMapEntry, ISeq, ISequential
+{
+
+static public PersistentListIdentityMap EMPTY = new PersistentListIdentityMap();
+
+static public PersistentListIdentityMap create(Object key, Object val){
+ return new Tail(key, val);
+}
+
+public Object key(){
+ return null;
+}
+
+public Object val(){
+ return null;
+}
+
+PersistentListIdentityMap next(){
+ return this;
+ }
+
+public int count(){
+ return 0;
+}
+
+public boolean contains(Object key){
+ return false;
+}
+
+public IMapEntry find(Object key){
+ return null;
+}
+
+public IPersistentMap add(Object key){
+ return put(key, null);
+}
+
+public PersistentListIdentityMap put(Object key, Object val){
+ return new Tail(key, val);
+}
+
+public PersistentListIdentityMap remove(Object key){
+ return this;
+}
+
+public Object get(Object key){
+ return null;
+}
+
+public int capacity(){
+ return 0;
+}
+
+public Object first() {
+ return null;
+}
+
+public ISeq rest() {
+ return null;
+}
+
+public ISeq seq() {
+ return null;
+}
+
+
+static class Iter implements Iterator{
+ PersistentListIdentityMap e;
+
+ Iter(PersistentListIdentityMap e)
+ {
+ this.e = e;
+ }
+
+ public boolean hasNext(){
+ return e != EMPTY;
+ }
+
+ public Object next(){
+ PersistentListIdentityMap ret = e;
+ e = e.next();
+ return ret;
+ }
+
+ public void remove(){
+ throw new UnsupportedOperationException();
+ }
+}
+
+public Iterator iterator(){
+ return new Iter(this);
+}
+
+static class Tail extends PersistentListIdentityMap {
+ final Object _key;
+ final Object _val;
+
+ Tail(Object key,Object val){
+ this._key = key;
+ this._val = val;
+ }
+
+ PersistentListIdentityMap next(){
+ return EMPTY;
+ }
+
+ public int count(){
+ return 1;
+ }
+
+ public Object get(Object key){
+ if(key ==_key)
+ return _val;
+ return null;
+ }
+
+ public int capacity(){
+ return 1;
+ }
+
+ public Object key(){
+ return _key;
+ }
+
+ public Object val(){
+ return _val;
+ }
+
+ public boolean contains(Object key){
+ return key ==_key;
+ }
+
+ public IMapEntry find(Object key){
+ if(key ==_key)
+ return this;
+ return null;
+ }
+
+ public PersistentListIdentityMap put(Object key, Object val){
+ if(key == _key) //replace
+ {
+ if(val == _val)
+ return this;
+ return new Tail(key,val);
+ }
+ return new Link(key,val,this);
+ }
+
+ public PersistentListIdentityMap remove(Object key){
+ if(key == _key)
+ return EMPTY;
+ return this;
+ }
+
+ public Object first() {
+ return this;
+ }
+
+ public ISeq rest() {
+ return null;
+ }
+
+ public ISeq seq() {
+ return this;
+ }
+}
+
+static class Link extends PersistentListIdentityMap {
+ final Object _key;
+ final Object _val;
+ final PersistentListIdentityMap _rest;
+
+ Link(Object key,Object val,PersistentListIdentityMap next){
+ this._key = key;
+ this._val = val;
+ this._rest = next;
+ }
+
+ public Object key(){
+ return _key;
+ }
+
+ public Object val(){
+ return _val;
+ }
+
+ PersistentListIdentityMap next(){
+ return _rest;
+ }
+
+ public int count(){
+ return 1 + _rest.count();
+ }
+
+ public boolean contains(Object key){
+ return find(key) != null;
+ }
+
+ public IMapEntry find(Object key){
+ if(key ==_key)
+ return this;
+ return _rest.find(key);
+ }
+
+ public PersistentListIdentityMap put(Object key, Object val){
+ IMapEntry e = find(key);
+ if(e != null)
+ {
+ if(e.val() == val)
+ return this;
+ return create(_key,_val,remove(key));
+ }
+ return new Link(key,val,this);
+ }
+
+ public PersistentListIdentityMap remove(Object key){
+ if(key == _key)
+ return _rest;
+ PersistentListIdentityMap r = _rest.remove(key);
+ if(r == _rest) //not there
+ return this;
+ return create(_key,_val,r);
+ }
+
+ public Object get(Object key){
+ IMapEntry e = find(key);
+ if(e != null)
+ return e.val();
+ return null;
+ }
+
+ public int capacity(){
+ return count();
+ }
+
+ public Object first() {
+ return this;
+ }
+
+ public ISeq rest() {
+ return _rest;
+ }
+
+ public ISeq seq() {
+ return this;
+ }
+
+ PersistentListIdentityMap create(Object k,Object v,PersistentListIdentityMap r){
+ if(r == EMPTY)
+ return new Tail(k,v);
+ return new Link(k, v, r);
+ }
+
+}
+
+}
diff --git a/src/jvm/clojure/runtime/PersistentListMap.java b/src/jvm/clojure/runtime/PersistentListMap.java new file mode 100644 index 00000000..b0e6cb73 --- /dev/null +++ b/src/jvm/clojure/runtime/PersistentListMap.java @@ -0,0 +1,290 @@ +/** + * 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 Jun 6, 2006 */ + +package clojure.runtime; + +import java.util.Iterator; + +/** + * Implementation of persistent map on a linked list + + * Note that instances of this class are constant values + * i.e. add/remove etc return new values + * + * Lookups/changes are linear, so only appropriate for _very_small_ maps + * PersistentArrayMap is generally faster, but this class avoids the double allocation, + * and so is better/faster as a bucket for hash tables + * + * null keys and values are ok, but you won't be able to distinguish a null value via get - use contains/find + */ +public class PersistentListMap implements IPersistentMap, IMapEntry, ISeq, ISequential +{ + +static public PersistentListMap EMPTY = new PersistentListMap(); + +static public PersistentListMap create(Object key, Object val){ + return new Tail(key, val); +} + + +public Object key(){ + return null; +} + +public Object val(){ + return null; +} + +PersistentListMap next(){ + return this; + } + +public int count(){ + return 0; +} + +public boolean contains(Object key){ + return false; +} + +public IMapEntry find(Object key){ + return null; +} + +public IPersistentMap add(Object key){ + return put(key, null); +} + +public PersistentListMap put(Object key, Object val){ + return new Tail(key, val); +} + +public PersistentListMap remove(Object key){ + return this; +} + +public Object get(Object key){ + return null; +} + +public int capacity(){ + return 0; +} + +public Object first() { + return null; +} + +public ISeq rest() { + return null; +} + +public ISeq seq() { + return null; +} + +static class Iter implements Iterator{ + PersistentListMap e; + + Iter(PersistentListMap e) + { + this.e = e; + } + + public boolean hasNext(){ + return e != EMPTY; + } + + public Object next(){ + PersistentListMap ret = e; + e = e.next(); + return ret; + } + + public void remove(){ + throw new UnsupportedOperationException(); + } +} + +public Iterator iterator(){ + return new Iter(this); +} + +static class Tail extends PersistentListMap { + final Object _key; + final Object _val; + + Tail(Object key,Object val){ + this._key = key; + this._val = val; + } + + PersistentListMap next(){ + return EMPTY; + } + + public int count(){ + return 1; + } + + public Object get(Object key){ + if(equalKey(key,_key)) + return _val; + return null; + } + + public int capacity(){ + return 1; + } + + public Object key(){ + return _key; + } + + public Object val(){ + return _val; + } + + public boolean contains(Object key){ + return equalKey(key,_key); + } + + public IMapEntry find(Object key){ + if(equalKey(key,_key)) + return this; + return null; + } + + public PersistentListMap put(Object key, Object val){ + if(equalKey(key,_key)) //replace + { + if(val == _val) + return this; + return new Tail(key,val); + } + return new Link(key,val,this); + } + + public PersistentListMap remove(Object key){ + if(equalKey(key,_key)) + return EMPTY; + return this; + } + + public Object first() { + return this; + } + + public ISeq rest() { + return null; + } + + public ISeq seq() { + return this; + } + +} + +static class Link extends PersistentListMap { + final Object _key; + final Object _val; + final PersistentListMap _rest; + + Link(Object key,Object val,PersistentListMap next){ + this._key = key; + this._val = val; + this._rest = next; + } + + public Object key(){ + return _key; + } + + public Object val(){ + return _val; + } + + PersistentListMap next(){ + return _rest; + } + + public int count(){ + return 1 + _rest.count(); + } + + public boolean contains(Object key){ + return find(key) != null; + } + + public IMapEntry find(Object key){ + if(equalKey(key,_key)) + return this; + return _rest.find(key); + } + + public PersistentListMap put(Object key, Object val){ + IMapEntry e = find(key); + if(e != null) + { + if(e.val() == val) + return this; + return create(_key,_val,remove(key)); + } + return new Link(key,val,this); + } + + public PersistentListMap remove(Object key){ + if(equalKey(key,_key)) + return _rest; + PersistentListMap r = _rest.remove(key); + if(r == _rest) //not there + return this; + return create(_key,_val,r); + } + + public Object get(Object key){ + IMapEntry e = find(key); + if(e != null) + return e.val(); + return null; + } + + public int capacity(){ + return count(); + } + + public Object first() { + return this; + } + + public ISeq rest() { + return _rest; + } + + public ISeq seq() { + return this; + } + + PersistentListMap create(Object k,Object v,PersistentListMap r){ + if(r == EMPTY) + return new Tail(k,v); + return new Link(k, v, r); + } + +} + +boolean equalKey(Object k1,Object k2){ + if(k1 == null) + return k2 == null; + return k1.equals(k2); +} +} diff --git a/src/jvm/clojure/runtime/PersistentTree.java b/src/jvm/clojure/runtime/PersistentTree.java new file mode 100644 index 00000000..291d1e69 --- /dev/null +++ b/src/jvm/clojure/runtime/PersistentTree.java @@ -0,0 +1,809 @@ +/** + * 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 May 20, 2006 */ + +package clojure.runtime; + +import java.util.*; + +/** + * Persistent Red Black Tree + * Note that instances of this class are constant values + * i.e. add/remove etc return new values + * <p/> + * See Okasaki, Kahrs, Larsen et al + */ + +public class PersistentTree implements IPersistentMap, ISequential { + +public final Comparator comp; +public final Node tree; +public final int _count; + +public PersistentTree(){ + this(null); +} + +public PersistentTree(Comparator comp){ + this.comp = comp; + tree = null; + _count = 0; +} + +public boolean contains(Object key){ + return find(key) != null; +} + +public PersistentTree add(Object key){ + return put(key, null); +} + +public PersistentTree put(Object key, Object val){ + Box found = new Box(null); + Node t = add(tree, key, val, found); + if(t == null) //null == already contains key + { + Node foundNode = (Node) found.val; + if(foundNode.val() == val) //note only get same collection on identity of val, not equals() + return this; + return new PersistentTree(comp, replace(tree, key, val), _count); + } + return new PersistentTree(comp, t.blacken(), _count + 1); +} + + +public PersistentTree remove(Object key){ + Box found = new Box(null); + Node t = remove(tree, key, found); + if(t == null) + { + if(found.val == null)//null == doesn't contain key + return this; + //empty + return new PersistentTree(comp); + } + return new PersistentTree(comp, t.blacken(), _count - 1); +} + +public ISeq seq() { + if(_count > 0) + return Seq.create(tree, true); + return null; +} + +public ISeq rseq() { + if(_count > 0) + return Seq.create(tree, false); + return null; +} + + +public NodeIterator iterator(){ + return new NodeIterator(tree, true); +} + +public NodeIterator reverseIterator(){ + return new NodeIterator(tree, false); +} + +public Iterator keys(){ + return keys(iterator()); +} + +public Iterator vals(){ + return vals(iterator()); +} + +public Iterator keys(NodeIterator it){ + return new KeyIterator(it); +} + +public Iterator vals(NodeIterator it){ + return new ValIterator(it); +} + +public Object minKey(){ + Node t = min(); + return t!=null?t.key:null; +} + +public Node min(){ + Node t = tree; + if(t != null) + { + while(t.left() != null) + t = t.left(); + } + return t; +} + +public Object maxKey(){ + Node t = max(); + return t!=null?t.key:null; +} + +public Node max(){ + Node t = tree; + if(t != null) + { + while(t.right() != null) + t = t.right(); + } + return t; +} + +public int depth(){ + return depth(tree); +} + +int depth(Node t){ + if(t == null) + return 0; + return 1 + Math.max(depth(t.left()), depth(t.right())); +} + +public Object get(Object key){ + Node n = find(key); + return (n != null) ? n.val() : null; +} + +public int capacity() { + return _count; +} + +public int count() { + return _count; +} + +public Node find(Object key){ + Node t = tree; + while(t != null) + { + int c = compare(key, t.key); + if(c == 0) + return t; + else if(c < 0) + t = t.left(); + else + t = t.right(); + } + return t; +} + +int compare(Object k1, Object k2){ + if(comp != null) + return comp.compare(k1, k2); + return ((Comparable) k1).compareTo(k2); +} + +Node add(Node t, Object key, Object val, Box found){ + if(t == null) + { + if(val == null) + return new Red(key); + return new RedVal(key, val); + } + int c = compare(key, t.key); + if(c == 0) + { + found.val = t; + return null; + } + Node ins = c < 0 ? add(t.left(), key, val, found) : add(t.right(), key, val, found); + if(ins == null) //found below + return null; + if(c < 0) + return t.addLeft(ins); + return t.addRight(ins); +} + +Node remove(Node t, Object key, Box found){ + if(t == null) + return null; //not found indicator + int c = compare(key, t.key); + if(c == 0) + { + found.val = t; + return append(t.left(), t.right()); + } + Node del = c < 0 ? remove(t.left(), key, found) : remove(t.right(), key, found); + if(del == null && found.val == null) //not found below + return null; + if(c < 0) + { + if(t.left() instanceof Black) + return balanceLeftDel(t.key, t.val(), del, t.right()); + else + return red(t.key, t.val(), del, t.right()); + } + if(t.right() instanceof Black) + return balanceRightDel(t.key, t.val(), t.left(), del); + return red(t.key, t.val(), t.left(), del); +// return t.removeLeft(del); +// return t.removeRight(del); +} + +static Node append(Node left, Node right){ + if(left == null) + return right; + else if(right == null) + return left; + else if(left instanceof Red) + { + if(right instanceof Red) + { + Node app = append(left.right(), right.left()); + if(app instanceof Red) + return red(app.key, app.val(), + red(left.key, left.val(), left.left(), app.left()), + red(right.key, right.val(), app.right(), right.right())); + else + return red(left.key, left.val(), left.left(), red(right.key, right.val(), app, right.right())); + } + else + return red(left.key, left.val(), left.left(), append(left.right(), right)); + } + else if(right instanceof Red) + return red(right.key, right.val(), append(left, right.left()), right.right()); + else //black/black + { + Node app = append(left.right(), right.left()); + if(app instanceof Red) + return red(app.key, app.val(), + black(left.key, left.val(), left.left(), app.left()), + black(right.key, right.val(), app.right(), right.right())); + else + return balanceLeftDel(left.key, left.val(), left.left(), black(right.key, right.val(), app, right.right())); + } +} + +static Node balanceLeftDel(Object key, Object val, Node del, Node right){ + if(del instanceof Red) + return red(key, val, del.blacken(), right); + else if(right instanceof Black) + return rightBalance(key, val, del, right.redden()); + else if(right instanceof Red && right.left() instanceof Black) + return red(right.left().key, right.left().val(), + black(key, val, del, right.left().left()), + rightBalance(right.key, right.val(), right.left().right(), right.right().redden())); + else + throw new UnsupportedOperationException("Invariant violation"); +} + +static Node balanceRightDel(Object key, Object val, Node left, Node del){ + if(del instanceof Red) + return red(key, val, left, del.blacken()); + else if(left instanceof Black) + return leftBalance(key, val, left.redden(), del); + else if(left instanceof Red && left.right() instanceof Black) + return red(left.right().key, left.right().val(), + leftBalance(left.key, left.val(), left.left().redden(), left.right().left()), + black(key, val, left.right().right(), del)); + else + throw new UnsupportedOperationException("Invariant violation"); +} + +static Node leftBalance(Object key, Object val, Node ins, Node right){ + if(ins instanceof Red && ins.left() instanceof Red) + return red(ins.key, ins.val(), ins.left().blacken(), black(key, val, ins.right(), right)); + else if(ins instanceof Red && ins.right() instanceof Red) + return red(ins.right().key, ins.right().val(), + black(ins.key, ins.val(), ins.left(), ins.right().left()), + black(key, val, ins.right().right(), right)); + else + return black(key, val, ins, right); +} + + +static Node rightBalance(Object key, Object val, Node left, Node ins){ + if(ins instanceof Red && ins.right() instanceof Red) + return red(ins.key, ins.val(), black(key, val, left, ins.left()), ins.right().blacken()); + else if(ins instanceof Red && ins.left() instanceof Red) + return red(ins.left().key, ins.left().val(), + black(key, val, left, ins.left().left()), + black(ins.key, ins.val(), ins.left().right(), ins.right())); + else + return black(key, val, left, ins); +} + +Node replace(Node t, Object key, Object val){ + int c = compare(key, t.key); + return t.replace(t.key, + c == 0 ? val : t.val(), + c < 0 ? replace(t.left(), key, val) : t.left(), + c > 0 ? replace(t.right(), key, val) : t.right()); +} + +PersistentTree(Comparator comp, Node tree, int count){ + this.comp = comp; + this.tree = tree; + this._count = count; +} + +static Red red(Object key, Object val, Node left, Node right){ + if(left == null && right == null) + { + if(val == null) + return new Red(key); + return new RedVal(key, val); + } + if(val == null) + return new RedBranch(key, left, right); + return new RedBranchVal(key, val, left, right); +} + +static Black black(Object key, Object val, Node left, Node right){ + if(left == null && right == null) + { + if(val == null) + return new Black(key); + return new BlackVal(key, val); + } + if(val == null) + return new BlackBranch(key, left, right); + return new BlackBranchVal(key, val, left, right); +} + +static abstract class Node implements IMapEntry { + final Object key; + + Node(Object key){ + this.key = key; + } + + public Object key(){ + return key; + } + + public Object val(){ + return null; + } + + Node left(){ + return null; + } + + Node right(){ + return null; + } + + abstract Node addLeft(Node ins); + + abstract Node addRight(Node ins); + + abstract Node removeLeft(Node del); + + abstract Node removeRight(Node del); + + abstract Node blacken(); + + abstract Node redden(); + + Node balanceLeft(Node parent){ + return black(parent.key, parent.val(), this, parent.right()); + } + + Node balanceRight(Node parent){ + return black(parent.key, parent.val(), parent.left(), this); + } + + abstract Node replace(Object key, Object val, Node left, Node right); + +} +static class Black extends Node{ + public Black(Object key){ + super(key); + } + + Node addLeft(Node ins){ + return ins.balanceLeft(this); + } + + Node addRight(Node ins){ + return ins.balanceRight(this); + } + + Node removeLeft(Node del){ + return balanceLeftDel(key, val(), del, right()); + } + + Node removeRight(Node del){ + return balanceRightDel(key, val(), left(), del); + } + + Node blacken(){ + return this; + } + + Node redden(){ + return new Red(key); + } + + Node replace(Object key, Object val, Node left, Node right){ + return black(key, val, left, right); + } + +} +static class BlackVal extends Black{ + final Object val; + + public BlackVal(Object key, Object val){ + super(key); + this.val = val; + } + + public Object val(){ + return val; + } + + Node redden(){ + return new RedVal(key, val); + } + +} +static class BlackBranch extends Black{ + final Node left; + + final Node right; + + public BlackBranch(Object key, Node left, Node right){ + super(key); + this.left = left; + this.right = right; + } + + public Node left(){ + return left; + } + + public Node right(){ + return right; + } + + Node redden(){ + return new RedBranch(key, left, right); + } + +} +static class BlackBranchVal extends BlackBranch{ + final Object val; + + public BlackBranchVal(Object key, Object val, Node left, Node right){ + super(key, left, right); + this.val = val; + } + + public Object val(){ + return val; + } + + Node redden(){ + return new RedBranchVal(key, val, left, right); + } + +} +static class Red extends Node{ + public Red(Object key){ + super(key); + } + + Node addLeft(Node ins){ + return red(key, val(), ins, right()); + } + + Node addRight(Node ins){ + return red(key, val(), left(), ins); + } + + Node removeLeft(Node del){ + return red(key, val(), del, right()); + } + + Node removeRight(Node del){ + return red(key, val(), left(), del); + } + + Node blacken(){ + return new Black(key); + } + + Node redden(){ + throw new UnsupportedOperationException("Invariant violation"); + } + + Node replace(Object key, Object val, Node left, Node right){ + return red(key, val, left, right); + } + +} +static class RedVal extends Red{ + final Object val; + + public RedVal(Object key, Object val){ + super(key); + this.val = val; + } + + public Object val(){ + return val; + } + + Node blacken(){ + return new BlackVal(key, val); + } + +} +static class RedBranch extends Red{ + final Node left; + + final Node right; + + public RedBranch(Object key, Node left, Node right){ + super(key); + this.left = left; + this.right = right; + } + + public Node left(){ + return left; + } + + public Node right(){ + return right; + } + + Node balanceLeft(Node parent){ + if(left instanceof Red) + return red(key, val(), left.blacken(), black(parent.key, parent.val(), right, parent.right())); + else if(right instanceof Red) + return red(right.key, right.val(), black(key, val(), left, right.left()), + black(parent.key, parent.val(), right.right(), parent.right())); + else + return super.balanceLeft(parent); + + } + + Node balanceRight(Node parent){ + if(right instanceof Red) + return red(key, val(), black(parent.key, parent.val(), parent.left(), left), right.blacken()); + else if(left instanceof Red) + return red(left.key, left.val(), black(parent.key, parent.val(), parent.left(), left.left()), + black(key, val(), left.right(), right)); + else + return super.balanceRight(parent); + } + + Node blacken(){ + return new BlackBranch(key, left, right); + } + +} + + +static class RedBranchVal extends RedBranch{ + final Object val; + + public RedBranchVal(Object key, Object val, Node left, Node right){ + super(key, left, right); + this.val = val; + } + + public Object val(){ + return val; + } + + Node blacken(){ + return new BlackBranchVal(key, val, left, right); + } +} + + +static public class Seq implements ISeq{ + final ISeq stack; + final boolean asc; + + public Seq(ISeq stack, boolean asc) { + this.stack = stack; + this.asc = asc; + } + + static Seq create(Node t, boolean asc){ + return new Seq(push(t, null, asc),asc); + } + + static ISeq push(Node t, ISeq stack, boolean asc){ + while(t != null) + { + stack = RT.cons(t,stack); + t = asc ? t.left() : t.right(); + } + return stack; + } + + public Object first() throws Exception { + return stack.first(); + } + + public ISeq rest() throws Exception { + Node t = (Node)stack.first(); + ISeq nextstack = push(asc ? t.right() : t.left(), stack.rest(), asc); + if(nextstack != null) + { + return new Seq(nextstack,asc); + } + return null; + } +} + +static public class NodeIterator implements Iterator{ + Stack stack = new Stack(); + boolean asc; + + NodeIterator(Node t, boolean asc){ + this.asc = asc; + push(t); + } + + void push(Node t){ + while(t != null) + { + stack.push(t); + t = asc ? t.left() : t.right(); + } + } + + public boolean hasNext(){ + return !stack.isEmpty(); + } + + public Object next(){ + Node t = (Node) stack.pop(); + push(asc ? t.right() : t.left()); + return t; + } + + public void remove(){ + throw new UnsupportedOperationException(); + } +} + +static class KeyIterator implements Iterator{ + NodeIterator it; + + KeyIterator(NodeIterator it){ + this.it = it; + } + + public boolean hasNext(){ + return it.hasNext(); + } + + public Object next(){ + return ((Node) it.next()).key; + } + + public void remove(){ + throw new UnsupportedOperationException(); + } +} + +static class ValIterator implements Iterator{ + NodeIterator it; + + ValIterator(NodeIterator it){ + this.it = it; + } + + public boolean hasNext(){ + return it.hasNext(); + } + + public Object next(){ + return ((Node) it.next()).val(); + } + + public void remove(){ + throw new UnsupportedOperationException(); + } +} + +static public void main(String args[]){ + if(args.length != 1) + System.err.println("Usage: RBTree n"); + int n = Integer.parseInt(args[0]); + Integer[] ints = new Integer[n]; + for(int i = 0; i < ints.length; i++) + { + ints[i] = new Integer(i); + } + Collections.shuffle(Arrays.asList(ints)); + //force the ListMap class loading now + PersistentListMap.EMPTY.add(1).add(2).add(3); + System.out.println("Building set"); + //IPersistentMap set = new PersistentHybridMap(1001); + IPersistentMap set = new PersistentHashtableMap(1001); + //IPersistentMap set = new ListMap(); + //IPersistentMap set = new ArrayMap(); + //IPersistentMap set = new RBTree(); +// for(int i = 0; i < ints.length; i++) +// { +// Integer anInt = ints[i]; +// set = set.add(anInt); +// } + long startTime = System.nanoTime(); + for(int i = 0; i < ints.length; i++) + { + Integer anInt = ints[i]; + set = set.put(anInt, anInt); + } + //System.out.println("_count = " + set.count()); + + +// System.out.println("_count = " + set._count + ", min: " + set.minKey() + ", max: " + set.maxKey() +// + ", depth: " + set.depth()); + Iterator it = set.iterator(); + while(it.hasNext()) + { + IMapEntry o = (IMapEntry) it.next(); + if(!set.contains(o.key())) + System.err.println("Can't find: " + o); + //else if(n < 2000) + // System.out.print(o.key().toString() + ","); + } + + for(int i = 0; i < ints.length/2; i++) + { + Integer anInt = ints[i]; + set = set.remove(anInt); + } + + long estimatedTime = System.nanoTime() - startTime; + System.out.println(); + + System.out.println("_count = " + set.count() + ", time: " + estimatedTime/10000); + + System.out.println("Building ht"); + Hashtable ht = new Hashtable(1001); + startTime = System.nanoTime(); +// for(int i = 0; i < ints.length; i++) +// { +// Integer anInt = ints[i]; +// ht.put(anInt,null); +// } + for(int i = 0; i < ints.length; i++) + { + Integer anInt = ints[i]; + ht.put(anInt, anInt); + } + //System.out.println("size = " + ht.size()); + it = ht.entrySet().iterator(); + while(it.hasNext()) + { + Map.Entry o = (Map.Entry) it.next(); + if(!ht.containsKey(o.getKey())) + System.err.println("Can't find: " + o); + //else if(n < 2000) + // System.out.print(o.toString() + ","); + } + + for(int i = 0; i < ints.length/2; i++) + { + Integer anInt = ints[i]; + ht.remove(anInt); + } + estimatedTime = System.nanoTime() - startTime; + System.out.println(); + System.out.println("size = " + ht.size() + ", time: " + estimatedTime/10000); + +// System.out.println("_count = " + set._count + ", min: " + set.minKey() + ", max: " + set.maxKey() +// + ", depth: " + set.depth()); +} +} diff --git a/src/jvm/clojure/runtime/RT.java b/src/jvm/clojure/runtime/RT.java index 4298a4c9..c0eee9f6 100644 --- a/src/jvm/clojure/runtime/RT.java +++ b/src/jvm/clojure/runtime/RT.java @@ -10,7 +10,7 @@ /* rich Mar 25, 2006 4:28:27 PM */ -package org.clojure.runtime; +package clojure.runtime; import java.util.Iterator; import java.io.Reader; @@ -49,18 +49,18 @@ public class RT{ return null; } - static public Object equal(Object arg1, Object arg2) { - if(arg1 == null) - return arg2 == null ? Boolean.TRUE : null; - else if(arg2 == null) - return null; - return (eql(arg1,arg2) != null - || (arg1.getClass() == Cons.class - && arg2.getClass() == Cons.class - && equal(((Cons)arg1).first,((Cons)arg2).first)!=null - && equal(((Cons)arg1).rest,((Cons)arg2).rest)!=null)) - ?Boolean.TRUE:null; - } +// static public Object equal(Object arg1, Object arg2) { +// if(arg1 == null) +// return arg2 == null ? Boolean.TRUE : null; +// else if(arg2 == null) +// return null; +// return (eql(arg1,arg2) != null +// || (arg1.getClass() == Cons.class +// && arg2.getClass() == Cons.class +// && equal(((Cons)arg1)._first,((Cons)arg2)._first)!=null +// && equal(((Cons)arg1)._rest,((Cons)arg2)._rest)!=null)) +// ?Boolean.TRUE:null; +// } static public Iter iter(Object coll) { @@ -174,7 +174,7 @@ static public double doubleCast(Object x) /******************************************* list support ********************************/ -static public Cons cons(Object x, Cons y) +static public Cons cons(Object x, ISeq y) { return new Cons(x, y); } @@ -209,27 +209,27 @@ static public Cons list(Object arg1, Object arg2, Object arg3, Object arg4, Obje return listStar(arg1, arg2, arg3, arg4, arg5, null); } -static public Cons listStar(Object arg1, Cons rest) +static public Cons listStar(Object arg1, ISeq rest) { return cons(arg1, rest); } -static public Cons listStar(Object arg1, Object arg2, Cons rest) +static public Cons listStar(Object arg1, Object arg2, ISeq rest) { return cons(arg1, cons(arg2, rest)); } -static public Cons listStar(Object arg1, Object arg2, Object arg3, Cons rest) +static public Cons listStar(Object arg1, Object arg2, Object arg3, ISeq rest) { return cons(arg1, cons(arg2, cons(arg3, rest))); } -static public Cons listStar(Object arg1, Object arg2, Object arg3, Object arg4, Cons rest) +static public Cons listStar(Object arg1, Object arg2, Object arg3, Object arg4, ISeq rest) { return cons(arg1, cons(arg2, cons(arg3, cons(arg4, rest)))); } -static public Cons listStar(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Cons rest) +static public Cons listStar(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq rest) { return cons(arg1, cons(arg2, cons(arg3, cons(arg4, cons(arg5, rest))))); } @@ -241,25 +241,23 @@ static public Cons arrayToList(Object[] a){ return ret; } -static public int length(Cons list) +static public int length(ISeq list) throws Exception { +int i = 0; +for(ISeq c = list; c != null; c = c.rest()) { - int i = 0; - for(Cons c = list; c != null; c = c.rest) - { - i++; - } - return i; + i++; } +return i; +} -static public int boundedLength(Cons list, int limit) +static public int boundedLength(ISeq list, int limit) throws Exception { +int i = 0; +for(ISeq c = list; c != null && i <= limit; c = c.rest()) { - int i = 0; - for(Cons c = list; c != null && i <= limit; c = c.rest) - { - i++; - } - return i; + i++; } +return i; +} ///////////////////////////////// reader support //////////////////////////////// @@ -310,80 +308,12 @@ static public boolean isLineNumberingReader(Reader r) { ///////////////////////////////// values ////////////////////////// -static public Object setValues(ThreadLocalData tld, Object arg1) - { - if(tld == null) - tld = ThreadLocalData.get(); - tld.mvCount = 1; - tld.mvArray[0] = arg1; - return arg1; - } - -static public Object setValues(ThreadLocalData tld, Object arg1, Object arg2) - { - if(tld == null) - tld = ThreadLocalData.get(); - tld.mvCount = 2; - tld.mvArray[0] = arg1; - tld.mvArray[1] = arg2; - return arg1; - } - -static public Object setValues(ThreadLocalData tld, Object arg1, Object arg2, Object arg3) - { - if(tld == null) - tld = ThreadLocalData.get(); - tld.mvCount = 3; - tld.mvArray[0] = arg1; - tld.mvArray[1] = arg2; - tld.mvArray[2] = arg3; - return arg1; - } - -static public Object setValues(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4) - { - if(tld == null) - tld = ThreadLocalData.get(); - tld.mvCount = 4; - tld.mvArray[0] = arg1; - tld.mvArray[1] = arg2; - tld.mvArray[2] = arg3; - tld.mvArray[3] = arg4; - return arg1; - } - -static public Object setValues(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, - Object arg5) +static public Object setValues(Object... vals) { - if(tld == null) - tld = ThreadLocalData.get(); - tld.mvCount = 5; - tld.mvArray[0] = arg1; - tld.mvArray[1] = arg2; - tld.mvArray[2] = arg3; - tld.mvArray[3] = arg4; - tld.mvArray[4] = arg5; - return arg1; - } - -static public Object setValues(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, - Object arg5, Cons args) throws Exception - { - if(tld == null) - tld = ThreadLocalData.get(); - tld.mvCount = 5; - tld.mvArray[0] = arg1; - tld.mvArray[1] = arg2; - tld.mvArray[2] = arg3; - tld.mvArray[3] = arg4; - tld.mvArray[4] = arg5; - for(int i = 5; args != null && i < ThreadLocalData.MULTIPLE_VALUES_LIMIT; i++, args = args.rest) - { - tld.mvArray[i] = args.first; - } - if(args != null) - throw new IllegalArgumentException("Too many arguments to values (> ThreadLocalData.MULTIPLE_VALUES_LIMIT)"); - return arg1; + ThreadLocalData.setValues(vals); + if(vals.length > 0) + return vals[0]; + return null; } } diff --git a/src/jvm/clojure/runtime/RatioNum.java b/src/jvm/clojure/runtime/RatioNum.java index e0efe5d1..8f39d1e0 100644 --- a/src/jvm/clojure/runtime/RatioNum.java +++ b/src/jvm/clojure/runtime/RatioNum.java @@ -10,7 +10,7 @@ /* rich Mar 28, 2006 10:14:44 AM */ -package org.clojure.runtime; +package clojure.runtime; import java.math.BigInteger; @@ -172,28 +172,28 @@ public Num divide(RatioNum n) } -public Object truncateDivide(ThreadLocalData tld, Num num) +public Object truncateDivide( Num num) { - return num.truncateBy(tld, this); + return num.truncateBy( this); } -public Object truncateBy(ThreadLocalData tld, int div) +public Object truncateBy( int div) { - Num q = (Num) Num.truncate(tld, numerator, denominator.multiply(div)); - return RT.setValues(tld, q, q.multiply(div).subtractFrom(this)); + Num q = (Num) Num.truncate( numerator, denominator.multiply(div)); + return RT.setValues( q, q.multiply(div).subtractFrom(this)); } -public Object truncateBy(ThreadLocalData tld, BigInteger div) +public Object truncateBy( BigInteger div) { - Num q = (Num) Num.truncate(tld, numerator, denominator.multiply(div)); - return RT.setValues(tld, q, q.multiply(div).subtractFrom(this)); + Num q = (Num) Num.truncate( numerator, denominator.multiply(div)); + return RT.setValues( q, q.multiply(div).subtractFrom(this)); } -public Object truncateBy(ThreadLocalData tld, RatioNum div) +public Object truncateBy( RatioNum div) { - Num q = (Num) Num.truncate(tld, numerator.multiplyBy(div.denominator), + Num q = (Num) Num.truncate( numerator.multiplyBy(div.denominator), denominator.multiplyBy(div.numerator)); - return RT.setValues(tld, q, q.multiplyBy(div).subtractFrom(this)); + return RT.setValues( q, q.multiplyBy(div).subtractFrom(this)); } diff --git a/src/jvm/clojure/runtime/RationalNum.java b/src/jvm/clojure/runtime/RationalNum.java index 81cd16b5..814122d5 100644 --- a/src/jvm/clojure/runtime/RationalNum.java +++ b/src/jvm/clojure/runtime/RationalNum.java @@ -10,7 +10,7 @@ /* rich Mar 28, 2006 10:12:30 AM */ -package org.clojure.runtime; +package clojure.runtime; public abstract class RationalNum extends RealNum { diff --git a/src/jvm/clojure/runtime/RealNum.java b/src/jvm/clojure/runtime/RealNum.java index 387f0a23..4f069e79 100644 --- a/src/jvm/clojure/runtime/RealNum.java +++ b/src/jvm/clojure/runtime/RealNum.java @@ -10,7 +10,7 @@ /* rich Mar 28, 2006 10:13:00 AM */ -package org.clojure.runtime; +package clojure.runtime; public abstract class RealNum extends Num { diff --git a/src/jvm/clojure/runtime/Reflector.java b/src/jvm/clojure/runtime/Reflector.java index c81a6341..fd0526cf 100644 --- a/src/jvm/clojure/runtime/Reflector.java +++ b/src/jvm/clojure/runtime/Reflector.java @@ -10,7 +10,7 @@ /* rich Apr 19, 2006 */ -package org.clojure.runtime; +package clojure.runtime; import java.lang.reflect.*; import java.util.ArrayList; @@ -167,7 +167,7 @@ public static Object invokeInstanceMember(String name, Object target, Object arg public static Object invokeInstanceMember(String name, Object target, Object arg1, Object arg2, Object arg3, Object arg4, - Cons arglist) + ISeq arglist) throws Exception { Object[] args = new Object[4 + RT.length(arglist)]; @@ -175,8 +175,8 @@ public static Object invokeInstanceMember(String name, Object target, Object arg args[1] = arg2; args[2] = arg3; args[3] = arg4; - for(int i = 4; arglist != null; i++, arglist = arglist.rest) - args[i] = arglist.first; + for(int i = 4; arglist != null; i++, arglist = arglist.rest()) + args[i] = arglist.first(); return invokeInstanceMethod(name, target, args); } diff --git a/src/jvm/clojure/runtime/RestFn0.java b/src/jvm/clojure/runtime/RestFn0.java index b6886c8b..bfc23ad5 100644 --- a/src/jvm/clojure/runtime/RestFn0.java +++ b/src/jvm/clojure/runtime/RestFn0.java @@ -10,51 +10,51 @@ /* rich Mar 27, 2006 7:34:25 PM */ -package org.clojure.runtime; +package clojure.runtime; public abstract class RestFn0 extends AFn{ -protected abstract Object doInvoke(ThreadLocalData tld, Cons rest) throws Exception; +protected abstract Object doInvoke( ISeq rest) throws Exception; -public Object applyTo(ThreadLocalData tld, Cons arglist) throws Exception +public Object applyTo( ISeq arglist) throws Exception { - return doInvoke(tld, arglist); + return doInvoke( arglist); } -public Object invoke(ThreadLocalData tld) throws Exception +public Object invoke() throws Exception { - return doInvoke(tld, null); + return doInvoke( null); } -public Object invoke(ThreadLocalData tld, Object arg1) throws Exception +public Object invoke( Object arg1) throws Exception { - return doInvoke(tld, RT.list(arg1)); + return doInvoke( RT.list(arg1)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2) throws Exception +public Object invoke( Object arg1, Object arg2) throws Exception { - return doInvoke(tld, RT.list(arg1, arg2)); + return doInvoke( RT.list(arg1, arg2)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3) throws Exception { - return doInvoke(tld, RT.list(arg1, arg2, arg3)); + return doInvoke( RT.list(arg1, arg2, arg3)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4) throws Exception { - return doInvoke(tld, RT.list(arg1, arg2, arg3, arg4)); + return doInvoke( RT.list(arg1, arg2, arg3, arg4)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception { - return doInvoke(tld, RT.list(arg1, arg2, arg3, arg4, arg5)); + return doInvoke( RT.list(arg1, arg2, arg3, arg4, arg5)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Cons args) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq args) throws Exception { - return doInvoke(tld, RT.listStar(arg1, arg2, arg3, arg4, arg5, args)); + return doInvoke( RT.listStar(arg1, arg2, arg3, arg4, arg5, args)); } } diff --git a/src/jvm/clojure/runtime/RestFn1.java b/src/jvm/clojure/runtime/RestFn1.java index f763b0c4..b401f763 100644 --- a/src/jvm/clojure/runtime/RestFn1.java +++ b/src/jvm/clojure/runtime/RestFn1.java @@ -10,56 +10,56 @@ /* rich Mar 27, 2006 8:00:28 PM */ -package org.clojure.runtime; +package clojure.runtime; public abstract class RestFn1 extends AFn{ -protected abstract Object doInvoke(ThreadLocalData tld, Object arg1, Cons rest) throws Exception; +protected abstract Object doInvoke( Object arg1, ISeq rest) throws Exception; -public Object applyTo(ThreadLocalData tld, Cons arglist) throws Exception +public Object applyTo( ISeq arglist) throws Exception { switch(RT.boundedLength(arglist, 1)) { case 0: - return invoke(tld); + return invoke(); case 1: - return invoke(tld,arglist.first); + return invoke(arglist.first()); default: - return doInvoke(tld, arglist.first - , arglist.rest); + return doInvoke( arglist.first() + , arglist.rest()); } } -public Object invoke(ThreadLocalData tld, Object arg1) throws Exception +public Object invoke( Object arg1) throws Exception { - return doInvoke(tld, arg1, null); + return doInvoke( arg1, null); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2) throws Exception +public Object invoke( Object arg1, Object arg2) throws Exception { - return doInvoke(tld, arg1, RT.list(arg2)); + return doInvoke( arg1, RT.list(arg2)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3) throws Exception { - return doInvoke(tld, arg1, RT.list(arg2, arg3)); + return doInvoke( arg1, RT.list(arg2, arg3)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4) throws Exception { - return doInvoke(tld, arg1, RT.list(arg2, arg3, arg4)); + return doInvoke( arg1, RT.list(arg2, arg3, arg4)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception { - return doInvoke(tld, arg1, RT.list(arg2, arg3, arg4, arg5)); + return doInvoke( arg1, RT.list(arg2, arg3, arg4, arg5)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Cons args) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq args) throws Exception { - return doInvoke(tld, arg1, RT.listStar(arg2, arg3, arg4, arg5, args)); + return doInvoke( arg1, RT.listStar(arg2, arg3, arg4, arg5, args)); } } diff --git a/src/jvm/clojure/runtime/RestFn2.java b/src/jvm/clojure/runtime/RestFn2.java index 8f12ade0..fb8ce4af 100644 --- a/src/jvm/clojure/runtime/RestFn2.java +++ b/src/jvm/clojure/runtime/RestFn2.java @@ -10,57 +10,57 @@ /* rich Mar 27, 2006 8:05:10 PM */ -package org.clojure.runtime; +package clojure.runtime; public abstract class RestFn2 extends AFn{ -protected abstract Object doInvoke(ThreadLocalData tld, Object arg1, Object arg2, Cons rest) throws Exception; +protected abstract Object doInvoke( Object arg1, Object arg2, ISeq rest) throws Exception; -public Object applyTo(ThreadLocalData tld, Cons arglist) throws Exception +public Object applyTo( ISeq arglist) throws Exception { switch(RT.boundedLength(arglist, 2)) { case 0: - return invoke(tld); + return invoke(); case 1: - return invoke(tld,arglist.first); + return invoke(arglist.first()); case 2: - return invoke(tld,arglist.first - , (arglist = arglist.rest).first + return invoke(arglist.first() + , (arglist = arglist.rest()).first() ); default: - return doInvoke(tld, arglist.first - , (arglist = arglist.rest).first - , arglist.rest); + return doInvoke( arglist.first() + , (arglist = arglist.rest()).first() + , arglist.rest()); } } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2) throws Exception +public Object invoke( Object arg1, Object arg2) throws Exception { - return doInvoke(tld, arg1, arg2, null); + return doInvoke( arg1, arg2, null); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3) throws Exception { - return doInvoke(tld, arg1, arg2, RT.list(arg3)); + return doInvoke( arg1, arg2, RT.list(arg3)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4) throws Exception { - return doInvoke(tld, arg1, arg2, RT.list(arg3, arg4)); + return doInvoke( arg1, arg2, RT.list(arg3, arg4)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception { - return doInvoke(tld, arg1, arg2, RT.list(arg3, arg4, arg5)); + return doInvoke( arg1, arg2, RT.list(arg3, arg4, arg5)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Cons args) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq args) throws Exception { - return doInvoke(tld, arg1, arg2, RT.listStar(arg3, arg4, arg5, args)); + return doInvoke( arg1, arg2, RT.listStar(arg3, arg4, arg5, args)); } } diff --git a/src/jvm/clojure/runtime/RestFn3.java b/src/jvm/clojure/runtime/RestFn3.java index 9efcbc3e..00aeeb5b 100644 --- a/src/jvm/clojure/runtime/RestFn3.java +++ b/src/jvm/clojure/runtime/RestFn3.java @@ -10,58 +10,58 @@ /* rich Mar 27, 2006 8:19:54 PM */ -package org.clojure.runtime; +package clojure.runtime; public abstract class RestFn3 extends AFn{ -protected abstract Object doInvoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Cons rest) throws Exception; +protected abstract Object doInvoke( Object arg1, Object arg2, Object arg3, ISeq rest) throws Exception; -public Object applyTo(ThreadLocalData tld, Cons arglist) throws Exception +public Object applyTo( ISeq arglist) throws Exception { switch(RT.boundedLength(arglist, 3)) { case 0: - return invoke(tld); + return invoke(); case 1: - return invoke(tld,arglist.first); + return invoke(arglist.first()); case 2: - return invoke(tld,arglist.first - , (arglist = arglist.rest).first + return invoke(arglist.first() + , (arglist = arglist.rest()).first() ); case 3: - return invoke(tld,arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first + return invoke(arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() ); default: - return doInvoke(tld, arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , arglist.rest); + return doInvoke( arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , arglist.rest()); } } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3) throws Exception { - return doInvoke(tld, arg1, arg2, arg3,null); + return doInvoke( arg1, arg2, arg3,null); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4) throws Exception { - return doInvoke(tld, arg1, arg2, arg3, RT.list(arg4)); + return doInvoke( arg1, arg2, arg3, RT.list(arg4)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception { - return doInvoke(tld, arg1, arg2, arg3, RT.list(arg4, arg5)); + return doInvoke( arg1, arg2, arg3, RT.list(arg4, arg5)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Cons args) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq args) throws Exception { - return doInvoke(tld, arg1, arg2, arg3, RT.listStar(arg4, arg5, args)); + return doInvoke( arg1, arg2, arg3, RT.listStar(arg4, arg5, args)); } } diff --git a/src/jvm/clojure/runtime/RestFn4.java b/src/jvm/clojure/runtime/RestFn4.java index 1114bce1..45044386 100644 --- a/src/jvm/clojure/runtime/RestFn4.java +++ b/src/jvm/clojure/runtime/RestFn4.java @@ -10,61 +10,61 @@ /* rich Mar 27, 2006 8:21:51 PM */ -package org.clojure.runtime; +package clojure.runtime; public abstract class RestFn4 extends AFn{ -protected abstract Object doInvoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Cons rest) +protected abstract Object doInvoke( Object arg1, Object arg2, Object arg3, Object arg4, ISeq rest) throws Exception; -public Object applyTo(ThreadLocalData tld, Cons arglist) throws Exception +public Object applyTo( ISeq arglist) throws Exception { switch(RT.boundedLength(arglist, 4)) { case 0: - return invoke(tld); + return invoke(); case 1: - return invoke(tld,arglist.first); + return invoke(arglist.first()); case 2: - return invoke(tld,arglist.first - , (arglist = arglist.rest).first + return invoke(arglist.first() + , (arglist = arglist.rest()).first() ); case 3: - return invoke(tld,arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first + return invoke(arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() ); case 4: - return invoke(tld,arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first + return invoke(arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() ); default: - return doInvoke(tld, arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , arglist.rest); + return doInvoke( arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , arglist.rest()); } } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4) throws Exception { - return doInvoke(tld, arg1, arg2, arg3, arg4, null); + return doInvoke( arg1, arg2, arg3, arg4, null); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception { - return doInvoke(tld, arg1, arg2, arg3, arg4, RT.list(arg5)); + return doInvoke( arg1, arg2, arg3, arg4, RT.list(arg5)); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Cons args) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq args) throws Exception { - return doInvoke(tld, arg1, arg2, arg3, arg4, RT.listStar(arg5, args)); + return doInvoke( arg1, arg2, arg3, arg4, RT.listStar(arg5, args)); } } diff --git a/src/jvm/clojure/runtime/RestFn5.java b/src/jvm/clojure/runtime/RestFn5.java index 7b8b414a..6271e0b2 100644 --- a/src/jvm/clojure/runtime/RestFn5.java +++ b/src/jvm/clojure/runtime/RestFn5.java @@ -10,64 +10,64 @@ /* rich Mar 27, 2006 8:24:31 PM */ -package org.clojure.runtime; +package clojure.runtime; public abstract class RestFn5 extends AFn{ -protected abstract Object doInvoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, - Cons rest) +protected abstract Object doInvoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, + ISeq rest) throws Exception; -public Object applyTo(ThreadLocalData tld, Cons arglist) throws Exception +public Object applyTo( ISeq arglist) throws Exception { switch(RT.boundedLength(arglist, 5)) { case 0: - return invoke(tld); + return invoke(); case 1: - return invoke(tld,arglist.first); + return invoke(arglist.first()); case 2: - return invoke(tld,arglist.first - , (arglist = arglist.rest).first + return invoke(arglist.first() + , (arglist = arglist.rest()).first() ); case 3: - return invoke(tld,arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first + return invoke(arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() ); case 4: - return invoke(tld,arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first + return invoke(arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() ); case 5: - return invoke(tld,arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first + return invoke(arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() ); default: - return doInvoke(tld, arglist.first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , (arglist = arglist.rest).first - , arglist.rest); + return doInvoke( arglist.first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , (arglist = arglist.rest()).first() + , arglist.rest()); } } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception { - return doInvoke(tld, arg1, arg2, arg3, arg4, arg5, null); + return doInvoke( arg1, arg2, arg3, arg4, arg5, null); } -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Cons args) +public Object invoke( Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq args) throws Exception { - return doInvoke(tld, arg1, arg2, arg3, arg4, arg5, args); + return doInvoke( arg1, arg2, arg3, arg4, arg5, args); } } diff --git a/src/jvm/clojure/runtime/Symbol.java b/src/jvm/clojure/runtime/Symbol.java index 269becfa..40e43587 100644 --- a/src/jvm/clojure/runtime/Symbol.java +++ b/src/jvm/clojure/runtime/Symbol.java @@ -10,7 +10,7 @@ /* rich Mar 25, 2006 11:42:47 AM */ -package org.clojure.runtime; +package clojure.runtime; import java.util.HashMap; import java.util.HashSet; diff --git a/src/jvm/clojure/runtime/TObj.java b/src/jvm/clojure/runtime/TObj.java index 8a0acb57..ece3a128 100644 --- a/src/jvm/clojure/runtime/TObj.java +++ b/src/jvm/clojure/runtime/TObj.java @@ -8,29 +8,30 @@ * You must not remove this notice, or any other, from this software.
**/
-package org.clojure.runtime;
+package clojure.runtime;
public class TObj implements IObj{
TRef attrs;
-public TObj(ThreadLocalData tld) throws Exception{
- this.attrs = Transaction.tref(tld,new RBTree());
+public TObj() throws Exception{
+ this.attrs = Transaction.tref(new PersistentTree());
}
-public Object put(ThreadLocalData tld, Comparable key, Object val) throws Exception {
- RBTree t = (RBTree) Transaction.get(tld, attrs);
+
+public Object put( Comparable key, Object val) throws Exception {
+ PersistentTree t = (PersistentTree) Transaction.get2( attrs);
t = t.put(key, val);
- Transaction.set(tld,attrs,t);
+ Transaction.set2(attrs,t);
return val;
}
-public Object get(ThreadLocalData tld, Comparable key) throws Exception {
- RBTree t = (RBTree) Transaction.get(tld, attrs);
+public Object get( Comparable key) throws Exception {
+ PersistentTree t = (PersistentTree) Transaction.get2( attrs);
return t.get(key);
}
-public boolean has(ThreadLocalData tld, Comparable key) throws Exception {
- RBTree t = (RBTree) Transaction.get(tld, attrs);
+public boolean has( Comparable key) throws Exception {
+ PersistentTree t = (PersistentTree) Transaction.get2( attrs);
return t.contains(key);
}
}
diff --git a/src/jvm/clojure/runtime/TRef.java b/src/jvm/clojure/runtime/TRef.java index a955cdf5..501674a6 100644 --- a/src/jvm/clojure/runtime/TRef.java +++ b/src/jvm/clojure/runtime/TRef.java @@ -10,7 +10,7 @@ /* rich May 30, 2006 */ -package org.clojure.runtime; +package clojure.runtime; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; diff --git a/src/jvm/clojure/runtime/TVal.java b/src/jvm/clojure/runtime/TVal.java index 1bc72a9b..8330839b 100644 --- a/src/jvm/clojure/runtime/TVal.java +++ b/src/jvm/clojure/runtime/TVal.java @@ -10,7 +10,7 @@ /* rich May 30, 2006 */ -package org.clojure.runtime; +package clojure.runtime; public class TVal{ volatile Object val; diff --git a/src/jvm/clojure/runtime/ThreadLocalData.java b/src/jvm/clojure/runtime/ThreadLocalData.java index 0bc9c665..85bda6ff 100644 --- a/src/jvm/clojure/runtime/ThreadLocalData.java +++ b/src/jvm/clojure/runtime/ThreadLocalData.java @@ -10,52 +10,28 @@ /* rich Mar 25, 2006 11:45:22 AM */ -package org.clojure.runtime; - -import java.util.IdentityHashMap; +package clojure.runtime; public class ThreadLocalData{ -final public static int MULTIPLE_VALUES_LIMIT = 20; -public int mvCount = 0; -public Object[] mvArray = new Object[MULTIPLE_VALUES_LIMIT]; +private static ThreadLocal<Transaction> transaction = new ThreadLocal<Transaction>(); +private static ThreadLocal<Object[]> values = new ThreadLocal<Object[]>(); + +static public Object[] getValues(){ + return values.get(); +} + +static public void setValues(Object[] vals) { + values.set(vals); +} -IdentityHashMap dynamicBindings = new IdentityHashMap(); -Transaction transaction; +static public Transaction getTransaction() { + return transaction.get(); -public Transaction getTransaction() throws Exception{ - if(transaction == null) - throw new Exception("No active transaction"); - return transaction; } -public ThreadLocalData(IdentityHashMap dynamicBindings) - { - this.mvCount = 0; - this.mvArray = new Object[MULTIPLE_VALUES_LIMIT]; - this.dynamicBindings = dynamicBindings; - } - -public ThreadLocalData() - { - this(new IdentityHashMap()); - } - -public static ThreadLocalData get() - { - return (ThreadLocalData) tld.get(); - } - -static InheritableThreadLocal tld = new InheritableThreadLocal(){ - protected Object childValue(Object object) - { - return new ThreadLocalData((IdentityHashMap) ((ThreadLocalData) object).dynamicBindings.clone()); - } - - protected Object initialValue() - { - return new ThreadLocalData(); - } -}; +static public void setTransaction(Transaction t){ + transaction.set(t); +} } diff --git a/src/jvm/clojure/runtime/Transaction.java b/src/jvm/clojure/runtime/Transaction.java index d6f4cab6..b0c65ca8 100644 --- a/src/jvm/clojure/runtime/Transaction.java +++ b/src/jvm/clojure/runtime/Transaction.java @@ -10,7 +10,7 @@ /* rich May 30, 2006 */ -package org.clojure.runtime; +package clojure.runtime; import java.util.*; @@ -44,46 +44,48 @@ Info info; int startSeq; IdentityHashMap<TRef,Object> sets; -IdentityHashMap<TRef,Cons> commutates; +IdentityHashMap<TRef,ISeq> commutates; -static public Object runInTransaction(ThreadLocalData tld,IFn fn) throws Exception{ - if(tld.transaction != null) - return fn.invoke(tld); - tld.transaction = new Transaction(); +static public Object runInTransaction(IFn fn) throws Exception{ + if(ThreadLocalData.getTransaction() != null) + return fn.invoke(); + Transaction t = new Transaction(); + ThreadLocalData.setTransaction(t); try{ - return tld.transaction.run(tld, fn); + return t.run(fn); } finally{ - tld.transaction = null; + ThreadLocalData.setTransaction(null); } } -static public TRef tref(ThreadLocalData tld, Object val) throws Exception{ - Transaction trans = tld.getTransaction(); +static public TRef tref(Object val) throws Exception{ + Transaction trans = ThreadLocalData.getTransaction(); TRef tref = new TRef(); trans.set(tref, val); return tref; } -static public Object get(ThreadLocalData tld, TRef tref) throws Exception{ - return tld.getTransaction().get(tref); +//* +static public Object get2(TRef tref) throws Exception{ + return ThreadLocalData.getTransaction().get(tref); } -static public Object set(ThreadLocalData tld, TRef tref, Object val) throws Exception{ - return tld.getTransaction().set(tref,val); +static public Object set2(TRef tref, Object val) throws Exception{ + return ThreadLocalData.getTransaction().set(tref,val); } -static public void touch(ThreadLocalData tld, TRef tref) throws Exception{ - tld.getTransaction().touch(tref); +static public void touch2(TRef tref) throws Exception{ + ThreadLocalData.getTransaction().touch(tref); } -static public void commutate(ThreadLocalData tld, TRef tref, IFn fn) throws Exception{ - tld.getTransaction().commutate(tref, fn); +static public void commutate2(TRef tref, IFn fn) throws Exception{ + ThreadLocalData.getTransaction().commutate(tref, fn); } +//*/ - -Object run(ThreadLocalData tld, IFn fn) throws Exception{ +Object run(IFn fn) throws Exception{ boolean done = false; Object ret = null; ArrayList<TRef> locks = null; @@ -93,7 +95,7 @@ Object run(ThreadLocalData tld, IFn fn) throws Exception{ while(!done){ try { - ret = fn.invoke(tld); + ret = fn.invoke(); if(locks == null && (sets != null || commutates != null)) locks = new ArrayList<TRef>(); if(sets != null) @@ -123,15 +125,15 @@ Object run(ThreadLocalData tld, IFn fn) throws Exception{ //at this point all write targets are locked //turn commutates into sets - for(Map.Entry<TRef, Cons> e : commutates.entrySet()) + for(Map.Entry<TRef, ISeq> e : commutates.entrySet()) { TRef tref = e.getKey(); //note this will npe if tref has never been set, as designed Object val = getCurrent(tref).val; - for(Cons c = e.getValue();c!=null;c = c.rest) + for(ISeq c = e.getValue();c!=null;c = c.rest()) { - IFn f = (IFn) c.first; - val = f.invoke(tld, val); + IFn f = (IFn) c.first(); + val = f.invoke(val); } sets.put(tref, val); } @@ -225,7 +227,7 @@ void touch(TRef tref) throws Exception{ void commutate(TRef tref, IFn fn) throws Exception{ if(commutates == null) - commutates = new IdentityHashMap<TRef,Cons>(); + commutates = new IdentityHashMap<TRef,ISeq>(); if(sets != null && sets.containsKey(tref)) throw new Exception("Can't commutate and set a TRef in the same transaction"); commutates.put(tref, RT.cons(fn, commutates.get(tref))); diff --git a/src/jvm/clojure/runtime/Var.java b/src/jvm/clojure/runtime/Var.java index 9e6fe46f..ab1f76b2 100644 --- a/src/jvm/clojure/runtime/Var.java +++ b/src/jvm/clojure/runtime/Var.java @@ -10,131 +10,133 @@ /* rich Apr 19, 2006 */ -package org.clojure.runtime; +package clojure.runtime; -public class Var extends AFn{ +import java.util.concurrent.atomic.AtomicReference; + +public class Var extends AFn { public final Symbol sym; public Namespace namespace; -public Box binding; +public Binding binding; public IFn fn; //todo, bind to throw stub? public IFn setfn; +AtomicReference<IPersistentMap> threadBindings = new AtomicReference(PersistentArrayIdentityMap.EMPTY); -Var(Symbol sym, Namespace ns) - { - if(!(sym.getClass() == Symbol.class)) +Var(Symbol sym, Namespace ns) { + if (!(sym.getClass() == Symbol.class)) throw new IllegalArgumentException("Only simple symbols can be vars"); this.namespace = ns; - this.sym = sym; - } - -public String toString() - { - if(namespace == null) - return "#:" + sym; - return namespace.name + ":" + sym; - } - -public Var bind(Object val) - { - if(binding == null) - binding = new Box(val); - else - binding.val = val; - - if(val instanceof IFn) - this.fn = (IFn) val; - else - this.fn = null; //todo, bind to throw stub? - + this.sym = sym; +} + +public String toString() { + if (namespace == null) + return "#:" + sym; + return namespace.name + ":" + sym; +} + +public Var bind(Object val) { + if (binding == null) + binding = new Binding(val); + else + binding.val = val; + + if (val instanceof IFn) + this.fn = (IFn) val; + else + this.fn = null; //todo, bind to throw stub? + return this; - } - -public Box getBinding(ThreadLocalData tld) - { - Box b = getDynamicBinding(tld); - if(b != null) - return b; - return binding; - } - -public Object getValue(ThreadLocalData tld) - { - Box binding = getBinding(tld); - if(binding != null) - return binding.val; - throw new IllegalStateException(this.toString() + " is unbound."); - } - -public Object setValue(ThreadLocalData tld, Object val) - { - Box b = getDynamicBinding(tld); - if(b != null) - return b.val = val; - //allow global set to create binding like this? - if(binding == null) - throw new IllegalStateException(this.toString() + " is unbound."); - - if(val instanceof IFn) - this.fn = (IFn) val; - else - this.fn = null; //todo, bind to throw stub? - - return binding.val = val; - } - -final public Box getDynamicBinding(ThreadLocalData tld) - { - return (Box) tld.dynamicBindings.get(this); - } - -final public Box establishDynamicBinding(ThreadLocalData tld, Object val) - { - Box ret = getDynamicBinding(tld); - tld.dynamicBindings.put(this, new Box(val)); - return ret; - } - -final public void restoreDynamicBinding(ThreadLocalData tld, Box old) - { - tld.dynamicBindings.put(this, old); - } - -public Object invoke(ThreadLocalData tld) throws Exception - { - return fn.invoke(tld); - } - -public Object invoke(ThreadLocalData tld, Object arg1) throws Exception - { - return fn.invoke(tld,arg1); - } - -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2) throws Exception - { - return fn.invoke(tld,arg1,arg2); - } - -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3) throws Exception - { - return fn.invoke(tld,arg1,arg2,arg3); - } - -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4) throws Exception - { - return fn.invoke(tld,arg1,arg2,arg3,arg4); - } - -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) - throws Exception - { - return fn.invoke(tld,arg1,arg2,arg3,arg4,arg5); - } - -public Object invoke(ThreadLocalData tld, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Cons args) - throws Exception - { - return fn.invoke(tld,arg1,arg2,arg3,arg4,arg5,args); - } +} + +public Object getValue() { + Binding binding = getBinding(); + if (binding != null) + return binding.val; + throw new IllegalStateException(this.toString() + " is unbound."); +} + +public Object setValue(Object val) { + Binding b = getThreadBinding(); + if (b != null) + return b.val = val; + if (binding == null) + throw new IllegalStateException(this.toString() + " is unbound."); + + if (val instanceof IFn) + this.fn = (IFn) val; + else + this.fn = null; //todo, bind to throw stub? + + return binding.val = val; +} + +public Binding pushThreadBinding(Object val) { + Binding ret = new Binding(val, getThreadBinding()); + setThreadBinding(ret); + return ret; +} + +public void popThreadBinding() { + setThreadBinding(getThreadBinding().rest); +} + +private Binding getThreadBinding() { + if (threadBindings.get().count() > 0) + return (Binding) threadBindings.get().get(Thread.currentThread()); + return null; +} + +private Binding getBinding() { + Binding b = getThreadBinding(); + if (b != null) + return b; + return binding; +} + +private void setThreadBinding(Binding b) { + Thread thread = Thread.currentThread(); + IPersistentMap tb; + IPersistentMap newtb; + do + { + tb = threadBindings.get(); + if (b == null) + newtb = tb.remove(thread); + else + newtb = tb.put(thread, b); + } while (!threadBindings.compareAndSet(tb, newtb)); +} + +public Object invoke() throws Exception { + return fn.invoke(); +} + +public Object invoke(Object arg1) throws Exception { + return fn.invoke(arg1); +} + +public Object invoke(Object arg1, Object arg2) throws Exception { + return fn.invoke(arg1, arg2); +} + +public Object invoke(Object arg1, Object arg2, Object arg3) throws Exception { + return fn.invoke(arg1, arg2, arg3); +} + +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4) throws Exception { + return fn.invoke(arg1, arg2, arg3, arg4); +} + +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) + throws Exception { + return fn.invoke(arg1, arg2, arg3, arg4, arg5); +} + +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq args) + throws Exception { + return fn.invoke(arg1, arg2, arg3, arg4, arg5, args); +} } |