-
Notifications
You must be signed in to change notification settings - Fork 256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimize CollectionSpec checker #436
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,19 +23,18 @@ | |
(let [_ (macros/assert! (= 2 (count e)) "remaining can have only one schema.") | ||
c (spec/sub-checker (second e) params)] | ||
#?(:clj (fn [^java.util.List res x] | ||
(doseq [i x] | ||
(.add res (c i))) | ||
(reduce (fn [res i] (doto res (.add (c i)))) res x) | ||
(then res nil)) | ||
:cljs (fn [res x] | ||
(swap! res into (map c x)) | ||
(reduce (fn [res i] (doto res (.push (c i)))) res x) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe that something mutable could be faster here, but I'm again unsure about the use of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
(then res nil))))) | ||
|
||
(let [parser (:parser e) | ||
c (spec/sub-checker e params)] | ||
#?(:clj (fn [^java.util.List res x] | ||
(then res (parser (fn [t] (.add res (if (utils/error? t) t (c t)))) x))) | ||
:cljs (fn [res x] | ||
(then res (parser (fn [t] (swap! res conj (if (utils/error? t) t (c t)))) x))))))) | ||
(then res (parser (fn [t] (.push res (if (utils/error? t) t (c t)))) x))))))) | ||
|
||
(defn- sequence-transformer [elts params then] | ||
(macros/assert! (not-any? #(and (vector? %) (= (first %) ::remaining)) (butlast elts)) | ||
|
@@ -58,7 +57,7 @@ | |
|
||
:cljs | ||
(defn- has-error? [l] | ||
(some utils/error? l))) | ||
(.some l utils/error?))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not super familiar with cljs, can you explain the change here please? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. Is that expected to be appreciably faster? |
||
|
||
(defn subschemas [elt] | ||
(if (map? elt) | ||
|
@@ -75,9 +74,8 @@ | |
t (sequence-transformer elements params (fn [_ x] x))] | ||
(fn [x] | ||
(or (pre x) | ||
(let [res #?(:clj (java.util.ArrayList.) :cljs (atom [])) | ||
remaining (t res x) | ||
res #?(:clj res :cljs @res)] | ||
(let [res #?(:clj (java.util.ArrayList.) :cljs #js []) | ||
remaining (t res x)] | ||
(if (or (seq remaining) (has-error? res)) | ||
(utils/error (on-error x res remaining)) | ||
(constructor res)))))))) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this expected to be faster? The
List
can't be used safely concurrently so I would be surprised if you could do better than thedoseq
. Have you profiled and seen a speedup?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reduce
(andrun!
) is faster and more memory efficient because as an internal iterator it can be fully specialized to the collection and usually does not need to allocate at all. I have profiled it sometime but by now it is just a habit like using(into [] (map ...) x)
instead of(into [] (map ... x))
. Sincereduce
works on all seqs really the only reason to ever usedoseq
is if:when
/:while
/:let
is super useful.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The weird thing about
reduce
here is that it's threading through an extra argument that you don't care about because you're mutating the argument anyway. I think it makes the code slightly less clear and I would be a bit surprised if there was a performance benefit, but I'd be happy to believe it if there were accompanying measurements.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth comparing to
(reduce #(.add res (c %2))) nil x)
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, it would probably beat the current code handily since I don't see a type hint on the inner
res
.EDIT: I've added a reflection check to the master build.
EDIT2: Of course I missed the
doto
propagating the type hint, nevermind.