Skip to content

Commit 457faf8

Browse files
mfikesdnolen
authored and
dnolen
committed
CLJS-2445: Reducible sequence generators
1 parent 2448716 commit 457faf8

File tree

3 files changed

+480
-11
lines changed

3 files changed

+480
-11
lines changed

benchmark/cljs/benchmark_runner.cljs

+28-1
Original file line numberDiff line numberDiff line change
@@ -421,4 +421,31 @@
421421
(simple-benchmark [x js/Infinity] (pr-str x) 1000000)
422422
(simple-benchmark [x js/-Infinity] (pr-str x) 1000000)
423423
(simple-benchmark [x (js-obj)] (pr-str x) 1000000)
424-
(println)
424+
425+
(println "\n")
426+
(println ";; cycle")
427+
(simple-benchmark [] (doall (take 1000 (cycle [1 2 3]))) 1000)
428+
(simple-benchmark [] (into [] (take 1000) (cycle [1 2 3])) 1000)
429+
(simple-benchmark [] (reduce + (take 64 (cycle [1 2 3]))) 10000)
430+
(simple-benchmark [] (transduce (take 64) + (cycle [1 2 3])) 10000)
431+
432+
(println "\n")
433+
(println ";; repeat")
434+
(simple-benchmark [] (doall (take 1000 (repeat 1))) 1000)
435+
(simple-benchmark [] (into [] (take 1000) (repeat 1)) 1000)
436+
(simple-benchmark [] (doall (repeat 1000 1)) 1000)
437+
(simple-benchmark [] (into [] (repeat 1000 1)) 1000)
438+
(simple-benchmark [] (reduce + 0 (repeat 1000 1)) 1000)
439+
(simple-benchmark [] (into [] (take 1000) (repeat 1)) 1000)
440+
(simple-benchmark [] (reduce + (take 64 (repeat 1))) 10000)
441+
(simple-benchmark [] (transduce (take 64) + (repeat 1)) 10000)
442+
(simple-benchmark [] (reduce + (take 64 (repeat 48 1))) 10000)
443+
(simple-benchmark [] (transduce (take 64) + (repeat 48 1)) 10000)
444+
445+
(println "\n")
446+
(println ";; iterate")
447+
(simple-benchmark [] (doall (take 1000 (iterate inc 0))) 1000)
448+
(simple-benchmark [] (into [] (take 1000) (iterate inc 0)) 1000)
449+
(simple-benchmark [] (reduce + (take 64 (iterate inc 0))) 10000)
450+
(simple-benchmark [] (transduce (take 64) + (iterate inc 0)) 10000)
451+
(println)

src/main/cljs/cljs/core.cljs

+230-9
Original file line numberDiff line numberDiff line change
@@ -1897,7 +1897,7 @@ reduces them without incurring seq initialization"
18971897
"Returns the nth rest of coll, coll when n is 0."
18981898
[coll n]
18991899
(loop [n n xs coll]
1900-
(if (and (pos? n) (seq xs))
1900+
(if-let [xs (and (pos? n) (seq xs))]
19011901
(recur (dec n) (rest xs))
19021902
xs)))
19031903

@@ -4775,21 +4775,175 @@ reduces them without incurring seq initialization"
47754775
s)))]
47764776
(lazy-seq (step pred coll)))))
47774777

4778+
(deftype Cycle [meta all prev ^:mutable current ^:mutable _next]
4779+
Object
4780+
(toString [coll]
4781+
(pr-str* coll))
4782+
(currentval [coll]
4783+
(when-not ^seq current
4784+
(if-let [c (next prev)]
4785+
(set! current c)
4786+
(set! current all)))
4787+
current)
4788+
4789+
IPending
4790+
(-realized? [coll]
4791+
(some? current))
4792+
4793+
IWithMeta
4794+
(-with-meta [coll meta] (Cycle. meta all prev current _next))
4795+
4796+
IMeta
4797+
(-meta [coll] meta)
4798+
4799+
ISeq
4800+
(-first [coll]
4801+
(first (.currentval coll)))
4802+
(-rest [coll]
4803+
(when (nil? _next)
4804+
(set! _next (Cycle. nil all (.currentval coll) nil nil)))
4805+
_next)
4806+
4807+
INext
4808+
(-next [coll]
4809+
(-rest coll))
4810+
4811+
ICollection
4812+
(-conj [coll o] (cons o coll))
4813+
4814+
IEmptyableCollection
4815+
(-empty [coll] (-with-meta (.-EMPTY List) meta))
4816+
4817+
ISequential
4818+
ISeqable
4819+
(-seq [coll] coll)
4820+
4821+
IReduce
4822+
(-reduce [coll f]
4823+
(loop [s (.currentval coll) ret (first s)]
4824+
(let [s (or (next s) all)
4825+
ret (f ret (first s))]
4826+
(if (reduced? ret)
4827+
@ret
4828+
(recur s ret)))))
4829+
(-reduce [coll f start]
4830+
(loop [s (.currentval coll) ret start]
4831+
(let [ret (f ret (first s))]
4832+
(if (reduced? ret)
4833+
@ret
4834+
(recur (or (next s) all) ret))))))
4835+
47784836
(defn cycle
47794837
"Returns a lazy (infinite!) sequence of repetitions of the items in coll."
4780-
[coll] (lazy-seq
4781-
(when-let [s (seq coll)]
4782-
(concat s (cycle s)))))
4838+
[coll] (if-let [vals (seq coll)]
4839+
(Cycle. nil vals nil vals nil)
4840+
(.-EMPTY List)))
47834841

47844842
(defn split-at
47854843
"Returns a vector of [(take n coll) (drop n coll)]"
47864844
[n coll]
47874845
[(take n coll) (drop n coll)])
47884846

4847+
(deftype Repeat [meta count val ^:mutable next ^:mutable __hash]
4848+
Object
4849+
(toString [coll]
4850+
(pr-str* coll))
4851+
(equiv [this other]
4852+
(-equiv this other))
4853+
(indexOf [coll x]
4854+
(-indexOf coll x 0))
4855+
(indexOf [coll x start]
4856+
(-indexOf coll x start))
4857+
(lastIndexOf [coll x]
4858+
(-lastIndexOf coll x count))
4859+
(lastIndexOf [coll x start]
4860+
(-lastIndexOf coll x start))
4861+
4862+
IPending
4863+
(-realized? [coll] false)
4864+
4865+
IWithMeta
4866+
(-with-meta [coll meta] (Repeat. meta count val next nil))
4867+
4868+
IMeta
4869+
(-meta [coll] meta)
4870+
4871+
ISeq
4872+
(-first [coll]
4873+
val)
4874+
(-rest [coll]
4875+
(if (nil? next)
4876+
(if (> count 1)
4877+
(do
4878+
(set! next (Repeat. nil (dec count) val nil nil))
4879+
next)
4880+
(if (== -1 count)
4881+
coll
4882+
()))
4883+
next))
4884+
4885+
INext
4886+
(-next [coll]
4887+
(if (nil? next)
4888+
(if (> count 1)
4889+
(do
4890+
(set! next (Repeat. nil (dec count) val nil nil))
4891+
next)
4892+
(if (== -1 count)
4893+
coll
4894+
nil))
4895+
next))
4896+
4897+
ICollection
4898+
(-conj [coll o] (cons o coll))
4899+
4900+
IEmptyableCollection
4901+
(-empty [coll] (-with-meta (.-EMPTY List) meta))
4902+
4903+
IHash
4904+
(-hash [coll] (caching-hash coll hash-ordered-coll __hash))
4905+
4906+
ISequential
4907+
ISeqable
4908+
(-seq [coll] coll)
4909+
4910+
IEquiv
4911+
(-equiv [coll other] (equiv-sequential coll other))
4912+
4913+
IReduce
4914+
(-reduce [coll f]
4915+
(if (== count -1)
4916+
(loop [ret (f val val)]
4917+
(if (reduced? ret)
4918+
@ret
4919+
(recur (f ret val))))
4920+
(loop [i 1 ret val]
4921+
(if (< i count)
4922+
(let [ret (f ret val)]
4923+
(if (reduced? ret)
4924+
@ret
4925+
(recur (inc i) ret)))
4926+
ret))))
4927+
(-reduce [coll f start]
4928+
(if (== count -1)
4929+
(loop [ret (f start val)]
4930+
(if (reduced? ret)
4931+
@ret
4932+
(recur (f ret val))))
4933+
(loop [i 0 ret start]
4934+
(if (< i count)
4935+
(let [ret (f ret val)]
4936+
(if (reduced? ret)
4937+
@ret
4938+
(recur (inc i) ret)))
4939+
ret)))))
4940+
47894941
(defn repeat
47904942
"Returns a lazy (infinite!, or length n if supplied) sequence of xs."
4791-
([x] (lazy-seq (cons x (repeat x))))
4792-
([n x] (take n (repeat x))))
4943+
([x] (Repeat. nil -1 x nil nil))
4944+
([n x] (if (pos? n)
4945+
(Repeat. nil n x nil nil)
4946+
(.-EMPTY List))))
47934947

47944948
(defn replicate
47954949
"DEPRECATED: Use 'repeat' instead.
@@ -4803,10 +4957,68 @@ reduces them without incurring seq initialization"
48034957
([f] (lazy-seq (cons (f) (repeatedly f))))
48044958
([n f] (take n (repeatedly f))))
48054959

4960+
(def ^:private UNREALIZED-SEED #js {})
4961+
4962+
(deftype Iterate [meta f prev-seed ^:mutable seed ^:mutable next]
4963+
Object
4964+
(toString [coll]
4965+
(pr-str* coll))
4966+
4967+
IPending
4968+
(-realized? [coll]
4969+
(not (identical? seed UNREALIZED-SEED)))
4970+
4971+
IWithMeta
4972+
(-with-meta [coll meta] (Iterate. meta f prev-seed seed next))
4973+
4974+
IMeta
4975+
(-meta [coll] meta)
4976+
4977+
ISeq
4978+
(-first [coll]
4979+
(when (identical? UNREALIZED-SEED seed)
4980+
(set! seed (f prev-seed)))
4981+
seed)
4982+
(-rest [coll]
4983+
(when (nil? next)
4984+
(set! next (Iterate. nil f (-first coll) UNREALIZED-SEED nil)))
4985+
next)
4986+
4987+
INext
4988+
(-next [coll]
4989+
(-rest coll))
4990+
4991+
ICollection
4992+
(-conj [coll o] (cons o coll))
4993+
4994+
IEmptyableCollection
4995+
(-empty [coll] (-with-meta (.-EMPTY List) meta))
4996+
4997+
ISequential
4998+
ISeqable
4999+
(-seq [coll] coll)
5000+
5001+
IReduce
5002+
(-reduce [coll rf]
5003+
(let [first (-first coll)
5004+
v (f first)]
5005+
(loop [ret (rf first v) v v]
5006+
(if (reduced? ret)
5007+
@ret
5008+
(let [v (f v)]
5009+
(recur (rf ret v) v))))))
5010+
(-reduce [coll rf start]
5011+
(let [v (-first coll)]
5012+
(loop [ret (rf start v) v v]
5013+
(if (reduced? ret)
5014+
@ret
5015+
(let [v (f v)]
5016+
(recur (rf ret v) v)))))))
5017+
48065018
(defn iterate
48075019
"Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects"
48085020
{:added "1.0"}
4809-
[f x] (cons x (lazy-seq (iterate f (f x)))))
5021+
[f x] (Iterate. nil f nil x nil))
48105022

48115023
(defn interleave
48125024
"Returns a lazy seq of the first item in each coll, then the second etc."
@@ -9507,8 +9719,8 @@ reduces them without incurring seq initialization"
95079719
be used to force any effects. Walks through the successive nexts of
95089720
the seq, does not retain the head and returns nil."
95099721
([coll]
9510-
(when (seq coll)
9511-
(recur (next coll))))
9722+
(when-let [s (seq coll)]
9723+
(recur (next s))))
95129724
([n coll]
95139725
(when (and (seq coll) (pos? n))
95149726
(recur (dec n) (next coll)))))
@@ -9960,6 +10172,15 @@ reduces them without incurring seq initialization"
996010172
Range
996110173
(-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
996210174

10175+
Cycle
10176+
(-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
10177+
10178+
Repeat
10179+
(-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
10180+
10181+
Iterate
10182+
(-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
10183+
996310184
ES6IteratorSeq
996410185
(-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
996510186

0 commit comments

Comments
 (0)