From 0a42f8bcb828c990ace36390706d6f74c7df3a4e Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Sun, 4 Nov 2012 16:02:25 -0800 Subject: [PATCH] CLJ-1103: Make conj assoc dissoc and transient versions handle args similarly All of these functions now return the given collection when no additional arguments are given, whereas before they threw an exception. conj conj! assoc assoc! dissoc! dissoc already implemented this case before. Formerly only (conj! coll x) was implemented. Now conj! takes any number of args that conj can. assoc! now checks for final key having no value like assoc does after patch for CLJ-1052 was committed. Tests written to cover all newly implemented cases. --- src/clj/clojure/core.clj | 26 +++++++++--- test/clojure/test_clojure/data_structures.clj | 18 +++++--- test/clojure/test_clojure/metadata.clj | 7 +++ test/clojure/test_clojure/transients.clj | 61 +++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 14 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 985532a..1b6aaba 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -80,6 +80,7 @@ :added "1.0" :static true} conj (fn ^:static conj + ([coll] coll) ([coll x] (. clojure.lang.RT (conj coll x))) ([coll x & xs] (if xs @@ -175,7 +176,7 @@ vector? (fn ^:static vector? [x] (instance? clojure.lang.IPersistentVector x))) (def - ^{:arglists '([map key val] [map key val & kvs]) + ^{:arglists '([map] [map key val] [map key val & kvs]) :doc "assoc[iate]. When applied to a map, returns a new map of the same (hashed/sorted) type, that contains the mapping of key(s) to val(s). When applied to a vector, returns a new vector that @@ -184,6 +185,7 @@ :static true} assoc (fn ^:static assoc + ([map] map) ([map key val] (. clojure.lang.RT (assoc map key val))) ([map key val & kvs] (let [ret (assoc map key val)] @@ -2988,8 +2990,13 @@ may happen at different 'places' depending on the concrete type." {:added "1.1" :static true} - [^clojure.lang.ITransientCollection coll x] - (.conj coll x)) + ([^clojure.lang.ITransientCollection coll] coll) + ([^clojure.lang.ITransientCollection coll x] + (.conj coll x)) + ([^clojure.lang.ITransientCollection coll x & xs] + (if xs + (recur (conj! coll x) (first xs) (next xs)) + (conj! coll x)))) (defn assoc! "Alpha - subject to change. @@ -2998,18 +3005,23 @@ Note - index must be <= (count vector). Returns coll." {:added "1.1" :static true} + ([^clojure.lang.ITransientAssociative coll] coll) ([^clojure.lang.ITransientAssociative coll key val] (.assoc coll key val)) ([^clojure.lang.ITransientAssociative coll key val & kvs] - (let [ret (.assoc coll key val)] - (if kvs - (recur ret (first kvs) (second kvs) (nnext kvs)) - ret)))) + (let [ret (.assoc coll key val)] + (if kvs + (if (next kvs) + (recur ret (first kvs) (second kvs) (nnext kvs)) + (throw (IllegalArgumentException. + "assoc! expects even number of arguments after map/vector, found odd number"))) + ret)))) (defn dissoc! "Alpha - subject to change. Returns a transient map that doesn't contain a mapping for key(s)." {:added "1.1" :static true} + ([^clojure.lang.ITransientMap map] map) ([^clojure.lang.ITransientMap map key] (.without map key)) ([^clojure.lang.ITransientMap map key & ks] (let [ret (.without map key)] diff --git a/test/clojure/test_clojure/data_structures.clj b/test/clojure/test_clojure/data_structures.clj index 3d913b3..040a667 100644 --- a/test/clojure/test_clojure/data_structures.clj +++ b/test/clojure/test_clojure/data_structures.clj @@ -956,11 +956,15 @@ v4a z3a, y2 2, v4b z3b, w5c v4c]))) -(deftest test-assoc - (are [x y] (= x y) - [4] (assoc [] 0 4) - [5 -7] (assoc [] 0 5 1 -7) - {:a 1} (assoc {} :a 1) - {:a 2 :b -2} (assoc {} :b -2 :a 2)) +(deftest test-assoc-assoc! + (are [x y z] (= x + (apply assoc y z) + (persistent! (apply assoc! (transient y) z))) + [4] [] '(0 4) + [5 -7] [] '(0 5 1 -7) + {:a 1} {} '(:a 1) + {:a 2 :b -2} {} '(:b -2 :a 2)) (is (thrown? IllegalArgumentException (assoc [] 0 5 1))) - (is (thrown? IllegalArgumentException (assoc {} :b -2 :a)))) + (is (thrown? IllegalArgumentException (assoc! (transient []) 0 5 1))) + (is (thrown? IllegalArgumentException (assoc {} :b -2 :a))) + (is (thrown? IllegalArgumentException (assoc! (transient {}) :b -2 :a)))) diff --git a/test/clojure/test_clojure/metadata.clj b/test/clojure/test_clojure/metadata.clj index 42f7dfe..fb962db 100644 --- a/test/clojure/test_clojure/metadata.clj +++ b/test/clojure/test_clojure/metadata.clj @@ -97,7 +97,10 @@ y (with-meta {:baz 4 :guh x} ym)] (is (= xm (meta (:guh y)))) + (is (= xm (meta (conj x y)))) + (is (= xm (meta (conj x)))) (is (= xm (meta (reduce #(assoc %1 %2 (inc %2)) x (range 1000))))) + (is (= xm (meta (assoc x)))) (is (= xm (meta (-> x (dissoc :foo) (dissoc :bar))))) (let [z (assoc-in y [:guh :la] 18)] (is (= ym (meta z))) @@ -134,6 +137,8 @@ (is (= xm (meta (y 1)))) (is (= xm (meta (assoc x 1 "one")))) + (is (= xm (meta (assoc x)))) + (is (= xm (meta (conj x)))) (is (= xm (meta (reduce #(conj %1 %2) x (range 1000))))) (is (= xm (meta (pop (pop (pop x)))))) (let [z (assoc-in y [1 2] 18)] @@ -167,8 +172,10 @@ y (with-meta #{4 x 6} ym)] (is (= xm (meta (y #{3 2 1})))) + (is (= xm (meta (conj x)))) (is (= xm (meta (reduce #(conj %1 %2) x (range 1000))))) (is (= xm (meta (-> x (disj 1) (disj 2) (disj 3))))) + (is (= xm (meta (disj x)))) (is (= xm (meta (into x y)))) (is (= ym (meta (into y x)))) diff --git a/test/clojure/test_clojure/transients.clj b/test/clojure/test_clojure/transients.clj index 721dcf2..40cf738 100644 --- a/test/clojure/test_clojure/transients.clj +++ b/test/clojure/test_clojure/transients.clj @@ -31,3 +31,64 @@ (deftest empty-transient (is (= false (.contains (transient #{}) :bogus-key)))) + +(deftest ops-on-transient-maps + (doseq [x [{:foo 1 :bar 2} + (array-map :foo 1 :bar 2) + (hash-map :foo 1 :bar 2)]] ; no transient sorted maps + (is (= (:foo x) (:foo (transient x)))) + (is (= (count x) (count (transient x)))) + (are [conj-args] (= (apply conj x conj-args) + (persistent! + (apply conj! (transient x) conj-args))) + '() + '({:bar -3 :baz 10}) + '({:bar -3 :baz 10} {:blub 0})) + (are [assoc-args] (= (apply assoc x assoc-args) + (persistent! + (apply assoc! (transient x) assoc-args))) + '() + '(:blub 0) + (mapcat (fn [i] [i (inc i)]) (range 1000))) + (are [dissoc-args] (= (apply dissoc x dissoc-args) + (persistent! + (apply dissoc! (transient x) dissoc-args))) + '() + '(:foo) + '(:foo :bar)))) + +(deftest ops-on-transient-vectors + (let [x ["foo" "bar"]] + (is (= "bar" ((transient x) 1))) + (is (= 2 (count (transient x)))) + (are [conj-args] (= (apply conj x conj-args) + (persistent! + (apply conj! (transient x) conj-args))) + '() + '("baz") + '("baz" "blub")) + (are [assoc-args] (= (apply assoc x assoc-args) + (persistent! + (apply assoc! (transient x) assoc-args))) + '() + '(0 "blub") + (mapcat (fn [i] [i (inc i)]) (range 1000))) + (is (= (pop x) + (persistent! (pop! (transient x))))))) + +(deftest ops-on-transient-sets + (doseq [x [#{"foo" "bar"} (hash-set "foo" "bar")]] ; no transient sorted sets + (is (= "bar" ((transient x) "bar"))) + (is (= 2 (count (transient x)))) + (are [conj-args] (= (apply conj x conj-args) + (persistent! + (apply conj! (transient x) conj-args))) + '() + '("baz") + '("baz" "blub")) + (are [disj-args] (= (apply disj x disj-args) + (persistent! + (apply disj! (transient x) disj-args))) + '() + '("bar") + '("bar" "baz" "foo")))) -- 1.8.0