Skip to content

Commit bdbd6c5

Browse files
committed
CLJS-3271: nth on range produces nonexistent values considering floating point
1 parent f5f9b79 commit bdbd6c5

File tree

4 files changed

+193
-23
lines changed

4 files changed

+193
-23
lines changed

src/main/cljs/cljs/core.cljs

Lines changed: 126 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9650,7 +9650,7 @@ reduces them without incurring seq initialization"
96509650
(take-while (mk-bound-fn sc start-test start-key)
96519651
(if ((mk-bound-fn sc end-test end-key) e) s (next s))))))
96529652

9653-
(deftype RangeChunk [start step count]
9653+
(deftype IntegerRangeChunk [start step count]
96549654
ICounted
96559655
(-count [coll] count)
96569656

@@ -9669,7 +9669,7 @@ reduces them without incurring seq initialization"
96699669
(-drop-first [coll]
96709670
(if (<= count 1)
96719671
(throw (js/Error. "-drop-first of empty chunk"))
9672-
(RangeChunk. (+ start step) step (dec count)))))
9672+
(IntegerRangeChunk. (+ start step) step (dec count)))))
96739673

96749674
(deftype RangeIterator [^:mutable i end step]
96759675
Object
@@ -9682,7 +9682,7 @@ reduces them without incurring seq initialization"
96829682
(set! i (+ i step))
96839683
ret)))
96849684

9685-
(deftype Range [meta start end step ^:mutable chunk ^:mutable chunk-next ^:mutable __hash]
9685+
(deftype IntegerRange [meta start end step ^:mutable chunk ^:mutable chunk-next ^:mutable __hash]
96869686
Object
96879687
(toString [coll]
96889688
(pr-str* coll))
@@ -9701,18 +9701,18 @@ reduces them without incurring seq initialization"
97019701
(let [count (-count coll)]
97029702
(if (> count 32)
97039703
(do
9704-
(set! chunk-next (Range. nil (+ start (* step 32)) end step nil nil nil))
9705-
(set! chunk (RangeChunk. start step 32)))
9706-
(set! chunk (RangeChunk. start step count))))))
9704+
(set! chunk-next (IntegerRange. nil (+ start (* step 32)) end step nil nil nil))
9705+
(set! chunk (IntegerRangeChunk. start step 32)))
9706+
(set! chunk (IntegerRangeChunk. start step count))))))
97079707

97089708
ICloneable
9709-
(-clone [_] (Range. meta start end step chunk chunk-next __hash))
9709+
(-clone [_] (IntegerRange. meta start end step chunk chunk-next __hash))
97109710

97119711
IWithMeta
97129712
(-with-meta [rng new-meta]
97139713
(if (identical? new-meta meta)
97149714
rng
9715-
(Range. new-meta start end step chunk chunk-next __hash)))
9715+
(IntegerRange. new-meta start end step chunk chunk-next __hash)))
97169716

97179717
IMeta
97189718
(-meta [rng] meta)
@@ -9736,9 +9736,9 @@ reduces them without incurring seq initialization"
97369736
(-next [rng]
97379737
(if (pos? step)
97389738
(when (< (+ start step) end)
9739-
(Range. nil (+ start step) end step nil nil nil))
9739+
(IntegerRange. nil (+ start step) end step nil nil nil))
97409740
(when (> (+ start step) end)
9741-
(Range. nil (+ start step) end step nil nil nil))))
9741+
(IntegerRange. nil (+ start step) end step nil nil nil))))
97429742

97439743
IChunkedSeq
97449744
(-chunked-first [rng]
@@ -9796,6 +9796,113 @@ reduces them without incurring seq initialization"
97969796
(recur (+ i step) ret)))
97979797
ret))))
97989798

9799+
(es6-iterable IntegerRange)
9800+
9801+
(deftype Range [meta start end step ^:mutable chunk ^:mutable chunk-next ^:mutable __hash]
9802+
Object
9803+
(toString [coll]
9804+
(pr-str* coll))
9805+
(equiv [this other]
9806+
(-equiv this other))
9807+
(indexOf [coll x]
9808+
(-indexOf coll x 0))
9809+
(indexOf [coll x start]
9810+
(-indexOf coll x start))
9811+
(lastIndexOf [coll x]
9812+
(-lastIndexOf coll x (count coll)))
9813+
(lastIndexOf [coll x start]
9814+
(-lastIndexOf coll x start))
9815+
(forceChunk [coll]
9816+
(when (nil? chunk)
9817+
(let [arr (make-array 32)
9818+
val (loop [n 0 val start]
9819+
(if (< n 32)
9820+
(do
9821+
(aset arr n val)
9822+
(let [n (inc n)
9823+
val (+ val step)]
9824+
(if (if (pos? step) (< val end) (> val end))
9825+
(recur n val)
9826+
(set! chunk (array-chunk arr 0 n)))))
9827+
val))]
9828+
(when (nil? chunk)
9829+
(set! chunk (array-chunk arr 0 32))
9830+
(when (if (pos? step) (< val end) (> val end))
9831+
(set! chunk-next (Range. nil val end step nil nil nil)))))))
9832+
9833+
ICloneable
9834+
(-clone [_] (Range. meta start end step chunk chunk-next __hash))
9835+
9836+
IWithMeta
9837+
(-with-meta [rng new-meta]
9838+
(if (identical? new-meta meta)
9839+
rng
9840+
(Range. new-meta start end step chunk chunk-next __hash)))
9841+
9842+
IMeta
9843+
(-meta [rng] meta)
9844+
9845+
ISeqable
9846+
(-seq [rng] rng)
9847+
9848+
ISeq
9849+
(-first [rng] start)
9850+
(-rest [rng]
9851+
(let [s (-next rng)]
9852+
(if (nil? s)
9853+
()
9854+
s)))
9855+
9856+
IIterable
9857+
(-iterator [_]
9858+
(RangeIterator. start end step))
9859+
9860+
INext
9861+
(-next [rng]
9862+
(if (pos? step)
9863+
(when (< (+ start step) end)
9864+
(Range. nil (+ start step) end step nil nil nil))
9865+
(when (> (+ start step) end)
9866+
(Range. nil (+ start step) end step nil nil nil))))
9867+
9868+
IChunkedSeq
9869+
(-chunked-first [rng]
9870+
(.forceChunk rng)
9871+
chunk)
9872+
(-chunked-rest [rng]
9873+
(.forceChunk rng)
9874+
(if (nil? chunk-next)
9875+
()
9876+
chunk-next))
9877+
9878+
IChunkedNext
9879+
(-chunked-next [rng]
9880+
(seq (-chunked-rest rng)))
9881+
9882+
ICollection
9883+
(-conj [rng o] (cons o rng))
9884+
9885+
IEmptyableCollection
9886+
(-empty [rng] (.-EMPTY List))
9887+
9888+
ISequential
9889+
IEquiv
9890+
(-equiv [rng other] (equiv-sequential rng other))
9891+
9892+
IHash
9893+
(-hash [rng] (caching-hash rng hash-ordered-coll __hash))
9894+
9895+
IReduce
9896+
(-reduce [rng f] (seq-reduce f rng))
9897+
(-reduce [rng f init]
9898+
(loop [i start ret init]
9899+
(if (if (pos? step) (< i end) (> i end))
9900+
(let [ret (f ret i)]
9901+
(if (reduced? ret)
9902+
@ret
9903+
(recur (+ i step) ret)))
9904+
ret))))
9905+
97999906
(es6-iterable Range)
98009907

98019908
(defn range
@@ -9810,12 +9917,16 @@ reduces them without incurring seq initialization"
98109917
(pos? step)
98119918
(if (<= end start)
98129919
()
9813-
(Range. nil start end step nil nil nil))
9920+
(if (and (integer? start) (integer? end) (integer? step))
9921+
(IntegerRange. nil start end step nil nil nil)
9922+
(Range. nil start end step nil nil nil)))
98149923

98159924
(neg? step)
98169925
(if (>= end start)
98179926
()
9818-
(Range. nil start end step nil nil nil))
9927+
(if (and (integer? start) (integer? end) (integer? step))
9928+
(IntegerRange. nil start end step nil nil nil)
9929+
(Range. nil start end step nil nil nil)))
98199930

98209931
:else
98219932
(if (== end start)
@@ -10429,6 +10540,9 @@ reduces them without incurring seq initialization"
1042910540
Range
1043010541
(-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
1043110542

10543+
IntegerRange
10544+
(-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
10545+
1043210546
Cycle
1043310547
(-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
1043410548

src/test/cljs/cljs/collections_test.cljs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
(ns cljs.collections-test
1010
(:refer-clojure :exclude [iter])
1111
(:require [cljs.test :refer-macros [deftest testing is are run-tests]]
12+
[clojure.test.check :as tc]
13+
[clojure.test.check.clojure-test :refer-macros [defspec]]
14+
[clojure.test.check.generators :as gen]
15+
[clojure.test.check.properties :as prop :include-macros true]
1216
[clojure.string :as s]
1317
[clojure.set :as set]))
1418

@@ -141,10 +145,18 @@
141145
(is (= #{1} (disj #{1 2 3} 2 3)))
142146
(is (nil? (disj nil :foo)))))
143147

148+
(defspec integerrange-equals-range 100
149+
(prop/for-all [start gen/int
150+
end gen/int
151+
step gen/s-pos-int]
152+
(= (Range. nil start end step nil nil nil)
153+
(IntegerRange. nil start end step nil nil nil))))
154+
144155
(deftest test-range
145156
(testing "Testing Range"
146157
;; Range
147158
(is (= (range 0 10 3) (list 0 3 6 9)))
159+
(is (= (range 2.5) '(0 1 2)))
148160
(is (= (count (range 0 10 3)) 4))
149161
(is (= (range 0 -10 -3) (list 0 -3 -6 -9)))
150162
(is (= (count (range 0 -10 -3)) 4))
@@ -163,6 +175,45 @@
163175
(is (= (count (range 0 0 0)) 0))
164176
(is (= (take 3 (range 1 0 0)) (list 1 1 1)))
165177
(is (= (take 3 (range 3 1 0)) (list 3 3 3)))
178+
(is (not (counted? (range))))
179+
(is (counted? (range 0 10 1)))
180+
(is (not (counted? (range 0.1 10 1))))
181+
(is (chunked-seq? (range 0 10 1)))
182+
(is (chunked-seq? (range 0.1 10 1)))
183+
(is (= (range 0.5 8 1.2) '(0.5 1.7 2.9 4.1 5.3 6.5 7.7)))
184+
(is (= (range 0.5 -4 -2) '(0.5 -1.5 -3.5)))
185+
(is (= (reduce + (range 0 100)) 4950))
186+
(is (= (reduce + 0 (range 0 100)) 4950))
187+
(is (= (reduce + (range 0.1 100)) 4960))
188+
(is (= (reduce + 0 (range 0.1 100)) 4960))
189+
(is (= (reduce + (map inc (range 0 100 1))) 5050))
190+
(is (= (reduce + 0 (map inc (range 0 100 1))) 5050))
191+
(is (= (reduce + (map inc (range 0 100 0.1))) 51051))
192+
(is (= (reduce + 0 (map inc (range 0 100 0.1))) 51051))
193+
(is (= (reduce + (range 0 3.1 0.1)) 46.500000000000014))
194+
(is (= (reduce + 0 (range 0 3.1 0.1)) 46.500000000000014))
195+
(is (= (reduce + (range 0 3.2 0.1)) 49.600000000000016))
196+
(is (= (reduce + 0 (range 0 3.2 0.1)) 49.600000000000016))
197+
(is (= (reduce + (range 0 3.3 0.1)) 52.80000000000002))
198+
(is (= (reduce + 0 (range 0 3.3 0.1)) 52.80000000000002))
199+
(is (= (reduce + (range 0 -3.1 -0.1)) -46.500000000000014))
200+
(is (= (reduce + 0 (range 0 -3.1 -0.1)) -46.500000000000014))
201+
(is (= (reduce + (range 0 -3.2 -0.1)) -49.600000000000016))
202+
(is (= (reduce + 0 (range 0 -3.2 -0.1)) -49.600000000000016))
203+
(is (= (reduce + (range 0 -3.3 -0.1)) -52.80000000000002))
204+
(is (= (reduce + 0 (range 0 -3.3 -0.1)) -52.80000000000002))
205+
(is (= (reduce + (map inc (range 0 3.1 0.1))) 77.50000000000001))
206+
(is (= (reduce + 0 (map inc (range 0 3.1 0.1))) 77.50000000000001))
207+
(is (= (reduce + (map inc (range 0 3.2 0.1))) 81.60000000000002))
208+
(is (= (reduce + 0 (map inc (range 0 3.2 0.1))) 81.60000000000002))
209+
(is (= (reduce + (map inc (range 0 3.3 0.1))) 85.80000000000003))
210+
(is (= (reduce + 0 (map inc (range 0 3.3 0.1))) 85.80000000000003))
211+
(is (= (reduce + (map inc (range 0 -3.1 -0.1))) -15.500000000000012))
212+
(is (= (reduce + 0 (map inc (range 0 -3.1 -0.1))) -15.500000000000012))
213+
(is (= (reduce + (map inc (range 0 -3.2 -0.1))) -17.600000000000016))
214+
(is (= (reduce + 0 (map inc (range 0 -3.2 -0.1))) -17.600000000000016))
215+
(is (= (reduce + (map inc (range 0 -3.3 -0.1))) -19.80000000000002))
216+
(is (= (reduce + 0 (map inc (range 0 -3.3 -0.1))) -19.80000000000002))
166217
))
167218

168219
(deftest test-cycle

src/test/cljs/cljs/core_test.cljs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -621,16 +621,6 @@
621621
(is (= (meta (with-meta (reify IFoo (foo [this] :foo)) {:foo :bar}))
622622
{:foo :bar})))
623623

624-
625-
(defprotocol Slashy (/ [_]))
626-
627-
(extend-type string
628-
Slashy
629-
(/ [_] "result"))
630-
631-
(deftest test-protocol-with-slash
632-
(is (= "result" (/ ""))))
633-
634624
(let [x "original"]
635625
(defn original-closure-stmt [] x))
636626

@@ -1818,4 +1808,10 @@
18181808

18191809
(deftest test-cljs-3202
18201810
(is (= :/ (keyword "/")))
1821-
(is (= (hash :/) (hash (keyword "/")))))
1811+
(is (= (hash :/) (hash (keyword "/")))))
1812+
1813+
(deftest test-cljs-3270
1814+
(is (== 10 (count (range 0 (+ 1 (/ 9)) (/ 9))))))
1815+
1816+
(deftest test-cljs-3271
1817+
(is (== 0.6 (nth (range 0 1 0.1) 6))))

src/test/cljs/cljs/extend_to_native_test.cljs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,12 @@
135135
(is (= :p (test-seqable 1)))
136136
(extend-type string IReduce (-reduce [_ _] :q))
137137
(is (= :q (test-reduceable "a"))))
138+
139+
(defprotocol Slashy (/ [_]))
140+
141+
(extend-type string
142+
Slashy
143+
(/ [_] "result"))
144+
145+
(deftest test-protocol-with-slash
146+
(is (= "result" (/ ""))))

0 commit comments

Comments
 (0)