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

Use it in examples where appropriate.

Depends on #5698.
This commit is contained in:
Richard Smith
2025-06-26 20:13:07 +00:00
committed by GitHub
parent 9855818bb8
commit c34d0c7adf
19 changed files with 133 additions and 197 deletions
+3 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;