add specialized MAP-KEYS navigator

This commit is contained in:
nathanmarz 2017-02-28 15:55:25 -05:00
parent cdbbd13939
commit 2504b7849a
3 changed files with 95 additions and 5 deletions

View file

@ -650,6 +650,16 @@
(transform* [this structure next-fn]
(n/map-vals-transform structure next-fn)))
(defnav
^{:doc "Navigate to each key of the map. This is more efficient than
navigating via [ALL FIRST]"}
MAP-KEYS
[]
(select* [this structure next-fn]
(doseqres NONE [k (keys structure)]
(next-fn k)))
(transform* [this structure next-fn]
(n/map-keys-transform structure next-fn)))
(defcollector VAL []

View file

@ -210,8 +210,12 @@
(defprotocol MapValsTransformProtocol
(map-vals-transform [structure next-fn]))
(defprotocol MapTransformProtocol
(map-vals-transform [structure next-fn])
(map-keys-transform [structure next-fn])
)
(defn map-vals-non-transient-transform [structure empty-map next-fn]
(reduce-kv
@ -223,10 +227,22 @@
empty-map
structure))
(extend-protocol MapValsTransformProtocol
(defn map-keys-non-transient-transform [structure empty-map next-fn]
(reduce-kv
(fn [m k v]
(let [newk (next-fn k)]
(if (identical? newk i/NONE)
m
(assoc m newk v))))
empty-map
structure))
(extend-protocol MapTransformProtocol
nil
(map-vals-transform [structure next-fn]
nil)
(map-keys-transform [structure next-fn]
nil)
#?(:clj clojure.lang.PersistentArrayMap)
@ -257,17 +273,48 @@
array
)]
(clojure.lang.PersistentArrayMap. array)))))
#?(:clj
(map-keys-transform [structure next-fn]
(let [k-it (.keyIterator structure)
v-it (.valIterator structure)
none-cell (i/mutable-cell 0)
len (.count structure)
array (i/fast-object-array (* 2 len))]
(loop [i 0
j 0]
(if (.hasNext k-it)
(let [k (.next k-it)
v (.next v-it)
newk (next-fn k)]
(if (identical? newk i/NONE)
(do
(i/update-cell! none-cell inc)
(recur (+ i 2) j))
(do
(aset array j newk)
(aset array (inc j) v)
(recur (+ i 2) (+ j 2)))))))
(let [none-count (i/get-cell none-cell)
array (if (not= 0 none-count)
(java.util.Arrays/copyOf array (int (* 2 (- len none-count))))
array
)]
(clojure.lang.PersistentArrayMap/createAsIfByAssoc array)))))
#?(:cljs cljs.core/PersistentArrayMap)
#?(:cljs
(map-vals-transform [structure next-fn]
(map-vals-non-transient-transform structure {} next-fn)))
#?(:cljs
(map-keys-transform [structure next-fn]
(map-keys-non-transient-transform structure {} next-fn)))
#?(:clj clojure.lang.PersistentTreeMap :cljs cljs.core/PersistentTreeMap)
(map-vals-transform [structure next-fn]
(map-vals-non-transient-transform structure (empty structure) next-fn))
(map-keys-transform [structure next-fn]
(map-keys-non-transient-transform structure (empty structure) next-fn))
#?(:clj clojure.lang.PersistentHashMap :cljs cljs.core/PersistentHashMap)
@ -283,7 +330,18 @@
#?(:clj clojure.lang.PersistentHashMap/EMPTY :cljs cljs.core.PersistentHashMap.EMPTY))
structure)))
(map-keys-transform [structure next-fn]
(persistent!
(reduce-kv
(fn [m k v]
(let [newk (next-fn k)]
(if (identical? newk i/NONE)
m
(assoc! m newk v))))
(transient
#?(:clj clojure.lang.PersistentHashMap/EMPTY :cljs cljs.core.PersistentHashMap.EMPTY))
structure)))
#?(:clj Object :cljs default)
(map-vals-transform [structure next-fn]
@ -294,9 +352,17 @@
m
(assoc m k newv))))
(empty structure)
structure))
(map-keys-transform [structure next-fn]
(reduce-kv
(fn [m k v]
(let [newk (next-fn k)]
(if (identical? newk i/NONE)
m
(assoc m newk v))))
(empty structure)
structure)))
(defn srange-select [structure start end next-fn]
(next-fn
(if (string? structure)

View file

@ -1455,3 +1455,17 @@
(is (predand= vector? [1 0] (setval s/AFTER-ELEM 0 v)))
(is (predand= vector? [1 0] (setval (s/srange 1 1) [0] v)))
))
(defspec map-keys-all-first-equivalence-transform
(for-all+
[m (limit-size 10 (gen/map gen/int gen/keyword))]
(= (transform s/MAP-KEYS inc m)
(transform [s/ALL s/FIRST] inc m )
)))
(defspec map-keys-all-first-equivalence-select
(for-all+
[m (limit-size 10 (gen/map gen/int gen/keyword))]
(= (select s/MAP-KEYS m)
(select [s/ALL s/FIRST] m)
)))