summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/system.nim47
-rw-r--r--tests/stdlib/tcount.nim29
2 files changed, 63 insertions, 13 deletions
diff --git a/lib/system.nim b/lib/system.nim
index 4180f24f9..ea35bd54a 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1556,30 +1556,51 @@ when not defined(nimrodVM) and hostOS != "standalone":
       ## returns the number of bytes on the shared heap that are owned by the
       ## process. This is only available when threads are enabled.
 
+when sizeof(int) <= 2:
+  type IntLikeForCount = int|int8|int16|char|bool|uint8
+else:
+  type IntLikeForCount = int|int8|int16|int32|char|bool|uint8|uint16
+
 iterator countdown*[T](a, b: T, step = 1): T {.inline.} =
   ## Counts from ordinal value `a` down to `b` with the given
   ## step count. `T` may be any ordinal type, `step` may only
-  ## be positive.
-  var res = a
-  while res >= b:
-    yield res
-    dec(res, step)
+  ## be positive. **Note**: This fails to count to ``low(int)`` if T = int for
+  ## efficiency reasons.
+  when T is IntLikeForCount:
+    var res = int(a)
+    while res >= int(b):
+      yield T(res)
+      dec(res, step)
+  else:
+    var res = a
+    while res >= b:
+      yield res
+      dec(res, step)
+
+template countupImpl(incr: stmt) {.immediate, dirty.} =
+  when T is IntLikeForCount:
+    var res = int(a)
+    while res <= int(b):
+      yield T(res)
+      incr
+  else:
+    var res: T = T(a)
+    while res <= b:
+      yield res
+      incr
 
 iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} =
   ## Counts from ordinal value `a` up to `b` with the given
   ## step count. `S`, `T` may be any ordinal type, `step` may only
-  ## be positive.
-  var res: T = T(a)
-  while res <= b:
-    yield res
+  ## be positive. **Note**: This fails to count to ``high(int)`` if T = int for
+  ## efficiency reasons.
+  countupImpl:
     inc(res, step)
 
 iterator `..`*[S, T](a: S, b: T): T {.inline.} =
   ## An alias for `countup`.
-  var res: T = T(a)
-  while res <= b:
-    yield res
-    inc res
+  countupImpl:
+    inc(res)
 
 iterator `||`*[S, T](a: S, b: T, annotation=""): T {.
   inline, magic: "OmpParFor", sideEffect.} =
diff --git a/tests/stdlib/tcount.nim b/tests/stdlib/tcount.nim
new file mode 100644
index 000000000..ce1d14b6c
--- /dev/null
+++ b/tests/stdlib/tcount.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''1
+2
+3
+4
+5
+done'''
+"""
+
+# bug #1845, #2224
+
+var arr = [3,2,1,5,4]
+
+# bubble sort
+for i in low(arr)..high(arr):
+  for j in i+1..high(arr): # Error: unhandled exception: value out of range: 5 [RangeError]
+    if arr[i] > arr[j]:
+      let tmp = arr[i]
+      arr[i] = arr[j]
+      arr[j] = tmp
+
+for i in low(arr)..high(arr):
+  echo arr[i]
+
+# check this terminates:
+for x in countdown('\255', '\0'):
+  discard
+
+echo "done"