From bed82e10d3ab4af51958dd5c425b865bee5e9d99 Mon Sep 17 00:00:00 2001 From: Ben Sless Date: Tue, 24 Aug 2021 19:16:31 +0300 Subject: [PATCH 1/2] Add lightweight keyset wrapper Saves on allocation and provides an immutable facade to underlying regular set --- src/malli/core.cljc | 49 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/malli/core.cljc b/src/malli/core.cljc index eeb69fdf4..2ab600023 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -278,14 +278,49 @@ (-arange [^objects arr to] #?(:clj (let [-arr (object-array to)] (System/arraycopy arr 0 -arr 0 to) -arr) :cljs (.slice arr 0 to))) + #?(:clj + (-set-wrapper + [^java.util.Set s] + (reify + Collection + (size [_] (.size s)) + (containsAll [_ c] (.containsAll s c)) + clojure.lang.IPersistentSet + (disjoin [_ key] (disj (set s) key)) + (contains [_ key] (.contains s key)) + (get [_ key] (when (.contains s key) key)) + clojure.lang.Counted + (count [_] (.size s)) + clojure.lang.IPersistentCollection + (cons [_ o] (.cons (set s) o)) + (empty [_] #{}) + (equiv [_ o] + (if (instance? java.util.Set o) + (if (== (.size s) (.size ^Collection o)) + (.containsAll s o) + false) + false)) + clojure.lang.Seqable + (seq [_] (seq s)) + clojure.lang.IFn + (invoke [_ o] (when (.contains s o) o)) + Iterable + (iterator [_] (.iterator s))))) (-keyset [] - (let [data (volatile! #{})] - (fn - ([] @data) - ([k] (let [old @data] - (vswap! data conj k) - (when (= old @data) - (-fail! ::non-distinct-entry-keys {:keys old, :key k})))))))] + #?(:clj + (let [data (java.util.HashSet.)] + (fn + ([] (-set-wrapper data)) + ([k] (when-not (.add data k) + (-fail! ::non-distinct-entry-keys {:keys (seq data), :key k}))))) + :cljs + (let [data (volatile! #{})] + (fn + ([] @data) + ([k] (let [old @data] + (vswap! data conj k) + (when (= old @data) + (-fail! ::non-distinct-entry-keys {:keys old, :key k}))))))))] (let [n (count children) -children (object-array n) -entries (object-array n) From 2e872b674a74404f65ce44541c02fe9ec6f0b44a Mon Sep 17 00:00:00 2001 From: Ben Sless Date: Tue, 24 Aug 2021 19:41:43 +0300 Subject: [PATCH 2/2] Tune hash set initial capacity and load factor --- src/malli/core.cljc | 124 ++++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/src/malli/core.cljc b/src/malli/core.cljc index 2ab600023..0eee6b578 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -272,69 +272,69 @@ (-fail! ::invalid-ref {:ref e}))))) (defn -parse-entries [children {:keys [naked-keys lazy-refs]} options] - (letfn [(-arr->vec [^objects arr] - #?(:clj (LazilyPersistentVector/createOwning arr) - :cljs (vec arr))) - (-arange [^objects arr to] - #?(:clj (let [-arr (object-array to)] (System/arraycopy arr 0 -arr 0 to) -arr) - :cljs (.slice arr 0 to))) - #?(:clj - (-set-wrapper - [^java.util.Set s] - (reify - Collection - (size [_] (.size s)) - (containsAll [_ c] (.containsAll s c)) - clojure.lang.IPersistentSet - (disjoin [_ key] (disj (set s) key)) - (contains [_ key] (.contains s key)) - (get [_ key] (when (.contains s key) key)) - clojure.lang.Counted - (count [_] (.size s)) - clojure.lang.IPersistentCollection - (cons [_ o] (.cons (set s) o)) - (empty [_] #{}) - (equiv [_ o] - (if (instance? java.util.Set o) - (if (== (.size s) (.size ^Collection o)) - (.containsAll s o) - false) - false)) - clojure.lang.Seqable - (seq [_] (seq s)) - clojure.lang.IFn - (invoke [_ o] (when (.contains s o) o)) - Iterable - (iterator [_] (.iterator s))))) - (-keyset [] + (let [n (count children)] + (letfn [(-arr->vec [^objects arr] + #?(:clj (LazilyPersistentVector/createOwning arr) + :cljs (vec arr))) + (-arange [^objects arr to] + #?(:clj (let [-arr (object-array to)] (System/arraycopy arr 0 -arr 0 to) -arr) + :cljs (.slice arr 0 to))) #?(:clj - (let [data (java.util.HashSet.)] - (fn - ([] (-set-wrapper data)) - ([k] (when-not (.add data k) - (-fail! ::non-distinct-entry-keys {:keys (seq data), :key k}))))) - :cljs - (let [data (volatile! #{})] - (fn - ([] @data) - ([k] (let [old @data] - (vswap! data conj k) - (when (= old @data) - (-fail! ::non-distinct-entry-keys {:keys old, :key k}))))))))] - (let [n (count children) - -children (object-array n) - -entries (object-array n) - -forms (object-array n) - -keyset (-keyset)] - (loop [i (int 0), ci (int 0)] - (if (== ci n) - (let [f (if (== ci i) -arr->vec #(-arr->vec (-arange % i)))] - {:children (f -children) - :entries (f -entries) - :forms (f -forms) - :keyset (-keyset)}) - (recur (-parse-entry (nth children i) naked-keys lazy-refs options i -children -entries -forms -keyset) - (unchecked-inc-int ci))))))) + (-set-wrapper + [^java.util.Set s] + (reify + Collection + (size [_] (.size s)) + (containsAll [_ c] (.containsAll s c)) + clojure.lang.IPersistentSet + (disjoin [_ key] (disj (set s) key)) + (contains [_ key] (.contains s key)) + (get [_ key] (when (.contains s key) key)) + clojure.lang.Counted + (count [_] (.size s)) + clojure.lang.IPersistentCollection + (cons [_ o] (.cons (set s) o)) + (empty [_] #{}) + (equiv [_ o] + (if (instance? java.util.Set o) + (if (== (.size s) (.size ^Collection o)) + (.containsAll s o) + false) + false)) + clojure.lang.Seqable + (seq [_] (seq s)) + clojure.lang.IFn + (invoke [_ o] (when (.contains s o) o)) + Iterable + (iterator [_] (.iterator s))))) + (-keyset [] + #?(:clj + (let [data (java.util.HashSet. (unchecked-multiply-int n 4) 0.25)] + (fn + ([] (-set-wrapper data)) + ([k] (when-not (.add data k) + (-fail! ::non-distinct-entry-keys {:keys (seq data), :key k}))))) + :cljs + (let [data (volatile! #{})] + (fn + ([] @data) + ([k] (let [old @data] + (vswap! data conj k) + (when (= old @data) + (-fail! ::non-distinct-entry-keys {:keys old, :key k}))))))))] + (let [-children (object-array n) + -entries (object-array n) + -forms (object-array n) + -keyset (-keyset)] + (loop [i (int 0), ci (int 0)] + (if (== ci n) + (let [f (if (== ci i) -arr->vec #(-arr->vec (-arange % i)))] + {:children (f -children) + :entries (f -entries) + :forms (f -forms) + :keyset (-keyset)}) + (recur (-parse-entry (nth children i) naked-keys lazy-refs options i -children -entries -forms -keyset) + (unchecked-inc-int ci)))))))) (defn -guard [pred tf] (when tf (fn [x] (if (pred x) (tf x) x))))