Skip to content

Commit 3977b13

Browse files
ducky427dnolen
authored andcommitted
Optimize seq (&) destructuring as per commit (0aa3467) of Clojure
1 parent 2f012ce commit 3977b13

File tree

2 files changed

+57
-32
lines changed

2 files changed

+57
-32
lines changed

benchmark/cljs/benchmark_runner.cljs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,12 @@
379379
(simple-benchmark [f array] (f 1 2 3 4 5 6 7 8 9 0) 100000)
380380
(simple-benchmark [f vector] (f 1 2 3 4 5 6 7 8 9 0) 100000)
381381
(simple-benchmark [] (= 1 1 1 1 1 1 1 1 1 0) 100000)
382+
383+
(println "\n")
384+
(println ";; Destructuring a sequence")
385+
(simple-benchmark [v (into [] (range 1000000))]
386+
(loop [[x & xs] v]
387+
(if-not (nil? xs)
388+
(recur xs)
389+
x))
390+
10)

src/main/clojure/cljs/core.cljc

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -612,63 +612,79 @@
612612
pb (core/fn pb [bvec b v]
613613
(core/let [pvec
614614
(core/fn [bvec b val]
615-
(core/let [gvec (gensym "vec__")]
616-
(core/loop [ret (core/-> bvec (conj gvec) (conj val))
615+
(core/let [gvec (gensym "vec__")
616+
gseq (gensym "seq__")
617+
gfirst (gensym "first__")
618+
has-rest (some #{'&} b)]
619+
(core/loop [ret (core/let [ret (conj bvec gvec val)]
620+
(if has-rest
621+
(conj ret gseq (core/list `seq gvec))
622+
ret))
617623
n 0
618624
bs b
619625
seen-rest? false]
620626
(if (seq bs)
621627
(core/let [firstb (first bs)]
622628
(core/cond
623-
(= firstb '&) (recur (pb ret (second bs) (core/list `nthnext gvec n))
624-
n
625-
(nnext bs)
626-
true)
629+
(= firstb '&) (recur (pb ret (second bs) gseq)
630+
n
631+
(nnext bs)
632+
true)
627633
(= firstb :as) (pb ret (second bs) gvec)
628634
:else (if seen-rest?
629-
(throw
630-
#?(:clj (new Exception "Unsupported binding form, only :as can follow & parameter")
631-
:cljs (new js/Error "Unsupported binding form, only :as can follow & parameter")))
632-
(recur (pb ret firstb (core/list `nth gvec n nil))
633-
(core/inc n)
634-
(next bs)
635-
seen-rest?))))
635+
(throw #?(:clj (new Exception "Unsupported binding form, only :as can follow & parameter")
636+
:cljs (new js/Error "Unsupported binding form, only :as can follow & parameter")))
637+
(recur (pb (if has-rest
638+
(conj ret
639+
gfirst `(first ~gseq)
640+
gseq `(next ~gseq))
641+
ret)
642+
firstb
643+
(if has-rest
644+
gfirst
645+
(core/list `nth gvec n nil)))
646+
(core/inc n)
647+
(next bs)
648+
seen-rest?))))
636649
ret))))
637650
pmap
638651
(core/fn [bvec b v]
639652
(core/let [gmap (gensym "map__")
640653
defaults (:or b)]
641654
(core/loop [ret (core/-> bvec (conj gmap) (conj v)
642-
(conj gmap) (conj `(if (implements? ISeq ~gmap) (apply cljs.core/hash-map ~gmap) ~gmap))
643-
((core/fn [ret]
644-
(if (:as b)
645-
(conj ret (:as b) gmap)
646-
ret))))
655+
(conj gmap) (conj `(if (implements? ISeq ~gmap) (apply cljs.core/hash-map ~gmap) ~gmap))
656+
((core/fn [ret]
657+
(if (:as b)
658+
(conj ret (:as b) gmap)
659+
ret))))
647660
bes (reduce
648-
(core/fn [bes entry]
649-
(reduce #(assoc %1 %2 ((val entry) %2))
650-
(dissoc bes (key entry))
651-
((key entry) bes)))
652-
(dissoc b :as :or)
653-
{:keys #(if (core/keyword? %) % (keyword (core/str %))),
654-
:strs core/str, :syms #(core/list `quote %)})]
661+
(core/fn [bes entry]
662+
(reduce #(assoc %1 %2 ((val entry) %2))
663+
(dissoc bes (key entry))
664+
((key entry) bes)))
665+
(dissoc b :as :or)
666+
{:keys #(if (core/keyword? %) % (keyword (core/str %))),
667+
:strs core/str, :syms #(core/list `quote %)})]
655668
(if (seq bes)
656669
(core/let [bb (key (first bes))
657670
bk (val (first bes))
658-
has-default (contains? defaults bb)]
659-
(recur (pb ret bb (if has-default
660-
(core/list 'cljs.core/get gmap bk (defaults bb))
661-
(core/list 'cljs.core/get gmap bk)))
662-
(next bes)))
671+
bv (if (contains? defaults bb)
672+
(core/list 'cljs.core/get gmap bk (defaults bb))
673+
(core/list 'cljs.core/get gmap bk))]
674+
(recur (core/cond
675+
(core/symbol? bb) (core/-> ret (conj (if (namespace bb) (symbol (name bb)) bb)) (conj bv))
676+
(core/keyword? bb) (core/-> ret (conj (symbol (name bb)) bv))
677+
:else (pb ret bb bv))
678+
(next bes)))
663679
ret))))]
664680
(core/cond
665681
(core/symbol? b) (core/-> bvec (conj (if (namespace b) (symbol (name b)) b)) (conj v))
666682
(core/keyword? b) (core/-> bvec (conj (symbol (name b))) (conj v))
667683
(vector? b) (pvec bvec b v)
668684
(map? b) (pmap bvec b v)
669685
:else (throw
670-
#?(:clj (new Exception (core/str "Unsupported binding form: " b))
671-
:cljs (new js/Error (core/str "Unsupported binding form: " b)))))))
686+
#?(:clj (new Exception (core/str "Unsupported binding form: " b))
687+
:cljs (new js/Error (core/str "Unsupported binding form: " b)))))))
672688
process-entry (core/fn [bvec b] (pb bvec (first b) (second b)))]
673689
(if (every? core/symbol? (map first bents))
674690
bindings

0 commit comments

Comments
 (0)