From fe258f77478444cab1ca86827b90de318f62c3eb Mon Sep 17 00:00:00 2001 From: Oleksandr Yakushev Date: Sat, 14 Sep 2024 00:04:47 +0300 Subject: [PATCH] [dispatcher] Optimize primary method calculation --- src/methodical/impl/dispatcher/common.clj | 24 +++++++----- .../impl/dispatcher/multi_default.clj | 39 ++++++++----------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/methodical/impl/dispatcher/common.clj b/src/methodical/impl/dispatcher/common.clj index 3e73032..56c0cf1 100644 --- a/src/methodical/impl/dispatcher/common.clj +++ b/src/methodical/impl/dispatcher/common.clj @@ -65,13 +65,17 @@ (defn distinct-by "Like `distinct`, but uses value of `(f item)` to determine whether to keep each `item` in the resulting collection." - [f coll] - (first - (reduce - (fn [[items already-seen? :as acc] item] - (let [v (f item)] - (if (already-seen? v) - acc - [(conj items item) (conj already-seen? v)]))) - [[] #{}] - coll))) + ([f] + (fn [rf] + (let [seen (volatile! #{})] + (fn + ([] (rf)) + ([result] (rf result)) + ([result input] + (let [v (f input)] + (if (contains? @seen v) + result + (do (vswap! seen conj v) + (rf result input))))))))) + ([f coll] + (into [] (distinct-by f) coll))) diff --git a/src/methodical/impl/dispatcher/multi_default.clj b/src/methodical/impl/dispatcher/multi_default.clj index 4ae3465..cb47e31 100644 --- a/src/methodical/impl/dispatcher/multi_default.clj +++ b/src/methodical/impl/dispatcher/multi_default.clj @@ -34,12 +34,13 @@ ;; 1 | 01 | [:default :y] ;; 0 | 00 | [:default :default] (let [cnt (count dispatch-value)] - (for [i (reverse (range (dec (int (Math/pow 2 cnt)))))] - (vec - (for [j (reverse (range 0 cnt))] - (if (pos? (bit-and i (bit-shift-left 1 j))) - (nth dispatch-value (- cnt j 1)) - default-value)))))) + (mapv (fn [i] + (mapv (fn [j] + (if (pos? (bit-and i (bit-shift-left 1 j))) + (nth dispatch-value (- cnt j 1)) + default-value)) + (range (dec cnt) -1 -1))) + (range (- (int (Math/pow 2 cnt)) 2) -1 -1)))) (defn partially-specialized-default-dispatch-values "Return a sequence of all partially-specialized default dispatch values for a given `dispatch-value` and @@ -57,27 +58,21 @@ (not (sequential? default-value))) (partially-specialized-default-dispatch-values* dispatch-value default-value))) -(defn- matching-partially-specialized-default-primary-method-pairs* - [{:keys [default-value dispatch-value unambiguous-pairs-seq-fn] - :or {unambiguous-pairs-seq-fn dispatcher.standard/unambiguous-pairs-seq} - :as opts}] - (mapcat - (fn [partial-default] - (let [pairs (dispatcher.standard/matching-primary-pairs-excluding-default - (assoc opts :dispatch-value partial-default))] - (unambiguous-pairs-seq-fn opts pairs))) - (partially-specialized-default-dispatch-values dispatch-value default-value))) - (defn matching-partially-specialized-default-primary-method-pairs "Return pairs of `[dispatch-value method]` for all matching partially-specialized default methods, sorted from most-specific to least-specific" ;; TODO - this is too many args! [opts standard-dispatch-vals] - (->> (matching-partially-specialized-default-primary-method-pairs* opts) - (dispatcher.common/distinct-by first) - (remove - (fn [[dispatch-val]] - (contains? standard-dispatch-vals dispatch-val))))) + (let [{:keys [default-value dispatch-value unambiguous-pairs-seq-fn] + :or {unambiguous-pairs-seq-fn dispatcher.standard/unambiguous-pairs-seq}} opts] + (into [] + (comp (mapcat (fn [partial-default] + (let [pairs (dispatcher.standard/matching-primary-pairs-excluding-default + (assoc opts :dispatch-value partial-default))] + (unambiguous-pairs-seq-fn opts pairs)))) + (dispatcher.common/distinct-by first) + (remove (fn [[dispatch-val]] (contains? standard-dispatch-vals dispatch-val)))) + (partially-specialized-default-dispatch-values dispatch-value default-value)))) (defn matching-primary-methods "Return a lazy sequence of applicable priamry methods for `dispatch-value`, sorted from most-specific to