Sfoglia il codice sorgente

Add `Core.Range(N)` facility to construct an integer range. (#5699)

Use it in examples where appropriate.

Depends on #5698.
Richard Smith 10 mesi fa
parent
commit
c34d0c7adf

+ 3 - 2
core/io.carbon

@@ -1,8 +1,9 @@
 // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
 // Exceptions. See /LICENSE for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-// AUTOUPDATE
+
+// TODO: This library is not part of the design. Either write a matching
+// proposal or remove this.
 
 package Core library "io";
 

+ 46 - 0
core/range.carbon

@@ -0,0 +1,46 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// TODO: This library is not part of the design. Either write a matching
+// proposal or remove this.
+
+package Core library "range";
+
+import library "prelude/iterate";
+import library "prelude/operators/arithmetic";
+import library "prelude/operators/as";
+import library "prelude/operators/comparison";
+import library "prelude/types/int";
+import library "prelude/types/int_literal";
+import library "prelude/types/optional";
+
+class IntRange(N:! IntLiteral()) {
+  fn Make(start: Int(N), end: Int(N)) -> Self {
+    return {.start = start, .end = end};
+  }
+
+  impl as Iterate where .CursorType = Int(N) and .ElementType = Int(N) {
+    fn NewCursor[self: Self]() -> Int(N) { return self.start; }
+    fn Next[self: Self](cursor: Int(N)*) -> Optional(Int(N)) {
+      var value: Int(N) = *cursor;
+      if (value < self.end) {
+        ++*cursor;
+        return Optional(Int(N)).Some(value);
+      } else {
+        return Optional(Int(N)).None();
+      }
+    }
+  }
+
+  private var start: Int(N);
+  private var end: Int(N);
+}
+
+fn Range(end: i32) -> IntRange(32) {
+  return IntRange(32).Make(0, end);
+}
+
+fn InclusiveRange(start: i32, end: i32) -> IntRange(32) {
+  return IntRange(32).Make(start, end + 1);
+}

+ 3 - 6
examples/advent2024/day10_common.carbon

@@ -7,20 +7,17 @@
 library "day10_common";
 
 import Core library "io";
+import Core library "range";
 import library "io_utils";
 
 class Terrain {
   fn Read() -> Terrain {
     returned var me: Terrain;
-    var y: i32 = 0;
-    while (y < 43) {
-      var x: i32 = 0;
-      while (x < 43) {
+    for (y: i32 in Core.Range(43)) {
+      for (x: i32 in Core.Range(43)) {
         me.height[x][y] = ReadChar() - 0x30;
-        ++x;
       }
       SkipNewline();
-      ++y;
     }
     return var;
   }

+ 8 - 21
examples/advent2024/day10_part1.carbon

@@ -5,6 +5,7 @@
 // https://adventofcode.com/2024/day/10
 
 import Core library "io";
+import Core library "range";
 
 import library "day10_common";
 import library "io_utils";
@@ -26,27 +27,21 @@ class Reachable {
   fn Make(terrain: Terrain) -> Reachable {
     returned var me: Reachable;
     var next: u256 = 1;
-    var y: i32 = 0;
-    while (y < 43) {
-      var x: i32 = 0;
-      while (x < 43) {
+    for (y: i32 in Core.Range(43)) {
+      for (x: i32 in Core.Range(43)) {
         if (terrain.height[x][y] == 0) {
           me.trailheads[x][y] = next;
           next <<= 1;
         }
-        ++x;
       }
-      ++y;
     }
     return var;
   }
 
   fn AddLevel[addr self: Self*](terrain: Terrain, level: i32) {
     let adj: array((i32, i32), 4) = ((-1, 0), (0, -1), (1, 0), (0, 1));
-    var y: i32 = 0;
-    while (y < 43) {
-      var x: i32 = 0;
-      while (x < 43) {
+    for (y: i32 in Core.Range(43)) {
+      for (x: i32 in Core.Range(43)) {
         if (terrain.height[x][y] == level) {
           var reach: u256 = 0;
           var i: i32 = 0;
@@ -62,24 +57,18 @@ class Reachable {
           }
           self->trailheads[x][y] = reach;
         }
-        ++x;
       }
-      ++y;
     }
   }
 
   fn Count[self: Self](terrain: Terrain, level: i32) -> i32 {
     var total: i32 = 0;
-    var y: i32 = 0;
-    while (y < 43) {
-      var x: i32 = 0;
-      while (x < 43) {
+    for (y: i32 in Core.Range(43)) {
+      for (x: i32 in Core.Range(43)) {
         if (terrain.height[x][y] == level) {
           total += PopCount(self.trailheads[x][y]);
         }
-        ++x;
       }
-      ++y;
     }
     return total;
   }
@@ -90,10 +79,8 @@ class Reachable {
 fn Run() {
   var terrain: Terrain = Terrain.Read();
   var reachable: Reachable = Reachable.Make(terrain);
-  var i: i32 = 1;
-  while (i <= 9) {
+  for (i: i32 in Core.InclusiveRange(1, 9)) {
     reachable.AddLevel(terrain, i);
-    ++i;
   }
   Core.Print(reachable.Count(terrain, 9));
 }

+ 9 - 19
examples/advent2024/day10_part2.carbon

@@ -5,6 +5,7 @@
 // https://adventofcode.com/2024/day/10
 
 import Core library "io";
+import Core library "range";
 
 import library "day10_common";
 import library "io_utils";
@@ -12,16 +13,12 @@ import library "io_utils";
 class PathsToTop {
   fn Make(terrain: Terrain) -> PathsToTop {
     returned var me: PathsToTop;
-    var y: i32 = 0;
-    while (y < 43) {
-      var x: i32 = 0;
-      while (x < 43) {
+    for (y: i32 in Core.Range(43)) {
+      for (x: i32 in Core.Range(43)) {
         // TODO: We shouldn't need an explicit cast here.
         me.paths[x][y] =
           if terrain.height[x][y] == 9 then 1 as i64 else 0;
-        ++x;
       }
-      ++y;
     }
     return var;
   }
@@ -29,14 +26,12 @@ class PathsToTop {
   fn AddLevel[addr self: Self*](terrain: Terrain, level: i32) -> i64 {
     var total: i64 = 0;
     let adj: array((i32, i32), 4) = ((-1, 0), (0, -1), (1, 0), (0, 1));
-    var y: i32 = 0;
-    while (y < 43) {
-      var x: i32 = 0;
-      while (x < 43) {
+    for (y: i32 in Core.Range(43)) {
+      for (x: i32 in Core.Range(43)) {
         if (terrain.height[x][y] == level) {
           var paths: i64 = 0;
-          var i: i32 = 0;
-          while (i < 4) {
+          // TODO: for ((adj_x: i32, adj_y: i32) in adj) {
+          for (i: i32 in Core.Range(4)) {
             let adj_x: i32 = x + adj[i].0;
             let adj_y: i32 = y + adj[i].1;
             if (adj_x >= 0 and adj_x < 43 and
@@ -44,14 +39,11 @@ class PathsToTop {
                 terrain.height[adj_x][adj_y] == level + 1) {
               paths += self->paths[adj_x][adj_y];
             }
-            ++i;
           }
           self->paths[x][y] = paths;
           total += paths;
         }
-        ++x;
       }
-      ++y;
     }
     return total;
   }
@@ -62,11 +54,9 @@ class PathsToTop {
 fn Run() {
   var terrain: Terrain = Terrain.Read();
   var paths: PathsToTop = PathsToTop.Make(terrain);
-  var i: i32 = 8;
   var total: i64;
-  while (i >= 0) {
-    total = paths.AddLevel(terrain, i);
-    --i;
+  for (i: i32 in Core.InclusiveRange(0, 8)) {
+    total = paths.AddLevel(terrain, 8 - i);
   }
   PrintInt64(total);
 }

+ 8 - 17
examples/advent2024/day11_part2.carbon

@@ -5,6 +5,7 @@
 // https://adventofcode.com/2024/day/11
 
 import Core library "io";
+import Core library "range";
 
 import library "day11_common";
 import library "io_utils";
@@ -12,31 +13,23 @@ import library "io_utils";
 class Digits {
   fn Make() -> Digits {
     returned var me: Digits;
-    var digit: i32 = 0;
-    while (digit < 10) {
-      var depth: i32 = 0;
-      while (depth < 75) {
+    for (digit: i32 in Core.Range(10)) {
+      for (depth: i32 in Core.Range(75)) {
         me.count[digit][depth] = 0;
-        ++depth;
       }
-      ++digit;
     }
     return var;
   }
 
   fn Print[self: Self](max_depth: i32) {
-    var digit: i32 = 0;
-    while (digit < 10) {
+    for (digit: i32 in Core.Range(10)) {
       Core.PrintChar(digit + 0x30);
       Core.PrintChar(0x3A);
-      var depth: i32 = 0;
-      while (depth <= max_depth) {
+      for (depth: i32 in Core.Range(max_depth)) {
         Core.PrintChar(0x20);
         PrintInt64NoNewline(self.count[digit][depth]);
-        ++depth;
       }
       Core.PrintChar(0x0A);
-      ++digit;
     }
     Core.PrintChar(0x0A);
   }
@@ -74,15 +67,13 @@ fn Run() {
   while (depth >= 0) {
     PrintInt64(total);
     digits.Print(depth);
-    var digit: i64 = 0;
-    while (digit < 10) {
-      let m: i64 = digits.count[digit as i32][depth];
+    for (digit: i32 in Core.Range(10)) {
+      let m: i64 = digits.count[digit][depth];
       if (m > 0) {
-        let next: (i64, i64) = Next(digit);
+        let next: (i64, i64) = Next(digit as i64);
         total += ReduceToDigits(next.0, depth, m, &digits) +
                  ReduceToDigits(next.1, depth, m, &digits);
       }
-      ++digit;
     }
     --depth;
   }

+ 7 - 18
examples/advent2024/day12_common.carbon

@@ -7,20 +7,17 @@
 library "day12_common";
 
 import Core library "io";
+import Core library "range";
 import library "io_utils";
 
 class Map {
   fn Read() -> Map {
     returned var me: Self;
-    var y: i32 = 0;
-    while (y < 140) {
-      var x: i32 = 0;
-      while (x < 140) {
+    for (y: i32 in Core.Range(140)) {
+      for (x: i32 in Core.Range(140)) {
         me.kind[x][y] = ReadChar();
-        ++x;
       }
       SkipNewline();
-      ++y;
     }
     return var;
   }
@@ -37,12 +34,10 @@ class Map {
 class DisjointSetForest {
   fn Make() -> DisjointSetForest {
     returned var me: Self;
-    var i: i32 = 0;
-    while (i < 140 * 140) {
+    for (i: i32 in Core.Range(140 * 140)) {
       me.nodes[i].next = i;
       me.nodes[i].weight = 1;
       me.nodes[i].unions = 0;
-      ++i;
     }
     return var;
   }
@@ -93,12 +88,9 @@ fn MakeRegions(map: Map) -> DisjointSetForest {
   returned var forest: DisjointSetForest =
     DisjointSetForest.Make();
 
-  var x: i32 = 0;
-  while (x < 140) {
-    var y: i32 = 0;
-    while (y < 140) {
-      var a: i32 = 0;
-      while (a < 2) {
+  for (x: i32 in Core.Range(140)) {
+    for (y: i32 in Core.Range(140)) {
+      for (a: i32 in Core.Range(2)) {
         // TODO: Crashes toolchain:
         // let adj: (i32, i32) = if a == 0 then (x - 1, y) else (x, y - 1);
         // if (map.At(adj.0, adj.1) == map.At(x, y)) {
@@ -109,11 +101,8 @@ fn MakeRegions(map: Map) -> DisjointSetForest {
         if (map.At(adj_x, adj_y) == map.At(x, y)) {
           forest.Union(y * 140 + x, adj_y * 140 + adj_x);
         }
-        ++a;
       }
-      ++y;
     }
-    ++x;
   }
 
   return var;

+ 2 - 3
examples/advent2024/day12_part1.carbon

@@ -5,6 +5,7 @@
 // https://adventofcode.com/2024/day/12
 
 import Core library "io";
+import Core library "range";
 
 import library "day12_common";
 import library "io_utils";
@@ -15,15 +16,13 @@ fn Run() {
 
   var total: i32 = 0;
 
-  var i: i32 = 0;
-  while (i < 140 * 140) {
+  for (i: i32 in Core.Range(140 * 140)) {
     if (regions.Lookup(i) == i) {
       let area: i32 = regions.Weight(i);
       let internal_edges: i32 = regions.Unions(i);
       let perimeter: i32 = area * 4 - internal_edges * 2;
       total += area * perimeter;
     }
-    ++i;
   }
 
   Core.Print(total);

+ 6 - 15
examples/advent2024/day12_part2.carbon

@@ -5,16 +5,15 @@
 // https://adventofcode.com/2024/day/12
 
 import Core library "io";
+import Core library "range";
 
 import library "day12_common";
 import library "io_utils";
 
 fn CountExtensions(map: Map, regions: DisjointSetForest*) -> array(i32, 140 * 140) {
   returned var extensions: array(i32, 140 * 140);
-  var i: i32 = 0;
-  while (i < 140 * 140) {
+  for (i: i32 in Core.Range(140 * 140)) {
     extensions[i] = 0;
-    ++i;
   }
 
   var ext: array({.same: (i32, i32), .adj: (i32, i32)}, 4) = (
@@ -24,24 +23,18 @@ fn CountExtensions(map: Map, regions: DisjointSetForest*) -> array(i32, 140 * 14
     {.same = (0, -1), .adj = (1, 0)},
   );
 
-  var x: i32 = 0;
-  while (x < 140) {
-    var y: i32 = 0;
-    while (y < 140) {
+  for (x: i32 in Core.Range(140)) {
+    for (y: i32 in Core.Range(140)) {
       let kind: i32 = map.At(x, y);
-      var e: i32 = 0;
-      while (e < 4) {
+      for (e: i32 in Core.Range(4)) {
         if (map.At(x + ext[e].same.0, y + ext[e].same.1) == kind and
             map.At(x + ext[e].adj.0, y + ext[e].adj.1) != kind and
             map.At(x + ext[e].same.0 + ext[e].adj.0,
                    y + ext[e].same.1 + ext[e].adj.1) != kind) {
           ++extensions[regions->Lookup(y * 140 + x)];
         }
-        ++e;
       }
-      ++y;
     }
-    ++x;
   }
   return var;
 }
@@ -53,8 +46,7 @@ fn Run() {
 
   var total: i32 = 0;
 
-  var i: i32 = 0;
-  while (i < 140 * 140) {
+  for (i: i32 in Core.Range(140 * 140)) {
     if (regions.Lookup(i) == i) {
       let area: i32 = regions.Weight(i);
       let internal_edges: i32 = regions.Unions(i);
@@ -62,7 +54,6 @@ fn Run() {
       let perimeter: i32 = area * 4 - internal_edges * 2 - extensions;
       total += area * perimeter;
     }
-    ++i;
   }
 
   Core.Print(total);

+ 2 - 3
examples/advent2024/day1_part1.carbon

@@ -5,6 +5,7 @@
 // https://adventofcode.com/2024/day/1
 
 import Core library "io";
+import Core library "range";
 
 import library "day1_common";
 import library "sort";
@@ -18,11 +19,9 @@ fn Run() {
   Quicksort(&a, 0, n);
   Quicksort(&b, 0, n);
 
-  var i: i32 = 0;
   var difference: i32 = 0;
-  while (i < n) {
+  for (i: i32 in Core.Range(n)) {
     difference += Abs(a[i] - b[i]);
-    i += 1;
   }
   Core.Print(difference);
 }

+ 5 - 13
examples/advent2024/day4_part1.carbon

@@ -5,6 +5,7 @@
 // https://adventofcode.com/2024/day/4
 
 import Core library "io";
+import Core library "range";
 
 import library "day4_common";
 import library "io_utils";
@@ -14,25 +15,16 @@ fn Run() {
   var xmas: array(i32, 4) = (0x58, 0x4D, 0x41, 0x53);
   var found: i32 = 0;
 
-  // TODO: Use for loops once they're implemented.
-  var y: i32 = 0;
-  while (y < 140) {
-    var x: i32 = 0;
-    while (x < 140) {
-      var dy: i32 = -1;
-      while (dy <= 1) {
-        var dx: i32 = -1;
-        while (dx <= 1) {
+  for (y: i32 in Core.Range(140)) {
+    for (x: i32 in Core.Range(140)) {
+      for (dy: i32 in Core.InclusiveRange(-1, 1)) {
+        for (dx: i32 in Core.InclusiveRange(-1, 1)) {
           if (search.Check4(xmas, x, y, dx, dy)) {
             ++found;
           }
-          ++dx;
         }
-        ++dy;
       }
-      ++x;
     }
-    ++y;
   }
   Core.Print(found);
 }

+ 3 - 7
examples/advent2024/day4_part2.carbon

@@ -5,6 +5,7 @@
 // https://adventofcode.com/2024/day/4
 
 import Core library "io";
+import Core library "range";
 
 import library "day4_common";
 import library "io_utils";
@@ -14,20 +15,15 @@ fn Run() {
   var mas: array(i32, 3) = (0x4D, 0x41, 0x53);
   var found: i32 = 0;
 
-  // TODO: Use for loops once they're implemented.
-  var y: i32 = 1;
-  while (y < 139) {
-    var x: i32 = 1;
-    while (x < 139) {
+  for (y: i32 in Core.InclusiveRange(1, 138)) {
+    for (x: i32 in Core.InclusiveRange(1, 138)) {
       if ((search.Check3(mas, x - 1, y - 1, 1, 1) or
            search.Check3(mas, x + 1, y + 1, -1, -1)) and
           (search.Check3(mas, x - 1, y + 1, 1, -1) or
            search.Check3(mas, x + 1, y - 1, -1, 1))) {
         ++found;
       }
-      ++x;
     }
-    ++y;
   }
   Core.Print(found);
 }

+ 6 - 12
examples/advent2024/day5_common.carbon

@@ -6,6 +6,8 @@
 
 library "day5_common";
 
+import Core library "range";
+
 import library "io_utils";
 
 fn PageMask(page: i32) -> Core.UInt(100) {
@@ -16,10 +18,8 @@ fn PageMask(page: i32) -> Core.UInt(100) {
 class Rules {
   fn Read() -> Rules {
     returned var rules: Rules;
-    var i: i32 = 0;
-    while (i < 100) {
+    for (i: i32 in Core.Range(100)) {
       rules.disallowed_before[i] = 0;
-      ++i;
     }
 
     var a: i32;
@@ -68,39 +68,33 @@ class PageList {
 
   fn FollowsRules[self: Self](rules: Rules) -> bool {
     var seen: Core.UInt(100) = 0;
-    var i: i32 = 0;
-    while (i < self.num_pages) {
+    for (i: i32 in Core.Range(self.num_pages)) {
       let page: i32 = self.pages[i];
       if (seen & rules.disallowed_before[page] != 0) {
         return false;
       }
       seen |= PageMask(page);
-      ++i;
     }
     return true;
   }
 
   fn IsPossibleFirstPage[self: Self](rules: Rules, page: i32) -> bool {
-    var i: i32 = 0;
-    while (i < self.num_pages) {
+    for (i: i32 in Core.Range(self.num_pages)) {
       if (not rules.IsValidOrder(page, self.pages[i])) {
         return false;
       }
-      ++i;
     }
     return true;
   }
 
   fn ExtractPossibleFirstPage[addr self: Self*](rules: Rules) -> i32 {
-    var i: i32 = 0;
-    while (i < self->num_pages) {
+    for (i: i32 in Core.Range(self->num_pages)) {
       var page: i32 = self->pages[i];
       if (self->IsPossibleFirstPage(rules, page)) {
         self->pages[i] = self->pages[self->num_pages - 1];
         --self->num_pages;
         return page;
       }
-      ++i;
     }
     // TODO: Assert.
     return 0;

+ 3 - 6
examples/advent2024/day8_common.carbon

@@ -7,20 +7,17 @@
 library "day8_common";
 
 import Core library "io";
+import Core library "range";
 import library "io_utils";
 
 class Grid {
   fn Read() -> Grid {
     returned var me: Grid;
-    var y: i32 = 0;
-    while (y < 50) {
-      var x: i32 = 0;
-      while (x < 50) {
+    for (y: i32 in Core.Range(50)) {
+      for (x: i32 in Core.Range(50)) {
         me.data[x][y] = ReadChar();
-        ++x;
       }
       SkipNewline();
-      ++y;
     }
     return var;
   }

+ 5 - 12
examples/advent2024/day8_part1.carbon

@@ -5,17 +5,16 @@
 // https://adventofcode.com/2024/day/8
 
 import Core library "io";
+import Core library "range";
 
 import library "day8_common";
 import library "io_utils";
 
 fn IsAntinode(grid: Grid, ox: i32, oy: i32) -> bool {
-  var ay: i32 = 0;
-  while (ay < 50) {
+  for (ay: i32 in Core.Range(50)) {
     let by: i32 = ay * 2 - oy;
     if (by >= 0 and by < 50) {
-      var ax: i32 = 0;
-      while (ax < 50) {
+      for (ax: i32 in Core.Range(50)) {
         let bx: i32 = ax * 2 - ox;
         if (bx >= 0 and bx < 50 and (ax != bx or ay != by)) {
           if (grid.data[ax][ay] != 0x2E and
@@ -23,26 +22,20 @@ fn IsAntinode(grid: Grid, ox: i32, oy: i32) -> bool {
             return true;
           }
         }
-        ++ax;
       }
     }
-    ++ay;
   }
   return false;
 }
 
 fn CountAntinodes(grid: Grid) -> i32 {
   var count: i32 = 0;
-  var y: i32 = 0;
-  while (y < 50) {
-    var x: i32 = 0;
-    while (x < 50) {
+  for (y: i32 in Core.Range(50)) {
+    for (x: i32 in Core.Range(50)) {
       if (IsAntinode(grid, x, y)) {
         ++count;
       }
-      ++x;
     }
-    ++y;
   }
   return count;
 }

+ 7 - 19
examples/advent2024/day8_part2.carbon

@@ -5,6 +5,7 @@
 // https://adventofcode.com/2024/day/8
 
 import Core library "io";
+import Core library "range";
 
 import library "day8_common";
 import library "io_utils";
@@ -19,14 +20,11 @@ fn MarkAndCount(marks: array(array(bool, 50), 50)*, x: i32, y: i32) -> i32 {
 
 fn MarkAndCountAntinodesFor(grid: Grid, marks: array(array(bool, 50), 50)*, ax: i32, ay: i32) -> i32 {
   var count: i32 = 0;
-  var by: i32 = 0;
-  while (by < 50) {
-    var bx: i32 = 0;
-    while (bx < 50) {
+  for (by: i32 in Core.Range(50)) {
+    for (bx: i32 in Core.Range(50)) {
       let dx: i32 = bx - ax;
       let dy: i32 = by - ay;
       if (grid.data[bx][by] != grid.data[ax][ay] or (dx == 0 and dy == 0)) {
-        ++bx;
         continue;
       }
 
@@ -37,39 +35,29 @@ fn MarkAndCountAntinodesFor(grid: Grid, marks: array(array(bool, 50), 50)*, ax:
         x += dx;
         y += dy;
       }
-      ++bx;
     }
-    ++by;
   }
   return count;
 }
 
 fn MarkAndCountAntinodes(grid: Grid, marks: array(array(bool, 50), 50)*) -> i32 {
   var count: i32 = 0;
-  var y: i32 = 0;
-  while (y < 50) {
-    var x: i32 = 0;
-    while (x < 50) {
+  for (y: i32 in Core.Range(50)) {
+    for (x: i32 in Core.Range(50)) {
       if (grid.data[x][y] != 0x2E) {
         count += MarkAndCountAntinodesFor(grid, marks, x, y);
       }
-      ++x;
     }
-    ++y;
   }
   return count;
 }
 
 fn Run() {
   var marks: array(array(bool, 50), 50);
-  var y: i32 = 0;
-  while (y < 50) {
-    var x: i32 = 0;
-    while (x < 50) {
+  for (y: i32 in Core.Range(50)) {
+    for (x: i32 in Core.Range(50)) {
       marks[x][y] = false;
-      ++x;
     }
-    ++y;
   }
 
   Core.Print(MarkAndCountAntinodes(Grid.Read(), &marks));

+ 5 - 12
examples/advent2024/day9_common.carbon

@@ -7,6 +7,7 @@
 library "day9_common";
 
 import Core library "io";
+import Core library "range";
 import library "io_utils";
 
 class SectorList {
@@ -19,11 +20,9 @@ class SectorList {
     var c: i32 = ReadChar();
     while (c != Core.EOF() and c != 0xA) {
       let v: i32 = if used then sector else -1;
-      var n: i32 = c - 0x30;
-      while (n > 0) {
+      for (_: i32 in Core.Range(c - 0x30)) {
         me.data[me.size] = v;
         ++me.size;
-        --n;
       }
       if (used) {
         ++sector;
@@ -52,21 +51,17 @@ class SectorList {
   }
 
   fn HasSpace[addr self: Self*](start: i32, size: i32) -> bool {
-    var i: i32 = start;
-    while (i < start + size) {
+    for (i: i32 in Core.InclusiveRange(start, start + size - 1)) {
       if (self->data[i] != -1) {
         return false;
       }
-      ++i;
     }
     return true;
   }
 
   fn Fill[addr self: Self*](start: i32, size: i32, sector: i32) {
-    var i: i32 = start;
-    while (i < start + size) {
+    for (i: i32 in Core.InclusiveRange(start, start + size - 1)) {
       self->data[i] = sector;
-      ++i;
     }
   }
 
@@ -106,12 +101,10 @@ class SectorList {
 
   fn Checksum[self: Self]() -> i64 {
     var total: i64 = 0;
-    var i: i32 = 0;
-    while (i < self.size) {
+    for (i: i32 in Core.Range(self.size)) {
       if (self.data[i] != -1) {
         total = total + ((i * self.data[i]) as i64);
       }
-      ++i;
     }
     return total;
   }

+ 2 - 3
examples/advent2024/io_utils.carbon

@@ -5,6 +5,7 @@
 library "io_utils";
 
 import Core library "io";
+import Core library "range";
 
 // If non-zero, this is the most recently read character plus 2.
 // The +2 is necessary to distinguish the case of no unread character
@@ -114,12 +115,10 @@ fn SkipNewline() -> bool {
 }
 
 fn SkipNChars(n: i32) -> bool {
-  var i: i32 = 0;
-  while (i < n) {
+  for (_: i32 in Core.Range(n)) {
     if (ReadChar() == Core.EOF()) {
       return false;
     }
-    ++i;
   }
   return true;
 }

+ 3 - 9
examples/sieve.carbon

@@ -3,20 +3,16 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
 import Core library "io";
+import Core library "range";
 
 // Compute and return the number of primes less than 1000.
 
 class Sieve {
   fn Make() -> Sieve {
     returned var s: Sieve;
-
-    // TODO: `for` loop.
-    var n: i32 = 0;
-    while (n < 1000) {
+    for (n: i32 in Core.Range(1000)) {
       s.is_prime[n] = true;
-      ++n;
     }
-
     return var;
   }
 
@@ -35,14 +31,12 @@ fn Run() -> i32 {
   var s: Sieve = Sieve.Make();
 
   var number_of_primes: i32 = 0;
-  var n: i32 = 2;
-  while (n < 1000) {
+  for (n: i32 in Core.InclusiveRange(2, 999)) {
     if (s.is_prime[n]) {
       ++number_of_primes;
       Core.Print(n);
       s.MarkMultiplesNotPrime(n);
     }
-    ++n;
   }
 
   return number_of_primes;