Skip to content
Permalink
Browse files

CLJS-962: fix inconsistent hashing of empty collections

  • Loading branch information...
michalmarczyk authored and swannodette committed Jan 6, 2015
1 parent e726c22 commit d1cf949fa2e7c44844dc95913db44ae061397af3
Showing with 34 additions and 9 deletions.
  1. +15 −9 src/cljs/cljs/core.cljs
  2. +19 −0 test/cljs/cljs/core_test.cljs
@@ -778,6 +778,9 @@
(next coll))
(mix-collection-hash hash-code n))))

(def ^:private empty-ordered-hash
(mix-collection-hash 1 0))

(defn ^number hash-unordered-coll
"Returns the hash code, consistent with =, for an external unordered
collection implementing Iterable. For maps, the iterator should
@@ -790,6 +793,9 @@
(recur (inc n) (bit-or (+ hash-code (hash (first coll))) 0) (next coll))
(mix-collection-hash hash-code n))))

(def ^:private empty-unordered-hash
(mix-collection-hash 0 0))

;;;;;;;;;;;;;;;;;;; protocols on primitives ;;;;;;;;
(declare hash-map list equiv-sequential)

@@ -2303,7 +2309,7 @@ reduces them without incurring seq initialization"
(-equiv [coll other] (equiv-sequential coll other))

IHash
(-hash [coll] 0)
(-hash [coll] empty-ordered-hash)

ISeqable
(-seq [coll] nil)
@@ -4364,7 +4370,7 @@ reduces them without incurring seq initialization"
(set! (.-EMPTY-NODE PersistentVector) (VectorNode. nil (make-array 32)))

(set! (.-EMPTY PersistentVector)
(PersistentVector. nil 0 5 (.-EMPTY-NODE PersistentVector) (array) 0))
(PersistentVector. nil 0 5 (.-EMPTY-NODE PersistentVector) (array) empty-ordered-hash))

(set! (.-fromArray PersistentVector)
(fn [xs ^boolean no-clone]
@@ -4878,7 +4884,7 @@ reduces them without incurring seq initialization"
ICounted
(-count [coll] count))

(set! (.-EMPTY PersistentQueue) (PersistentQueue. nil 0 nil [] 0))
(set! (.-EMPTY PersistentQueue) (PersistentQueue. nil 0 nil [] empty-ordered-hash))

(es6-iterable PersistentQueue)

@@ -5055,7 +5061,7 @@ reduces them without incurring seq initialization"
(-as-transient [coll]
(transient (into (hash-map) coll))))

(set! (.-EMPTY ObjMap) (ObjMap. nil (array) (js-obj) 0 0))
(set! (.-EMPTY ObjMap) (ObjMap. nil (array) (js-obj) 0 empty-unordered-hash))

(set! (.-HASHMAP_THRESHOLD ObjMap) 8)

@@ -5392,7 +5398,7 @@ reduces them without incurring seq initialization"
(-as-transient [coll]
(TransientArrayMap. (js-obj) (alength arr) (aclone arr))))

(set! (.-EMPTY PersistentArrayMap) (PersistentArrayMap. nil 0 (array) nil))
(set! (.-EMPTY PersistentArrayMap) (PersistentArrayMap. nil 0 (array) empty-unordered-hash))

(set! (.-HASHMAP-THRESHOLD PersistentArrayMap) 8)

@@ -6234,7 +6240,7 @@ reduces them without incurring seq initialization"
(-as-transient [coll]
(TransientHashMap. (js-obj) root cnt has-nil? nil-val)))

(set! (.-EMPTY PersistentHashMap) (PersistentHashMap. nil 0 nil false nil 0))
(set! (.-EMPTY PersistentHashMap) (PersistentHashMap. nil 0 nil false nil empty-unordered-hash))

(set! (.-fromArrays PersistentHashMap)
(fn [ks vs]
@@ -7017,7 +7023,7 @@ reduces them without incurring seq initialization"

(-comparator [coll] comp))

(set! (.-EMPTY PersistentTreeMap) (PersistentTreeMap. compare nil 0 nil 0))
(set! (.-EMPTY PersistentTreeMap) (PersistentTreeMap. compare nil 0 nil empty-unordered-hash))

(es6-iterable PersistentTreeMap)

@@ -7321,7 +7327,7 @@ reduces them without incurring seq initialization"
(-as-transient [coll] (TransientHashSet. (-as-transient hash-map))))

(set! (.-EMPTY PersistentHashSet)
(PersistentHashSet. nil (.-EMPTY PersistentArrayMap) 0))
(PersistentHashSet. nil (.-EMPTY PersistentArrayMap) empty-unordered-hash))

(set! (.-fromArray PersistentHashSet)
(fn [items ^boolean no-clone]
@@ -7467,7 +7473,7 @@ reduces them without incurring seq initialization"
(-lookup coll k not-found)))

(set! (.-EMPTY PersistentTreeSet)
(PersistentTreeSet. nil (.-EMPTY PersistentTreeMap) 0))
(PersistentTreeSet. nil (.-EMPTY PersistentTreeMap) empty-unordered-hash))

(es6-iterable PersistentTreeSet)

@@ -2563,6 +2563,25 @@
(is (== @a0 10))
(is (== @a1 20)))))

(deftest test-962-empty-literal-hashes
(testing "CLJS-962: empty literals should produce collections with correct hash codes"
(let [l ()
v []
s #{}
m {}]
(is (== (hash l) (hash v) (hash-ordered-coll ())))
(is (== (hash s) (hash m) (hash-unordered-coll #{})))))
(testing "CLJS-962: EMPTY collections should have correct hash codes"
(let [l (.-EMPTY List)
pv (.-EMPTY PersistentVector)
phs (.-EMPTY PersistentHashSet)
pts (.-EMPTY PersistentTreeSet)
pam (.-EMPTY PersistentArrayMap)
phm (.-EMPTY PersistentHashMap)
ptm (.-EMPTY PersistentTreeMap)]
(is (== (hash l) (hash pv) (hash-ordered-coll ())))
(is (apply == (hash-unordered-coll #{}) (map hash [phs pts pam phm ptm]))))))

(comment
;; ObjMap
;; (let [ks (map (partial str "foo") (range 500))

0 comments on commit d1cf949

Please sign in to comment.
You can’t perform that action at this time.