mirror of
https://github.com/penpot/penpot.git
synced 2026-09-15 00:19:01 +00:00
⚡ Add cache and faster way to iterate over PathData
This commit is contained in:
parent
4f6dffabb4
commit
230e330eb2
@ -7,9 +7,12 @@
|
|||||||
(ns app.common.types.path.impl
|
(ns app.common.types.path.impl
|
||||||
"Contains schemas and data type implementation for PathData binary
|
"Contains schemas and data type implementation for PathData binary
|
||||||
and plain formats"
|
and plain formats"
|
||||||
|
#?(:cljs
|
||||||
|
(:require-macros [app.common.types.path.impl]))
|
||||||
(:require
|
(:require
|
||||||
#?(:clj [app.common.fressian :as fres])
|
#?(:clj [app.common.fressian :as fres])
|
||||||
#?(:clj [clojure.data.json :as json])
|
#?(:clj [clojure.data.json :as json])
|
||||||
|
#?(:cljs [app.common.weak-map :as weak-map])
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.schema.generators :as sg]
|
[app.common.schema.generators :as sg]
|
||||||
@ -29,7 +32,8 @@
|
|||||||
(-get-byte-size [_] "get byte size"))
|
(-get-byte-size [_] "get byte size"))
|
||||||
|
|
||||||
(defprotocol ITransformable
|
(defprotocol ITransformable
|
||||||
(-transform [_ m] "apply a transform"))
|
(-transform [_ m] "apply a transform")
|
||||||
|
(-walk [_ f]))
|
||||||
|
|
||||||
(defn- transform!
|
(defn- transform!
|
||||||
"Apply a transformation to a segment located under specified offset"
|
"Apply a transformation to a segment located under specified offset"
|
||||||
@ -215,8 +219,28 @@
|
|||||||
(.set dst-view src-view)
|
(.set dst-view src-view)
|
||||||
dst-buff)))
|
dst-buff)))
|
||||||
|
|
||||||
|
(defmacro with-cache
|
||||||
|
"A helper macro that facilitates cache handling for content
|
||||||
|
instance"
|
||||||
|
[target key & expr]
|
||||||
|
(if (:ns &env)
|
||||||
|
(let [cache (gensym "cache-")
|
||||||
|
target (with-meta target {:tag 'js})]
|
||||||
|
`(let [~cache (.-cache ~target)
|
||||||
|
~'result (.get ~cache ~key)]
|
||||||
|
(if ~'result
|
||||||
|
(do
|
||||||
|
~'result)
|
||||||
|
(let [~'result (do ~@expr)]
|
||||||
|
(.set ~cache ~key ~'result)
|
||||||
|
~'result))))
|
||||||
|
`(do ~@expr)))
|
||||||
|
|
||||||
|
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(deftype PathData [size buffer ^:unsynchronized-mutable hash]
|
(deftype PathData [size
|
||||||
|
^ByteBuffer buffer
|
||||||
|
^:unsynchronized-mutable hash]
|
||||||
Object
|
Object
|
||||||
(toString [_]
|
(toString [_]
|
||||||
(to-string buffer size))
|
(to-string buffer size))
|
||||||
@ -236,6 +260,30 @@
|
|||||||
(recur (inc index)))))
|
(recur (inc index)))))
|
||||||
(PathData. size buffer nil)))
|
(PathData. size buffer nil)))
|
||||||
|
|
||||||
|
(-walk [_ f]
|
||||||
|
(loop [index 0
|
||||||
|
result (transient [])]
|
||||||
|
(if (< index size)
|
||||||
|
(let [offset (* index SEGMENT-BYTE-SIZE)
|
||||||
|
type (.getShort ^ByteBuffer buffer offset)
|
||||||
|
c1x (.getFloat ^ByteBuffer buffer (+ offset 4))
|
||||||
|
c1y (.getFloat ^ByteBuffer buffer (+ offset 8))
|
||||||
|
c2x (.getFloat ^ByteBuffer buffer (+ offset 12))
|
||||||
|
c2y (.getFloat ^ByteBuffer buffer (+ offset 16))
|
||||||
|
x (.getFloat ^ByteBuffer buffer (+ offset 20))
|
||||||
|
y (.getFloat ^ByteBuffer buffer (+ offset 24))
|
||||||
|
type (case type
|
||||||
|
1 :line-to
|
||||||
|
2 :move-to
|
||||||
|
3 :curve-to
|
||||||
|
4 :close-path)
|
||||||
|
res (f type c1x c1y c2x c2y x y)]
|
||||||
|
(recur (inc index)
|
||||||
|
(if (some? res)
|
||||||
|
(conj! result res)
|
||||||
|
result)))
|
||||||
|
(persistent! result))))
|
||||||
|
|
||||||
json/JSONWriter
|
json/JSONWriter
|
||||||
(-write [this writter options]
|
(-write [this writter options]
|
||||||
(json/-write (.toString this) writter options))
|
(json/-write (.toString this) writter options))
|
||||||
@ -290,7 +338,7 @@
|
|||||||
|
|
||||||
:cljs
|
:cljs
|
||||||
#_:clj-kondo/ignore
|
#_:clj-kondo/ignore
|
||||||
(deftype PathData [size buffer dview ^:mutable __hash]
|
(deftype PathData [size buffer dview cache ^:mutable __hash]
|
||||||
Object
|
Object
|
||||||
(toString [_]
|
(toString [_]
|
||||||
(to-string dview size))
|
(to-string dview size))
|
||||||
@ -317,7 +365,33 @@
|
|||||||
(let [offset (* index SEGMENT-BYTE-SIZE)]
|
(let [offset (* index SEGMENT-BYTE-SIZE)]
|
||||||
(transform! dview offset m)
|
(transform! dview offset m)
|
||||||
(recur (inc index)))))
|
(recur (inc index)))))
|
||||||
(PathData. size buffer dview nil)))
|
(PathData. size buffer dview (weak-map/create) nil)))
|
||||||
|
|
||||||
|
(-walk [_ f]
|
||||||
|
(let [farray (js/Float32Array. buffer)
|
||||||
|
iarray (js/Int32Array. buffer)]
|
||||||
|
(loop [index 0
|
||||||
|
result (transient [])]
|
||||||
|
(if (< index size)
|
||||||
|
(let [offset (* index SEGMENT-BYTE-SIZE)
|
||||||
|
type (.getInt16 dview offset)
|
||||||
|
c1x (.getFloat32 dview (+ offset 4))
|
||||||
|
c1y (.getFloat32 dview (+ offset 8))
|
||||||
|
c2x (.getFloat32 dview (+ offset 12))
|
||||||
|
c2y (.getFloat32 dview (+ offset 16))
|
||||||
|
x (.getFloat32 dview (+ offset 20))
|
||||||
|
y (.getFloat32 dview (+ offset 24))
|
||||||
|
type (case type
|
||||||
|
1 :line-to
|
||||||
|
2 :move-to
|
||||||
|
3 :curve-to
|
||||||
|
4 :close-path)
|
||||||
|
res (f type c1x c1y c2x c2y x y)]
|
||||||
|
(recur (inc index)
|
||||||
|
(if (some? res)
|
||||||
|
(conj! result res)
|
||||||
|
result)))
|
||||||
|
(persistent! result)))))
|
||||||
|
|
||||||
cljs.core/ISequential
|
cljs.core/ISequential
|
||||||
cljs.core/IEquiv
|
cljs.core/IEquiv
|
||||||
@ -383,8 +457,11 @@
|
|||||||
cljs.core/ISeqable
|
cljs.core/ISeqable
|
||||||
(-seq [this]
|
(-seq [this]
|
||||||
(when (pos? size)
|
(when (pos? size)
|
||||||
(->> (range size)
|
((fn next-seq [i]
|
||||||
(map (fn [i] (cljs.core/-nth this i))))))
|
(when (< i size)
|
||||||
|
(cons (read-segment dview i)
|
||||||
|
(lazy-seq (next-seq (inc i))))))
|
||||||
|
0)))
|
||||||
|
|
||||||
cljs.core/IPrintWithWriter
|
cljs.core/IPrintWithWriter
|
||||||
(-pr-writer [this writer _]
|
(-pr-writer [this writer _]
|
||||||
@ -526,6 +603,7 @@
|
|||||||
(PathData. count
|
(PathData. count
|
||||||
buffer
|
buffer
|
||||||
(js/DataView. buffer)
|
(js/DataView. buffer)
|
||||||
|
(weak-map/create)
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
(instance? js/DataView buffer)
|
(instance? js/DataView buffer)
|
||||||
@ -533,7 +611,7 @@
|
|||||||
buffer (.-buffer dview)
|
buffer (.-buffer dview)
|
||||||
size (.-byteLength buffer)
|
size (.-byteLength buffer)
|
||||||
count (long (/ size SEGMENT-BYTE-SIZE))]
|
count (long (/ size SEGMENT-BYTE-SIZE))]
|
||||||
(PathData. count buffer dview nil))
|
(PathData. count buffer dview (weak-map/create) nil))
|
||||||
|
|
||||||
(instance? js/Uint8Array buffer)
|
(instance? js/Uint8Array buffer)
|
||||||
(from-bytes (.-buffer buffer))
|
(from-bytes (.-buffer buffer))
|
||||||
|
|||||||
29
common/src/app/common/weak_map.cljs
Normal file
29
common/src/app/common/weak_map.cljs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.common.weak-map
|
||||||
|
"A value based weak-map implementation (CLJS/JS)")
|
||||||
|
|
||||||
|
(deftype ValueWeakMap [^js/Map data ^js/FinalizationRegistry registry]
|
||||||
|
Object
|
||||||
|
(clear [_]
|
||||||
|
(.clear data))
|
||||||
|
(delete [_ key]
|
||||||
|
(.delete data key))
|
||||||
|
(get [_ key]
|
||||||
|
(if-let [ref (.get data key)]
|
||||||
|
(.deref ^WeakRef ref)
|
||||||
|
nil))
|
||||||
|
(set [_ key val]
|
||||||
|
(.set data key (js/WeakRef. val))
|
||||||
|
(.register registry val key)
|
||||||
|
nil))
|
||||||
|
|
||||||
|
(defn create
|
||||||
|
[]
|
||||||
|
(let [data (js/Map.)
|
||||||
|
registry (js/FinalizationRegistry. #(.delete data %))]
|
||||||
|
(ValueWeakMap. data registry)))
|
||||||
Loading…
x
Reference in New Issue
Block a user