major performnace enhancements for ALL on vectors (2x) and maps (10% for arraymas, 25% for hashmaps)

This commit is contained in:
Nathan Marz 2016-06-04 17:12:40 -04:00
parent 0bc26c950e
commit 86f05b3cbe
2 changed files with 72 additions and 24 deletions

View file

@ -1,6 +1,6 @@
## 0.11.1 (unreleased) ## 0.11.1 (unreleased)
* More efficient inline caching for Clojure version, now inline caching is always within 5% of manually precompiled code * More efficient inline caching for Clojure version, now inline caching is always within 5% of manually precompiled code
* Significant performance improvement for ALL transform on maps for Clojure version (25% on simple benchmarks) * Huge performance improvement for ALL transform on maps and vectors
* Significant performance improvements for FIRST/LAST for vectors * Significant performance improvements for FIRST/LAST for vectors
* Huge performance improvements for `if-path` and `cond-path` * Huge performance improvements for `if-path` and `cond-path`
* Eliminated compiler warnings for ClojureScript version * Eliminated compiler warnings for ClojureScript version

View file

@ -593,36 +593,84 @@
(defn queue? [coll] (defn queue? [coll]
(instance? clojure.lang.PersistentQueue coll)) (instance? clojure.lang.PersistentQueue coll))
#+clj (defprotocol AllTransformProtocol
(defn all-transform [structure next-fn] (all-transform [structure next-fn]))
(let [empty-structure (empty structure)]
(cond (and (list? empty-structure) (not (queue? empty-structure)))
;; this is done to maintain order, otherwise lists get reversed
(doall (map next-fn structure))
(map? structure) (defn- non-transient-map-all-transform [structure next-fn empty-map]
;; reduce-kv is much faster than doing r/map through call to (into ...) (reduce-kv
(reduce-kv (fn [m k v]
(fn [m k v] (let [[newk newv] (next-fn [k v])]
(let [[newk newv] (next-fn [k v])] (assoc m newk newv)
(assoc m newk newv) ))
)) empty-map
empty-structure structure
structure ))
)
:else (extend-protocol AllTransformProtocol
(->> structure (r/map next-fn) (into empty-structure)) #+clj clojure.lang.PersistentVector #+cljs cljs.core/PersistentVector
))) (all-transform [structure next-fn]
(mapv next-fn structure))
#+cljs #+clj clojure.lang.PersistentArrayMap #+cljs cljs.core/PersistentArrayMap
(defn all-transform [structure next-fn] (all-transform [structure next-fn]
(let [empty-structure (empty structure)] (non-transient-map-all-transform structure next-fn {})
(if (and (list? empty-structure) (not (queue? empty-structure))) )
#+clj clojure.lang.PersistentTreeMap #+cljs cljs.core/PersistentTreeMap
(all-transform [structure next-fn]
(non-transient-map-all-transform structure next-fn (sorted-map))
)
#+clj clojure.lang.PersistentHashMap #+cljs cljs.core/PersistentHashMap
(all-transform [structure next-fn]
(persistent!
(reduce-kv
(fn [m k v]
(let [[newk newv] (next-fn [k v])]
(assoc! m newk newv)
))
(transient
#+clj clojure.lang.PersistentHashMap/EMPTY #+cljs cljs.core.PersistentHashMap.EMPTY
)
structure
)))
#+clj
Object
#+clj
(all-transform [structure next-fn]
(let [empty-structure (empty structure)]
(cond (and (list? empty-structure) (not (queue? empty-structure)))
;; this is done to maintain order, otherwise lists get reversed
(doall (map next-fn structure))
(map? structure)
;; reduce-kv is much faster than doing r/map through call to (into ...)
(reduce-kv
(fn [m k v]
(let [[newk newv] (next-fn [k v])]
(assoc m newk newv)
))
empty-structure
structure
)
:else
(->> structure (r/map next-fn) (into empty-structure))
)))
#+cljs
default
#+cljs
(all-transform [structure next-fn]
(let [empty-structure (empty structure)]
(if (and (list? empty-structure) (not (queue? empty-structure)))
;; this is done to maintain order, otherwise lists get reversed ;; this is done to maintain order, otherwise lists get reversed
(doall (map next-fn structure)) (doall (map next-fn structure))
(into empty-structure (map #(next-fn %)) structure) (into empty-structure (map #(next-fn %)) structure)
))) )))
)
(deftype AllNavigator []) (deftype AllNavigator [])