Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: clojure/clojure
...
head fork: clojure/clojure
Checking mergeability… Don't worry, you can still create the pull request.
  • 18 commits
  • 15 files changed
  • 0 commit comments
  • 6 contributors
Commits on Jul 14, 2010
@stuarthalloway stuarthalloway prepare for 1.2.0 beta1 9c01e1f
Commits on Jul 16, 2010
@richhickey richhickey switch to soft refs in DynamicClassLoader 27df859
@richhickey richhickey factor out cache clearing to Util helper 758672e
@richhickey richhickey use soft refs for keyword intern table ed89fd1
Commits on Jul 19, 2010
@stuarthalloway stuarthalloway minor errata in changes.txt 43c7e04
Commits on Jul 27, 2010
@stuarthalloway stuarthalloway Merge commit '43c7e04' into 1.2.x f27cb08
Fogus Fixes missing this arg on the reify and defprotocol docstrings #340
Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
bbc859d
@djpowell djpowell read stdout and stderr in parallel (using futures)
Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
f314991
@stuarthalloway stuarthalloway fix degenerate defrecords, #402
Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
9929b83
@djpowell djpowell fixed extend-protocol doc
Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
973ea84
@bpsm bpsm ♯413 parse-args defaults in-enc and out-enc to UTF-8, as required by sh
Previously parse-args was defaulting in-enc and out-enc to the
platform default charset. This contradicted the intent of sh, which is
to default to UTF-8 on all platforms.

This appears not to have been noticed because the unit tests were
still testing for the previous behavior of defaulting to platform
encoding.

(As it turns out the old behavior of using Charset/defaultCharset
would have been wrong on Mac OS X since it claims "Mac Roman" here
despite the fact that Mac OS X uses UTF-8 throughout, including in
Terminal.app, shell and file system.)

Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
a2c95ef
Commits on Jul 30, 2010
@stuarthalloway stuarthalloway #407 use munge as cheap validity test for Java method names
Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
60d5927
@stuarthalloway stuarthalloway prep for 1.2 RC1 6dec446
Commits on Aug 04, 2010
@richhickey richhickey fix record equality with other maps, = includes type, .equals doesn't…
…. see #418
f01cef9
Commits on Aug 05, 2010
@stuarthalloway stuarthalloway deployment hack 626f0cf
@fogus fogus Tweaked changes document a bit for case and vector-of
Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
942784c
@stuarthalloway stuarthalloway narrowing changes.txt for primitive monitors e930c04
Commits on Aug 06, 2010
@stuarthalloway stuarthalloway preparing for 1.2RC2 0f47e7c
View
22 build.xml
@@ -222,6 +222,28 @@
</sequential>
</macrodef>
+ <macrodef name="remote-deploy">
+ <sequential>
+ <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant"/>
+ <mvn:deploy file="${clojure_jar}">
+ <pom file="pom.xml"/>
+ <attach file="${src_jar}" classifier="sources"/>
+ <attach file="${slim_jar}" classifier="slim"/>
+ <remoteRepository url="scp://build.clojure.org/srv/www/releases">
+ <authentication username="root" privateKey="${user.home}/.ssh/id_rsa"/>
+ </remoteRepository>
+ </mvn:deploy>
+ </sequential>
+ </macrodef>
+
+ <target name="remote-stable-build" depends="ci-build" description="Build and deploy to remote stable repository.">
+ <sequential>
+ <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant"/>
+ <mvn:install-provider artifactId="wagon-ssh" version="1.0-beta-2"/>
+ <remote-deploy/>
+ </sequential>
+ </target>
+
<target name="ci-build" depends="clean,all,-setup-maven"
description="Continous integration build, installed to local repository.">
<mvn:install file="${clojure_jar}">
View
297 changes.txt
@@ -0,0 +1,297 @@
+Changes to Clojure in Version 1.2
+
+= CONTENTS =
+
+ 0 Changes from beta -> RC1 -> RC2
+ 0.1 Changes from RC1 to RC2
+ 0.2 Changes from beta1 to RC1
+ 1 Deprecated and Removed Features
+ 1.1 metadata reader macro is now ^
+ 2 New/Improved Features in clojure.core
+ 2.1 Protocols, Records, and Types
+ 2.2 Sequence Library
+ 2.3 Destructuring
+ 2.4 Case
+ 2.5 Duplicate Key Prevention
+ 2.6 Primitive Vectors
+ 2.7 Agent Error Handling
+ 2.8 Improved Ratio Support
+ 2.9 Macro Implicit Args
+ 2.10 Multimethod Enhancements
+ 2.11 Function Metadata (Alpha)
+ 2.12 Java Annotations
+ 2.13 Namespace Collision Warnings
+ 3 New Namespaces
+ 3.1 clojure.java.io
+ 3.1 clojure.java.javadoc
+ 3.3 clojure.java.shell
+ 3.4 clojure.pprint
+ 3.5 clojure.repl
+ 3.6 clojure.string
+ 4 Functions with Improved Performance
+ 5 Bug Fixes
+
+= 0 Changes from beta1 -> RC1 -> RC2
+
+= 0.1 Changes from RC1 to RC2
+
+Record/map equality is now symmetric in all cases. There are two
+variants:
+
+ * In most cases, you should use =. Calls to = include type
+ information, so instances of different record types can never be =
+ to each other, or to plain maps.
+
+ * Calls to .equals are different. They respect the Java semantics
+ for maps, which is a requirement for correct interop. Type
+ information is *not* included, so any kind of map can be .equals
+ to any other.
+
+Possible impacts for your programs:
+
+ * If you create a custom implementation of Clojure's IPersistentMap,
+ you probably want it to be able to be = to other maps. If so, all
+ you need to do is implement the marker interface
+ clojure.lang.MapEquivalence. Note that APersistentMap does this
+ for you.
+
+= 0.2 Changes from beta1 to RC1 =
+
+ * switch to soft refs for class and keyword cache
+ * update reify, defprotocol, extend-protocol docstrings (#340)
+ * fix fieldless defrecord corner case (#402)
+ * sh reads stdout and stderr in parallel
+ * sh stdin, stdout default to UTF-8 (#413)
+ * gen-class checks validity of method names (#407)
+
+= 1 Deprecated and Removed Features =
+
+== 1.1 metadata reader macro is now ^ ==
+
+^ is the metadata reader macro. The former syntax #^ is deprecated and
+will be removed in a future version of Clojure.
+
+
+= 2 New Features in clojure.core =
+
+== 2.1 Protocols, Records, Reify, and Types ==
+
+defprotocol provides polymorphism without type intrusion.
+
+defrecord, reify, and deftype provide datatypes. They support, in a
+relatively clean manner, access to the highest-performance primitive
+representation and polymorphism mechanisms of the host.
+
+See http://clojure.org/protocols and http://clojure.org/datatypes for
+a more complete description.
+
+
+== 2.2 Sequence Library ==
+
+The sequence library has several new functions in Clojure 1.2. The
+notes in parentheses indicate differences from the similarly-named
+functions in clojure-contrib.
+
+ * flatten - New
+ * frequencies - New
+ * group-by - New (note: unsorted)
+ * keep - New
+ * keep-indexed - New (preferred over contrib's indexed for perf)
+ * map-indexed - New (preferred over contrib's indexed for perf)
+ * partition-all - New
+ * partition-by - New
+ * rand-nth - New (name indicates dependency on nth's perf)
+ * range - Improved (added zero arity)
+ * reductions - New
+ * repeatedly - Improved! (added "do n times" semantics)
+ * shuffle - New
+
+
+== 2.3 Destructuring Enhanced ==
+
+If you associatively destructure a seq, it will be poured into a map first:
+
+ (defn foo [& {:keys [a b c]}]
+ [a b c])
+
+ (foo :c 3 :b 2)
+ => [nil 2 3]
+
+
+== 2.4 Case ==
+
+Case provides constant time dispatch on its clauses, which can be any
+compile-time literal
+
+ (defn release-status
+ [version]
+ (case version
+ (0.9 1.0 1.1) "History"
+ 1.2 "Right now"
+ :sentient "RSN"
+ "The default"))
+
+The string "The default" represents the default clause and can be any
+expression, not only a compile-time literal.
+
+
+== 2.5 Duplicate Key Prevention ==
+
+Associative literals and their constructor functions hash-map and
+hash-set now prevent duplicate keys:
+
+ #{1 1}
+ => java.lang.IllegalArgumentException: Duplicate key: 1
+
+
+== 2.6 Primitive Vectors ==
+
+vector-of creates a vector of unboxed Java primitives, which follows
+the contract of Clojure vectors. It takes one keyword argument
+corresponding to its primitive type that can be any of :int, :long,
+:float, :double, :byte, :short, :boolean, or :char.
+
+
+== 2.7 Agent Error Handling ==
+
+Agent error handling has been reworked in Clojure 1.2.
+
+ * agent-error - New
+ * restart-agent - New
+ * set-error-handler - New
+ * error-handler - New
+ * set-error-mode! - New
+ * error-mode - New
+ * await - improved docstring, explains failed agent semantics
+ * agent-errors - DEPRECATED
+ * clear-agent-errors - DEPRECATED
+
+
+== 2.8 Improved Ratio Support ==
+
+ * numerator - New
+ * denominator - New
+ * bigint - Enhanced, now ratio aware
+
+
+== 2.9 Macro Implicit Args ==
+
+Macros now have access to implicit arguments:
+
+ * &form - the macro form
+ * &env - the local bindings
+
+
+== 2.10 Multimethod Enhancements ==
+
+Multimethods have been enhanced to improve interactive development:
+
+ * remove-all-methods - New
+ * defmulti - Enhanced to have defonce semantics
+
+
+== 2.11 Function Metadata ==
+
+Clojure functions can now have metadata. Please treat this capability
+as alpha and subject to possible change or removal in a future version
+of Clojure.
+
+
+== 2.12 Java Annotations ==
+
+Java Annotations can be added simply by making a Java annotation
+class a key in a Clojure metadata map:
+
+ ;; Name is deprecated
+ (defrecord ^{Deprecated true} Name [first last])
+
+Please use Java annotations for interop purposes only.
+
+== 2.13 Namespace Collision Warnings ==
+
+If a namespace defines a Var whose name collides with a name in the
+clojure.core namespace, you will see a warning but the definition will
+be allowed to proceed. This facilitates promoting useful functions
+into clojure.core without causing a breaking change.
+
+Please track down and fix these warnings, as matching names do not
+always imply matching semantics!
+
+
+= 3 New Namespaces =
+
+Complete documentation for all namespaces is in the source and API
+docs: http://clojure.github.com/clojure/
+
+
+== 3.1 clojure.java.io ==
+
+Java I/O libraries distilled from the duck-streams and io namespaces
+in clojure-contrib.
+
+
+== 3.2 clojure.java.javadoc ==
+
+Launch a Javadoc browser from the REPL, promoted from the javadoc and
+repl-util namespace in clojure-contrib.
+
+
+== 3.3 clojure.java.shell ==
+
+Utilities for launching a subprocess, promoted from shell-out
+namespace in clojure-contrib.
+
+
+== 3.4 clojure.pprint ==
+
+Pretty-printer for Clojure, promoted from pprint in clojure-contrib.
+
+
+== 3.5 clojure.repl ==
+
+Utilities for a more pleasant REPL experience, promoted from the
+repl-utils and ns-utils namespaces in clojure-contrib.
+
+
+== 3.6 clojure.string ==
+
+String utilities promoted from the str-utils, str-utils2, str-utils3,
+and string namespaces in clojure-contrib.
+
+
+= 4 Performance Enhancements =
+
+Many functions have improved performance in Clojure 1.2:
+
+ aget
+ array-map
+ aset
+ bit-shift-left
+ bit-shift-right
+ boolean
+ byte
+ count
+ double
+ false?
+ float
+ future-call
+ get
+ into
+ keyword
+ line-seq
+ long
+ nil?
+ nth
+ promise
+ re-seq
+ reduce
+ resultset-seq
+ set
+ short
+ true?
+ vector
+
+= 5 Bug Fixes =
+
+Please see the complete list at
+https://www.assembla.com/spaces/ticket_reports/show/13167?space_id=clojure.
View
78 src/clj/clojure/core_deftype.clj
@@ -70,11 +70,11 @@
or more method bodies:
protocol-or-interface-or-Object
- (methodName [args*] body)*
+ (methodName [args+] body)*
Methods should be supplied for all methods of the desired
protocol(s) and interface(s). You can also define overrides for
- methods of Object. Note that a parameter must be supplied to
+ methods of Object. Note that the first parameter must be supplied to
correspond to the target object ('this' in Java parlance). Thus
methods for interfaces will take one more argument than do the
interface declarations. Note also that recur calls to the method
@@ -97,12 +97,12 @@
(str (let [f \"foo\"]
(reify Object
- (toString [] f))))
+ (toString [this] f))))
== \"foo\"
(seq (let [f \"foo\"]
(reify clojure.lang.Seqable
- (seq [] (seq f)))))
+ (seq [this] (seq f)))))
== (\\f \\o \\o))"
{:added "1.2"}
[& opts+specs]
@@ -151,14 +151,8 @@
[(eqhash [[i m]]
[i
(conj m
- `(hashCode [this#] (-> ~tag hash ~@(map #(list `hash-combine %) (remove #{'__meta} fields))))
- `(equals [this# ~gs]
- (boolean
- (or (identical? this# ~gs)
- (when (identical? (class this#) (class ~gs))
- (let [~gs ~(with-meta gs {:tag tagname})]
- (and ~@(map (fn [fld] `(= ~fld (. ~gs ~fld))) base-fields)
- (= ~'__extmap (. ~gs ~'__extmap)))))))))])
+ `(hashCode [this#] (clojure.lang.APersistentMap/mapHash this#))
+ `(equals [this# ~gs] (clojure.lang.APersistentMap/mapEquals this# ~gs)))])
(iobj [[i m]]
[(conj i 'clojure.lang.IObj)
(conj m `(meta [this#] ~'__meta)
@@ -190,13 +184,19 @@
`(count [this#] (+ ~(count base-fields) (count ~'__extmap)))
`(empty [this#] (throw (UnsupportedOperationException. (str "Can't create empty: " ~(str classname)))))
`(cons [this# e#] ((var imap-cons) this# e#))
- `(equiv [this# o#] (.equals this# o#))
+ `(equiv [this# ~gs]
+ (boolean
+ (or (identical? this# ~gs)
+ (when (identical? (class this#) (class ~gs))
+ (let [~gs ~(with-meta gs {:tag tagname})]
+ (and ~@(map (fn [fld] `(= ~fld (. ~gs ~fld))) base-fields)
+ (= ~'__extmap (. ~gs ~'__extmap))))))))
`(containsKey [this# k#] (not (identical? this# (.valAt this# k# this#))))
`(entryAt [this# k#] (let [v# (.valAt this# k# this#)]
(when-not (identical? this# v#)
(clojure.lang.MapEntry. k# v#))))
- `(seq [this#] (concat [~@(map #(list `new `clojure.lang.MapEntry (keyword %) %) base-fields)]
- ~'__extmap))
+ `(seq [this#] (seq (concat [~@(map #(list `new `clojure.lang.MapEntry (keyword %) %) base-fields)]
+ ~'__extmap)))
`(assoc [this# k# ~gs]
(condp identical? k#
~@(mapcat (fn [fld]
@@ -212,7 +212,7 @@
(conj m
`(size [this#] (.count this#))
`(isEmpty [this#] (= 0 (.count this#)))
- `(containsValue [this# v#] (-> this# vals (.contains v#)))
+ `(containsValue [this# v#] (boolean (some #{v#} (vals this#))))
`(get [this# k#] (.valAt this# k#))
`(put [this# k# v#] (throw (UnsupportedOperationException.)))
`(remove [this# k#] (throw (UnsupportedOperationException.)))
@@ -581,18 +581,18 @@
\"A doc string for AProtocol abstraction\"
;method signatures
- (bar [a b] \"bar docs\")
- (baz [a] [a b] [a b c] \"baz docs\"))
+ (bar [this a b] \"bar docs\")
+ (baz [this a] [this a b] [this a b c] \"baz docs\"))
No implementations are provided. Docs can be specified for the
protocol overall and for each method. The above yields a set of
polymorphic functions and a protocol object. All are
namespace-qualified by the ns enclosing the definition The resulting
- functions dispatch on the type of their first argument, and thus
- must have at least one argument. defprotocol is dynamic, has no
- special compile-time effect, and defines no new types or classes
- Implementations of the protocol methods can be provided using
- extend.
+ functions dispatch on the type of their first argument, which is
+ required and corresponds to the implicit target object ('this' in
+ Java parlance). defprotocol is dynamic, has no special compile-time
+ effect, and defines no new types or classes. Implementations of
+ the protocol methods can be provided using extend.
defprotocol will automatically generate a corresponding interface,
with the same name as the protocol, i.e. given a protocol:
@@ -604,23 +604,25 @@
reify, as they support the protocol directly:
(defprotocol P
- (foo [x])
- (bar-me [x] [x y]))
+ (foo [this])
+ (bar-me [this] [this y]))
(deftype Foo [a b c]
P
- (foo [] a)
- (bar-me [] b)
- (bar-me [y] (+ c y)))
+ (foo [this] a)
+ (bar-me [this] b)
+ (bar-me [this y] (+ c y)))
- (bar-me (Foo 1 2 3) 42)
+ (bar-me (Foo. 1 2 3) 42)
+ => 45
(foo
(let [x 42]
(reify P
- (foo [] 17)
- (bar-me [] x)
- (bar-me [y] x))))"
+ (foo [this] 17)
+ (bar-me [this] x)
+ (bar-me [this y] x))))
+ => 17"
{:added "1.2"}
[name & opts+sigs]
(emit-protocol name opts+sigs))
@@ -729,13 +731,13 @@
"Useful when you want to provide several implementations of the same
protocol all at once. Takes a single protocol and the implementation
of that protocol for one or more types. Expands into calls to
- extend-type and extend-class:
+ extend-type:
(extend-protocol Protocol
- ::AType
+ AType
(foo [x] ...)
(bar [x y] ...)
- ::BType
+ BType
(foo [x] ...)
(bar [x y] ...)
AClass
@@ -748,13 +750,13 @@
expands into:
(do
- (clojure.core/extend-type ::AType Protocol
+ (clojure.core/extend-type AType Protocol
(foo [x] ...)
(bar [x y] ...))
- (clojure.core/extend-type ::BType Protocol
+ (clojure.core/extend-type BType Protocol
(foo [x] ...)
(bar [x y] ...))
- (clojure.core/extend-class AClass Protocol
+ (clojure.core/extend-type AClass Protocol
(foo [x] ...)
(bar [x y] ...))
(clojure.core/extend-type nil Protocol
View
11 src/clj/clojure/genclass.clj
@@ -90,7 +90,18 @@
strx
(str "java.lang." strx))))))
+;; someday this can be made codepoint aware
+(defn- valid-java-method-name
+ [^String s]
+ (= s (clojure.lang.Compiler/munge s)))
+
+(defn- validate-generate-class-options
+ [{:keys [methods]}]
+ (let [[mname] (remove valid-java-method-name (map (comp str first) methods))]
+ (when mname (throw (IllegalArgumentException. (str "Not a valid method name: " mname))))))
+
(defn- generate-class [options-map]
+ (validate-generate-class-options options-map)
(let [default-options {:prefix "-" :load-impl-ns true :impl-ns (ns-name *ns*)}
{:keys [name extends implements constructors methods main factory state init exposes
exposes-methods prefix load-impl-ns impl-ns post-init]}
View
8 src/clj/clojure/java/shell.clj
@@ -44,7 +44,7 @@ collecting its stdout"}
(defn- parse-args
[args]
- (let [default-encoding (.name (Charset/defaultCharset))
+ (let [default-encoding "UTF-8" ;; see sh doc string
default-opts {:out-enc default-encoding :in-enc default-encoding :dir *sh-dir* :env *sh-env*}
[cmd opts] (split-with string? args)]
[cmd (merge default-opts (apply hash-map opts))]))
@@ -124,10 +124,10 @@ collecting its stdout"}
(.close (.getOutputStream proc)))
(with-open [stdout (.getInputStream proc)
stderr (.getErrorStream proc)]
- (let [out (stream-to-enc stdout out-enc)
- err (stream-to-string stderr)
+ (let [out (future (stream-to-enc stdout out-enc))
+ err (future (stream-to-string stderr))
exit-code (.waitFor proc)]
- {:exit exit-code :out out :err err}))))
+ {:exit exit-code :out @out :err @err}))))
(comment
View
4 src/clj/clojure/version.properties
@@ -1,5 +1,5 @@
clojure.version.major=1
clojure.version.minor=2
clojure.version.incremental=0
-clojure.version.qualifier=master
-clojure.version.interim=true
+clojure.version.qualifier=RC2
+clojure.version.interim=false
View
37 src/jvm/clojure/lang/APersistentMap.java
@@ -13,7 +13,7 @@
import java.io.Serializable;
import java.util.*;
-public abstract class APersistentMap extends AFn implements IPersistentMap, Map, Iterable, Serializable {
+public abstract class APersistentMap extends AFn implements IPersistentMap, Map, Iterable, Serializable, MapEquivalence {
int _hash = -1;
public String toString(){
@@ -45,15 +45,19 @@ else if(o instanceof IPersistentVector)
}
public boolean equals(Object obj){
- if(this == obj) return true;
+ return mapEquals(this, obj);
+}
+
+static public boolean mapEquals(IPersistentMap m1, Object obj){
+ if(m1 == obj) return true;
if(!(obj instanceof Map))
return false;
Map m = (Map) obj;
- if(m.size() != size() || m.hashCode() != hashCode())
+ if(m.size() != m1.count() || m.hashCode() != m1.hashCode())
return false;
- for(ISeq s = seq(); s != null; s = s.next())
+ for(ISeq s = m1.seq(); s != null; s = s.next())
{
Map.Entry e = (Map.Entry) s.first();
boolean found = m.containsKey(e.getKey());
@@ -68,6 +72,9 @@ public boolean equals(Object obj){
public boolean equiv(Object obj){
if(!(obj instanceof Map))
return false;
+ if(obj instanceof IPersistentMap && !(obj instanceof MapEquivalence))
+ return false;
+
Map m = (Map) obj;
if(m.size() != size())
@@ -87,20 +94,22 @@ public boolean equiv(Object obj){
public int hashCode(){
if(_hash == -1)
{
- //int hash = count();
- int hash = 0;
- for(ISeq s = seq(); s != null; s = s.next())
- {
- Map.Entry e = (Map.Entry) s.first();
- hash += (e.getKey() == null ? 0 : e.getKey().hashCode()) ^
- (e.getValue() == null ? 0 : e.getValue().hashCode());
- //hash ^= Util.hashCombine(Util.hash(e.getKey()), Util.hash(e.getValue()));
- }
- this._hash = hash;
+ this._hash = mapHash(this);
}
return _hash;
}
+static public int mapHash(IPersistentMap m){
+ int hash = 0;
+ for(ISeq s = m.seq(); s != null; s = s.next())
+ {
+ Map.Entry e = (Map.Entry) s.first();
+ hash += (e.getKey() == null ? 0 : e.getKey().hashCode()) ^
+ (e.getValue() == null ? 0 : e.getValue().hashCode());
+ }
+ return hash;
+}
+
static public class KeySeq extends ASeq{
ISeq seq;
View
23 src/jvm/clojure/lang/DynamicClassLoader.java
@@ -14,17 +14,16 @@
import java.util.HashMap;
import java.util.Map;
-import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.net.URLClassLoader;
import java.net.URL;
-import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
public class DynamicClassLoader extends URLClassLoader{
HashMap<Integer, Object[]> constantVals = new HashMap<Integer, Object[]>();
-static ConcurrentHashMap<String, WeakReference<Class> >classCache =
- new ConcurrentHashMap<String, WeakReference<Class> >();
+static ConcurrentHashMap<String, SoftReference<Class>>classCache =
+ new ConcurrentHashMap<String, SoftReference<Class> >();
static final URL[] EMPTY_URLS = new URL[]{};
@@ -42,24 +41,14 @@ public DynamicClassLoader(ClassLoader parent){
}
public Class defineClass(String name, byte[] bytes, Object srcForm){
+ Util.clearCache(rq, classCache);
Class c = defineClass(name, bytes, 0, bytes.length);
- classCache.put(name, new WeakReference(c,rq));
- //cleanup any dead entries
- if(rq.poll() != null)
- {
- while(rq.poll() != null)
- ;
- for(Map.Entry<String,WeakReference<Class>> e : classCache.entrySet())
- {
- if(e.getValue().get() == null)
- classCache.remove(e.getKey(), e.getValue());
- }
- }
+ classCache.put(name, new SoftReference(c,rq));
return c;
}
protected Class<?> findClass(String name) throws ClassNotFoundException{
- WeakReference<Class> cr = classCache.get(name);
+ SoftReference<Class> cr = classCache.get(name);
if(cr != null)
{
Class c = cr.get();
View
16 src/jvm/clojure/lang/Keyword.java
@@ -15,18 +15,28 @@
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.concurrent.ConcurrentHashMap;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
public final class Keyword implements IFn, Comparable, Named, Serializable {
-private static ConcurrentHashMap<Symbol, Keyword> table = new ConcurrentHashMap();
+private static ConcurrentHashMap<Symbol, SoftReference<Keyword>> table = new ConcurrentHashMap();
+static final ReferenceQueue rq = new ReferenceQueue();
public final Symbol sym;
final int hash;
public static Keyword intern(Symbol sym){
+ Util.clearCache(rq, table);
Keyword k = new Keyword(sym);
- Keyword existingk = table.putIfAbsent(sym, k);
- return existingk == null ? k : existingk;
+ SoftReference<Keyword> existingRef = table.putIfAbsent(sym, new SoftReference<Keyword>(k,rq));
+ if(existingRef == null)
+ return k;
+ Keyword existingk = existingRef.get();
+ if(existingk != null)
+ return existingk;
+ //entry died in the interim, do over
+ return intern(sym);
}
public static Keyword intern(String ns, String name){
View
17 src/jvm/clojure/lang/MapEquivalence.java
@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) Rich Hickey. All rights reserved.
+ * The use and distribution terms for this software are covered by the
+ * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
+ * which can be found in the file epl-v10.html at the root of this distribution.
+ * By using this software in any fashion, you are agreeing to be bound by
+ * the terms of this license.
+ * You must not remove this notice, or any other, from this software.
+ **/
+
+/* rich Aug 4, 2010 */
+
+package clojure.lang;
+
+//marker interface
+public interface MapEquivalence{
+}
View
28 src/jvm/clojure/lang/Util.java
@@ -13,6 +13,11 @@
package clojure.lang;
import java.math.BigInteger;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.lang.ref.SoftReference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.Reference;
public class Util{
static public boolean equiv(Object k1, Object k2){
@@ -22,13 +27,19 @@ static public boolean equiv(Object k1, Object k2){
{
if(k1 instanceof Number && k2 instanceof Number)
return Numbers.equiv(k1, k2);
- else if(k1 instanceof IPersistentCollection && k2 instanceof IPersistentCollection)
- return ((IPersistentCollection)k1).equiv(k2);
+ else if(k1 instanceof IPersistentCollection || k2 instanceof IPersistentCollection)
+ return pcequiv(k1,k2);
return k1.equals(k2);
}
return false;
}
+static public boolean pcequiv(Object k1, Object k2){
+ if(k1 instanceof IPersistentCollection)
+ return ((IPersistentCollection)k1).equiv(k2);
+ return ((IPersistentCollection)k2).equiv(k1);
+}
+
static public boolean equals(Object k1, Object k2){
if(k1 == k2)
return true;
@@ -89,4 +100,17 @@ static public ISeq ret1(ISeq ret, Object nil){
return ret;
}
+static public <K,V> void clearCache(ReferenceQueue rq, ConcurrentHashMap<K, SoftReference<V>> cache){
+ //cleanup any dead entries
+ if(rq.poll() != null)
+ {
+ while(rq.poll() != null)
+ ;
+ for(Map.Entry<K, SoftReference<V>> e : cache.entrySet())
+ {
+ if(e.getValue().get() == null)
+ cache.remove(e.getKey(), e.getValue());
+ }
+ }
+}
}
View
17 test/clojure/test_clojure/genclass.clj
@@ -9,7 +9,7 @@
(ns ^{:doc "Tests for clojure.core/gen-class"
:author "Stuart Halloway, Daniel Solano Gómez"}
clojure.test-clojure.genclass
- (:use clojure.test)
+ (:use clojure.test clojure.test-clojure.helpers)
(:import [clojure.test_clojure.genclass.examples ExampleClass
ExampleAnnotationClass]
[java.lang.annotation ElementType
@@ -17,17 +17,6 @@
RetentionPolicy
Target]))
-;; pull this up to a suite-wide helper if you find other tests need it!
-(defn get-field
- "Access to private or protected field. field-name is a symbol or
- keyword."
- ([klass field-name]
- (get-field klass field-name nil))
- ([klass field-name inst]
- (-> klass (.getDeclaredField (name field-name))
- (doto (.setAccessible true))
- (.get inst))))
-
(deftest arg-support
(let [example (ExampleClass.)
o (Object.)]
@@ -70,3 +59,7 @@
(let [target (aget first-param-annots 1)]
(is (instance? Target target))
(is (= [ElementType/TYPE ElementType/PARAMETER] (seq (.value target)))))))))))
+
+(deftest genclass-option-validation
+ (is (fails-with-cause? IllegalArgumentException #"Not a valid method name: has-hyphen"
+ (@#'clojure.core/validate-generate-class-options {:methods '[[fine [] void] [has-hyphen [] void]]}))))
View
12 test/clojure/test_clojure/helpers.clj
@@ -49,3 +49,15 @@
(report {:type :fail, :message ~msg,
:expected '~form, :actual t#})))))
+
+(defn get-field
+ "Access to private or protected field. field-name is a symbol or
+ keyword."
+ ([klass field-name]
+ (get-field klass field-name nil))
+ ([klass field-name inst]
+ (-> klass (.getDeclaredField (name field-name))
+ (doto (.setAccessible true))
+ (.get inst))))
+
+
View
10 test/clojure/test_clojure/java/shell.clj
@@ -12,13 +12,15 @@
(:import (java.io File)))
(def platform-enc (.name (java.nio.charset.Charset/defaultCharset)))
+(def default-enc "UTF-8")
(deftest test-parse-args
(are [x y] (= x y)
- [[] {:in-enc platform-enc :out-enc platform-enc :dir nil :env nil}] (#'sh/parse-args [])
- [["ls"] {:in-enc platform-enc :out-enc platform-enc :dir nil :env nil}] (#'sh/parse-args ["ls"])
- [["ls" "-l"] {:in-enc platform-enc :out-enc platform-enc :dir nil :env nil}] (#'sh/parse-args ["ls" "-l"])
- [["ls"] {:in-enc platform-enc :out-enc "ISO-8859-1" :dir nil :env nil}] (#'sh/parse-args ["ls" :out-enc "ISO-8859-1"])))
+ [[] {:in-enc default-enc :out-enc default-enc :dir nil :env nil}] (#'sh/parse-args [])
+ [["ls"] {:in-enc default-enc :out-enc default-enc :dir nil :env nil}] (#'sh/parse-args ["ls"])
+ [["ls" "-l"] {:in-enc default-enc :out-enc default-enc :dir nil :env nil}] (#'sh/parse-args ["ls" "-l"])
+ [["ls"] {:in-enc default-enc :out-enc "ISO-8859-1" :dir nil :env nil}] (#'sh/parse-args ["ls" :out-enc "ISO-8859-1"])
+ [[] {:in-enc platform-enc :out-enc platform-enc :dir nil :env nil}] (#'sh/parse-args [:in-enc platform-enc :out-enc platform-enc])))
(deftest test-with-sh-dir
(are [x y] (= x y)
View
25 test/clojure/test_clojure/protocols.clj
@@ -175,22 +175,21 @@
(defrecord DefrecordObjectMethodsWidgetA [a])
(defrecord DefrecordObjectMethodsWidgetB [a])
(deftest defrecord-object-methods-test
- (testing ".equals depends on fields and type"
- (is (true? (.equals (DefrecordObjectMethodsWidgetA. 1) (DefrecordObjectMethodsWidgetA. 1))))
- (is (false? (.equals (DefrecordObjectMethodsWidgetA. 1) (DefrecordObjectMethodsWidgetA. 2))))
- (is (false? (.equals (DefrecordObjectMethodsWidgetA. 1) (DefrecordObjectMethodsWidgetB. 1)))))
- (testing ".hashCode depends on fields and type"
- (is (= (.hashCode (DefrecordObjectMethodsWidgetA. 1)) (.hashCode (DefrecordObjectMethodsWidgetA. 1))))
- (is (= (.hashCode (DefrecordObjectMethodsWidgetA. 2)) (.hashCode (DefrecordObjectMethodsWidgetA. 2))))
- (is (not= (.hashCode (DefrecordObjectMethodsWidgetA. 1)) (.hashCode (DefrecordObjectMethodsWidgetA. 2))))
- (is (= (.hashCode (DefrecordObjectMethodsWidgetB. 1)) (.hashCode (DefrecordObjectMethodsWidgetB. 1))))
- (is (not= (.hashCode (DefrecordObjectMethodsWidgetA. 1)) (.hashCode (DefrecordObjectMethodsWidgetB. 1))))))
+ (testing "= depends on fields and type"
+ (is (true? (= (DefrecordObjectMethodsWidgetA. 1) (DefrecordObjectMethodsWidgetA. 1))))
+ (is (false? (= (DefrecordObjectMethodsWidgetA. 1) (DefrecordObjectMethodsWidgetA. 2))))
+ (is (false? (= (DefrecordObjectMethodsWidgetA. 1) (DefrecordObjectMethodsWidgetB. 1))))))
(deftest defrecord-acts-like-a-map
(let [rec (r 1 2)]
- (is (= (r 1 3 {} {:c 4}) (merge rec {:b 3 :c 4})))
- (is (= {:foo 1 :b 2} (set/rename-keys rec {:a :foo})))
- (is (= {:a 11 :b 2 :c 10} (merge-with + rec {:a 10 :c 10})))))
+ (is (.equals (r 1 3 {} {:c 4}) (merge rec {:b 3 :c 4})))
+ (is (.equals {:foo 1 :b 2} (set/rename-keys rec {:a :foo})))
+ (is (.equals {:a 11 :b 2 :c 10} (merge-with + rec {:a 10 :c 10})))))
+
+(deftest degenerate-defrecord-test
+ (let [empty (EmptyRecord.)]
+ (is (nil? (seq empty)))
+ (is (not (.containsValue empty :a)))))
(deftest defrecord-interfaces-test
(testing "java.util.Map"

No commit comments for this range

Something went wrong with that request. Please try again.