Skip to content
Browse files

CLJS-584: duplicate map keys

cljs.core.PersistentArrayMap.fromArray now takes a 3rd no-check
parameter. The inlining array-map macro and the compiler emission for
array-maps now analyzes for constants and emits a direct instantiation
if possible - otherwise cljs.core.PersistentArrayMap.fromArray called
with no-check set to false.
  • Loading branch information...
1 parent 8f0eafa commit d929ae942bc2859cc7b684334affc1b590173f88 @swannodette swannodette committed Nov 17, 2013
Showing with 42 additions and 11 deletions.
  1. +13 −5 src/clj/cljs/compiler.clj
  2. +14 −3 src/clj/cljs/core.clj
  3. +11 −3 src/cljs/cljs/core.cljs
  4. +4 −0 test/cljs/cljs/core_test.cljs
View
18 src/clj/cljs/compiler.clj
@@ -276,6 +276,10 @@
(def ^:private array-map-threshold 8)
(def ^:private obj-map-threshold 8)
+(defn distinct-keys? [keys]
+ (and (every? #(= (:op %) :constant) keys)
+ (= (count (into #{} keys)) (count keys))))
+
(defmethod emit* :map
[{:keys [env keys vals]}]
(let [simple-keys? (every? #(or (string? %) (keyword? %)) keys)]
@@ -285,9 +289,13 @@
(emits "cljs.core.PersistentArrayMap.EMPTY")
(<= (count keys) array-map-threshold)
- (emits "new cljs.core.PersistentArrayMap(null, " (count keys) ", ["
- (comma-sep (interleave keys vals))
- "], null)")
+ (if (distinct-keys? keys)
+ (emits "new cljs.core.PersistentArrayMap(null, " (count keys) ", ["
+ (comma-sep (interleave keys vals))
+ "], null)")
+ (emits "new cljs.core.PersistentArrayMap.fromArray(["
+ (comma-sep (interleave keys vals))
+ "], true, false)"))
:else
(emits "cljs.core.PersistentHashMap.fromArrays(["
@@ -326,8 +334,8 @@
(emits "cljs.core.PersistentHashSet.EMPTY")
(distinct-constants? items)
- (emits "new cljs.core.PersistentHashSet(null, cljs.core.PersistentArrayMap.fromArray(["
- (comma-sep (interleave items (repeat "null"))) "], true), null)")
+ (emits "new cljs.core.PersistentHashSet(null, new cljs.core.PersistentArrayMap(null, " (count items) ", ["
+ (comma-sep (interleave items (repeat "null"))) "], null), null)")
:else (emits "cljs.core.PersistentHashSet.fromArray([" (comma-sep items) "], true)"))))
View
17 src/clj/cljs/core.clj
@@ -1306,9 +1306,18 @@
(defmacro array-map
([] `cljs.core.PersistentArrayMap.EMPTY)
([& kvs]
- (if (core/> (count kvs) 16)
+ (cond
+ (core/> (count kvs) 16)
`(hash-map ~@kvs)
- `(cljs.core.PersistentArrayMap. nil ~(clojure.core// (count kvs) 2) (array ~@kvs) nil))))
+
+ (let [keys (map first (partition 2 kvs))]
+ (core/and (every? #(= (:op %) :constant)
+ (map #(cljs.analyzer/analyze &env %) keys))
+ (= (count (into #{} keys)) (count keys))))
+ `(cljs.core.PersistentArrayMap. nil ~(clojure.core// (count kvs) 2) (array ~@kvs) nil)
+
+ :else
+ `(cljs.core.PersistentArrayMap.fromArray (array ~@kvs) true false))))
(defmacro hash-map
([] `cljs.core.PersistentHashMap.EMPTY)
@@ -1324,7 +1333,9 @@
(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. nil
+ (cljs.core.PersistentArrayMap. nil ~(count xs) (array ~@(interleave xs (repeat nil))) nil)
+ nil)
`(cljs.core.PersistentHashSet.fromArray (array ~@xs) true))))
(defn js-obj* [kvs]
View
14 src/cljs/cljs/core.cljs
@@ -4256,10 +4256,18 @@ reduces them without incurring seq initialization"
(set! cljs.core.PersistentArrayMap.HASHMAP_THRESHOLD 8)
(set! cljs.core.PersistentArrayMap.fromArray
- (fn [arr ^boolean no-clone]
+ (fn [arr ^boolean no-clone ^boolean no-check]
(let [arr (if no-clone arr (aclone arr))]
- (let [cnt (/ (alength arr) 2)]
- (PersistentArrayMap. nil cnt arr nil)))))
+ (if no-check
+ (let [cnt (/ (alength arr) 2)]
+ (PersistentArrayMap. nil cnt arr nil))
+ (let [len (alength arr)]
+ (loop [i 0
+ ret (transient cljs.core.PersistentArrayMap.EMPTY)]
+ (if (< i len)
+ (recur (+ i 2)
+ (-assoc! ret (aget arr i) (aget arr (inc i))))
+ (-persistent! ret))))))))
(declare array->transient-hash-map)
View
4 test/cljs/cljs/core_test.cljs
@@ -2009,5 +2009,9 @@
(assert (= (count #{some-x some-y}) 1))
+ ;; CLJS-584
+
+ (assert (= (count {some-x :foo some-y :bar}) 1))
+
:ok
)

0 comments on commit d929ae9

Please sign in to comment.
Something went wrong with that request. Please try again.