Skip to content

Commit 78891af

Browse files
thomasmulvaneydnolen
authored andcommitted
CLJS-2013 - Add MapEntry type
New additions: * A MapEntry type for use by PAM and PHM * -contains-key? from IAssociative protocol was missing from PersistentVector, RedNode and BlackNode Changes: * -nth on RedNode and BlackNode now throws on out of bounds * -invoke on RedNode and BlackNode now throws on out of bounds * -find on RedNode and BlackNode now returns correct value
1 parent 9dafe7d commit 78891af

File tree

3 files changed

+262
-8
lines changed

3 files changed

+262
-8
lines changed

src/main/cljs/cljs/core.cljs

Lines changed: 114 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5161,6 +5161,10 @@ reduces them without incurring seq initialization"
51615161
(if (number? k)
51625162
(-assoc-n coll k v)
51635163
(throw (js/Error. "Vector's key for assoc must be a number."))))
5164+
(-contains-key? [coll k]
5165+
(if (integer? k)
5166+
(and (<= 0 k) (< k cnt))
5167+
false))
51645168

51655169
IFind
51665170
(-find [coll k]
@@ -6134,6 +6138,98 @@ reduces them without incurring seq initialization"
61346138

61356139
(declare TransientArrayMap)
61366140

6141+
(deftype MapEntry [key val ^:mutable __hash]
6142+
Object
6143+
(indexOf [coll x]
6144+
(-indexOf coll x 0))
6145+
(indexOf [coll x start]
6146+
(-indexOf coll x start))
6147+
(lastIndexOf [coll x]
6148+
(-lastIndexOf coll x (count coll)))
6149+
(lastIndexOf [coll x start]
6150+
(-lastIndexOf coll x start))
6151+
6152+
IMapEntry
6153+
(-key [node] key)
6154+
(-val [node] val)
6155+
6156+
IHash
6157+
(-hash [coll] (caching-hash coll hash-ordered-coll __hash))
6158+
6159+
IEquiv
6160+
(-equiv [coll other] (equiv-sequential coll other))
6161+
6162+
IMeta
6163+
(-meta [node] nil)
6164+
6165+
IWithMeta
6166+
(-with-meta [node meta]
6167+
(with-meta [key val] meta))
6168+
6169+
IStack
6170+
(-peek [node] val)
6171+
6172+
(-pop [node] [key])
6173+
6174+
ICollection
6175+
(-conj [node o] [key val o])
6176+
6177+
IEmptyableCollection
6178+
(-empty [node] [])
6179+
6180+
ISequential
6181+
ISeqable
6182+
(-seq [node] (list key val))
6183+
6184+
ICounted
6185+
(-count [node] 2)
6186+
6187+
IIndexed
6188+
(-nth [node n]
6189+
(cond (== n 0) key
6190+
(== n 1) val
6191+
:else (throw (js/Error. "Index out of bounds"))))
6192+
6193+
(-nth [node n not-found]
6194+
(cond (== n 0) key
6195+
(== n 1) val
6196+
:else not-found))
6197+
6198+
ILookup
6199+
(-lookup [node k] (-nth node k nil))
6200+
(-lookup [node k not-found] (-nth node k not-found))
6201+
6202+
IAssociative
6203+
(-assoc [node k v]
6204+
(assoc [key val] k v))
6205+
(-contains-key? [node k]
6206+
(or (== k 0) (== k 1)))
6207+
6208+
IFind
6209+
(-find [node k]
6210+
(cond
6211+
(== k 0) [0 key]
6212+
(== k 1) [1 val]
6213+
:else nil))
6214+
6215+
IVector
6216+
(-assoc-n [node n v]
6217+
(-assoc-n [key val] n v))
6218+
6219+
IReduce
6220+
(-reduce [node f]
6221+
(ci-reduce node f))
6222+
6223+
(-reduce [node f start]
6224+
(ci-reduce node f start))
6225+
6226+
IFn
6227+
(-invoke [node k]
6228+
(-nth node k))
6229+
6230+
(-invoke [node k not-found]
6231+
(-nth node k not-found)))
6232+
61376233
(deftype PersistentArrayMapSeq [arr i _meta]
61386234
Object
61396235
(toString [coll]
@@ -7754,7 +7850,7 @@ reduces them without incurring seq initialization"
77547850
(-nth [node n]
77557851
(cond (== n 0) key
77567852
(== n 1) val
7757-
:else nil))
7853+
:else (throw (js/Error. "Index out of bounds"))))
77587854

77597855
(-nth [node n not-found]
77607856
(cond (== n 0) key
@@ -7768,10 +7864,15 @@ reduces them without incurring seq initialization"
77687864
IAssociative
77697865
(-assoc [node k v]
77707866
(assoc [key val] k v))
7867+
(-contains-key? [node k]
7868+
(or (== k 0) (== k 1)))
77717869

77727870
IFind
77737871
(-find [node k]
7774-
[key val])
7872+
(cond
7873+
(== k 0) [0 key]
7874+
(== k 1) [1 val]
7875+
:else nil))
77757876

77767877
IVector
77777878
(-assoc-n [node n v]
@@ -7786,10 +7887,10 @@ reduces them without incurring seq initialization"
77867887

77877888
IFn
77887889
(-invoke [node k]
7789-
(-lookup node k))
7890+
(-nth node k))
77907891

77917892
(-invoke [node k not-found]
7792-
(-lookup node k not-found)))
7893+
(-nth node k not-found)))
77937894

77947895
(es6-iterable BlackNode)
77957896

@@ -7910,7 +8011,7 @@ reduces them without incurring seq initialization"
79108011
(-nth [node n]
79118012
(cond (== n 0) key
79128013
(== n 1) val
7913-
:else nil))
8014+
:else (throw (js/Error. "Index out of bounds"))))
79148015

79158016
(-nth [node n not-found]
79168017
(cond (== n 0) key
@@ -7924,10 +8025,15 @@ reduces them without incurring seq initialization"
79248025
IAssociative
79258026
(-assoc [node k v]
79268027
(assoc [key val] k v))
8028+
(-contains-key? [node k]
8029+
(or (== k 0) (== k 1)))
79278030

79288031
IFind
79298032
(-find [node k]
7930-
[key val])
8033+
(cond
8034+
(== k 0) [0 key]
8035+
(== k 1) [1 val]
8036+
:else nil))
79318037

79328038
IVector
79338039
(-assoc-n [node n v]
@@ -7942,10 +8048,10 @@ reduces them without incurring seq initialization"
79428048

79438049
IFn
79448050
(-invoke [node k]
7945-
(-lookup node k))
8051+
(-nth node k))
79468052

79478053
(-invoke [node k not-found]
7948-
(-lookup node k not-found)))
8054+
(-nth node k not-found)))
79498055

79508056
(es6-iterable RedNode)
79518057

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
;; Copyright (c) Rich Hickey. All rights reserved.
2+
;; The use and distribution terms for this software are covered by the
3+
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4+
;; which can be found in the file epl-v10.html at the root of this distribution.
5+
;; By using this software in any fashion, you are agreeing to be bound by
6+
;; the terms of this license.
7+
;; You must not remove this notice, or any other, from this software.
8+
9+
(ns cljs.map-entry-test
10+
(:refer-clojure :exclude [iter])
11+
(:require [cljs.test :refer-macros [deftest testing is are]]))
12+
13+
(defn map-entry-interface-tests
14+
"Tests that a MapEntry implements all the expected interfaces correctly.
15+
Expects a MapEntry type with key `:key` and a val `:val`."
16+
[e]
17+
(testing "map entry interfaces"
18+
(testing "IMapEntry"
19+
(testing "-key"
20+
(is (= :key (-key e))))
21+
(testing "-val"
22+
(is (= :val (-val e)))))
23+
24+
(testing "IEquiv"
25+
(testing "-equiv"
26+
(are [x y] (-equiv x y)
27+
e [:key :val]
28+
e '(:key :val))))
29+
30+
(testing "ILookup"
31+
(testing "-lookup 2-arity"
32+
(are [x y] (= x y)
33+
:key (-lookup e 0)
34+
:val (-lookup e 1)
35+
nil (-lookup e 2)
36+
nil (-lookup e -1)))
37+
(testing "-lookup 3-arity"
38+
(are [x y] (= x y)
39+
:key (-lookup e 0 :not-found)
40+
:val (-lookup e 1 :not-found)
41+
:not-found (-lookup e 2 :not-found)
42+
:not-found (-lookup e -1 :not-found))))
43+
44+
(testing "IStack"
45+
(testing "-peek"
46+
(is (= :val (-peek e))))
47+
(testing "-pop"
48+
(is (vector? (-pop e)))
49+
(is (= [:key] (-pop e)))))
50+
51+
(testing "ICollection"
52+
(testing "-conj"
53+
(is (vector? (-conj e :thing)))
54+
(is (= [:key :val :thing] (-conj e :thing)))))
55+
56+
(testing "IEmptyableCollection"
57+
(testing "-empty"
58+
(is (= [] (empty e)))))
59+
60+
(testing "ISequential"
61+
(is (satisfies? ISequential e)))
62+
63+
(testing "ISeqable"
64+
(testing "-seq"
65+
(is (= (list :key :val) (-seq e)))))
66+
67+
(testing "ICounted"
68+
(testing "-count"
69+
(is (= 2 (-count e)))))
70+
71+
(testing "IIndexed"
72+
(testing "-nth 2-arity"
73+
(are [x y] (= x y)
74+
:key (-nth e 0)
75+
:val (-nth e 1))
76+
(is (thrown? js/Error (-nth e 2)))
77+
(is (thrown? js/Error (-nth e -1))))
78+
(testing "-nth 3-arity"
79+
(are [x y] (= x y)
80+
:key (-nth e 0 :not-found)
81+
:val (-nth e 1 :not-found)
82+
:not-found (-nth e 2 :not-found)
83+
:not-found (-nth e -1 :not-found))))
84+
85+
(testing "IAssociative"
86+
(testing "-assoc"
87+
(are [x y] (= x y)
88+
[:new :val] (-assoc e 0 :new)
89+
[:key :new] (-assoc e 1 :new)
90+
[:key :val :new] (-assoc e 2 :new)))
91+
(testing "-contains-key?"
92+
(are [x y] (= x y)
93+
true (-contains-key? e 0)
94+
true (-contains-key? e 1)
95+
false (-contains-key? e 2)
96+
false (-contains-key? e -1))))
97+
98+
(testing "IVector"
99+
(testing "-assoc-n"
100+
(are [x y] (= x y)
101+
[:new :val] (-assoc-n e 0 :new)
102+
[:key :new] (-assoc-n e 1 :new)
103+
[:key :val :new] (-assoc-n e 2 :new))))
104+
105+
(testing "IReduce"
106+
(testing "-reduce 2-arity"
107+
(is (= [:key :val] (-reduce e (fn [r e] [r e])))))
108+
(testing "-reduce 3-arity"
109+
(is (= [:key :val] (-reduce e conj [])))))
110+
111+
(testing "IFind"
112+
(testing "-find"
113+
(are [x y] (= x y)
114+
[0 :key] (-find e 0)
115+
[1 :val] (-find e 1)
116+
;; Commented out as unsure about contract of -find
117+
;; in the case where key is not present.
118+
;nil (-find e 2)
119+
;nil (-find e -1)
120+
;; So testing `find` in this case instead as contract is clear.
121+
nil (find e 2)
122+
nil (find e -1))))
123+
124+
(testing "IFn"
125+
(testing "-invoke 2-arity"
126+
(are [x y] (= x y)
127+
:key (e 0)
128+
:val (e 1))
129+
(is (thrown? js/Error (e 2)))
130+
(is (thrown? js/Error (e -1))))
131+
(testing "-invoke 3-arity"
132+
(are [x y] (= x y)
133+
:key (e 0 :not-found)
134+
:val (e 1 :not-found)
135+
:not-found (e 2 :not-found)
136+
:not-found (e -1 :not-found))))))
137+
138+
(deftest all-map-entry-tests
139+
(testing "BlackNode"
140+
(map-entry-interface-tests (BlackNode. :key :val nil nil nil)))
141+
(testing "RedNode"
142+
(map-entry-interface-tests (RedNode. :key :val nil nil nil)))
143+
(testing "Vector"
144+
(map-entry-interface-tests [:key :val]))
145+
(testing "MapEntry"
146+
(map-entry-interface-tests (MapEntry. :key :val nil))))

src/test/cljs/test_runner.cljs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
[cljs.spec.test-test]
3838
[cljs.clojure-alias-test]
3939
[cljs.hash-map-test]
40+
[cljs.map-entry-test]
4041
[cljs.predicates-test]
4142
[cljs.tagged-literals-test]
4243
[cljs.test-test]
@@ -73,6 +74,7 @@
7374
'cljs.spec.test-test
7475
'cljs.clojure-alias-test
7576
'cljs.hash-map-test
77+
'cljs.map-entry-test
7678
'cljs.pprint-test
7779
'cljs.predicates-test
7880
'cljs.syntax-quote-test

0 commit comments

Comments
 (0)