From edfcc92a85cddb9b7b96be8ffca73adb61e8331a Mon Sep 17 00:00:00 2001 From: Nathan Marz Date: Wed, 1 Jun 2016 12:27:02 -0400 Subject: [PATCH] big optimization for LAST for small vectors (e.g. those used for mapentries) --- src/clj/com/rpl/specter/impl.cljx | 33 +++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/clj/com/rpl/specter/impl.cljx b/src/clj/com/rpl/specter/impl.cljx index 1cc8cde..7ec5195 100644 --- a/src/clj/com/rpl/specter/impl.cljx +++ b/src/clj/com/rpl/specter/impl.cljx @@ -447,12 +447,23 @@ (get-first [s]) (get-last [s])) +(defprotocol FastEmpty + (fast-empty? [s])) + (defn- update-first-list [l afn] (cons (afn (first l)) (rest l))) (defn- update-last-list [l afn] (append (butlast l) (afn (last l)))) +#+clj +(defn vec-count [^clojure.lang.PersistentVector v] + (.count v)) + +#+cljs +(defn vec-count [v] + (count v)) + (extend-protocol UpdateExtremes #+clj clojure.lang.PersistentVector #+cljs cljs.core/PersistentVector (update-first [v afn] @@ -460,8 +471,12 @@ (assoc v 0 (afn val)) )) (update-last [v afn] - (conj (pop v) (afn (peek v))) - ) + (let [c (vec-count v)] + (case c + 1 (let [[e] v] [(afn e)]) + 2 (let [[e1 e2] v] [e1 (afn e2)]) + (conj (pop v) (afn (peek v))) + ))) #+clj Object #+cljs default (update-first [l val] (update-first-list l val)) @@ -482,6 +497,16 @@ (last s) )) + +(extend-protocol FastEmpty + #+clj clojure.lang.PersistentVector #+cljs cljs.core/PersistentVector + (fast-empty? [v] + (= 0 (vec-count v))) + #+clj Object #+cljs default + (fast-empty? [s] + (empty? s)) + ) + (defn walk-until [pred on-match-fn structure] (if (pred structure) (on-match-fn structure) @@ -617,10 +642,10 @@ (extend-protocol p/Navigator PosNavigator (select* [this structure next-fn] - (if-not (empty? structure) + (if-not (fast-empty? structure) (next-fn ((.-getter this) structure)))) (transform* [this structure next-fn] - (if (empty? structure) + (if (fast-empty? structure) structure ((.-updater this) structure next-fn))))