From 1c77126fe61d3ba7ff3a0abcef10836ab65a0f61 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 9 Apr 2025 15:57:07 +0200 Subject: [PATCH] :zap: Implement get-handlers in term of internal reduce That has an average performance improvement of 64% over original impl and reduction of generation of object garbage --- common/src/app/common/types/path/segment.cljc | 34 +++++++++---------- .../common_tests/types/path_data_test.cljc | 28 +++++++++++++++ .../app/main/data/workspace/path/drawing.cljs | 2 +- .../main/ui/workspace/shapes/path/editor.cljs | 5 +-- 4 files changed, 49 insertions(+), 20 deletions(-) diff --git a/common/src/app/common/types/path/segment.cljc b/common/src/app/common/types/path/segment.cljc index f5e082459..2bf9f471d 100644 --- a/common/src/app/common/types/path/segment.cljc +++ b/common/src/app/common/types/path/segment.cljc @@ -34,24 +34,24 @@ (gpt/point (get params cx) (get params cy))))) -;; FIXME: rename segments->handlers -(defn content->handlers +(defn get-handlers "Retrieve a map where for every point will retrieve a list of the handlers that are associated with that point. point -> [[index, prefix]]" [content] - (->> (d/with-prev content) - (d/enumerate) - (mapcat (fn [[index [cur-segment pre-segment]]] - (if (and pre-segment (= :curve-to (:command cur-segment))) - (let [cur-pos (helpers/segment->point cur-segment) - pre-pos (helpers/segment->point pre-segment)] - (-> [[pre-pos [index :c1]] - [cur-pos [index :c2]]])) - []))) - - (group-by first) - (d/mapm #(mapv second %2)))) + (let [prev-point* (volatile! nil) + vec-conj (fnil conj [])] + (impl/-reduce content + (fn [result index type _ _ _ _ x y] + (let [curr-point (gpt/point x y) + prev-point (deref prev-point*)] + (vreset! prev-point* curr-point) + (if (and prev-point (= :curve-to type)) + (-> result + (update prev-point vec-conj [index :c1]) + (update curr-point vec-conj [index :c2])) + result))) + {}))) (defn point-indices [content point] @@ -81,7 +81,7 @@ (helpers/segment->point (nth content index)) (helpers/segment->point (nth content (dec index)))) - point->handlers (content->handlers content) + point->handlers (get-handlers content) handlers (->> point (point->handlers) @@ -350,7 +350,7 @@ (defn make-corner-point "Changes the content to make a point a 'corner'" [content point] - (let [handlers (-> (content->handlers content) + (let [handlers (-> (get-handlers content) (get point)) change-content (fn [content [index prefix]] @@ -395,7 +395,7 @@ ;; FIXME: optimize (defn is-curve? [content point] - (let [handlers (-> (content->handlers content) + (let [handlers (-> (get-handlers content) (get point)) handler-points (map #(get-handler-point content (first %) (second %)) handlers)] (some #(not= point %) handler-points))) diff --git a/common/test/common_tests/types/path_data_test.cljc b/common/test/common_tests/types/path_data_test.cljc index 4e6c21da8..6aab6c335 100644 --- a/common/test/common_tests/types/path_data_test.cljc +++ b/common/test/common_tests/types/path_data_test.cljc @@ -340,3 +340,31 @@ (t/is (= result4 expect1)) (t/is (= result5 expect2)) (t/is (= result6 expect3)))) + + +(defn get-handlers + "Retrieve a map where for every point will retrieve a list of + the handlers that are associated with that point. + point -> [[index, prefix]]. + + Legacy impl" + [content] + (->> (d/with-prev content) + (d/enumerate) + (mapcat (fn [[index [cur-segment pre-segment]]] + (if (and pre-segment (= :curve-to (:command cur-segment))) + (let [cur-pos (path.helpers/segment->point cur-segment) + pre-pos (path.helpers/segment->point pre-segment)] + (-> [[pre-pos [index :c1]] + [cur-pos [index :c2]]])) + []))) + + (group-by first) + (d/mapm #(mapv second %2)))) + +(t/deftest content-to-handlers + (let [content (path/content sample-content-large) + result1 (get-handlers content) + result2 (path.segment/get-handlers content)] + + (t/is (= result1 result2)))) diff --git a/frontend/src/app/main/data/workspace/path/drawing.cljs b/frontend/src/app/main/data/workspace/path/drawing.cljs index 191e097b5..7d9eb3cdb 100644 --- a/frontend/src/app/main/data/workspace/path/drawing.cljs +++ b/frontend/src/app/main/data/workspace/path/drawing.cljs @@ -129,7 +129,7 @@ ptk/WatchEvent (watch [_ state stream] (let [content (st/get-path state :content) - handlers (-> (path.segment/content->handlers content) + handlers (-> (path.segment/get-handlers content) (get position)) [idx prefix] (when (= (count handlers) 1) diff --git a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs index f660d9334..56189d104 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs @@ -300,11 +300,12 @@ (mf/with-memo [content-points] (into #{} content-points)) - last-p (->> content last path.helpers/segment->point) + last-p + (->> content last path.helpers/segment->point) handlers (mf/with-memo [content] - (path.segment/content->handlers content)) + (path.segment/get-handlers content)) is-path-start (not (some? last-point))