Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change ordered-map assoc behavior to be like that of Clojure 1.5.1 #14

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions src/flatland/ordered/map.clj
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,10 @@

(assoc [this k v]
(if-let [^MapEntry e (.get ^Map backing-map k)]
(let [old-v (.val e)]
(if (= old-v v)
this
(let [i (.key e)]
(OrderedMap. (.cons backing-map (entry k v i))
(.assoc order i (MapEntry. k v))))))
(let [i (.key e)
old-k (.key ^MapEntry (order i))]
(OrderedMap. (.cons backing-map (entry old-k v i))
(.assoc order i (MapEntry. old-k v))))
(OrderedMap. (.cons backing-map (entry k v (.count order)))
(.cons order (MapEntry. k v)))))
(without [this k]
Expand Down Expand Up @@ -156,15 +154,15 @@
(.val e)
not-found))
(assoc [this k v]
(let [^MapEntry e (.valAt backing-map k this)
vector-entry (MapEntry. k v)
i (if (identical? e this)
(do (change! order .conj vector-entry)
(dec (.count order)))
(let [idx (.key e)]
(change! order .assoc idx vector-entry)
idx))]
(change! backing-map .conj (entry k v i))
(let [^MapEntry e (.valAt backing-map k this)]
(if-not (identical? e this)
(let [i (.key e)
old-k (.key ^MapEntry (order i))]
(change! backing-map .conj (entry old-k v i))
(change! order .assoc i (MapEntry. old-k v)))
(do
(change! backing-map .conj (entry k v (.count order)))
(change! order .conj (MapEntry. k v))))
this))
(conj [this e]
(let [[k v] e]
Expand Down
85 changes: 85 additions & 0 deletions test/flatland/ordered/combined_test.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
(ns flatland.ordered.combined-test
(:use clojure.test
[flatland.ordered.map :only [ordered-map]]
[flatland.ordered.set :only [ordered-set]]))

(defn version->= [vers-a vers-b]
(>= (compare ((juxt :major :minor :incremental) vers-a)
((juxt :major :minor :incremental) vers-b))
0))

(deftest test-duplicates-with-metadata
(let [equal-sets-incl-meta (fn [s1 s2]
(and (= s1 s2)
(let [ss1 (sort s1)
ss2 (sort s2)]
(every? identity
(map #(and (= %1 %2)
(= (meta %1) (meta %2)))
ss1 ss2)))))
all-equal-sets-incl-meta (fn [& ss]
(every? (fn [[s1 s2]]
(equal-sets-incl-meta s1 s2))
(partition 2 1 ss)))
equal-maps-incl-meta (fn [m1 m2]
(and (= m1 m2)
(equal-sets-incl-meta (set (keys m1))
(set (keys m2)))
(every? #(= (meta (m1 %)) (meta (m2 %)))
(keys m1))))
all-equal-maps-incl-meta (fn [& ms]
(every? (fn [[m1 m2]]
(equal-maps-incl-meta m1 m2))
(partition 2 1 ms)))
cmp-first #(> (first %1) (first %2))
x1 (with-meta [1] {:me "x"})
y2 (with-meta [2] {:me "y"})
z3a (with-meta [3] {:me "z3a"})
z3b (with-meta [3] {:me "z3b"})
v4a (with-meta [4] {:me "v4a"})
v4b (with-meta [4] {:me "v4b"})
v4c (with-meta [4] {:me "v4c"})
w5a (with-meta [5] {:me "w5a"})
w5b (with-meta [5] {:me "w5b"})
w5c (with-meta [5] {:me "w5c"})]

;; Sets
;; If there are duplicate items when doing (conj #{} x1 x2 ...),
;; the behavior is that the metadata of the first item is kept.
(are [s x] (apply all-equal-sets-incl-meta s
(concat (if (version->= *clojure-version*
{:major 1 :minor 5})
[ (apply hash-set x) ]
[])
[ (apply conj #{} x)
(into #{} x)
(apply ordered-set x)
(apply conj (ordered-set) x)
(into (ordered-set) x) ]))
#{x1 y2} [x1 y2]
#{x1 z3a} [x1 z3a z3b]
#{w5b} [w5b w5a w5c]
#{z3a x1} [z3a z3b x1])

;; Maps
;; If there are duplicate keys when doing (assoc {} k1 v1 k2 v2
;; ...), the behavior is that the metadata of the first duplicate
;; key is kept, but mapped to the last value with an equal key
;; (where metadata of keys are not compared).
(are [h x] (apply all-equal-maps-incl-meta h
(concat (if (version->= *clojure-version*
{:major 1 :minor 5})
[ (apply hash-map x) ]
[])
[ (apply assoc {} x)
(into {} (map vec (partition 2 x)))
(apply ordered-map x)
(apply assoc (ordered-map) x)
(ordered-map (partition 2 x)) ]))
{x1 2, z3a 4} [x1 2, z3a 4]
{x1 2, z3a 5} [x1 2, z3a 4, z3b 5]
{z3a 5} [z3a 2, z3a 4, z3b 5]
{z3b 4, x1 5} [z3b 2, z3a 4, x1 5]
{z3b v4b, x1 5} [z3b v4a, z3a v4b, x1 5]
{x1 v4a, w5a v4c, v4a z3b, y2 2} [x1 v4a, w5a v4a, w5b v4b,
v4a z3a, y2 2, v4b z3b, w5c v4c])))