From 81ec559e69bbdbb0bd3cbc135c571cbea2158ec5 Mon Sep 17 00:00:00 2001 From: Nathan Marz Date: Tue, 7 Jun 2016 10:31:07 -0400 Subject: [PATCH 1/4] docstring for MAP-VALS --- src/clj/com/rpl/specter.cljx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/clj/com/rpl/specter.cljx b/src/clj/com/rpl/specter.cljx index 9d7bac2..b655a15 100644 --- a/src/clj/com/rpl/specter.cljx +++ b/src/clj/com/rpl/specter.cljx @@ -163,9 +163,15 @@ ALL (comp-paths (i/->AllNavigator))) -(defnav MAP-VALS [] +(defnav + ^{:doc "Navigate to each value of the map. This is more efficient than + navigating via [ALL LAST]"} + MAP-VALS + [] (select* [this structure next-fn] - (doall (mapcat next-fn (vals structure)))) + (doseqres NONE [v (vals structure)] + (next-fn v) + )) (transform* [this structure next-fn] (i/map-vals-transform structure next-fn) )) From 205b6a13193092ad990df22efb30575f4ac01545 Mon Sep 17 00:00:00 2001 From: Nathan Marz Date: Tue, 7 Jun 2016 10:51:08 -0400 Subject: [PATCH 2/4] fix MAP-VALS --- src/clj/com/rpl/specter.cljx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/clj/com/rpl/specter.cljx b/src/clj/com/rpl/specter.cljx index b655a15..dc794c9 100644 --- a/src/clj/com/rpl/specter.cljx +++ b/src/clj/com/rpl/specter.cljx @@ -169,9 +169,7 @@ MAP-VALS [] (select* [this structure next-fn] - (doseqres NONE [v (vals structure)] - (next-fn v) - )) + (doall (mapcat next-fn (vals structure)))) (transform* [this structure next-fn] (i/map-vals-transform structure next-fn) )) From c28245b4200c5ff8b4e51361b49fa1f50cd86b33 Mon Sep 17 00:00:00 2001 From: Nathan Marz Date: Tue, 7 Jun 2016 14:40:31 -0400 Subject: [PATCH 3/4] add protocols ns to api docs --- project.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 9f2ab74..a646ba8 100644 --- a/project.clj +++ b/project.clj @@ -14,7 +14,8 @@ :codox {:source-paths ["target/classes" "src/clj"] :namespaces [com.rpl.specter com.rpl.specter.macros - com.rpl.specter.zipper] + com.rpl.specter.zipper + com.rpl.specter.protocols] :source-uri {#"target/classes" "https://github.com/nathanmarz/specter/tree/{version}/src/clj/{classpath}x#L{line}" #".*" "https://github.com/nathanmarz/specter/tree/{version}/src/clj/{classpath}#L{line}" From 5161f6dfbfa5d1919170b351a5d1723de2c51be0 Mon Sep 17 00:00:00 2001 From: Nathan Marz Date: Tue, 7 Jun 2016 16:07:01 -0400 Subject: [PATCH 4/4] optimize END for vectors --- CHANGES.md | 1 + scripts/benchmarks.clj | 8 ++++++-- src/clj/com/rpl/specter.cljx | 22 +++++++++++++++++----- src/clj/com/rpl/specter/impl.cljx | 24 ++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f20b99c..71152b0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,7 @@ * Huge performance improvement for ALL transform on maps and vectors * Significant performance improvements for FIRST/LAST for vectors * Huge performance improvements for `if-path`, `cond-path`, `selected?`, and `not-selected?`, especially for condition path containing only static functions +* Huge performance improvement for `END` on vectors * Added specialized MAP-VALS navigator that is twice as fast as using [ALL LAST] * Eliminated compiler warnings for ClojureScript version * Dropped support for Clojurescript below v1.7.10 diff --git a/scripts/benchmarks.clj b/scripts/benchmarks.clj index e93357e..35484b0 100644 --- a/scripts/benchmarks.clj +++ b/scripts/benchmarks.clj @@ -49,8 +49,6 @@ (println "\n********************************\n") ))) - - (let [data {:a {:b {:c 1}}} p (comp-paths :a :b :c)] (run-benchmark "get value in nested map" 10000000 @@ -87,6 +85,12 @@ (transform ALL inc data) )) +(let [v (vec (range 1000))] + (run-benchmark "END on large vector" + 5000000 + (setval END [1] v) + (reduce conj v [1]) + (conj v 1))) (defn- update-pair [[k v]] [k (inc v)]) diff --git a/src/clj/com/rpl/specter.cljx b/src/clj/com/rpl/specter.cljx index dc794c9..d55b8e9 100644 --- a/src/clj/com/rpl/specter.cljx +++ b/src/clj/com/rpl/specter.cljx @@ -229,16 +229,28 @@ (reverse (i/matching-ranges structure pred)) ))) -(def +(defnav ^{:doc "Navigate to the empty subsequence before the first element of the collection."} BEGINNING - (srange 0 0)) + [] + (select* [this structure next-fn] + (next-fn [])) + (transform* [this structure next-fn] + (let [to-prepend (next-fn [])] + (i/prepend-all structure to-prepend) + ))) -(def +(defnav ^{:doc "Navigate to the empty subsequence after the last element of the collection."} END - (srange-dynamic count count)) - + [] + (select* [this structure next-fn] + (next-fn [])) + (transform* [this structure next-fn] + (let [to-append (next-fn [])] + (i/append-all structure to-append) + ))) + (defnav ^{:doc "Navigates to the specified subset (by taking an intersection). In a transform, that subset in the original set is changed to the diff --git a/src/clj/com/rpl/specter/impl.cljx b/src/clj/com/rpl/specter/impl.cljx index c1db2ed..b401e79 100644 --- a/src/clj/com/rpl/specter/impl.cljx +++ b/src/clj/com/rpl/specter/impl.cljx @@ -448,6 +448,30 @@ (defn- append [coll elem] (-> coll vec (conj elem))) +(defprotocol AddExtremes + (append-all [structure elements]) + (prepend-all [structure elements])) + +(extend-protocol AddExtremes + #+clj clojure.lang.PersistentVector #+cljs cljs.core/PersistentVector + (append-all [structure elements] + (reduce conj structure elements)) + (prepend-all [structure elements] + (let [ret (transient [])] + (as-> ret <> + (reduce conj! <> elements) + (reduce conj! <> structure) + (persistent! <>) + ))) + + #+clj Object #+cljs default + (append-all [structure elements] + (concat structure elements)) + (prepend-all [structure elements] + (concat elements structure)) + ) + + (defprotocol UpdateExtremes (update-first [s afn]) (update-last [s afn]))