Permalink
Browse files

CLJS-583: duplicate keys in sets

fix cljs.core.PersistentHashSet so that duplicate keys are
prevented. Add a fast path for hash-set inlining macro and hash-set
emission in compiler.clj, if all keys are distinct constants don't check
for duplicates
  • Loading branch information...
1 parent 9af32d5 commit fe9b5577cd9b9784d0c0c75edccc4441c99ee924 @swannodette swannodette committed Nov 17, 2013
Showing with 37 additions and 14 deletions.
  1. +12 −3 src/clj/cljs/compiler.clj
  2. +7 −3 src/clj/cljs/core.clj
  3. +11 −8 src/cljs/cljs/core.cljs
  4. +7 −0 test/cljs/cljs/core_test.cljs
@@ -314,13 +314,22 @@
", 5, cljs.core.PersistentVector.EMPTY_NODE, [" (comma-sep items) "], null)")
(emits "cljs.core.PersistentVector.fromArray([" (comma-sep items) "], true)"))))))
+(defn distinct-constants? [items]
+ (and (every? #(= (:op %) :constant) items)
+ (= (count (into #{} items)) (count items))))
+
(defmethod emit* :set
[{:keys [items env]}]
(emit-wrap env
- (if (empty? items)
+ (cond
+ (empty? items)
(emits "cljs.core.PersistentHashSet.EMPTY")
- (emits "cljs.core.PersistentHashSet.fromArray(["
- (comma-sep (interleave items (repeat "null"))) "], true)"))))
+
+ (distinct-constants? items)
+ (emits "new cljs.core.PersistentHashSet(null, cljs.core.PersistentArrayMap.fromArray(["
+ (comma-sep (interleave items (repeat "null"))) "], true), null)")
+
+ :else (emits "cljs.core.PersistentHashSet.fromArray([" (comma-sep items) "], true)"))))
(defmethod emit* :constant
[{:keys [form env]}]
View
@@ -1314,14 +1314,18 @@
([] `cljs.core.PersistentHashMap.EMPTY)
([& kvs]
(let [pairs (partition 2 kvs)
- ks (map first pairs)
- vs (map second pairs)]
+ ks (map first pairs)
+ vs (map second pairs)]
`(cljs.core.PersistentHashMap.fromArrays (array ~@ks) (array ~@vs)))))
(defmacro hash-set
([] `cljs.core.PersistentHashSet.EMPTY)
([& xs]
- `(set (array ~@xs))))
+ (if (core/and (every? #(= (:op %) :constant)
+ (map #(cljs.analyzer/analyze &env %) xs))
+ (= (count (into #{} xs)) (count xs)))
+ `(cljs.core.PersistentHashSet. nil (cljs.core.PersistentArrayMap.fromArray (array ~@(interleave xs (repeat nil))) true) nil)
+ `(cljs.core.PersistentHashSet.fromArray (array ~@xs) true))))
(defn js-obj* [kvs]
(let [kvs-str (->> (repeat "~{}:~{}")
@@ -2447,10 +2447,10 @@ reduces them without incurring seq initialization"
;;; Transients
-(defn transient [coll]
+(defn ^not-native transient [coll]
(-as-transient coll))
-(defn persistent! [tcoll]
+(defn ^not-native persistent! [tcoll]
(-persistent! tcoll))
(defn conj! [tcoll val]
@@ -6090,15 +6090,18 @@ reduces them without incurring seq initialization"
(set! cljs.core.PersistentHashSet.fromArray
(fn [items ^boolean no-clone]
(let [len (alength items)]
- (if (<= (/ len 2) cljs.core.PersistentArrayMap.HASHMAP_THRESHOLD)
- (let [arr (if no-clone items (aclone items))]
- (PersistentHashSet. nil
- (cljs.core.PersistentArrayMap.fromArray arr true) nil))
+ (if (<= len cljs.core.PersistentArrayMap.HASHMAP_THRESHOLD)
+ (let [arr (if no-clone items (aclone items))]
+ (loop [i 0
+ out (transient cljs.core.PersistentArrayMap.EMPTY)]
+ (if (< i len)
+ (recur (inc i) (-assoc! out (aget items i) nil))
+ (cljs.core.PersistentHashSet. nil (-persistent! out) nil))))
(loop [i 0
out (transient cljs.core.PersistentHashSet.EMPTY)]
(if (< i len)
- (recur (+ i 2) (conj! out (aget items i)))
- (persistent! out)))))))
+ (recur (+ i 2) (-conj! out (aget items i)))
+ (-persistent! out)))))))
(deftype TransientHashSet [^:mutable transient-map]
ITransientCollection
@@ -2002,5 +2002,12 @@
(keys (js-obj (identity "x") "y"))
(keys (js-obj z "y")))))
+ ;; CLJS-583
+
+ (def some-x 1)
+ (def some-y 1)
+
+ (assert (= (count #{some-x some-y}) 1))
+
:ok
)

0 comments on commit fe9b557

Please sign in to comment.