Skip to content

Commit 345a9b6

Browse files
committed
CLJS-2693: Have Range implement IChunkedSeq
This set of changes mirrors those in Clojure surrounding LongRange and LongChunk. In particular, range is modified to follow the 3-arg LongRange/create. The previous next implementation is preserved. (The Clojure implemenation forces a chunk for each next call, which, in ClojureScript, slows down algorithms like doall which walk the seq.) RangeChunk does not implement IReduce because, unlike in Clojure, ClojureScript doesn't have an internal-reduce which reduces chunked-seq chunks. (Additionally, reduce for ranges is handled directly by Range.)
1 parent 7db5826 commit 345a9b6

File tree

2 files changed

+88
-19
lines changed

2 files changed

+88
-19
lines changed

src/main/cljs/cljs/core.cljs

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9547,6 +9547,27 @@ reduces them without incurring seq initialization"
95479547
(take-while (mk-bound-fn sc start-test start-key)
95489548
(if ((mk-bound-fn sc end-test end-key) e) s (next s))))))
95499549

9550+
(deftype RangeChunk [start step count]
9551+
ICounted
9552+
(-count [coll] count)
9553+
9554+
ISeq
9555+
(-first [coll] start)
9556+
9557+
IIndexed
9558+
(-nth [coll i]
9559+
(+ start (* i step)))
9560+
(-nth [coll i not-found]
9561+
(if (and (>= i 0) (< i count))
9562+
(+ start (* i step))
9563+
not-found))
9564+
9565+
IChunk
9566+
(-drop-first [coll]
9567+
(if (<= count 1)
9568+
(throw (js/Error. "-drop-first of empty chunk"))
9569+
(RangeChunk. (+ start step) step (dec count)))))
9570+
95509571
(deftype RangeIterator [^:mutable i end step]
95519572
Object
95529573
(hasNext [_]
@@ -9558,7 +9579,7 @@ reduces them without incurring seq initialization"
95589579
(set! i (+ i step))
95599580
ret)))
95609581

9561-
(deftype Range [meta start end step ^:mutable __hash]
9582+
(deftype Range [meta start end step ^:mutable chunk ^:mutable chunk-next ^:mutable __hash]
95629583
Object
95639584
(toString [coll]
95649585
(pr-str* coll))
@@ -9572,30 +9593,34 @@ reduces them without incurring seq initialization"
95729593
(-lastIndexOf coll x (count coll)))
95739594
(lastIndexOf [coll x start]
95749595
(-lastIndexOf coll x start))
9596+
(forceChunk [coll]
9597+
(when (nil? chunk)
9598+
(let [count (-count coll)]
9599+
(if (> count 32)
9600+
(do
9601+
(set! chunk-next (Range. nil (+ start (* step 32)) end step nil nil nil))
9602+
(set! chunk (RangeChunk. start step 32)))
9603+
(set! chunk (RangeChunk. start step count))))))
95759604

95769605
ICloneable
9577-
(-clone [_] (Range. meta start end step __hash))
9606+
(-clone [_] (Range. meta start end step chunk chunk-next __hash))
95789607

95799608
IWithMeta
9580-
(-with-meta [rng meta] (Range. meta start end step __hash))
9609+
(-with-meta [rng meta] (Range. meta start end step chunk chunk-next __hash))
95819610

95829611
IMeta
95839612
(-meta [rng] meta)
95849613

95859614
ISeqable
9586-
(-seq [rng]
9587-
(cond
9588-
(pos? step) (when (< start end) rng)
9589-
(neg? step) (when (> start end) rng)
9590-
:else (when-not (== start end) rng)))
9615+
(-seq [rng] rng)
95919616

95929617
ISeq
9593-
(-first [rng]
9594-
(when-not (nil? (-seq rng)) start))
9618+
(-first [rng] start)
95959619
(-rest [rng]
9596-
(if-not (nil? (-seq rng))
9597-
(Range. meta (+ start step) end step nil)
9598-
()))
9620+
(let [s (-next rng)]
9621+
(if (nil? s)
9622+
()
9623+
s)))
95999624

96009625
IIterable
96019626
(-iterator [_]
@@ -9605,9 +9630,23 @@ reduces them without incurring seq initialization"
96059630
(-next [rng]
96069631
(if (pos? step)
96079632
(when (< (+ start step) end)
9608-
(Range. meta (+ start step) end step nil))
9633+
(Range. meta (+ start step) end step nil nil nil))
96099634
(when (> (+ start step) end)
9610-
(Range. meta (+ start step) end step nil))))
9635+
(Range. meta (+ start step) end step nil nil nil))))
9636+
9637+
IChunkedSeq
9638+
(-chunked-first [rng]
9639+
(.forceChunk rng)
9640+
chunk)
9641+
(-chunked-rest [rng]
9642+
(.forceChunk rng)
9643+
(if (nil? chunk-next)
9644+
()
9645+
chunk-next))
9646+
9647+
IChunkedNext
9648+
(-chunked-next [rng]
9649+
(seq (-chunked-rest rng)))
96119650

96129651
ICollection
96139652
(-conj [rng o] (cons o rng))
@@ -9624,9 +9663,7 @@ reduces them without incurring seq initialization"
96249663

96259664
ICounted
96269665
(-count [rng]
9627-
(if-not (-seq rng)
9628-
0
9629-
(Math/ceil (/ (- end start) step))))
9666+
(Math/ceil (/ (- end start) step)))
96309667

96319668
IIndexed
96329669
(-nth [rng n]
@@ -9662,7 +9699,22 @@ reduces them without incurring seq initialization"
96629699
([] (range 0 (.-MAX_VALUE js/Number) 1))
96639700
([end] (range 0 end 1))
96649701
([start end] (range start end 1))
9665-
([start end step] (Range. nil start end step nil)))
9702+
([start end step]
9703+
(cond
9704+
(pos? step)
9705+
(if (<= end start)
9706+
()
9707+
(Range. nil start end step nil nil nil))
9708+
9709+
(neg? step)
9710+
(if (>= end start)
9711+
()
9712+
(Range. nil start end step nil nil nil))
9713+
9714+
:else
9715+
(if (== end start)
9716+
()
9717+
(repeat start)))))
96669718

96679719
(defn take-nth
96689720
"Returns a lazy seq of every nth item in coll. Returns a stateful

src/test/cljs/cljs/core_test.cljs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,23 @@
15991599
;; Make sure we didn't delete the alpha? fn
16001600
(is (some? alpha-2585?)))
16011601

1602+
(deftest test-cljs-2693
1603+
(is (chunked-seq? (range 5)))
1604+
(is (satisfies? IChunk (chunk-first (range 5))))
1605+
(is (nil? (chunk-next (range 32))))
1606+
(is (satisfies? IChunk (chunk-first (chunk-next (range 33)))))
1607+
(is (satisfies? IChunk (chunk-first (chunk-rest (range 33)))))
1608+
(is (not (chunked-seq? (range 2 -2 0))))
1609+
(is (chunked-seq? (range)))
1610+
(is (= 5 (count (chunk-first (range 5)))))
1611+
(is (= 32 (count (chunk-first (range)))))
1612+
(is (= 17 (nth (chunk-first (range 100)) 17)))
1613+
(is (= ::not-found (nth (chunk-first (range 100)) 35 ::not-found)))
1614+
(is (= 0 (first (range 5))))
1615+
(is (= 1 (second (range 5))))
1616+
(is (= (range 1 5) (rest (range 5))))
1617+
(is (= (range 1 5) (next (range 5)))))
1618+
16021619
(defn fn-2741* ([x]) ([x y]))
16031620
(def fn-2741 fn-2741*)
16041621

0 commit comments

Comments
 (0)